提交 dc7c65db 编写于 作者: L Linus Torvalds

Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6

* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (72 commits)
  Revert "x86/PCI: ACPI based PCI gap calculation"
  PCI: remove unnecessary volatile in PCIe hotplug struct controller
  x86/PCI: ACPI based PCI gap calculation
  PCI: include linux/pm_wakeup.h for device_set_wakeup_capable
  PCI PM: Fix pci_prepare_to_sleep
  x86/PCI: Fix PCI config space for domains > 0
  Fix acpi_pm_device_sleep_wake() by providing a stub for CONFIG_PM_SLEEP=n
  PCI: Simplify PCI device PM code
  PCI PM: Introduce pci_prepare_to_sleep and pci_back_from_sleep
  PCI ACPI: Rework PCI handling of wake-up
  ACPI: Introduce new device wakeup flag 'prepared'
  ACPI: Introduce acpi_device_sleep_wake function
  PCI: rework pci_set_power_state function to call platform first
  PCI: Introduce platform_pci_power_manageable function
  ACPI: Introduce acpi_bus_power_manageable function
  PCI: make pci_name use dev_name
  PCI: handle pci_name() being const
  PCI: add stub for pci_set_consistent_dma_mask()
  PCI: remove unused arch pcibios_update_resource() functions
  PCI: fix pci_setup_device()'s sprinting into a const buffer
  ...

