From 49db139955d3392c6c4facf987905d0a9afed581 Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Tue, 13 May 2008 11:15:05 +0800 Subject: PCI: Disable PME during PCI scan If a device supports #PME and can generate PME events from D0, we may see superfluous events before a driver is loaded (drivers should only enable PME as needed), preventing suspend from working if the corresponding GPE was enabled. Likewise, if the ACPI device has the _PRW object, the _PSW/_DSW object will be called in order to disable the wakeup functionality. But when it is allowed to wake up the sleeping state, OSPM will enable it again. So we should disable PME in the course of scanning PCI devices and enable it again only when PME events are actually required to be generated from the requested PCI state (for example, D3_hot or D3_cold). It is also safe to disable PME again when the PME is disabled for the PCI devices. Signed-off-by: Zhao Yakui Signed-off-by: Li Shaohua Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 3706ce7972d..aebab71abeb 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -857,6 +857,49 @@ int pci_cfg_space_size_ext(struct pci_dev *dev) return PCI_CFG_SPACE_SIZE; } +/** + * pci_disable_pme - Disable the PME function of PCI device + * @dev: PCI device affected + * -EINVAL is returned if PCI device doesn't support PME. + * Zero is returned if the PME is supported and can be disabled. + */ +static int pci_disable_pme(struct pci_dev *dev) +{ + int pm; + u16 value; + + /* find PCI PM capability in list */ + pm = pci_find_capability(dev, PCI_CAP_ID_PM); + + /* If device doesn't support PM Capabilities, it means that PME is + * not supported. + */ + if (!pm) + return -EINVAL; + /* Check device's ability to generate PME# */ + pci_read_config_word(dev, pm + PCI_PM_PMC, &value); + + value &= PCI_PM_CAP_PME_MASK; + /* Check if it can generate PME# */ + if (!value) { + /* + * If it is zero, it means that PME is still unsupported + * although there exists the PM capability. + */ + return -EINVAL; + } + + pci_read_config_word(dev, pm + PCI_PM_CTRL, &value); + + /* Clear PME_Status by writing 1 to it */ + value |= PCI_PM_CTRL_PME_STATUS ; + /* Disable PME enable bit */ + value &= ~PCI_PM_CTRL_PME_ENABLE; + pci_write_config_word(dev, pm + PCI_PM_CTRL, value); + + return 0; +} + int pci_cfg_space_size(struct pci_dev *dev) { int pos; @@ -964,6 +1007,7 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) } pci_vpd_pci22_init(dev); + pci_disable_pme(dev); return dev; } -- cgit v1.2.3 From f46753c5e354b857b20ab8e0fe7b2579831dc369 Mon Sep 17 00:00:00 2001 From: Alex Chiang Date: Tue, 10 Jun 2008 15:28:50 -0600 Subject: PCI: introduce pci_slot Currently, /sys/bus/pci/slots/ only exposes hotplug attributes when a hotplug driver is loaded, but PCI slots have attributes such as address, speed, width, etc. that are not related to hotplug at all. Introduce pci_slot as the primary data structure and kobject model. Hotplug attributes described in hotplug_slot become a secondary structure associated with the pci_slot. This patch only creates the infrastructure that allows the separation of PCI slot attributes and hotplug attributes. In this patch, the PCI hotplug core remains the only user of this infrastructure, and thus, /sys/bus/pci/slots/ will still only become populated when a hotplug driver is loaded. A later patch in this series will add a second user of this new infrastructure and demonstrate splitting the task of exposing pci_slot attributes from hotplug_slot attributes. - Make pci_slot the primary sysfs entity. hotplug_slot becomes a subsidiary structure. o pci_create_slot() creates and registers a slot with the PCI core o pci_slot_add_hotplug() gives it hotplug capability - Change the prototype of pci_hp_register() to take the bus and slot number (on parent bus) as parameters. - Remove all the ->get_address methods since this functionality is now handled by pci_slot directly. [achiang@hp.com: rpaphp-correctly-pci_hp_register-for-empty-pci-slots] Tested-by: Badari Pulavarty Acked-by: Benjamin Herrenschmidt [akpm@linux-foundation.org: build fix] [akpm@linux-foundation.org: make headers_check happy] [akpm@linux-foundation.org: nuther build fix] [akpm@linux-foundation.org: fix typo in #include] Signed-off-by: Alex Chiang Signed-off-by: Matthew Wilcox Cc: Greg KH Cc: Kristen Carlson Accardi Cc: Len Brown Acked-by: Kenji Kaneshige Signed-off-by: Andrew Morton Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index aebab71abeb..4562827b7e2 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -414,6 +414,7 @@ static struct pci_bus * pci_alloc_bus(void) INIT_LIST_HEAD(&b->node); INIT_LIST_HEAD(&b->children); INIT_LIST_HEAD(&b->devices); + INIT_LIST_HEAD(&b->slots); } return b; } -- cgit v1.2.3 From 80ccba1186d48fa728dc4b1456cc07ffb07da501 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 13 Jun 2008 10:52:11 -0600 Subject: PCI: use dev_printk when possible Convert printks to use dev_printk(). I converted pr_debug() to dev_dbg(). Both use KERN_DEBUG and are enabled only when DEBUG is defined. I converted printk(KERN_DEBUG) to dev_printk(KERN_DEBUG), not to dev_dbg(), because dev_dbg() is only enabled when DEBUG is defined. I converted DBG(KERN_INFO) (only in setup-bus.c) to dev_info(). The DBG() name makes it sound like debug, but it's been enabled forever, so dev_info() preserves the previous behavior. I tried to make the resource assignment formats more consistent, e.g., "BAR %d: got res [%#llx-%#llx] bus [%#llx-%#llx] flags %#lx\n" instead of sometimes using "start-end" and sometimes using "size@start". I'm not attached to one or the other; I'd just like them consistent. Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 4562827b7e2..f8291191ef9 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -277,8 +277,8 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) res->end = res->start + sz64; #else if (sz64 > 0x100000000ULL) { - printk(KERN_ERR "PCI: Unable to handle 64-bit " - "BAR for device %s\n", pci_name(dev)); + dev_err(&dev->dev, "BAR %d: can't handle 64-bit" + " BAR\n", pos); res->start = 0; res->flags = 0; } else if (lhi) { @@ -329,7 +329,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) return; if (dev->transparent) { - printk(KERN_INFO "PCI: Transparent bridge - %s\n", pci_name(dev)); + dev_info(&dev->dev, "transparent bridge\n"); for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++) child->resource[i] = child->parent->resource[i - 3]; } @@ -392,7 +392,8 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) limit |= ((long) mem_limit_hi) << 32; #else if (mem_base_hi || mem_limit_hi) { - printk(KERN_ERR "PCI: Unable to handle 64-bit address space for bridge %s\n", pci_name(dev)); + dev_err(&dev->dev, "can't handle 64-bit " + "address space for bridge\n"); return; } #endif @@ -512,8 +513,8 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); - pr_debug("PCI: Scanning behind PCI bridge %s, config %06x, pass %d\n", - pci_name(dev), buses & 0xffffff, pass); + dev_dbg(&dev->dev, "scanning behind bridge, config %06x, pass %d\n", + buses & 0xffffff, pass); /* Disable MasterAbortMode during probing to avoid reporting of bus errors (in some architectures) */ @@ -536,8 +537,8 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, * ignore it. This can happen with the i450NX chipset. */ if (pci_find_bus(pci_domain_nr(bus), busnr)) { - printk(KERN_INFO "PCI: Bus %04x:%02x already known\n", - pci_domain_nr(bus), busnr); + dev_info(&dev->dev, "bus %04x:%02x already known\n", + pci_domain_nr(bus), busnr); goto out; } @@ -721,7 +722,7 @@ static int pci_setup_device(struct pci_dev * dev) dev->class = class; class >>= 8; - pr_debug("PCI: Found %s [%04x/%04x] %06x %02x\n", pci_name(dev), + dev_dbg(&dev->dev, "found [%04x/%04x] class %06x header type %02x\n", dev->vendor, dev->device, class, dev->hdr_type); /* "Unknown power state" */ @@ -789,13 +790,13 @@ static int pci_setup_device(struct pci_dev * dev) break; default: /* unknown header */ - printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n", - pci_name(dev), dev->hdr_type); + dev_err(&dev->dev, "unknown header type %02x, " + "ignoring device\n", dev->hdr_type); return -1; bad: - printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n", - pci_name(dev), class, dev->hdr_type); + dev_err(&dev->dev, "ignoring class %02x (doesn't match header " + "type %02x)\n", class, dev->hdr_type); dev->class = PCI_CLASS_NOT_DEFINED; } @@ -971,7 +972,7 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) return NULL; /* Card hasn't responded in 60 seconds? Must be stuck. */ if (delay > 60 * 1000) { - printk(KERN_WARNING "Device %04x:%02x:%02x.%d not " + printk(KERN_WARNING "pci %04x:%02x:%02x.%d: not " "responding\n", pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); -- cgit v1.2.3 From 8b285ce84bbc719e363a796f466404576b840d36 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 27 Jun 2008 13:23:20 +0100 Subject: PCI: fix pci_setup_device()'s sprinting into a const buffer Make pci_setup_device() write the bus ID directly into the allotted storage, rather than using pci_name() as the address as that now returns a const pointer. Signed-off-by: David Howells Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f8291191ef9..0420fd8027b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -713,8 +713,9 @@ static int pci_setup_device(struct pci_dev * dev) { u32 class; - sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus), - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + snprintf(dev->dev.bus_id, BUS_ID_SIZE, + "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus), + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); dev->revision = class & 0xff; -- cgit v1.2.3 From eebfcfb52ce753eaaa8525078bda6b539586066c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 2 Jul 2008 13:24:49 -0700 Subject: PCI: handle pci_name() being const This changes pci_setup_device to handle pci_name() now returning a constant string. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 0420fd8027b..2f0ae70710d 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -713,9 +713,9 @@ static int pci_setup_device(struct pci_dev * dev) { u32 class; - snprintf(dev->dev.bus_id, BUS_ID_SIZE, - "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus), - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus), + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); dev->revision = class & 0xff; -- cgit v1.2.3 From eb9d0fe40e313c0a74115ef456a2e43a6c8da72f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 7 Jul 2008 03:34:48 +0200 Subject: PCI ACPI: Rework PCI handling of wake-up * Introduce function acpi_pm_device_sleep_wake() for enabling and disabling the system wake-up capability of devices that are power manageable by ACPI. * Introduce function acpi_bus_can_wakeup() allowing other (dependent) subsystems to check if ACPI is able to enable the system wake-up capability of given device. * Introduce callback .sleep_wake() in struct pci_platform_pm_ops and for the ACPI PCI 'driver' make it use acpi_pm_device_sleep_wake(). * Introduce callback .can_wakeup() in struct pci_platform_pm_ops and for the ACPI 'driver' make it use acpi_bus_can_wakeup(). * Move the PME# handlig code out of pci_enable_wake() and split it into two functions, pci_pme_capable() and pci_pme_active(), allowing the caller to check if given device is capable of generating PME# from given power state and to enable/disable the device's PME# functionality, respectively. * Modify pci_enable_wake() to use the new ACPI callbacks and the new PME#-related functions. * Drop the generic .platform_enable_wakeup() callback that is not used any more. * Introduce device_set_wakeup_capable() that will set the power.can_wakeup flag of given device. * Rework PCI device PM initialization so that, if given device is capable of generating wake-up events, either natively through the PME# mechanism, or with the help of the platform, its power.can_wakeup flag is set and its power.should_wakeup flag is unset as appropriate. * Make ACPI set the power.can_wakeup flag for devices found to be wake-up capable by it. * Make the ACPI wake-up code enable/disable GPEs for devices that have the wakeup.flags.prepared flag set (which means that their wake-up power has been enabled). Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 47 +++-------------------------------------------- 1 file changed, 3 insertions(+), 44 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2f0ae70710d..b1724cf31b6 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -860,49 +860,6 @@ int pci_cfg_space_size_ext(struct pci_dev *dev) return PCI_CFG_SPACE_SIZE; } -/** - * pci_disable_pme - Disable the PME function of PCI device - * @dev: PCI device affected - * -EINVAL is returned if PCI device doesn't support PME. - * Zero is returned if the PME is supported and can be disabled. - */ -static int pci_disable_pme(struct pci_dev *dev) -{ - int pm; - u16 value; - - /* find PCI PM capability in list */ - pm = pci_find_capability(dev, PCI_CAP_ID_PM); - - /* If device doesn't support PM Capabilities, it means that PME is - * not supported. - */ - if (!pm) - return -EINVAL; - /* Check device's ability to generate PME# */ - pci_read_config_word(dev, pm + PCI_PM_PMC, &value); - - value &= PCI_PM_CAP_PME_MASK; - /* Check if it can generate PME# */ - if (!value) { - /* - * If it is zero, it means that PME is still unsupported - * although there exists the PM capability. - */ - return -EINVAL; - } - - pci_read_config_word(dev, pm + PCI_PM_CTRL, &value); - - /* Clear PME_Status by writing 1 to it */ - value |= PCI_PM_CTRL_PME_STATUS ; - /* Disable PME enable bit */ - value &= ~PCI_PM_CTRL_PME_ENABLE; - pci_write_config_word(dev, pm + PCI_PM_CTRL, value); - - return 0; -} - int pci_cfg_space_size(struct pci_dev *dev) { int pos; @@ -1010,7 +967,6 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) } pci_vpd_pci22_init(dev); - pci_disable_pme(dev); return dev; } @@ -1031,6 +987,9 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) /* Fix up broken headers */ pci_fixup_device(pci_fixup_header, dev); + /* Initialize power management of the device */ + pci_pm_init(dev); + /* * Add the device to our list of discovered devices * and the bus list for fixup functions, etc. -- cgit v1.2.3