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
to assume that this machine's pmtimer latches its value
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
Format: { level | edge | high | low }
......
......@@ -920,7 +920,7 @@ The available commands are:
echo '<LED number> off' >/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
mapping:
......@@ -932,6 +932,11 @@ mapping:
5 - UltraBase battery slot
6 - (unknown)
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.
......@@ -940,10 +945,12 @@ sysfs notes:
The ThinkPad LED sysfs interface is described in detail by the LED class
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::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
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
"timer" trigger, and leave the delay_on and delay_off parameters set to
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
----------------------------------
......@@ -1156,17 +1169,19 @@ may not be distinct. Later Lenovo models that implement the ACPI
display backlight brightness control methods have 16 levels, ranging
from 0 to 15.
There are two interfaces to the firmware for direct brightness control,
EC and UCMS (or CMOS). To select which one should be used, use the
brightness_mode module parameter: brightness_mode=1 selects EC mode,
brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC
mode with NVRAM backing (so that brightness changes are remembered
across shutdown/reboot).
For IBM ThinkPads, there are two interfaces to the firmware for direct
brightness control, EC and UCMS (or CMOS). To select which one should be
used, use the brightness_mode module parameter: brightness_mode=1 selects
EC mode, brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC
mode with NVRAM backing (so that brightness changes are remembered across
shutdown/reboot).
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
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
standard ACPI interface, it is best to use it instead of this direct
ThinkPad-specific interface. The driver will disable its native
......@@ -1254,7 +1269,7 @@ Fan control and monitoring: fan speed, fan enable/disable
procfs: /proc/acpi/ibm/fan
sysfs device attributes: (hwmon "thinkpad") fan1_input, pwm1,
pwm1_enable
pwm1_enable, fan2_input
sysfs hwmon driver attributes: fan_watchdog
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
to work on later R, T, X and Z series ThinkPads but may show a bogus
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:
Most ThinkPad fans work in "levels" at the firmware interface. Level 0
......@@ -1397,6 +1415,11 @@ hwmon device attribute fan1_input:
which can take up to two minutes. May return rubbish on older
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:
Fan safety watchdog timer interval, in seconds. Minimum is
1 second, maximum is 120 seconds. 0 disables the watchdog.
......@@ -1555,3 +1578,7 @@ Sysfs interface changelog:
0x020300: hotkey enable/disable support removed, attributes
hotkey_bios_enabled and hotkey_enable deprecated and
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
S: Maintained
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
P: Carlos Corbacho
M: carlos@strangeworlds.co.uk
......@@ -913,8 +920,7 @@ M: corentincj@iksaif.net
P: Karol Kozimor
M: sziwan@users.sourceforge.net
L: acpi4asus-user@lists.sourceforge.net
W: http://sourceforge.net/projects/acpi4asus
W: http://xf.iksaif.net/acpi4asus
W: http://acpi4asus.sf.net
S: Maintained
F: arch/x86/kernel/acpi/boot.c
F: drivers/platform/x86/asus_acpi.c
......@@ -930,8 +936,7 @@ ASUS LAPTOP EXTRAS DRIVER
P: Corentin Chary
M: corentincj@iksaif.net
L: acpi4asus-user@lists.sourceforge.net
W: http://sourceforge.net/projects/acpi4asus
W: http://xf.iksaif.net/acpi4asus
W: http://acpi4asus.sf.net
S: Maintained
F: drivers/platform/x86/asus-laptop.c
......@@ -2110,7 +2115,7 @@ EEEPC LAPTOP EXTRAS DRIVER
P: Corentin Chary
M: corentincj@iksaif.net
L: acpi4asus-user@lists.sourceforge.net
W: http://sourceforge.net/projects/acpi4asus
W: http://acpi4asus.sf.net
S: Maintained
F: drivers/platform/x86/eeepc-laptop.c
......
......@@ -71,3 +71,15 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr)
}
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)
#else /* !CONFIG_ACPI */
#define acpi_disabled 1
#define acpi_lapic 0
#define acpi_ioapic 0
static inline void acpi_noirq_set(void) { }
......
......@@ -121,6 +121,9 @@ extern int __init pcibios_init(void);
extern int __init pci_mmcfg_arch_init(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
* on their northbrige except through the * %eax register. As such, you MUST
......
......@@ -44,11 +44,7 @@
static int __initdata acpi_force = 0;
u32 acpi_rsdt_forced;
#ifdef CONFIG_ACPI
int acpi_disabled = 0;
#else
int acpi_disabled = 1;
#endif
int acpi_disabled;
EXPORT_SYMBOL(acpi_disabled);
#ifdef CONFIG_X86_64
......@@ -122,72 +118,6 @@ void __init __acpi_unmap_table(char *map, unsigned long 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
static int __init acpi_parse_madt(struct acpi_table_header *table)
{
......@@ -1517,14 +1447,6 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = {
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,
.ident = "ASUS P2B-DS",
......
......@@ -34,12 +34,22 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
flags->bm_check = 1;
else if (c->x86_vendor == X86_VENDOR_INTEL) {
/*
* Today all CPUs that support C3 share cache.
* TBD: This needs to look at cache shared map, once
* multi-core detection patch makes to the base.
* Today all MP CPUs that support C3 share cache.
* And caches should not be flushed by software while
* entering C3 type state.
*/
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);
......
......@@ -72,6 +72,7 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c)
return;
}
/* Initialize _PDC data based on the CPU vendor */
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);
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)
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)
{
/* MMCONFIG disabled */
......@@ -543,7 +606,7 @@ static void __init __pci_mmcfg_init(int early)
}
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);
......
......@@ -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_remove(struct acpi_device *device, int type);
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[] = {
{"ACPI0003", 0},
......@@ -72,10 +73,12 @@ static struct acpi_driver acpi_ac_driver = {
.name = "ac",
.class = ACPI_AC_CLASS,
.ids = ac_device_ids,
.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
.ops = {
.add = acpi_ac_add,
.remove = acpi_ac_remove,
.resume = acpi_ac_resume,
.notify = acpi_ac_notify,
},
};
......@@ -220,16 +223,14 @@ static int acpi_ac_remove_fs(struct acpi_device *device)
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_device *device = NULL;
struct acpi_ac *ac = acpi_driver_data(device);
if (!ac)
return;
device = ac->device;
switch (event) {
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
......@@ -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)
{
int result = 0;
acpi_status status = AE_OK;
struct acpi_ac *ac = NULL;
......@@ -286,13 +286,6 @@ static int acpi_ac_add(struct acpi_device *device)
ac->charger.get_property = get_ac_property;
power_supply_register(&ac->device->dev, &ac->charger);
#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",
acpi_device_name(device), acpi_device_bid(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)
{
acpi_status status = AE_OK;
struct acpi_ac *ac = NULL;
......@@ -337,8 +329,6 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
ac = acpi_driver_data(device);
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY, acpi_ac_notify);
#ifdef CONFIG_ACPI_SYSFS_POWER
if (ac->charger.dev)
power_supply_unregister(&ac->charger);
......
......@@ -796,13 +796,12 @@ static void acpi_battery_remove_fs(struct acpi_device *device)
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_device *device;
struct acpi_battery *battery = acpi_driver_data(device);
if (!battery)
return;
device = battery->device;
acpi_battery_update(battery);
acpi_bus_generate_proc_event(device, event,
acpi_battery_present(battery));
......@@ -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)
{
int result = 0;
acpi_status status = 0;
struct acpi_battery *battery = NULL;
if (!device)
return -EINVAL;
......@@ -834,22 +832,12 @@ static int acpi_battery_add(struct acpi_device *device)
acpi_battery_update(battery);
#ifdef CONFIG_ACPI_PROCFS_POWER
result = acpi_battery_add_fs(device);
if (result)
goto end;
#endif
status = acpi_install_notify_handler(device->handle,
ACPI_ALL_NOTIFY,
acpi_battery_notify, battery);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler"));
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) {
if (!result) {
printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
device->status.battery_present ? "present" : "absent");
} else {
#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_battery_remove_fs(device);
#endif
......@@ -860,15 +848,11 @@ static int acpi_battery_add(struct acpi_device *device)
static int acpi_battery_remove(struct acpi_device *device, int type)
{
acpi_status status = 0;
struct acpi_battery *battery = NULL;
if (!device || !acpi_driver_data(device))
return -EINVAL;
battery = acpi_driver_data(device);
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY,
acpi_battery_notify);
#ifdef CONFIG_ACPI_PROCFS_POWER
acpi_battery_remove_fs(device);
#endif
......@@ -896,10 +880,12 @@ static struct acpi_driver acpi_battery_driver = {
.name = "battery",
.class = ACPI_BATTERY_CLASS,
.ids = battery_device_ids,
.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
.ops = {
.add = acpi_battery_add,
.resume = acpi_battery_resume,
.remove = acpi_battery_remove,
.notify = acpi_battery_notify,
},
};
......
......@@ -192,6 +192,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
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.
......
......@@ -450,18 +450,16 @@ int acpi_bus_receive_event(struct acpi_bus_event *event)
Notification Handling
-------------------------------------------------------------------------- */
static int
acpi_bus_check_device(struct acpi_device *device, int *status_changed)
static void acpi_bus_check_device(acpi_handle handle)
{
acpi_status status = 0;
struct acpi_device *device;
acpi_status status;
struct acpi_device_status old_status;
if (acpi_bus_get_device(handle, &device))
return;
if (!device)
return -EINVAL;
if (status_changed)
*status_changed = 0;
return;
old_status = device->status;
......@@ -471,22 +469,15 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed)
*/
if (device->parent && !device->parent->status.present) {
device->status = device->parent->status;
if (STRUCT_TO_INT(old_status) != STRUCT_TO_INT(device->status)) {
if (status_changed)
*status_changed = 1;
}
return 0;
return;
}
status = acpi_bus_get_status(device);
if (ACPI_FAILURE(status))
return -ENODEV;
return;
if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
return 0;
if (status_changed)
*status_changed = 1;
return;
/*
* Device Insertion/Removal
......@@ -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"));
/* 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? */
result = acpi_bus_check_device(device, &status_changed);
if (result)
return result;
if (!status_changed)
return 0;
acpi_bus_check_device(handle);
/*
* TBD: Enumerate child devices within this device's scope and
* run acpi_bus_check_device()'s on them.
*/
return 0;
}
static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
......@@ -547,22 +522,19 @@ EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
*/
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
{
int result = 0;
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,
type, (void *)handle);
if (acpi_bus_get_device(handle, &device))
return;
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received BUS CHECK notification for device [%s]\n",
device->pnp.bus_id));
result = acpi_bus_check_scope(device);
acpi_bus_check_scope(handle);
/*
* TBD: We'll need to outsource certain events to non-ACPI
* drivers via the device manager (device.c).
......@@ -570,10 +542,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
break;
case ACPI_NOTIFY_DEVICE_CHECK:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received DEVICE CHECK notification for device [%s]\n",
device->pnp.bus_id));
result = acpi_bus_check_device(device, NULL);
acpi_bus_check_device(handle);
/*
* TBD: We'll need to outsource certain events to non-ACPI
* drivers via the device manager (device.c).
......@@ -581,44 +550,26 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
break;
case ACPI_NOTIFY_DEVICE_WAKE:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received DEVICE WAKE notification for device [%s]\n",
device->pnp.bus_id));
/* TBD */
break;
case ACPI_NOTIFY_EJECT_REQUEST:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received EJECT REQUEST notification for device [%s]\n",
device->pnp.bus_id));
/* TBD */
break;
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? */
break;
case ACPI_NOTIFY_FREQUENCY_MISMATCH:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received FREQUENCY MISMATCH notification for device [%s]\n",
device->pnp.bus_id));
/* TBD */
break;
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 */
break;
case ACPI_NOTIFY_POWER_FAULT:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Received POWER FAULT notification for device [%s]\n",
device->pnp.bus_id));
/* TBD */
break;
......@@ -629,7 +580,13 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
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)
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)
{
struct acpi_device *acpi_dev;
......
......@@ -79,6 +79,7 @@ static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq;
static struct workqueue_struct *kacpi_notify_wq;
static struct workqueue_struct *kacpi_hotplug_wq;
struct acpi_res_list {
resource_size_t start;
......@@ -192,8 +193,10 @@ acpi_status acpi_os_initialize1(void)
{
kacpid_wq = create_singlethread_workqueue("kacpid");
kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
kacpi_hotplug_wq = create_singlethread_workqueue("kacpi_hotplug");
BUG_ON(!kacpid_wq);
BUG_ON(!kacpi_notify_wq);
BUG_ON(!kacpi_hotplug_wq);
return AE_OK;
}
......@@ -206,6 +209,7 @@ acpi_status acpi_os_terminate(void)
destroy_workqueue(kacpid_wq);
destroy_workqueue(kacpi_notify_wq);
destroy_workqueue(kacpi_hotplug_wq);
return AE_OK;
}
......@@ -716,6 +720,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
acpi_status status = AE_OK;
struct acpi_os_dpc *dpc;
struct workqueue_struct *queue;
work_func_t func;
int ret;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Scheduling function [%p(%p)] for deferred execution.\n",
......@@ -740,15 +745,17 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
dpc->function = function;
dpc->context = context;
if (!hp) {
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
queue = (type == OSL_NOTIFY_HANDLER) ?
kacpi_notify_wq : kacpid_wq;
ret = queue_work(queue, &dpc->work);
} else {
INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred);
ret = schedule_work(&dpc->work);
}
/*
* We can't run hotplug code in keventd_wq/kacpid_wq/kacpid_notify_wq
* because the hotplug code may call driver .remove() functions,
* which invoke flush_scheduled_work/acpi_os_wait_events_complete
* to flush these workqueues.
*/
queue = hp ? kacpi_hotplug_wq :
(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) {
printk(KERN_ERR PREFIX
......
......@@ -24,12 +24,7 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/pci.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
......@@ -38,310 +33,76 @@
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_bind");
struct acpi_pci_data {
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)
static int acpi_pci_unbind(struct acpi_device *device)
{
int result = 0;
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;
}
struct pci_dev *dev;
*id = data->id;
dev = acpi_get_pci_dev(device->handle);
if (!dev || !dev->subordinate)
goto out;
/*
id->segment = data->id.segment;
id->bus = data->id.bus;
id->device = data->id.device;
id->function = data->id.function;
*/
acpi_pci_irq_del_prt(dev->subordinate);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device %s has PCI address %04x:%02x:%02x.%d\n",
acpi_device_bid(device), id->segment, id->bus,
id->device, id->function));
device->ops.bind = NULL;
device->ops.unbind = NULL;
return AE_OK;
out:
pci_dev_put(dev);
return 0;
}
EXPORT_SYMBOL(acpi_get_pci_id);
int acpi_pci_bind(struct acpi_device *device)
static int acpi_pci_bind(struct acpi_device *device)
{
int result = 0;
acpi_status status;
struct acpi_pci_data *data;
struct acpi_pci_data *pdata;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_handle handle;
struct pci_bus *bus;
struct pci_dev *dev;
if (!device || !device->parent)
return -EINVAL;
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;
}
dev = acpi_get_pci_dev(device->handle);
if (!dev)
return 0;
/*
* PCI Bridge?
* -----------
* If so, set the 'bus' field and install the 'bind' function to
* facilitate callbacks for all of its children.
* Install the 'bind' function to facilitate callbacks for
* children of the P2P bridge.
*/
if (data->dev->subordinate) {
if (dev->subordinate) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device %04x:%02x:%02x.%d is a PCI bridge\n",
data->id.segment, data->id.bus,
data->id.device, data->id.function));
data->bus = data->dev->subordinate;
pci_domain_nr(dev->bus), dev->bus->number,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)));
device->ops.bind = acpi_pci_bind;
device->ops.unbind = acpi_pci_unbind;
}
/*
* Attach ACPI-PCI Context
* -----------------------
* Thus binding the ACPI and PCI devices.
*/
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.
* Evaluate and parse _PRT, if exists. This code allows 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?
*/
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))
return -ENODEV;
goto out;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n",
(char *) buffer.pointer));
kfree(buffer.pointer);
if (dev->subordinate)
bus = dev->subordinate;
else
bus = dev->bus;
status =
acpi_get_data(device->handle, acpi_pci_data_handler,
(void **)&data);
if (ACPI_FAILURE(status)) {
result = -ENODEV;
goto end;
}
acpi_pci_irq_add_prt(device->handle, bus);
status = acpi_detach_data(device->handle, acpi_pci_data_handler);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"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;
out:
pci_dev_put(dev);
return 0;
}
int
acpi_pci_bind_root(struct acpi_device *device,
struct acpi_pci_id *id, struct pci_bus *bus)
int acpi_pci_bind_root(struct acpi_device *device)
{
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.unbind = acpi_pci_unbind;
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 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;
return 0;
}
......@@ -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_prt_entry *entry;
......@@ -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
* it here.
*/
entry->id.segment = segment;
entry->id.bus = bus;
entry->id.segment = pci_domain_nr(bus);
entry->id.bus = bus->number;
entry->id.device = (prt->address >> 16) & 0xFFFF;
entry->pin = prt->pin + 1;
......@@ -242,7 +242,7 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus,
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;
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)
entry = buffer.pointer;
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 *)
((unsigned long)entry + entry->length);
}
......@@ -280,16 +280,17 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
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;
printk(KERN_DEBUG
"ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n",
segment, bus);
pci_domain_nr(bus), bus->number);
spin_lock(&acpi_prt_lock);
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);
kfree(entry);
}
......
......@@ -63,9 +63,10 @@ static struct acpi_driver acpi_pci_root_driver = {
struct acpi_pci_root {
struct list_head node;
struct acpi_device * device;
struct acpi_pci_id id;
struct acpi_device *device;
struct pci_bus *bus;
u16 segment;
u8 bus_nr;
u32 osc_support_set; /* _OSC state of support bits */
u32 osc_control_set; /* _OSC state of control bits */
......@@ -82,7 +83,7 @@ static DEFINE_MUTEX(osc_lock);
int acpi_pci_register_driver(struct acpi_pci_driver *driver)
{
int n = 0;
struct list_head *entry;
struct acpi_pci_root *root;
struct acpi_pci_driver **pptr = &sub_driver;
while (*pptr)
......@@ -92,9 +93,7 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver)
if (!driver->add)
return 0;
list_for_each(entry, &acpi_pci_roots) {
struct acpi_pci_root *root;
root = list_entry(entry, struct acpi_pci_root, node);
list_for_each_entry(root, &acpi_pci_roots, node) {
driver->add(root->device->handle);
n++;
}
......@@ -106,7 +105,7 @@ EXPORT_SYMBOL(acpi_pci_register_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;
while (*pptr) {
......@@ -120,28 +119,48 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
if (!driver->remove)
return;
list_for_each(entry, &acpi_pci_roots) {
struct acpi_pci_root *root;
root = list_entry(entry, struct acpi_pci_root, node);
list_for_each_entry(root, &acpi_pci_roots, node)
driver->remove(root->device->handle);
}
}
EXPORT_SYMBOL(acpi_pci_unregister_driver);
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) {
if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus))
return tmp->device->handle;
}
list_for_each_entry(root, &acpi_pci_roots, node)
if ((root->segment == (u16) seg) && (root->bus_nr == (u16) bus))
return root->device->handle;
return NULL;
}
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
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;
}
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;
int busnum;
*busnum = -1;
busnum = -1;
status =
acpi_walk_resources(handle, METHOD_NAME__CRS,
get_root_bridge_busnr_callback, busnum);
get_root_bridge_busnr_callback, &busnum);
if (ACPI_FAILURE(status))
return status;
/* Check if we really get a bus number from _CRS */
if (*busnum == -1)
if (busnum == -1)
return AE_ERROR;
*bus = busnum;
return AE_OK;
}
......@@ -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)
{
struct acpi_pci_root *root;
list_for_each_entry(root, &acpi_pci_roots, node) {
if (root->device->handle == handle)
return root;
......@@ -305,6 +328,87 @@ static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
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
* @handle: acpi_handle for the target ACPI object
......@@ -363,31 +467,46 @@ EXPORT_SYMBOL(acpi_pci_osc_control_set);
static int __devinit acpi_pci_root_add(struct acpi_device *device)
{
int result = 0;
struct acpi_pci_root *root = NULL;
struct acpi_pci_root *tmp;
acpi_status status = AE_OK;
unsigned long long value = 0;
acpi_handle handle = NULL;
unsigned long long segment, bus;
acpi_status status;
int result;
struct acpi_pci_root *root;
acpi_handle handle;
struct acpi_device *child;
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)
return -EINVAL;
/* Check _CRS first, then _BBN. If no _BBN, default to zero. */
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);
if (!root)
return -ENOMEM;
INIT_LIST_HEAD(&root->node);
INIT_LIST_HEAD(&root->node);
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_class(device), ACPI_PCI_ROOT_CLASS);
device->driver_data = root;
device->ops.bind = acpi_pci_bind;
/*
* All supported architectures that use ACPI have support for
* 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)
flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
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.
*/
......@@ -477,7 +523,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n",
acpi_device_name(device), acpi_device_bid(device),
root->id.segment, root->id.bus);
root->segment, root->bus_nr);
/*
* Scan the Root Bridge
......@@ -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
* 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) {
printk(KERN_ERR PREFIX
"Bus %04x:%02x not present in PCI namespace\n",
root->id.segment, root->id.bus);
root->segment, root->bus_nr);
result = -ENODEV;
goto end;
}
......@@ -500,7 +546,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
* -----------------------
* 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)
goto end;
......@@ -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);
if (ACPI_SUCCESS(status))
result = acpi_pci_irq_add_prt(device->handle, root->id.segment,
root->id.bus);
result = acpi_pci_irq_add_prt(device->handle, root->bus);
/*
* Scan and bind all _ADR-Based Devices
......@@ -531,42 +576,28 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
if (flags != base_flags)
acpi_pci_osc_support(root, flags);
end:
if (result) {
if (!list_empty(&root->node))
list_del(&root->node);
kfree(root);
}
return 0;
end:
if (!list_empty(&root->node))
list_del(&root->node);
kfree(root);
return result;
}
static int acpi_pci_root_start(struct acpi_device *device)
{
struct acpi_pci_root *root;
struct acpi_pci_root *root = acpi_driver_data(device);
list_for_each_entry(root, &acpi_pci_roots, node) {
if (root->device == device) {
pci_bus_add_devices(root->bus);
return 0;
}
}
return -ENODEV;
pci_bus_add_devices(root->bus);
return 0;
}
static int acpi_pci_root_remove(struct acpi_device *device, int type)
{
struct acpi_pci_root *root = NULL;
if (!device || !acpi_driver_data(device))
return -EINVAL;
root = acpi_driver_data(device);
struct acpi_pci_root *root = acpi_driver_data(device);
kfree(root);
return 0;
}
......
......@@ -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)
{
int result = 0, state;
int result = 0;
int found = 0;
acpi_status status = AE_OK;
struct acpi_power_resource *resource = NULL;
......@@ -236,18 +236,6 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
if (ACPI_FAILURE(status))
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 */
resource->device->power.state = ACPI_STATE_D0;
......@@ -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)
{
int result = 0, state;
int result = 0;
acpi_status status = AE_OK;
struct acpi_power_resource *resource = NULL;
struct list_head *node, *next;
......@@ -293,18 +281,6 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
if (ACPI_FAILURE(status))
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 */
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