diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/Kconfig | 13 | ||||
-rw-r--r-- | drivers/acpi/Makefile | 2 | ||||
-rw-r--r-- | drivers/acpi/ac.c | 20 | ||||
-rw-r--r-- | drivers/acpi/acpi_extlog.c | 8 | ||||
-rw-r--r-- | drivers/acpi/acpi_ipmi.c | 3 | ||||
-rw-r--r-- | drivers/acpi/acpi_platform.c | 13 | ||||
-rw-r--r-- | drivers/acpi/acpi_processor.c | 5 | ||||
-rw-r--r-- | drivers/acpi/acpi_video.c | 157 | ||||
-rw-r--r-- | drivers/acpi/acpica/utresrc.c | 17 | ||||
-rw-r--r-- | drivers/acpi/apei/ghes.c | 1 | ||||
-rw-r--r-- | drivers/acpi/battery.c | 22 | ||||
-rw-r--r-- | drivers/acpi/blacklist.c | 8 | ||||
-rw-r--r-- | drivers/acpi/cppc_acpi.c | 80 | ||||
-rw-r--r-- | drivers/acpi/glue.c | 12 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 2 | ||||
-rw-r--r-- | drivers/acpi/ioapic.c | 6 | ||||
-rw-r--r-- | drivers/acpi/nfit/core.c | 6 | ||||
-rw-r--r-- | drivers/acpi/pmic/intel_pmic_chtwc.c | 280 | ||||
-rw-r--r-- | drivers/acpi/pmic/intel_pmic_xpower.c | 21 | ||||
-rw-r--r-- | drivers/acpi/power.c | 1 | ||||
-rw-r--r-- | drivers/acpi/property.c | 259 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 37 | ||||
-rw-r--r-- | drivers/acpi/spcr.c | 2 | ||||
-rw-r--r-- | drivers/acpi/sysfs.c | 9 | ||||
-rw-r--r-- | drivers/acpi/tables.c | 16 | ||||
-rw-r--r-- | drivers/acpi/utils.c | 66 |
26 files changed, 853 insertions, 213 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 83e5f7e1a20d..de3b8fce5164 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -256,7 +256,7 @@ config ACPI_PROCESSOR config ACPI_IPMI tristate "IPMI" - depends on IPMI_SI + depends on IPMI_HANDLER default n help This driver enables the ACPI to access the BMC controller. And it @@ -469,9 +469,8 @@ config ACPI_WATCHDOG config ACPI_EXTLOG tristate "Extended Error Log support" - depends on X86_MCE && X86_LOCAL_APIC + depends on X86_MCE && X86_LOCAL_APIC && EDAC select UEFI_CPER - select RAS default n help Certain usages such as Predictive Failure Analysis (PFA) require @@ -506,7 +505,7 @@ config CRC_PMIC_OPREGION config XPOWER_PMIC_OPREGION bool "ACPI operation region support for XPower AXP288 PMIC" - depends on AXP288_ADC = y + depends on MFD_AXP20X_I2C help This config adds ACPI operation region support for XPower AXP288 PMIC. @@ -516,6 +515,12 @@ config BXT_WC_PMIC_OPREGION help This config adds ACPI operation region support for BXT WhiskeyCove PMIC. +config CHT_WC_PMIC_OPREGION + bool "ACPI operation region support for CHT Whiskey Cove PMIC" + depends on INTEL_SOC_PMIC_CHTWC + help + This config adds ACPI operation region support for CHT Whiskey Cove PMIC. + endif config ACPI_CONFIGFS diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index a391bbc48105..d78065cc9324 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -2,7 +2,6 @@ # Makefile for the Linux ACPI interpreter # -ccflags-y := -Os ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT # @@ -102,6 +101,7 @@ obj-$(CONFIG_PMIC_OPREGION) += pmic/intel_pmic.o obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o obj-$(CONFIG_BXT_WC_PMIC_OPREGION) += pmic/intel_pmic_bxtwc.o +obj-$(CONFIG_CHT_WC_PMIC_OPREGION) += pmic/intel_pmic_chtwc.o obj-$(CONFIG_ACPI_CONFIGFS) += acpi_configfs.o diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index f71b756b05c4..8f52483219ba 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -57,12 +57,23 @@ static int acpi_ac_add(struct acpi_device *device); static int acpi_ac_remove(struct acpi_device *device); static void acpi_ac_notify(struct acpi_device *device, u32 event); +struct acpi_ac_bl { + const char *hid; + int hrv; +}; + static const struct acpi_device_id ac_device_ids[] = { {"ACPI0003", 0}, {"", 0}, }; MODULE_DEVICE_TABLE(acpi, ac_device_ids); +/* Lists of PMIC ACPI HIDs with an (often better) native charger driver */ +static const struct acpi_ac_bl acpi_ac_blacklist[] = { + { "INT33F4", -1 }, /* X-Powers AXP288 PMIC */ + { "INT34D3", 3 }, /* Intel Cherrytrail Whiskey Cove PMIC */ +}; + #ifdef CONFIG_PM_SLEEP static int acpi_ac_resume(struct device *dev); #endif @@ -424,11 +435,20 @@ static int acpi_ac_remove(struct acpi_device *device) static int __init acpi_ac_init(void) { + unsigned int i; int result; if (acpi_disabled) return -ENODEV; + for (i = 0; i < ARRAY_SIZE(acpi_ac_blacklist); i++) + if (acpi_dev_present(acpi_ac_blacklist[i].hid, "1", + acpi_ac_blacklist[i].hrv)) { + pr_info(PREFIX "AC: found native %s PMIC, not loading\n", + acpi_ac_blacklist[i].hid); + return -ENODEV; + } + #ifdef CONFIG_ACPI_PROCFS_POWER acpi_ac_dir = acpi_lock_ac_dir(); if (!acpi_ac_dir) diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index a15270a806fc..502ea4dc2080 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -229,7 +229,7 @@ static int __init extlog_init(void) if (!(cap & MCG_ELOG_P) || !extlog_get_l1addr()) return -ENODEV; - if (get_edac_report_status() == EDAC_REPORTING_FORCE) { + if (edac_get_report_status() == EDAC_REPORTING_FORCE) { pr_warn("Not loading eMCA, error reporting force-enabled through EDAC.\n"); return -EPERM; } @@ -285,8 +285,8 @@ static int __init extlog_init(void) * eMCA event report method has higher priority than EDAC method, * unless EDAC event report method is mandatory. */ - old_edac_report_status = get_edac_report_status(); - set_edac_report_status(EDAC_REPORTING_DISABLED); + old_edac_report_status = edac_get_report_status(); + edac_set_report_status(EDAC_REPORTING_DISABLED); mce_register_decode_chain(&extlog_mce_dec); /* enable OS to be involved to take over management from BIOS */ ((struct extlog_l1_head *)extlog_l1_addr)->flags |= FLAG_OS_OPTIN; @@ -308,7 +308,7 @@ err: static void __exit extlog_exit(void) { - set_edac_report_status(old_edac_report_status); + edac_set_report_status(old_edac_report_status); mce_unregister_decode_chain(&extlog_mce_dec); ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN; if (extlog_l1_addr) diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c index 747c2ba98534..1b64419e2fec 100644 --- a/drivers/acpi/acpi_ipmi.c +++ b/drivers/acpi/acpi_ipmi.c @@ -429,8 +429,7 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) if (msg->recv_type == IPMI_RESPONSE_RECV_TYPE && msg->msg.data_len == 1) { if (msg->msg.data[0] == IPMI_TIMEOUT_COMPLETION_CODE) { - dev_WARN_ONCE(dev, true, - "Unexpected response (timeout).\n"); + dev_dbg_once(dev, "Unexpected response (timeout).\n"); tx_msg->msg_done = ACPI_IPMI_TIMEOUT; } goto out_comp; diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index b4c1a6a51da4..88cd949003f3 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -25,9 +25,11 @@ ACPI_MODULE_NAME("platform"); static const struct acpi_device_id forbidden_id_list[] = { - {"PNP0000", 0}, /* PIC */ - {"PNP0100", 0}, /* Timer */ - {"PNP0200", 0}, /* AT DMA Controller */ + {"PNP0000", 0}, /* PIC */ + {"PNP0100", 0}, /* Timer */ + {"PNP0200", 0}, /* AT DMA Controller */ + {"ACPI0009", 0}, /* IOxAPIC */ + {"ACPI000A", 0}, /* IOAPIC */ {"", 0}, }; @@ -119,11 +121,14 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev, if (IS_ERR(pdev)) dev_err(&adev->dev, "platform device creation failed: %ld\n", PTR_ERR(pdev)); - else + else { + set_dev_node(&pdev->dev, acpi_get_node(adev->handle)); dev_dbg(&adev->dev, "created platform device %s\n", dev_name(&pdev->dev)); + } kfree(resources); + return pdev; } EXPORT_SYMBOL_GPL(acpi_create_platform_device); diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 0143135b3abe..f098e25b6b41 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -388,11 +388,6 @@ static int acpi_processor_add(struct acpi_device *device, if (result) /* Processor is not physically present or unavailable */ return 0; -#ifdef CONFIG_SMP - if (pr->id >= setup_max_cpus && pr->id != 0) - return 0; -#endif - BUG_ON(pr->id >= nr_cpu_ids); /* diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index d00bc0ef87a6..e88fe3632dd6 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -73,6 +73,10 @@ module_param(report_key_events, int, 0644); MODULE_PARM_DESC(report_key_events, "0: none, 1: output changes, 2: brightness changes, 3: all"); +/* + * Whether the struct acpi_video_device_attrib::device_id_scheme bit should be + * assumed even if not actually set. + */ static bool device_id_scheme = false; module_param(device_id_scheme, bool, 0444); @@ -88,6 +92,18 @@ static int acpi_video_bus_remove(struct acpi_device *device); static void acpi_video_bus_notify(struct acpi_device *device, u32 event); void acpi_video_detect_exit(void); +/* + * Indices in the _BCL method response: the first two items are special, + * the rest are all supported levels. + * + * See page 575 of the ACPI spec 3.0 + */ +enum acpi_video_level_idx { + ACPI_VIDEO_AC_LEVEL, /* level when machine has full power */ + ACPI_VIDEO_BATTERY_LEVEL, /* level when machine is on batteries */ + ACPI_VIDEO_FIRST_LEVEL, /* actual supported levels begin here */ +}; + static const struct acpi_device_id video_device_ids[] = { {ACPI_VIDEO_HID, 0}, {"", 0}, @@ -132,7 +148,15 @@ struct acpi_video_device_attrib { the VGA device. */ u32 pipe_id:3; /* For VGA multiple-head devices. */ u32 reserved:10; /* Must be 0 */ - u32 device_id_scheme:1; /* Device ID Scheme */ + + /* + * The device ID might not actually follow the scheme described by this + * struct acpi_video_device_attrib. If it does, then this bit + * device_id_scheme is set; otherwise, other fields should be ignored. + * + * (but also see the global flag device_id_scheme) + */ + u32 device_id_scheme:1; }; struct acpi_video_enumerated_device { @@ -217,20 +241,16 @@ static int acpi_video_get_brightness(struct backlight_device *bd) if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false)) return -EINVAL; - for (i = 2; i < vd->brightness->count; i++) { + for (i = ACPI_VIDEO_FIRST_LEVEL; i < vd->brightness->count; i++) { if (vd->brightness->levels[i] == cur_level) - /* - * The first two entries are special - see page 575 - * of the ACPI spec 3.0 - */ - return i - 2; + return i - ACPI_VIDEO_FIRST_LEVEL; } return 0; } static int acpi_video_set_brightness(struct backlight_device *bd) { - int request_level = bd->props.brightness + 2; + int request_level = bd->props.brightness + ACPI_VIDEO_FIRST_LEVEL; struct acpi_video_device *vd = bl_get_data(bd); cancel_delayed_work(&vd->switch_brightness_work); @@ -244,18 +264,18 @@ static const struct backlight_ops acpi_backlight_ops = { }; /* thermal cooling device callbacks */ -static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned - long *state) +static int video_get_max_state(struct thermal_cooling_device *cooling_dev, + unsigned long *state) { struct acpi_device *device = cooling_dev->devdata; struct acpi_video_device *video = acpi_driver_data(device); - *state = video->brightness->count - 3; + *state = video->brightness->count - ACPI_VIDEO_FIRST_LEVEL - 1; return 0; } -static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsigned - long *state) +static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, + unsigned long *state) { struct acpi_device *device = cooling_dev->devdata; struct acpi_video_device *video = acpi_driver_data(device); @@ -264,7 +284,8 @@ static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsig if (acpi_video_device_lcd_get_level_current(video, &level, false)) return -EINVAL; - for (offset = 2; offset < video->brightness->count; offset++) + for (offset = ACPI_VIDEO_FIRST_LEVEL; offset < video->brightness->count; + offset++) if (level == video->brightness->levels[offset]) { *state = video->brightness->count - offset - 1; return 0; @@ -280,7 +301,7 @@ video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long st struct acpi_video_device *video = acpi_driver_data(device); int level; - if (state >= video->brightness->count - 2) + if (state >= video->brightness->count - ACPI_VIDEO_FIRST_LEVEL) return -EINVAL; state = video->brightness->count - state; @@ -345,10 +366,12 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) } device->brightness->curr = level; - for (state = 2; state < device->brightness->count; state++) + for (state = ACPI_VIDEO_FIRST_LEVEL; state < device->brightness->count; + state++) if (level == device->brightness->levels[state]) { if (device->backlight) - device->backlight->props.brightness = state - 2; + device->backlight->props.brightness = + state - ACPI_VIDEO_FIRST_LEVEL; return 0; } @@ -530,14 +553,16 @@ acpi_video_bqc_value_to_level(struct acpi_video_device *device, if (device->brightness->flags._BQC_use_index) { /* - * _BQC returns an index that doesn't account for - * the first 2 items with special meaning, so we need - * to compensate for that by offsetting ourselves + * _BQC returns an index that doesn't account for the first 2 + * items with special meaning (see enum acpi_video_level_idx), + * so we need to compensate for that by offsetting ourselves */ if (device->brightness->flags._BCL_reversed) - bqc_value = device->brightness->count - 3 - bqc_value; + bqc_value = device->brightness->count - + ACPI_VIDEO_FIRST_LEVEL - 1 - bqc_value; - level = device->brightness->levels[bqc_value + 2]; + level = device->brightness->levels[bqc_value + + ACPI_VIDEO_FIRST_LEVEL]; } else { level = bqc_value; } @@ -571,7 +596,8 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, *level = acpi_video_bqc_value_to_level(device, *level); - for (i = 2; i < device->brightness->count; i++) + for (i = ACPI_VIDEO_FIRST_LEVEL; + i < device->brightness->count; i++) if (device->brightness->levels[i] == *level) { device->brightness->curr = *level; return 0; @@ -714,9 +740,37 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device, /* * Some systems always report current brightness level as maximum - * through _BQC, we need to test another value for them. + * through _BQC, we need to test another value for them. However, + * there is a subtlety: + * + * If the _BCL package ordering is descending, the first level + * (br->levels[2]) is likely to be 0, and if the number of levels + * matches the number of steps, we might confuse a returned level to + * mean the index. + * + * For example: + * + * current_level = max_level = 100 + * test_level = 0 + * returned level = 100 + * + * In this case 100 means the level, not the index, and _BCM failed. + * Still, if the _BCL package ordering is descending, the index of + * level 0 is also 100, so we assume _BQC is indexed, when it's not. + * + * This causes all _BQC calls to return bogus values causing weird + * behavior from the user's perspective. For example: + * + * xbacklight -set 10; xbacklight -set 20; + * + * would flash to 90% and then slowly down to the desired level (20). + * + * The solution is simple; test anything other than the first level + * (e.g. 1). */ - test_level = current_level == max_level ? br->levels[3] : max_level; + test_level = current_level == max_level + ? br->levels[ACPI_VIDEO_FIRST_LEVEL + 1] + : max_level; result = acpi_video_device_lcd_set_level(device, test_level); if (result) @@ -730,8 +784,8 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device, /* buggy _BQC found, need to find out if it uses index */ if (level < br->count) { if (br->flags._BCL_reversed) - level = br->count - 3 - level; - if (br->levels[level + 2] == test_level) + level = br->count - ACPI_VIDEO_FIRST_LEVEL - 1 - level; + if (br->levels[level + ACPI_VIDEO_FIRST_LEVEL] == test_level) br->flags._BQC_use_index = 1; } @@ -761,7 +815,7 @@ int acpi_video_get_levels(struct acpi_device *device, goto out; } - if (obj->package.count < 2) { + if (obj->package.count < ACPI_VIDEO_FIRST_LEVEL) { result = -EINVAL; goto out; } @@ -773,8 +827,13 @@ int acpi_video_get_levels(struct acpi_device *device, goto out; } - br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), - GFP_KERNEL); + /* + * Note that we have to reserve 2 extra items (ACPI_VIDEO_FIRST_LEVEL), + * in order to account for buggy BIOS which don't export the first two + * special levels (see below) + */ + br->levels = kmalloc((obj->package.count + ACPI_VIDEO_FIRST_LEVEL) * + sizeof(*br->levels), GFP_KERNEL); if (!br->levels) { result = -ENOMEM; goto out_free; @@ -788,7 +847,8 @@ int acpi_video_get_levels(struct acpi_device *device, } value = (u32) o->integer.value; /* Skip duplicate entries */ - if (count > 2 && br->levels[count - 1] == value) + if (count > ACPI_VIDEO_FIRST_LEVEL + && br->levels[count - 1] == value) continue; br->levels[count] = value; @@ -804,27 +864,30 @@ int acpi_video_get_levels(struct acpi_device *device, * In this case, the first two elements in _BCL packages * are also supported brightness levels that OS should take care of. */ - for (i = 2; i < count; i++) { - if (br->levels[i] == br->levels[0]) + for (i = ACPI_VIDEO_FIRST_LEVEL; i < count; i++) { + if (br->levels[i] == br->levels[ACPI_VIDEO_AC_LEVEL]) level_ac_battery++; - if (br->levels[i] == br->levels[1]) + if (br->levels[i] == br->levels[ACPI_VIDEO_BATTERY_LEVEL]) level_ac_battery++; } - if (level_ac_battery < 2) { - level_ac_battery = 2 - level_ac_battery; + if (level_ac_battery < ACPI_VIDEO_FIRST_LEVEL) { + level_ac_battery = ACPI_VIDEO_FIRST_LEVEL - level_ac_battery; br->flags._BCL_no_ac_battery_levels = 1; - for (i = (count - 1 + level_ac_battery); i >= 2; i--) + for (i = (count - 1 + level_ac_battery); + i >= ACPI_VIDEO_FIRST_LEVEL; i--) br->levels[i] = br->levels[i - level_ac_battery]; count += level_ac_battery; - } else if (level_ac_battery > 2) + } else if (level_ac_battery > ACPI_VIDEO_FIRST_LEVEL) ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package")); /* Check if the _BCL package is in a reversed order */ - if (max_level == br->levels[2]) { + if (max_level == br->levels[ACPI_VIDEO_FIRST_LEVEL]) { br->flags._BCL_reversed = 1; - sort(&br->levels[2], count - 2, sizeof(br->levels[2]), - acpi_video_cmp_level, NULL); + sort(&br->levels[ACPI_VIDEO_FIRST_LEVEL], + count - ACPI_VIDEO_FIRST_LEVEL, + sizeof(br->levels[ACPI_VIDEO_FIRST_LEVEL]), + acpi_video_cmp_level, NULL); } else if (max_level != br->levels[count - 1]) ACPI_ERROR((AE_INFO, "Found unordered _BCL package")); @@ -894,7 +957,7 @@ acpi_video_init_brightness(struct acpi_video_device *device) * level_old is invalid (no matter whether it's a level * or an index). Set the backlight to max_level in this case. */ - for (i = 2; i < br->count; i++) + for (i = ACPI_VIDEO_FIRST_LEVEL; i < br->count; i++) if (level == br->levels[i]) break; if (i == br->count || !level) @@ -906,7 +969,8 @@ set_level: goto out_free_levels; ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "found %d brightness levels\n", br->count - 2)); + "found %d brightness levels\n", + br->count - ACPI_VIDEO_FIRST_LEVEL)); return 0; out_free_levels: @@ -1297,7 +1361,7 @@ acpi_video_get_next_level(struct acpi_video_device *device, max = max_below = 0; min = min_above = 255; /* Find closest level to level_current */ - for (i = 2; i < device->brightness->count; i++) { + for (i = ACPI_VIDEO_FIRST_LEVEL; i < device->brightness->count; i++) { l = device->brightness->levels[i]; if (abs(l - level_current) < abs(delta)) { delta = l - level_current; @@ -1307,7 +1371,7 @@ acpi_video_get_next_level(struct acpi_video_device *device, } /* Ajust level_current to closest available level */ level_current += delta; - for (i = 2; i < device->brightness->count; i++) { + for (i = ACPI_VIDEO_FIRST_LEVEL; i < device->brightness->count; i++) { l = device->brightness->levels[i]; if (l < min) min = l; @@ -1680,7 +1744,8 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_FIRMWARE; - props.max_brightness = device->brightness->count - 3; + props.max_brightness = + device->brightness->count - ACPI_VIDEO_FIRST_LEVEL - 1; device->backlight = backlight_device_register(name, parent, device, diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index c86bae7b1d0f..ff096d9755b9 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -421,10 +421,8 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE(ut_walk_aml_resources); - /* - * The absolute minimum resource template is one end_tag descriptor. - * However, we will treat a lone end_tag as just a simple buffer. - */ + /* The absolute minimum resource template is one end_tag descriptor */ + if (aml_length < sizeof(struct aml_resource_end_tag)) { return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); } @@ -456,8 +454,9 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, /* Invoke the user function */ if (user_function) { - status = user_function(aml, length, offset, - resource_index, context); + status = + user_function(aml, length, offset, resource_index, + context); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -481,12 +480,6 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, *context = aml; } - /* Check if buffer is defined to be longer than the resource length */ - - if (aml_length > (offset + length)) { - return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); - } - /* Normal exit */ return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index b192b42a8351..79b3c9c5a3bc 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -1073,6 +1073,7 @@ static int ghes_remove(struct platform_device *ghes_dev) if (list_empty(&ghes_sci)) unregister_acpi_hed_notifier(&ghes_notifier_sci); mutex_unlock(&ghes_list_mutex); + synchronize_rcu(); break; case ACPI_HEST_NOTIFY_NMI: ghes_nmi_remove(ghes); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 4ef1e4624b2b..d42eeef9d928 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -67,6 +67,7 @@ MODULE_DESCRIPTION("ACPI Battery Driver"); MODULE_LICENSE("GPL"); static async_cookie_t async_cookie; +static bool battery_driver_registered; static int battery_bix_broken_package; static int battery_notification_delay_ms; static unsigned int cache_time = 1000; @@ -93,6 +94,11 @@ static const struct acpi_device_id battery_device_ids[] = { MODULE_DEVICE_TABLE(acpi, battery_device_ids); +/* Lists of PMIC ACPI HIDs with an (often better) native battery driver */ +static const char * const acpi_battery_blacklist[] = { + "INT33F4", /* X-Powers AXP288 PMIC */ +}; + enum { ACPI_BATTERY_ALARM_PRESENT, ACPI_BATTERY_XINFO_PRESENT, @@ -1315,8 +1321,17 @@ static struct acpi_driver acpi_battery_driver = { static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) { + unsigned int i; int result; + for (i = 0; i < ARRAY_SIZE(acpi_battery_blacklist); i++) + if (acpi_dev_present(acpi_battery_blacklist[i], "1", -1)) { + pr_info(PREFIX ACPI_BATTERY_DEVICE_NAME + ": found native %s PMIC, not loading\n", + acpi_battery_blacklist[i]); + return; + } + dmi_check_system(bat_dmi_table); #ifdef CONFIG_ACPI_PROCFS_POWER @@ -1329,6 +1344,7 @@ static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) if (result < 0) acpi_unlock_battery_dir(acpi_battery_dir); #endif + battery_driver_registered = (result == 0); } static int __init acpi_battery_init(void) @@ -1343,9 +1359,11 @@ static int __init acpi_battery_init(void) static void __exit acpi_battery_exit(void) { async_synchronize_cookie(async_cookie + 1); - acpi_bus_unregister_driver(&acpi_battery_driver); + if (battery_driver_registered) + acpi_bus_unregister_driver(&acpi_battery_driver); #ifdef CONFIG_ACPI_PROCFS_POWER - acpi_unlock_battery_dir(acpi_battery_dir); + if (acpi_battery_dir) + acpi_unlock_battery_dir(acpi_battery_dir); #endif } diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 4421f7c9981c..bb542acc0574 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -188,6 +188,14 @@ static struct dmi_system_id acpi_rev_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 3350"), }, }, + { + .callback = dmi_enable_rev_override, + .ident = "DELL Inspiron 7537", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7537"), + }, + }, #endif {} }; diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 3ca0729f7e0e..6cbe6036da99 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -132,49 +132,54 @@ __ATTR(_name, 0444, show_##_name, NULL) #define to_cpc_desc(a) container_of(a, struct cpc_desc, kobj) +#define show_cppc_data(access_fn, struct_name, member_name) \ + static ssize_t show_##member_name(struct kobject *kobj, \ + struct attribute *attr, char *buf) \ + { \ + struct cpc_desc *cpc_ptr = to_cpc_desc(kobj); \ + struct struct_name st_name = {0}; \ + int ret; \ + \ + ret = access_fn(cpc_ptr->cpu_id, &st_name); \ + if (ret) \ + return ret; \ + \ + return scnprintf(buf, PAGE_SIZE, "%llu\n", \ + (u64)st_name.member_name); \ + } \ + define_one_cppc_ro(member_name) + +show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, highest_perf); +show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf); +show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf); +show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf); +show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf); +show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time); + static ssize_t show_feedback_ctrs(struct kobject *kobj, struct attribute *attr, char *buf) { struct cpc_desc *cpc_ptr = to_cpc_desc(kobj); struct cppc_perf_fb_ctrs fb_ctrs = {0}; + int ret; - cppc_get_perf_ctrs(cpc_ptr->cpu_id, &fb_ctrs); + ret = cppc_get_perf_ctrs(cpc_ptr->cpu_id, &fb_ctrs); + if (ret) + return ret; return scnprintf(buf, PAGE_SIZE, "ref:%llu del:%llu\n", fb_ctrs.reference, fb_ctrs.delivered); } define_one_cppc_ro(feedback_ctrs); -static ssize_t show_reference_perf(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct cpc_desc *cpc_ptr = to_cpc_desc(kobj); - struct cppc_perf_fb_ctrs fb_ctrs = {0}; - - cppc_get_perf_ctrs(cpc_ptr->cpu_id, &fb_ctrs); - - return scnprintf(buf, PAGE_SIZE, "%llu\n", - fb_ctrs.reference_perf); -} -define_one_cppc_ro(reference_perf); - -static ssize_t show_wraparound_time(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct cpc_desc *cpc_ptr = to_cpc_desc(kobj); - struct cppc_perf_fb_ctrs fb_ctrs = {0}; - - cppc_get_perf_ctrs(cpc_ptr->cpu_id, &fb_ctrs); - - return scnprintf(buf, PAGE_SIZE, "%llu\n", fb_ctrs.ctr_wrap_time); - -} -define_one_cppc_ro(wraparound_time); - static struct attribute *cppc_attrs[] = { &feedback_ctrs.attr, &reference_perf.attr, &wraparound_time.attr, + &highest_perf.attr, + &lowest_perf.attr, + &lowest_nonlinear_perf.attr, + &nominal_perf.attr, NULL }; @@ -972,9 +977,9 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); - struct cpc_register_resource *highest_reg, *lowest_reg, *ref_perf, - *nom_perf; - u64 high, low, nom; + struct cpc_register_resource *highest_reg, *lowest_reg, + *lowest_non_linear_reg, *nominal_reg; + u64 high, low, nom, min_nonlinear; int ret = 0, regs_in_pcc = 0; if (!cpc_desc) { @@ -984,12 +989,12 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) highest_reg = &cpc_desc->cpc_regs[HIGHEST_PERF]; lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF]; - ref_perf = &cpc_desc->cpc_regs[REFERENCE_PERF]; - nom_perf = &cpc_desc->cpc_regs[NOMINAL_PERF]; + lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF]; + nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF]; /* Are any of the regs PCC ?*/ if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) || - CPC_IN_PCC(ref_perf) || CPC_IN_PCC(nom_perf)) { + CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg)) { regs_in_pcc = 1; down_write(&pcc_data.pcc_lock); /* Ring doorbell once to update PCC subspace */ @@ -1005,10 +1010,13 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) cpc_read(cpunum, lowest_reg, &low); perf_caps->lowest_perf = low; - cpc_read(cpunum, nom_perf, &nom); + cpc_read(cpunum, nominal_reg, &nom); perf_caps->nominal_perf = nom; - if (!high || !low || !nom) + cpc_read(cpunum, lowest_non_linear_reg, &min_nonlinear); + perf_caps->lowest_nonlinear_perf = min_nonlinear; + + if (!high || !low || !nom || !min_nonlinear) ret = -EFAULT; out_err: @@ -1083,7 +1091,7 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) perf_fb_ctrs->delivered = delivered; perf_fb_ctrs->reference = reference; perf_fb_ctrs->reference_perf = ref_perf; - perf_fb_ctrs->ctr_wrap_time = ctr_wrap_time; + perf_fb_ctrs->wraparound_time = ctr_wrap_time; out_err: if (regs_in_pcc) up_write(&pcc_data.pcc_lock); diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index fb19e1cdb641..edc8663b5db3 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -99,13 +99,13 @@ static int find_child_checks(struct acpi_device *adev, bool check_children) return -ENODEV; /* - * If the device has a _HID (or _CID) returning a valid ACPI/PNP - * device ID, it is better to make it look less attractive here, so that - * the other device with the same _ADR value (that may not have a valid - * device ID) can be matched going forward. [This means a second spec - * violation in a row, so whatever we do here is best effort anyway.] + * If the device has a _HID returning a valid ACPI/PNP device ID, it is + * better to make it look less attractive here, so that the other device + * with the same _ADR value (that may not have a valid device ID) can be + * matched going forward. [This means a second spec violation in a row, + * so whatever we do here is best effort anyway.] */ - return sta_present && list_empty(&adev->pnp.ids) ? + return sta_present && !adev->pnp.type.platform_id ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE; } diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index f15900132912..66229ffa909b 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -65,8 +65,6 @@ static inline void acpi_cmos_rtc_init(void) {} #endif int acpi_rev_override_setup(char *str); -extern bool acpi_force_hot_remove; - void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, const char *name); int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c index 1120dfd625b8..7e4fbf9a53a3 100644 --- a/drivers/acpi/ioapic.c +++ b/drivers/acpi/ioapic.c @@ -45,6 +45,12 @@ static acpi_status setup_res(struct acpi_resource *acpi_res, void *data) struct resource *res = data; struct resource_win win; + /* + * We might assign this to 'res' later, make sure all pointers are + * cleared before the resource is added to the global list + */ + memset(&win, 0, sizeof(win)); + res->flags = 0; if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM)) return AE_OK; diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 662036bdc65e..c8ea9d698cd0 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1617,7 +1617,11 @@ static int cmp_map(const void *m0, const void *m1) const struct nfit_set_info_map *map0 = m0; const struct nfit_set_info_map *map1 = m1; - return map0->region_offset - map1->region_offset; + if (map0->region_offset < map1->region_offset) + return -1; + else if (map0->region_offset > map1->region_offset) + return 1; + return 0; } /* Retrieve the nth entry referencing this spa */ diff --git a/drivers/acpi/pmic/intel_pmic_chtwc.c b/drivers/acpi/pmic/intel_pmic_chtwc.c new file mode 100644 index 000000000000..85636d7a9d39 --- /dev/null +++ b/drivers/acpi/pmic/intel_pmic_chtwc.c @@ -0,0 +1,280 @@ +/* + * Intel CHT Whiskey Cove PMIC operation region driver + * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> + * + * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: + * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/acpi.h> +#include <linux/init.h> +#include <linux/mfd/intel_soc_pmic.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include "intel_pmic.h" + +#define CHT_WC_V1P05A_CTRL 0x6e3b +#define CHT_WC_V1P15_CTRL 0x6e3c +#define CHT_WC_V1P05A_VSEL 0x6e3d +#define CHT_WC_V1P15_VSEL 0x6e3e +#define CHT_WC_V1P8A_CTRL 0x6e56 +#define CHT_WC_V1P8SX_CTRL 0x6e57 +#define CHT_WC_VDDQ_CTRL 0x6e58 +#define CHT_WC_V1P2A_CTRL 0x6e59 +#define CHT_WC_V1P2SX_CTRL 0x6e5a +#define CHT_WC_V1P8A_VSEL 0x6e5b +#define CHT_WC_VDDQ_VSEL 0x6e5c +#define CHT_WC_V2P8SX_CTRL 0x6e5d +#define CHT_WC_V3P3A_CTRL 0x6e5e +#define CHT_WC_V3P3SD_CTRL 0x6e5f +#define CHT_WC_VSDIO_CTRL 0x6e67 +#define CHT_WC_V3P3A_VSEL 0x6e68 +#define CHT_WC_VPROG1A_CTRL 0x6e90 +#define CHT_WC_VPROG1B_CTRL 0x6e91 +#define CHT_WC_VPROG1F_CTRL 0x6e95 +#define CHT_WC_VPROG2D_CTRL 0x6e99 +#define CHT_WC_VPROG3A_CTRL 0x6e9a +#define CHT_WC_VPROG3B_CTRL 0x6e9b +#define CHT_WC_VPROG4A_CTRL 0x6e9c +#define CHT_WC_VPROG4B_CTRL 0x6e9d +#define CHT_WC_VPROG4C_CTRL 0x6e9e +#define CHT_WC_VPROG4D_CTRL 0x6e9f +#define CHT_WC_VPROG5A_CTRL 0x6ea0 +#define CHT_WC_VPROG5B_CTRL 0x6ea1 +#define CHT_WC_VPROG6A_CTRL 0x6ea2 +#define CHT_WC_VPROG6B_CTRL 0x6ea3 +#define CHT_WC_VPROG1A_VSEL 0x6ec0 +#define CHT_WC_VPROG1B_VSEL 0x6ec1 +#define CHT_WC_V1P8SX_VSEL 0x6ec2 +#define CHT_WC_V1P2SX_VSEL 0x6ec3 +#define CHT_WC_V1P2A_VSEL 0x6ec4 +#define CHT_WC_VPROG1F_VSEL 0x6ec5 +#define CHT_WC_VSDIO_VSEL 0x6ec6 +#define CHT_WC_V2P8SX_VSEL 0x6ec7 +#define CHT_WC_V3P3SD_VSEL 0x6ec8 +#define CHT_WC_VPROG2D_VSEL 0x6ec9 +#define CHT_WC_VPROG3A_VSEL 0x6eca +#define CHT_WC_VPROG3B_VSEL 0x6ecb +#define CHT_WC_VPROG4A_VSEL 0x6ecc +#define CHT_WC_VPROG4B_VSEL 0x6ecd +#define CHT_WC_VPROG4C_VSEL 0x6ece +#define CHT_WC_VPROG4D_VSEL 0x6ecf +#define CHT_WC_VPROG5A_VSEL 0x6ed0 +#define CHT_WC_VPROG5B_VSEL 0x6ed1 +#define CHT_WC_VPROG6A_VSEL 0x6ed2 +#define CHT_WC_VPROG6B_VSEL 0x6ed3 + +/* + * Regulator support is based on the non upstream patch: + * "regulator: whiskey_cove: implements Whiskey Cove pmic VRF support" + * https://github.com/intel-aero/meta-intel-aero/blob/master/recipes-kernel/linux/linux-yocto/0019-regulator-whiskey_cove-implements-WhiskeyCove-pmic-V.patch + */ +static struct pmic_table power_table[] = { + { + .address = 0x0, + .reg = CHT_WC_V1P8A_CTRL, + .bit = 0x01, + }, /* V18A */ + { + .address = 0x04, + .reg = CHT_WC_V1P8SX_CTRL, + .bit = 0x07, + }, /* V18X */ + { + .address = 0x08, + .reg = CHT_WC_VDDQ_CTRL, + .bit = 0x01, + }, /* VDDQ */ + { + .address = 0x0c, + .reg = CHT_WC_V1P2A_CTRL, + .bit = 0x07, + }, /* V12A */ + { + .address = 0x10, + .reg = CHT_WC_V1P2SX_CTRL, + .bit = 0x07, + }, /* V12X */ + { + .address = 0x14, + .reg = CHT_WC_V2P8SX_CTRL, + .bit = 0x07, + }, /* V28X */ + { + .address = 0x18, + .reg = CHT_WC_V3P3A_CTRL, + .bit = 0x01, + }, /* V33A */ + { + .address = 0x1c, + .reg = CHT_WC_V3P3SD_CTRL, + .bit = 0x07, + }, /* V3SD */ + { + .address = 0x20, + .reg = CHT_WC_VSDIO_CTRL, + .bit = 0x07, + }, /* VSD */ +/* { + .address = 0x24, + .reg = ??, + .bit = ??, + }, ** VSW2 */ +/* { + .address = 0x28, + .reg = ??, + .bit = ??, + }, ** VSW1 */ +/* { + .address = 0x2c, + .reg = ??, + .bit = ??, + }, ** VUPY */ +/* { + .address = 0x30, + .reg = ??, + .bit = ??, + }, ** VRSO */ + { + .address = 0x34, + .reg = CHT_WC_VPROG1A_CTRL, + .bit = 0x07, + }, /* VP1A */ + { + .address = 0x38, + .reg = CHT_WC_VPROG1B_CTRL, + .bit = 0x07, + }, /* VP1B */ + { + .address = 0x3c, + .reg = CHT_WC_VPROG1F_CTRL, + .bit = 0x07, + }, /* VP1F */ + { + .address = 0x40, + .reg = CHT_WC_VPROG2D_CTRL, + .bit = 0x07, + }, /* VP2D */ + { + .address = 0x44, + .reg = CHT_WC_VPROG3A_CTRL, + .bit = 0x07, + }, /* VP3A */ + { + .address = 0x48, + .reg = CHT_WC_VPROG3B_CTRL, + .bit = 0x07, + }, /* VP3B */ + { + .address = 0x4c, + .reg = CHT_WC_VPROG4A_CTRL, + .bit = 0x07, + }, /* VP4A */ + { + .address = 0x50, + .reg = CHT_WC_VPROG4B_CTRL, + .bit = 0x07, + }, /* VP4B */ + { + .address = 0x54, + .reg = CHT_WC_VPROG4C_CTRL, + .bit = 0x07, + }, /* VP4C */ + { + .address = 0x58, + .reg = CHT_WC_VPROG4D_CTRL, + .bit = 0x07, + }, /* VP4D */ + { + .address = 0x5c, + .reg = CHT_WC_VPROG5A_CTRL, + .bit = 0x07, + }, /* VP5A */ + { + .address = 0x60, + .reg = CHT_WC_VPROG5B_CTRL, + .bit = 0x07, + }, /* VP5B */ + { + .address = 0x64, + .reg = CHT_WC_VPROG6A_CTRL, + .bit = 0x07, + }, /* VP6A */ + { + .address = 0x68, + .reg = CHT_WC_VPROG6B_CTRL, + .bit = 0x07, + }, /* VP6B */ +/* { + .address = 0x6c, + .reg = ??, + .bit = ??, + } ** VP7A */ +}; + +static int intel_cht_wc_pmic_get_power(struct regmap *regmap, int reg, + int bit, u64 *value) +{ + int data; + + if (regmap_read(regmap, reg, &data)) + return -EIO; + + *value = (data & bit) ? 1 : 0; + return 0; +} + +static int intel_cht_wc_pmic_update_power(struct regmap *regmap, int reg, + int bitmask, bool on) +{ + return regmap_update_bits(regmap, reg, bitmask, on ? 1 : 0); +} + +/* + * The thermal table and ops are empty, we do not support the Thermal opregion + * (DPTF) due to lacking documentation. + */ +static struct intel_pmic_opregion_data intel_cht_wc_pmic_opregion_data = { + .get_power = intel_cht_wc_pmic_get_power, + .update_power = intel_cht_wc_pmic_update_power, + .power_table = power_table, + .power_table_count = ARRAY_SIZE(power_table), +}; + +static int intel_cht_wc_pmic_opregion_probe(struct platform_device *pdev) +{ + struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); + + return intel_pmic_install_opregion_handler(&pdev->dev, + ACPI_HANDLE(pdev->dev.parent), + pmic->regmap, + &intel_cht_wc_pmic_opregion_data); +} + +static struct platform_device_id cht_wc_opregion_id_table[] = { + { .name = "cht_wcove_region" }, + {}, +}; +MODULE_DEVICE_TABLE(platform, cht_wc_opregion_id_table); + +static struct platform_driver intel_cht_wc_pmic_opregion_driver = { + .probe = intel_cht_wc_pmic_opregion_probe, + .driver = { + .name = "cht_whiskey_cove_pmic", + }, + .id_table = cht_wc_opregion_id_table, +}; +module_platform_driver(intel_cht_wc_pmic_opregion_driver); + +MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC operation region driver"); +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index e6e991ac20f3..55f51115f016 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c @@ -18,7 +18,6 @@ #include <linux/mfd/axp20x.h> #include <linux/regmap.h> #include <linux/platform_device.h> -#include <linux/iio/consumer.h> #include "intel_pmic.h" #define XPOWER_GPADC_LOW 0x5b @@ -186,28 +185,16 @@ static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg, * @regmap: regmap of the PMIC device * @reg: register to get the reading * - * We could get the sensor value by manipulating the HW regs here, but since - * the axp288 IIO driver may also access the same regs at the same time, the - * APIs provided by IIO subsystem are used here instead to avoid problems. As - * a result, the two passed in params are of no actual use. - * * Return a positive value on success, errno on failure. */ static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg) { - struct iio_channel *gpadc_chan; - int ret, val; - - gpadc_chan = iio_channel_get(NULL, "axp288-system-temp"); - if (IS_ERR_OR_NULL(gpadc_chan)) - return -EACCES; + u8 buf[2]; - ret = iio_read_channel_raw(gpadc_chan, &val); - if (ret < 0) - val = ret; + if (regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2)) + return -EIO; - iio_channel_release(gpadc_chan); - return val; + return (buf[0] << 4) + ((buf[1] >> 4) & 0x0F); } static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = { diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index fcd4ce6f78d5..1c2b846c5776 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -200,6 +200,7 @@ static int acpi_power_get_list_state(struct list_head *list, int *state) return -EINVAL; /* The state of the list is 'on' IFF all resources are 'on'. */ + cur_state = 0; list_for_each_entry(entry, list, node) { struct acpi_power_resource *resource = entry->resource; acpi_handle handle = resource->device.handle; diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 3afddcd834ef..9364398204e9 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -37,14 +37,16 @@ static const u8 ads_uuid[16] = { static bool acpi_enumerate_nondev_subnodes(acpi_handle scope, const union acpi_object *desc, - struct acpi_device_data *data); + struct acpi_device_data *data, + struct fwnode_handle *parent); static bool acpi_extract_properties(const union acpi_object *desc, struct acpi_device_data *data); static bool acpi_nondev_subnode_extract(const union acpi_object *desc, acpi_handle handle, const union acpi_object *link, - struct list_head *list) + struct list_head *list, + struct fwnode_handle *parent) { struct acpi_data_node *dn; bool result; @@ -55,6 +57,7 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc, dn->name = link->package.elements[0].string.pointer; dn->fwnode.type = FWNODE_ACPI_DATA; + dn->parent = parent; INIT_LIST_HEAD(&dn->data.subnodes); result = acpi_extract_properties(desc, &dn->data); @@ -71,9 +74,11 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc, */ status = acpi_get_parent(handle, &scope); if (ACPI_SUCCESS(status) - && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data)) + && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data, + &dn->fwnode)) result = true; - } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data)) { + } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data, + &dn->fwnode)) { result = true; } @@ -91,7 +96,8 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc, static bool acpi_nondev_subnode_data_ok(acpi_handle handle, const union acpi_object *link, - struct list_head *list) + struct list_head *list, + struct fwnode_handle *parent) { struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; acpi_status status; @@ -101,7 +107,8 @@ static bool acpi_nondev_subnode_data_ok(acpi_handle handle, if (ACPI_FAILURE(status)) return false; - if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list)) + if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list, + parent)) return true; ACPI_FREE(buf.pointer); @@ -110,7 +117,8 @@ static bool acpi_nondev_subnode_data_ok(acpi_handle handle, static bool acpi_nondev_subnode_ok(acpi_handle scope, const union acpi_object *link, - struct list_head *list) + struct list_head *list, + struct fwnode_handle *parent) { acpi_handle handle; acpi_status status; @@ -123,12 +131,13 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope, if (ACPI_FAILURE(status)) return false; - return acpi_nondev_subnode_data_ok(handle, link, list); + return acpi_nondev_subnode_data_ok(handle, link, list, parent); } static int acpi_add_nondev_subnodes(acpi_handle scope, const union acpi_object *links, - struct list_head *list) + struct list_head *list, + struct fwnode_handle *parent) { bool ret = false; int i; @@ -150,15 +159,18 @@ static int acpi_add_nondev_subnodes(acpi_handle scope, /* The second one may be a string, a reference or a package. */ switch (link->package.elements[1].type) { case ACPI_TYPE_STRING: - result = acpi_nondev_subnode_ok(scope, link, list); + result = acpi_nondev_subnode_ok(scope, link, list, + parent); break; case ACPI_TYPE_LOCAL_REFERENCE: handle = link->package.elements[1].reference.handle; - result = acpi_nondev_subnode_data_ok(handle, link, list); + result = acpi_nondev_subnode_data_ok(handle, link, list, + parent); break; case ACPI_TYPE_PACKAGE: desc = &link->package.elements[1]; - result = acpi_nondev_subnode_extract(desc, NULL, link, list); + result = acpi_nondev_subnode_extract(desc, NULL, link, + list, parent); break; default: result = false; @@ -172,7 +184,8 @@ static int acpi_add_nondev_subnodes(acpi_handle scope, static bool acpi_enumerate_nondev_subnodes(acpi_handle scope, const union acpi_object *desc, - struct acpi_device_data *data) + struct acpi_device_data *data, + struct fwnode_handle *parent) { int i; @@ -194,7 +207,8 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope, if (memcmp(uuid->buffer.pointer, ads_uuid, sizeof(ads_uuid))) continue; - return acpi_add_nondev_subnodes(scope, links, &data->subnodes); + return acpi_add_nondev_subnodes(scope, links, &data->subnodes, + parent); } return false; @@ -345,7 +359,8 @@ void acpi_init_properties(struct acpi_device *adev) if (acpi_of) acpi_init_of_compatible(adev); } - if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer, &adev->data)) + if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer, + &adev->data, acpi_fwnode_handle(adev))) adev->data.pointer = buf.pointer; if (!adev->data.pointer) { @@ -699,6 +714,8 @@ static int acpi_data_prop_read_single(struct acpi_device_data *data, return ret; *(char **)val = obj->string.pointer; + + return 1; } else { ret = -EINVAL; } @@ -708,7 +725,15 @@ static int acpi_data_prop_read_single(struct acpi_device_data *data, int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname, enum dev_prop_type proptype, void *val) { - return adev ? acpi_data_prop_read_single(&adev->data, propname, proptype, val) : -EINVAL; + int ret; + + if (!adev) + return -EINVAL; + + ret = acpi_data_prop_read_single(&adev->data, propname, proptype, val); + if (ret < 0 || proptype != ACPI_TYPE_STRING) + return ret; + return 0; } static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val, @@ -784,7 +809,7 @@ static int acpi_copy_property_array_string(const union acpi_object *items, val[i] = items[i].string.pointer; } - return 0; + return nval; } static int acpi_data_prop_read(struct acpi_device_data *data, @@ -798,7 +823,7 @@ static int acpi_data_prop_read(struct acpi_device_data *data, if (val && nval == 1) { ret = acpi_data_prop_read_single(data, propname, proptype, val); - if (!ret) + if (ret >= 0) return ret; } @@ -809,7 +834,7 @@ static int acpi_data_prop_read(struct acpi_device_data *data, if (!val) return obj->package.count; - if (nval > obj->package.count) + if (proptype != DEV_PROP_STRING && nval > obj->package.count) return -EOVERFLOW; else if (nval <= 0) return -EINVAL; @@ -830,7 +855,9 @@ static int acpi_data_prop_read(struct acpi_device_data *data, ret = acpi_copy_property_array_u64(items, (u64 *)val, nval); break; case DEV_PROP_STRING: - ret = acpi_copy_property_array_string(items, (char **)val, nval); + ret = acpi_copy_property_array_string( + items, (char **)val, + min_t(u32, nval, obj->package.count)); break; default: ret = -EINVAL; @@ -865,21 +892,22 @@ int acpi_node_prop_read(struct fwnode_handle *fwnode, const char *propname, } /** - * acpi_get_next_subnode - Return the next child node handle for a device. - * @dev: Device to find the next child node for. + * acpi_get_next_subnode - Return the next child node handle for a fwnode + * @fwnode: Firmware node to find the next child node for. * @child: Handle to one of the device's child nodes or a null handle. */ -struct fwnode_handle *acpi_get_next_subnode(struct device *dev, +struct fwnode_handle *acpi_get_next_subnode(struct fwnode_handle *fwnode, struct fwnode_handle *child) { - struct acpi_device *adev = ACPI_COMPANION(dev); + struct acpi_device *adev = to_acpi_device_node(fwnode); struct list_head *head, *next; - if (!adev) - return NULL; - if (!child || child->type == FWNODE_ACPI) { - head = &adev->children; + if (adev) + head = &adev->children; + else + goto nondev; + if (list_empty(head)) goto nondev; @@ -888,7 +916,6 @@ struct fwnode_handle *acpi_get_next_subnode(struct device *dev, next = adev->node.next; if (next == head) { child = NULL; - adev = ACPI_COMPANION(dev); goto nondev; } adev = list_entry(next, struct acpi_device, node); @@ -900,9 +927,16 @@ struct fwnode_handle *acpi_get_next_subnode(struct device *dev, nondev: if (!child || child->type == FWNODE_ACPI_DATA) { + struct acpi_data_node *data = to_acpi_data_node(fwnode); struct acpi_data_node *dn; - head = &adev->data.subnodes; + if (adev) + head = &adev->data.subnodes; + else if (data) + head = &data->data.subnodes; + else + return NULL; + if (list_empty(head)) return NULL; @@ -920,3 +954,168 @@ struct fwnode_handle *acpi_get_next_subnode(struct device *dev, } return NULL; } + +/** + * acpi_node_get_parent - Return parent fwnode of this fwnode + * @fwnode: Firmware node whose parent to get + * + * Returns parent node of an ACPI device or data firmware node or %NULL if + * not available. + */ +struct fwnode_handle *acpi_node_get_parent(struct fwnode_handle *fwnode) +{ + if (is_acpi_data_node(fwnode)) { + /* All data nodes have parent pointer so just return that */ + return to_acpi_data_node(fwnode)->parent; + } else if (is_acpi_device_node(fwnode)) { + acpi_handle handle, parent_handle; + + handle = to_acpi_device_node(fwnode)->handle; + if (ACPI_SUCCESS(acpi_get_parent(handle, &parent_handle))) { + struct acpi_device *adev; + + if (!acpi_bus_get_device(parent_handle, &adev)) + return acpi_fwnode_handle(adev); + } + } + + return NULL; +} + +/** + * acpi_graph_get_next_endpoint - Get next endpoint ACPI firmware node + * @fwnode: Pointer to the parent firmware node + * @prev: Previous endpoint node or %NULL to get the first + * + * Looks up next endpoint ACPI firmware node below a given @fwnode. Returns + * %NULL if there is no next endpoint, ERR_PTR() in case of error. In case + * of success the next endpoint is returned. + */ +struct fwnode_handle *acpi_graph_get_next_endpoint(struct fwnode_handle *fwnode, + struct fwnode_handle *prev) +{ + struct fwnode_handle *port = NULL; + struct fwnode_handle *endpoint; + + if (!prev) { + do { + port = fwnode_get_next_child_node(fwnode, port); + /* Ports must have port property */ + if (fwnode_property_present(port, "port")) + break; + } while (port); + } else { + port = fwnode_get_parent(prev); + } + + if (!port) + return NULL; + + endpoint = fwnode_get_next_child_node(port, prev); + while (!endpoint) { + port = fwnode_get_next_child_node(fwnode, port); + if (!port) + break; + if (fwnode_property_present(port, "port")) + endpoint = fwnode_get_next_child_node(port, NULL); + } + + if (endpoint) { + /* Endpoints must have "endpoint" property */ + if (!fwnode_property_present(endpoint, "endpoint")) + return ERR_PTR(-EPROTO); + } + + return endpoint; +} + +/** + * acpi_graph_get_child_prop_value - Return a child with a given property value + * @fwnode: device fwnode + * @prop_name: The name of the property to look for + * @val: the desired property value + * + * Return the port node corresponding to a given port number. Returns + * the child node on success, NULL otherwise. + */ +static struct fwnode_handle *acpi_graph_get_child_prop_value( + struct fwnode_handle *fwnode, const char *prop_name, unsigned int val) +{ + struct fwnode_handle *child; + + fwnode_for_each_child_node(fwnode, child) { + u32 nr; + + if (!fwnode_property_read_u32(fwnode, prop_name, &nr)) + continue; + + if (val == nr) + return child; + } + + return NULL; +} + + +/** + * acpi_graph_get_remote_enpoint - Parses and returns remote end of an endpoint + * @fwnode: Endpoint firmware node pointing to a remote device + * @parent: Firmware node of remote port parent is filled here if not %NULL + * @port: Firmware node of remote port is filled here if not %NULL + * @endpoint: Firmware node of remote endpoint is filled here if not %NULL + * + * Function parses remote end of ACPI firmware remote endpoint and fills in + * fields requested by the caller. Returns %0 in case of success and + * negative errno otherwise. + */ +int acpi_graph_get_remote_endpoint(struct fwnode_handle *fwnode, + struct fwnode_handle **parent, + struct fwnode_handle **port, + struct fwnode_handle **endpoint) +{ + unsigned int port_nr, endpoint_nr; + struct acpi_reference_args args; + int ret; + + memset(&args, 0, sizeof(args)); + ret = acpi_node_get_property_reference(fwnode, "remote-endpoint", 0, + &args); + if (ret) + return ret; + + /* + * Always require two arguments with the reference: port and + * endpoint indices. + */ + if (args.nargs != 2) + return -EPROTO; + + fwnode = acpi_fwnode_handle(args.adev); + port_nr = args.args[0]; + endpoint_nr = args.args[1]; + + if (parent) + *parent = fwnode; + + if (!port && !endpoint) + return 0; + + fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr); + if (!fwnode) + return -EPROTO; + + if (port) + *port = fwnode; + + if (!endpoint) + return 0; + + fwnode = acpi_graph_get_child_prop_value(fwnode, "endpoint", + endpoint_nr); + if (!fwnode) + return -EPROTO; + + *endpoint = fwnode; + + return 0; +} diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 192691880d55..c26931067415 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -30,12 +30,6 @@ extern struct acpi_device *acpi_root; #define INVALID_ACPI_HANDLE ((acpi_handle)empty_zero_page) -/* - * If set, devices will be hot-removed even if they cannot be put offline - * gracefully (from the kernel's standpoint). - */ -bool acpi_force_hot_remove; - static const char *dummy_hid = "device"; static LIST_HEAD(acpi_dep_list); @@ -170,9 +164,6 @@ static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data, pn->put_online = false; } ret = device_offline(pn->dev); - if (acpi_force_hot_remove) - continue; - if (ret >= 0) { pn->put_online = !ret; } else { @@ -241,11 +232,11 @@ static int acpi_scan_try_to_offline(struct acpi_device *device) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, NULL, acpi_bus_offline, (void *)true, (void **)&errdev); - if (!errdev || acpi_force_hot_remove) + if (!errdev) acpi_bus_offline(handle, 0, (void *)true, (void **)&errdev); - if (errdev && !acpi_force_hot_remove) { + if (errdev) { dev_warn(errdev, "Offline failed.\n"); acpi_bus_online(handle, 0, NULL, NULL); acpi_walk_namespace(ACPI_TYPE_ANY, handle, @@ -263,8 +254,7 @@ static int acpi_scan_hot_remove(struct acpi_device *device) unsigned long long sta; acpi_status status; - if (device->handler && device->handler->hotplug.demand_offline - && !acpi_force_hot_remove) { + if (device->handler && device->handler->hotplug.demand_offline) { if (!acpi_scan_is_offline(device, true)) return -EBUSY; } else { @@ -1850,6 +1840,8 @@ static void acpi_bus_attach(struct acpi_device *device) device->flags.power_manageable = 0; device->flags.initialized = true; + } else if (device->flags.visited) { + goto ok; } ret = acpi_scan_attach_handler(device); @@ -1857,15 +1849,20 @@ static void acpi_bus_attach(struct acpi_device *device) return; device->flags.match_driver = true; - if (!ret) { - ret = device_attach(&device->dev); - if (ret < 0) - return; - - if (!ret && device->pnp.type.platform_id) - acpi_default_enumeration(device); + if (ret > 0) { + acpi_device_set_enumerated(device); + goto ok; } + ret = device_attach(&device->dev); + if (ret < 0) + return; + + if (device->pnp.type.platform_id) + acpi_default_enumeration(device); + else + acpi_device_set_enumerated(device); + ok: list_for_each_entry(child, &device->children, node) acpi_bus_attach(child); diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 01c94669a2b0..3afa8c1fa127 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -30,7 +30,7 @@ static bool qdf2400_erratum_44_present(struct acpi_table_header *h) return true; if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) && - h->oem_revision == 0) + h->oem_revision == 1) return true; return false; diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index cf05ae973381..1b5ee1e0e5a3 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -921,7 +921,7 @@ void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, static ssize_t force_remove_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", !!acpi_force_hot_remove); + return sprintf(buf, "%d\n", 0); } static ssize_t force_remove_store(struct kobject *kobj, @@ -935,9 +935,10 @@ static ssize_t force_remove_store(struct kobject *kobj, if (ret < 0) return ret; - lock_device_hotplug(); - acpi_force_hot_remove = val; - unlock_device_hotplug(); + if (val) { + pr_err("Enabling force_remove is not supported anymore. Please report to linux-acpi@vger.kernel.org if you depend on this functionality\n"); + return -EINVAL; + } return size; } diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 2604189d6cd1..0dae722ab2ec 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -311,22 +311,6 @@ acpi_parse_entries_array(char *id, unsigned long table_size, } int __init -acpi_parse_entries(char *id, - unsigned long table_size, - acpi_tbl_entry_handler handler, - struct acpi_table_header *table_header, - int entry_id, unsigned int max_entries) -{ - struct acpi_subtable_proc proc = { - .id = entry_id, - .handler = handler, - }; - - return acpi_parse_entries_array(id, table_size, table_header, - &proc, 1, max_entries); -} - -int __init acpi_table_parse_entries_array(char *id, unsigned long table_size, struct acpi_subtable_proc *proc, int proc_num, diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 22c09952e177..27d0dcfcf47d 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -736,6 +736,72 @@ bool acpi_dev_found(const char *hid) } EXPORT_SYMBOL(acpi_dev_found); +struct acpi_dev_present_info { + struct acpi_device_id hid[2]; + const char *uid; + s64 hrv; +}; + +static int acpi_dev_present_cb(struct device *dev, void *data) +{ + struct acpi_device *adev = to_acpi_device(dev); + struct acpi_dev_present_info *match = data; + unsigned long long hrv; + acpi_status status; + + if (acpi_match_device_ids(adev, match->hid)) + return 0; + + if (match->uid && (!adev->pnp.unique_id || + strcmp(adev->pnp.unique_id, match->uid))) + return 0; + + if (match->hrv == -1) + return 1; + + status = acpi_evaluate_integer(adev->handle, "_HRV", NULL, &hrv); + if (ACPI_FAILURE(status)) + return 0; + + return hrv == match->hrv; +} + +/** + * acpi_dev_present - Detect that a given ACPI device is present + * @hid: Hardware ID of the device. + * @uid: Unique ID of the device, pass NULL to not check _UID + * @hrv: Hardware Revision of the device, pass -1 to not check _HRV + * + * Return %true if a matching device was present at the moment of invocation. + * Note that if the device is pluggable, it may since have disappeared. + * + * Note that unlike acpi_dev_found() this function checks the status + * of the device. So for devices which are present in the dsdt, but + * which are disabled (their _STA callback returns 0) this function + * will return false. + * + * For this function to work, acpi_bus_scan() must have been executed + * which happens in the subsys_initcall() subsection. Hence, do not + * call from a subsys_initcall() or earlier (use acpi_get_devices() + * instead). Calling from module_init() is fine (which is synonymous + * with device_initcall()). + */ +bool acpi_dev_present(const char *hid, const char *uid, s64 hrv) +{ + struct acpi_dev_present_info match = {}; + struct device *dev; + + strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); + match.uid = uid; + match.hrv = hrv; + + dev = bus_find_device(&acpi_bus_type, NULL, &match, + acpi_dev_present_cb); + + return !!dev; +} +EXPORT_SYMBOL(acpi_dev_present); + /* * acpi_backlight= handling, this is done here rather then in video_detect.c * because __setup cannot be used in modules. |