static void qib_msix_setup(struct qib_devdata *dd, int pos, u32 *msixcnt, struct msix_entry *msix_entry) { int ret; u32 tabsize = 0; u16 msix_flags; pci_read_config_word(dd->pcidev, pos + PCI_MSIX_FLAGS, &msix_flags); tabsize = 1 + (msix_flags & PCI_MSIX_FLAGS_QSIZE); if (tabsize > *msixcnt) tabsize = *msixcnt; ret = pci_enable_msix(dd->pcidev, msix_entry, tabsize); if (ret > 0) { tabsize = ret; ret = pci_enable_msix(dd->pcidev, msix_entry, tabsize); } if (ret) { qib_dev_err(dd, "pci_enable_msix %d vectors failed: %d, " "falling back to INTx\n", tabsize, ret); tabsize = 0; } *msixcnt = tabsize; if (ret) qib_enable_intx(dd->pcidev); }
/* * Setup pcie interrupt stuff again after a reset. I'd like to just call * pci_enable_msi() again for msi, but when I do that, * the MSI enable bit doesn't get set in the command word, and * we switch to to a different interrupt vector, which is confusing, * so I instead just do it all inline. Perhaps somehow can tie this * into the PCIe hotplug support at some point */ int qib_reinit_intr(struct qib_devdata *dd) { int pos; u16 control; int ret = 0; if (!dd->msi_lo) /* we weren't using MSI, so don't restore it */ goto bail; #ifdef CONFIG_PCI_MSI pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI); if (!pos) { qib_dev_err(dd, "Can't find MSI capability, " "can't restore MSI settings\n"); ret = 0; /* nothing special for MSIx, just MSI */ goto bail; } qib_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n", dd->msi_lo, pos + PCI_MSI_ADDRESS_LO); pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO, dd->msi_lo); qib_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n", dd->msi_hi, pos + PCI_MSI_ADDRESS_HI); pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI, dd->msi_hi); pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, &control); if (!(control & PCI_MSI_FLAGS_ENABLE)) { qib_cdbg(INIT, "MSI control at off %x was %x, " "setting MSI enable (%x)\n", pos + PCI_MSI_FLAGS, control, control | PCI_MSI_FLAGS_ENABLE); control |= PCI_MSI_FLAGS_ENABLE; pci_write_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, control); } /* now rewrite the data (vector) info */ pci_write_config_word(dd->pcidev, pos + ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8), dd->msi_data); ret = 1; #endif /* CONFIG_PCI_MSI */ bail: if (!ret && (dd->flags & QIB_HAS_INTX)) { qib_cdbg(INIT, "Using INTx, MSI disabled or not configured\n"); qib_enable_intx(dd->pcidev); ret = 1; } /* and now set the pci master bit again */ pci_set_master(dd->pcidev); return ret; }
static void qib_msix_setup(struct qib_devdata *dd, int pos, u32 *msixcnt, struct qib_msix_entry *qib_msix_entry) { int ret; int nvec = *msixcnt; struct msix_entry *msix_entry; int i; ret = pci_msix_vec_count(dd->pcidev); if (ret < 0) goto do_intx; nvec = min(nvec, ret); /* We can't pass qib_msix_entry array to qib_msix_setup * so use a dummy msix_entry array and copy the allocated * irq back to the qib_msix_entry array. */ msix_entry = kcalloc(nvec, sizeof(*msix_entry), GFP_KERNEL); if (!msix_entry) goto do_intx; for (i = 0; i < nvec; i++) msix_entry[i] = qib_msix_entry[i].msix; ret = pci_enable_msix_range(dd->pcidev, msix_entry, 1, nvec); if (ret < 0) goto free_msix_entry; else nvec = ret; for (i = 0; i < nvec; i++) qib_msix_entry[i].msix = msix_entry[i]; kfree(msix_entry); *msixcnt = nvec; return; free_msix_entry: kfree(msix_entry); do_intx: qib_dev_err( dd, "pci_enable_msix_range %d vectors failed: %d, falling back to INTx\n", nvec, ret); *msixcnt = 0; qib_enable_intx(dd->pcidev); }
static void qib_msix_setup(struct qib_devdata *dd, int pos, u32 *msixcnt, struct qib_msix_entry *qib_msix_entry) { int ret; u32 tabsize = 0; u16 msix_flags; struct msix_entry *msix_entry; int i; /* We can't pass qib_msix_entry array to qib_msix_setup * so use a dummy msix_entry array and copy the allocated * irq back to the qib_msix_entry array. */ msix_entry = kmalloc(*msixcnt * sizeof(*msix_entry), GFP_KERNEL); if (!msix_entry) { ret = -ENOMEM; goto do_intx; } for (i = 0; i < *msixcnt; i++) msix_entry[i] = qib_msix_entry[i].msix; pci_read_config_word(dd->pcidev, pos + PCI_MSIX_FLAGS, &msix_flags); tabsize = 1 + (msix_flags & PCI_MSIX_FLAGS_QSIZE); if (tabsize > *msixcnt) tabsize = *msixcnt; ret = pci_enable_msix(dd->pcidev, msix_entry, tabsize); if (ret > 0) { tabsize = ret; ret = pci_enable_msix(dd->pcidev, msix_entry, tabsize); } do_intx: if (ret) { qib_dev_err(dd, "pci_enable_msix %d vectors failed: %d, falling back to INTx\n", tabsize, ret); tabsize = 0; } for (i = 0; i < tabsize; i++) qib_msix_entry[i].msix = msix_entry[i]; kfree(msix_entry); *msixcnt = tabsize; if (ret) qib_enable_intx(dd->pcidev); }
/* * Setup pcie interrupt stuff again after a reset. I'd like to just call * pci_enable_msi() again for msi, but when I do that, * the MSI enable bit doesn't get set in the command word, and * we switch to to a different interrupt vector, which is confusing, * so I instead just do it all inline. Perhaps somehow can tie this * into the PCIe hotplug support at some point */ int qib_reinit_intr(struct qib_devdata *dd) { int pos; u16 control; int ret = 0; /* If we aren't using MSI, don't restore it */ if (!dd->msi_lo) goto bail; pos = dd->pcidev->msi_cap; if (!pos) { qib_dev_err(dd, "Can't find MSI capability, can't restore MSI settings\n"); ret = 0; /* nothing special for MSIx, just MSI */ goto bail; } pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO, dd->msi_lo); pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI, dd->msi_hi); pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, &control); if (!(control & PCI_MSI_FLAGS_ENABLE)) { control |= PCI_MSI_FLAGS_ENABLE; pci_write_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, control); } /* now rewrite the data (vector) info */ pci_write_config_word(dd->pcidev, pos + ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8), dd->msi_data); ret = 1; bail: if (!ret && (dd->flags & QIB_HAS_INTX)) { qib_enable_intx(dd); ret = 1; } /* and now set the pci master bit again */ pci_set_master(dd->pcidev); return ret; }
int qib_reinit_intr(struct qib_devdata *dd) { int pos; u16 control; int ret = 0; /* */ if (!dd->msi_lo) goto bail; pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI); if (!pos) { qib_dev_err(dd, "Can't find MSI capability, " "can't restore MSI settings\n"); ret = 0; /* */ goto bail; } pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO, dd->msi_lo); pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI, dd->msi_hi); pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, &control); if (!(control & PCI_MSI_FLAGS_ENABLE)) { control |= PCI_MSI_FLAGS_ENABLE; pci_write_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, control); } /* */ pci_write_config_word(dd->pcidev, pos + ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8), dd->msi_data); ret = 1; bail: if (!ret && (dd->flags & QIB_HAS_INTX)) { qib_enable_intx(dd->pcidev); ret = 1; } /* */ pci_set_master(dd->pcidev); return ret; }
int qib_pcie_params(struct qib_devdata *dd, u32 minw, u32 *nent, struct qib_msix_entry *entry) { u16 linkstat, speed; int pos = 0, pose, ret = 1; pose = pci_pcie_cap(dd->pcidev); if (!pose) { qib_dev_err(dd, "Can't find PCI Express capability!\n"); /* */ dd->lbus_width = 1; dd->lbus_speed = 2500; /* */ goto bail; } pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSIX); if (nent && *nent && pos) { qib_msix_setup(dd, pos, nent, entry); ret = 0; /* */ } else { pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI); if (pos) ret = qib_msi_setup(dd, pos); else qib_dev_err(dd, "No PCI MSI or MSIx capability!\n"); } if (!pos) qib_enable_intx(dd->pcidev); pci_read_config_word(dd->pcidev, pose + PCI_EXP_LNKSTA, &linkstat); /* */ speed = linkstat & 0xf; linkstat >>= 4; linkstat &= 0x1f; dd->lbus_width = linkstat; switch (speed) { case 1: dd->lbus_speed = 2500; /* */ break; case 2: dd->lbus_speed = 5000; /* */ break; default: /* */ dd->lbus_speed = 2500; break; } /* */ if (minw && linkstat < minw) qib_dev_err(dd, "PCIe width %u (x%u HCA), performance reduced\n", linkstat, minw); qib_tune_pcie_caps(dd); qib_tune_pcie_coalesce(dd); bail: /* */ snprintf(dd->lbus_info, sizeof(dd->lbus_info), "PCIe,%uMHz,x%u\n", dd->lbus_speed, dd->lbus_width); return ret; }
int qib_pcie_params(struct qib_devdata *dd, u32 minw, u32 *nent, struct qib_msix_entry *entry) { u16 linkstat, speed; int pos = 0, ret = 1; if (!pci_is_pcie(dd->pcidev)) { qib_dev_err(dd, "Can't find PCI Express capability!\n"); /* set up something... */ dd->lbus_width = 1; dd->lbus_speed = 2500; /* Gen1, 2.5GHz */ goto bail; } pos = dd->pcidev->msix_cap; if (nent && *nent && pos) { qib_msix_setup(dd, pos, nent, entry); ret = 0; /* did it, either MSIx or INTx */ } else { pos = dd->pcidev->msi_cap; if (pos) ret = qib_msi_setup(dd, pos); else qib_dev_err(dd, "No PCI MSI or MSIx capability!\n"); } if (!pos) qib_enable_intx(dd->pcidev); pcie_capability_read_word(dd->pcidev, PCI_EXP_LNKSTA, &linkstat); /* * speed is bits 0-3, linkwidth is bits 4-8 * no defines for them in headers */ speed = linkstat & 0xf; linkstat >>= 4; linkstat &= 0x1f; dd->lbus_width = linkstat; switch (speed) { case 1: dd->lbus_speed = 2500; /* Gen1, 2.5GHz */ break; case 2: dd->lbus_speed = 5000; /* Gen1, 5GHz */ break; default: /* not defined, assume gen1 */ dd->lbus_speed = 2500; break; } /* * Check against expected pcie width and complain if "wrong" * on first initialization, not afterwards (i.e., reset). */ if (minw && linkstat < minw) qib_dev_err(dd, "PCIe width %u (x%u HCA), performance reduced\n", linkstat, minw); qib_tune_pcie_caps(dd); qib_tune_pcie_coalesce(dd); bail: /* fill in string, even on errors */ snprintf(dd->lbus_info, sizeof(dd->lbus_info), "PCIe,%uMHz,x%u\n", dd->lbus_speed, dd->lbus_width); return ret; }