diff options
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r-- | drivers/pci/pci.c | 176 |
1 files changed, 138 insertions, 38 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d549bbc..4c3a9e9 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -77,6 +77,8 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE; unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE; +enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF; + /* * The default CLS is used if arch didn't set CLS explicitly and not * all pci devices agree on the same value. Arch can override either @@ -662,12 +664,11 @@ static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state) error = platform_pci_set_power_state(dev, state); if (!error) pci_update_current_state(dev, state); - } else { + } else error = -ENODEV; - /* Fall back to PCI_D0 if native PM is not supported */ - if (!dev->pm_cap) - dev->current_state = PCI_D0; - } + + if (error && !dev->pm_cap) /* Fall back to PCI_D0 */ + dev->current_state = PCI_D0; return error; } @@ -1077,6 +1078,8 @@ EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state); static int do_pci_enable_device(struct pci_dev *dev, int bars) { int err; + u16 cmd; + u8 pin; err = pci_set_power_state(dev, PCI_D0); if (err < 0 && err != -EIO) @@ -1086,6 +1089,17 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars) return err; pci_fixup_device(pci_fixup_enable, dev); + if (dev->msi_enabled || dev->msix_enabled) + return 0; + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (pin) { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (cmd & PCI_COMMAND_INTX_DISABLE) + pci_write_config_word(dev, PCI_COMMAND, + cmd & ~PCI_COMMAND_INTX_DISABLE); + } + return 0; } @@ -1124,7 +1138,11 @@ static int __pci_enable_device_flags(struct pci_dev *dev, if (atomic_add_return(1, &dev->enable_cnt) > 1) return 0; /* already enabled */ - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) + /* only skip sriov related */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) + if (dev->resource[i].flags & flags) + bars |= (1 << i); + for (i = PCI_BRIDGE_RESOURCES; i < DEVICE_COUNT_RESOURCE; i++) if (dev->resource[i].flags & flags) bars |= (1 << i); @@ -1405,13 +1423,16 @@ bool pci_check_pme_status(struct pci_dev *dev) /** * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set. * @dev: Device to handle. - * @ign: Ignored. + * @pme_poll_reset: Whether or not to reset the device's pme_poll flag. * * Check if @dev has generated PME and queue a resume request for it in that * case. */ -static int pci_pme_wakeup(struct pci_dev *dev, void *ign) +static int pci_pme_wakeup(struct pci_dev *dev, void *pme_poll_reset) { + if (pme_poll_reset && dev->pme_poll) + dev->pme_poll = false; + if (pci_check_pme_status(dev)) { pci_wakeup_event(dev); pm_request_resume(&dev->dev); @@ -1426,7 +1447,7 @@ static int pci_pme_wakeup(struct pci_dev *dev, void *ign) void pci_pme_wakeup_bus(struct pci_bus *bus) { if (bus) - pci_walk_bus(bus, pci_pme_wakeup, NULL); + pci_walk_bus(bus, pci_pme_wakeup, (void *)true); } /** @@ -1444,31 +1465,26 @@ bool pci_pme_capable(struct pci_dev *dev, pci_power_t state) static void pci_pme_list_scan(struct work_struct *work) { - struct pci_pme_device *pme_dev; + struct pci_pme_device *pme_dev, *n; mutex_lock(&pci_pme_list_mutex); if (!list_empty(&pci_pme_list)) { - list_for_each_entry(pme_dev, &pci_pme_list, list) - pci_pme_wakeup(pme_dev->dev, NULL); - schedule_delayed_work(&pci_pme_work, msecs_to_jiffies(PME_TIMEOUT)); + list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) { + if (pme_dev->dev->pme_poll) { + pci_pme_wakeup(pme_dev->dev, NULL); + } else { + list_del(&pme_dev->list); + kfree(pme_dev); + } + } + if (!list_empty(&pci_pme_list)) + schedule_delayed_work(&pci_pme_work, + msecs_to_jiffies(PME_TIMEOUT)); } mutex_unlock(&pci_pme_list_mutex); } /** - * pci_external_pme - is a device an external PCI PME source? - * @dev: PCI device to check - * - */ - -static bool pci_external_pme(struct pci_dev *dev) -{ - if (pci_is_pcie(dev) || dev->bus->number == 0) - return false; - return true; -} - -/** * pci_pme_active - enable or disable PCI device's PME# function * @dev: PCI device to handle. * @enable: 'true' to enable PME# generation; 'false' to disable it. @@ -1501,7 +1517,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable) hit, and the power savings from the devices will still be a win. */ - if (pci_external_pme(dev)) { + if (dev->pme_poll) { struct pci_pme_device *pme_dev; if (enable) { pme_dev = kmalloc(sizeof(struct pci_pme_device), @@ -1819,6 +1835,7 @@ void pci_pm_init(struct pci_dev *dev) (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "", (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : ""); dev->pme_support = pmc >> PCI_PM_CAP_PME_SHIFT; + dev->pme_poll = true; /* * Make device's PM flags reflect the wake-up capability, but * let the user space enable it to wake up the system as needed. @@ -1911,10 +1928,6 @@ void pci_enable_ari(struct pci_dev *dev) if (!pci_is_pcie(dev) || dev->devfn) return; - pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); - if (!pos) - return; - bridge = dev->bus->self; if (!bridge || !pci_is_pcie(bridge)) return; @@ -1933,10 +1946,14 @@ void pci_enable_ari(struct pci_dev *dev) return; pci_read_config_word(bridge, pos + PCI_EXP_DEVCTL2, &ctrl); - ctrl |= PCI_EXP_DEVCTL2_ARI; + if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI)) { + ctrl |= PCI_EXP_DEVCTL2_ARI; + bridge->ari_enabled = 1; + } else { + ctrl &= ~PCI_EXP_DEVCTL2_ARI; + bridge->ari_enabled = 0; + } pci_write_config_word(bridge, pos + PCI_EXP_DEVCTL2, ctrl); - - bridge->ari_enabled = 1; } /** @@ -3191,7 +3208,7 @@ EXPORT_SYMBOL(pcie_get_readrq); * @rq: maximum memory read count in bytes * valid values are 128, 256, 512, 1024, 2048, 4096 * - * If possible sets maximum read byte count + * If possible sets maximum memory read request in bytes */ int pcie_set_readrq(struct pci_dev *dev, int rq) { @@ -3201,8 +3218,6 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) if (rq < 128 || rq > 4096 || !is_power_of_2(rq)) goto out; - v = (ffs(rq) - 8) << 12; - cap = pci_pcie_cap(dev); if (!cap) goto out; @@ -3210,11 +3225,27 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl); if (err) goto out; + /* + * If using the "performance" PCIe config, we clamp the + * read rq size to the max packet size to prevent the + * host bridge generating requests larger than we can + * cope with + */ + if (pcie_bus_config == PCIE_BUS_PERFORMANCE) { + int mps = pcie_get_mps(dev); + + if (mps < 0) + return mps; + if (mps < rq) + rq = mps; + } + + v = (ffs(rq) - 8) << 12; if ((ctl & PCI_EXP_DEVCTL_READRQ) != v) { ctl &= ~PCI_EXP_DEVCTL_READRQ; ctl |= v; - err = pci_write_config_dword(dev, cap + PCI_EXP_DEVCTL, ctl); + err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, ctl); } out: @@ -3223,6 +3254,67 @@ out: EXPORT_SYMBOL(pcie_set_readrq); /** + * pcie_get_mps - get PCI Express maximum payload size + * @dev: PCI device to query + * + * Returns maximum payload size in bytes + * or appropriate error value. + */ +int pcie_get_mps(struct pci_dev *dev) +{ + int ret, cap; + u16 ctl; + + cap = pci_pcie_cap(dev); + if (!cap) + return -EINVAL; + + ret = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl); + if (!ret) + ret = 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5); + + return ret; +} + +/** + * pcie_set_mps - set PCI Express maximum payload size + * @dev: PCI device to query + * @mps: maximum payload size in bytes + * valid values are 128, 256, 512, 1024, 2048, 4096 + * + * If possible sets maximum payload size + */ +int pcie_set_mps(struct pci_dev *dev, int mps) +{ + int cap, err = -EINVAL; + u16 ctl, v; + + if (mps < 128 || mps > 4096 || !is_power_of_2(mps)) + goto out; + + v = ffs(mps) - 8; + if (v > dev->pcie_mpss) + goto out; + v <<= 5; + + cap = pci_pcie_cap(dev); + if (!cap) + goto out; + + err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl); + if (err) + goto out; + + if ((ctl & PCI_EXP_DEVCTL_PAYLOAD) != v) { + ctl &= ~PCI_EXP_DEVCTL_PAYLOAD; + ctl |= v; + err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, ctl); + } +out: + return err; +} + +/** * pci_select_bars - Make BAR mask from the type of resource * @dev: the PCI device for which BAR mask is made * @flags: resource type mask to be selected @@ -3505,6 +3597,14 @@ static int __init pci_setup(char *str) pci_hotplug_io_size = memparse(str + 9, &str); } else if (!strncmp(str, "hpmemsize=", 10)) { pci_hotplug_mem_size = memparse(str + 10, &str); + } else if (!strncmp(str, "pcie_bus_tune_off", 17)) { + pcie_bus_config = PCIE_BUS_TUNE_OFF; + } else if (!strncmp(str, "pcie_bus_safe", 13)) { + pcie_bus_config = PCIE_BUS_SAFE; + } else if (!strncmp(str, "pcie_bus_perf", 13)) { + pcie_bus_config = PCIE_BUS_PERFORMANCE; + } else if (!strncmp(str, "pcie_bus_peer2peer", 18)) { + pcie_bus_config = PCIE_BUS_PEER2PEER; } else { printk(KERN_ERR "PCI: Unknown option `%s'\n", str); |