From 31646171933faaac961652489e62d7e549656456 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Mon, 16 Jan 2012 15:10:27 +0800 Subject: [PATCH] msix: Rework MSI-X allocation, step 1/3 Add pci_{setup,teardown}_msix(), which prepare/cleanup necessary information for MSI-X allocation operation. --- sys/bus/pci/pci.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++-- sys/bus/pci/pcivar.h | 2 + 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/sys/bus/pci/pci.c b/sys/bus/pci/pci.c index afeacfc..26f39eb 100644 --- a/sys/bus/pci/pci.c +++ b/sys/bus/pci/pci.c @@ -112,6 +112,7 @@ static void pci_setup_msix_vector(device_t dev, u_int index, uint64_t address, uint32_t data); static void pci_mask_msix_vector(device_t dev, u_int index); static void pci_unmask_msix_vector(device_t dev, u_int index); +static void pci_mask_msix_allvectors(device_t dev); static int pci_msi_blacklisted(void); static void pci_resume_msi(device_t dev); static void pci_resume_msix(device_t dev); @@ -1420,6 +1421,9 @@ pci_pending_msix_vector(device_t dev, u_int index) struct pcicfg_msix *msix = &dinfo->cfg.msix; uint32_t offset, bit; + KASSERT(msix->msix_table_res != NULL && msix->msix_pba_res != NULL, + ("MSI-X is not setup yet\n")); + KASSERT(msix->msix_table_len > index, ("bogus index")); offset = msix->msix_pba_offset + (index / 32) * 4; bit = 1 << index % 32; @@ -1441,11 +1445,9 @@ pci_resume_msix(device_t dev) int i; if (msix->msix_alloc > 0) { - /* First, mask all vectors. */ - for (i = 0; i < msix->msix_msgnum; i++) - pci_mask_msix_vector(dev, i); + pci_mask_msix_allvectors(dev); - /* Second, program any messages with at least one handler. */ + /* Program any messages with at least one handler. */ for (i = 0; i < msix->msix_table_len; i++) { mte = &msix->msix_table[i]; if (mte->mte_vector == 0 || mte->mte_handlers == 0) @@ -1672,6 +1674,83 @@ pci_msix_count_method(device_t dev, device_t child) return (0); } +int +pci_setup_msix(device_t dev) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + pcicfgregs *cfg = &dinfo->cfg; + struct resource_list_entry *rle; + struct resource *table_res, *pba_res; + + KASSERT(cfg->msix.msix_table_res == NULL && + cfg->msix.msix_pba_res == NULL, ("MSI-X has been setup yet\n")); + + /* If rid 0 is allocated, then fail. */ + rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 0); + if (rle != NULL && rle->res != NULL) + return (ENXIO); + + /* Already have allocated MSIs? */ + if (cfg->msi.msi_alloc != 0) + return (ENXIO); + + /* If MSI is blacklisted for this system, fail. */ + if (pci_msi_blacklisted()) + return (ENXIO); + + /* MSI-X capability present? */ + if (cfg->msix.msix_location == 0 || !pci_do_msix) + return (ENODEV); + + /* Make sure the appropriate BARs are mapped. */ + rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY, + cfg->msix.msix_table_bar); + if (rle == NULL || rle->res == NULL || + !(rman_get_flags(rle->res) & RF_ACTIVE)) + return (ENXIO); + table_res = rle->res; + if (cfg->msix.msix_pba_bar != cfg->msix.msix_table_bar) { + rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY, + cfg->msix.msix_pba_bar); + if (rle == NULL || rle->res == NULL || + !(rman_get_flags(rle->res) & RF_ACTIVE)) + return (ENXIO); + } + pba_res = rle->res; + + cfg->msix.msix_table_res = table_res; + cfg->msix.msix_pba_res = pba_res; + + pci_mask_msix_allvectors(dev); + + return 0; +} + +void +pci_teardown_msix(device_t dev) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pcicfg_msix *msix = &dinfo->cfg.msix; + + KASSERT(msix->msix_table_res != NULL && + msix->msix_pba_res != NULL, ("MSI-X is not setup yet\n")); + + pci_mask_msix_allvectors(dev); + + msix->msix_table_res = NULL; + msix->msix_pba_res = NULL; +} + +static void +pci_mask_msix_allvectors(device_t dev) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + u_int i; + + for (i = 0; i < dinfo->cfg.msix.msix_msgnum; ++i) + pci_mask_msix_vector(dev, i); +} + /* * HyperTransport MSI mapping control */ diff --git a/sys/bus/pci/pcivar.h b/sys/bus/pci/pcivar.h index 73fd2e4..b031f89 100644 --- a/sys/bus/pci/pcivar.h +++ b/sys/bus/pci/pcivar.h @@ -500,6 +500,8 @@ device_t pci_find_device(uint16_t, uint16_t); /* Can be used by drivers to manage the MSI-X table. */ int pci_pending_msix_vector(device_t dev, u_int index); +int pci_setup_msix(device_t dev); +void pci_teardown_msix(device_t dev); int pci_msi_device_blacklisted(device_t dev); -- 1.7.7.2