Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107327470
D3009.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D3009.diff
View Options
Index: head/sys/dev/ahci/ahci.h
===================================================================
--- head/sys/dev/ahci/ahci.h
+++ head/sys/dev/ahci/ahci.h
@@ -482,11 +482,15 @@
device_t dev;
bus_dma_tag_t dma_tag;
int r_rid;
+ int r_msix_tab_rid;
+ int r_msix_pba_rid;
uint16_t vendorid; /* Vendor ID from the bus */
uint16_t deviceid; /* Device ID from the bus */
uint16_t subvendorid; /* Subvendor ID from the bus */
uint16_t subdeviceid; /* Subdevice ID from the bus */
struct resource *r_mem;
+ struct resource *r_msix_table;
+ struct resource *r_msix_pba;
struct rman sc_iomem;
struct ahci_controller_irq {
struct ahci_controller *ctlr;
@@ -621,3 +625,4 @@
bus_dma_tag_t ahci_get_dma_tag(device_t dev, device_t child);
int ahci_ctlr_reset(device_t dev);
int ahci_ctlr_setup(device_t dev);
+void ahci_free_mem(device_t dev);
Index: head/sys/dev/ahci/ahci.c
===================================================================
--- head/sys/dev/ahci/ahci.c
+++ head/sys/dev/ahci/ahci.c
@@ -181,12 +181,12 @@
ctlr->sc_iomem.rm_type = RMAN_ARRAY;
ctlr->sc_iomem.rm_descr = "I/O memory addresses";
if ((error = rman_init(&ctlr->sc_iomem)) != 0) {
- bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
+ ahci_free_mem(dev);
return (error);
}
if ((error = rman_manage_region(&ctlr->sc_iomem,
rman_get_start(ctlr->r_mem), rman_get_end(ctlr->r_mem))) != 0) {
- bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
+ ahci_free_mem(dev);
rman_fini(&ctlr->sc_iomem);
return (error);
}
@@ -250,8 +250,7 @@
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
BUS_SPACE_MAXSIZE, BUS_SPACE_UNRESTRICTED, BUS_SPACE_MAXSIZE,
0, NULL, NULL, &ctlr->dma_tag)) {
- bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid,
- ctlr->r_mem);
+ ahci_free_mem(dev);
rman_fini(&ctlr->sc_iomem);
return (ENXIO);
}
@@ -261,8 +260,7 @@
/* Setup interrupts. */
if ((error = ahci_setup_interrupt(dev)) != 0) {
bus_dma_tag_destroy(ctlr->dma_tag);
- bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid,
- ctlr->r_mem);
+ ahci_free_mem(dev);
rman_fini(&ctlr->sc_iomem);
return (error);
}
@@ -367,9 +365,26 @@
bus_dma_tag_destroy(ctlr->dma_tag);
/* Free memory. */
rman_fini(&ctlr->sc_iomem);
+ ahci_free_mem(dev);
+ return (0);
+}
+
+void
+ahci_free_mem(device_t dev)
+{
+ struct ahci_controller *ctlr = device_get_softc(dev);
+
+ /* Release memory resources */
if (ctlr->r_mem)
bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
- return (0);
+ if (ctlr->r_msix_table)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ ctlr->r_msix_tab_rid, ctlr->r_msix_table);
+ if (ctlr->r_msix_pba)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ ctlr->r_msix_pba_rid, ctlr->r_msix_pba);
+
+ ctlr->r_msix_pba = ctlr->r_mem = ctlr->r_msix_table = NULL;
}
int
Index: head/sys/dev/ahci/ahci_pci.c
===================================================================
--- head/sys/dev/ahci/ahci_pci.c
+++ head/sys/dev/ahci/ahci_pci.c
@@ -374,12 +374,39 @@
}
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)
{
struct ahci_controller *ctlr = device_get_softc(dev);
int error, i;
uint32_t devid = pci_get_devid(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;
while (ahci_ids[i].id != 0 &&
@@ -406,10 +433,57 @@
if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&ctlr->r_rid, RF_ACTIVE)))
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);
/* Reset controller */
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);
};
@@ -426,24 +500,51 @@
resource_int_value(device_get_name(dev),
device_get_unit(dev), "msi", &ctlr->msi);
ctlr->numirqs = 1;
+ if (msi_count == 0 && msix_count == 0)
+ ctlr->msi = 0;
if (ctlr->msi < 0)
ctlr->msi = 0;
- else if (ctlr->msi == 1)
- ctlr->msi = min(1, pci_msi_count(dev));
- else if (ctlr->msi > 1) {
+ else if (ctlr->msi == 1) {
+ msi_count = min(1, msi_count);
+ msix_count = min(1, msix_count);
+ } else if (ctlr->msi > 1)
ctlr->msi = 2;
- ctlr->numirqs = pci_msi_count(dev);
- }
- /* Allocate MSI if needed/present. */
- if (ctlr->msi && pci_alloc_msi(dev, &ctlr->numirqs) != 0) {
- ctlr->msi = 0;
- ctlr->numirqs = 1;
+
+ /* 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;
+ }
+
+ /*
+ * 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;
+ device_printf(dev, "Failed to allocate MSI/MSI-x, "
+ "falling back to INTx\n");
+ }
}
error = ahci_attach(dev);
- if (error != 0)
- if (ctlr->msi)
+ if (error != 0) {
+ if (ctlr->msi > 0)
pci_release_msi(dev);
+ ahci_free_mem(dev);
+ }
return error;
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Jan 13, 1:34 PM (18 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15782621
Default Alt Text
D3009.diff (7 KB)
Attached To
Mode
D3009: Add MSI-x support to AHCI driver
Attached
Detach File
Event Timeline
Log In to Comment