Fixed up conflicts in various files (arch/x86/kernel/setup_64.c,
arch/x86/pci/irq.c, arch/x86/pci/pci.h, drivers/acpi/sleep/main.c,
drivers/pci/pci.c, drivers/pci/pci.h, include/acpi/acpi_bus.h) from x86
and ACPI updates manually.
...@@ -147,10 +147,14 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -147,10 +147,14 @@ and is between 256 and 4096 characters. It is defined in the file
default: 0 default: 0
acpi_sleep= [HW,ACPI] Sleep options acpi_sleep= [HW,ACPI] Sleep options
Format: { s3_bios, s3_mode, s3_beep } Format: { s3_bios, s3_mode, s3_beep, old_ordering }
See Documentation/power/video.txt for s3_bios and s3_mode. See Documentation/power/video.txt for s3_bios and s3_mode.
s3_beep is for debugging; it makes the PC's speaker beep s3_beep is for debugging; it makes the PC's speaker beep
as soon as the kernel's real-mode entry point is called. as soon as the kernel's real-mode entry point is called.
old_ordering causes the ACPI 1.0 ordering of the _PTS
control method, wrt putting devices into low power
states, to be enforced (the ACPI 2.0 ordering of _PTS is
used by default).
acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode
Format: { level | edge | high | low } Format: { level | edge | high | low }
...@@ -1537,6 +1541,9 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -1537,6 +1541,9 @@ and is between 256 and 4096 characters. It is defined in the file
Use with caution as certain devices share Use with caution as certain devices share
address decoders between ROMs and other address decoders between ROMs and other
resources. resources.
norom [X86-32,X86_64] Do not assign address space to
expansion ROMs that do not already have
BIOS assigned address ranges.
irqmask=0xMMMM [X86-32] Set a bit mask of IRQs allowed to be irqmask=0xMMMM [X86-32] Set a bit mask of IRQs allowed to be
assigned automatically to PCI devices. You can assigned automatically to PCI devices. You can
make the kernel exclude IRQs of your ISA cards make the kernel exclude IRQs of your ISA cards
......
...@@ -248,7 +248,7 @@ S: Supported ...@@ -248,7 +248,7 @@ S: Supported
ACPI PCI HOTPLUG DRIVER ACPI PCI HOTPLUG DRIVER
P: Kristen Carlson Accardi P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com M: kristen.c.accardi@intel.com
L: pcihpd-discuss@lists.sourceforge.net L: linux-pci@vger.kernel.org
S: Supported S: Supported
ACPI THERMAL DRIVER ACPI THERMAL DRIVER
...@@ -1145,21 +1145,21 @@ COMPACTPCI HOTPLUG CORE ...@@ -1145,21 +1145,21 @@ COMPACTPCI HOTPLUG CORE
P: Scott Murray P: Scott Murray
M: scottm@somanetworks.com M: scottm@somanetworks.com
M: scott@spiteful.org M: scott@spiteful.org
L: pcihpd-discuss@lists.sourceforge.net L: linux-pci@vger.kernel.org
S: Supported S: Supported
COMPACTPCI HOTPLUG ZIATECH ZT5550 DRIVER COMPACTPCI HOTPLUG ZIATECH ZT5550 DRIVER
P: Scott Murray P: Scott Murray
M: scottm@somanetworks.com M: scottm@somanetworks.com
M: scott@spiteful.org M: scott@spiteful.org
L: pcihpd-discuss@lists.sourceforge.net L: linux-pci@vger.kernel.org
S: Supported S: Supported
COMPACTPCI HOTPLUG GENERIC DRIVER COMPACTPCI HOTPLUG GENERIC DRIVER
P: Scott Murray P: Scott Murray
M: scottm@somanetworks.com M: scottm@somanetworks.com
M: scott@spiteful.org M: scott@spiteful.org
L: pcihpd-discuss@lists.sourceforge.net L: linux-pci@vger.kernel.org
S: Supported S: Supported
COMPAL LAPTOP SUPPORT COMPAL LAPTOP SUPPORT
...@@ -3219,7 +3219,7 @@ S: Supported ...@@ -3219,7 +3219,7 @@ S: Supported
PCIE HOTPLUG DRIVER PCIE HOTPLUG DRIVER
P: Kristen Carlson Accardi P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com M: kristen.c.accardi@intel.com
L: pcihpd-discuss@lists.sourceforge.net L: linux-pci@vger.kernel.org
S: Supported S: Supported
PCMCIA SUBSYSTEM PCMCIA SUBSYSTEM
...@@ -3865,7 +3865,7 @@ S: Maintained ...@@ -3865,7 +3865,7 @@ S: Maintained
SHPC HOTPLUG DRIVER SHPC HOTPLUG DRIVER
P: Kristen Carlson Accardi P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com M: kristen.c.accardi@intel.com
L: pcihpd-discuss@lists.sourceforge.net L: linux-pci@vger.kernel.org
S: Supported S: Supported
SECURE DIGITAL HOST CONTROLLER INTERFACE DRIVER SECURE DIGITAL HOST CONTROLLER INTERFACE DRIVER
......
...@@ -19,36 +19,6 @@ ...@@ -19,36 +19,6 @@
#include "pci-frv.h" #include "pci-frv.h"
#if 0
void
pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
{
u32 new, check;
int reg;
new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
if (resource < 6) {
reg = PCI_BASE_ADDRESS_0 + 4*resource;
} else if (resource == PCI_ROM_RESOURCE) {
res->flags |= IORESOURCE_ROM_ENABLE;
new |= PCI_ROM_ADDRESS_ENABLE;
reg = dev->rom_base_reg;
} else {
/* Somebody might have asked allocation of a non-standard resource */
return;
}
pci_write_config_dword(dev, reg, new);
pci_read_config_dword(dev, reg, &check);
if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
printk(KERN_ERR "PCI: Error while updating region "
"%s/%d (%08x != %08x)\n", pci_name(dev), resource,
new, check);
}
}
#endif
/* /*
* We need to avoid collisions with `mirrored' VGA ports * We need to avoid collisions with `mirrored' VGA ports
* and other strange ISA hardware, so we always want the * and other strange ISA hardware, so we always want the
......
...@@ -373,15 +373,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) ...@@ -373,15 +373,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
return(0); return(0);
} }
/*****************************************************************************/
void pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *r, int resource)
{
printk(KERN_WARNING "%s(%d): no support for changing PCI resources...\n",
__FILE__, __LINE__);
}
/*****************************************************************************/ /*****************************************************************************/
/* /*
......
...@@ -345,42 +345,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) ...@@ -345,42 +345,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
return pcibios_enable_resources(dev); return pcibios_enable_resources(dev);
} }
void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
{
u32 new, check;
int reg;
return;
new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
if (resource < 6) {
reg = PCI_BASE_ADDRESS_0 + 4 * resource;
} else if (resource == PCI_ROM_RESOURCE) {
res->flags |= IORESOURCE_ROM_ENABLE;
reg = dev->rom_base_reg;
} else {
/*
* Somebody might have asked allocation of a non-standard
* resource
*/
return;
}
pci_write_config_dword(dev, reg, new);
pci_read_config_dword(dev, reg, &check);
if ((new ^ check) &
((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK :
PCI_BASE_ADDRESS_MEM_MASK)) {
printk(KERN_ERR "PCI: Error while updating region "
"%s/%d (%08x != %08x)\n", pci_name(dev), resource,
new, check);
}
}
void pcibios_align_resource(void *data, struct resource *res, void pcibios_align_resource(void *data, struct resource *res,
resource_size_t size, resource_size_t align) resource_size_t size, resource_size_t align)
{ {
......
...@@ -76,38 +76,6 @@ void __devinit __weak pcibios_fixup_bus(struct pci_bus *bus) ...@@ -76,38 +76,6 @@ void __devinit __weak pcibios_fixup_bus(struct pci_bus *bus)
pci_read_bridge_bases(bus); pci_read_bridge_bases(bus);
} }
void
pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
{
u32 new, check;
int reg;
new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
if (resource < 6) {
reg = PCI_BASE_ADDRESS_0 + 4*resource;
} else if (resource == PCI_ROM_RESOURCE) {
res->flags |= IORESOURCE_ROM_ENABLE;
new |= PCI_ROM_ADDRESS_ENABLE;
reg = dev->rom_base_reg;
} else {
/*
* Somebody might have asked allocation of a non-standard
* resource
*/
return;
}
pci_write_config_dword(dev, reg, new);
pci_read_config_dword(dev, reg, &check);
if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ?
PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
printk(KERN_ERR "PCI: Error while updating region "
"%s/%d (%08x != %08x)\n", pci_name(dev), resource,
new, check);
}
}
void pcibios_align_resource(void *data, struct resource *res, void pcibios_align_resource(void *data, struct resource *res,
resource_size_t size, resource_size_t align) resource_size_t size, resource_size_t align)
__attribute__ ((weak)); __attribute__ ((weak));
......
...@@ -408,7 +408,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, ...@@ -408,7 +408,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
dev->class = class >> 8; dev->class = class >> 8;
dev->revision = class & 0xff; dev->revision = class & 0xff;
sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), sprintf(dev->dev.bus_id, "%04x:%02x:%02x.%d", pci_domain_nr(bus),
dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
if (ofpci_verbose) if (ofpci_verbose)
......
...@@ -158,6 +158,8 @@ static int __init acpi_sleep_setup(char *str) ...@@ -158,6 +158,8 @@ static int __init acpi_sleep_setup(char *str)
acpi_realmode_flags |= 2; acpi_realmode_flags |= 2;
if (strncmp(str, "s3_beep", 7) == 0) if (strncmp(str, "s3_beep", 7) == 0)
acpi_realmode_flags |= 4; acpi_realmode_flags |= 4;
if (strncmp(str, "old_ordering", 12) == 0)
acpi_old_suspend_ordering();
str = strchr(str, ','); str = strchr(str, ',');
if (str != NULL) if (str != NULL)
str += strspn(str, ", \t"); str += strspn(str, ", \t");
......
...@@ -1213,9 +1213,9 @@ static int suspend(int vetoable) ...@@ -1213,9 +1213,9 @@ static int suspend(int vetoable)
if (err != APM_SUCCESS) if (err != APM_SUCCESS)
apm_error("suspend", err); apm_error("suspend", err);
err = (err == APM_SUCCESS) ? 0 : -EIO; err = (err == APM_SUCCESS) ? 0 : -EIO;
device_power_up(); device_power_up(PMSG_RESUME);
local_irq_enable(); local_irq_enable();
device_resume(); device_resume(PMSG_RESUME);
queue_event(APM_NORMAL_RESUME, NULL); queue_event(APM_NORMAL_RESUME, NULL);
spin_lock(&user_list_lock); spin_lock(&user_list_lock);
for (as = user_list; as != NULL; as = as->next) { for (as = user_list; as != NULL; as = as->next) {
...@@ -1240,7 +1240,7 @@ static void standby(void) ...@@ -1240,7 +1240,7 @@ static void standby(void)
apm_error("standby", err); apm_error("standby", err);
local_irq_disable(); local_irq_disable();
device_power_up(); device_power_up(PMSG_RESUME);
local_irq_enable(); local_irq_enable();
} }
...@@ -1326,7 +1326,7 @@ static void check_events(void) ...@@ -1326,7 +1326,7 @@ static void check_events(void)
ignore_bounce = 1; ignore_bounce = 1;
if ((event != APM_NORMAL_RESUME) if ((event != APM_NORMAL_RESUME)
|| (ignore_normal_resume == 0)) { || (ignore_normal_resume == 0)) {
device_resume(); device_resume(PMSG_RESUME);
queue_event(event, NULL); queue_event(event, NULL);
} }
ignore_normal_resume = 0; ignore_normal_resume = 0;
......
...@@ -120,7 +120,18 @@ static struct chipset early_qrk[] __initdata = { ...@@ -120,7 +120,18 @@ static struct chipset early_qrk[] __initdata = {
{} {}
}; };
static void __init check_dev_quirk(int num, int slot, int func) /**
* check_dev_quirk - apply early quirks to a given PCI device
* @num: bus number
* @slot: slot number
* @func: PCI function
*
* Check the vendor & device ID against the early quirks table.
*
* If the device is single function, let early_quirks() know so we don't
* poke at this device again.
*/
static int __init check_dev_quirk(int num, int slot, int func)
{ {
u16 class; u16 class;
u16 vendor; u16 vendor;
...@@ -131,7 +142,7 @@ static void __init check_dev_quirk(int num, int slot, int func) ...@@ -131,7 +142,7 @@ static void __init check_dev_quirk(int num, int slot, int func)
class = read_pci_config_16(num, slot, func, PCI_CLASS_DEVICE); class = read_pci_config_16(num, slot, func, PCI_CLASS_DEVICE);
if (class == 0xffff) if (class == 0xffff)
return; return -1; /* no class, treat as single function */
vendor = read_pci_config_16(num, slot, func, PCI_VENDOR_ID); vendor = read_pci_config_16(num, slot, func, PCI_VENDOR_ID);
...@@ -154,7 +165,9 @@ static void __init check_dev_quirk(int num, int slot, int func) ...@@ -154,7 +165,9 @@ static void __init check_dev_quirk(int num, int slot, int func)
type = read_pci_config_byte(num, slot, func, type = read_pci_config_byte(num, slot, func,
PCI_HEADER_TYPE); PCI_HEADER_TYPE);
if (!(type & 0x80)) if (!(type & 0x80))
return; return -1;
return 0;
} }
void __init early_quirks(void) void __init early_quirks(void)
...@@ -167,6 +180,9 @@ void __init early_quirks(void) ...@@ -167,6 +180,9 @@ void __init early_quirks(void)
/* Poor man's PCI discovery */ /* Poor man's PCI discovery */
for (num = 0; num < 32; num++) for (num = 0; num < 32; num++)
for (slot = 0; slot < 32; slot++) for (slot = 0; slot < 32; slot++)
for (func = 0; func < 8; func++) for (func = 0; func < 8; func++) {
check_dev_quirk(num, slot, func); /* Only probe function 0 on single fn devices */
if (check_dev_quirk(num, slot, func))
break;
}
} }
...@@ -684,6 +684,11 @@ void __init setup_arch(char **cmdline_p) ...@@ -684,6 +684,11 @@ void __init setup_arch(char **cmdline_p)
clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC);
} }
#ifdef CONFIG_PCI
if (pci_early_dump_regs)
early_dump_pci_devices();
#endif
finish_e820_parsing(); finish_e820_parsing();
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
PCI_PROBE_MMCONF; PCI_PROBE_MMCONF;
unsigned int pci_early_dump_regs;
static int pci_bf_sort; static int pci_bf_sort;
int pci_routeirq; int pci_routeirq;
int pcibios_last_bus = -1; int pcibios_last_bus = -1;
...@@ -31,7 +32,7 @@ struct pci_raw_ops *raw_pci_ext_ops; ...@@ -31,7 +32,7 @@ struct pci_raw_ops *raw_pci_ext_ops;
int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
int reg, int len, u32 *val) int reg, int len, u32 *val)
{ {
if (reg < 256 && raw_pci_ops) if (domain == 0 && reg < 256 && raw_pci_ops)
return raw_pci_ops->read(domain, bus, devfn, reg, len, val); return raw_pci_ops->read(domain, bus, devfn, reg, len, val);
if (raw_pci_ext_ops) if (raw_pci_ext_ops)
return raw_pci_ext_ops->read(domain, bus, devfn, reg, len, val); return raw_pci_ext_ops->read(domain, bus, devfn, reg, len, val);
...@@ -41,7 +42,7 @@ int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, ...@@ -41,7 +42,7 @@ int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
int reg, int len, u32 val) int reg, int len, u32 val)
{ {
if (reg < 256 && raw_pci_ops) if (domain == 0 && reg < 256 && raw_pci_ops)
return raw_pci_ops->write(domain, bus, devfn, reg, len, val); return raw_pci_ops->write(domain, bus, devfn, reg, len, val);
if (raw_pci_ext_ops) if (raw_pci_ext_ops)
return raw_pci_ext_ops->write(domain, bus, devfn, reg, len, val); return raw_pci_ext_ops->write(domain, bus, devfn, reg, len, val);
...@@ -121,6 +122,21 @@ void __init dmi_check_skip_isa_align(void) ...@@ -121,6 +122,21 @@ void __init dmi_check_skip_isa_align(void)
dmi_check_system(can_skip_pciprobe_dmi_table); dmi_check_system(can_skip_pciprobe_dmi_table);
} }
static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
{
struct resource *rom_r = &dev->resource[PCI_ROM_RESOURCE];
if (pci_probe & PCI_NOASSIGN_ROMS) {
if (rom_r->parent)
return;
if (rom_r->start) {
/* we deal with BIOS assigned ROM later */
return;
}
rom_r->start = rom_r->end = rom_r->flags = 0;
}
}
/* /*
* Called after each bus is probed, but before its children * Called after each bus is probed, but before its children
* are examined. * are examined.
...@@ -128,7 +144,11 @@ void __init dmi_check_skip_isa_align(void) ...@@ -128,7 +144,11 @@ void __init dmi_check_skip_isa_align(void)
void __devinit pcibios_fixup_bus(struct pci_bus *b) void __devinit pcibios_fixup_bus(struct pci_bus *b)
{ {
struct pci_dev *dev;
pci_read_bridge_bases(b); pci_read_bridge_bases(b);
list_for_each_entry(dev, &b->devices, bus_list)
pcibios_fixup_device_resources(dev);
} }
/* /*
...@@ -481,12 +501,18 @@ char * __devinit pcibios_setup(char *str) ...@@ -481,12 +501,18 @@ char * __devinit pcibios_setup(char *str)
else if (!strcmp(str, "rom")) { else if (!strcmp(str, "rom")) {
pci_probe |= PCI_ASSIGN_ROMS; pci_probe |= PCI_ASSIGN_ROMS;
return NULL; return NULL;
} else if (!strcmp(str, "norom")) {
pci_probe |= PCI_NOASSIGN_ROMS;
return NULL;
} else if (!strcmp(str, "assign-busses")) { } else if (!strcmp(str, "assign-busses")) {
pci_probe |= PCI_ASSIGN_ALL_BUSSES; pci_probe |= PCI_ASSIGN_ALL_BUSSES;
return NULL; return NULL;
} else if (!strcmp(str, "use_crs")) { } else if (!strcmp(str, "use_crs")) {
pci_probe |= PCI_USE__CRS; pci_probe |= PCI_USE__CRS;
return NULL; return NULL;
} else if (!strcmp(str, "earlydump")) {
pci_early_dump_regs = 1;
return NULL;
} else if (!strcmp(str, "routeirq")) { } else if (!strcmp(str, "routeirq")) {
pci_routeirq = 1; pci_routeirq = 1;
return NULL; return NULL;
......
...@@ -49,7 +49,14 @@ void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val) ...@@ -49,7 +49,14 @@ void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val)
{ {
PDprintk("%x writing to %x: %x\n", slot, offset, val); PDprintk("%x writing to %x: %x\n", slot, offset, val);
outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
outb(val, 0xcfc); outb(val, 0xcfc + (offset&3));
}
void write_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset, u16 val)
{
PDprintk("%x writing to %x: %x\n", slot, offset, val);
outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
outw(val, 0xcfc + (offset&2));
} }
int early_pci_allowed(void) int early_pci_allowed(void)
...@@ -57,3 +64,54 @@ int early_pci_allowed(void) ...@@ -57,3 +64,54 @@ int early_pci_allowed(void)
return (pci_probe & (PCI_PROBE_CONF1|PCI_PROBE_NOEARLY)) == return (pci_probe & (PCI_PROBE_CONF1|PCI_PROBE_NOEARLY)) ==
PCI_PROBE_CONF1; PCI_PROBE_CONF1;
} }
void early_dump_pci_device(u8 bus, u8 slot, u8 func)
{
int i;
int j;
u32 val;
printk("PCI: %02x:%02x:%02x", bus, slot, func);
for (i = 0; i < 256; i += 4) {
if (!(i & 0x0f))
printk("\n%04x:",i);
val = read_pci_config(bus, slot, func, i);
for (j = 0; j < 4; j++) {
printk(" %02x", val & 0xff);
val >>= 8;
}
}
printk("\n");
}
void early_dump_pci_devices(void)
{
unsigned bus, slot, func;
if (!early_pci_allowed())
return;
for (bus = 0; bus < 256; bus++) {
for (slot = 0; slot < 32; slot++) {
for (func = 0; func < 8; func++) {
u32 class;
u8 type;
class = read_pci_config(bus, slot, func,
PCI_CLASS_REVISION);
if (class == 0xffffffff)
break;
early_dump_pci_device(bus, slot, func);
/* No multi-function device? */
type = read_pci_config_byte(bus, slot, func,
PCI_HEADER_TYPE);
if (!(type & 0x80))
break;
}
}
}
}
...@@ -45,7 +45,8 @@ struct irq_router { ...@@ -45,7 +45,8 @@ struct irq_router {
char *name; char *name;
u16 vendor, device; u16 vendor, device;
int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq); int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq);
int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new); int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq,
int new);
}; };
struct irq_router_handler { struct irq_router_handler {
...@@ -77,7 +78,8 @@ static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr) ...@@ -77,7 +78,8 @@ static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr)
for (i = 0; i < rt->size; i++) for (i = 0; i < rt->size; i++)
sum += addr[i]; sum += addr[i];
if (!sum) { if (!sum) {
DBG(KERN_DEBUG "PCI: Interrupt Routing Table found at 0x%p\n", rt); DBG(KERN_DEBUG "PCI: Interrupt Routing Table found at 0x%p\n",
rt);
return rt; return rt;
} }
return NULL; return NULL;
...@@ -183,7 +185,8 @@ static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, ...@@ -183,7 +185,8 @@ static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset,
return (nr & 1) ? (x >> 4) : (x & 0xf); return (nr & 1) ? (x >> 4) : (x & 0xf);
} }
static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val) static void write_config_nybble(struct pci_dev *router, unsigned offset,
unsigned nr, unsigned int val)
{ {
u8 x; u8 x;
unsigned reg = offset + (nr >> 1); unsigned reg = offset + (nr >> 1);
...@@ -467,7 +470,8 @@ static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int ...@@ -467,7 +470,8 @@ static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int
return inb(0xc01) & 0xf; return inb(0xc01) & 0xf;
} }
static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev,
int pirq, int irq)
{ {
outb(pirq, 0xc00); outb(pirq, 0xc00);
outb(irq, 0xc01); outb(irq, 0xc01);
...@@ -660,7 +664,8 @@ static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router ...@@ -660,7 +664,8 @@ static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router
} }
static __init int serverworks_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) static __init int serverworks_router_probe(struct irq_router *r,
struct pci_dev *router, u16 device)
{ {
switch (device) { switch (device) {
case PCI_DEVICE_ID_SERVERWORKS_OSB4: case PCI_DEVICE_ID_SERVERWORKS_OSB4:
...@@ -827,10 +832,12 @@ static void __init pirq_find_router(struct irq_router *r) ...@@ -827,10 +832,12 @@ static void __init pirq_find_router(struct irq_router *r)
for (h = pirq_routers; h->vendor; h++) { for (h = pirq_routers; h->vendor; h++) {
/* First look for a router match */ /* First look for a router match */
if (rt->rtr_vendor == h->vendor && h->probe(r, pirq_router_dev, rt->rtr_device)) if (rt->rtr_vendor == h->vendor &&
h->probe(r, pirq_router_dev, rt->rtr_device))
break; break;
/* Fall back to a device match */ /* Fall back to a device match */
if (pirq_router_dev->vendor == h->vendor && h->probe(r, pirq_router_dev, pirq_router_dev->device)) if (pirq_router_dev->vendor == h->vendor &&
h->probe(r, pirq_router_dev, pirq_router_dev->device))
break; break;
} }
printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n", printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
...@@ -845,11 +852,13 @@ static void __init pirq_find_router(struct irq_router *r) ...@@ -845,11 +852,13 @@ static void __init pirq_find_router(struct irq_router *r)
static struct irq_info *pirq_get_info(struct pci_dev *dev) static struct irq_info *pirq_get_info(struct pci_dev *dev)
{ {
struct irq_routing_table *rt = pirq_table; struct irq_routing_table *rt = pirq_table;
int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); int entries = (rt->size - sizeof(struct irq_routing_table)) /
sizeof(struct irq_info);
struct irq_info *info; struct irq_info *info;
for (info = rt->slots; entries--; info++) for (info = rt->slots; entries--; info++)
if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn)) if (info->bus == dev->bus->number &&
PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
return info; return info;
return NULL; return NULL;
} }
...@@ -890,7 +899,8 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -890,7 +899,8 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
DBG(" -> not routed\n" KERN_DEBUG); DBG(" -> not routed\n" KERN_DEBUG);
return 0; return 0;
} }
DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs); DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask,
pirq_table->exclusive_irqs);
mask &= pcibios_irq_mask; mask &= pcibios_irq_mask;
/* Work around broken HP Pavilion Notebooks which assign USB to /* Work around broken HP Pavilion Notebooks which assign USB to
...@@ -903,7 +913,8 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -903,7 +913,8 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
} }
/* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */ /* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */
if (acer_tm360_irqrouting && dev->irq == 11 && dev->vendor == PCI_VENDOR_ID_O2) { if (acer_tm360_irqrouting && dev->irq == 11 &&
dev->vendor == PCI_VENDOR_ID_O2) {
pirq = 0x68; pirq = 0x68;
mask = 0x400; mask = 0x400;
dev->irq = r->get(pirq_router_dev, dev, pirq); dev->irq = r->get(pirq_router_dev, dev, pirq);
...@@ -920,15 +931,16 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -920,15 +931,16 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
newirq = 0; newirq = 0;
else else
printk("\n" KERN_WARNING printk("\n" KERN_WARNING
"PCI: IRQ %i for device %s doesn't match PIRQ mask " "PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n"
"- try pci=usepirqmask\n" KERN_DEBUG, newirq, KERN_DEBUG, newirq,
pci_name(dev)); pci_name(dev));
} }
if (!newirq && assign) { if (!newirq && assign) {
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
if (!(mask & (1 << i))) if (!(mask & (1 << i)))
continue; continue;
if (pirq_penalty[i] < pirq_penalty[newirq] && can_request_irq(i, IRQF_SHARED)) if (pirq_penalty[i] < pirq_penalty[newirq] &&
can_request_irq(i, IRQF_SHARED))
newirq = i; newirq = i;
} }
} }
...@@ -944,7 +956,8 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -944,7 +956,8 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
DBG(" -> got IRQ %d\n", irq); DBG(" -> got IRQ %d\n", irq);
msg = "Found"; msg = "Found";
eisa_set_level_irq(irq); eisa_set_level_irq(irq);
} else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { } else if (newirq && r->set &&
(dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
DBG(" -> assigning IRQ %d", newirq); DBG(" -> assigning IRQ %d", newirq);
if (r->set(pirq_router_dev, dev, pirq, newirq)) { if (r->set(pirq_router_dev, dev, pirq, newirq)) {
eisa_set_level_irq(newirq); eisa_set_level_irq(newirq);
...@@ -962,7 +975,8 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -962,7 +975,8 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
} else } else
return 0; return 0;
} }
printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, pci_name(dev)); printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq,
pci_name(dev));
/* Update IRQ for all devices with the same pirq value */ /* Update IRQ for all devices with the same pirq value */
while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) { while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) {
...@@ -974,7 +988,10 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -974,7 +988,10 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
if (!info) if (!info)
continue; continue;
if (info->irq[pin].link == pirq) { if (info->irq[pin].link == pirq) {
/* We refuse to override the dev->irq information. Give a warning! */ /*
* We refuse to override the dev->irq
* information. Give a warning!
*/
if (dev2->irq && dev2->irq != irq && \ if (dev2->irq && dev2->irq != irq && \
(!(pci_probe & PCI_USE_PIRQ_MASK) || \ (!(pci_probe & PCI_USE_PIRQ_MASK) || \
((1 << dev2->irq) & mask))) { ((1 << dev2->irq) & mask))) {
...@@ -987,7 +1004,9 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -987,7 +1004,9 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
dev2->irq = irq; dev2->irq = irq;
pirq_penalty[irq]++; pirq_penalty[irq]++;
if (dev != dev2) if (dev != dev2)
printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, pci_name(dev2)); printk(KERN_INFO
"PCI: Sharing IRQ %d with %s\n",
irq, pci_name(dev2));
} }
} }
return 1; return 1;
...@@ -1001,15 +1020,21 @@ static void __init pcibios_fixup_irqs(void) ...@@ -1001,15 +1020,21 @@ static void __init pcibios_fixup_irqs(void)
DBG(KERN_DEBUG "PCI: IRQ fixup\n"); DBG(KERN_DEBUG "PCI: IRQ fixup\n");
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
/* /*
* If the BIOS has set an out of range IRQ number, just ignore it. * If the BIOS has set an out of range IRQ number, just
* Also keep track of which IRQ's are already in use. * ignore it. Also keep track of which IRQ's are
* already in use.
*/ */
if (dev->irq >= 16) { if (dev->irq >= 16) {
DBG(KERN_DEBUG "%s: ignoring bogus IRQ %d\n", pci_name(dev), dev->irq); DBG(KERN_DEBUG "%s: ignoring bogus IRQ %d\n",
pci_name(dev), dev->irq);
dev->irq = 0; dev->irq = 0;
} }
/* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */ /*
if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000) * If the IRQ is already assigned to a PCI device,
* ignore its ISA use penalty
*/
if (pirq_penalty[dev->irq] >= 100 &&
pirq_penalty[dev->irq] < 100000)
pirq_penalty[dev->irq] = 0; pirq_penalty[dev->irq] = 0;
pirq_penalty[dev->irq]++; pirq_penalty[dev->irq]++;
} }
...@@ -1025,8 +1050,13 @@ static void __init pcibios_fixup_irqs(void) ...@@ -1025,8 +1050,13 @@ static void __init pcibios_fixup_irqs(void)
int irq; int irq;
if (pin) { if (pin) {
pin--; /* interrupt pins are numbered starting from 1 */ /*
irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); * interrupt pins are numbered starting
* from 1
*/
pin--;
irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
PCI_SLOT(dev->devfn), pin);
/* /*
* Busses behind bridges are typically not listed in the MP-table. * Busses behind bridges are typically not listed in the MP-table.
* In this case we have to look up the IRQ based on the parent bus, * In this case we have to look up the IRQ based on the parent bus,
...@@ -1067,7 +1097,8 @@ static int __init fix_broken_hp_bios_irq9(const struct dmi_system_id *d) ...@@ -1067,7 +1097,8 @@ static int __init fix_broken_hp_bios_irq9(const struct dmi_system_id *d)
{ {
if (!broken_hp_bios_irq9) { if (!broken_hp_bios_irq9) {
broken_hp_bios_irq9 = 1; broken_hp_bios_irq9 = 1;
printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); printk(KERN_INFO "%s detected - fixing broken IRQ routing\n",
d->ident);
} }
return 0; return 0;
} }
...@@ -1080,7 +1111,8 @@ static int __init fix_acer_tm360_irqrouting(const struct dmi_system_id *d) ...@@ -1080,7 +1111,8 @@ static int __init fix_acer_tm360_irqrouting(const struct dmi_system_id *d)
{ {
if (!acer_tm360_irqrouting) { if (!acer_tm360_irqrouting) {
acer_tm360_irqrouting = 1; acer_tm360_irqrouting = 1;
printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); printk(KERN_INFO "%s detected - fixing broken IRQ routing\n",
d->ident);
} }
return 0; return 0;
} }
...@@ -1092,7 +1124,8 @@ static struct dmi_system_id __initdata pciirq_dmi_table[] = { ...@@ -1092,7 +1124,8 @@ static struct dmi_system_id __initdata pciirq_dmi_table[] = {
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_BIOS_VERSION, "GE.M1.03"), DMI_MATCH(DMI_BIOS_VERSION, "GE.M1.03"),
DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"), DMI_MATCH(DMI_PRODUCT_VERSION,
"HP Pavilion Notebook Model GE"),
DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"), DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"),
}, },
}, },
...@@ -1131,7 +1164,10 @@ int __init pcibios_irq_init(void) ...@@ -1131,7 +1164,10 @@ int __init pcibios_irq_init(void)
if (!(pirq_table->exclusive_irqs & (1 << i))) if (!(pirq_table->exclusive_irqs & (1 << i)))
pirq_penalty[i] += 100; pirq_penalty[i] += 100;
} }
/* If we're using the I/O APIC, avoid using the PCI IRQ routing table */ /*
* If we're using the I/O APIC, avoid using the PCI IRQ
* routing table
*/
if (io_apic_assign_pci_irqs) if (io_apic_assign_pci_irqs)
pirq_table = NULL; pirq_table = NULL;
} }
...@@ -1175,7 +1211,7 @@ static int pirq_enable_irq(struct pci_dev *dev) ...@@ -1175,7 +1211,7 @@ static int pirq_enable_irq(struct pci_dev *dev)
if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
char *msg = ""; char *msg = "";
pin--; /* interrupt pins are numbered starting from 1 */ pin--; /* interrupt pins are numbered starting from 1 */
if (io_apic_assign_pci_irqs) { if (io_apic_assign_pci_irqs) {
int irq; int irq;
...@@ -1195,13 +1231,16 @@ static int pirq_enable_irq(struct pci_dev *dev) ...@@ -1195,13 +1231,16 @@ static int pirq_enable_irq(struct pci_dev *dev)
irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
PCI_SLOT(bridge->devfn), pin); PCI_SLOT(bridge->devfn), pin);
if (irq >= 0) if (irq >= 0)
printk(KERN_WARNING "PCI: using PPB %s[%c] to get irq %d\n", printk(KERN_WARNING
pci_name(bridge), 'A' + pin, irq); "PCI: using PPB %s[%c] to get irq %d\n",
pci_name(bridge),
'A' + pin, irq);
dev = bridge; dev = bridge;
} }
dev = temp_dev; dev = temp_dev;
if (irq >= 0) { if (irq >= 0) {
printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", printk(KERN_INFO
"PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
pci_name(dev), 'A' + pin, irq); pci_name(dev), 'A' + pin, irq);
dev->irq = irq; dev->irq = irq;
return 0; return 0;
...@@ -1212,12 +1251,17 @@ static int pirq_enable_irq(struct pci_dev *dev) ...@@ -1212,12 +1251,17 @@ static int pirq_enable_irq(struct pci_dev *dev)
else else
msg = " Please try using pci=biosirq."; msg = " Please try using pci=biosirq.";
/* With IDE legacy devices the IRQ lookup failure is not a problem.. */ /*
if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5)) * With IDE legacy devices the IRQ lookup failure is not
* a problem..
*/
if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE &&
!(dev->class & 0x5))
return 0; return 0;
printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n", printk(KERN_WARNING
'A' + pin, pci_name(dev), msg); "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
'A' + pin, pci_name(dev), msg);
} }
return 0; return 0;
} }
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#define PCI_USE__CRS 0x10000 #define PCI_USE__CRS 0x10000
#define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000 #define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000
#define PCI_HAS_IO_ECS 0x40000 #define PCI_HAS_IO_ECS 0x40000
#define PCI_NOASSIGN_ROMS 0x80000
extern unsigned int pci_probe; extern unsigned int pci_probe;
extern unsigned long pirq_table_addr; extern unsigned long pirq_table_addr;
......
...@@ -336,6 +336,15 @@ config ACPI_EC ...@@ -336,6 +336,15 @@ config ACPI_EC
the battery and thermal drivers. If you are compiling for a the battery and thermal drivers. If you are compiling for a
mobile system, say Y. mobile system, say Y.
config ACPI_PCI_SLOT
tristate "PCI slot detection driver"
default n
help
This driver will attempt to discover all PCI slots in your system,
and creates entries in /sys/bus/pci/slots/. This feature can
help you correlate PCI bus addresses with the physical geography
of your slots. If you are unsure, say N.
config ACPI_POWER config ACPI_POWER
bool bool
default y default y
......
...@@ -48,6 +48,7 @@ obj-$(CONFIG_ACPI_DOCK) += dock.o ...@@ -48,6 +48,7 @@ obj-$(CONFIG_ACPI_DOCK) += dock.o
obj-$(CONFIG_ACPI_BAY) += bay.o obj-$(CONFIG_ACPI_BAY) += bay.o
obj-$(CONFIG_ACPI_VIDEO) += video.o obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
obj-$(CONFIG_ACPI_POWER) += power.o obj-$(CONFIG_ACPI_POWER) += power.o
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
obj-$(CONFIG_ACPI_CONTAINER) += container.o obj-$(CONFIG_ACPI_CONTAINER) += container.o
......
...@@ -295,6 +295,28 @@ int acpi_bus_set_power(acpi_handle handle, int state) ...@@ -295,6 +295,28 @@ int acpi_bus_set_power(acpi_handle handle, int state)
EXPORT_SYMBOL(acpi_bus_set_power); EXPORT_SYMBOL(acpi_bus_set_power);
bool acpi_bus_power_manageable(acpi_handle handle)
{
struct acpi_device *device;
int result;
result = acpi_bus_get_device(handle, &device);
return result ? false : device->flags.power_manageable;
}
EXPORT_SYMBOL(acpi_bus_power_manageable);
bool acpi_bus_can_wakeup(acpi_handle handle)
{
struct acpi_device *device;
int result;
result = acpi_bus_get_device(handle, &device);
return result ? false : device->wakeup.flags.valid;
}
EXPORT_SYMBOL(acpi_bus_can_wakeup);
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Event Management Event Management
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
......
...@@ -166,6 +166,8 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) ...@@ -166,6 +166,8 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
"firmware_node"); "firmware_node");
ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
"physical_node"); "physical_node");
if (acpi_dev->wakeup.flags.valid)
device_set_wakeup_capable(dev, true);
} }
return 0; return 0;
......
/*
* pci_slot.c - ACPI PCI Slot Driver
*
* The code here is heavily leveraged from the acpiphp module.
* Thanks to Matthew Wilcox <matthew@wil.cx> for much guidance.
* Thanks to Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> for code
* review and fixes.
*
* Copyright (C) 2007 Alex Chiang <achiang@hp.com>
* Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
static int debug;
static int check_sta_before_sun;
#define DRIVER_VERSION "0.1"
#define DRIVER_AUTHOR "Alex Chiang <achiang@hp.com>"
#define DRIVER_DESC "ACPI PCI Slot Detection Driver"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
module_param(debug, bool, 0644);
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_slot");
#define MY_NAME "pci_slot"
#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
#define dbg(format, arg...) \
do { \
if (debug) \
printk(KERN_DEBUG "%s: " format, \
MY_NAME , ## arg); \
} while (0)
#define SLOT_NAME_SIZE 20 /* Inspired by #define in acpiphp.h */
struct acpi_pci_slot {
acpi_handle root_handle; /* handle of the root bridge */
struct pci_slot *pci_slot; /* corresponding pci_slot */
struct list_head list; /* node in the list of slots */
};
static int acpi_pci_slot_add(acpi_handle handle);
static void acpi_pci_slot_remove(acpi_handle handle);
static LIST_HEAD(slot_list);
static DEFINE_MUTEX(slot_list_lock);
static struct acpi_pci_driver acpi_pci_slot_driver = {
.add = acpi_pci_slot_add,
.remove = acpi_pci_slot_remove,
};
static int
check_slot(acpi_handle handle, int *device, unsigned long *sun)
{
int retval = 0;
unsigned long adr, sta;
acpi_status status;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
dbg("Checking slot on path: %s\n", (char *)buffer.pointer);
if (check_sta_before_sun) {
/* If SxFy doesn't have _STA, we just assume it's there */
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_SUCCESS(status) && !(sta & ACPI_STA_DEVICE_PRESENT)) {
retval = -1;
goto out;
}
}
status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
if (ACPI_FAILURE(status)) {
dbg("_ADR returned %d on %s\n", status, (char *)buffer.pointer);
retval = -1;
goto out;
}
*device = (adr >> 16) & 0xffff;
/* No _SUN == not a slot == bail */
status = acpi_evaluate_integer(handle, "_SUN", NULL, sun);
if (ACPI_FAILURE(status)) {
dbg("_SUN returned %d on %s\n", status, (char *)buffer.pointer);
retval = -1;
goto out;
}
out:
kfree(buffer.pointer);
return retval;
}
struct callback_args {
acpi_walk_callback user_function; /* only for walk_p2p_bridge */
struct pci_bus *pci_bus;
acpi_handle root_handle;
};
/*
* register_slot
*
* Called once for each SxFy object in the namespace. Don't worry about
* calling pci_create_slot multiple times for the same pci_bus:device,
* since each subsequent call simply bumps the refcount on the pci_slot.
*
* The number of calls to pci_destroy_slot from unregister_slot is
* symmetrical.
*/
static acpi_status
register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
{
int device;
unsigned long sun;
char name[SLOT_NAME_SIZE];
struct acpi_pci_slot *slot;
struct pci_slot *pci_slot;
struct callback_args *parent_context = context;
struct pci_bus *pci_bus = parent_context->pci_bus;
if (check_slot(handle, &device, &sun))
return AE_OK;
slot = kmalloc(sizeof(*slot), GFP_KERNEL);
if (!slot) {
err("%s: cannot allocate memory\n", __func__);
return AE_OK;
}
snprintf(name, sizeof(name), "%u", (u32)sun);
pci_slot = pci_create_slot(pci_bus, device, name);
if (IS_ERR(pci_slot)) {
err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot));
kfree(slot);
}
slot->root_handle = parent_context->root_handle;
slot->pci_slot = pci_slot;
INIT_LIST_HEAD(&slot->list);
mutex_lock(&slot_list_lock);
list_add(&slot->list, &slot_list);
mutex_unlock(&slot_list_lock);
dbg("pci_slot: %p, pci_bus: %x, device: %d, name: %s\n",
pci_slot, pci_bus->number, device, name);
return AE_OK;
}
/*
* walk_p2p_bridge - discover and walk p2p bridges
* @handle: points to an acpi_pci_root
* @context: p2p_bridge_context pointer
*
* Note that when we call ourselves recursively, we pass a different
* value of pci_bus in the child_context.
*/
static acpi_status
walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
{
int device, function;
unsigned long adr;
acpi_status status;
acpi_handle dummy_handle;
acpi_walk_callback user_function;
struct pci_dev *dev;
struct pci_bus *pci_bus;
struct callback_args child_context;
struct callback_args *parent_context = context;
pci_bus = parent_context->pci_bus;
user_function = parent_context->user_function;
status = acpi_get_handle(handle, "_ADR", &dummy_handle);
if (ACPI_FAILURE(status))
return AE_OK;
status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
if (ACPI_FAILURE(status))
return AE_OK;
device = (adr >> 16) & 0xffff;
function = adr & 0xffff;
dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function));
if (!dev || !dev->subordinate)
goto out;
child_context.pci_bus = dev->subordinate;
child_context.user_function = user_function;
child_context.root_handle = parent_context->root_handle;
dbg("p2p bridge walk, pci_bus = %x\n", dev->subordinate->number);
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
user_function, &child_context, NULL);
if (ACPI_FAILURE(status))
goto out;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
walk_p2p_bridge, &child_context, NULL);
out:
pci_dev_put(dev);
return AE_OK;
}
/*
* walk_root_bridge - generic root bridge walker
* @handle: points to an acpi_pci_root
* @user_function: user callback for slot objects
*
* Call user_function for all objects underneath this root bridge.
* Walk p2p bridges underneath us and call user_function on those too.
*/
static int
walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function)
{
int seg, bus;
unsigned long tmp;
acpi_status status;
acpi_handle dummy_handle;
struct pci_bus *pci_bus;
struct callback_args context;
/* If the bridge doesn't have _STA, we assume it is always there */
status = acpi_get_handle(handle, "_STA", &dummy_handle);
if (ACPI_SUCCESS(status)) {
status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
if (ACPI_FAILURE(status)) {
info("%s: _STA evaluation failure\n", __func__);
return 0;
}
if ((tmp & ACPI_STA_DEVICE_FUNCTIONING) == 0)
/* don't register this object */
return 0;
}
status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp);
seg = ACPI_SUCCESS(status) ? tmp : 0;
status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp);
bus = ACPI_SUCCESS(status) ? tmp : 0;
pci_bus = pci_find_bus(seg, bus);
if (!pci_bus)
return 0;
context.pci_bus = pci_bus;
context.user_function = user_function;
context.root_handle = handle;
dbg("root bridge walk, pci_bus = %x\n", pci_bus->number);
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
user_function, &context, NULL);
if (ACPI_FAILURE(status))
return status;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
walk_p2p_bridge, &context, NULL);
if (ACPI_FAILURE(status))
err("%s: walk_p2p_bridge failure - %d\n", __func__, status);
return status;
}
/*
* acpi_pci_slot_add
* @handle: points to an acpi_pci_root
*/
static int
acpi_pci_slot_add(acpi_handle handle)
{
acpi_status status;
status = walk_root_bridge(handle, register_slot);
if (ACPI_FAILURE(status))
err("%s: register_slot failure - %d\n", __func__, status);
return status;
}
/*
* acpi_pci_slot_remove
* @handle: points to an acpi_pci_root
*/
static void
acpi_pci_slot_remove(acpi_handle handle)
{
struct acpi_pci_slot *slot, *tmp;
mutex_lock(&slot_list_lock);
list_for_each_entry_safe(slot, tmp, &slot_list, list) {
if (slot->root_handle == handle) {
list_del(&slot->list);
pci_destroy_slot(slot->pci_slot);
kfree(slot);
}
}
mutex_unlock(&slot_list_lock);
}
static int do_sta_before_sun(const struct dmi_system_id *d)
{
info("%s detected: will evaluate _STA before calling _SUN\n", d->ident);
check_sta_before_sun = 1;
return 0;
}
static struct dmi_system_id acpi_pci_slot_dmi_table[] __initdata = {
/*
* Fujitsu Primequest machines will return 1023 to indicate an
* error if the _SUN method is evaluated on SxFy objects that
* are not present (as indicated by _STA), so for those machines,
* we want to check _STA before evaluating _SUN.
*/
{
.callback = do_sta_before_sun,
.ident = "Fujitsu PRIMEQUEST",
.matches = {
DMI_MATCH(DMI_BIOS_VENDOR, "FUJITSU LIMITED"),
DMI_MATCH(DMI_BIOS_VERSION, "PRIMEQUEST"),
},
},
{}
};
static int __init
acpi_pci_slot_init(void)
{
dmi_check_system(acpi_pci_slot_dmi_table);
acpi_pci_register_driver(&acpi_pci_slot_driver);
return 0;
}
static void __exit
acpi_pci_slot_exit(void)
{
acpi_pci_unregister_driver(&acpi_pci_slot_driver);
}
module_init(acpi_pci_slot_init);
module_exit(acpi_pci_slot_exit);
...@@ -292,69 +292,135 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) ...@@ -292,69 +292,135 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
return 0; return 0;
} }
/**
* acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
* ACPI 3.0) _PSW (Power State Wake)
* @dev: Device to handle.
* @enable: 0 - disable, 1 - enable the wake capabilities of the device.
* @sleep_state: Target sleep state of the system.
* @dev_state: Target power state of the device.
*
* Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
* State Wake) for the device, if present. On failure reset the device's
* wakeup.flags.valid flag.
*
* RETURN VALUE:
* 0 if either _DSW or _PSW has been successfully executed
* 0 if neither _DSW nor _PSW has been found
* -ENODEV if the execution of either _DSW or _PSW has failed
*/
int acpi_device_sleep_wake(struct acpi_device *dev,
int enable, int sleep_state, int dev_state)
{
union acpi_object in_arg[3];
struct acpi_object_list arg_list = { 3, in_arg };
acpi_status status = AE_OK;
/*
* Try to execute _DSW first.
*
* Three agruments are needed for the _DSW object:
* Argument 0: enable/disable the wake capabilities
* Argument 1: target system state
* Argument 2: target device state
* When _DSW object is called to disable the wake capabilities, maybe
* the first argument is filled. The values of the other two agruments
* are meaningless.
*/
in_arg[0].type = ACPI_TYPE_INTEGER;
in_arg[0].integer.value = enable;
in_arg[1].type = ACPI_TYPE_INTEGER;
in_arg[1].integer.value = sleep_state;
in_arg[2].type = ACPI_TYPE_INTEGER;
in_arg[2].integer.value = dev_state;
status = acpi_evaluate_object(dev->handle, "_DSW", &arg_list, NULL);
if (ACPI_SUCCESS(status)) {
return 0;
} else if (status != AE_NOT_FOUND) {
printk(KERN_ERR PREFIX "_DSW execution failed\n");
dev->wakeup.flags.valid = 0;
return -ENODEV;
}
/* Execute _PSW */
arg_list.count = 1;
in_arg[0].integer.value = enable;
status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
printk(KERN_ERR PREFIX "_PSW execution failed\n");
dev->wakeup.flags.valid = 0;
return -ENODEV;
}
return 0;
}
/* /*
* Prepare a wakeup device, two steps (Ref ACPI 2.0:P229): * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229):
* 1. Power on the power resources required for the wakeup device * 1. Power on the power resources required for the wakeup device
* 2. Enable _PSW (power state wake) for the device if present * 2. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
* State Wake) for the device, if present
*/ */
int acpi_enable_wakeup_device_power(struct acpi_device *dev) int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
{ {
union acpi_object arg = { ACPI_TYPE_INTEGER }; int i, err;
struct acpi_object_list arg_list = { 1, &arg };
acpi_status status = AE_OK;
int i;
int ret = 0;
if (!dev || !dev->wakeup.flags.valid) if (!dev || !dev->wakeup.flags.valid)
return -1; return -EINVAL;
/*
* Do not execute the code below twice in a row without calling
* acpi_disable_wakeup_device_power() in between for the same device
*/
if (dev->wakeup.flags.prepared)
return 0;
arg.integer.value = 1;
/* Open power resource */ /* Open power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) { for (i = 0; i < dev->wakeup.resources.count; i++) {
ret = acpi_power_on(dev->wakeup.resources.handles[i], dev); int ret = acpi_power_on(dev->wakeup.resources.handles[i], dev);
if (ret) { if (ret) {
printk(KERN_ERR PREFIX "Transition power state\n"); printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0; dev->wakeup.flags.valid = 0;
return -1; return -ENODEV;
} }
} }
/* Execute PSW */ /*
status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); * Passing 3 as the third argument below means the device may be placed
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { * in arbitrary power state afterwards.
printk(KERN_ERR PREFIX "Evaluate _PSW\n"); */
dev->wakeup.flags.valid = 0; err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
ret = -1; if (!err)
} dev->wakeup.flags.prepared = 1;
return ret; return err;
} }
/* /*
* Shutdown a wakeup device, counterpart of above method * Shutdown a wakeup device, counterpart of above method
* 1. Disable _PSW (power state wake) * 1. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
* State Wake) for the device, if present
* 2. Shutdown down the power resources * 2. Shutdown down the power resources
*/ */
int acpi_disable_wakeup_device_power(struct acpi_device *dev) int acpi_disable_wakeup_device_power(struct acpi_device *dev)
{ {
union acpi_object arg = { ACPI_TYPE_INTEGER }; int i, ret;
struct acpi_object_list arg_list = { 1, &arg };
acpi_status status = AE_OK;
int i;
int ret = 0;
if (!dev || !dev->wakeup.flags.valid) if (!dev || !dev->wakeup.flags.valid)
return -1; return -EINVAL;
arg.integer.value = 0; /*
/* Execute PSW */ * Do not execute the code below twice in a row without calling
status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); * acpi_enable_wakeup_device_power() in between for the same device
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { */
printk(KERN_ERR PREFIX "Evaluate _PSW\n"); if (!dev->wakeup.flags.prepared)
dev->wakeup.flags.valid = 0; return 0;
return -1;
} dev->wakeup.flags.prepared = 0;
ret = acpi_device_sleep_wake(dev, 0, 0, 0);
if (ret)
return ret;
/* Close power resource */ /* Close power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) { for (i = 0; i < dev->wakeup.resources.count; i++) {
...@@ -362,7 +428,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) ...@@ -362,7 +428,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
if (ret) { if (ret) {
printk(KERN_ERR PREFIX "Transition power state\n"); printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0; dev->wakeup.flags.valid = 0;
return -1; return -ENODEV;
} }
} }
......
...@@ -703,9 +703,7 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) ...@@ -703,9 +703,7 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
acpi_status status = 0; acpi_status status = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package = NULL; union acpi_object *package = NULL;
union acpi_object in_arg[3]; int psw_error;
struct acpi_object_list arg_list = { 3, in_arg };
acpi_status psw_status = AE_OK;
struct acpi_device_id button_device_ids[] = { struct acpi_device_id button_device_ids[] = {
{"PNP0C0D", 0}, {"PNP0C0D", 0},
...@@ -737,39 +735,11 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) ...@@ -737,39 +735,11 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
* So it is necessary to call _DSW object first. Only when it is not * So it is necessary to call _DSW object first. Only when it is not
* present will the _PSW object used. * present will the _PSW object used.
*/ */
/* psw_error = acpi_device_sleep_wake(device, 0, 0, 0);
* Three agruments are needed for the _DSW object. if (psw_error)
* Argument 0: enable/disable the wake capabilities ACPI_DEBUG_PRINT((ACPI_DB_INFO,
* When _DSW object is called to disable the wake capabilities, maybe "error in _DSW or _PSW evaluation\n"));
* the first argument is filled. The value of the other two agruments
* is meaningless.
*/
in_arg[0].type = ACPI_TYPE_INTEGER;
in_arg[0].integer.value = 0;
in_arg[1].type = ACPI_TYPE_INTEGER;
in_arg[1].integer.value = 0;
in_arg[2].type = ACPI_TYPE_INTEGER;
in_arg[2].integer.value = 0;
psw_status = acpi_evaluate_object(device->handle, "_DSW",
&arg_list, NULL);
if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in evaluate _DSW\n"));
/*
* When the _DSW object is not present, OSPM will call _PSW object.
*/
if (psw_status == AE_NOT_FOUND) {
/*
* Only one agruments is required for the _PSW object.
* agrument 0: enable/disable the wake capabilities
*/
arg_list.count = 1;
in_arg[0].integer.value = 0;
psw_status = acpi_evaluate_object(device->handle, "_PSW",
&arg_list, NULL);
if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in "
"evaluate _PSW\n"));
}
/* Power button, Lid switch always enable wakeup */ /* Power button, Lid switch always enable wakeup */
if (!acpi_match_device_ids(device, button_device_ids)) if (!acpi_match_device_ids(device, button_device_ids))
device->wakeup.flags.run_wake = 1; device->wakeup.flags.run_wake = 1;
......
...@@ -24,10 +24,6 @@ ...@@ -24,10 +24,6 @@
u8 sleep_states[ACPI_S_STATE_COUNT]; u8 sleep_states[ACPI_S_STATE_COUNT];
#ifdef CONFIG_PM_SLEEP
static u32 acpi_target_sleep_state = ACPI_STATE_S0;
#endif
static int acpi_sleep_prepare(u32 acpi_state) static int acpi_sleep_prepare(u32 acpi_state)
{ {
#ifdef CONFIG_ACPI_SLEEP #ifdef CONFIG_ACPI_SLEEP
...@@ -49,9 +45,96 @@ static int acpi_sleep_prepare(u32 acpi_state) ...@@ -49,9 +45,96 @@ static int acpi_sleep_prepare(u32 acpi_state)
return 0; return 0;
} }
#ifdef CONFIG_SUSPEND #ifdef CONFIG_PM_SLEEP
static struct platform_suspend_ops acpi_suspend_ops; static u32 acpi_target_sleep_state = ACPI_STATE_S0;
/*
* ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
* user to request that behavior by using the 'acpi_old_suspend_ordering'
* kernel command line option that causes the following variable to be set.
*/
static bool old_suspend_ordering;
void __init acpi_old_suspend_ordering(void)
{
old_suspend_ordering = true;
}
/**
* acpi_pm_disable_gpes - Disable the GPEs.
*/
static int acpi_pm_disable_gpes(void)
{
acpi_hw_disable_all_gpes();
return 0;
}
/**
* __acpi_pm_prepare - Prepare the platform to enter the target state.
*
* If necessary, set the firmware waking vector and do arch-specific
* nastiness to get the wakeup code to the waking vector.
*/
static int __acpi_pm_prepare(void)
{
int error = acpi_sleep_prepare(acpi_target_sleep_state);
if (error)
acpi_target_sleep_state = ACPI_STATE_S0;
return error;
}
/**
* acpi_pm_prepare - Prepare the platform to enter the target sleep
* state and disable the GPEs.
*/
static int acpi_pm_prepare(void)
{
int error = __acpi_pm_prepare();
if (!error)
acpi_hw_disable_all_gpes();
return error;
}
/**
* acpi_pm_finish - Instruct the platform to leave a sleep state.
*
* This is called after we wake back up (or if entering the sleep state
* failed).
*/
static void acpi_pm_finish(void)
{
u32 acpi_state = acpi_target_sleep_state;
if (acpi_state == ACPI_STATE_S0)
return;
printk(KERN_INFO PREFIX "Waking up from system sleep state S%d\n",
acpi_state);
acpi_disable_wakeup_device(acpi_state);
acpi_leave_sleep_state(acpi_state);
/* reset firmware waking vector */
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
acpi_target_sleep_state = ACPI_STATE_S0;
}
/**
* acpi_pm_end - Finish up suspend sequence.
*/
static void acpi_pm_end(void)
{
/*
* This is necessary in case acpi_pm_finish() is not called during a
* failing transition to a sleep state.
*/
acpi_target_sleep_state = ACPI_STATE_S0;
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_SUSPEND
extern void do_suspend_lowlevel(void); extern void do_suspend_lowlevel(void);
static u32 acpi_suspend_states[] = { static u32 acpi_suspend_states[] = {
...@@ -65,7 +148,6 @@ static u32 acpi_suspend_states[] = { ...@@ -65,7 +148,6 @@ static u32 acpi_suspend_states[] = {
* acpi_suspend_begin - Set the target system sleep state to the state * acpi_suspend_begin - Set the target system sleep state to the state
* associated with given @pm_state, if supported. * associated with given @pm_state, if supported.
*/ */
static int acpi_suspend_begin(suspend_state_t pm_state) static int acpi_suspend_begin(suspend_state_t pm_state)
{ {
u32 acpi_state = acpi_suspend_states[pm_state]; u32 acpi_state = acpi_suspend_states[pm_state];
...@@ -81,25 +163,6 @@ static int acpi_suspend_begin(suspend_state_t pm_state) ...@@ -81,25 +163,6 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
return error; return error;
} }
/**
* acpi_suspend_prepare - Do preliminary suspend work.
*
* If necessary, set the firmware waking vector and do arch-specific
* nastiness to get the wakeup code to the waking vector.
*/
static int acpi_suspend_prepare(void)
{
int error = acpi_sleep_prepare(acpi_target_sleep_state);
if (error) {
acpi_target_sleep_state = ACPI_STATE_S0;
return error;
}
return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
}
/** /**
* acpi_suspend_enter - Actually enter a sleep state. * acpi_suspend_enter - Actually enter a sleep state.
* @pm_state: ignored * @pm_state: ignored
...@@ -108,7 +171,6 @@ static int acpi_suspend_prepare(void) ...@@ -108,7 +171,6 @@ static int acpi_suspend_prepare(void)
* assembly, which in turn call acpi_enter_sleep_state(). * assembly, which in turn call acpi_enter_sleep_state().
* It's unfortunate, but it works. Please fix if you're feeling frisky. * It's unfortunate, but it works. Please fix if you're feeling frisky.
*/ */
static int acpi_suspend_enter(suspend_state_t pm_state) static int acpi_suspend_enter(suspend_state_t pm_state)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
...@@ -165,39 +227,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) ...@@ -165,39 +227,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
return ACPI_SUCCESS(status) ? 0 : -EFAULT; return ACPI_SUCCESS(status) ? 0 : -EFAULT;
} }
/**
* acpi_suspend_finish - Instruct the platform to leave a sleep state.
*
* This is called after we wake back up (or if entering the sleep state
* failed).
*/
static void acpi_suspend_finish(void)
{
u32 acpi_state = acpi_target_sleep_state;
acpi_disable_wakeup_device(acpi_state);
acpi_leave_sleep_state(acpi_state);
/* reset firmware waking vector */
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
acpi_target_sleep_state = ACPI_STATE_S0;
}
/**
* acpi_suspend_end - Finish up suspend sequence.
*/
static void acpi_suspend_end(void)
{
/*
* This is necessary in case acpi_suspend_finish() is not called during a
* failing transition to a sleep state.
*/
acpi_target_sleep_state = ACPI_STATE_S0;
}
static int acpi_suspend_state_valid(suspend_state_t pm_state) static int acpi_suspend_state_valid(suspend_state_t pm_state)
{ {
u32 acpi_state; u32 acpi_state;
...@@ -217,10 +246,39 @@ static int acpi_suspend_state_valid(suspend_state_t pm_state) ...@@ -217,10 +246,39 @@ static int acpi_suspend_state_valid(suspend_state_t pm_state)
static struct platform_suspend_ops acpi_suspend_ops = { static struct platform_suspend_ops acpi_suspend_ops = {
.valid = acpi_suspend_state_valid, .valid = acpi_suspend_state_valid,
.begin = acpi_suspend_begin, .begin = acpi_suspend_begin,
.prepare = acpi_suspend_prepare, .prepare = acpi_pm_prepare,
.enter = acpi_suspend_enter, .enter = acpi_suspend_enter,
.finish = acpi_suspend_finish, .finish = acpi_pm_finish,
.end = acpi_suspend_end, .end = acpi_pm_end,
};
/**
* acpi_suspend_begin_old - Set the target system sleep state to the
* state associated with given @pm_state, if supported, and
* execute the _PTS control method. This function is used if the
* pre-ACPI 2.0 suspend ordering has been requested.
*/
static int acpi_suspend_begin_old(suspend_state_t pm_state)
{
int error = acpi_suspend_begin(pm_state);
if (!error)
error = __acpi_pm_prepare();
return error;
}
/*
* The following callbacks are used if the pre-ACPI 2.0 suspend ordering has
* been requested.
*/
static struct platform_suspend_ops acpi_suspend_ops_old = {
.valid = acpi_suspend_state_valid,
.begin = acpi_suspend_begin_old,
.prepare = acpi_pm_disable_gpes,
.enter = acpi_suspend_enter,
.finish = acpi_pm_finish,
.end = acpi_pm_end,
.recover = acpi_pm_finish,
}; };
#endif /* CONFIG_SUSPEND */ #endif /* CONFIG_SUSPEND */
...@@ -228,22 +286,9 @@ static struct platform_suspend_ops acpi_suspend_ops = { ...@@ -228,22 +286,9 @@ static struct platform_suspend_ops acpi_suspend_ops = {
static int acpi_hibernation_begin(void) static int acpi_hibernation_begin(void)
{ {
acpi_target_sleep_state = ACPI_STATE_S4; acpi_target_sleep_state = ACPI_STATE_S4;
return 0; return 0;
} }
static int acpi_hibernation_prepare(void)
{
int error = acpi_sleep_prepare(ACPI_STATE_S4);
if (error) {
acpi_target_sleep_state = ACPI_STATE_S0;
return error;
}
return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
}
static int acpi_hibernation_enter(void) static int acpi_hibernation_enter(void)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
...@@ -273,52 +318,55 @@ static void acpi_hibernation_leave(void) ...@@ -273,52 +318,55 @@ static void acpi_hibernation_leave(void)
acpi_leave_sleep_state_prep(ACPI_STATE_S4); acpi_leave_sleep_state_prep(ACPI_STATE_S4);
} }
static void acpi_hibernation_finish(void) static void acpi_pm_enable_gpes(void)
{ {
acpi_disable_wakeup_device(ACPI_STATE_S4); acpi_hw_enable_all_runtime_gpes();
acpi_leave_sleep_state(ACPI_STATE_S4);
/* reset firmware waking vector */
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
acpi_target_sleep_state = ACPI_STATE_S0;
} }
static void acpi_hibernation_end(void) static struct platform_hibernation_ops acpi_hibernation_ops = {
{ .begin = acpi_hibernation_begin,
/* .end = acpi_pm_end,
* This is necessary in case acpi_hibernation_finish() is not called .pre_snapshot = acpi_pm_prepare,
* during a failing transition to the sleep state. .finish = acpi_pm_finish,
*/ .prepare = acpi_pm_prepare,
acpi_target_sleep_state = ACPI_STATE_S0; .enter = acpi_hibernation_enter,
} .leave = acpi_hibernation_leave,
.pre_restore = acpi_pm_disable_gpes,
.restore_cleanup = acpi_pm_enable_gpes,
};
static int acpi_hibernation_pre_restore(void) /**
* acpi_hibernation_begin_old - Set the target system sleep state to
* ACPI_STATE_S4 and execute the _PTS control method. This
* function is used if the pre-ACPI 2.0 suspend ordering has been
* requested.
*/
static int acpi_hibernation_begin_old(void)
{ {
acpi_status status; int error = acpi_sleep_prepare(ACPI_STATE_S4);
status = acpi_hw_disable_all_gpes();
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
}
static void acpi_hibernation_restore_cleanup(void) if (!error)
{ acpi_target_sleep_state = ACPI_STATE_S4;
acpi_hw_enable_all_runtime_gpes(); return error;
} }
static struct platform_hibernation_ops acpi_hibernation_ops = { /*
.begin = acpi_hibernation_begin, * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has
.end = acpi_hibernation_end, * been requested.
.pre_snapshot = acpi_hibernation_prepare, */
.finish = acpi_hibernation_finish, static struct platform_hibernation_ops acpi_hibernation_ops_old = {
.prepare = acpi_hibernation_prepare, .begin = acpi_hibernation_begin_old,
.end = acpi_pm_end,
.pre_snapshot = acpi_pm_disable_gpes,
.finish = acpi_pm_finish,
.prepare = acpi_pm_disable_gpes,
.enter = acpi_hibernation_enter, .enter = acpi_hibernation_enter,
.leave = acpi_hibernation_leave, .leave = acpi_hibernation_leave,
.pre_restore = acpi_hibernation_pre_restore, .pre_restore = acpi_pm_disable_gpes,
.restore_cleanup = acpi_hibernation_restore_cleanup, .restore_cleanup = acpi_pm_enable_gpes,
.recover = acpi_pm_finish,
}; };
#endif /* CONFIG_HIBERNATION */ #endif /* CONFIG_HIBERNATION */
int acpi_suspend(u32 acpi_state) int acpi_suspend(u32 acpi_state)
{ {
...@@ -419,6 +467,31 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) ...@@ -419,6 +467,31 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
*d_min_p = d_min; *d_min_p = d_min;
return d_max; return d_max;
} }
/**
* acpi_pm_device_sleep_wake - enable or disable the system wake-up
* capability of given device
* @dev: device to handle
* @enable: 'true' - enable, 'false' - disable the wake-up capability
*/
int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
{
acpi_handle handle;
struct acpi_device *adev;
if (!device_may_wakeup(dev))
return -EINVAL;
handle = DEVICE_ACPI_HANDLE(dev);
if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
printk(KERN_DEBUG "ACPI handle has no context!\n");
return -ENODEV;
}
return enable ?
acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) :
acpi_disable_wakeup_device_power(adev);
}
#endif #endif
static void acpi_power_off_prepare(void) static void acpi_power_off_prepare(void)
...@@ -460,13 +533,15 @@ int __init acpi_sleep_init(void) ...@@ -460,13 +533,15 @@ int __init acpi_sleep_init(void)
} }
} }
suspend_set_ops(&acpi_suspend_ops); suspend_set_ops(old_suspend_ordering ?
&acpi_suspend_ops_old : &acpi_suspend_ops);
#endif #endif
#ifdef CONFIG_HIBERNATION #ifdef CONFIG_HIBERNATION
status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b); status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
hibernation_set_ops(&acpi_hibernation_ops); hibernation_set_ops(old_suspend_ordering ?
&acpi_hibernation_ops_old : &acpi_hibernation_ops);
sleep_states[ACPI_STATE_S4] = 1; sleep_states[ACPI_STATE_S4] = 1;
printk(" S4"); printk(" S4");
} }
......
...@@ -42,7 +42,7 @@ void acpi_enable_wakeup_device_prep(u8 sleep_state) ...@@ -42,7 +42,7 @@ void acpi_enable_wakeup_device_prep(u8 sleep_state)
continue; continue;
spin_unlock(&acpi_device_lock); spin_unlock(&acpi_device_lock);
acpi_enable_wakeup_device_power(dev); acpi_enable_wakeup_device_power(dev, sleep_state);
spin_lock(&acpi_device_lock); spin_lock(&acpi_device_lock);
} }
spin_unlock(&acpi_device_lock); spin_unlock(&acpi_device_lock);
...@@ -66,13 +66,15 @@ void acpi_enable_wakeup_device(u8 sleep_state) ...@@ -66,13 +66,15 @@ void acpi_enable_wakeup_device(u8 sleep_state)
list_for_each_safe(node, next, &acpi_wakeup_device_list) { list_for_each_safe(node, next, &acpi_wakeup_device_list) {
struct acpi_device *dev = struct acpi_device *dev =
container_of(node, struct acpi_device, wakeup_list); container_of(node, struct acpi_device, wakeup_list);
if (!dev->wakeup.flags.valid) if (!dev->wakeup.flags.valid)
continue; continue;
/* If users want to disable run-wake GPE, /* If users want to disable run-wake GPE,
* we only disable it for wake and leave it for runtime * we only disable it for wake and leave it for runtime
*/ */
if (!dev->wakeup.state.enabled || if ((!dev->wakeup.state.enabled && !dev->wakeup.flags.prepared)
sleep_state > (u32) dev->wakeup.sleep_state) { || sleep_state > (u32) dev->wakeup.sleep_state) {
if (dev->wakeup.flags.run_wake) { if (dev->wakeup.flags.run_wake) {
spin_unlock(&acpi_device_lock); spin_unlock(&acpi_device_lock);
/* set_gpe_type will disable GPE, leave it like that */ /* set_gpe_type will disable GPE, leave it like that */
...@@ -110,8 +112,9 @@ void acpi_disable_wakeup_device(u8 sleep_state) ...@@ -110,8 +112,9 @@ void acpi_disable_wakeup_device(u8 sleep_state)
if (!dev->wakeup.flags.valid) if (!dev->wakeup.flags.valid)
continue; continue;
if (!dev->wakeup.state.enabled ||
sleep_state > (u32) dev->wakeup.sleep_state) { if ((!dev->wakeup.state.enabled && !dev->wakeup.flags.prepared)
|| sleep_state > (u32) dev->wakeup.sleep_state) {
if (dev->wakeup.flags.run_wake) { if (dev->wakeup.flags.run_wake) {
spin_unlock(&acpi_device_lock); spin_unlock(&acpi_device_lock);
acpi_set_gpe_type(dev->wakeup.gpe_device, acpi_set_gpe_type(dev->wakeup.gpe_device,
......
...@@ -453,6 +453,8 @@ int platform_driver_register(struct platform_driver *drv) ...@@ -453,6 +453,8 @@ int platform_driver_register(struct platform_driver *drv)
drv->driver.suspend = platform_drv_suspend; drv->driver.suspend = platform_drv_suspend;
if (drv->resume) if (drv->resume)
drv->driver.resume = platform_drv_resume; drv->driver.resume = platform_drv_resume;
if (drv->pm)
drv->driver.pm = &drv->pm->base;
return driver_register(&drv->driver); return driver_register(&drv->driver);
} }
EXPORT_SYMBOL_GPL(platform_driver_register); EXPORT_SYMBOL_GPL(platform_driver_register);
...@@ -560,7 +562,9 @@ static int platform_match(struct device *dev, struct device_driver *drv) ...@@ -560,7 +562,9 @@ static int platform_match(struct device *dev, struct device_driver *drv)
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
} }
static int platform_suspend(struct device *dev, pm_message_t mesg) #ifdef CONFIG_PM_SLEEP
static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
{ {
int ret = 0; int ret = 0;
...@@ -570,7 +574,7 @@ static int platform_suspend(struct device *dev, pm_message_t mesg) ...@@ -570,7 +574,7 @@ static int platform_suspend(struct device *dev, pm_message_t mesg)
return ret; return ret;
} }
static int platform_suspend_late(struct device *dev, pm_message_t mesg) static int platform_legacy_suspend_late(struct device *dev, pm_message_t mesg)
{ {
struct platform_driver *drv = to_platform_driver(dev->driver); struct platform_driver *drv = to_platform_driver(dev->driver);
struct platform_device *pdev; struct platform_device *pdev;
...@@ -583,7 +587,7 @@ static int platform_suspend_late(struct device *dev, pm_message_t mesg) ...@@ -583,7 +587,7 @@ static int platform_suspend_late(struct device *dev, pm_message_t mesg)
return ret; return ret;
} }
static int platform_resume_early(struct device *dev) static int platform_legacy_resume_early(struct device *dev)
{ {
struct platform_driver *drv = to_platform_driver(dev->driver); struct platform_driver *drv = to_platform_driver(dev->driver);
struct platform_device *pdev; struct platform_device *pdev;
...@@ -596,7 +600,7 @@ static int platform_resume_early(struct device *dev) ...@@ -596,7 +600,7 @@ static int platform_resume_early(struct device *dev)
return ret; return ret;
} }
static int platform_resume(struct device *dev) static int platform_legacy_resume(struct device *dev)
{ {
int ret = 0; int ret = 0;
...@@ -606,15 +610,291 @@ static int platform_resume(struct device *dev) ...@@ -606,15 +610,291 @@ static int platform_resume(struct device *dev)
return ret; return ret;
} }
static int platform_pm_prepare(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
if (drv && drv->pm && drv->pm->prepare)
ret = drv->pm->prepare(dev);
return ret;
}
static void platform_pm_complete(struct device *dev)
{
struct device_driver *drv = dev->driver;
if (drv && drv->pm && drv->pm->complete)
drv->pm->complete(dev);
}
#ifdef CONFIG_SUSPEND
static int platform_pm_suspend(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
if (drv && drv->pm) {
if (drv->pm->suspend)
ret = drv->pm->suspend(dev);
} else {
ret = platform_legacy_suspend(dev, PMSG_SUSPEND);
}
return ret;
}
static int platform_pm_suspend_noirq(struct device *dev)
{
struct platform_driver *pdrv;
int ret = 0;
if (!dev->driver)
return 0;
pdrv = to_platform_driver(dev->driver);
if (pdrv->pm) {
if (pdrv->pm->suspend_noirq)
ret = pdrv->pm->suspend_noirq(dev);
} else {
ret = platform_legacy_suspend_late(dev, PMSG_SUSPEND);
}
return ret;
}
static int platform_pm_resume(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
if (drv && drv->pm) {
if (drv->pm->resume)
ret = drv->pm->resume(dev);
} else {
ret = platform_legacy_resume(dev);
}
return ret;
}
static int platform_pm_resume_noirq(struct device *dev)
{
struct platform_driver *pdrv;
int ret = 0;
if (!dev->driver)
return 0;
pdrv = to_platform_driver(dev->driver);
if (pdrv->pm) {
if (pdrv->pm->resume_noirq)
ret = pdrv->pm->resume_noirq(dev);
} else {
ret = platform_legacy_resume_early(dev);
}
return ret;
}
#else /* !CONFIG_SUSPEND */
#define platform_pm_suspend NULL
#define platform_pm_resume NULL
#define platform_pm_suspend_noirq NULL
#define platform_pm_resume_noirq NULL
#endif /* !CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATION
static int platform_pm_freeze(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
if (!drv)
return 0;
if (drv->pm) {
if (drv->pm->freeze)
ret = drv->pm->freeze(dev);
} else {
ret = platform_legacy_suspend(dev, PMSG_FREEZE);
}
return ret;
}
static int platform_pm_freeze_noirq(struct device *dev)
{
struct platform_driver *pdrv;
int ret = 0;
if (!dev->driver)
return 0;
pdrv = to_platform_driver(dev->driver);
if (pdrv->pm) {
if (pdrv->pm->freeze_noirq)
ret = pdrv->pm->freeze_noirq(dev);
} else {
ret = platform_legacy_suspend_late(dev, PMSG_FREEZE);
}
return ret;
}
static int platform_pm_thaw(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
if (drv && drv->pm) {
if (drv->pm->thaw)
ret = drv->pm->thaw(dev);
} else {
ret = platform_legacy_resume(dev);
}
return ret;
}
static int platform_pm_thaw_noirq(struct device *dev)
{
struct platform_driver *pdrv;
int ret = 0;
if (!dev->driver)
return 0;
pdrv = to_platform_driver(dev->driver);
if (pdrv->pm) {
if (pdrv->pm->thaw_noirq)
ret = pdrv->pm->thaw_noirq(dev);
} else {
ret = platform_legacy_resume_early(dev);
}
return ret;
}
static int platform_pm_poweroff(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
if (drv && drv->pm) {
if (drv->pm->poweroff)
ret = drv->pm->poweroff(dev);
} else {
ret = platform_legacy_suspend(dev, PMSG_HIBERNATE);
}
return ret;
}
static int platform_pm_poweroff_noirq(struct device *dev)
{
struct platform_driver *pdrv;
int ret = 0;
if (!dev->driver)
return 0;
pdrv = to_platform_driver(dev->driver);
if (pdrv->pm) {
if (pdrv->pm->poweroff_noirq)
ret = pdrv->pm->poweroff_noirq(dev);
} else {
ret = platform_legacy_suspend_late(dev, PMSG_HIBERNATE);
}
return ret;
}
static int platform_pm_restore(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
if (drv && drv->pm) {
if (drv->pm->restore)
ret = drv->pm->restore(dev);
} else {
ret = platform_legacy_resume(dev);
}
return ret;
}
static int platform_pm_restore_noirq(struct device *dev)
{
struct platform_driver *pdrv;
int ret = 0;
if (!dev->driver)
return 0;
pdrv = to_platform_driver(dev->driver);
if (pdrv->pm) {
if (pdrv->pm->restore_noirq)
ret = pdrv->pm->restore_noirq(dev);
} else {
ret = platform_legacy_resume_early(dev);
}
return ret;
}
#else /* !CONFIG_HIBERNATION */
#define platform_pm_freeze NULL
#define platform_pm_thaw NULL
#define platform_pm_poweroff NULL
#define platform_pm_restore NULL
#define platform_pm_freeze_noirq NULL
#define platform_pm_thaw_noirq NULL
#define platform_pm_poweroff_noirq NULL
#define platform_pm_restore_noirq NULL
#endif /* !CONFIG_HIBERNATION */
struct pm_ext_ops platform_pm_ops = {
.base = {
.prepare = platform_pm_prepare,
.complete = platform_pm_complete,
.suspend = platform_pm_suspend,
.resume = platform_pm_resume,
.freeze = platform_pm_freeze,
.thaw = platform_pm_thaw,
.poweroff = platform_pm_poweroff,
.restore = platform_pm_restore,
},
.suspend_noirq = platform_pm_suspend_noirq,
.resume_noirq = platform_pm_resume_noirq,
.freeze_noirq = platform_pm_freeze_noirq,
.thaw_noirq = platform_pm_thaw_noirq,
.poweroff_noirq = platform_pm_poweroff_noirq,
.restore_noirq = platform_pm_restore_noirq,
};
#define PLATFORM_PM_OPS_PTR &platform_pm_ops
#else /* !CONFIG_PM_SLEEP */
#define PLATFORM_PM_OPS_PTR NULL
#endif /* !CONFIG_PM_SLEEP */
struct bus_type platform_bus_type = { struct bus_type platform_bus_type = {
.name = "platform", .name = "platform",
.dev_attrs = platform_dev_attrs, .dev_attrs = platform_dev_attrs,
.match = platform_match, .match = platform_match,
.uevent = platform_uevent, .uevent = platform_uevent,
.suspend = platform_suspend, .pm = PLATFORM_PM_OPS_PTR,
.suspend_late = platform_suspend_late,
.resume_early = platform_resume_early,
.resume = platform_resume,
}; };
EXPORT_SYMBOL_GPL(platform_bus_type); EXPORT_SYMBOL_GPL(platform_bus_type);
......
此差异已折叠。
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* main.c * main.c
*/ */
extern struct list_head dpm_active; /* The active device list */ extern struct list_head dpm_list; /* The active device list */
static inline struct device *to_device(struct list_head *entry) static inline struct device *to_device(struct list_head *entry)
{ {
......
...@@ -6,9 +6,6 @@ ...@@ -6,9 +6,6 @@
#include <linux/string.h> #include <linux/string.h>
#include "power.h" #include "power.h"
int (*platform_enable_wakeup)(struct device *dev, int is_on);
/* /*
* wakeup - Report/change current wakeup option for device * wakeup - Report/change current wakeup option for device
* *
......
...@@ -188,9 +188,9 @@ static int show_file_hash(unsigned int value) ...@@ -188,9 +188,9 @@ static int show_file_hash(unsigned int value)
static int show_dev_hash(unsigned int value) static int show_dev_hash(unsigned int value)
{ {
int match = 0; int match = 0;
struct list_head * entry = dpm_active.prev; struct list_head *entry = dpm_list.prev;
while (entry != &dpm_active) { while (entry != &dpm_list) {
struct device * dev = to_device(entry); struct device * dev = to_device(entry);
unsigned int hash = hash_string(DEVSEED, dev->bus_id, DEVHASH); unsigned int hash = hash_string(DEVSEED, dev->bus_id, DEVHASH);
if (hash == value) { if (hash == value) {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for the PCI bus specific drivers. # Makefile for the PCI bus specific drivers.
# #
obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \ obj-y += access.o bus.o probe.o remove.o pci.o quirks.o slot.o \
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o pci-driver.o search.o pci-sysfs.o rom.o setup-res.o
obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_PROC_FS) += proc.o
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci_hotplug.h> #include <linux/pci_hotplug.h>
#include <linux/pci-acpi.h>
#include <acpi/acpi.h> #include <acpi/acpi.h>
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#include <acpi/actypes.h> #include <acpi/actypes.h>
...@@ -299,7 +300,7 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) ...@@ -299,7 +300,7 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
* *
* @handle - the handle of the hotplug controller. * @handle - the handle of the hotplug controller.
*/ */
acpi_status acpi_run_oshp(acpi_handle handle) static acpi_status acpi_run_oshp(acpi_handle handle)
{ {
acpi_status status; acpi_status status;
struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
...@@ -322,9 +323,6 @@ acpi_status acpi_run_oshp(acpi_handle handle) ...@@ -322,9 +323,6 @@ acpi_status acpi_run_oshp(acpi_handle handle)
kfree(string.pointer); kfree(string.pointer);
return status; return status;
} }
EXPORT_SYMBOL_GPL(acpi_run_oshp);
/* acpi_get_hp_params_from_firmware /* acpi_get_hp_params_from_firmware
* *
...@@ -374,6 +372,85 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, ...@@ -374,6 +372,85 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
} }
EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware); EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware);
/**
* acpi_get_hp_hw_control_from_firmware
* @dev: the pci_dev of the bridge that has a hotplug controller
* @flags: requested control bits for _OSC
*
* Attempt to take hotplug control from firmware.
*/
int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags)
{
acpi_status status;
acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev));
struct pci_dev *pdev = dev;
struct pci_bus *parent;
struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
OSC_SHPC_NATIVE_HP_CONTROL |
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
if (!flags) {
err("Invalid flags %u specified!\n", flags);
return -EINVAL;
}
/*
* Per PCI firmware specification, we should run the ACPI _OSC
* method to get control of hotplug hardware before using it. If
* an _OSC is missing, we look for an OSHP to do the same thing.
* To handle different BIOS behavior, we look for _OSC and OSHP
* within the scope of the hotplug controller and its parents,
* upto the host bridge under which this controller exists.
*/
while (!handle) {
/*
* This hotplug controller was not listed in the ACPI name
* space at all. Try to get acpi handle of parent pci bus.
*/
if (!pdev || !pdev->bus->parent)
break;
parent = pdev->bus->parent;
dbg("Could not find %s in acpi namespace, trying parent\n",
pci_name(pdev));
if (!parent->self)
/* Parent must be a host bridge */
handle = acpi_get_pci_rootbridge_handle(
pci_domain_nr(parent),
parent->number);
else
handle = DEVICE_ACPI_HANDLE(&(parent->self->dev));
pdev = parent->self;
}
while (handle) {
acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
dbg("Trying to get hotplug control for %s \n",
(char *)string.pointer);
status = pci_osc_control_set(handle, flags);
if (status == AE_NOT_FOUND)
status = acpi_run_oshp(handle);
if (ACPI_SUCCESS(status)) {
dbg("Gained control for hotplug HW for pci %s (%s)\n",
pci_name(dev), (char *)string.pointer);
kfree(string.pointer);
return 0;
}
if (acpi_root_bridge(handle))
break;
chandle = handle;
status = acpi_get_parent(chandle, &handle);
if (ACPI_FAILURE(status))
break;
}
dbg("Cannot get control of hotplug hardware for pci %s\n",
pci_name(dev));
kfree(string.pointer);
return -ENODEV;
}
EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware);
/* acpi_root_bridge - check to see if this acpi object is a root bridge /* acpi_root_bridge - check to see if this acpi object is a root bridge
* *
......
...@@ -215,7 +215,6 @@ extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot); ...@@ -215,7 +215,6 @@ extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot);
extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot); extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot);
extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
extern u32 acpiphp_get_address (struct acpiphp_slot *slot);
/* variables */ /* variables */
extern int acpiphp_debug; extern int acpiphp_debug;
......
...@@ -70,7 +70,6 @@ static int disable_slot (struct hotplug_slot *slot); ...@@ -70,7 +70,6 @@ static int disable_slot (struct hotplug_slot *slot);
static int set_attention_status (struct hotplug_slot *slot, u8 value); static int set_attention_status (struct hotplug_slot *slot, u8 value);
static int get_power_status (struct hotplug_slot *slot, u8 *value); static int get_power_status (struct hotplug_slot *slot, u8 *value);
static int get_attention_status (struct hotplug_slot *slot, u8 *value); static int get_attention_status (struct hotplug_slot *slot, u8 *value);
static int get_address (struct hotplug_slot *slot, u32 *value);
static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_latch_status (struct hotplug_slot *slot, u8 *value);
static int get_adapter_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
...@@ -83,7 +82,6 @@ static struct hotplug_slot_ops acpi_hotplug_slot_ops = { ...@@ -83,7 +82,6 @@ static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
.get_attention_status = get_attention_status, .get_attention_status = get_attention_status,
.get_latch_status = get_latch_status, .get_latch_status = get_latch_status,
.get_adapter_status = get_adapter_status, .get_adapter_status = get_adapter_status,
.get_address = get_address,
}; };
...@@ -274,23 +272,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) ...@@ -274,23 +272,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
return 0; return 0;
} }
/**
* get_address - get pci address of a slot
* @hotplug_slot: slot to get status
* @value: pointer to struct pci_busdev (seg, bus, dev)
*/
static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
{
struct slot *slot = hotplug_slot->private;
dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
*value = acpiphp_get_address(slot->acpi_slot);
return 0;
}
static int __init init_acpi(void) static int __init init_acpi(void)
{ {
int retval; int retval;
...@@ -357,7 +338,11 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) ...@@ -357,7 +338,11 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
acpiphp_slot->slot = slot; acpiphp_slot->slot = slot;
snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun); snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun);
retval = pci_hp_register(slot->hotplug_slot); retval = pci_hp_register(slot->hotplug_slot,
acpiphp_slot->bridge->pci_bus,
acpiphp_slot->device);
if (retval == -EBUSY)
goto error_hpslot;
if (retval) { if (retval) {
err("pci_hp_register failed with error %d\n", retval); err("pci_hp_register failed with error %d\n", retval);
goto error_hpslot; goto error_hpslot;
......
...@@ -258,7 +258,12 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -258,7 +258,12 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
bridge->pci_bus->number, slot->device); bridge->pci_bus->number, slot->device);
retval = acpiphp_register_hotplug_slot(slot); retval = acpiphp_register_hotplug_slot(slot);
if (retval) { if (retval) {
warn("acpiphp_register_hotplug_slot failed(err code = 0x%x)\n", retval); if (retval == -EBUSY)
warn("Slot %d already registered by another "
"hotplug driver\n", slot->sun);
else
warn("acpiphp_register_hotplug_slot failed "
"(err code = 0x%x)\n", retval);
goto err_exit; goto err_exit;
} }
} }
...@@ -1878,19 +1883,3 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) ...@@ -1878,19 +1883,3 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)
return (sta == 0) ? 0 : 1; return (sta == 0) ? 0 : 1;
} }
/*
* pci address (seg/bus/dev)
*/
u32 acpiphp_get_address(struct acpiphp_slot *slot)
{
u32 address;
struct pci_bus *pci_bus = slot->bridge->pci_bus;
address = (pci_domain_nr(pci_bus) << 16) |
(pci_bus->number << 8) |
slot->device;
return address;
}
...@@ -33,8 +33,10 @@ ...@@ -33,8 +33,10 @@
#include <linux/kobject.h> #include <linux/kobject.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/pci.h>
#include "acpiphp.h" #include "acpiphp.h"
#include "../pci.h"
#define DRIVER_VERSION "1.0.1" #define DRIVER_VERSION "1.0.1"
#define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>" #define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"
...@@ -430,7 +432,7 @@ static int __init ibm_acpiphp_init(void) ...@@ -430,7 +432,7 @@ static int __init ibm_acpiphp_init(void)
int retval = 0; int retval = 0;
acpi_status status; acpi_status status;
struct acpi_device *device; struct acpi_device *device;
struct kobject *sysdir = &pci_hotplug_slots_kset->kobj; struct kobject *sysdir = &pci_slots_kset->kobj;
dbg("%s\n", __func__); dbg("%s\n", __func__);
...@@ -477,7 +479,7 @@ static int __init ibm_acpiphp_init(void) ...@@ -477,7 +479,7 @@ static int __init ibm_acpiphp_init(void)
static void __exit ibm_acpiphp_exit(void) static void __exit ibm_acpiphp_exit(void)
{ {
acpi_status status; acpi_status status;
struct kobject *sysdir = &pci_hotplug_slots_kset->kobj; struct kobject *sysdir = &pci_slots_kset->kobj;
dbg("%s\n", __func__); dbg("%s\n", __func__);
......
...@@ -285,7 +285,7 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) ...@@ -285,7 +285,7 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
info->attention_status = cpci_get_attention_status(slot); info->attention_status = cpci_get_attention_status(slot);
dbg("registering slot %s", slot->hotplug_slot->name); dbg("registering slot %s", slot->hotplug_slot->name);
status = pci_hp_register(slot->hotplug_slot); status = pci_hp_register(slot->hotplug_slot, bus, i);
if (status) { if (status) {
err("pci_hp_register failed with error %d", status); err("pci_hp_register failed with error %d", status);
goto error_name; goto error_name;
......
...@@ -434,7 +434,9 @@ static int ctrl_slot_setup(struct controller *ctrl, ...@@ -434,7 +434,9 @@ static int ctrl_slot_setup(struct controller *ctrl,
slot->bus, slot->device, slot->bus, slot->device,
slot->number, ctrl->slot_device_offset, slot->number, ctrl->slot_device_offset,
slot_number); slot_number);
result = pci_hp_register(hotplug_slot); result = pci_hp_register(hotplug_slot,
ctrl->pci_dev->subordinate,
slot->device);
if (result) { if (result) {
err("pci_hp_register failed with error %d\n", result); err("pci_hp_register failed with error %d\n", result);
goto error_name; goto error_name;
......
...@@ -66,6 +66,7 @@ struct dummy_slot { ...@@ -66,6 +66,7 @@ struct dummy_slot {
struct pci_dev *dev; struct pci_dev *dev;
struct work_struct remove_work; struct work_struct remove_work;
unsigned long removed; unsigned long removed;
char name[8];
}; };
static int debug; static int debug;
...@@ -100,6 +101,7 @@ static int add_slot(struct pci_dev *dev) ...@@ -100,6 +101,7 @@ static int add_slot(struct pci_dev *dev)
struct dummy_slot *dslot; struct dummy_slot *dslot;
struct hotplug_slot *slot; struct hotplug_slot *slot;
int retval = -ENOMEM; int retval = -ENOMEM;
static int count = 1;
slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
if (!slot) if (!slot)
...@@ -113,18 +115,18 @@ static int add_slot(struct pci_dev *dev) ...@@ -113,18 +115,18 @@ static int add_slot(struct pci_dev *dev)
slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
slot->name = &dev->dev.bus_id[0];
dbg("slot->name = %s\n", slot->name);
dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL); dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL);
if (!dslot) if (!dslot)
goto error_info; goto error_info;
slot->name = dslot->name;
snprintf(slot->name, sizeof(dslot->name), "fake%d", count++);
dbg("slot->name = %s\n", slot->name);
slot->ops = &dummy_hotplug_slot_ops; slot->ops = &dummy_hotplug_slot_ops;
slot->release = &dummy_release; slot->release = &dummy_release;
slot->private = dslot; slot->private = dslot;
retval = pci_hp_register(slot); retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn));
if (retval) { if (retval) {
err("pci_hp_register failed with error %d\n", retval); err("pci_hp_register failed with error %d\n", retval);
goto error_dslot; goto error_dslot;
...@@ -148,17 +150,17 @@ static int add_slot(struct pci_dev *dev) ...@@ -148,17 +150,17 @@ static int add_slot(struct pci_dev *dev)
static int __init pci_scan_buses(void) static int __init pci_scan_buses(void)
{ {
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
int retval = 0; int lastslot = 0;
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
retval = add_slot(dev); if (PCI_FUNC(dev->devfn) > 0 &&
if (retval) { lastslot == PCI_SLOT(dev->devfn))
pci_dev_put(dev); continue;
break; lastslot = PCI_SLOT(dev->devfn);
} add_slot(dev);
} }
return retval; return 0;
} }
static void remove_slot(struct dummy_slot *dslot) static void remove_slot(struct dummy_slot *dslot)
...@@ -296,23 +298,9 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) ...@@ -296,23 +298,9 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
return 0; return 0;
} }
/* find the hotplug_slot for the pci_dev */
static struct hotplug_slot *get_slot_from_dev(struct pci_dev *dev)
{
struct dummy_slot *dslot;
list_for_each_entry(dslot, &slot_list, node) {
if (dslot->dev == dev)
return dslot->slot;
}
return NULL;
}
static int disable_slot(struct hotplug_slot *slot) static int disable_slot(struct hotplug_slot *slot)
{ {
struct dummy_slot *dslot; struct dummy_slot *dslot;
struct hotplug_slot *hslot;
struct pci_dev *dev; struct pci_dev *dev;
int func; int func;
...@@ -322,41 +310,27 @@ static int disable_slot(struct hotplug_slot *slot) ...@@ -322,41 +310,27 @@ static int disable_slot(struct hotplug_slot *slot)
dbg("%s - physical_slot = %s\n", __func__, slot->name); dbg("%s - physical_slot = %s\n", __func__, slot->name);
/* don't disable bridged devices just yet, we can't handle them easily... */ for (func = 7; func >= 0; func--) {
if (dslot->dev->subordinate) { dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func);
err("Can't remove PCI devices with other PCI devices behind it yet.\n"); if (!dev)
return -ENODEV; continue;
}
if (test_and_set_bit(0, &dslot->removed)) { if (test_and_set_bit(0, &dslot->removed)) {
dbg("Slot already scheduled for removal\n"); dbg("Slot already scheduled for removal\n");
return -ENODEV; return -ENODEV;
}
/* search for subfunctions and disable them first */
if (!(dslot->dev->devfn & 7)) {
for (func = 1; func < 8; func++) {
dev = pci_get_slot(dslot->dev->bus,
dslot->dev->devfn + func);
if (dev) {
hslot = get_slot_from_dev(dev);
if (hslot)
disable_slot(hslot);
else {
err("Hotplug slot not found for subfunction of PCI device\n");
return -ENODEV;
}
pci_dev_put(dev);
} else
dbg("No device in slot found\n");
} }
}
/* remove the device from the pci core */ /* queue work item to blow away this sysfs entry and other
pci_remove_bus_device(dslot->dev); * parts.
*/
INIT_WORK(&dslot->remove_work, remove_slot_worker);
queue_work(dummyphp_wq, &dslot->remove_work);
/* queue work item to blow away this sysfs entry and other parts. */ /* blow away this sysfs entry and other parts. */
INIT_WORK(&dslot->remove_work, remove_slot_worker); remove_slot(dslot);
queue_work(dummyphp_wq, &dslot->remove_work);
pci_dev_put(dev);
}
return 0; return 0;
} }
......
...@@ -1001,7 +1001,8 @@ static int __init ebda_rsrc_controller (void) ...@@ -1001,7 +1001,8 @@ static int __init ebda_rsrc_controller (void)
tmp_slot = list_entry (list, struct slot, ibm_slot_list); tmp_slot = list_entry (list, struct slot, ibm_slot_list);
snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot)); snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot));
pci_hp_register (tmp_slot->hotplug_slot); pci_hp_register(tmp_slot->hotplug_slot,
pci_find_bus(0, tmp_slot->bus), tmp_slot->device);
} }
print_ebda_hpc (); print_ebda_hpc ();
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci_hotplug.h> #include <linux/pci_hotplug.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "../pci.h"
#define MY_NAME "pci_hotplug" #define MY_NAME "pci_hotplug"
...@@ -60,41 +61,7 @@ static int debug; ...@@ -60,41 +61,7 @@ static int debug;
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
static LIST_HEAD(pci_hotplug_slot_list); static LIST_HEAD(pci_hotplug_slot_list);
static DEFINE_SPINLOCK(pci_hotplug_slot_list_lock);
struct kset *pci_hotplug_slots_kset;
static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
struct hotplug_slot *slot = to_hotplug_slot(kobj);
struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
return attribute->show ? attribute->show(slot, buf) : -EIO;
}
static ssize_t hotplug_slot_attr_store(struct kobject *kobj,
struct attribute *attr, const char *buf, size_t len)
{
struct hotplug_slot *slot = to_hotplug_slot(kobj);
struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
return attribute->store ? attribute->store(slot, buf, len) : -EIO;
}
static struct sysfs_ops hotplug_slot_sysfs_ops = {
.show = hotplug_slot_attr_show,
.store = hotplug_slot_attr_store,
};
static void hotplug_slot_release(struct kobject *kobj)
{
struct hotplug_slot *slot = to_hotplug_slot(kobj);
if (slot->release)
slot->release(slot);
}
static struct kobj_type hotplug_slot_ktype = {
.sysfs_ops = &hotplug_slot_sysfs_ops,
.release = &hotplug_slot_release,
};
/* these strings match up with the values in pci_bus_speed */ /* these strings match up with the values in pci_bus_speed */
static char *pci_bus_speed_strings[] = { static char *pci_bus_speed_strings[] = {
...@@ -149,16 +116,15 @@ GET_STATUS(power_status, u8) ...@@ -149,16 +116,15 @@ GET_STATUS(power_status, u8)
GET_STATUS(attention_status, u8) GET_STATUS(attention_status, u8)
GET_STATUS(latch_status, u8) GET_STATUS(latch_status, u8)
GET_STATUS(adapter_status, u8) GET_STATUS(adapter_status, u8)
GET_STATUS(address, u32)
GET_STATUS(max_bus_speed, enum pci_bus_speed) GET_STATUS(max_bus_speed, enum pci_bus_speed)
GET_STATUS(cur_bus_speed, enum pci_bus_speed) GET_STATUS(cur_bus_speed, enum pci_bus_speed)
static ssize_t power_read_file (struct hotplug_slot *slot, char *buf) static ssize_t power_read_file(struct pci_slot *slot, char *buf)
{ {
int retval; int retval;
u8 value; u8 value;
retval = get_power_status (slot, &value); retval = get_power_status(slot->hotplug, &value);
if (retval) if (retval)
goto exit; goto exit;
retval = sprintf (buf, "%d\n", value); retval = sprintf (buf, "%d\n", value);
...@@ -166,9 +132,10 @@ static ssize_t power_read_file (struct hotplug_slot *slot, char *buf) ...@@ -166,9 +132,10 @@ static ssize_t power_read_file (struct hotplug_slot *slot, char *buf)
return retval; return retval;
} }
static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf, static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
size_t count) size_t count)
{ {
struct hotplug_slot *slot = pci_slot->hotplug;
unsigned long lpower; unsigned long lpower;
u8 power; u8 power;
int retval = 0; int retval = 0;
...@@ -204,29 +171,30 @@ static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf, ...@@ -204,29 +171,30 @@ static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf,
return count; return count;
} }
static struct hotplug_slot_attribute hotplug_slot_attr_power = { static struct pci_slot_attribute hotplug_slot_attr_power = {
.attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR}, .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR},
.show = power_read_file, .show = power_read_file,
.store = power_write_file .store = power_write_file
}; };
static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf) static ssize_t attention_read_file(struct pci_slot *slot, char *buf)
{ {
int retval; int retval;
u8 value; u8 value;
retval = get_attention_status (slot, &value); retval = get_attention_status(slot->hotplug, &value);
if (retval) if (retval)
goto exit; goto exit;
retval = sprintf (buf, "%d\n", value); retval = sprintf(buf, "%d\n", value);
exit: exit:
return retval; return retval;
} }
static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, static ssize_t attention_write_file(struct pci_slot *slot, const char *buf,
size_t count) size_t count)
{ {
struct hotplug_slot_ops *ops = slot->hotplug->ops;
unsigned long lattention; unsigned long lattention;
u8 attention; u8 attention;
int retval = 0; int retval = 0;
...@@ -235,13 +203,13 @@ static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, ...@@ -235,13 +203,13 @@ static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
attention = (u8)(lattention & 0xff); attention = (u8)(lattention & 0xff);
dbg (" - attention = %d\n", attention); dbg (" - attention = %d\n", attention);
if (!try_module_get(slot->ops->owner)) { if (!try_module_get(ops->owner)) {
retval = -ENODEV; retval = -ENODEV;
goto exit; goto exit;
} }
if (slot->ops->set_attention_status) if (ops->set_attention_status)
retval = slot->ops->set_attention_status(slot, attention); retval = ops->set_attention_status(slot->hotplug, attention);
module_put(slot->ops->owner); module_put(ops->owner);
exit: exit:
if (retval) if (retval)
...@@ -249,18 +217,18 @@ static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, ...@@ -249,18 +217,18 @@ static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
return count; return count;
} }
static struct hotplug_slot_attribute hotplug_slot_attr_attention = { static struct pci_slot_attribute hotplug_slot_attr_attention = {
.attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR}, .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR},
.show = attention_read_file, .show = attention_read_file,
.store = attention_write_file .store = attention_write_file
}; };
static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf) static ssize_t latch_read_file(struct pci_slot *slot, char *buf)
{ {
int retval; int retval;
u8 value; u8 value;
retval = get_latch_status (slot, &value); retval = get_latch_status(slot->hotplug, &value);
if (retval) if (retval)
goto exit; goto exit;
retval = sprintf (buf, "%d\n", value); retval = sprintf (buf, "%d\n", value);
...@@ -269,17 +237,17 @@ static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf) ...@@ -269,17 +237,17 @@ static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf)
return retval; return retval;
} }
static struct hotplug_slot_attribute hotplug_slot_attr_latch = { static struct pci_slot_attribute hotplug_slot_attr_latch = {
.attr = {.name = "latch", .mode = S_IFREG | S_IRUGO}, .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO},
.show = latch_read_file, .show = latch_read_file,
}; };
static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf) static ssize_t presence_read_file(struct pci_slot *slot, char *buf)
{ {
int retval; int retval;
u8 value; u8 value;
retval = get_adapter_status (slot, &value); retval = get_adapter_status(slot->hotplug, &value);
if (retval) if (retval)
goto exit; goto exit;
retval = sprintf (buf, "%d\n", value); retval = sprintf (buf, "%d\n", value);
...@@ -288,42 +256,20 @@ static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf) ...@@ -288,42 +256,20 @@ static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf)
return retval; return retval;
} }
static struct hotplug_slot_attribute hotplug_slot_attr_presence = { static struct pci_slot_attribute hotplug_slot_attr_presence = {
.attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO}, .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO},
.show = presence_read_file, .show = presence_read_file,
}; };
static ssize_t address_read_file (struct hotplug_slot *slot, char *buf)
{
int retval;
u32 address;
retval = get_address (slot, &address);
if (retval)
goto exit;
retval = sprintf (buf, "%04x:%02x:%02x\n",
(address >> 16) & 0xffff,
(address >> 8) & 0xff,
address & 0xff);
exit:
return retval;
}
static struct hotplug_slot_attribute hotplug_slot_attr_address = {
.attr = {.name = "address", .mode = S_IFREG | S_IRUGO},
.show = address_read_file,
};
static char *unknown_speed = "Unknown bus speed"; static char *unknown_speed = "Unknown bus speed";
static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf) static ssize_t max_bus_speed_read_file(struct pci_slot *slot, char *buf)
{ {
char *speed_string; char *speed_string;
int retval; int retval;
enum pci_bus_speed value; enum pci_bus_speed value;
retval = get_max_bus_speed (slot, &value); retval = get_max_bus_speed(slot->hotplug, &value);
if (retval) if (retval)
goto exit; goto exit;
...@@ -338,18 +284,18 @@ static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf) ...@@ -338,18 +284,18 @@ static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
return retval; return retval;
} }
static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = { static struct pci_slot_attribute hotplug_slot_attr_max_bus_speed = {
.attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO}, .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO},
.show = max_bus_speed_read_file, .show = max_bus_speed_read_file,
}; };
static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf) static ssize_t cur_bus_speed_read_file(struct pci_slot *slot, char *buf)
{ {
char *speed_string; char *speed_string;
int retval; int retval;
enum pci_bus_speed value; enum pci_bus_speed value;
retval = get_cur_bus_speed (slot, &value); retval = get_cur_bus_speed(slot->hotplug, &value);
if (retval) if (retval)
goto exit; goto exit;
...@@ -364,14 +310,15 @@ static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf) ...@@ -364,14 +310,15 @@ static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
return retval; return retval;
} }
static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = { static struct pci_slot_attribute hotplug_slot_attr_cur_bus_speed = {
.attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO}, .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO},
.show = cur_bus_speed_read_file, .show = cur_bus_speed_read_file,
}; };
static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf, static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf,
size_t count) size_t count)
{ {
struct hotplug_slot *slot = pci_slot->hotplug;
unsigned long ltest; unsigned long ltest;
u32 test; u32 test;
int retval = 0; int retval = 0;
...@@ -394,13 +341,14 @@ static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf, ...@@ -394,13 +341,14 @@ static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf,
return count; return count;
} }
static struct hotplug_slot_attribute hotplug_slot_attr_test = { static struct pci_slot_attribute hotplug_slot_attr_test = {
.attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR}, .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR},
.store = test_write_file .store = test_write_file
}; };
static int has_power_file (struct hotplug_slot *slot) static int has_power_file(struct pci_slot *pci_slot)
{ {
struct hotplug_slot *slot = pci_slot->hotplug;
if ((!slot) || (!slot->ops)) if ((!slot) || (!slot->ops))
return -ENODEV; return -ENODEV;
if ((slot->ops->enable_slot) || if ((slot->ops->enable_slot) ||
...@@ -410,8 +358,9 @@ static int has_power_file (struct hotplug_slot *slot) ...@@ -410,8 +358,9 @@ static int has_power_file (struct hotplug_slot *slot)
return -ENOENT; return -ENOENT;
} }
static int has_attention_file (struct hotplug_slot *slot) static int has_attention_file(struct pci_slot *pci_slot)
{ {
struct hotplug_slot *slot = pci_slot->hotplug;
if ((!slot) || (!slot->ops)) if ((!slot) || (!slot->ops))
return -ENODEV; return -ENODEV;
if ((slot->ops->set_attention_status) || if ((slot->ops->set_attention_status) ||
...@@ -420,8 +369,9 @@ static int has_attention_file (struct hotplug_slot *slot) ...@@ -420,8 +369,9 @@ static int has_attention_file (struct hotplug_slot *slot)
return -ENOENT; return -ENOENT;
} }
static int has_latch_file (struct hotplug_slot *slot) static int has_latch_file(struct pci_slot *pci_slot)
{ {
struct hotplug_slot *slot = pci_slot->hotplug;
if ((!slot) || (!slot->ops)) if ((!slot) || (!slot->ops))
return -ENODEV; return -ENODEV;
if (slot->ops->get_latch_status) if (slot->ops->get_latch_status)
...@@ -429,8 +379,9 @@ static int has_latch_file (struct hotplug_slot *slot) ...@@ -429,8 +379,9 @@ static int has_latch_file (struct hotplug_slot *slot)
return -ENOENT; return -ENOENT;
} }
static int has_adapter_file (struct hotplug_slot *slot) static int has_adapter_file(struct pci_slot *pci_slot)
{ {
struct hotplug_slot *slot = pci_slot->hotplug;
if ((!slot) || (!slot->ops)) if ((!slot) || (!slot->ops))
return -ENODEV; return -ENODEV;
if (slot->ops->get_adapter_status) if (slot->ops->get_adapter_status)
...@@ -438,17 +389,9 @@ static int has_adapter_file (struct hotplug_slot *slot) ...@@ -438,17 +389,9 @@ static int has_adapter_file (struct hotplug_slot *slot)
return -ENOENT; return -ENOENT;
} }
static int has_address_file (struct hotplug_slot *slot) static int has_max_bus_speed_file(struct pci_slot *pci_slot)
{
if ((!slot) || (!slot->ops))
return -ENODEV;
if (slot->ops->get_address)
return 0;
return -ENOENT;
}
static int has_max_bus_speed_file (struct hotplug_slot *slot)
{ {
struct hotplug_slot *slot = pci_slot->hotplug;
if ((!slot) || (!slot->ops)) if ((!slot) || (!slot->ops))
return -ENODEV; return -ENODEV;
if (slot->ops->get_max_bus_speed) if (slot->ops->get_max_bus_speed)
...@@ -456,8 +399,9 @@ static int has_max_bus_speed_file (struct hotplug_slot *slot) ...@@ -456,8 +399,9 @@ static int has_max_bus_speed_file (struct hotplug_slot *slot)
return -ENOENT; return -ENOENT;
} }
static int has_cur_bus_speed_file (struct hotplug_slot *slot) static int has_cur_bus_speed_file(struct pci_slot *pci_slot)
{ {
struct hotplug_slot *slot = pci_slot->hotplug;
if ((!slot) || (!slot->ops)) if ((!slot) || (!slot->ops))
return -ENODEV; return -ENODEV;
if (slot->ops->get_cur_bus_speed) if (slot->ops->get_cur_bus_speed)
...@@ -465,8 +409,9 @@ static int has_cur_bus_speed_file (struct hotplug_slot *slot) ...@@ -465,8 +409,9 @@ static int has_cur_bus_speed_file (struct hotplug_slot *slot)
return -ENOENT; return -ENOENT;
} }
static int has_test_file (struct hotplug_slot *slot) static int has_test_file(struct pci_slot *pci_slot)
{ {
struct hotplug_slot *slot = pci_slot->hotplug;
if ((!slot) || (!slot->ops)) if ((!slot) || (!slot->ops))
return -ENODEV; return -ENODEV;
if (slot->ops->hardware_test) if (slot->ops->hardware_test)
...@@ -474,7 +419,7 @@ static int has_test_file (struct hotplug_slot *slot) ...@@ -474,7 +419,7 @@ static int has_test_file (struct hotplug_slot *slot)
return -ENOENT; return -ENOENT;
} }
static int fs_add_slot (struct hotplug_slot *slot) static int fs_add_slot(struct pci_slot *slot)
{ {
int retval = 0; int retval = 0;
...@@ -505,13 +450,6 @@ static int fs_add_slot (struct hotplug_slot *slot) ...@@ -505,13 +450,6 @@ static int fs_add_slot (struct hotplug_slot *slot)
goto exit_adapter; goto exit_adapter;
} }
if (has_address_file(slot) == 0) {
retval = sysfs_create_file(&slot->kobj,
&hotplug_slot_attr_address.attr);
if (retval)
goto exit_address;
}
if (has_max_bus_speed_file(slot) == 0) { if (has_max_bus_speed_file(slot) == 0) {
retval = sysfs_create_file(&slot->kobj, retval = sysfs_create_file(&slot->kobj,
&hotplug_slot_attr_max_bus_speed.attr); &hotplug_slot_attr_max_bus_speed.attr);
...@@ -544,10 +482,6 @@ static int fs_add_slot (struct hotplug_slot *slot) ...@@ -544,10 +482,6 @@ static int fs_add_slot (struct hotplug_slot *slot)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
exit_max_speed: exit_max_speed:
if (has_address_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
exit_address:
if (has_adapter_file(slot) == 0) if (has_adapter_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
...@@ -567,7 +501,7 @@ static int fs_add_slot (struct hotplug_slot *slot) ...@@ -567,7 +501,7 @@ static int fs_add_slot (struct hotplug_slot *slot)
return retval; return retval;
} }
static void fs_remove_slot (struct hotplug_slot *slot) static void fs_remove_slot(struct pci_slot *slot)
{ {
if (has_power_file(slot) == 0) if (has_power_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
...@@ -581,9 +515,6 @@ static void fs_remove_slot (struct hotplug_slot *slot) ...@@ -581,9 +515,6 @@ static void fs_remove_slot (struct hotplug_slot *slot)
if (has_adapter_file(slot) == 0) if (has_adapter_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
if (has_address_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
if (has_max_bus_speed_file(slot) == 0) if (has_max_bus_speed_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
...@@ -599,27 +530,33 @@ static struct hotplug_slot *get_slot_from_name (const char *name) ...@@ -599,27 +530,33 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
struct hotplug_slot *slot; struct hotplug_slot *slot;
struct list_head *tmp; struct list_head *tmp;
spin_lock(&pci_hotplug_slot_list_lock);
list_for_each (tmp, &pci_hotplug_slot_list) { list_for_each (tmp, &pci_hotplug_slot_list) {
slot = list_entry (tmp, struct hotplug_slot, slot_list); slot = list_entry (tmp, struct hotplug_slot, slot_list);
if (strcmp(slot->name, name) == 0) if (strcmp(slot->name, name) == 0)
return slot; goto out;
} }
return NULL; slot = NULL;
out:
spin_unlock(&pci_hotplug_slot_list_lock);
return slot;
} }
/** /**
* pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
* @bus: bus this slot is on
* @slot: pointer to the &struct hotplug_slot to register * @slot: pointer to the &struct hotplug_slot to register
* @slot_nr: slot number
* *
* Registers a hotplug slot with the pci hotplug subsystem, which will allow * Registers a hotplug slot with the pci hotplug subsystem, which will allow
* userspace interaction to the slot. * userspace interaction to the slot.
* *
* Returns 0 if successful, anything else for an error. * Returns 0 if successful, anything else for an error.
*/ */
int pci_hp_register (struct hotplug_slot *slot) int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr)
{ {
int result; int result;
struct hotplug_slot *tmp; struct pci_slot *pci_slot;
if (slot == NULL) if (slot == NULL)
return -ENODEV; return -ENODEV;
...@@ -632,57 +569,89 @@ int pci_hp_register (struct hotplug_slot *slot) ...@@ -632,57 +569,89 @@ int pci_hp_register (struct hotplug_slot *slot)
} }
/* Check if we have already registered a slot with the same name. */ /* Check if we have already registered a slot with the same name. */
tmp = get_slot_from_name(slot->name); if (get_slot_from_name(slot->name))
if (tmp)
return -EEXIST; return -EEXIST;
slot->kobj.kset = pci_hotplug_slots_kset; /*
result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL, * No problems if we call this interface from both ACPI_PCI_SLOT
"%s", slot->name); * driver and call it here again. If we've already created the
if (result) { * pci_slot, the interface will simply bump the refcount.
err("Unable to register kobject '%s'", slot->name); */
return -EINVAL; pci_slot = pci_create_slot(bus, slot_nr, slot->name);
if (IS_ERR(pci_slot))
return PTR_ERR(pci_slot);
if (pci_slot->hotplug) {
dbg("%s: already claimed\n", __func__);
pci_destroy_slot(pci_slot);
return -EBUSY;
} }
list_add (&slot->slot_list, &pci_hotplug_slot_list); slot->pci_slot = pci_slot;
pci_slot->hotplug = slot;
/*
* Allow pcihp drivers to override the ACPI_PCI_SLOT name.
*/
if (strcmp(kobject_name(&pci_slot->kobj), slot->name)) {
result = kobject_rename(&pci_slot->kobj, slot->name);
if (result) {
pci_destroy_slot(pci_slot);
return result;
}
}
spin_lock(&pci_hotplug_slot_list_lock);
list_add(&slot->slot_list, &pci_hotplug_slot_list);
spin_unlock(&pci_hotplug_slot_list_lock);
result = fs_add_slot(pci_slot);
kobject_uevent(&pci_slot->kobj, KOBJ_ADD);
dbg("Added slot %s to the list\n", slot->name);
result = fs_add_slot (slot);
kobject_uevent(&slot->kobj, KOBJ_ADD);
dbg ("Added slot %s to the list\n", slot->name);
return result; return result;
} }
/** /**
* pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem
* @slot: pointer to the &struct hotplug_slot to deregister * @hotplug: pointer to the &struct hotplug_slot to deregister
* *
* The @slot must have been registered with the pci hotplug subsystem * The @slot must have been registered with the pci hotplug subsystem
* previously with a call to pci_hp_register(). * previously with a call to pci_hp_register().
* *
* Returns 0 if successful, anything else for an error. * Returns 0 if successful, anything else for an error.
*/ */
int pci_hp_deregister (struct hotplug_slot *slot) int pci_hp_deregister(struct hotplug_slot *hotplug)
{ {
struct hotplug_slot *temp; struct hotplug_slot *temp;
struct pci_slot *slot;
if (slot == NULL) if (!hotplug)
return -ENODEV; return -ENODEV;
temp = get_slot_from_name (slot->name); temp = get_slot_from_name(hotplug->name);
if (temp != slot) { if (temp != hotplug)
return -ENODEV; return -ENODEV;
}
list_del (&slot->slot_list);
fs_remove_slot (slot); spin_lock(&pci_hotplug_slot_list_lock);
dbg ("Removed slot %s from the list\n", slot->name); list_del(&hotplug->slot_list);
kobject_put(&slot->kobj); spin_unlock(&pci_hotplug_slot_list_lock);
slot = hotplug->pci_slot;
fs_remove_slot(slot);
dbg("Removed slot %s from the list\n", hotplug->name);
hotplug->release(hotplug);
slot->hotplug = NULL;
pci_destroy_slot(slot);
return 0; return 0;
} }
/** /**
* pci_hp_change_slot_info - changes the slot's information structure in the core * pci_hp_change_slot_info - changes the slot's information structure in the core
* @slot: pointer to the slot whose info has changed * @hotplug: pointer to the slot whose info has changed
* @info: pointer to the info copy into the slot's info structure * @info: pointer to the info copy into the slot's info structure
* *
* @slot must have been registered with the pci * @slot must have been registered with the pci
...@@ -690,13 +659,15 @@ int pci_hp_deregister (struct hotplug_slot *slot) ...@@ -690,13 +659,15 @@ int pci_hp_deregister (struct hotplug_slot *slot)
* *
* Returns 0 if successful, anything else for an error. * Returns 0 if successful, anything else for an error.
*/ */
int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, int __must_check pci_hp_change_slot_info(struct hotplug_slot *hotplug,
struct hotplug_slot_info *info) struct hotplug_slot_info *info)
{ {
if ((slot == NULL) || (info == NULL)) struct pci_slot *slot;
if (!hotplug || !info)
return -ENODEV; return -ENODEV;
slot = hotplug->pci_slot;
memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info));
return 0; return 0;
} }
...@@ -704,36 +675,22 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, ...@@ -704,36 +675,22 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
static int __init pci_hotplug_init (void) static int __init pci_hotplug_init (void)
{ {
int result; int result;
struct kset *pci_bus_kset;
pci_bus_kset = bus_get_kset(&pci_bus_type);
pci_hotplug_slots_kset = kset_create_and_add("slots", NULL,
&pci_bus_kset->kobj);
if (!pci_hotplug_slots_kset) {
result = -ENOMEM;
err("Register subsys error\n");
goto exit;
}
result = cpci_hotplug_init(debug); result = cpci_hotplug_init(debug);
if (result) { if (result) {
err ("cpci_hotplug_init with error %d\n", result); err ("cpci_hotplug_init with error %d\n", result);
goto err_subsys; goto err_cpci;
} }
info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
goto exit;
err_subsys: err_cpci:
kset_unregister(pci_hotplug_slots_kset);
exit:
return result; return result;
} }
static void __exit pci_hotplug_exit (void) static void __exit pci_hotplug_exit (void)
{ {
cpci_hotplug_exit(); cpci_hotplug_exit();
kset_unregister(pci_hotplug_slots_kset);
} }
module_init(pci_hotplug_init); module_init(pci_hotplug_init);
...@@ -745,7 +702,6 @@ MODULE_LICENSE("GPL"); ...@@ -745,7 +702,6 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, 0644); module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
EXPORT_SYMBOL_GPL(pci_hotplug_slots_kset);
EXPORT_SYMBOL_GPL(pci_hp_register); EXPORT_SYMBOL_GPL(pci_hp_register);
EXPORT_SYMBOL_GPL(pci_hp_deregister); EXPORT_SYMBOL_GPL(pci_hp_deregister);
EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
...@@ -43,6 +43,7 @@ extern int pciehp_poll_mode; ...@@ -43,6 +43,7 @@ extern int pciehp_poll_mode;
extern int pciehp_poll_time; extern int pciehp_poll_time;
extern int pciehp_debug; extern int pciehp_debug;
extern int pciehp_force; extern int pciehp_force;
extern int pciehp_slot_with_bus;
extern struct workqueue_struct *pciehp_wq; extern struct workqueue_struct *pciehp_wq;
#define dbg(format, arg...) \ #define dbg(format, arg...) \
...@@ -96,7 +97,7 @@ struct controller { ...@@ -96,7 +97,7 @@ struct controller {
u32 slot_cap; u32 slot_cap;
u8 cap_base; u8 cap_base;
struct timer_list poll_timer; struct timer_list poll_timer;
volatile int cmd_busy; int cmd_busy;
unsigned int no_cmd_complete:1; unsigned int no_cmd_complete:1;
}; };
...@@ -156,10 +157,10 @@ extern u8 pciehp_handle_power_fault(struct slot *p_slot); ...@@ -156,10 +157,10 @@ extern u8 pciehp_handle_power_fault(struct slot *p_slot);
extern int pciehp_configure_device(struct slot *p_slot); extern int pciehp_configure_device(struct slot *p_slot);
extern int pciehp_unconfigure_device(struct slot *p_slot); extern int pciehp_unconfigure_device(struct slot *p_slot);
extern void pciehp_queue_pushbutton_work(struct work_struct *work); extern void pciehp_queue_pushbutton_work(struct work_struct *work);
int pcie_init(struct controller *ctrl, struct pcie_device *dev); struct controller *pcie_init(struct pcie_device *dev);
int pciehp_enable_slot(struct slot *p_slot); int pciehp_enable_slot(struct slot *p_slot);
int pciehp_disable_slot(struct slot *p_slot); int pciehp_disable_slot(struct slot *p_slot);
int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev); int pcie_enable_notification(struct controller *ctrl);
static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
{ {
...@@ -202,8 +203,13 @@ struct hpc_ops { ...@@ -202,8 +203,13 @@ struct hpc_ops {
#include <acpi/actypes.h> #include <acpi/actypes.h>
#include <linux/pci-acpi.h> #include <linux/pci-acpi.h>
#define pciehp_get_hp_hw_control_from_firmware(dev) \ static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
pciehp_acpi_get_hp_hw_control_from_firmware(dev) {
u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
return acpi_get_hp_hw_control_from_firmware(dev, flags);
}
static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
struct hotplug_params *hpp) struct hotplug_params *hpp)
{ {
......
...@@ -72,7 +72,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value); ...@@ -72,7 +72,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value);
static int get_attention_status (struct hotplug_slot *slot, u8 *value); static int get_attention_status (struct hotplug_slot *slot, u8 *value);
static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_latch_status (struct hotplug_slot *slot, u8 *value);
static int get_adapter_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
static int get_address (struct hotplug_slot *slot, u32 *value);
static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
...@@ -85,7 +84,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { ...@@ -85,7 +84,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
.get_attention_status = get_attention_status, .get_attention_status = get_attention_status,
.get_latch_status = get_latch_status, .get_latch_status = get_latch_status,
.get_adapter_status = get_adapter_status, .get_adapter_status = get_adapter_status,
.get_address = get_address,
.get_max_bus_speed = get_max_bus_speed, .get_max_bus_speed = get_max_bus_speed,
.get_cur_bus_speed = get_cur_bus_speed, .get_cur_bus_speed = get_cur_bus_speed,
}; };
...@@ -185,23 +183,10 @@ static struct hotplug_slot_attribute hotplug_slot_attr_lock = { ...@@ -185,23 +183,10 @@ static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
*/ */
static void release_slot(struct hotplug_slot *hotplug_slot) static void release_slot(struct hotplug_slot *hotplug_slot)
{ {
struct slot *slot = hotplug_slot->private;
dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
kfree(slot->hotplug_slot->info); kfree(hotplug_slot->info);
kfree(slot->hotplug_slot); kfree(hotplug_slot);
kfree(slot);
}
static void make_slot_name(struct slot *slot)
{
if (pciehp_slot_with_bus)
snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
slot->bus, slot->number);
else
snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d",
slot->number);
} }
static int init_slots(struct controller *ctrl) static int init_slots(struct controller *ctrl)
...@@ -210,49 +195,34 @@ static int init_slots(struct controller *ctrl) ...@@ -210,49 +195,34 @@ static int init_slots(struct controller *ctrl)
struct hotplug_slot *hotplug_slot; struct hotplug_slot *hotplug_slot;
struct hotplug_slot_info *info; struct hotplug_slot_info *info;
int retval = -ENOMEM; int retval = -ENOMEM;
int i;
for (i = 0; i < ctrl->num_slots; i++) {
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
if (!slot)
goto error;
list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
if (!hotplug_slot) if (!hotplug_slot)
goto error_slot; goto error;
slot->hotplug_slot = hotplug_slot;
info = kzalloc(sizeof(*info), GFP_KERNEL); info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) if (!info)
goto error_hpslot; goto error_hpslot;
hotplug_slot->info = info;
hotplug_slot->name = slot->name;
slot->hp_slot = i;
slot->ctrl = ctrl;
slot->bus = ctrl->pci_dev->subordinate->number;
slot->device = ctrl->slot_device_offset + i;
slot->hpc_ops = ctrl->hpc_ops;
slot->number = ctrl->first_slot;
mutex_init(&slot->lock);
INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
/* register this slot with the hotplug pci core */ /* register this slot with the hotplug pci core */
hotplug_slot->info = info;
hotplug_slot->name = slot->name;
hotplug_slot->private = slot; hotplug_slot->private = slot;
hotplug_slot->release = &release_slot; hotplug_slot->release = &release_slot;
make_slot_name(slot);
hotplug_slot->ops = &pciehp_hotplug_slot_ops; hotplug_slot->ops = &pciehp_hotplug_slot_ops;
get_power_status(hotplug_slot, &info->power_status); get_power_status(hotplug_slot, &info->power_status);
get_attention_status(hotplug_slot, &info->attention_status); get_attention_status(hotplug_slot, &info->attention_status);
get_latch_status(hotplug_slot, &info->latch_status); get_latch_status(hotplug_slot, &info->latch_status);
get_adapter_status(hotplug_slot, &info->adapter_status); get_adapter_status(hotplug_slot, &info->adapter_status);
slot->hotplug_slot = hotplug_slot;
dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
"slot_device_offset=%x\n", slot->bus, slot->device, "slot_device_offset=%x\n", slot->bus, slot->device,
slot->hp_slot, slot->number, ctrl->slot_device_offset); slot->hp_slot, slot->number, ctrl->slot_device_offset);
retval = pci_hp_register(hotplug_slot); retval = pci_hp_register(hotplug_slot,
ctrl->pci_dev->subordinate,
slot->device);
if (retval) { if (retval) {
err("pci_hp_register failed with error %d\n", retval); err("pci_hp_register failed with error %d\n", retval);
if (retval == -EEXIST) if (retval == -EEXIST)
...@@ -263,7 +233,7 @@ static int init_slots(struct controller *ctrl) ...@@ -263,7 +233,7 @@ static int init_slots(struct controller *ctrl)
} }
/* create additional sysfs entries */ /* create additional sysfs entries */
if (EMI(ctrl)) { if (EMI(ctrl)) {
retval = sysfs_create_file(&hotplug_slot->kobj, retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj,
&hotplug_slot_attr_lock.attr); &hotplug_slot_attr_lock.attr);
if (retval) { if (retval) {
pci_hp_deregister(hotplug_slot); pci_hp_deregister(hotplug_slot);
...@@ -271,8 +241,6 @@ static int init_slots(struct controller *ctrl) ...@@ -271,8 +241,6 @@ static int init_slots(struct controller *ctrl)
goto error_info; goto error_info;
} }
} }
list_add(&slot->slot_list, &ctrl->slot_list);
} }
return 0; return 0;
...@@ -280,27 +248,18 @@ static int init_slots(struct controller *ctrl) ...@@ -280,27 +248,18 @@ static int init_slots(struct controller *ctrl)
kfree(info); kfree(info);
error_hpslot: error_hpslot:
kfree(hotplug_slot); kfree(hotplug_slot);
error_slot:
kfree(slot);
error: error:
return retval; return retval;
} }
static void cleanup_slots(struct controller *ctrl) static void cleanup_slots(struct controller *ctrl)
{ {
struct list_head *tmp;
struct list_head *next;
struct slot *slot; struct slot *slot;
list_for_each_safe(tmp, next, &ctrl->slot_list) { list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
list_del(&slot->slot_list);
if (EMI(ctrl)) if (EMI(ctrl))
sysfs_remove_file(&slot->hotplug_slot->kobj, sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj,
&hotplug_slot_attr_lock.attr); &hotplug_slot_attr_lock.attr);
cancel_delayed_work(&slot->work);
flush_scheduled_work();
flush_workqueue(pciehp_wq);
pci_hp_deregister(slot->hotplug_slot); pci_hp_deregister(slot->hotplug_slot);
} }
} }
...@@ -398,19 +357,8 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) ...@@ -398,19 +357,8 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
return 0; return 0;
} }
static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) static int get_max_bus_speed(struct hotplug_slot *hotplug_slot,
{ enum pci_bus_speed *value)
struct slot *slot = hotplug_slot->private;
struct pci_bus *bus = slot->ctrl->pci_dev->subordinate;
dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
*value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device;
return 0;
}
static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
{ {
struct slot *slot = hotplug_slot->private; struct slot *slot = hotplug_slot->private;
int retval; int retval;
...@@ -444,34 +392,30 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ ...@@ -444,34 +392,30 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
struct controller *ctrl; struct controller *ctrl;
struct slot *t_slot; struct slot *t_slot;
u8 value; u8 value;
struct pci_dev *pdev; struct pci_dev *pdev = dev->port;
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); if (pciehp_force)
if (!ctrl) { dbg("Bypassing BIOS check for pciehp use on %s\n",
err("%s : out of memory\n", __func__); pci_name(pdev));
else if (pciehp_get_hp_hw_control_from_firmware(pdev))
goto err_out_none; goto err_out_none;
}
INIT_LIST_HEAD(&ctrl->slot_list);
pdev = dev->port;
ctrl->pci_dev = pdev;
rc = pcie_init(ctrl, dev); ctrl = pcie_init(dev);
if (rc) { if (!ctrl) {
dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME); dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME);
goto err_out_free_ctrl; goto err_out_none;
} }
set_service_data(dev, ctrl);
pci_set_drvdata(pdev, ctrl);
dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n",
__func__, pdev->bus->number, PCI_SLOT(pdev->devfn),
PCI_FUNC(pdev->devfn), pdev->irq);
/* Setup the slot information structures */ /* Setup the slot information structures */
rc = init_slots(ctrl); rc = init_slots(ctrl);
if (rc) { if (rc) {
err("%s: slot initialization failed\n", PCIE_MODULE_NAME); if (rc == -EBUSY)
warn("%s: slot already registered by another "
"hotplug driver\n", PCIE_MODULE_NAME);
else
err("%s: slot initialization failed\n",
PCIE_MODULE_NAME);
goto err_out_release_ctlr; goto err_out_release_ctlr;
} }
...@@ -495,20 +439,16 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ ...@@ -495,20 +439,16 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
cleanup_slots(ctrl); cleanup_slots(ctrl);
err_out_release_ctlr: err_out_release_ctlr:
ctrl->hpc_ops->release_ctlr(ctrl); ctrl->hpc_ops->release_ctlr(ctrl);
err_out_free_ctrl:
kfree(ctrl);
err_out_none: err_out_none:
return -ENODEV; return -ENODEV;
} }
static void pciehp_remove (struct pcie_device *dev) static void pciehp_remove (struct pcie_device *dev)
{ {
struct pci_dev *pdev = dev->port; struct controller *ctrl = get_service_data(dev);
struct controller *ctrl = pci_get_drvdata(pdev);
cleanup_slots(ctrl); cleanup_slots(ctrl);
ctrl->hpc_ops->release_ctlr(ctrl); ctrl->hpc_ops->release_ctlr(ctrl);
kfree(ctrl);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -522,13 +462,12 @@ static int pciehp_resume (struct pcie_device *dev) ...@@ -522,13 +462,12 @@ static int pciehp_resume (struct pcie_device *dev)
{ {
printk("%s ENTRY\n", __func__); printk("%s ENTRY\n", __func__);
if (pciehp_force) { if (pciehp_force) {
struct pci_dev *pdev = dev->port; struct controller *ctrl = get_service_data(dev);
struct controller *ctrl = pci_get_drvdata(pdev);
struct slot *t_slot; struct slot *t_slot;
u8 status; u8 status;
/* reinitialize the chipset's event detection logic */ /* reinitialize the chipset's event detection logic */
pcie_init_hardware_part2(ctrl, dev); pcie_enable_notification(ctrl);
t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
......
...@@ -247,30 +247,32 @@ static inline void pciehp_free_irq(struct controller *ctrl) ...@@ -247,30 +247,32 @@ static inline void pciehp_free_irq(struct controller *ctrl)
free_irq(ctrl->pci_dev->irq, ctrl); free_irq(ctrl->pci_dev->irq, ctrl);
} }
static inline int pcie_poll_cmd(struct controller *ctrl) static int pcie_poll_cmd(struct controller *ctrl)
{ {
u16 slot_status; u16 slot_status;
int timeout = 1000; int timeout = 1000;
if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) {
if (slot_status & CMD_COMPLETED) if (slot_status & CMD_COMPLETED) {
goto completed; pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED);
for (timeout = 1000; timeout > 0; timeout -= 100) { return 1;
msleep(100); }
if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) }
if (slot_status & CMD_COMPLETED) while (timeout > 1000) {
goto completed; msleep(10);
timeout -= 10;
if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) {
if (slot_status & CMD_COMPLETED) {
pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED);
return 1;
}
}
} }
return 0; /* timeout */ return 0; /* timeout */
completed:
pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED);
return timeout;
} }
static inline int pcie_wait_cmd(struct controller *ctrl, int poll) static void pcie_wait_cmd(struct controller *ctrl, int poll)
{ {
int retval = 0;
unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
unsigned long timeout = msecs_to_jiffies(msecs); unsigned long timeout = msecs_to_jiffies(msecs);
int rc; int rc;
...@@ -278,16 +280,9 @@ static inline int pcie_wait_cmd(struct controller *ctrl, int poll) ...@@ -278,16 +280,9 @@ static inline int pcie_wait_cmd(struct controller *ctrl, int poll)
if (poll) if (poll)
rc = pcie_poll_cmd(ctrl); rc = pcie_poll_cmd(ctrl);
else else
rc = wait_event_interruptible_timeout(ctrl->queue, rc = wait_event_timeout(ctrl->queue, !ctrl->cmd_busy, timeout);
!ctrl->cmd_busy, timeout);
if (!rc) if (!rc)
dbg("Command not completed in 1000 msec\n"); dbg("Command not completed in 1000 msec\n");
else if (rc < 0) {
retval = -EINTR;
info("Command was interrupted by a signal\n");
}
return retval;
} }
/** /**
...@@ -342,10 +337,6 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) ...@@ -342,10 +337,6 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
slot_ctrl &= ~mask; slot_ctrl &= ~mask;
slot_ctrl |= (cmd & mask); slot_ctrl |= (cmd & mask);
/* Don't enable command completed if caller is changing it. */
if (!(mask & CMD_CMPL_INTR_ENABLE))
slot_ctrl |= CMD_CMPL_INTR_ENABLE;
ctrl->cmd_busy = 1; ctrl->cmd_busy = 1;
smp_mb(); smp_mb();
retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl); retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl);
...@@ -365,7 +356,7 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) ...@@ -365,7 +356,7 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
if (!(slot_ctrl & HP_INTR_ENABLE) || if (!(slot_ctrl & HP_INTR_ENABLE) ||
!(slot_ctrl & CMD_CMPL_INTR_ENABLE)) !(slot_ctrl & CMD_CMPL_INTR_ENABLE))
poll = 1; poll = 1;
retval = pcie_wait_cmd(ctrl, poll); pcie_wait_cmd(ctrl, poll);
} }
out: out:
mutex_unlock(&ctrl->ctrl_lock); mutex_unlock(&ctrl->ctrl_lock);
...@@ -614,23 +605,6 @@ static void hpc_set_green_led_blink(struct slot *slot) ...@@ -614,23 +605,6 @@ static void hpc_set_green_led_blink(struct slot *slot)
__func__, ctrl->cap_base + SLOTCTRL, slot_cmd); __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
} }
static void hpc_release_ctlr(struct controller *ctrl)
{
/* Mask Hot-plug Interrupt Enable */
if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE))
err("%s: Cannot mask hotplut interrupt enable\n", __func__);
/* Free interrupt handler or interrupt polling timer */
pciehp_free_irq(ctrl);
/*
* If this is the last controller to be released, destroy the
* pciehp work queue
*/
if (atomic_dec_and_test(&pciehp_num_controllers))
destroy_workqueue(pciehp_wq);
}
static int hpc_power_on_slot(struct slot * slot) static int hpc_power_on_slot(struct slot * slot)
{ {
struct controller *ctrl = slot->ctrl; struct controller *ctrl = slot->ctrl;
...@@ -785,7 +759,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) ...@@ -785,7 +759,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
intr_loc |= detected; intr_loc |= detected;
if (!intr_loc) if (!intr_loc)
return IRQ_NONE; return IRQ_NONE;
if (pciehp_writew(ctrl, SLOTSTATUS, detected)) { if (detected && pciehp_writew(ctrl, SLOTSTATUS, detected)) {
err("%s: Cannot write to SLOTSTATUS\n", __func__); err("%s: Cannot write to SLOTSTATUS\n", __func__);
return IRQ_NONE; return IRQ_NONE;
} }
...@@ -797,25 +771,13 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) ...@@ -797,25 +771,13 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
if (intr_loc & CMD_COMPLETED) { if (intr_loc & CMD_COMPLETED) {
ctrl->cmd_busy = 0; ctrl->cmd_busy = 0;
smp_mb(); smp_mb();
wake_up_interruptible(&ctrl->queue); wake_up(&ctrl->queue);
} }
if (!(intr_loc & ~CMD_COMPLETED)) if (!(intr_loc & ~CMD_COMPLETED))
return IRQ_HANDLED; return IRQ_HANDLED;
/*
* Return without handling events if this handler routine is
* called before controller initialization is done. This may
* happen if hotplug event or another interrupt that shares
* the IRQ with pciehp arrives before slot initialization is
* done after interrupt handler is registered.
*
* FIXME - Need more structural fixes. We need to be ready to
* handle the event before installing interrupt handler.
*/
p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
if (!p_slot || !p_slot->hpc_ops)
return IRQ_HANDLED;
/* Check MRL Sensor Changed */ /* Check MRL Sensor Changed */
if (intr_loc & MRL_SENS_CHANGED) if (intr_loc & MRL_SENS_CHANGED)
...@@ -992,6 +954,7 @@ static int hpc_get_cur_lnk_width(struct slot *slot, ...@@ -992,6 +954,7 @@ static int hpc_get_cur_lnk_width(struct slot *slot,
return retval; return retval;
} }
static void pcie_release_ctrl(struct controller *ctrl);
static struct hpc_ops pciehp_hpc_ops = { static struct hpc_ops pciehp_hpc_ops = {
.power_on_slot = hpc_power_on_slot, .power_on_slot = hpc_power_on_slot,
.power_off_slot = hpc_power_off_slot, .power_off_slot = hpc_power_off_slot,
...@@ -1013,97 +976,11 @@ static struct hpc_ops pciehp_hpc_ops = { ...@@ -1013,97 +976,11 @@ static struct hpc_ops pciehp_hpc_ops = {
.green_led_off = hpc_set_green_led_off, .green_led_off = hpc_set_green_led_off,
.green_led_blink = hpc_set_green_led_blink, .green_led_blink = hpc_set_green_led_blink,
.release_ctlr = hpc_release_ctlr, .release_ctlr = pcie_release_ctrl,
.check_lnk_status = hpc_check_lnk_status, .check_lnk_status = hpc_check_lnk_status,
}; };
#ifdef CONFIG_ACPI int pcie_enable_notification(struct controller *ctrl)
static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
{
acpi_status status;
acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev));
struct pci_dev *pdev = dev;
struct pci_bus *parent;
struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
/*
* Per PCI firmware specification, we should run the ACPI _OSC
* method to get control of hotplug hardware before using it.
* If an _OSC is missing, we look for an OSHP to do the same thing.
* To handle different BIOS behavior, we look for _OSC and OSHP
* within the scope of the hotplug controller and its parents, upto
* the host bridge under which this controller exists.
*/
while (!handle) {
/*
* This hotplug controller was not listed in the ACPI name
* space at all. Try to get acpi handle of parent pci bus.
*/
if (!pdev || !pdev->bus->parent)
break;
parent = pdev->bus->parent;
dbg("Could not find %s in acpi namespace, trying parent\n",
pci_name(pdev));
if (!parent->self)
/* Parent must be a host bridge */
handle = acpi_get_pci_rootbridge_handle(
pci_domain_nr(parent),
parent->number);
else
handle = DEVICE_ACPI_HANDLE(
&(parent->self->dev));
pdev = parent->self;
}
while (handle) {
acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
dbg("Trying to get hotplug control for %s \n",
(char *)string.pointer);
status = pci_osc_control_set(handle,
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL |
OSC_PCI_EXPRESS_NATIVE_HP_CONTROL);
if (status == AE_NOT_FOUND)
status = acpi_run_oshp(handle);
if (ACPI_SUCCESS(status)) {
dbg("Gained control for hotplug HW for pci %s (%s)\n",
pci_name(dev), (char *)string.pointer);
kfree(string.pointer);
return 0;
}
if (acpi_root_bridge(handle))
break;
chandle = handle;
status = acpi_get_parent(chandle, &handle);
if (ACPI_FAILURE(status))
break;
}
dbg("Cannot get control of hotplug hardware for pci %s\n",
pci_name(dev));
kfree(string.pointer);
return -1;
}
#endif
static int pcie_init_hardware_part1(struct controller *ctrl,
struct pcie_device *dev)
{
/* Clear all remaining event bits in Slot Status register */
if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
err("%s: Cannot write to SLOTSTATUS register\n", __func__);
return -1;
}
/* Mask Hot-plug Interrupt Enable */
if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) {
err("%s: Cannot mask hotplug interrupt enable\n", __func__);
return -1;
}
return 0;
}
int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
{ {
u16 cmd, mask; u16 cmd, mask;
...@@ -1115,30 +992,83 @@ int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) ...@@ -1115,30 +992,83 @@ int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
if (MRL_SENS(ctrl)) if (MRL_SENS(ctrl))
cmd |= MRL_DETECT_ENABLE; cmd |= MRL_DETECT_ENABLE;
if (!pciehp_poll_mode) if (!pciehp_poll_mode)
cmd |= HP_INTR_ENABLE; cmd |= HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE;
mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | MRL_DETECT_ENABLE |
PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | HP_INTR_ENABLE; PWR_FAULT_DETECT_ENABLE | HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE;
if (pcie_write_cmd(ctrl, cmd, mask)) { if (pcie_write_cmd(ctrl, cmd, mask)) {
err("%s: Cannot enable software notification\n", __func__); err("%s: Cannot enable software notification\n", __func__);
goto abort; return -1;
} }
return 0;
}
if (pciehp_force) static void pcie_disable_notification(struct controller *ctrl)
dbg("Bypassing BIOS check for pciehp use on %s\n", {
pci_name(ctrl->pci_dev)); u16 mask;
else if (pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev)) mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | MRL_DETECT_ENABLE |
goto abort_disable_intr; PWR_FAULT_DETECT_ENABLE | HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE;
if (pcie_write_cmd(ctrl, 0, mask))
warn("%s: Cannot disable software notification\n", __func__);
}
static int pcie_init_notification(struct controller *ctrl)
{
if (pciehp_request_irq(ctrl))
return -1;
if (pcie_enable_notification(ctrl)) {
pciehp_free_irq(ctrl);
return -1;
}
return 0; return 0;
}
/* We end up here for the many possible ways to fail this API. */ static void pcie_shutdown_notification(struct controller *ctrl)
abort_disable_intr: {
if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE)) pcie_disable_notification(ctrl);
err("%s : disabling interrupts failed\n", __func__); pciehp_free_irq(ctrl);
abort: }
return -1;
static void make_slot_name(struct slot *slot)
{
if (pciehp_slot_with_bus)
snprintf(slot->name, SLOT_NAME_SIZE, "%04d_%04d",
slot->bus, slot->number);
else
snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number);
}
static int pcie_init_slot(struct controller *ctrl)
{
struct slot *slot;
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
if (!slot)
return -ENOMEM;
slot->hp_slot = 0;
slot->ctrl = ctrl;
slot->bus = ctrl->pci_dev->subordinate->number;
slot->device = ctrl->slot_device_offset + slot->hp_slot;
slot->hpc_ops = ctrl->hpc_ops;
slot->number = ctrl->first_slot;
make_slot_name(slot);
mutex_init(&slot->lock);
INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
list_add(&slot->slot_list, &ctrl->slot_list);
return 0;
}
static void pcie_cleanup_slot(struct controller *ctrl)
{
struct slot *slot;
slot = list_first_entry(&ctrl->slot_list, struct slot, slot_list);
list_del(&slot->slot_list);
cancel_delayed_work(&slot->work);
flush_scheduled_work();
flush_workqueue(pciehp_wq);
kfree(slot);
} }
static inline void dbg_ctrl(struct controller *ctrl) static inline void dbg_ctrl(struct controller *ctrl)
...@@ -1176,15 +1106,23 @@ static inline void dbg_ctrl(struct controller *ctrl) ...@@ -1176,15 +1106,23 @@ static inline void dbg_ctrl(struct controller *ctrl)
dbg(" Comamnd Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes"); dbg(" Comamnd Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes");
pciehp_readw(ctrl, SLOTSTATUS, &reg16); pciehp_readw(ctrl, SLOTSTATUS, &reg16);
dbg("Slot Status : 0x%04x\n", reg16); dbg("Slot Status : 0x%04x\n", reg16);
pciehp_readw(ctrl, SLOTSTATUS, &reg16); pciehp_readw(ctrl, SLOTCTRL, &reg16);
dbg("Slot Control : 0x%04x\n", reg16); dbg("Slot Control : 0x%04x\n", reg16);
} }
int pcie_init(struct controller *ctrl, struct pcie_device *dev) struct controller *pcie_init(struct pcie_device *dev)
{ {
struct controller *ctrl;
u32 slot_cap; u32 slot_cap;
struct pci_dev *pdev = dev->port; struct pci_dev *pdev = dev->port;
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl) {
err("%s : out of memory\n", __func__);
goto abort;
}
INIT_LIST_HEAD(&ctrl->slot_list);
ctrl->pci_dev = pdev; ctrl->pci_dev = pdev;
ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP);
if (!ctrl->cap_base) { if (!ctrl->cap_base) {
...@@ -1215,15 +1153,12 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev) ...@@ -1215,15 +1153,12 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev)
!(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl)))
ctrl->no_cmd_complete = 1; ctrl->no_cmd_complete = 1;
info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", /* Clear all remaining event bits in Slot Status register */
pdev->vendor, pdev->device, if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f))
pdev->subsystem_vendor, pdev->subsystem_device); goto abort_ctrl;
if (pcie_init_hardware_part1(ctrl, dev)) /* Disable sotfware notification */
goto abort; pcie_disable_notification(ctrl);
if (pciehp_request_irq(ctrl))
goto abort;
/* /*
* If this is the first controller to be initialized, * If this is the first controller to be initialized,
...@@ -1231,18 +1166,39 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev) ...@@ -1231,18 +1166,39 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev)
*/ */
if (atomic_add_return(1, &pciehp_num_controllers) == 1) { if (atomic_add_return(1, &pciehp_num_controllers) == 1) {
pciehp_wq = create_singlethread_workqueue("pciehpd"); pciehp_wq = create_singlethread_workqueue("pciehpd");
if (!pciehp_wq) { if (!pciehp_wq)
goto abort_free_irq; goto abort_ctrl;
}
} }
if (pcie_init_hardware_part2(ctrl, dev)) info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n",
goto abort_free_irq; pdev->vendor, pdev->device,
pdev->subsystem_vendor, pdev->subsystem_device);
if (pcie_init_slot(ctrl))
goto abort_ctrl;
return 0; if (pcie_init_notification(ctrl))
goto abort_slot;
abort_free_irq: return ctrl;
pciehp_free_irq(ctrl);
abort_slot:
pcie_cleanup_slot(ctrl);
abort_ctrl:
kfree(ctrl);
abort: abort:
return -1; return NULL;
}
void pcie_release_ctrl(struct controller *ctrl)
{
pcie_shutdown_notification(ctrl);
pcie_cleanup_slot(ctrl);
/*
* If this is the last controller to be released, destroy the
* pciehp work queue
*/
if (atomic_dec_and_test(&pciehp_num_controllers))
destroy_workqueue(pciehp_wq);
kfree(ctrl);
} }
...@@ -14,8 +14,10 @@ ...@@ -14,8 +14,10 @@
*/ */
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h> #include <linux/pci_hotplug.h>
#include "rpadlpar.h" #include "rpadlpar.h"
#include "../pci.h"
#define DLPAR_KOBJ_NAME "control" #define DLPAR_KOBJ_NAME "control"
...@@ -27,7 +29,6 @@ ...@@ -27,7 +29,6 @@
#define MAX_DRC_NAME_LEN 64 #define MAX_DRC_NAME_LEN 64
static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr, static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t nbytes) const char *buf, size_t nbytes)
{ {
...@@ -112,7 +113,7 @@ int dlpar_sysfs_init(void) ...@@ -112,7 +113,7 @@ int dlpar_sysfs_init(void)
int error; int error;
dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME, dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME,
&pci_hotplug_slots_kset->kobj); &pci_slots_kset->kobj);
if (!dlpar_kobj) if (!dlpar_kobj)
return -EINVAL; return -EINVAL;
......
...@@ -33,33 +33,6 @@ ...@@ -33,33 +33,6 @@
#include <asm/rtas.h> #include <asm/rtas.h>
#include "rpaphp.h" #include "rpaphp.h"
static ssize_t address_read_file (struct hotplug_slot *php_slot, char *buf)
{
int retval;
struct slot *slot = (struct slot *)php_slot->private;
struct pci_bus *bus;
if (!slot)
return -ENOENT;
bus = slot->bus;
if (!bus)
return -ENOENT;
if (bus->self)
retval = sprintf(buf, pci_name(bus->self));
else
retval = sprintf(buf, "%04x:%02x:00.0",
pci_domain_nr(bus), bus->number);
return retval;
}
static struct hotplug_slot_attribute php_attr_address = {
.attr = {.name = "address", .mode = S_IFREG | S_IRUGO},
.show = address_read_file,
};
/* free up the memory used by a slot */ /* free up the memory used by a slot */
static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
{ {
...@@ -135,9 +108,6 @@ int rpaphp_deregister_slot(struct slot *slot) ...@@ -135,9 +108,6 @@ int rpaphp_deregister_slot(struct slot *slot)
list_del(&slot->rpaphp_slot_list); list_del(&slot->rpaphp_slot_list);
/* remove "address" file */
sysfs_remove_file(&php_slot->kobj, &php_attr_address.attr);
retval = pci_hp_deregister(php_slot); retval = pci_hp_deregister(php_slot);
if (retval) if (retval)
err("Problem unregistering a slot %s\n", slot->name); err("Problem unregistering a slot %s\n", slot->name);
...@@ -151,6 +121,7 @@ int rpaphp_register_slot(struct slot *slot) ...@@ -151,6 +121,7 @@ int rpaphp_register_slot(struct slot *slot)
{ {
struct hotplug_slot *php_slot = slot->hotplug_slot; struct hotplug_slot *php_slot = slot->hotplug_slot;
int retval; int retval;
int slotno;
dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n",
__func__, slot->dn->full_name, slot->index, slot->name, __func__, slot->dn->full_name, slot->index, slot->name,
...@@ -162,19 +133,16 @@ int rpaphp_register_slot(struct slot *slot) ...@@ -162,19 +133,16 @@ int rpaphp_register_slot(struct slot *slot)
return -EAGAIN; return -EAGAIN;
} }
retval = pci_hp_register(php_slot); if (slot->dn->child)
slotno = PCI_SLOT(PCI_DN(slot->dn->child)->devfn);
else
slotno = -1;
retval = pci_hp_register(php_slot, slot->bus, slotno);
if (retval) { if (retval) {
err("pci_hp_register failed with error %d\n", retval); err("pci_hp_register failed with error %d\n", retval);
return retval; return retval;
} }
/* create "address" file */
retval = sysfs_create_file(&php_slot->kobj, &php_attr_address.attr);
if (retval) {
err("sysfs_create_file failed with error %d\n", retval);
goto sysfs_fail;
}
/* add slot to our internal list */ /* add slot to our internal list */
list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
info("Slot [%s] registered\n", slot->name); info("Slot [%s] registered\n", slot->name);
......
...@@ -197,13 +197,15 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, ...@@ -197,13 +197,15 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
static struct hotplug_slot * sn_hp_destroy(void) static struct hotplug_slot * sn_hp_destroy(void)
{ {
struct slot *slot; struct slot *slot;
struct pci_slot *pci_slot;
struct hotplug_slot *bss_hotplug_slot = NULL; struct hotplug_slot *bss_hotplug_slot = NULL;
list_for_each_entry(slot, &sn_hp_list, hp_list) { list_for_each_entry(slot, &sn_hp_list, hp_list) {
bss_hotplug_slot = slot->hotplug_slot; bss_hotplug_slot = slot->hotplug_slot;
pci_slot = bss_hotplug_slot->pci_slot;
list_del(&((struct slot *)bss_hotplug_slot->private)-> list_del(&((struct slot *)bss_hotplug_slot->private)->
hp_list); hp_list);
sysfs_remove_file(&bss_hotplug_slot->kobj, sysfs_remove_file(&pci_slot->kobj,
&sn_slot_path_attr.attr); &sn_slot_path_attr.attr);
break; break;
} }
...@@ -614,6 +616,7 @@ static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot) ...@@ -614,6 +616,7 @@ static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot)
static int sn_hotplug_slot_register(struct pci_bus *pci_bus) static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
{ {
int device; int device;
struct pci_slot *pci_slot;
struct hotplug_slot *bss_hotplug_slot; struct hotplug_slot *bss_hotplug_slot;
int rc = 0; int rc = 0;
...@@ -650,11 +653,12 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) ...@@ -650,11 +653,12 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
bss_hotplug_slot->ops = &sn_hotplug_slot_ops; bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
bss_hotplug_slot->release = &sn_release_slot; bss_hotplug_slot->release = &sn_release_slot;
rc = pci_hp_register(bss_hotplug_slot); rc = pci_hp_register(bss_hotplug_slot, pci_bus, device);
if (rc) if (rc)
goto register_err; goto register_err;
rc = sysfs_create_file(&bss_hotplug_slot->kobj, pci_slot = bss_hotplug_slot->pci_slot;
rc = sysfs_create_file(&pci_slot->kobj,
&sn_slot_path_attr.attr); &sn_slot_path_attr.attr);
if (rc) if (rc)
goto register_err; goto register_err;
...@@ -664,7 +668,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) ...@@ -664,7 +668,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
register_err: register_err:
dev_dbg(&pci_bus->self->dev, "bus failed to register with err = %d\n", dev_dbg(&pci_bus->self->dev, "bus failed to register with err = %d\n",
rc); rc);
alloc_err: alloc_err:
if (rc == -ENOMEM) if (rc == -ENOMEM)
......
...@@ -170,6 +170,7 @@ extern void shpchp_queue_pushbutton_work(struct work_struct *work); ...@@ -170,6 +170,7 @@ extern void shpchp_queue_pushbutton_work(struct work_struct *work);
extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev); extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
#include <linux/pci-acpi.h>
static inline int get_hp_params_from_firmware(struct pci_dev *dev, static inline int get_hp_params_from_firmware(struct pci_dev *dev,
struct hotplug_params *hpp) struct hotplug_params *hpp)
{ {
...@@ -177,14 +178,15 @@ static inline int get_hp_params_from_firmware(struct pci_dev *dev, ...@@ -177,14 +178,15 @@ static inline int get_hp_params_from_firmware(struct pci_dev *dev,
return -ENODEV; return -ENODEV;
return 0; return 0;
} }
#define get_hp_hw_control_from_firmware(pdev) \
do { \ static inline int get_hp_hw_control_from_firmware(struct pci_dev *dev)
if (DEVICE_ACPI_HANDLE(&(pdev->dev))) \ {
acpi_run_oshp(DEVICE_ACPI_HANDLE(&(pdev->dev)));\ u32 flags = OSC_SHPC_NATIVE_HP_CONTROL;
} while (0) return acpi_get_hp_hw_control_from_firmware(dev, flags);
}
#else #else
#define get_hp_params_from_firmware(dev, hpp) (-ENODEV) #define get_hp_params_from_firmware(dev, hpp) (-ENODEV)
#define get_hp_hw_control_from_firmware(dev) do { } while (0) #define get_hp_hw_control_from_firmware(dev) (0)
#endif #endif
struct ctrl_reg { struct ctrl_reg {
......
此差异已折叠。
...@@ -1084,7 +1084,6 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) ...@@ -1084,7 +1084,6 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __func__, dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __func__,
pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->bus->number, PCI_SLOT(pdev->devfn),
PCI_FUNC(pdev->devfn), pdev->irq); PCI_FUNC(pdev->devfn), pdev->irq);
get_hp_hw_control_from_firmware(pdev);
/* /*
* If this is the first controller to be initialized, * If this is the first controller to be initialized,
......
...@@ -1748,7 +1748,6 @@ int __init init_dmars(void) ...@@ -1748,7 +1748,6 @@ int __init init_dmars(void)
deferred_flush = kzalloc(g_num_of_iommus * deferred_flush = kzalloc(g_num_of_iommus *
sizeof(struct deferred_flush_tables), GFP_KERNEL); sizeof(struct deferred_flush_tables), GFP_KERNEL);
if (!deferred_flush) { if (!deferred_flush) {
kfree(g_iommus);
ret = -ENOMEM; ret = -ENOMEM;
goto error; goto error;
} }
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -50,10 +50,10 @@ int aer_osc_setup(struct pcie_device *pciedev) ...@@ -50,10 +50,10 @@ int aer_osc_setup(struct pcie_device *pciedev)
} }
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
printk(KERN_DEBUG "AER service couldn't init device %s - %s\n", dev_printk(KERN_DEBUG, &pciedev->device, "AER service couldn't "
pciedev->device.bus_id, "init device: %s\n",
(status == AE_SUPPORT || status == AE_NOT_FOUND) ? (status == AE_SUPPORT || status == AE_NOT_FOUND) ?
"no _OSC support" : "Run ACPI _OSC fails"); "no _OSC support" : "_OSC failed");
return -1; return -1;
} }
......
此差异已折叠。
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/pcieport_if.h> #include <linux/pcieport_if.h>
#include "portdrv.h"
static int pcie_port_bus_match(struct device *dev, struct device_driver *drv); static int pcie_port_bus_match(struct device *dev, struct device_driver *drv);
static int pcie_port_bus_suspend(struct device *dev, pm_message_t state); static int pcie_port_bus_suspend(struct device *dev, pm_message_t state);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册