Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/ahci/ahci_pci.c
Show First 20 Lines • Show All 368 Lines • ▼ Show 20 Lines | if (ahci_ids[i].id == devid && | ||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
} | } | ||||
device_set_desc_copy(dev, "AHCI SATA controller"); | device_set_desc_copy(dev, "AHCI SATA controller"); | ||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
static int | static int | ||||
ahci_pci_read_msix_bars(device_t dev, uint8_t *table_bar, uint8_t *pba_bar) | |||||
{ | |||||
int cap_offset = 0, ret; | |||||
uint32_t val; | |||||
if ((table_bar == NULL) || (pba_bar == NULL)) | |||||
return (EINVAL); | |||||
ret = pci_find_cap(dev, PCIY_MSIX, &cap_offset); | |||||
if (ret != 0) | |||||
return (EINVAL); | |||||
val = pci_read_config(dev, cap_offset + PCIR_MSIX_TABLE, 4); | |||||
*table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); | |||||
val = pci_read_config(dev, cap_offset + PCIR_MSIX_PBA, 4); | |||||
*pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); | |||||
return (0); | |||||
} | |||||
static int | |||||
ahci_pci_attach(device_t dev) | ahci_pci_attach(device_t dev) | ||||
{ | { | ||||
struct ahci_controller *ctlr = device_get_softc(dev); | struct ahci_controller *ctlr = device_get_softc(dev); | ||||
int error, i; | int error, i; | ||||
uint32_t devid = pci_get_devid(dev); | uint32_t devid = pci_get_devid(dev); | ||||
uint8_t revid = pci_get_revid(dev); | uint8_t revid = pci_get_revid(dev); | ||||
int msi_count, msix_count; | |||||
uint8_t table_bar = 0, pba_bar = 0; | |||||
msi_count = pci_msi_count(dev); | |||||
msix_count = pci_msix_count(dev); | |||||
i = 0; | i = 0; | ||||
while (ahci_ids[i].id != 0 && | while (ahci_ids[i].id != 0 && | ||||
(ahci_ids[i].id != devid || | (ahci_ids[i].id != devid || | ||||
ahci_ids[i].rev > revid)) | ahci_ids[i].rev > revid)) | ||||
i++; | i++; | ||||
ctlr->quirks = ahci_ids[i].quirks; | ctlr->quirks = ahci_ids[i].quirks; | ||||
/* Limit speed for my onboard JMicron external port. | /* Limit speed for my onboard JMicron external port. | ||||
* It is not eSATA really, limit to SATA 1 */ | * It is not eSATA really, limit to SATA 1 */ | ||||
Show All 9 Lines | ahci_pci_attach(device_t dev) | ||||
/* Default AHCI Base Address is BAR(5), Cavium uses BAR(0) */ | /* Default AHCI Base Address is BAR(5), Cavium uses BAR(0) */ | ||||
if (ctlr->quirks & AHCI_Q_ABAR0) | if (ctlr->quirks & AHCI_Q_ABAR0) | ||||
ctlr->r_rid = PCIR_BAR(0); | ctlr->r_rid = PCIR_BAR(0); | ||||
else | else | ||||
ctlr->r_rid = PCIR_BAR(5); | ctlr->r_rid = PCIR_BAR(5); | ||||
if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | ||||
&ctlr->r_rid, RF_ACTIVE))) | &ctlr->r_rid, RF_ACTIVE))) | ||||
return ENXIO; | return ENXIO; | ||||
/* Read MSI-x BAR IDs if supported */ | |||||
if (msix_count > 0) { | |||||
error = ahci_pci_read_msix_bars(dev, &table_bar, &pba_bar); | |||||
if (error == 0) { | |||||
ctlr->r_msix_tab_rid = table_bar; | |||||
ctlr->r_msix_pba_rid = pba_bar; | |||||
} else { | |||||
/* Failed to read BARs, disable MSI-x */ | |||||
msix_count = 0; | |||||
} | |||||
} | |||||
/* Allocate resources for MSI-x table and PBA */ | |||||
if (msix_count > 0) { | |||||
/* | |||||
* Allocate new MSI-x table only if not | |||||
* allocated before. | |||||
*/ | |||||
ctlr->r_msix_table = NULL; | |||||
if (ctlr->r_msix_tab_rid != ctlr->r_rid) { | |||||
/* Separate BAR for MSI-x */ | |||||
ctlr->r_msix_table = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | |||||
&ctlr->r_msix_tab_rid, RF_ACTIVE); | |||||
if (ctlr->r_msix_table == NULL) { | |||||
ahci_free_mem(dev); | |||||
return (ENXIO); | |||||
} | |||||
} | |||||
/* | |||||
* Allocate new PBA table only if not | |||||
* allocated before. | |||||
*/ | |||||
ctlr->r_msix_pba = NULL; | |||||
if ((ctlr->r_msix_pba_rid != ctlr->r_msix_tab_rid) && | |||||
(ctlr->r_msix_pba_rid != ctlr->r_rid)) { | |||||
/* Separate BAR for PBA */ | |||||
ctlr->r_msix_pba = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | |||||
&ctlr->r_msix_pba_rid, RF_ACTIVE); | |||||
if (ctlr->r_msix_pba == NULL) { | |||||
ahci_free_mem(dev); | |||||
return (ENXIO); | |||||
} | |||||
} | |||||
} | |||||
pci_enable_busmaster(dev); | pci_enable_busmaster(dev); | ||||
/* Reset controller */ | /* Reset controller */ | ||||
if ((error = ahci_pci_ctlr_reset(dev)) != 0) { | if ((error = ahci_pci_ctlr_reset(dev)) != 0) { | ||||
bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); | ahci_free_mem(dev); | ||||
return (error); | return (error); | ||||
}; | }; | ||||
/* Setup interrupts. */ | /* Setup interrupts. */ | ||||
/* Setup MSI register parameters */ | /* Setup MSI register parameters */ | ||||
/* Process hints. */ | /* Process hints. */ | ||||
if (ctlr->quirks & AHCI_Q_NOMSI) | if (ctlr->quirks & AHCI_Q_NOMSI) | ||||
ctlr->msi = 0; | ctlr->msi = 0; | ||||
else if (ctlr->quirks & AHCI_Q_1MSI) | else if (ctlr->quirks & AHCI_Q_1MSI) | ||||
ctlr->msi = 1; | ctlr->msi = 1; | ||||
else | else | ||||
ctlr->msi = 2; | ctlr->msi = 2; | ||||
resource_int_value(device_get_name(dev), | resource_int_value(device_get_name(dev), | ||||
device_get_unit(dev), "msi", &ctlr->msi); | device_get_unit(dev), "msi", &ctlr->msi); | ||||
ctlr->numirqs = 1; | ctlr->numirqs = 1; | ||||
if (msi_count == 0 && msix_count == 0) | |||||
ctlr->msi = 0; | |||||
if (ctlr->msi < 0) | if (ctlr->msi < 0) | ||||
ctlr->msi = 0; | ctlr->msi = 0; | ||||
else if (ctlr->msi == 1) | else if (ctlr->msi == 1) { | ||||
ctlr->msi = min(1, pci_msi_count(dev)); | msi_count = min(1, msi_count); | ||||
else if (ctlr->msi > 1) { | msix_count = min(1, msix_count); | ||||
} else if (ctlr->msi > 1) | |||||
ctlr->msi = 2; | ctlr->msi = 2; | ||||
ctlr->numirqs = pci_msi_count(dev); | |||||
/* Allocate MSI/MSI-x if needed/present. */ | |||||
if (ctlr->msi > 0) { | |||||
error = ENXIO; | |||||
/* Try to allocate MSI-x first */ | |||||
if (msix_count > 0) { | |||||
error = pci_alloc_msix(dev, &msix_count); | |||||
if (error == 0) | |||||
ctlr->numirqs = msix_count; | |||||
} | } | ||||
/* Allocate MSI if needed/present. */ | |||||
if (ctlr->msi && pci_alloc_msi(dev, &ctlr->numirqs) != 0) { | /* | ||||
* Try to allocate MSI if msi_count is greater than 0 | |||||
* and if MSI-x allocation failed. | |||||
*/ | |||||
if ((error != 0) && (msi_count > 0)) { | |||||
error = pci_alloc_msi(dev, &msi_count); | |||||
if (error == 0) | |||||
ctlr->numirqs = msi_count; | |||||
} | |||||
/* Both MSI and MSI-x allocations failed */ | |||||
if (error != 0) { | |||||
ctlr->msi = 0; | ctlr->msi = 0; | ||||
ctlr->numirqs = 1; | device_printf(dev, "Failed to allocate MSI/MSI-x, " | ||||
"falling back to INTx\n"); | |||||
} | } | ||||
} | |||||
error = ahci_attach(dev); | error = ahci_attach(dev); | ||||
if (error != 0) | if (error != 0) { | ||||
if (ctlr->msi) | if (ctlr->msi > 0) | ||||
pci_release_msi(dev); | pci_release_msi(dev); | ||||
ahci_free_mem(dev); | |||||
} | |||||
return error; | return error; | ||||
} | } | ||||
static int | static int | ||||
ahci_pci_detach(device_t dev) | ahci_pci_detach(device_t dev) | ||||
{ | { | ||||
ahci_detach(dev); | ahci_detach(dev); | ||||
▲ Show 20 Lines • Show All 69 Lines • Show Last 20 Lines |