mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 20:54:03 +02:00
Merge branches 'acpi-processor', 'acpi-ec', 'acpi-fan' and 'acpi-battery'
Merge updates of the ACPI processor, EC, fan, and battery drivers for
7.3-rc1:
- Unregister the cpufreq notifier on init failure in the ACPI processor
driver (Can Peng)
- Validate MADT IOAPIC entry bounds during IOAPIC hotplug lookup in the
ACPI processor driver (Pengpeng Hou)
- Avoid _REG disconnect on probe deferrals related to GPIO IRQ in the
ACPI EC driver (Zhu Ling)
- Use a correct function parameter name in kernel-doc in the ACPI fan
driver (Randy Dunlap)
- Update ACPI fan IDs to follow modern style and clean up header file
inclusions in the ACPI fan driver (Andy Shevchenko)
- Use devm_acpi_install_notify_handler() to replace a custom open-coded
devres-based management of an ACPI notify handler in the ACPI fan
driver (Rafael Wysocki)
- Adjust charging status validation check in the ACPI battery driver to
avoid incorrect status reporting (Rafael Wysocki)
- Merge consecutive battery notifications in the ACPI battery driver to
reduce the pressure on STA, _BST and _BIX/_BIF ACPI control methods
and make that driver use kstrtoul() instead of sscanf("%lu\n") (Rong
Zhang)
- Sanitise model_number in the ACPI battery driver by dropping
unprintable characters (Kate Hsuan)
* acpi-processor:
ACPI: processor: Unregister cpufreq notifier on init failure
ACPI: processor: validate MADT IOAPIC entry bounds
* acpi-ec:
ACPI: EC: Avoid _REG disconnect on GPIO IRQ defer
* acpi-fan:
ACPI: fan: Use correct function parameter name in kernel-doc
ACPI: fan: Update ACPI fan IDs to follow modern style
ACPI: fan: Don't use "proxy" headers
ACPI: fan: Use devm_acpi_install_notify_handler()
* acpi-battery:
ACPI: battery: Adjust charging status validation check
ACPI: battery: Use kstrtoul() over sscanf("%lu\n")
ACPI: battery: Merge consecutive battery notifications
ACPI: battery: Sanitise model_number by dropping unprintable characters
This commit is contained in:
commit
dc42307fae
|
|
@ -10,10 +10,12 @@
|
|||
|
||||
#define pr_fmt(fmt) "ACPI: battery: " fmt
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
|
|
@ -21,6 +23,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
|
|
@ -43,6 +46,9 @@
|
|||
|
||||
#define MAX_STRING_LENGTH 64
|
||||
|
||||
#define MAX_QUEUED_EVENTS 16
|
||||
#define NOTIF_MERGING_MS 10
|
||||
|
||||
MODULE_AUTHOR("Paul Diefenbaugh");
|
||||
MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
|
||||
MODULE_DESCRIPTION("ACPI Battery Driver");
|
||||
|
|
@ -95,6 +101,8 @@ struct acpi_battery {
|
|||
struct power_supply_desc bat_desc;
|
||||
struct acpi_device *device;
|
||||
struct device *phys_dev;
|
||||
struct kfifo acpi_notif_fifo;
|
||||
struct delayed_work acpi_notif_dwork;
|
||||
struct notifier_block pm_nb;
|
||||
struct list_head list;
|
||||
unsigned long update_time;
|
||||
|
|
@ -150,27 +158,28 @@ static int acpi_battery_technology(struct acpi_battery *battery)
|
|||
|
||||
static int acpi_battery_get_state(struct acpi_battery *battery);
|
||||
|
||||
static bool acpi_battery_is_full(struct acpi_battery *battery)
|
||||
{
|
||||
/* battery not reporting charge */
|
||||
if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
|
||||
battery->capacity_now == 0)
|
||||
return false;
|
||||
|
||||
/* good batteries update full_charge as the batteries degrade */
|
||||
if (battery->full_charge_capacity == battery->capacity_now)
|
||||
return true;
|
||||
|
||||
/* fallback to using design values for broken batteries */
|
||||
return battery->design_capacity <= battery->capacity_now;
|
||||
}
|
||||
|
||||
static int acpi_battery_is_charged(struct acpi_battery *battery)
|
||||
{
|
||||
/* charging, discharging, critical low or charge limited */
|
||||
if (battery->state != 0)
|
||||
return 0;
|
||||
|
||||
/* battery not reporting charge */
|
||||
if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
|
||||
battery->capacity_now == 0)
|
||||
return 0;
|
||||
|
||||
/* good batteries update full_charge as the batteries degrade */
|
||||
if (battery->full_charge_capacity == battery->capacity_now)
|
||||
return 1;
|
||||
|
||||
/* fallback to using design values for broken batteries */
|
||||
if (battery->design_capacity <= battery->capacity_now)
|
||||
return 1;
|
||||
|
||||
/* we don't do any sort of metric based on percentages */
|
||||
return 0;
|
||||
return acpi_battery_is_full(battery);
|
||||
}
|
||||
|
||||
static bool acpi_battery_is_degraded(struct acpi_battery *battery)
|
||||
|
|
@ -211,13 +220,14 @@ static int acpi_battery_get_property(struct power_supply *psy,
|
|||
if (battery->state & ACPI_BATTERY_STATE_DISCHARGING)
|
||||
val->intval = acpi_battery_handle_discharging(battery);
|
||||
else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
|
||||
/* Validate the status by checking the current. */
|
||||
if (battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN &&
|
||||
battery->rate_now == 0) {
|
||||
/* On charge but no current (0W/0mA). */
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
} else {
|
||||
/* Check the rate and capacity to validate the status. */
|
||||
if (!acpi_battery_is_full(battery) ||
|
||||
(battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN &&
|
||||
battery->rate_now > 0)) {
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
} else {
|
||||
/* Full and zero rate. */
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
}
|
||||
else if (battery->state & ACPI_BATTERY_STATE_CHARGE_LIMITING)
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
|
|
@ -483,6 +493,15 @@ static int acpi_battery_get_status(struct acpi_battery *battery)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void acpi_battery_clean_unprintable_chars(char *str, size_t length)
|
||||
{
|
||||
for (unsigned int i = 0; i < length; i++) {
|
||||
if (!isascii(str[i]) || !isprint(str[i])) {
|
||||
str[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int extract_battery_info(const int use_bix,
|
||||
struct acpi_battery *battery,
|
||||
|
|
@ -524,6 +543,10 @@ static int extract_battery_info(const int use_bix,
|
|||
battery->capacity_now > battery->full_charge_capacity)
|
||||
battery->capacity_now = battery->full_charge_capacity;
|
||||
|
||||
if (!result)
|
||||
acpi_battery_clean_unprintable_chars(battery->model_number,
|
||||
ARRAY_SIZE(battery->model_number));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -668,9 +691,13 @@ static ssize_t acpi_battery_alarm_store(struct device *dev,
|
|||
{
|
||||
unsigned long x;
|
||||
struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
|
||||
int err;
|
||||
|
||||
if (sscanf(buf, "%lu\n", &x) == 1)
|
||||
battery->alarm = x/1000;
|
||||
err = kstrtoul(buf, 10, &x);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
battery->alarm = x / 1000;
|
||||
if (acpi_battery_present(battery))
|
||||
acpi_battery_set_alarm(battery);
|
||||
return count;
|
||||
|
|
@ -1059,14 +1086,24 @@ static void acpi_battery_refresh(struct acpi_battery *battery)
|
|||
}
|
||||
|
||||
/* Driver Interface */
|
||||
static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
|
||||
static void acpi_battery_notification_worker(struct work_struct *work)
|
||||
{
|
||||
struct acpi_battery *battery = data;
|
||||
struct acpi_battery *battery = container_of(work, struct acpi_battery,
|
||||
acpi_notif_dwork.work);
|
||||
struct acpi_device *device = battery->device;
|
||||
u32 events[MAX_QUEUED_EVENTS];
|
||||
struct power_supply *old;
|
||||
unsigned int count, i;
|
||||
|
||||
guard(mutex)(&battery->update_lock);
|
||||
|
||||
count = kfifo_out(&battery->acpi_notif_fifo, events, sizeof(events));
|
||||
count /= sizeof(events[0]);
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
pr_debug("merged %u battery notifications within %dms\n", count, NOTIF_MERGING_MS);
|
||||
|
||||
old = battery->bat;
|
||||
/*
|
||||
* On Acer Aspire V5-573G notifications are sometimes triggered too
|
||||
|
|
@ -1076,19 +1113,46 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
|
|||
*/
|
||||
if (battery_notification_delay_ms > 0)
|
||||
msleep(battery_notification_delay_ms);
|
||||
if (event == ACPI_BATTERY_NOTIFY_INFO)
|
||||
acpi_battery_refresh(battery);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (events[i] == ACPI_BATTERY_NOTIFY_INFO) {
|
||||
acpi_battery_refresh(battery);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
acpi_battery_update(battery, false);
|
||||
acpi_bus_generate_netlink_event(ACPI_BATTERY_CLASS,
|
||||
dev_name(&device->dev), event,
|
||||
acpi_battery_present(battery));
|
||||
acpi_notifier_call_chain(ACPI_BATTERY_CLASS, acpi_device_bid(device),
|
||||
event, acpi_battery_present(battery));
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
acpi_bus_generate_netlink_event(ACPI_BATTERY_CLASS,
|
||||
dev_name(&device->dev), events[i],
|
||||
acpi_battery_present(battery));
|
||||
acpi_notifier_call_chain(ACPI_BATTERY_CLASS, acpi_device_bid(device),
|
||||
events[i], acpi_battery_present(battery));
|
||||
}
|
||||
|
||||
/* acpi_battery_update could remove power_supply object */
|
||||
if (old && battery->bat)
|
||||
power_supply_changed(battery->bat);
|
||||
}
|
||||
|
||||
static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct acpi_battery *battery = data;
|
||||
|
||||
guard(mutex)(&battery->update_lock);
|
||||
|
||||
if (kfifo_avail(&battery->acpi_notif_fifo) >= sizeof(event)) {
|
||||
kfifo_in(&battery->acpi_notif_fifo, &event, sizeof(event));
|
||||
schedule_delayed_work(&battery->acpi_notif_dwork,
|
||||
msecs_to_jiffies(NOTIF_MERGING_MS));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pr_err_ratelimited("too many battery notifications within %dms\n", NOTIF_MERGING_MS);
|
||||
}
|
||||
|
||||
static int battery_notify(struct notifier_block *nb,
|
||||
unsigned long mode, void *_unused)
|
||||
{
|
||||
|
|
@ -1231,6 +1295,29 @@ static int devm_acpi_battery_update_retry(struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void acpi_battery_notify_dwork_cleanup(void *data)
|
||||
{
|
||||
struct acpi_battery *battery = data;
|
||||
|
||||
cancel_delayed_work_sync(&battery->acpi_notif_dwork);
|
||||
kfifo_free(&battery->acpi_notif_fifo);
|
||||
}
|
||||
|
||||
static int devm_acpi_battery_init_notify_dwork(struct device *dev,
|
||||
struct acpi_battery *battery)
|
||||
{
|
||||
int ret;
|
||||
|
||||
INIT_DELAYED_WORK(&battery->acpi_notif_dwork, acpi_battery_notification_worker);
|
||||
|
||||
ret = kfifo_alloc(&battery->acpi_notif_fifo,
|
||||
MAX_QUEUED_EVENTS * sizeof(u32), GFP_KERNEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_add_action_or_reset(dev, acpi_battery_notify_dwork_cleanup, battery);
|
||||
}
|
||||
|
||||
static int acpi_battery_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
|
@ -1272,6 +1359,10 @@ static int acpi_battery_probe(struct platform_device *pdev)
|
|||
if (result)
|
||||
return result;
|
||||
|
||||
result = devm_acpi_battery_init_notify_dwork(dev, battery);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = devm_acpi_install_notify_handler(dev, ACPI_ALL_NOTIFY,
|
||||
acpi_battery_notify, battery);
|
||||
if (result)
|
||||
|
|
|
|||
|
|
@ -1510,6 +1510,24 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
|
|||
IRQF_SHARED | IRQF_ONESHOT, "ACPI EC", ec) >= 0;
|
||||
}
|
||||
|
||||
static int ec_prepare_gpio_irq(struct acpi_ec *ec, struct acpi_device *device)
|
||||
{
|
||||
int irq;
|
||||
|
||||
if (!device || ec->gpe >= 0 || ec->irq >= 0)
|
||||
return 0;
|
||||
|
||||
/* ACPI reduced hardware platforms use a GpioInt from _CRS. */
|
||||
irq = acpi_dev_gpio_irq_get(device, 0);
|
||||
if (irq == -EPROBE_DEFER)
|
||||
return irq;
|
||||
|
||||
if (irq >= 0)
|
||||
ec->irq = irq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ec_install_handlers - Install service callbacks and register query methods.
|
||||
* @ec: Target EC.
|
||||
|
|
@ -1524,7 +1542,6 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
|
|||
* Return:
|
||||
* -ENODEV if the address space handler cannot be installed, which means
|
||||
* "unable to handle transactions",
|
||||
* -EPROBE_DEFER if GPIO IRQ acquisition needs to be deferred,
|
||||
* or 0 (success) otherwise.
|
||||
*/
|
||||
static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
|
||||
|
|
@ -1557,19 +1574,6 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
|
|||
if (!device)
|
||||
return 0;
|
||||
|
||||
if (ec->gpe < 0) {
|
||||
/* ACPI reduced hardware platforms use a GpioInt from _CRS. */
|
||||
int irq = acpi_dev_gpio_irq_get(device, 0);
|
||||
/*
|
||||
* Bail out right away for deferred probing or complete the
|
||||
* initialization regardless of any other errors.
|
||||
*/
|
||||
if (irq == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
else if (irq >= 0)
|
||||
ec->irq = irq;
|
||||
}
|
||||
|
||||
if (!test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
|
||||
/* Find and register all query methods */
|
||||
acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
|
||||
|
|
@ -1647,6 +1651,14 @@ static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool ca
|
|||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* GPIO IRQ lookup can defer. Do it before publishing the EC
|
||||
* OpRegion to AML to avoid a spurious _REG(disconnect).
|
||||
*/
|
||||
ret = ec_prepare_gpio_irq(ec, device);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* First EC capable of handling transactions */
|
||||
if (!first_ec)
|
||||
first_ec = ec;
|
||||
|
|
|
|||
|
|
@ -10,20 +10,21 @@
|
|||
#ifndef _ACPI_FAN_H_
|
||||
#define _ACPI_FAN_H_
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define ACPI_FAN_DEVICE_IDS \
|
||||
{"INT3404", }, /* Fan */ \
|
||||
{"INTC1044", }, /* Fan for Tiger Lake generation */ \
|
||||
{"INTC1048", }, /* Fan for Alder Lake generation */ \
|
||||
{"INTC1063", }, /* Fan for Meteor Lake generation */ \
|
||||
{"INTC106A", }, /* Fan for Lunar Lake generation */ \
|
||||
{"INTC10A2", }, /* Fan for Raptor Lake generation */ \
|
||||
{"INTC10D6", }, /* Fan for Panther Lake generation */ \
|
||||
{"INTC10FE", }, /* Fan for Wildcat Lake generation */ \
|
||||
{"INTC10F5", }, /* Fan for Nova Lake generation */ \
|
||||
{"PNP0C0B", } /* Generic ACPI fan */
|
||||
#define ACPI_FAN_DEVICE_IDS \
|
||||
{ .id = "INT3404" }, /* Fan */ \
|
||||
{ .id = "INTC1044" }, /* Fan for Tiger Lake generation */ \
|
||||
{ .id = "INTC1048" }, /* Fan for Alder Lake generation */ \
|
||||
{ .id = "INTC1063" }, /* Fan for Meteor Lake generation */ \
|
||||
{ .id = "INTC106A" }, /* Fan for Lunar Lake generation */ \
|
||||
{ .id = "INTC10A2" }, /* Fan for Raptor Lake generation */ \
|
||||
{ .id = "INTC10D6" }, /* Fan for Panther Lake generation */ \
|
||||
{ .id = "INTC10FE" }, /* Fan for Wildcat Lake generation */ \
|
||||
{ .id = "INTC10F5" }, /* Fan for Nova Lake generation */ \
|
||||
{ .id = "PNP0C0B" } /* Generic ACPI fan */
|
||||
|
||||
#define ACPI_FPS_NAME_LEN 20
|
||||
|
||||
|
|
@ -69,7 +70,7 @@ struct acpi_fan {
|
|||
|
||||
/**
|
||||
* acpi_fan_speed_valid - Check if fan speed value is valid
|
||||
* @speeed: Speed value returned by the ACPI firmware
|
||||
* @speed: Speed value returned by the ACPI firmware
|
||||
*
|
||||
* Check if the fan speed value returned by the ACPI firmware is valid. This function is
|
||||
* necessary as ACPI firmware implementations can return 0xFFFFFFFF to signal that the
|
||||
|
|
|
|||
|
|
@ -489,26 +489,6 @@ static void acpi_fan_notify_handler(acpi_handle handle, u32 event, void *context
|
|||
}
|
||||
}
|
||||
|
||||
static void acpi_fan_notify_remove(void *data)
|
||||
{
|
||||
struct acpi_fan *fan = data;
|
||||
|
||||
acpi_remove_notify_handler(fan->handle, ACPI_DEVICE_NOTIFY, acpi_fan_notify_handler);
|
||||
}
|
||||
|
||||
static int devm_acpi_fan_notify_init(struct device *dev)
|
||||
{
|
||||
struct acpi_fan *fan = dev_get_drvdata(dev);
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_install_notify_handler(fan->handle, ACPI_DEVICE_NOTIFY,
|
||||
acpi_fan_notify_handler, dev);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
return devm_add_action_or_reset(dev, acpi_fan_notify_remove, fan);
|
||||
}
|
||||
|
||||
static int acpi_fan_probe(struct platform_device *pdev)
|
||||
{
|
||||
int result = 0;
|
||||
|
|
@ -556,7 +536,10 @@ static int acpi_fan_probe(struct platform_device *pdev)
|
|||
if (result)
|
||||
return result;
|
||||
|
||||
result = devm_acpi_fan_notify_init(&pdev->dev);
|
||||
result = devm_acpi_install_notify_handler(&pdev->dev,
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
acpi_fan_notify_handler,
|
||||
&pdev->dev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
|
|
|
|||
|
|
@ -336,11 +336,26 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
|
|||
EXPORT_SYMBOL_GPL(acpi_get_cpuid);
|
||||
|
||||
#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
|
||||
static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base,
|
||||
static bool madt_entry_is_valid(struct acpi_subtable_header *entry,
|
||||
unsigned long end)
|
||||
{
|
||||
unsigned long start = (unsigned long)entry;
|
||||
|
||||
if (start >= end || end - start < sizeof(*entry))
|
||||
return false;
|
||||
|
||||
return entry->length >= sizeof(*entry) && entry->length <= end - start;
|
||||
}
|
||||
|
||||
static int get_ioapic_id(struct acpi_subtable_header *entry,
|
||||
const unsigned long end, u32 gsi_base,
|
||||
u64 *phys_addr, int *ioapic_id)
|
||||
{
|
||||
struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;
|
||||
|
||||
if (!madt_entry_is_valid(entry, end) || BAD_MADT_ENTRY(ioapic, end))
|
||||
return 0;
|
||||
|
||||
if (ioapic->global_irq_base != gsi_base)
|
||||
return 0;
|
||||
|
||||
|
|
@ -361,17 +376,19 @@ static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)
|
|||
return apic_id;
|
||||
|
||||
entry = (unsigned long)madt;
|
||||
if (madt->header.length < sizeof(*madt))
|
||||
return apic_id;
|
||||
madt_end = entry + madt->header.length;
|
||||
|
||||
/* Parse all entries looking for a match. */
|
||||
entry += sizeof(struct acpi_table_madt);
|
||||
while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
|
||||
while (madt_entry_is_valid((struct acpi_subtable_header *)entry,
|
||||
madt_end)) {
|
||||
hdr = (struct acpi_subtable_header *)entry;
|
||||
if (hdr->type == ACPI_MADT_TYPE_IO_APIC &&
|
||||
get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id))
|
||||
get_ioapic_id(hdr, madt_end, gsi_base, phys_addr, &apic_id))
|
||||
break;
|
||||
else
|
||||
entry += hdr->length;
|
||||
entry += hdr->length;
|
||||
}
|
||||
|
||||
return apic_id;
|
||||
|
|
@ -398,7 +415,9 @@ static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base,
|
|||
|
||||
header = (struct acpi_subtable_header *)obj->buffer.pointer;
|
||||
if (header->type == ACPI_MADT_TYPE_IO_APIC)
|
||||
get_ioapic_id(header, gsi_base, phys_addr, &apic_id);
|
||||
get_ioapic_id(header,
|
||||
(unsigned long)header + obj->buffer.length,
|
||||
gsi_base, phys_addr, &apic_id);
|
||||
|
||||
exit:
|
||||
kfree(buffer.pointer);
|
||||
|
|
|
|||
|
|
@ -285,6 +285,12 @@ static int __init acpi_processor_driver_init(void)
|
|||
unregister_idle_drv:
|
||||
acpi_processor_unregister_idle_driver();
|
||||
|
||||
if (acpi_processor_cpufreq_init) {
|
||||
cpufreq_unregister_notifier(&acpi_processor_notifier_block,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
acpi_processor_cpufreq_init = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user