Index: sys/dev/ahci/ahci.h =================================================================== --- sys/dev/ahci/ahci.h +++ 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: sys/dev/ahci/ahci.c =================================================================== --- sys/dev/ahci/ahci.c +++ 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: sys/dev/ahci/ahci_pci.c =================================================================== --- sys/dev/ahci/ahci_pci.c +++ sys/dev/ahci/ahci_pci.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include "ahci.h" @@ -380,6 +381,11 @@ int error, i; uint32_t devid = pci_get_devid(dev); uint8_t revid = pci_get_revid(dev); + struct pci_devinfo *dinfo; + int msi_count, msix_count; + + msi_count = pci_msi_count(dev); + msix_count = pci_msix_count(dev); i = 0; while (ahci_ids[i].id != 0 && @@ -406,10 +412,35 @@ if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ctlr->r_rid, RF_ACTIVE))) return ENXIO; + + if (msix_count > 0) { + /* Allocate resources for MSI-X table and PBA */ + /* No need to check dinfo for NULL as it is allocated before by + * pci during device discovery */ + dinfo = (struct pci_devinfo *)device_get_ivars(dev); + ctlr->r_msix_tab_rid = dinfo->cfg.msix.msix_table_bar; + ctlr->r_msix_pba_rid = dinfo->cfg.msix.msix_pba_bar; + if (!(ctlr->r_msix_table = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &ctlr->r_msix_tab_rid, RF_ACTIVE))) { + ahci_free_mem(dev); + return ENXIO; + } + + if (ctlr->r_msix_tab_rid != ctlr->r_msix_pba_rid) { + /* Separate BAR for PBA */ + if (!(ctlr->r_msix_pba = bus_alloc_resource_any(dev, + SYS_RES_MEMORY, &ctlr->r_msix_pba_rid, + RF_ACTIVE))) { + 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); }; @@ -428,22 +459,42 @@ ctlr->numirqs = 1; 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) { + if (msi_count == 0 && msix_count == 0) + ctlr->msi = 0; + else + ctlr->msi = 1; + } else if (ctlr->msi > 1) { ctlr->msi = 2; - ctlr->numirqs = pci_msi_count(dev); + ctlr->numirqs = (msix_count > 0) ? msix_count: msi_count; } - /* Allocate MSI if needed/present. */ - if (ctlr->msi && pci_alloc_msi(dev, &ctlr->numirqs) != 0) { + /* Allocate MSI/MSI-x if needed/present. */ + if (ctlr->msi > 0) { + error = -1; + if (msix_count > 0) + error = pci_alloc_msix(dev, &ctlr->numirqs); + + /* + * Try to allocate MSI if msi_count is greater than 0 + * and if msix allocation failed. + */ + if ((error != 0) && (msi_count > 0)) + error = pci_alloc_msi(dev, &ctlr->numirqs); + + /* We don't have any MSI or MSI-x */ + if (error) { ctlr->msi = 0; ctlr->numirqs = 1; } + } error = ahci_attach(dev); - if (error != 0) - if (ctlr->msi) + if (error != 0) { + if (ctlr->msi > 0 && (msix_count > 0 || msi_count > 0)) pci_release_msi(dev); + ahci_free_mem(dev); + } return error; }