Commit 0c26d7cc authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6

* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (72 commits)
  asus-laptop: remove EXPERIMENTAL dependency
  asus-laptop: use pr_fmt and pr_<level>
  eeepc-laptop: cpufv updates
  eeepc-laptop: sync eeepc-laptop with asus_acpi
  asus_acpi: Deprecate in favor of asus-laptop
  acpi4asus: update MAINTAINER and KConfig links
  asus-laptop: platform dev as parent for led and backlight
  eeepc-laptop: enable camera by default
  ACPI: Rename ACPI processor device bus ID
  acerhdf: Acer Aspire One fan control
  ACPI: video: DMI workaround broken Acer 7720 BIOS enabling display brightness
  ACPI: run ACPI device hot removal in kacpi_hotplug_wq
  ACPI: Add the reference count to avoid unloading ACPI video bus twice
  ACPI: DMI to disable Vista compatibility on some Sony laptops
  ACPI: fix a deadlock in hotplug case
  Show the physical device node of backlight class device.
  ACPI: pdc init related memory leak with physical CPU hotplug
  ACPI: pci_root: remove unused dev/fn information
  ACPI: pci_root: simplify list traversals
  ACPI: pci_root: use driver data rather than list lookup
  ...
parents 936940a9 21ab01e2
...@@ -229,14 +229,6 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -229,14 +229,6 @@ and is between 256 and 4096 characters. It is defined in the file
to assume that this machine's pmtimer latches its value to assume that this machine's pmtimer latches its value
and always returns good values. and always returns good values.
acpi.power_nocheck= [HW,ACPI]
Format: 1/0 enable/disable the check of power state.
On some bogus BIOS the _PSC object/_STA object of
power resource can't return the correct device power
state. In such case it is unneccessary to check its
power state again in power transition.
1 : disable the power state check
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 }
......
...@@ -920,7 +920,7 @@ The available commands are: ...@@ -920,7 +920,7 @@ The available commands are:
echo '<LED number> off' >/proc/acpi/ibm/led echo '<LED number> off' >/proc/acpi/ibm/led
echo '<LED number> blink' >/proc/acpi/ibm/led echo '<LED number> blink' >/proc/acpi/ibm/led
The <LED number> range is 0 to 7. The set of LEDs that can be The <LED number> range is 0 to 15. The set of LEDs that can be
controlled varies from model to model. Here is the common ThinkPad controlled varies from model to model. Here is the common ThinkPad
mapping: mapping:
...@@ -932,6 +932,11 @@ mapping: ...@@ -932,6 +932,11 @@ mapping:
5 - UltraBase battery slot 5 - UltraBase battery slot
6 - (unknown) 6 - (unknown)
7 - standby 7 - standby
8 - dock status 1
9 - dock status 2
10, 11 - (unknown)
12 - thinkvantage
13, 14, 15 - (unknown)
All of the above can be turned on and off and can be made to blink. All of the above can be turned on and off and can be made to blink.
...@@ -940,10 +945,12 @@ sysfs notes: ...@@ -940,10 +945,12 @@ sysfs notes:
The ThinkPad LED sysfs interface is described in detail by the LED class The ThinkPad LED sysfs interface is described in detail by the LED class
documentation, in Documentation/leds-class.txt. documentation, in Documentation/leds-class.txt.
The leds are named (in LED ID order, from 0 to 7): The LEDs are named (in LED ID order, from 0 to 12):
"tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt", "tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt",
"tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt", "tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt",
"tpacpi::unknown_led", "tpacpi::standby". "tpacpi::unknown_led", "tpacpi::standby", "tpacpi::dock_status1",
"tpacpi::dock_status2", "tpacpi::unknown_led2", "tpacpi::unknown_led3",
"tpacpi::thinkvantage".
Due to limitations in the sysfs LED class, if the status of the LED Due to limitations in the sysfs LED class, if the status of the LED
indicators cannot be read due to an error, thinkpad-acpi will report it as indicators cannot be read due to an error, thinkpad-acpi will report it as
...@@ -958,6 +965,12 @@ ThinkPad indicator LED should blink in hardware accelerated mode, use the ...@@ -958,6 +965,12 @@ ThinkPad indicator LED should blink in hardware accelerated mode, use the
"timer" trigger, and leave the delay_on and delay_off parameters set to "timer" trigger, and leave the delay_on and delay_off parameters set to
zero (to request hardware acceleration autodetection). zero (to request hardware acceleration autodetection).
LEDs that are known not to exist in a given ThinkPad model are not
made available through the sysfs interface. If you have a dock and you
notice there are LEDs listed for your ThinkPad that do not exist (and
are not in the dock), or if you notice that there are missing LEDs,
a report to ibm-acpi-devel@lists.sourceforge.net is appreciated.
ACPI sounds -- /proc/acpi/ibm/beep ACPI sounds -- /proc/acpi/ibm/beep
---------------------------------- ----------------------------------
...@@ -1156,17 +1169,19 @@ may not be distinct. Later Lenovo models that implement the ACPI ...@@ -1156,17 +1169,19 @@ may not be distinct. Later Lenovo models that implement the ACPI
display backlight brightness control methods have 16 levels, ranging display backlight brightness control methods have 16 levels, ranging
from 0 to 15. from 0 to 15.
There are two interfaces to the firmware for direct brightness control, For IBM ThinkPads, there are two interfaces to the firmware for direct
EC and UCMS (or CMOS). To select which one should be used, use the brightness control, EC and UCMS (or CMOS). To select which one should be
brightness_mode module parameter: brightness_mode=1 selects EC mode, used, use the brightness_mode module parameter: brightness_mode=1 selects
brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC EC mode, brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC
mode with NVRAM backing (so that brightness changes are remembered mode with NVRAM backing (so that brightness changes are remembered across
across shutdown/reboot). shutdown/reboot).
The driver tries to select which interface to use from a table of The driver tries to select which interface to use from a table of
defaults for each ThinkPad model. If it makes a wrong choice, please defaults for each ThinkPad model. If it makes a wrong choice, please
report this as a bug, so that we can fix it. report this as a bug, so that we can fix it.
Lenovo ThinkPads only support brightness_mode=2 (UCMS).
When display backlight brightness controls are available through the When display backlight brightness controls are available through the
standard ACPI interface, it is best to use it instead of this direct standard ACPI interface, it is best to use it instead of this direct
ThinkPad-specific interface. The driver will disable its native ThinkPad-specific interface. The driver will disable its native
...@@ -1254,7 +1269,7 @@ Fan control and monitoring: fan speed, fan enable/disable ...@@ -1254,7 +1269,7 @@ Fan control and monitoring: fan speed, fan enable/disable
procfs: /proc/acpi/ibm/fan procfs: /proc/acpi/ibm/fan
sysfs device attributes: (hwmon "thinkpad") fan1_input, pwm1, sysfs device attributes: (hwmon "thinkpad") fan1_input, pwm1,
pwm1_enable pwm1_enable, fan2_input
sysfs hwmon driver attributes: fan_watchdog sysfs hwmon driver attributes: fan_watchdog
NOTE NOTE NOTE: fan control operations are disabled by default for NOTE NOTE NOTE: fan control operations are disabled by default for
...@@ -1267,6 +1282,9 @@ from the hardware registers of the embedded controller. This is known ...@@ -1267,6 +1282,9 @@ from the hardware registers of the embedded controller. This is known
to work on later R, T, X and Z series ThinkPads but may show a bogus to work on later R, T, X and Z series ThinkPads but may show a bogus
value on other models. value on other models.
Some Lenovo ThinkPads support a secondary fan. This fan cannot be
controlled separately, it shares the main fan control.
Fan levels: Fan levels:
Most ThinkPad fans work in "levels" at the firmware interface. Level 0 Most ThinkPad fans work in "levels" at the firmware interface. Level 0
...@@ -1397,6 +1415,11 @@ hwmon device attribute fan1_input: ...@@ -1397,6 +1415,11 @@ hwmon device attribute fan1_input:
which can take up to two minutes. May return rubbish on older which can take up to two minutes. May return rubbish on older
ThinkPads. ThinkPads.
hwmon device attribute fan2_input:
Fan tachometer reading, in RPM, for the secondary fan.
Available only on some ThinkPads. If the secondary fan is
not installed, will always read 0.
hwmon driver attribute fan_watchdog: hwmon driver attribute fan_watchdog:
Fan safety watchdog timer interval, in seconds. Minimum is Fan safety watchdog timer interval, in seconds. Minimum is
1 second, maximum is 120 seconds. 0 disables the watchdog. 1 second, maximum is 120 seconds. 0 disables the watchdog.
...@@ -1555,3 +1578,7 @@ Sysfs interface changelog: ...@@ -1555,3 +1578,7 @@ Sysfs interface changelog:
0x020300: hotkey enable/disable support removed, attributes 0x020300: hotkey enable/disable support removed, attributes
hotkey_bios_enabled and hotkey_enable deprecated and hotkey_bios_enabled and hotkey_enable deprecated and
marked for removal. marked for removal.
0x020400: Marker for 16 LEDs support. Also, LEDs that are known
to not exist in a given model are not registered with
the LED sysfs class anymore.
...@@ -230,6 +230,13 @@ L: linux-acenic@sunsite.dk ...@@ -230,6 +230,13 @@ L: linux-acenic@sunsite.dk
S: Maintained S: Maintained
F: drivers/net/acenic* F: drivers/net/acenic*
ACER ASPIRE ONE TEMPERATURE AND FAN DRIVER
P: Peter Feuerer
M: peter@piie.net
W: http://piie.net/?section=acerhdf
S: Maintained
F: drivers/platform/x86/acerhdf.c
ACER WMI LAPTOP EXTRAS ACER WMI LAPTOP EXTRAS
P: Carlos Corbacho P: Carlos Corbacho
M: carlos@strangeworlds.co.uk M: carlos@strangeworlds.co.uk
...@@ -913,8 +920,7 @@ M: corentincj@iksaif.net ...@@ -913,8 +920,7 @@ M: corentincj@iksaif.net
P: Karol Kozimor P: Karol Kozimor
M: sziwan@users.sourceforge.net M: sziwan@users.sourceforge.net
L: acpi4asus-user@lists.sourceforge.net L: acpi4asus-user@lists.sourceforge.net
W: http://sourceforge.net/projects/acpi4asus W: http://acpi4asus.sf.net
W: http://xf.iksaif.net/acpi4asus
S: Maintained S: Maintained
F: arch/x86/kernel/acpi/boot.c F: arch/x86/kernel/acpi/boot.c
F: drivers/platform/x86/asus_acpi.c F: drivers/platform/x86/asus_acpi.c
...@@ -930,8 +936,7 @@ ASUS LAPTOP EXTRAS DRIVER ...@@ -930,8 +936,7 @@ ASUS LAPTOP EXTRAS DRIVER
P: Corentin Chary P: Corentin Chary
M: corentincj@iksaif.net M: corentincj@iksaif.net
L: acpi4asus-user@lists.sourceforge.net L: acpi4asus-user@lists.sourceforge.net
W: http://sourceforge.net/projects/acpi4asus W: http://acpi4asus.sf.net
W: http://xf.iksaif.net/acpi4asus
S: Maintained S: Maintained
F: drivers/platform/x86/asus-laptop.c F: drivers/platform/x86/asus-laptop.c
...@@ -2110,7 +2115,7 @@ EEEPC LAPTOP EXTRAS DRIVER ...@@ -2110,7 +2115,7 @@ EEEPC LAPTOP EXTRAS DRIVER
P: Corentin Chary P: Corentin Chary
M: corentincj@iksaif.net M: corentincj@iksaif.net
L: acpi4asus-user@lists.sourceforge.net L: acpi4asus-user@lists.sourceforge.net
W: http://sourceforge.net/projects/acpi4asus W: http://acpi4asus.sf.net
S: Maintained S: Maintained
F: drivers/platform/x86/eeepc-laptop.c F: drivers/platform/x86/eeepc-laptop.c
......
...@@ -71,3 +71,15 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr) ...@@ -71,3 +71,15 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr)
} }
EXPORT_SYMBOL(arch_acpi_processor_init_pdc); EXPORT_SYMBOL(arch_acpi_processor_init_pdc);
void arch_acpi_processor_cleanup_pdc(struct acpi_processor *pr)
{
if (pr->pdc) {
kfree(pr->pdc->pointer->buffer.pointer);
kfree(pr->pdc->pointer);
kfree(pr->pdc);
pr->pdc = NULL;
}
}
EXPORT_SYMBOL(arch_acpi_processor_cleanup_pdc);
...@@ -144,6 +144,7 @@ static inline unsigned int acpi_processor_cstate_check(unsigned int max_cstate) ...@@ -144,6 +144,7 @@ static inline unsigned int acpi_processor_cstate_check(unsigned int max_cstate)
#else /* !CONFIG_ACPI */ #else /* !CONFIG_ACPI */
#define acpi_disabled 1
#define acpi_lapic 0 #define acpi_lapic 0
#define acpi_ioapic 0 #define acpi_ioapic 0
static inline void acpi_noirq_set(void) { } static inline void acpi_noirq_set(void) { }
......
...@@ -121,6 +121,9 @@ extern int __init pcibios_init(void); ...@@ -121,6 +121,9 @@ extern int __init pcibios_init(void);
extern int __init pci_mmcfg_arch_init(void); extern int __init pci_mmcfg_arch_init(void);
extern void __init pci_mmcfg_arch_free(void); extern void __init pci_mmcfg_arch_free(void);
extern struct acpi_mcfg_allocation *pci_mmcfg_config;
extern int pci_mmcfg_config_num;
/* /*
* AMD Fam10h CPUs are buggy, and cannot access MMIO config space * AMD Fam10h CPUs are buggy, and cannot access MMIO config space
* on their northbrige except through the * %eax register. As such, you MUST * on their northbrige except through the * %eax register. As such, you MUST
......
...@@ -44,11 +44,7 @@ ...@@ -44,11 +44,7 @@
static int __initdata acpi_force = 0; static int __initdata acpi_force = 0;
u32 acpi_rsdt_forced; u32 acpi_rsdt_forced;
#ifdef CONFIG_ACPI int acpi_disabled;
int acpi_disabled = 0;
#else
int acpi_disabled = 1;
#endif
EXPORT_SYMBOL(acpi_disabled); EXPORT_SYMBOL(acpi_disabled);
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
...@@ -122,72 +118,6 @@ void __init __acpi_unmap_table(char *map, unsigned long size) ...@@ -122,72 +118,6 @@ void __init __acpi_unmap_table(char *map, unsigned long size)
early_iounmap(map, size); early_iounmap(map, size);
} }
#ifdef CONFIG_PCI_MMCONFIG
static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
struct acpi_mcfg_allocation *pci_mmcfg_config;
int pci_mmcfg_config_num;
static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg)
{
if (!strcmp(mcfg->header.oem_id, "SGI"))
acpi_mcfg_64bit_base_addr = TRUE;
return 0;
}
int __init acpi_parse_mcfg(struct acpi_table_header *header)
{
struct acpi_table_mcfg *mcfg;
unsigned long i;
int config_size;
if (!header)
return -EINVAL;
mcfg = (struct acpi_table_mcfg *)header;
/* how many config structures do we have */
pci_mmcfg_config_num = 0;
i = header->length - sizeof(struct acpi_table_mcfg);
while (i >= sizeof(struct acpi_mcfg_allocation)) {
++pci_mmcfg_config_num;
i -= sizeof(struct acpi_mcfg_allocation);
};
if (pci_mmcfg_config_num == 0) {
printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
return -ENODEV;
}
config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config);
pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL);
if (!pci_mmcfg_config) {
printk(KERN_WARNING PREFIX
"No memory for MCFG config tables\n");
return -ENOMEM;
}
memcpy(pci_mmcfg_config, &mcfg[1], config_size);
acpi_mcfg_oem_check(mcfg);
for (i = 0; i < pci_mmcfg_config_num; ++i) {
if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) &&
!acpi_mcfg_64bit_base_addr) {
printk(KERN_ERR PREFIX
"MMCONFIG not in low 4GB of memory\n");
kfree(pci_mmcfg_config);
pci_mmcfg_config_num = 0;
return -ENODEV;
}
}
return 0;
}
#endif /* CONFIG_PCI_MMCONFIG */
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
static int __init acpi_parse_madt(struct acpi_table_header *table) static int __init acpi_parse_madt(struct acpi_table_header *table)
{ {
...@@ -1517,14 +1447,6 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = { ...@@ -1517,14 +1447,6 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Workstation W8000"), DMI_MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
}, },
}, },
{
.callback = force_acpi_ht,
.ident = "ASUS P4B266",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_BOARD_NAME, "P4B266"),
},
},
{ {
.callback = force_acpi_ht, .callback = force_acpi_ht,
.ident = "ASUS P2B-DS", .ident = "ASUS P2B-DS",
......
...@@ -34,12 +34,22 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, ...@@ -34,12 +34,22 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
flags->bm_check = 1; flags->bm_check = 1;
else if (c->x86_vendor == X86_VENDOR_INTEL) { else if (c->x86_vendor == X86_VENDOR_INTEL) {
/* /*
* Today all CPUs that support C3 share cache. * Today all MP CPUs that support C3 share cache.
* TBD: This needs to look at cache shared map, once * And caches should not be flushed by software while
* multi-core detection patch makes to the base. * entering C3 type state.
*/ */
flags->bm_check = 1; flags->bm_check = 1;
} }
/*
* On all recent Intel platforms, ARB_DISABLE is a nop.
* So, set bm_control to zero to indicate that ARB_DISABLE
* is not required while entering C3 type state on
* P4, Core and beyond CPUs
*/
if (c->x86_vendor == X86_VENDOR_INTEL &&
(c->x86 > 0x6 || (c->x86 == 6 && c->x86_model >= 14)))
flags->bm_control = 0;
} }
EXPORT_SYMBOL(acpi_processor_power_init_bm_check); EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
......
...@@ -72,6 +72,7 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c) ...@@ -72,6 +72,7 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c)
return; return;
} }
/* Initialize _PDC data based on the CPU vendor */ /* Initialize _PDC data based on the CPU vendor */
void arch_acpi_processor_init_pdc(struct acpi_processor *pr) void arch_acpi_processor_init_pdc(struct acpi_processor *pr)
{ {
...@@ -85,3 +86,15 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr) ...@@ -85,3 +86,15 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr)
} }
EXPORT_SYMBOL(arch_acpi_processor_init_pdc); EXPORT_SYMBOL(arch_acpi_processor_init_pdc);
void arch_acpi_processor_cleanup_pdc(struct acpi_processor *pr)
{
if (pr->pdc) {
kfree(pr->pdc->pointer->buffer.pointer);
kfree(pr->pdc->pointer);
kfree(pr->pdc);
pr->pdc = NULL;
}
}
EXPORT_SYMBOL(arch_acpi_processor_cleanup_pdc);
...@@ -523,6 +523,69 @@ static void __init pci_mmcfg_reject_broken(int early) ...@@ -523,6 +523,69 @@ static void __init pci_mmcfg_reject_broken(int early)
static int __initdata known_bridge; static int __initdata known_bridge;
static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
struct acpi_mcfg_allocation *pci_mmcfg_config;
int pci_mmcfg_config_num;
static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg)
{
if (!strcmp(mcfg->header.oem_id, "SGI"))
acpi_mcfg_64bit_base_addr = TRUE;
return 0;
}
static int __init pci_parse_mcfg(struct acpi_table_header *header)
{
struct acpi_table_mcfg *mcfg;
unsigned long i;
int config_size;
if (!header)
return -EINVAL;
mcfg = (struct acpi_table_mcfg *)header;
/* how many config structures do we have */
pci_mmcfg_config_num = 0;
i = header->length - sizeof(struct acpi_table_mcfg);
while (i >= sizeof(struct acpi_mcfg_allocation)) {
++pci_mmcfg_config_num;
i -= sizeof(struct acpi_mcfg_allocation);
};
if (pci_mmcfg_config_num == 0) {
printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
return -ENODEV;
}
config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config);
pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL);
if (!pci_mmcfg_config) {
printk(KERN_WARNING PREFIX
"No memory for MCFG config tables\n");
return -ENOMEM;
}
memcpy(pci_mmcfg_config, &mcfg[1], config_size);
acpi_mcfg_oem_check(mcfg);
for (i = 0; i < pci_mmcfg_config_num; ++i) {
if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) &&
!acpi_mcfg_64bit_base_addr) {
printk(KERN_ERR PREFIX
"MMCONFIG not in low 4GB of memory\n");
kfree(pci_mmcfg_config);
pci_mmcfg_config_num = 0;
return -ENODEV;
}
}
return 0;
}
static void __init __pci_mmcfg_init(int early) static void __init __pci_mmcfg_init(int early)
{ {
/* MMCONFIG disabled */ /* MMCONFIG disabled */
...@@ -543,7 +606,7 @@ static void __init __pci_mmcfg_init(int early) ...@@ -543,7 +606,7 @@ static void __init __pci_mmcfg_init(int early)
} }
if (!known_bridge) if (!known_bridge)
acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); acpi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
pci_mmcfg_reject_broken(early); pci_mmcfg_reject_broken(early);
......
...@@ -61,6 +61,7 @@ static int acpi_ac_open_fs(struct inode *inode, struct file *file); ...@@ -61,6 +61,7 @@ static int acpi_ac_open_fs(struct inode *inode, struct file *file);
static int acpi_ac_add(struct acpi_device *device); static int acpi_ac_add(struct acpi_device *device);
static int acpi_ac_remove(struct acpi_device *device, int type); static int acpi_ac_remove(struct acpi_device *device, int type);
static int acpi_ac_resume(struct acpi_device *device); static int acpi_ac_resume(struct acpi_device *device);
static void acpi_ac_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id ac_device_ids[] = { static const struct acpi_device_id ac_device_ids[] = {
{"ACPI0003", 0}, {"ACPI0003", 0},
...@@ -72,10 +73,12 @@ static struct acpi_driver acpi_ac_driver = { ...@@ -72,10 +73,12 @@ static struct acpi_driver acpi_ac_driver = {
.name = "ac", .name = "ac",
.class = ACPI_AC_CLASS, .class = ACPI_AC_CLASS,
.ids = ac_device_ids, .ids = ac_device_ids,
.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
.ops = { .ops = {
.add = acpi_ac_add, .add = acpi_ac_add,
.remove = acpi_ac_remove, .remove = acpi_ac_remove,
.resume = acpi_ac_resume, .resume = acpi_ac_resume,
.notify = acpi_ac_notify,
}, },
}; };
...@@ -220,16 +223,14 @@ static int acpi_ac_remove_fs(struct acpi_device *device) ...@@ -220,16 +223,14 @@ static int acpi_ac_remove_fs(struct acpi_device *device)
Driver Model Driver Model
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) static void acpi_ac_notify(struct acpi_device *device, u32 event)
{ {
struct acpi_ac *ac = data; struct acpi_ac *ac = acpi_driver_data(device);
struct acpi_device *device = NULL;
if (!ac) if (!ac)
return; return;
device = ac->device;
switch (event) { switch (event) {
default: default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
...@@ -253,7 +254,6 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) ...@@ -253,7 +254,6 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
static int acpi_ac_add(struct acpi_device *device) static int acpi_ac_add(struct acpi_device *device)
{ {
int result = 0; int result = 0;
acpi_status status = AE_OK;
struct acpi_ac *ac = NULL; struct acpi_ac *ac = NULL;
...@@ -286,13 +286,6 @@ static int acpi_ac_add(struct acpi_device *device) ...@@ -286,13 +286,6 @@ static int acpi_ac_add(struct acpi_device *device)
ac->charger.get_property = get_ac_property; ac->charger.get_property = get_ac_property;
power_supply_register(&ac->device->dev, &ac->charger); power_supply_register(&ac->device->dev, &ac->charger);
#endif #endif
status = acpi_install_notify_handler(device->handle,
ACPI_ALL_NOTIFY, acpi_ac_notify,
ac);
if (ACPI_FAILURE(status)) {
result = -ENODEV;
goto end;
}
printk(KERN_INFO PREFIX "%s [%s] (%s)\n", printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
acpi_device_name(device), acpi_device_bid(device), acpi_device_name(device), acpi_device_bid(device),
...@@ -328,7 +321,6 @@ static int acpi_ac_resume(struct acpi_device *device) ...@@ -328,7 +321,6 @@ static int acpi_ac_resume(struct acpi_device *device)
static int acpi_ac_remove(struct acpi_device *device, int type) static int acpi_ac_remove(struct acpi_device *device, int type)
{ {
acpi_status status = AE_OK;
struct acpi_ac *ac = NULL; struct acpi_ac *ac = NULL;
...@@ -337,8 +329,6 @@ static int acpi_ac_remove(struct acpi_device *device, int type) ...@@ -337,8 +329,6 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
ac = acpi_driver_data(device); ac = acpi_driver_data(device);
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY, acpi_ac_notify);
#ifdef CONFIG_ACPI_SYSFS_POWER #ifdef CONFIG_ACPI_SYSFS_POWER
if (ac->charger.dev) if (ac->charger.dev)
power_supply_unregister(&ac->charger); power_supply_unregister(&ac->charger);
......
...@@ -796,13 +796,12 @@ static void acpi_battery_remove_fs(struct acpi_device *device) ...@@ -796,13 +796,12 @@ static void acpi_battery_remove_fs(struct acpi_device *device)
Driver Interface Driver Interface
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) static void acpi_battery_notify(struct acpi_device *device, u32 event)
{ {
struct acpi_battery *battery = data; struct acpi_battery *battery = acpi_driver_data(device);
struct acpi_device *device;
if (!battery) if (!battery)
return; return;
device = battery->device;
acpi_battery_update(battery); acpi_battery_update(battery);
acpi_bus_generate_proc_event(device, event, acpi_bus_generate_proc_event(device, event,
acpi_battery_present(battery)); acpi_battery_present(battery));
...@@ -819,7 +818,6 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) ...@@ -819,7 +818,6 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
static int acpi_battery_add(struct acpi_device *device) static int acpi_battery_add(struct acpi_device *device)
{ {
int result = 0; int result = 0;
acpi_status status = 0;
struct acpi_battery *battery = NULL; struct acpi_battery *battery = NULL;
if (!device) if (!device)
return -EINVAL; return -EINVAL;
...@@ -834,22 +832,12 @@ static int acpi_battery_add(struct acpi_device *device) ...@@ -834,22 +832,12 @@ static int acpi_battery_add(struct acpi_device *device)
acpi_battery_update(battery); acpi_battery_update(battery);
#ifdef CONFIG_ACPI_PROCFS_POWER #ifdef CONFIG_ACPI_PROCFS_POWER
result = acpi_battery_add_fs(device); result = acpi_battery_add_fs(device);
if (result)
goto end;
#endif #endif
status = acpi_install_notify_handler(device->handle, if (!result) {
ACPI_ALL_NOTIFY, printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
acpi_battery_notify, battery); ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
if (ACPI_FAILURE(status)) { device->status.battery_present ? "present" : "absent");
ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler")); } else {
result = -ENODEV;
goto end;
}
printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
device->status.battery_present ? "present" : "absent");
end:
if (result) {
#ifdef CONFIG_ACPI_PROCFS_POWER #ifdef CONFIG_ACPI_PROCFS_POWER
acpi_battery_remove_fs(device); acpi_battery_remove_fs(device);
#endif #endif
...@@ -860,15 +848,11 @@ static int acpi_battery_add(struct acpi_device *device) ...@@ -860,15 +848,11 @@ static int acpi_battery_add(struct acpi_device *device)
static int acpi_battery_remove(struct acpi_device *device, int type) static int acpi_battery_remove(struct acpi_device *device, int type)
{ {
acpi_status status = 0;
struct acpi_battery *battery = NULL; struct acpi_battery *battery = NULL;
if (!device || !acpi_driver_data(device)) if (!device || !acpi_driver_data(device))
return -EINVAL; return -EINVAL;
battery = acpi_driver_data(device); battery = acpi_driver_data(device);
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY,
acpi_battery_notify);
#ifdef CONFIG_ACPI_PROCFS_POWER #ifdef CONFIG_ACPI_PROCFS_POWER
acpi_battery_remove_fs(device); acpi_battery_remove_fs(device);
#endif #endif
...@@ -896,10 +880,12 @@ static struct acpi_driver acpi_battery_driver = { ...@@ -896,10 +880,12 @@ static struct acpi_driver acpi_battery_driver = {
.name = "battery", .name = "battery",
.class = ACPI_BATTERY_CLASS, .class = ACPI_BATTERY_CLASS,
.ids = battery_device_ids, .ids = battery_device_ids,
.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
.ops = { .ops = {
.add = acpi_battery_add, .add = acpi_battery_add,
.resume = acpi_battery_resume, .resume = acpi_battery_resume,
.remove = acpi_battery_remove, .remove = acpi_battery_remove,
.notify = acpi_battery_notify,
}, },
}; };
......
...@@ -192,6 +192,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { ...@@ -192,6 +192,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"), DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"),
}, },
}, },
{
.callback = dmi_disable_osi_vista,
.ident = "Sony VGN-NS10J_S",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS10J_S"),
},
},
{
.callback = dmi_disable_osi_vista,
.ident = "Sony VGN-SR290J",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "Sony VGN-SR290J"),
},
},
/* /*
* BIOS invocation of _OSI(Linux) is almost always a BIOS bug. * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
......
...@@ -450,18 +450,16 @@ int acpi_bus_receive_event(struct acpi_bus_event *event) ...@@ -450,18 +450,16 @@ int acpi_bus_receive_event(struct acpi_bus_event *event)
Notification Handling Notification Handling
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
static int static void acpi_bus_check_device(acpi_handle handle)
acpi_bus_check_device(struct acpi_device *device, int *status_changed)
{ {
acpi_status status = 0; struct acpi_device *device;
acpi_status status;
struct acpi_device_status old_status; struct acpi_device_status old_status;
if (acpi_bus_get_device(handle, &device))
return;
if (!device) if (!device)
return -EINVAL; return;
if (status_changed)
*status_changed = 0;
old_status = device->status; old_status = device->status;
...@@ -471,22 +469,15 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed) ...@@ -471,22 +469,15 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed)
*/ */
if (device->parent && !device->parent->status.present) { if (device->parent && !device->parent->status.present) {
device->status = device->parent->status; device->status = device->parent->status;
if (STRUCT_TO_INT(old_status) != STRUCT_TO_INT(device->status)) { return;
if (status_changed)
*status_changed = 1;
}
return 0;
} }
status = acpi_bus_get_status(device); status = acpi_bus_get_status(device);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; return;
if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status)) if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
return 0; return;
if (status_changed)
*status_changed = 1;
/* /*
* Device Insertion/Removal * Device Insertion/Removal
...@@ -498,33 +489,17 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed) ...@@ -498,33 +489,17 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n")); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n"));
/* TBD: Handle device removal */ /* TBD: Handle device removal */
} }
return 0;
} }
static int acpi_bus_check_scope(struct acpi_device *device) static void acpi_bus_check_scope(acpi_handle handle)
{ {
int result = 0;
int status_changed = 0;
if (!device)
return -EINVAL;
/* Status Change? */ /* Status Change? */
result = acpi_bus_check_device(device, &status_changed); acpi_bus_check_device(handle);
if (result)
return result;
if (!status_changed)
return 0;
/* /*
* TBD: Enumerate child devices within this device's scope and * TBD: Enumerate child devices within this device's scope and
* run acpi_bus_check_device()'s on them. * run acpi_bus_check_device()'s on them.
*/ */
return 0;
} }
static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list); static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
...@@ -547,22 +522,19 @@ EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier); ...@@ -547,22 +522,19 @@ EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
*/ */
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
{ {
int result = 0;
struct acpi_device *device = NULL; struct acpi_device *device = NULL;
struct acpi_driver *driver;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
type, handle));
blocking_notifier_call_chain(&acpi_bus_notify_list, blocking_notifier_call_chain(&acpi_bus_notify_list,
type, (void *)handle); type, (void *)handle);
if (acpi_bus_get_device(handle, &device))
return;
switch (type) { switch (type) {
case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_BUS_CHECK:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, acpi_bus_check_scope(handle);
"Received BUS CHECK notification for device [%s]\n",
device->pnp.bus_id));
result = acpi_bus_check_scope(device);
/* /*
* TBD: We'll need to outsource certain events to non-ACPI * TBD: We'll need to outsource certain events to non-ACPI
* drivers via the device manager (device.c). * drivers via the device manager (device.c).
...@@ -570,10 +542,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) ...@@ -570,10 +542,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
break; break;
case ACPI_NOTIFY_DEVICE_CHECK: case ACPI_NOTIFY_DEVICE_CHECK:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, acpi_bus_check_device(handle);
"Received DEVICE CHECK notification for device [%s]\n",
device->pnp.bus_id));
result = acpi_bus_check_device(device, NULL);
/* /*
* TBD: We'll need to outsource certain events to non-ACPI * TBD: We'll need to outsource certain events to non-ACPI
* drivers via the device manager (device.c). * drivers via the device manager (device.c).
...@@ -581,44 +550,26 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) ...@@ -581,44 +550,26 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
break; break;
case ACPI_NOTIFY_DEVICE_WAKE: case ACPI_NOTIFY_DEVICE_WAKE:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received DEVICE WAKE notification for device [%s]\n",
device->pnp.bus_id));
/* TBD */ /* TBD */
break; break;
case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_NOTIFY_EJECT_REQUEST:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received EJECT REQUEST notification for device [%s]\n",
device->pnp.bus_id));
/* TBD */ /* TBD */
break; break;
case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received DEVICE CHECK LIGHT notification for device [%s]\n",
device->pnp.bus_id));
/* TBD: Exactly what does 'light' mean? */ /* TBD: Exactly what does 'light' mean? */
break; break;
case ACPI_NOTIFY_FREQUENCY_MISMATCH: case ACPI_NOTIFY_FREQUENCY_MISMATCH:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received FREQUENCY MISMATCH notification for device [%s]\n",
device->pnp.bus_id));
/* TBD */ /* TBD */
break; break;
case ACPI_NOTIFY_BUS_MODE_MISMATCH: case ACPI_NOTIFY_BUS_MODE_MISMATCH:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received BUS MODE MISMATCH notification for device [%s]\n",
device->pnp.bus_id));
/* TBD */ /* TBD */
break; break;
case ACPI_NOTIFY_POWER_FAULT: case ACPI_NOTIFY_POWER_FAULT:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received POWER FAULT notification for device [%s]\n",
device->pnp.bus_id));
/* TBD */ /* TBD */
break; break;
...@@ -629,7 +580,13 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) ...@@ -629,7 +580,13 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
break; break;
} }
return; acpi_bus_get_device(handle, &device);
if (device) {
driver = device->driver;
if (driver && driver->ops.notify &&
(driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
driver->ops.notify(device, type);
}
} }
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
......
...@@ -140,46 +140,6 @@ struct device *acpi_get_physical_device(acpi_handle handle) ...@@ -140,46 +140,6 @@ struct device *acpi_get_physical_device(acpi_handle handle)
EXPORT_SYMBOL(acpi_get_physical_device); EXPORT_SYMBOL(acpi_get_physical_device);
/* ToDo: When a PCI bridge is found, return the PCI device behind the bridge
* This should work in general, but did not on a Lenovo T61 for the
* graphics card. But this must be fixed when the PCI device is
* bound and the kernel device struct is attached to the acpi device
* Note: A success call will increase reference count by one
* Do call put_device(dev) on the returned device then
*/
struct device *acpi_get_physical_pci_device(acpi_handle handle)
{
struct device *dev;
long long device_id;
acpi_status status;
status =
acpi_evaluate_integer(handle, "_ADR", NULL, &device_id);
if (ACPI_FAILURE(status))
return NULL;
/* We need to attempt to determine whether the _ADR refers to a
PCI device or not. There's no terribly good way to do this,
so the best we can hope for is to assume that there'll never
be a device in the host bridge */
if (device_id >= 0x10000) {
/* It looks like a PCI device. Does it exist? */
dev = acpi_get_physical_device(handle);
} else {
/* It doesn't look like a PCI device. Does its parent
exist? */
acpi_handle phandle;
if (acpi_get_parent(handle, &phandle))
return NULL;
dev = acpi_get_physical_device(phandle);
}
if (!dev)
return NULL;
return dev;
}
EXPORT_SYMBOL(acpi_get_physical_pci_device);
static int acpi_bind_one(struct device *dev, acpi_handle handle) static int acpi_bind_one(struct device *dev, acpi_handle handle)
{ {
struct acpi_device *acpi_dev; struct acpi_device *acpi_dev;
......
...@@ -79,6 +79,7 @@ static acpi_osd_handler acpi_irq_handler; ...@@ -79,6 +79,7 @@ static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context; static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq; static struct workqueue_struct *kacpid_wq;
static struct workqueue_struct *kacpi_notify_wq; static struct workqueue_struct *kacpi_notify_wq;
static struct workqueue_struct *kacpi_hotplug_wq;
struct acpi_res_list { struct acpi_res_list {
resource_size_t start; resource_size_t start;
...@@ -192,8 +193,10 @@ acpi_status acpi_os_initialize1(void) ...@@ -192,8 +193,10 @@ acpi_status acpi_os_initialize1(void)
{ {
kacpid_wq = create_singlethread_workqueue("kacpid"); kacpid_wq = create_singlethread_workqueue("kacpid");
kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify"); kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
kacpi_hotplug_wq = create_singlethread_workqueue("kacpi_hotplug");
BUG_ON(!kacpid_wq); BUG_ON(!kacpid_wq);
BUG_ON(!kacpi_notify_wq); BUG_ON(!kacpi_notify_wq);
BUG_ON(!kacpi_hotplug_wq);
return AE_OK; return AE_OK;
} }
...@@ -206,6 +209,7 @@ acpi_status acpi_os_terminate(void) ...@@ -206,6 +209,7 @@ acpi_status acpi_os_terminate(void)
destroy_workqueue(kacpid_wq); destroy_workqueue(kacpid_wq);
destroy_workqueue(kacpi_notify_wq); destroy_workqueue(kacpi_notify_wq);
destroy_workqueue(kacpi_hotplug_wq);
return AE_OK; return AE_OK;
} }
...@@ -716,6 +720,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, ...@@ -716,6 +720,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
acpi_status status = AE_OK; acpi_status status = AE_OK;
struct acpi_os_dpc *dpc; struct acpi_os_dpc *dpc;
struct workqueue_struct *queue; struct workqueue_struct *queue;
work_func_t func;
int ret; int ret;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Scheduling function [%p(%p)] for deferred execution.\n", "Scheduling function [%p(%p)] for deferred execution.\n",
...@@ -740,15 +745,17 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, ...@@ -740,15 +745,17 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
dpc->function = function; dpc->function = function;
dpc->context = context; dpc->context = context;
if (!hp) { /*
INIT_WORK(&dpc->work, acpi_os_execute_deferred); * We can't run hotplug code in keventd_wq/kacpid_wq/kacpid_notify_wq
queue = (type == OSL_NOTIFY_HANDLER) ? * because the hotplug code may call driver .remove() functions,
kacpi_notify_wq : kacpid_wq; * which invoke flush_scheduled_work/acpi_os_wait_events_complete
ret = queue_work(queue, &dpc->work); * to flush these workqueues.
} else { */
INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred); queue = hp ? kacpi_hotplug_wq :
ret = schedule_work(&dpc->work); (type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq);
} func = hp ? acpi_os_execute_hp_deferred : acpi_os_execute_deferred;
INIT_WORK(&dpc->work, func);
ret = queue_work(queue, &dpc->work);
if (!ret) { if (!ret) {
printk(KERN_ERR PREFIX printk(KERN_ERR PREFIX
......
...@@ -24,12 +24,7 @@ ...@@ -24,12 +24,7 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
...@@ -38,310 +33,76 @@ ...@@ -38,310 +33,76 @@
#define _COMPONENT ACPI_PCI_COMPONENT #define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_bind"); ACPI_MODULE_NAME("pci_bind");
struct acpi_pci_data { static int acpi_pci_unbind(struct acpi_device *device)
struct acpi_pci_id id;
struct pci_bus *bus;
struct pci_dev *dev;
};
static int acpi_pci_unbind(struct acpi_device *device);
static void acpi_pci_data_handler(acpi_handle handle, u32 function,
void *context)
{
/* TBD: Anything we need to do here? */
return;
}
/**
* acpi_get_pci_id
* ------------------
* This function is used by the ACPI Interpreter (a.k.a. Core Subsystem)
* to resolve PCI information for ACPI-PCI devices defined in the namespace.
* This typically occurs when resolving PCI operation region information.
*/
acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id)
{ {
int result = 0; struct pci_dev *dev;
acpi_status status = AE_OK;
struct acpi_device *device = NULL;
struct acpi_pci_data *data = NULL;
if (!id)
return AE_BAD_PARAMETER;
result = acpi_bus_get_device(handle, &device);
if (result) {
printk(KERN_ERR PREFIX
"Invalid ACPI Bus context for device %s\n",
acpi_device_bid(device));
return AE_NOT_EXIST;
}
status = acpi_get_data(handle, acpi_pci_data_handler, (void **)&data);
if (ACPI_FAILURE(status) || !data) {
ACPI_EXCEPTION((AE_INFO, status,
"Invalid ACPI-PCI context for device %s",
acpi_device_bid(device)));
return status;
}
*id = data->id; dev = acpi_get_pci_dev(device->handle);
if (!dev || !dev->subordinate)
goto out;
/* acpi_pci_irq_del_prt(dev->subordinate);
id->segment = data->id.segment;
id->bus = data->id.bus;
id->device = data->id.device;
id->function = data->id.function;
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO, device->ops.bind = NULL;
"Device %s has PCI address %04x:%02x:%02x.%d\n", device->ops.unbind = NULL;
acpi_device_bid(device), id->segment, id->bus,
id->device, id->function));
return AE_OK; out:
pci_dev_put(dev);
return 0;
} }
EXPORT_SYMBOL(acpi_get_pci_id); static int acpi_pci_bind(struct acpi_device *device)
int acpi_pci_bind(struct acpi_device *device)
{ {
int result = 0;
acpi_status status; acpi_status status;
struct acpi_pci_data *data;
struct acpi_pci_data *pdata;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_handle handle; acpi_handle handle;
struct pci_bus *bus;
struct pci_dev *dev;
if (!device || !device->parent) dev = acpi_get_pci_dev(device->handle);
return -EINVAL; if (!dev)
return 0;
data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
if (ACPI_FAILURE(status)) {
kfree(data);
return -ENODEV;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n",
(char *)buffer.pointer));
/*
* Segment & Bus
* -------------
* These are obtained via the parent device's ACPI-PCI context.
*/
status = acpi_get_data(device->parent->handle, acpi_pci_data_handler,
(void **)&pdata);
if (ACPI_FAILURE(status) || !pdata || !pdata->bus) {
ACPI_EXCEPTION((AE_INFO, status,
"Invalid ACPI-PCI context for parent device %s",
acpi_device_bid(device->parent)));
result = -ENODEV;
goto end;
}
data->id.segment = pdata->id.segment;
data->id.bus = pdata->bus->number;
/*
* Device & Function
* -----------------
* These are simply obtained from the device's _ADR method. Note
* that a value of zero is valid.
*/
data->id.device = device->pnp.bus_address >> 16;
data->id.function = device->pnp.bus_address & 0xFFFF;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %04x:%02x:%02x.%d\n",
data->id.segment, data->id.bus, data->id.device,
data->id.function));
/*
* TBD: Support slot devices (e.g. function=0xFFFF).
*/
/*
* Locate PCI Device
* -----------------
* Locate matching device in PCI namespace. If it doesn't exist
* this typically means that the device isn't currently inserted
* (e.g. docking station, port replicator, etc.).
*/
data->dev = pci_get_slot(pdata->bus,
PCI_DEVFN(data->id.device, data->id.function));
if (!data->dev) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device %04x:%02x:%02x.%d not present in PCI namespace\n",
data->id.segment, data->id.bus,
data->id.device, data->id.function));
result = -ENODEV;
goto end;
}
if (!data->dev->bus) {
printk(KERN_ERR PREFIX
"Device %04x:%02x:%02x.%d has invalid 'bus' field\n",
data->id.segment, data->id.bus,
data->id.device, data->id.function);
result = -ENODEV;
goto end;
}
/* /*
* PCI Bridge? * Install the 'bind' function to facilitate callbacks for
* ----------- * children of the P2P bridge.
* If so, set the 'bus' field and install the 'bind' function to
* facilitate callbacks for all of its children.
*/ */
if (data->dev->subordinate) { if (dev->subordinate) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device %04x:%02x:%02x.%d is a PCI bridge\n", "Device %04x:%02x:%02x.%d is a PCI bridge\n",
data->id.segment, data->id.bus, pci_domain_nr(dev->bus), dev->bus->number,
data->id.device, data->id.function)); PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)));
data->bus = data->dev->subordinate;
device->ops.bind = acpi_pci_bind; device->ops.bind = acpi_pci_bind;
device->ops.unbind = acpi_pci_unbind; device->ops.unbind = acpi_pci_unbind;
} }
/* /*
* Attach ACPI-PCI Context * Evaluate and parse _PRT, if exists. This code allows parsing of
* ----------------------- * _PRT objects within the scope of non-bridge devices. Note that
* Thus binding the ACPI and PCI devices. * _PRTs within the scope of a PCI bridge assume the bridge's
*/ * subordinate bus number.
status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Unable to attach ACPI-PCI context to device %s",
acpi_device_bid(device)));
result = -ENODEV;
goto end;
}
/*
* PCI Routing Table
* -----------------
* Evaluate and parse _PRT, if exists. This code is independent of
* PCI bridges (above) to allow parsing of _PRT objects within the
* scope of non-bridge devices. Note that _PRTs within the scope of
* a PCI bridge assume the bridge's subordinate bus number.
* *
* TBD: Can _PRTs exist within the scope of non-bridge PCI devices? * TBD: Can _PRTs exist within the scope of non-bridge PCI devices?
*/ */
status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
if (ACPI_SUCCESS(status)) {
if (data->bus) /* PCI-PCI bridge */
acpi_pci_irq_add_prt(device->handle, data->id.segment,
data->bus->number);
else /* non-bridge PCI device */
acpi_pci_irq_add_prt(device->handle, data->id.segment,
data->id.bus);
}
end:
kfree(buffer.pointer);
if (result) {
pci_dev_put(data->dev);
kfree(data);
}
return result;
}
static int acpi_pci_unbind(struct acpi_device *device)
{
int result = 0;
acpi_status status;
struct acpi_pci_data *data;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
if (!device || !device->parent)
return -EINVAL;
status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; goto out;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n", if (dev->subordinate)
(char *) buffer.pointer)); bus = dev->subordinate;
kfree(buffer.pointer); else
bus = dev->bus;
status = acpi_pci_irq_add_prt(device->handle, bus);
acpi_get_data(device->handle, acpi_pci_data_handler,
(void **)&data);
if (ACPI_FAILURE(status)) {
result = -ENODEV;
goto end;
}
status = acpi_detach_data(device->handle, acpi_pci_data_handler); out:
if (ACPI_FAILURE(status)) { pci_dev_put(dev);
ACPI_EXCEPTION((AE_INFO, status, return 0;
"Unable to detach data from device %s",
acpi_device_bid(device)));
result = -ENODEV;
goto end;
}
if (data->dev->subordinate) {
acpi_pci_irq_del_prt(data->id.segment, data->bus->number);
}
pci_dev_put(data->dev);
kfree(data);
end:
return result;
} }
int int acpi_pci_bind_root(struct acpi_device *device)
acpi_pci_bind_root(struct acpi_device *device,
struct acpi_pci_id *id, struct pci_bus *bus)
{ {
int result = 0;
acpi_status status;
struct acpi_pci_data *data = NULL;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
if (!device || !id || !bus) {
return -EINVAL;
}
data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->id = *id;
data->bus = bus;
device->ops.bind = acpi_pci_bind; device->ops.bind = acpi_pci_bind;
device->ops.unbind = acpi_pci_unbind; device->ops.unbind = acpi_pci_unbind;
status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); return 0;
if (ACPI_FAILURE(status)) {
kfree (data);
return -ENODEV;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to "
"%04x:%02x\n", (char *)buffer.pointer,
id->segment, id->bus));
status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Unable to attach ACPI-PCI context to device %s",
(char *)buffer.pointer));
result = -ENODEV;
goto end;
}
end:
kfree(buffer.pointer);
if (result != 0)
kfree(data);
return result;
} }
...@@ -182,7 +182,7 @@ static void do_prt_fixups(struct acpi_prt_entry *entry, ...@@ -182,7 +182,7 @@ static void do_prt_fixups(struct acpi_prt_entry *entry,
} }
} }
static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, static int acpi_pci_irq_add_entry(acpi_handle handle, struct pci_bus *bus,
struct acpi_pci_routing_table *prt) struct acpi_pci_routing_table *prt)
{ {
struct acpi_prt_entry *entry; struct acpi_prt_entry *entry;
...@@ -196,8 +196,8 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, ...@@ -196,8 +196,8 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus,
* 1=INTA, 2=INTB. We use the PCI encoding throughout, so convert * 1=INTA, 2=INTB. We use the PCI encoding throughout, so convert
* it here. * it here.
*/ */
entry->id.segment = segment; entry->id.segment = pci_domain_nr(bus);
entry->id.bus = bus; entry->id.bus = bus->number;
entry->id.device = (prt->address >> 16) & 0xFFFF; entry->id.device = (prt->address >> 16) & 0xFFFF;
entry->pin = prt->pin + 1; entry->pin = prt->pin + 1;
...@@ -242,7 +242,7 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, ...@@ -242,7 +242,7 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus,
return 0; return 0;
} }
int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) int acpi_pci_irq_add_prt(acpi_handle handle, struct pci_bus *bus)
{ {
acpi_status status; acpi_status status;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
...@@ -271,7 +271,7 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) ...@@ -271,7 +271,7 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
entry = buffer.pointer; entry = buffer.pointer;
while (entry && (entry->length > 0)) { while (entry && (entry->length > 0)) {
acpi_pci_irq_add_entry(handle, segment, bus, entry); acpi_pci_irq_add_entry(handle, bus, entry);
entry = (struct acpi_pci_routing_table *) entry = (struct acpi_pci_routing_table *)
((unsigned long)entry + entry->length); ((unsigned long)entry + entry->length);
} }
...@@ -280,16 +280,17 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) ...@@ -280,16 +280,17 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
return 0; return 0;
} }
void acpi_pci_irq_del_prt(int segment, int bus) void acpi_pci_irq_del_prt(struct pci_bus *bus)
{ {
struct acpi_prt_entry *entry, *tmp; struct acpi_prt_entry *entry, *tmp;
printk(KERN_DEBUG printk(KERN_DEBUG
"ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n", "ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n",
segment, bus); pci_domain_nr(bus), bus->number);
spin_lock(&acpi_prt_lock); spin_lock(&acpi_prt_lock);
list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) { list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) {
if (segment == entry->id.segment && bus == entry->id.bus) { if (pci_domain_nr(bus) == entry->id.segment
&& bus->number == entry->id.bus) {
list_del(&entry->list); list_del(&entry->list);
kfree(entry); kfree(entry);
} }
......
...@@ -63,9 +63,10 @@ static struct acpi_driver acpi_pci_root_driver = { ...@@ -63,9 +63,10 @@ static struct acpi_driver acpi_pci_root_driver = {
struct acpi_pci_root { struct acpi_pci_root {
struct list_head node; struct list_head node;
struct acpi_device * device; struct acpi_device *device;
struct acpi_pci_id id;
struct pci_bus *bus; struct pci_bus *bus;
u16 segment;
u8 bus_nr;
u32 osc_support_set; /* _OSC state of support bits */ u32 osc_support_set; /* _OSC state of support bits */
u32 osc_control_set; /* _OSC state of control bits */ u32 osc_control_set; /* _OSC state of control bits */
...@@ -82,7 +83,7 @@ static DEFINE_MUTEX(osc_lock); ...@@ -82,7 +83,7 @@ static DEFINE_MUTEX(osc_lock);
int acpi_pci_register_driver(struct acpi_pci_driver *driver) int acpi_pci_register_driver(struct acpi_pci_driver *driver)
{ {
int n = 0; int n = 0;
struct list_head *entry; struct acpi_pci_root *root;
struct acpi_pci_driver **pptr = &sub_driver; struct acpi_pci_driver **pptr = &sub_driver;
while (*pptr) while (*pptr)
...@@ -92,9 +93,7 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver) ...@@ -92,9 +93,7 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver)
if (!driver->add) if (!driver->add)
return 0; return 0;
list_for_each(entry, &acpi_pci_roots) { list_for_each_entry(root, &acpi_pci_roots, node) {
struct acpi_pci_root *root;
root = list_entry(entry, struct acpi_pci_root, node);
driver->add(root->device->handle); driver->add(root->device->handle);
n++; n++;
} }
...@@ -106,7 +105,7 @@ EXPORT_SYMBOL(acpi_pci_register_driver); ...@@ -106,7 +105,7 @@ EXPORT_SYMBOL(acpi_pci_register_driver);
void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
{ {
struct list_head *entry; struct acpi_pci_root *root;
struct acpi_pci_driver **pptr = &sub_driver; struct acpi_pci_driver **pptr = &sub_driver;
while (*pptr) { while (*pptr) {
...@@ -120,28 +119,48 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) ...@@ -120,28 +119,48 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
if (!driver->remove) if (!driver->remove)
return; return;
list_for_each(entry, &acpi_pci_roots) { list_for_each_entry(root, &acpi_pci_roots, node)
struct acpi_pci_root *root;
root = list_entry(entry, struct acpi_pci_root, node);
driver->remove(root->device->handle); driver->remove(root->device->handle);
}
} }
EXPORT_SYMBOL(acpi_pci_unregister_driver); EXPORT_SYMBOL(acpi_pci_unregister_driver);
acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
{ {
struct acpi_pci_root *tmp; struct acpi_pci_root *root;
list_for_each_entry(tmp, &acpi_pci_roots, node) { list_for_each_entry(root, &acpi_pci_roots, node)
if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus)) if ((root->segment == (u16) seg) && (root->bus_nr == (u16) bus))
return tmp->device->handle; return root->device->handle;
}
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle); EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
/**
* acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge
* @handle - the ACPI CA node in question.
*
* Note: we could make this API take a struct acpi_device * instead, but
* for now, it's more convenient to operate on an acpi_handle.
*/
int acpi_is_root_bridge(acpi_handle handle)
{
int ret;
struct acpi_device *device;
ret = acpi_bus_get_device(handle, &device);
if (ret)
return 0;
ret = acpi_match_device_ids(device, root_device_ids);
if (ret)
return 0;
else
return 1;
}
EXPORT_SYMBOL_GPL(acpi_is_root_bridge);
static acpi_status static acpi_status
get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
{ {
...@@ -161,19 +180,22 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) ...@@ -161,19 +180,22 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
return AE_OK; return AE_OK;
} }
static acpi_status try_get_root_bridge_busnr(acpi_handle handle, int *busnum) static acpi_status try_get_root_bridge_busnr(acpi_handle handle,
unsigned long long *bus)
{ {
acpi_status status; acpi_status status;
int busnum;
*busnum = -1; busnum = -1;
status = status =
acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_walk_resources(handle, METHOD_NAME__CRS,
get_root_bridge_busnr_callback, busnum); get_root_bridge_busnr_callback, &busnum);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return status; return status;
/* Check if we really get a bus number from _CRS */ /* Check if we really get a bus number from _CRS */
if (*busnum == -1) if (busnum == -1)
return AE_ERROR; return AE_ERROR;
*bus = busnum;
return AE_OK; return AE_OK;
} }
...@@ -298,6 +320,7 @@ static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags) ...@@ -298,6 +320,7 @@ static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags)
static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
{ {
struct acpi_pci_root *root; struct acpi_pci_root *root;
list_for_each_entry(root, &acpi_pci_roots, node) { list_for_each_entry(root, &acpi_pci_roots, node) {
if (root->device->handle == handle) if (root->device->handle == handle)
return root; return root;
...@@ -305,6 +328,87 @@ static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) ...@@ -305,6 +328,87 @@ static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
return NULL; return NULL;
} }
struct acpi_handle_node {
struct list_head node;
acpi_handle handle;
};
/**
* acpi_get_pci_dev - convert ACPI CA handle to struct pci_dev
* @handle: the handle in question
*
* Given an ACPI CA handle, the desired PCI device is located in the
* list of PCI devices.
*
* If the device is found, its reference count is increased and this
* function returns a pointer to its data structure. The caller must
* decrement the reference count by calling pci_dev_put().
* If no device is found, %NULL is returned.
*/
struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
{
int dev, fn;
unsigned long long adr;
acpi_status status;
acpi_handle phandle;
struct pci_bus *pbus;
struct pci_dev *pdev = NULL;
struct acpi_handle_node *node, *tmp;
struct acpi_pci_root *root;
LIST_HEAD(device_list);
/*
* Walk up the ACPI CA namespace until we reach a PCI root bridge.
*/
phandle = handle;
while (!acpi_is_root_bridge(phandle)) {
node = kzalloc(sizeof(struct acpi_handle_node), GFP_KERNEL);
if (!node)
goto out;
INIT_LIST_HEAD(&node->node);
node->handle = phandle;
list_add(&node->node, &device_list);
status = acpi_get_parent(phandle, &phandle);
if (ACPI_FAILURE(status))
goto out;
}
root = acpi_pci_find_root(phandle);
if (!root)
goto out;
pbus = root->bus;
/*
* Now, walk back down the PCI device tree until we return to our
* original handle. Assumes that everything between the PCI root
* bridge and the device we're looking for must be a P2P bridge.
*/
list_for_each_entry(node, &device_list, node) {
acpi_handle hnd = node->handle;
status = acpi_evaluate_integer(hnd, "_ADR", NULL, &adr);
if (ACPI_FAILURE(status))
goto out;
dev = (adr >> 16) & 0xffff;
fn = adr & 0xffff;
pdev = pci_get_slot(pbus, PCI_DEVFN(dev, fn));
if (hnd == handle)
break;
pbus = pdev->subordinate;
pci_dev_put(pdev);
}
out:
list_for_each_entry_safe(node, tmp, &device_list, node)
kfree(node);
return pdev;
}
EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
/** /**
* acpi_pci_osc_control_set - commit requested control to Firmware * acpi_pci_osc_control_set - commit requested control to Firmware
* @handle: acpi_handle for the target ACPI object * @handle: acpi_handle for the target ACPI object
...@@ -363,31 +467,46 @@ EXPORT_SYMBOL(acpi_pci_osc_control_set); ...@@ -363,31 +467,46 @@ EXPORT_SYMBOL(acpi_pci_osc_control_set);
static int __devinit acpi_pci_root_add(struct acpi_device *device) static int __devinit acpi_pci_root_add(struct acpi_device *device)
{ {
int result = 0; unsigned long long segment, bus;
struct acpi_pci_root *root = NULL; acpi_status status;
struct acpi_pci_root *tmp; int result;
acpi_status status = AE_OK; struct acpi_pci_root *root;
unsigned long long value = 0; acpi_handle handle;
acpi_handle handle = NULL;
struct acpi_device *child; struct acpi_device *child;
u32 flags, base_flags; u32 flags, base_flags;
segment = 0;
status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
&segment);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
printk(KERN_ERR PREFIX "can't evaluate _SEG\n");
return -ENODEV;
}
if (!device) /* Check _CRS first, then _BBN. If no _BBN, default to zero. */
return -EINVAL; bus = 0;
status = try_get_root_bridge_busnr(device->handle, &bus);
if (ACPI_FAILURE(status)) {
status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, &bus);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
printk(KERN_ERR PREFIX
"no bus number in _CRS and can't evaluate _BBN\n");
return -ENODEV;
}
}
root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
if (!root) if (!root)
return -ENOMEM; return -ENOMEM;
INIT_LIST_HEAD(&root->node);
INIT_LIST_HEAD(&root->node);
root->device = device; root->device = device;
root->segment = segment & 0xFFFF;
root->bus_nr = bus & 0xFF;
strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
device->driver_data = root; device->driver_data = root;
device->ops.bind = acpi_pci_bind;
/* /*
* All supported architectures that use ACPI have support for * All supported architectures that use ACPI have support for
* PCI domains, so we indicate this in _OSC support capabilities. * PCI domains, so we indicate this in _OSC support capabilities.
...@@ -395,79 +514,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) ...@@ -395,79 +514,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
acpi_pci_osc_support(root, flags); acpi_pci_osc_support(root, flags);
/*
* Segment
* -------
* Obtained via _SEG, if exists, otherwise assumed to be zero (0).
*/
status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
&value);
switch (status) {
case AE_OK:
root->id.segment = (u16) value;
break;
case AE_NOT_FOUND:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Assuming segment 0 (no _SEG)\n"));
root->id.segment = 0;
break;
default:
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SEG"));
result = -ENODEV;
goto end;
}
/*
* Bus
* ---
* Obtained via _BBN, if exists, otherwise assumed to be zero (0).
*/
status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL,
&value);
switch (status) {
case AE_OK:
root->id.bus = (u16) value;
break;
case AE_NOT_FOUND:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Assuming bus 0 (no _BBN)\n"));
root->id.bus = 0;
break;
default:
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BBN"));
result = -ENODEV;
goto end;
}
/* Some systems have wrong _BBN */
list_for_each_entry(tmp, &acpi_pci_roots, node) {
if ((tmp->id.segment == root->id.segment)
&& (tmp->id.bus == root->id.bus)) {
int bus = 0;
acpi_status status;
printk(KERN_ERR PREFIX
"Wrong _BBN value, reboot"
" and use option 'pci=noacpi'\n");
status = try_get_root_bridge_busnr(device->handle, &bus);
if (ACPI_FAILURE(status))
break;
if (bus != root->id.bus) {
printk(KERN_INFO PREFIX
"PCI _CRS %d overrides _BBN 0\n", bus);
root->id.bus = bus;
}
break;
}
}
/*
* Device & Function
* -----------------
* Obtained from _ADR (which has already been evaluated for us).
*/
root->id.device = device->pnp.bus_address >> 16;
root->id.function = device->pnp.bus_address & 0xFFFF;
/* /*
* TBD: Need PCI interface for enumeration/configuration of roots. * TBD: Need PCI interface for enumeration/configuration of roots.
*/ */
...@@ -477,7 +523,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) ...@@ -477,7 +523,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n", printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n",
acpi_device_name(device), acpi_device_bid(device), acpi_device_name(device), acpi_device_bid(device),
root->id.segment, root->id.bus); root->segment, root->bus_nr);
/* /*
* Scan the Root Bridge * Scan the Root Bridge
...@@ -486,11 +532,11 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) ...@@ -486,11 +532,11 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
* PCI namespace does not get created until this call is made (and * PCI namespace does not get created until this call is made (and
* thus the root bridge's pci_dev does not exist). * thus the root bridge's pci_dev does not exist).
*/ */
root->bus = pci_acpi_scan_root(device, root->id.segment, root->id.bus); root->bus = pci_acpi_scan_root(device, segment, bus);
if (!root->bus) { if (!root->bus) {
printk(KERN_ERR PREFIX printk(KERN_ERR PREFIX
"Bus %04x:%02x not present in PCI namespace\n", "Bus %04x:%02x not present in PCI namespace\n",
root->id.segment, root->id.bus); root->segment, root->bus_nr);
result = -ENODEV; result = -ENODEV;
goto end; goto end;
} }
...@@ -500,7 +546,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) ...@@ -500,7 +546,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
* ----------------------- * -----------------------
* Thus binding the ACPI and PCI devices. * Thus binding the ACPI and PCI devices.
*/ */
result = acpi_pci_bind_root(device, &root->id, root->bus); result = acpi_pci_bind_root(device);
if (result) if (result)
goto end; goto end;
...@@ -511,8 +557,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) ...@@ -511,8 +557,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
*/ */
status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
result = acpi_pci_irq_add_prt(device->handle, root->id.segment, result = acpi_pci_irq_add_prt(device->handle, root->bus);
root->id.bus);
/* /*
* Scan and bind all _ADR-Based Devices * Scan and bind all _ADR-Based Devices
...@@ -531,42 +576,28 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) ...@@ -531,42 +576,28 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
if (flags != base_flags) if (flags != base_flags)
acpi_pci_osc_support(root, flags); acpi_pci_osc_support(root, flags);
end: return 0;
if (result) {
if (!list_empty(&root->node))
list_del(&root->node);
kfree(root);
}
end:
if (!list_empty(&root->node))
list_del(&root->node);
kfree(root);
return result; return result;
} }
static int acpi_pci_root_start(struct acpi_device *device) static int acpi_pci_root_start(struct acpi_device *device)
{ {
struct acpi_pci_root *root; struct acpi_pci_root *root = acpi_driver_data(device);
pci_bus_add_devices(root->bus);
list_for_each_entry(root, &acpi_pci_roots, node) { return 0;
if (root->device == device) {
pci_bus_add_devices(root->bus);
return 0;
}
}
return -ENODEV;
} }
static int acpi_pci_root_remove(struct acpi_device *device, int type) static int acpi_pci_root_remove(struct acpi_device *device, int type)
{ {
struct acpi_pci_root *root = NULL; struct acpi_pci_root *root = acpi_driver_data(device);
if (!device || !acpi_driver_data(device))
return -EINVAL;
root = acpi_driver_data(device);
kfree(root); kfree(root);
return 0; return 0;
} }
......
...@@ -194,7 +194,7 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) ...@@ -194,7 +194,7 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
{ {
int result = 0, state; int result = 0;
int found = 0; int found = 0;
acpi_status status = AE_OK; acpi_status status = AE_OK;
struct acpi_power_resource *resource = NULL; struct acpi_power_resource *resource = NULL;
...@@ -236,18 +236,6 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) ...@@ -236,18 +236,6 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; return -ENODEV;
if (!acpi_power_nocheck) {
/*
* If acpi_power_nocheck is set, it is unnecessary to check
* the power state after power transition.
*/
result = acpi_power_get_state(resource->device->handle,
&state);
if (result)
return result;
if (state != ACPI_POWER_RESOURCE_STATE_ON)
return -ENOEXEC;
}
/* Update the power resource's _device_ power state */ /* Update the power resource's _device_ power state */
resource->device->power.state = ACPI_STATE_D0; resource->device->power.state = ACPI_STATE_D0;
...@@ -258,7 +246,7 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) ...@@ -258,7 +246,7 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
{ {
int result = 0, state; int result = 0;
acpi_status status = AE_OK; acpi_status status = AE_OK;
struct acpi_power_resource *resource = NULL; struct acpi_power_resource *resource = NULL;
struct list_head *node, *next; struct list_head *node, *next;
...@@ -293,18 +281,6 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) ...@@ -293,18 +281,6 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; return -ENODEV;
if (!acpi_power_nocheck) {
/*
* If acpi_power_nocheck is set, it is unnecessary to check
* the power state after power transition.
*/
result = acpi_power_get_state(handle, &state);
if (result)
return result;
if (state != ACPI_POWER_RESOURCE_STATE_OFF)
return -ENOEXEC;
}
/* Update the power resource's _device_ power state */ /* Update the power resource's _device_ power state */
resource->device->power.state = ACPI_STATE_D3; resource->device->power.state = ACPI_STATE_D3;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment