From 6b87e700cd65120b70aaa097a8f4e7f22f1945ee Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 26 Oct 2013 18:23:25 +0100 Subject: PCI: Update pcie_ports 'auto' behavior for non-ACPI platforms The pcie_ports parameter, which defaults to 'auto', allows a user to specify if PCIe port services are disabled ('compat'), always enabled ('native'), or only used when allowed by the BIOS ('auto'). Where CONFIG_ACPI isn't enabled, as is often the case for non x86/ia64 platforms, the 'auto' behavior results in that of 'compat'. Thus in order to use port services on these platforms 'pcie_ports=native' must be added to the kernel command line. This patch results in the 'native' behavior being followed where 'auto' is selected and ACPI is not enabled. Signed-off-by: Andrew Murray Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/portdrv_core.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 31063ac..08d131f 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -260,13 +260,14 @@ static int get_port_device_capability(struct pci_dev *dev) if (pcie_ports_disabled) return 0; - err = pcie_port_platform_notify(dev, &cap_mask); - if (!pcie_ports_auto) { - cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP - | PCIE_PORT_SERVICE_VC; - if (pci_aer_available()) - cap_mask |= PCIE_PORT_SERVICE_AER; - } else if (err) { + cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP + | PCIE_PORT_SERVICE_VC; + if (pci_aer_available()) + cap_mask |= PCIE_PORT_SERVICE_AER; + + if (pcie_ports_auto) { + err = pcie_port_platform_notify(dev, &cap_mask); + if (err) return 0; } -- cgit v1.1 From cf3e1feba7f906f233790f1806592730a88f584d Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 5 Nov 2013 13:34:38 -0700 Subject: PCI: Workaround missing pci_set_master in pci drivers Ben Herrenschmidt found that commit 928bea964827 ("PCI: Delay enabling bridges until they're needed") breaks PCI in some powerpc environments. The reason is that the PCIe port driver will call pci_enable_device() on the bridge, so the device is enabled, but skips pci_set_master because pcie_port_auto and no acpi on powerpc. Because of that, pci_enable_bridge() later on (called as a result of the child device driver doing pci_enable_device) will see the bridge as already enabled and will not call pci_set_master() on it. Fixed by add checking in pci_enable_bridge, and call pci_set_master if driver skip that. That will make the code more robot and wade off problem for missing pci_set_master in drivers. Reported-by: Benjamin Herrenschmidt Signed-off-by: Yinghai Lu Signed-off-by: Linus Torvalds --- drivers/pci/pci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 36cc8d5..7a92d81 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1155,8 +1155,14 @@ static void pci_enable_bridge(struct pci_dev *dev) pci_enable_bridge(dev->bus->self); - if (pci_is_enabled(dev)) + if (pci_is_enabled(dev)) { + if (!dev->is_busmaster) { + dev_warn(&dev->dev, "driver skip pci_set_master, fix it!\n"); + pci_set_master(dev); + } return; + } + retval = pci_enable_device(dev); if (retval) dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n", -- cgit v1.1 From fbeeb822f6f45cadf154d7b7cff1c13537cd799d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 5 Nov 2013 13:34:51 -0700 Subject: PCI: Drop warning about drivers that don't use pci_set_master() f41f064cf4 ("PCI: Workaround missing pci_set_master in pci drivers") made pci_enable_bridge() turn on bus mastering if the driver hadn't done so already. It also added a warning in this case. But there's no reason to warn about it unless it's actually a problem to enable bus mastering here. This patch drops the warning because I'm not aware of any such problem. Signed-off-by: Bjorn Helgaas CC: Paul Bolle --- drivers/pci/pci.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7a92d81..ac40f90 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1156,10 +1156,8 @@ static void pci_enable_bridge(struct pci_dev *dev) pci_enable_bridge(dev->bus->self); if (pci_is_enabled(dev)) { - if (!dev->is_busmaster) { - dev_warn(&dev->dev, "driver skip pci_set_master, fix it!\n"); + if (!dev->is_busmaster) pci_set_master(dev); - } return; } -- cgit v1.1 From f92d74c1f5afaff7cd1ea14ade8f1ba6b519e422 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Fri, 1 Nov 2013 14:34:55 -0500 Subject: PCI: Warn on driver probe return value greater than zero Ages ago, drivers could return values greater than zero from their probe function and this would be regarded as success. But after f3ec4f87d607 ("PCI: change device runtime PM settings for probe and remove") and 967577b06241 ("PCI/PM: Keep runtime PM enabled for unbound PCI devices"), we set dev->driver to NULL if the driver's probe function returns a value greater than zero. __pci_device_probe() treats this as success, and drivers can still mostly work even with dev->driver == NULL, but PCI power management doesn't work, and we don't call the driver's remove function on rmmod. To help catch these driver problems, issue a warning in this case. [bhelgaas: changelog] Signed-off-by: Stephen M. Cameron Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-driver.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index b60fe67..0929ae3e 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -264,11 +264,19 @@ static long local_pci_probe(void *_ddi) pm_runtime_get_sync(dev); pci_dev->driver = pci_drv; rc = pci_drv->probe(pci_dev, ddi->id); - if (rc) { + if (!rc) + return rc; + if (rc < 0) { pci_dev->driver = NULL; pm_runtime_put_sync(dev); + return rc; } - return rc; + /* + * Probe function should return < 0 for failure, 0 for success + * Treat values > 0 as success, but warn. + */ + dev_warn(dev, "Driver probe function unexpectedly returned %d\n", rc); + return 0; } static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, -- cgit v1.1