diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-06-27 22:26:44 +0200 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-06-27 22:26:44 +0200 |
commit | a976c2951d8f376112361830aa7762beff83a205 (patch) | |
tree | 24f6647aedd4b570cb67f3195962f5c8a040c824 /drivers/acpi | |
parent | 83848fbe7e6af978c080a88c130a67178b1ac0e4 (diff) | |
parent | 16b9951f656ea8f2b47546bd898325a7e256932f (diff) | |
download | linux-a976c2951d8f376112361830aa7762beff83a205.tar.bz2 |
Merge back ACPICA material for v4.13.
Diffstat (limited to 'drivers/acpi')
88 files changed, 3402 insertions, 794 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 83e5f7e1a20d..1ce52f84dc23 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 @@ -440,7 +440,7 @@ config ACPI_CUSTOM_METHOD config ACPI_BGRT bool "Boottime Graphics Resource Table support" - depends on EFI && X86 + depends on EFI && (X86 || ARM64) help This driver adds support for exposing the ACPI Boottime Graphics Resource Table, which allows the operating system to obtain @@ -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,16 +505,22 @@ 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. config BXT_WC_PMIC_OPREGION bool "ACPI operation region support for BXT WhiskeyCove PMIC" - depends on INTEL_SOC_PMIC + depends on INTEL_SOC_PMIC_BXTWC 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 d94f92f88ca1..b1aacfc62b1f 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -50,6 +50,7 @@ acpi-$(CONFIG_ACPI_REDUCED_HARDWARE_ONLY) += evged.o acpi-y += sysfs.o acpi-y += property.o acpi-$(CONFIG_X86) += acpi_cmos_rtc.o +acpi-$(CONFIG_X86) += x86/utils.o acpi-$(CONFIG_DEBUG_FS) += debugfs.o acpi-$(CONFIG_ACPI_NUMA) += numa.o acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o @@ -101,6 +102,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_apd.c b/drivers/acpi/acpi_apd.c index 26696b693e63..fc6c416f8724 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -106,6 +106,16 @@ static const struct apd_device_desc vulcan_spi_desc = { .setup = acpi_apd_setup, .fixed_clk_rate = 133000000, }; + +static const struct apd_device_desc hip07_i2c_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 200000000, +}; + +static const struct apd_device_desc hip08_i2c_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 250000000, +}; #endif #else @@ -169,6 +179,9 @@ static const struct acpi_device_id acpi_apd_device_ids[] = { #ifdef CONFIG_ARM64 { "APMC0D0F", APD_ADDR(xgene_i2c_desc) }, { "BRCM900D", APD_ADDR(vulcan_spi_desc) }, + { "CAV900D", APD_ADDR(vulcan_spi_desc) }, + { "HISI0A21", APD_ADDR(hip07_i2c_desc) }, + { "HISI0A22", APD_ADDR(hip08_i2c_desc) }, #endif { } }; 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_lpss.c b/drivers/acpi/acpi_lpss.c index 5edfd9c49044..10347e3d73ad 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -143,6 +143,22 @@ static void lpss_deassert_reset(struct lpss_private_data *pdata) writel(val, pdata->mmio_base + offset); } +/* + * BYT PWM used for backlight control by the i915 driver on systems without + * the Crystal Cove PMIC. + */ +static struct pwm_lookup byt_pwm_lookup[] = { + PWM_LOOKUP_WITH_MODULE("80860F09:00", 0, "0000:00:02.0", + "pwm_backlight", 0, PWM_POLARITY_NORMAL, + "pwm-lpss-platform"), +}; + +static void byt_pwm_setup(struct lpss_private_data *pdata) +{ + if (!acpi_dev_present("INT33FD", NULL, -1)) + pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup)); +} + #define LPSS_I2C_ENABLE 0x6c static void byt_i2c_setup(struct lpss_private_data *pdata) @@ -200,6 +216,7 @@ static const struct lpss_device_desc lpt_sdio_dev_desc = { static const struct lpss_device_desc byt_pwm_dev_desc = { .flags = LPSS_SAVE_CTX, + .setup = byt_pwm_setup, }; static const struct lpss_device_desc bsw_pwm_dev_desc = { diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 03250e1f1103..88cd949003f3 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -121,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/Makefile b/drivers/acpi/acpica/Makefile index dea65306b687..b125bdd3d58b 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -172,6 +172,7 @@ acpi-y += \ utosi.o \ utownerid.o \ utpredef.o \ + utresdecode.o \ utresrc.o \ utstate.o \ utstring.o \ diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index b65f2731e9e2..bb6a84b0b4b3 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -158,8 +158,8 @@ acpi_dm_finish_namespace_load(union acpi_parse_object *parse_tree_root, acpi_owner_id owner_id); void -acpi_dm_convert_resource_indexes(union acpi_parse_object *parse_tree_root, - struct acpi_namespace_node *namespace_root); +acpi_dm_convert_parse_objects(union acpi_parse_object *parse_tree_root, + struct acpi_namespace_node *namespace_root); /* * adfile diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index abe8c316908c..95eed442703f 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -315,6 +315,7 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_force_aml_disassembly, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_dm_opt_verbose, TRUE); ACPI_INIT_GLOBAL(u8, acpi_gbl_dm_emit_external_opcodes, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_do_disassembler_optimizations, TRUE); +ACPI_INIT_GLOBAL(ACPI_PARSE_OBJECT_LIST, *acpi_gbl_temp_list_head, NULL); ACPI_GLOBAL(u8, acpi_gbl_dm_opt_disasm); ACPI_GLOBAL(u8, acpi_gbl_dm_opt_listing); @@ -368,6 +369,8 @@ ACPI_GLOBAL(const char, *acpi_gbl_pld_vertical_position_list[]); ACPI_GLOBAL(const char, *acpi_gbl_pld_horizontal_position_list[]); ACPI_GLOBAL(const char, *acpi_gbl_pld_shape_list[]); +ACPI_INIT_GLOBAL(u8, acpi_gbl_disasm_flag, FALSE); + #endif /* diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index f9b3f7fef462..8ddd3b20e0c6 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -859,7 +859,7 @@ ACPI_PARSE_COMMON}; * and bytelists. */ struct acpi_parse_obj_named { - ACPI_PARSE_COMMON u8 *path; + ACPI_PARSE_COMMON char *path; u8 *data; /* AML body or bytelist data */ u32 length; /* AML length */ u32 name; /* 4-byte name or zero if no name */ @@ -1142,8 +1142,13 @@ struct acpi_port_info { #define ACPI_RESOURCE_NAME_ADDRESS64 0x8A #define ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 0x8B #define ACPI_RESOURCE_NAME_GPIO 0x8C +#define ACPI_RESOURCE_NAME_PIN_FUNCTION 0x8D #define ACPI_RESOURCE_NAME_SERIAL_BUS 0x8E -#define ACPI_RESOURCE_NAME_LARGE_MAX 0x8E +#define ACPI_RESOURCE_NAME_PIN_CONFIG 0x8F +#define ACPI_RESOURCE_NAME_PIN_GROUP 0x90 +#define ACPI_RESOURCE_NAME_PIN_GROUP_FUNCTION 0x91 +#define ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG 0x92 +#define ACPI_RESOURCE_NAME_LARGE_MAX 0x92 /***************************************************************************** * @@ -1176,12 +1181,18 @@ struct acpi_external_list { #define ACPI_EXT_INTERNAL_PATH_ALLOCATED 0x04 /* Deallocate internal path on completion */ #define ACPI_EXT_EXTERNAL_EMITTED 0x08 /* External() statement has been emitted */ #define ACPI_EXT_ORIGIN_FROM_OPCODE 0x10 /* External came from a External() opcode */ +#define ACPI_EXT_CONFLICTING_DECLARATION 0x20 /* External has a conflicting declaration within AML */ struct acpi_external_file { char *path; struct acpi_external_file *next; }; +struct acpi_parse_object_list { + union acpi_parse_object *op; + struct acpi_parse_object_list *next; +}; + /***************************************************************************** * * Debugger diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index a5d9af758c52..cbd59a302679 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -112,7 +112,7 @@ #define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA) #define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST) #define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME) -#define ARGP_EXTERNAL_OP ARGP_LIST3 (ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_BYTEDATA) +#define ARGP_EXTERNAL_OP ARGP_LIST3 (ARGP_NAME, ARGP_BYTEDATA, ARGP_BYTEDATA) #define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG) #define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST) #define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index dcfc05d40e36..cdfcad8eb74c 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -581,6 +581,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = { {{"_HID", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING)}}, + {{"_HMA", METHOD_0ARGS, + METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, + {{"_HOT", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, @@ -626,6 +629,19 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = { ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER | ACPI_RTYPE_STRING, 10, 0), + {{"_LSI", METHOD_0ARGS, + METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, + PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0, 0, 0), + + {{"_LSR", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, + PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 1, + ACPI_RTYPE_BUFFER, 1, 0), + + {{"_LSW", + METHOD_3ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_BUFFER), + METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, + {{"_MAT", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h index b4d22f6e48e2..438f3098a093 100644 --- a/drivers/acpi/acpica/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h @@ -148,7 +148,10 @@ typedef enum { ACPI_RSD_UINT16, ACPI_RSD_UINT32, ACPI_RSD_UINT64, - ACPI_RSD_WORDLIST + ACPI_RSD_WORDLIST, + ACPI_RSD_LABEL, + ACPI_RSD_SOURCE_LABEL, + } ACPI_RSDUMP_OPCODES; /* restore default alignment */ @@ -329,6 +332,11 @@ extern struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[]; extern struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[]; extern struct acpi_rsconvert_info acpi_rs_convert_spi_serial_bus[]; extern struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[]; +extern struct acpi_rsconvert_info acpi_rs_convert_pin_function[]; +extern struct acpi_rsconvert_info acpi_rs_convert_pin_config[]; +extern struct acpi_rsconvert_info acpi_rs_convert_pin_group[]; +extern struct acpi_rsconvert_info acpi_rs_convert_pin_group_function[]; +extern struct acpi_rsconvert_info acpi_rs_convert_pin_group_config[]; /* These resources require separate get/set tables */ @@ -372,12 +380,17 @@ extern struct acpi_rsdump_info acpi_rs_dump_ext_address64[]; extern struct acpi_rsdump_info acpi_rs_dump_ext_irq[]; extern struct acpi_rsdump_info acpi_rs_dump_generic_reg[]; extern struct acpi_rsdump_info acpi_rs_dump_gpio[]; +extern struct acpi_rsdump_info acpi_rs_dump_pin_function[]; extern struct acpi_rsdump_info acpi_rs_dump_fixed_dma[]; extern struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[]; extern struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[]; extern struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[]; extern struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[]; extern struct acpi_rsdump_info acpi_rs_dump_general_flags[]; +extern struct acpi_rsdump_info acpi_rs_dump_pin_config[]; +extern struct acpi_rsdump_info acpi_rs_dump_pin_group[]; +extern struct acpi_rsdump_info acpi_rs_dump_pin_group_function[]; +extern struct acpi_rsdump_info acpi_rs_dump_pin_group_config[]; #endif #endif /* __ACRESRC_H__ */ diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 6f28cfae2212..2a3cc4296481 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -85,6 +85,7 @@ extern const char *acpi_gbl_bpb_decode[]; extern const char *acpi_gbl_sb_decode[]; extern const char *acpi_gbl_fc_decode[]; extern const char *acpi_gbl_pt_decode[]; +extern const char *acpi_gbl_ptyp_decode[]; #endif /* diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 176f7e9b4d0e..f54dc5a34bdc 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -313,6 +313,11 @@ * #A is the number of required arguments * #T is the number of target operands * #R indicates whether there is a return value + * + * These types are used for the top-level dispatch of the AML + * opcode. They group similar operators that can share common + * front-end code before dispatch to the final code that implements + * the operator. */ /* @@ -353,42 +358,42 @@ * The opcode Type is used in a dispatch table, do not change * or add anything new without updating the table. */ -#define AML_TYPE_EXEC_0A_0T_1R 0x00 -#define AML_TYPE_EXEC_1A_0T_0R 0x01 /* Monadic1 */ -#define AML_TYPE_EXEC_1A_0T_1R 0x02 /* Monadic2 */ -#define AML_TYPE_EXEC_1A_1T_0R 0x03 -#define AML_TYPE_EXEC_1A_1T_1R 0x04 /* monadic2_r */ -#define AML_TYPE_EXEC_2A_0T_0R 0x05 /* Dyadic1 */ -#define AML_TYPE_EXEC_2A_0T_1R 0x06 /* Dyadic2 */ -#define AML_TYPE_EXEC_2A_1T_1R 0x07 /* dyadic2_r */ -#define AML_TYPE_EXEC_2A_2T_1R 0x08 -#define AML_TYPE_EXEC_3A_0T_0R 0x09 -#define AML_TYPE_EXEC_3A_1T_1R 0x0A -#define AML_TYPE_EXEC_6A_0T_1R 0x0B +#define AML_TYPE_EXEC_0A_0T_1R 0x00 /* 0 Args, 0 Target, 1 ret_val */ +#define AML_TYPE_EXEC_1A_0T_0R 0x01 /* 1 Args, 0 Target, 0 ret_val */ +#define AML_TYPE_EXEC_1A_0T_1R 0x02 /* 1 Args, 0 Target, 1 ret_val */ +#define AML_TYPE_EXEC_1A_1T_0R 0x03 /* 1 Args, 1 Target, 0 ret_val */ +#define AML_TYPE_EXEC_1A_1T_1R 0x04 /* 1 Args, 1 Target, 1 ret_val */ +#define AML_TYPE_EXEC_2A_0T_0R 0x05 /* 2 Args, 0 Target, 0 ret_val */ +#define AML_TYPE_EXEC_2A_0T_1R 0x06 /* 2 Args, 0 Target, 1 ret_val */ +#define AML_TYPE_EXEC_2A_1T_1R 0x07 /* 2 Args, 1 Target, 1 ret_val */ +#define AML_TYPE_EXEC_2A_2T_1R 0x08 /* 2 Args, 2 Target, 1 ret_val */ +#define AML_TYPE_EXEC_3A_0T_0R 0x09 /* 3 Args, 0 Target, 0 ret_val */ +#define AML_TYPE_EXEC_3A_1T_1R 0x0A /* 3 Args, 1 Target, 1 ret_val */ +#define AML_TYPE_EXEC_6A_0T_1R 0x0B /* 6 Args, 0 Target, 1 ret_val */ /* End of types used in dispatch table */ -#define AML_TYPE_LITERAL 0x0B -#define AML_TYPE_CONSTANT 0x0C -#define AML_TYPE_METHOD_ARGUMENT 0x0D -#define AML_TYPE_LOCAL_VARIABLE 0x0E -#define AML_TYPE_DATA_TERM 0x0F +#define AML_TYPE_LITERAL 0x0C +#define AML_TYPE_CONSTANT 0x0D +#define AML_TYPE_METHOD_ARGUMENT 0x0E +#define AML_TYPE_LOCAL_VARIABLE 0x0F +#define AML_TYPE_DATA_TERM 0x10 /* Generic for an op that returns a value */ -#define AML_TYPE_METHOD_CALL 0x10 +#define AML_TYPE_METHOD_CALL 0x11 /* Miscellaneous types */ -#define AML_TYPE_CREATE_FIELD 0x11 -#define AML_TYPE_CREATE_OBJECT 0x12 -#define AML_TYPE_CONTROL 0x13 -#define AML_TYPE_NAMED_NO_OBJ 0x14 -#define AML_TYPE_NAMED_FIELD 0x15 -#define AML_TYPE_NAMED_SIMPLE 0x16 -#define AML_TYPE_NAMED_COMPLEX 0x17 -#define AML_TYPE_RETURN 0x18 -#define AML_TYPE_UNDEFINED 0x19 -#define AML_TYPE_BOGUS 0x1A +#define AML_TYPE_CREATE_FIELD 0x12 +#define AML_TYPE_CREATE_OBJECT 0x13 +#define AML_TYPE_CONTROL 0x14 +#define AML_TYPE_NAMED_NO_OBJ 0x15 +#define AML_TYPE_NAMED_FIELD 0x16 +#define AML_TYPE_NAMED_SIMPLE 0x17 +#define AML_TYPE_NAMED_COMPLEX 0x18 +#define AML_TYPE_RETURN 0x19 +#define AML_TYPE_UNDEFINED 0x1A +#define AML_TYPE_BOGUS 0x1B /* AML Package Length encodings */ diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index 653a3d1ef5d5..1236e9a414e4 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -65,6 +65,7 @@ #define ACPI_RESTAG_DRIVESTRENGTH "_DRS" #define ACPI_RESTAG_ENDIANNESS "_END" #define ACPI_RESTAG_FLOWCONTROL "_FLC" +#define ACPI_RESTAG_FUNCTION "_FUN" #define ACPI_RESTAG_GRANULARITY "_GRA" #define ACPI_RESTAG_INTERRUPT "_INT" #define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* active_lo(1), active_hi(0) */ @@ -84,6 +85,8 @@ #define ACPI_RESTAG_PHASE "_PHA" #define ACPI_RESTAG_PIN "_PIN" #define ACPI_RESTAG_PINCONFIG "_PPI" +#define ACPI_RESTAG_PINCONFIG_TYPE "_TYP" +#define ACPI_RESTAG_PINCONFIG_VALUE "_VAL" #define ACPI_RESTAG_POLARITY "_POL" #define ACPI_RESTAG_REGISTERBITOFFSET "_RBO" #define ACPI_RESTAG_REGISTERBITWIDTH "_RBW" @@ -404,6 +407,102 @@ struct aml_resource_uart_serialbus { #define AML_RESOURCE_UART_TYPE_REVISION 1 /* ACPI 5.0 */ #define AML_RESOURCE_UART_MIN_DATA_LEN 10 +struct aml_resource_pin_function { + AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; + u16 flags; + u8 pin_config; + u16 function_number; + u16 pin_table_offset; + u8 res_source_index; + u16 res_source_offset; + u16 vendor_offset; + u16 vendor_length; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Source String + * 3) Vendor Data bytes + */ +}; + +#define AML_RESOURCE_PIN_FUNCTION_REVISION 1 /* ACPI 6.2 */ + +struct aml_resource_pin_config { + AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; + u16 flags; + u8 pin_config_type; + u32 pin_config_value; + u16 pin_table_offset; + u8 res_source_index; + u16 res_source_offset; + u16 vendor_offset; + u16 vendor_length; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Source String + * 3) Vendor Data bytes + */ +}; + +#define AML_RESOURCE_PIN_CONFIG_REVISION 1 /* ACPI 6.2 */ + +struct aml_resource_pin_group { + AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; + u16 flags; + u16 pin_table_offset; + u16 label_offset; + u16 vendor_offset; + u16 vendor_length; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Label String + * 3) Vendor Data bytes + */ +}; + +#define AML_RESOURCE_PIN_GROUP_REVISION 1 /* ACPI 6.2 */ + +struct aml_resource_pin_group_function { + AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; + u16 flags; + u16 function_number; + u8 res_source_index; + u16 res_source_offset; + u16 res_source_label_offset; + u16 vendor_offset; + u16 vendor_length; + /* + * Optional fields follow immediately: + * 1) Resource Source String + * 2) Resource Source Label String + * 3) Vendor Data bytes + */ +}; + +#define AML_RESOURCE_PIN_GROUP_FUNCTION_REVISION 1 /* ACPI 6.2 */ + +struct aml_resource_pin_group_config { + AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; + u16 flags; + u8 pin_config_type; + u32 pin_config_value; + u8 res_source_index; + u16 res_source_offset; + u16 res_source_label_offset; + u16 vendor_offset; + u16 vendor_length; + /* + * Optional fields follow immediately: + * 1) Resource Source String + * 2) Resource Source Label String + * 3) Vendor Data bytes + */ +}; + +#define AML_RESOURCE_PIN_GROUP_CONFIG_REVISION 1 /* ACPI 6.2 */ + /* restore default alignment */ #pragma pack() @@ -446,6 +545,11 @@ union aml_resource { struct aml_resource_spi_serialbus spi_serial_bus; struct aml_resource_uart_serialbus uart_serial_bus; struct aml_resource_common_serialbus common_serial_bus; + struct aml_resource_pin_function pin_function; + struct aml_resource_pin_config pin_config; + struct aml_resource_pin_group pin_group; + struct aml_resource_pin_group_function pin_group_function; + struct aml_resource_pin_group_config pin_group_config; /* Utility overlays */ diff --git a/drivers/acpi/acpica/dbexec.c b/drivers/acpi/acpica/dbexec.c index b611cd92b5f5..3b30319752f0 100644 --- a/drivers/acpi/acpica/dbexec.c +++ b/drivers/acpi/acpica/dbexec.c @@ -181,6 +181,18 @@ acpi_db_execute_method(struct acpi_db_method_info *info, acpi_gbl_method_executing = FALSE; if (ACPI_FAILURE(status)) { + if ((status == AE_ABORT_METHOD) || acpi_gbl_abort_method) { + + /* Clear the abort and fall back to the debugger prompt */ + + ACPI_EXCEPTION((AE_INFO, status, + "Aborting top-level method")); + + acpi_gbl_abort_method = FALSE; + status = AE_OK; + goto cleanup; + } + ACPI_EXCEPTION((AE_INFO, status, "while executing %s from debugger", info->pathname)); diff --git a/drivers/acpi/acpica/dbobject.c b/drivers/acpi/acpica/dbobject.c index f2252b1ac0b3..e7b415c20aa8 100644 --- a/drivers/acpi/acpica/dbobject.c +++ b/drivers/acpi/acpica/dbobject.c @@ -448,7 +448,7 @@ void acpi_db_decode_locals(struct acpi_walk_state *walk_state) if (display_locals) { acpi_os_printf - ("\nInitialized Local Variables for method [%4.4s]:\n", + ("\nInitialized Local Variables for Method [%4.4s]:\n", acpi_ut_get_node_name(node)); for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) { @@ -461,7 +461,7 @@ void acpi_db_decode_locals(struct acpi_walk_state *walk_state) } } else { acpi_os_printf - ("No Local Variables are initialized for method [%4.4s]\n", + ("No Local Variables are initialized for Method [%4.4s]\n", acpi_ut_get_node_name(node)); } } @@ -515,7 +515,7 @@ void acpi_db_decode_arguments(struct acpi_walk_state *walk_state) acpi_os_printf("Initialized Arguments for Method [%4.4s]: " "(%X arguments defined for method invocation)\n", acpi_ut_get_node_name(node), - obj_desc->method.param_count); + node->object->method.param_count); for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) { obj_desc = walk_state->arguments[i].object; diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c index 8f665d94b8b5..b6985323e7eb 100644 --- a/drivers/acpi/acpica/dbxface.c +++ b/drivers/acpi/acpica/dbxface.c @@ -244,7 +244,7 @@ acpi_db_single_step(struct acpi_walk_state *walk_state, if ((acpi_gbl_db_output_to_file) || (acpi_dbg_level & ACPI_LV_PARSE)) { acpi_os_printf - ("\n[AmlDebug] Next AML Opcode to execute:\n"); + ("\nAML Debug: Next AML Opcode to execute:\n"); } /* diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index 287b3fd73cfc..2873455c986d 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -82,7 +82,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node, union acpi_parse_object *op; struct acpi_walk_state *walk_state; - ACPI_FUNCTION_TRACE(ds_execute_arguments); + ACPI_FUNCTION_TRACE_PTR(ds_execute_arguments, aml_start); /* Allocate a new parser op to be the root of the parsed tree */ @@ -338,7 +338,8 @@ acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc) return_ACPI_STATUS(AE_AML_INTERNAL); } - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Package Arg Init\n")); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Package Argument Init, AML Ptr: %p\n", + obj_desc->package.aml_start)); /* Execute the AML code for the term_arg arguments */ diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index 4d885eb8eda9..d1f457eda980 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -196,6 +196,7 @@ acpi_ds_dump_method_stack(acpi_status status, op->common.next = NULL; #ifdef ACPI_DISASSEMBLER + acpi_os_printf("Failed at "); acpi_dm_disassemble(next_walk_state, op, ACPI_UINT32_MAX); #endif diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 31c9c7aec3d5..d7fc36917c67 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -212,6 +212,7 @@ acpi_status acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state) { u32 aml_offset; + acpi_name name = 0; ACPI_FUNCTION_ENTRY(); @@ -237,10 +238,13 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state) walk_state->parser_state. aml_start); - status = acpi_gbl_exception_handler(status, - walk_state->method_node ? - walk_state->method_node-> - name.integer : 0, + if (walk_state->method_node) { + name = walk_state->method_node->name.integer; + } else if (walk_state->deferred_node) { + name = walk_state->deferred_node->name.integer; + } + + status = acpi_gbl_exception_handler(status, name, walk_state->opcode, aml_offset, NULL); acpi_ex_enter_interpreter(); diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 9a8f8a992b3e..dfc3c25a083d 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -227,13 +227,12 @@ acpi_ds_init_buffer_field(u16 aml_opcode, /* Entire field must fit within the current length of the buffer */ - if ((bit_offset + bit_count) > (8 * (u32) buffer_desc->buffer.length)) { + if ((bit_offset + bit_count) > (8 * (u32)buffer_desc->buffer.length)) { ACPI_ERROR((AE_INFO, - "Field [%4.4s] at %u exceeds Buffer [%4.4s] size %u (bits)", - acpi_ut_get_node_name(result_desc), - bit_offset + bit_count, - acpi_ut_get_node_name(buffer_desc->buffer.node), - 8 * (u32) buffer_desc->buffer.length)); + "Field [%4.4s] at bit offset/length %u/%u " + "exceeds size of target Buffer (%u bits)", + acpi_ut_get_node_name(result_desc), bit_offset, + bit_count, 8 * (u32)buffer_desc->buffer.length)); status = AE_AML_BUFFER_LIMIT; goto cleanup; } diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 406edec20de7..0dabd9b95684 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -633,15 +633,6 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, if ((op_info->flags & AML_HAS_RETVAL) || (arg->common.flags & ACPI_PARSEOP_IN_STACK)) { - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Argument previously created, already stacked\n")); - - acpi_db_display_argument_object(walk_state-> - operands[walk_state-> - num_operands - - 1], - walk_state); - /* * Use value that was already previously returned * by the evaluation of this argument diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index a2ff8ad70d58..20d7744b06ae 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -576,8 +576,8 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) case AML_TYPE_CREATE_OBJECT: ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Executing CreateObject (Buffer/Package) Op=%p\n", - op)); + "Executing CreateObject (Buffer/Package) Op=%p AMLPtr=%p\n", + op, op->named.data)); switch (op->common.parent->common.aml_opcode) { case AML_NAME_OP: diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index cafb3ab567ab..eaa859a89702 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -397,7 +397,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state, /* Initialize the op */ #if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)) - op->named.path = ACPI_CAST_PTR(u8, path); + op->named.path = path; #endif if (node) { @@ -434,6 +434,10 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) acpi_object_type object_type; acpi_status status = AE_OK; +#ifdef ACPI_ASL_COMPILER + u8 param_count; +#endif + ACPI_FUNCTION_TRACE(ds_load1_end_op); op = walk_state->op; @@ -514,6 +518,38 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) } } } +#ifdef ACPI_ASL_COMPILER + /* + * For external opcode, get the object type from the argument and + * get the parameter count from the argument's next. + */ + if (acpi_gbl_disasm_flag && + op->common.node && op->common.aml_opcode == AML_EXTERNAL_OP) { + /* + * Note, if this external is not a method + * Op->Common.Value.Arg->Common.Next->Common.Value.Integer == 0 + * Therefore, param_count will be 0. + */ + param_count = + (u8)op->common.value.arg->common.next->common.value.integer; + object_type = (u8)op->common.value.arg->common.value.integer; + op->common.node->flags |= ANOBJ_IS_EXTERNAL; + op->common.node->type = (u8)object_type; + + acpi_dm_create_subobject_for_external((u8)object_type, + &op->common.node, + param_count); + + /* + * Add the external to the external list because we may be + * emitting code based off of the items within the external list. + */ + acpi_dm_add_op_to_external_list(op, op->named.path, + (u8)object_type, param_count, + ACPI_EXT_ORIGIN_FROM_OPCODE | + ACPI_EXT_RESOLVED_REFERENCE); + } +#endif /* * If we are executing a method, do not create any namespace objects @@ -563,7 +599,9 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) /* Pop the scope stack (only if loading a table) */ - if (!walk_state->method_node && acpi_ns_opens_scope(object_type)) { + if (!walk_state->method_node && + op->common.aml_opcode != AML_EXTERNAL_OP && + acpi_ns_opens_scope(object_type)) { ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "(%s): Popping scope for Op %p\n", acpi_ut_get_type_name(object_type), op)); diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index 8d510c7e20c8..aad83ef5a4ec 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -310,6 +310,22 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, flags |= ACPI_NS_TEMPORARY; } } +#ifdef ACPI_ASL_COMPILER + + /* + * Do not open a scope for AML_EXTERNAL_OP + * acpi_ns_lookup can open a new scope based on the object type + * of this op. AML_EXTERNAL_OP is a declaration rather than a + * definition. In the case that this external is a method object, + * acpi_ns_lookup will open a new scope. However, an AML_EXTERNAL_OP + * associated with the ACPI_TYPE_METHOD is a declaration, rather than + * a definition. Flags is set to avoid opening a scope for any + * AML_EXTERNAL_OP. + */ + if (walk_state->opcode == AML_EXTERNAL_OP) { + flags |= ACPI_NS_DONT_OPEN_SCOPE; + } +#endif /* Add new entry or lookup existing entry */ diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 82e8971f23a4..c773ac4892cb 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -180,6 +180,12 @@ acpi_status acpi_enable_event(u32 event, u32 flags) ACPI_FUNCTION_TRACE(acpi_enable_event); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Decode the Fixed Event */ if (event > ACPI_EVENT_MAX) { @@ -237,6 +243,12 @@ acpi_status acpi_disable_event(u32 event, u32 flags) ACPI_FUNCTION_TRACE(acpi_disable_event); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Decode the Fixed Event */ if (event > ACPI_EVENT_MAX) { @@ -290,6 +302,12 @@ acpi_status acpi_clear_event(u32 event) ACPI_FUNCTION_TRACE(acpi_clear_event); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Decode the Fixed Event */ if (event > ACPI_EVENT_MAX) { diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index ec614f5a3bcb..a8191d2ca5e3 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -117,10 +117,10 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, timer = ((u32)acpi_os_get_timer() / 10); timer &= 0x03FFFFFF; - acpi_os_printf("[ACPI Debug T=0x%8.8X] %*s", timer, + acpi_os_printf("ACPI Debug: T=0x%8.8X %*s", timer, level, " "); } else { - acpi_os_printf("[ACPI Debug] %*s", level, " "); + acpi_os_printf("ACPI Debug: %*s", level, " "); } } diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 970dc6c53994..44092f744477 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -645,10 +645,12 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) /* obj_desc is a valid object */ if (depth > 0) { - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%*s[%u] %p ", - depth, " ", depth, obj_desc)); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%*s[%u] %p Refs=%u ", + depth, " ", depth, obj_desc, + obj_desc->common.reference_count)); } else { - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%p ", obj_desc)); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%p Refs=%u ", + obj_desc, obj_desc->common.reference_count)); } /* Decode object type */ @@ -690,8 +692,11 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) case ACPI_REFCLASS_NAME: - acpi_os_printf("- [%4.4s]\n", - obj_desc->reference.node->name.ascii); + acpi_ut_repair_name(obj_desc->reference.node->name. + ascii); + acpi_os_printf("- [%4.4s] (Node %p)\n", + obj_desc->reference.node->name.ascii, + obj_desc->reference.node); break; case ACPI_REFCLASS_ARG: @@ -999,9 +1004,15 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc) status = acpi_ns_handle_to_pathname(obj_desc->reference.node, &ret_buf, TRUE); if (ACPI_FAILURE(status)) { - acpi_os_printf(" Could not convert name to pathname\n"); + acpi_os_printf + (" Could not convert name to pathname: %s\n", + acpi_format_exception(status)); } else { - acpi_os_printf("%s\n", (char *)ret_buf.pointer); + acpi_os_printf("%s: %s\n", + acpi_ut_get_type_name(obj_desc-> + reference.node-> + type), + (char *)ret_buf.pointer); ACPI_FREE(ret_buf.pointer); } } else if (obj_desc->reference.object) { @@ -1111,9 +1122,8 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc, case ACPI_TYPE_LOCAL_REFERENCE: - acpi_os_printf("[Object Reference] Type [%s] %2.2X", - acpi_ut_get_reference_name(obj_desc), - obj_desc->reference.class); + acpi_os_printf("[Object Reference] Class [%s]", + acpi_ut_get_reference_name(obj_desc)); acpi_ex_dump_reference_obj(obj_desc); break; diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index e327349675cd..f787651348c1 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -921,13 +921,26 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) * This is a deref_of (object_reference) * Get the actual object from the Node (This is the dereference). * This case may only happen when a local_x or arg_x is - * dereferenced above. + * dereferenced above, or for references to device and + * thermal objects. */ - return_desc = acpi_ns_get_attached_object((struct - acpi_namespace_node - *) - operand[0]); - acpi_ut_add_reference(return_desc); + switch (((struct acpi_namespace_node *)operand[0])-> + type) { + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_THERMAL: + + /* These types have no node subobject, return the NS node */ + + return_desc = operand[0]; + break; + + default: + /* For most types, get the object attached to the node */ + + return_desc = acpi_ns_get_attached_object((struct acpi_namespace_node *)operand[0]); + acpi_ut_add_reference(return_desc); + break; + } } else { /* * This must be a reference object produced by either the diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index aa8c6fd74cc3..5e1854ea85f6 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -368,11 +368,24 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, *)obj_desc); } - if (!obj_desc) { - ACPI_ERROR((AE_INFO, - "[%4.4s] Node is unresolved or uninitialized", - acpi_ut_get_node_name(node))); - return_ACPI_STATUS(AE_AML_UNINITIALIZED_NODE); + switch (type) { + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_THERMAL: + + /* These types have no attached subobject */ + break; + + default: + + /* All other types require a subobject */ + + if (!obj_desc) { + ACPI_ERROR((AE_INFO, + "[%4.4s] Node is unresolved or uninitialized", + acpi_ut_get_node_name(node))); + return_ACPI_STATUS(AE_AML_UNINITIALIZED_NODE); + } + break; } break; diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index fb265b5737de..e5f4fa496572 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -47,6 +47,10 @@ #include "acnamesp.h" #include "acdispat.h" +#ifdef ACPI_ASL_COMPILER +#include "acdisasm.h" +#endif + #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsaccess") @@ -580,6 +584,29 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, (char *)¤t_node->name, current_node)); } +#ifdef ACPI_ASL_COMPILER + /* + * If this ACPI name already exists within the namespace as an + * external declaration, then mark the external as a conflicting + * declaration and proceed to process the current node as if it did + * not exist in the namespace. If this node is not processed as + * normal, then it could cause improper namespace resolution + * by failing to open a new scope. + */ + if (acpi_gbl_disasm_flag && + (status == AE_ALREADY_EXISTS) && + ((this_node->flags & ANOBJ_IS_EXTERNAL) || + (walk_state + && walk_state->opcode == AML_EXTERNAL_OP))) { + this_node->flags &= ~ANOBJ_IS_EXTERNAL; + this_node->type = (u8)this_search_type; + if (walk_state->opcode != AML_EXTERNAL_OP) { + acpi_dm_mark_external_conflict + (this_node); + } + break; + } +#endif *return_node = this_node; return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index 3db9ca25a620..aa16aeaa8937 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -190,9 +190,6 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, (void)acpi_ns_build_normalized_path(node, buffer->pointer, required_size, no_trailing); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%X]\n", (char *)buffer->pointer, (u32) required_size)); diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 2fe87d0dd9d5..b43fe5fce64b 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -89,7 +89,7 @@ acpi_ns_print_node_pathname(struct acpi_namespace_node *node, acpi_os_printf("%s ", message); } - acpi_os_printf("[%s] (Node %p)", (char *)buffer.pointer, node); + acpi_os_printf("%s", (char *)buffer.pointer); ACPI_FREE(buffer.pointer); } } diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index c944ff5c9c3d..538c61677c10 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -85,6 +85,8 @@ acpi_evaluate_object_typed(acpi_handle handle, { acpi_status status; u8 free_buffer_on_error = FALSE; + acpi_handle target_handle; + char *full_pathname; ACPI_FUNCTION_TRACE(acpi_evaluate_object_typed); @@ -98,38 +100,51 @@ acpi_evaluate_object_typed(acpi_handle handle, free_buffer_on_error = TRUE; } + status = acpi_get_handle(handle, pathname, &target_handle); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + full_pathname = acpi_ns_get_external_pathname(target_handle); + if (!full_pathname) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + /* Evaluate the object */ - status = acpi_evaluate_object(handle, pathname, - external_params, return_buffer); + status = acpi_evaluate_object(target_handle, NULL, external_params, + return_buffer); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto exit; } - /* Type ANY means "don't care" */ + /* Type ANY means "don't care about return value type" */ if (return_type == ACPI_TYPE_ANY) { - return_ACPI_STATUS(AE_OK); + goto exit; } if (return_buffer->length == 0) { /* Error because caller specifically asked for a return value */ - ACPI_ERROR((AE_INFO, "No return value")); - return_ACPI_STATUS(AE_NULL_OBJECT); + ACPI_ERROR((AE_INFO, "%s did not return any object", + full_pathname)); + status = AE_NULL_OBJECT; + goto exit; } /* Examine the object type returned from evaluate_object */ if (((union acpi_object *)return_buffer->pointer)->type == return_type) { - return_ACPI_STATUS(AE_OK); + goto exit; } /* Return object type does not match requested type */ ACPI_ERROR((AE_INFO, - "Incorrect return type [%s] requested [%s]", + "Incorrect return type from %s - received [%s], requested [%s]", + full_pathname, acpi_ut_get_type_name(((union acpi_object *)return_buffer-> pointer)->type), acpi_ut_get_type_name(return_type))); @@ -147,7 +162,11 @@ acpi_evaluate_object_typed(acpi_handle handle, } return_buffer->length = 0; - return_ACPI_STATUS(AE_TYPE); + status = AE_TYPE; + +exit: + ACPI_FREE(full_pathname); + return_ACPI_STATUS(status); } ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed) diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index 5bcb61831706..ef6384e374fc 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -122,6 +122,9 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) (u32)(aml_offset + sizeof(struct acpi_table_header))); + ACPI_ERROR((AE_INFO, + "Aborting disassembly, AML byte code is corrupt")); + /* Dump the context surrounding the invalid opcode */ acpi_ut_dump_buffer(((u8 *)walk_state->parser_state. @@ -130,6 +133,14 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) sizeof(struct acpi_table_header) - 16)); acpi_os_printf(" */\n"); + + /* + * Just abort the disassembly, cannot continue because the + * parser is essentially lost. The disassembler can then + * randomly fail because an ill-constructed parse tree + * can result. + */ + return_ACPI_STATUS(AE_AML_BAD_OPCODE); #endif } @@ -331,6 +342,9 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, if (status == AE_CTRL_PARSE_CONTINUE) { return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); } + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } /* Create Op structure and append to parent's argument list */ diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index c343a0d5a3d2..a402ad772a1e 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -650,9 +650,11 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /* ACPI 6.0 opcodes */ - /* 81 */ ACPI_OP("External", ARGP_EXTERNAL_OP, ARGI_EXTERNAL_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, /* ? */ - AML_TYPE_EXEC_3A_0T_0R, AML_FLAGS_EXEC_3A_0T_0R), +/* 81 */ ACPI_OP("External", ARGP_EXTERNAL_OP, ARGI_EXTERNAL_OP, + ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_SIMPLE, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 82 */ ACPI_OP("Comment", ARGP_COMMENT_OP, ARGI_COMMENT_OP, ACPI_TYPE_STRING, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT) diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 8116a670de39..ac88319dc111 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -56,6 +56,7 @@ #include "acdispat.h" #include "amlcode.h" #include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psparse") @@ -538,9 +539,16 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) /* Either the method parse or actual execution failed */ acpi_ex_exit_interpreter(); - ACPI_ERROR_METHOD("Method parse/execution failed", - walk_state->method_node, NULL, - status); + if (status == AE_ABORT_METHOD) { + acpi_ns_print_node_pathname(walk_state-> + method_node, + "Method aborted:"); + acpi_os_printf("\n"); + } else { + ACPI_ERROR_METHOD + ("Method parse/execution failed", + walk_state->method_node, NULL, status); + } acpi_ex_enter_interpreter(); /* Check for possible multi-thread reentrancy problem */ diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 74e47f829ccb..659fb718504a 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -340,6 +340,22 @@ acpi_rs_get_aml_length(struct acpi_resource *resource, break; + case ACPI_RESOURCE_TYPE_PIN_FUNCTION: + + total_size = (acpi_rs_length)(total_size + + (resource->data. + pin_function. + pin_table_length * 2) + + resource->data. + pin_function. + resource_source. + string_length + + resource->data. + pin_function. + vendor_length); + + break; + case ACPI_RESOURCE_TYPE_SERIAL_BUS: total_size = @@ -359,6 +375,67 @@ acpi_rs_get_aml_length(struct acpi_resource *resource, break; + case ACPI_RESOURCE_TYPE_PIN_CONFIG: + + total_size = (acpi_rs_length)(total_size + + (resource->data. + pin_config. + pin_table_length * 2) + + resource->data.pin_config. + resource_source. + string_length + + resource->data.pin_config. + vendor_length); + + break; + + case ACPI_RESOURCE_TYPE_PIN_GROUP: + + total_size = (acpi_rs_length)(total_size + + (resource->data.pin_group. + pin_table_length * 2) + + resource->data.pin_group. + resource_label. + string_length + + resource->data.pin_group. + vendor_length); + + break; + + case ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION: + + total_size = (acpi_rs_length)(total_size + + resource->data. + pin_group_function. + resource_source. + string_length + + resource->data. + pin_group_function. + resource_source_label. + string_length + + resource->data. + pin_group_function. + vendor_length); + + break; + + case ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG: + + total_size = (acpi_rs_length)(total_size + + resource->data. + pin_group_config. + resource_source. + string_length + + resource->data. + pin_group_config. + resource_source_label. + string_length + + resource->data. + pin_group_config. + vendor_length); + + break; + default: break; @@ -537,6 +614,24 @@ acpi_rs_get_list_length(u8 *aml_buffer, } break; + case ACPI_RESOURCE_NAME_PIN_FUNCTION: + + /* Vendor data is optional */ + + if (aml_resource->pin_function.vendor_length) { + extra_struct_bytes += + aml_resource->pin_function.vendor_offset - + aml_resource->pin_function. + pin_table_offset + + aml_resource->pin_function.vendor_length; + } else { + extra_struct_bytes += + aml_resource->large_header.resource_length + + sizeof(struct aml_resource_large_header) - + aml_resource->pin_function.pin_table_offset; + } + break; + case ACPI_RESOURCE_NAME_SERIAL_BUS: minimum_aml_resource_length = @@ -547,6 +642,50 @@ acpi_rs_get_list_length(u8 *aml_buffer, minimum_aml_resource_length; break; + case ACPI_RESOURCE_NAME_PIN_CONFIG: + + /* Vendor data is optional */ + + if (aml_resource->pin_config.vendor_length) { + extra_struct_bytes += + aml_resource->pin_config.vendor_offset - + aml_resource->pin_config.pin_table_offset + + aml_resource->pin_config.vendor_length; + } else { + extra_struct_bytes += + aml_resource->large_header.resource_length + + sizeof(struct aml_resource_large_header) - + aml_resource->pin_config.pin_table_offset; + } + break; + + case ACPI_RESOURCE_NAME_PIN_GROUP: + + extra_struct_bytes += + aml_resource->pin_group.vendor_offset - + aml_resource->pin_group.pin_table_offset + + aml_resource->pin_group.vendor_length; + + break; + + case ACPI_RESOURCE_NAME_PIN_GROUP_FUNCTION: + + extra_struct_bytes += + aml_resource->pin_group_function.vendor_offset - + aml_resource->pin_group_function.res_source_offset + + aml_resource->pin_group_function.vendor_length; + + break; + + case ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG: + + extra_struct_bytes += + aml_resource->pin_group_config.vendor_offset - + aml_resource->pin_group_config.res_source_offset + + aml_resource->pin_group_config.vendor_length; + + break; + default: break; diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index f4cdf8d832dc..55fd1880efbe 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -75,6 +75,10 @@ static void acpi_rs_dump_short_byte_list(u8 length, u8 *data); static void acpi_rs_dump_resource_source(struct acpi_resource_source *resource_source); +static void +acpi_rs_dump_resource_label(char *title, + struct acpi_resource_label *resource_label); + static void acpi_rs_dump_address_common(union acpi_resource_data *resource); static void @@ -371,6 +375,26 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) target)); break; + case ACPI_RSD_LABEL: + /* + * resource_label + */ + acpi_rs_dump_resource_label("Resource Label", + ACPI_CAST_PTR(struct + acpi_resource_label, + target)); + break; + + case ACPI_RSD_SOURCE_LABEL: + /* + * resource_source_label + */ + acpi_rs_dump_resource_label("Resource Source Label", + ACPI_CAST_PTR(struct + acpi_resource_label, + target)); + break; + default: acpi_os_printf("**** Invalid table opcode [%X] ****\n", @@ -414,6 +438,30 @@ acpi_rs_dump_resource_source(struct acpi_resource_source *resource_source) /******************************************************************************* * + * FUNCTION: acpi_rs_dump_resource_label + * + * PARAMETERS: title - Title of the dumped resource field + * resource_label - Pointer to a Resource Label struct + * + * RETURN: None + * + * DESCRIPTION: Common routine for dumping the resource_label + * + ******************************************************************************/ + +static void +acpi_rs_dump_resource_label(char *title, + struct acpi_resource_label *resource_label) +{ + ACPI_FUNCTION_ENTRY(); + + acpi_rs_out_string(title, + resource_label->string_ptr ? + resource_label->string_ptr : "[Not Specified]"); +} + +/******************************************************************************* + * * FUNCTION: acpi_rs_dump_address_common * * PARAMETERS: resource - Pointer to an internal resource descriptor diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c index 8aacd28293fa..da150e17795b 100644 --- a/drivers/acpi/acpica/rsdumpinfo.c +++ b/drivers/acpi/acpica/rsdumpinfo.c @@ -314,6 +314,120 @@ struct acpi_rsdump_info acpi_rs_dump_gpio[16] = { NULL}, }; +struct acpi_rsdump_info acpi_rs_dump_pin_function[10] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_pin_function), + "PinFunction", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_function.revision_id), + "RevisionId", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_function.pin_config), "PinConfig", + acpi_gbl_ppc_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_function.sharable), "Sharing", + acpi_gbl_shr_decode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_function.function_number), + "FunctionNumber", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(pin_function.resource_source), + "ResourceSource", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_function.pin_table_length), + "PinTableLength", NULL}, + {ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(pin_function.pin_table), "PinTable", + NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_function.vendor_length), + "VendorLength", NULL}, + {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(pin_function.vendor_data), + "VendorData", NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_pin_config[11] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_pin_config), + "PinConfig", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_config.revision_id), "RevisionId", + NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_config.producer_consumer), + "ProducerConsumer", acpi_gbl_consume_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_config.sharable), "Sharing", + acpi_gbl_shr_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_config.pin_config_type), + "PinConfigType", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(pin_config.pin_config_value), + "PinConfigValue", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(pin_config.resource_source), + "ResourceSource", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_config.pin_table_length), + "PinTableLength", NULL}, + {ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(pin_config.pin_table), "PinTable", + NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_config.vendor_length), + "VendorLength", NULL}, + {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(pin_config.vendor_data), + "VendorData", NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_pin_group[8] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_pin_group), + "PinGroup", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_group.revision_id), "RevisionId", + NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_group.producer_consumer), + "ProducerConsumer", acpi_gbl_consume_decode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_group.pin_table_length), + "PinTableLength", NULL}, + {ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(pin_group.pin_table), "PinTable", + NULL}, + {ACPI_RSD_LABEL, ACPI_RSD_OFFSET(pin_group.resource_label), + "ResourceLabel", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_group.vendor_length), + "VendorLength", NULL}, + {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(pin_group.vendor_data), + "VendorData", NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_pin_group_function[9] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_pin_group_function), + "PinGroupFunction", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_group_function.revision_id), + "RevisionId", NULL}, + {ACPI_RSD_1BITFLAG, + ACPI_RSD_OFFSET(pin_group_function.producer_consumer), + "ProducerConsumer", acpi_gbl_consume_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_group_function.sharable), + "Sharing", acpi_gbl_shr_decode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_group_function.function_number), + "FunctionNumber", NULL}, + {ACPI_RSD_SOURCE_LABEL, + ACPI_RSD_OFFSET(pin_group_function.resource_source_label), + "ResourceSourceLabel", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(pin_group_function.resource_source), + "ResourceSource", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_group_function.vendor_length), + "VendorLength", NULL}, + {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(pin_group_function.vendor_data), + "VendorData", NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_pin_group_config[10] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_pin_group_config), + "PinGroupConfig", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_group_config.revision_id), + "RevisionId", NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_group_config.producer_consumer), + "ProducerConsumer", acpi_gbl_consume_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_group_config.sharable), + "Sharing", acpi_gbl_shr_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_group_config.pin_config_type), + "PinConfigType", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(pin_group_config.pin_config_value), + "PinConfigValue", NULL}, + {ACPI_RSD_SOURCE_LABEL, + ACPI_RSD_OFFSET(pin_group_config.resource_source_label), + "ResourceSourceLabel", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(pin_group_config.resource_source), + "ResourceSource", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_group_config.vendor_length), + "VendorLength", NULL}, + {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(pin_group_config.vendor_data), + "VendorData", NULL}, +}; + struct acpi_rsdump_info acpi_rs_dump_fixed_dma[4] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_dma), "FixedDma", NULL}, diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index 475da9d6aed5..b0e50518d766 100644 --- a/drivers/acpi/acpica/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -80,6 +80,11 @@ struct acpi_rsconvert_info *acpi_gbl_set_resource_dispatch[] = { acpi_rs_convert_gpio, /* 0x11, ACPI_RESOURCE_TYPE_GPIO */ acpi_rs_convert_fixed_dma, /* 0x12, ACPI_RESOURCE_TYPE_FIXED_DMA */ NULL, /* 0x13, ACPI_RESOURCE_TYPE_SERIAL_BUS - Use subtype table below */ + acpi_rs_convert_pin_function, /* 0x14, ACPI_RESOURCE_TYPE_PIN_FUNCTION */ + acpi_rs_convert_pin_config, /* 0x15, ACPI_RESOURCE_TYPE_PIN_CONFIG */ + acpi_rs_convert_pin_group, /* 0x16, ACPI_RESOURCE_TYPE_PIN_GROUP */ + acpi_rs_convert_pin_group_function, /* 0x17, ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION */ + acpi_rs_convert_pin_group_config, /* 0x18, ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG */ }; /* Dispatch tables for AML-to-resource (Get Resource) conversion functions */ @@ -119,8 +124,12 @@ struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[] = { acpi_rs_convert_address64, /* 0x0A, ACPI_RESOURCE_NAME_ADDRESS64 */ acpi_rs_convert_ext_address64, /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 */ acpi_rs_convert_gpio, /* 0x0C, ACPI_RESOURCE_NAME_GPIO */ - NULL, /* 0x0D, Reserved */ + acpi_rs_convert_pin_function, /* 0x0D, ACPI_RESOURCE_NAME_PIN_FUNCTION */ NULL, /* 0x0E, ACPI_RESOURCE_NAME_SERIAL_BUS - Use subtype table below */ + acpi_rs_convert_pin_config, /* 0x0F, ACPI_RESOURCE_NAME_PIN_CONFIG */ + acpi_rs_convert_pin_group, /* 0x10, ACPI_RESOURCE_NAME_PIN_GROUP */ + acpi_rs_convert_pin_group_function, /* 0x11, ACPI_RESOURCE_NAME_PIN_GROUP_FUNCTION */ + acpi_rs_convert_pin_group_config, /* 0x12, ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG */ }; /* Subtype table for serial_bus -- I2C, SPI, and UART */ @@ -157,6 +166,11 @@ struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[] = { acpi_rs_dump_gpio, /* ACPI_RESOURCE_TYPE_GPIO */ acpi_rs_dump_fixed_dma, /* ACPI_RESOURCE_TYPE_FIXED_DMA */ NULL, /* ACPI_RESOURCE_TYPE_SERIAL_BUS */ + acpi_rs_dump_pin_function, /* ACPI_RESOURCE_TYPE_PIN_FUNCTION */ + acpi_rs_dump_pin_config, /* ACPI_RESOURCE_TYPE_PIN_CONFIG */ + acpi_rs_dump_pin_group, /* ACPI_RESOURCE_TYPE_PIN_GROUP */ + acpi_rs_dump_pin_group_function, /* ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION */ + acpi_rs_dump_pin_group_config, /* ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG */ }; struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[] = { @@ -193,6 +207,11 @@ const u8 acpi_gbl_aml_resource_sizes[] = { sizeof(struct aml_resource_gpio), /* ACPI_RESOURCE_TYPE_GPIO */ sizeof(struct aml_resource_fixed_dma), /* ACPI_RESOURCE_TYPE_FIXED_DMA */ sizeof(struct aml_resource_common_serialbus), /* ACPI_RESOURCE_TYPE_SERIAL_BUS */ + sizeof(struct aml_resource_pin_function), /* ACPI_RESOURCE_TYPE_PIN_FUNCTION */ + sizeof(struct aml_resource_pin_config), /* ACPI_RESOURCE_TYPE_PIN_CONFIG */ + sizeof(struct aml_resource_pin_group), /* ACPI_RESOURCE_TYPE_PIN_GROUP */ + sizeof(struct aml_resource_pin_group_function), /* ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION */ + sizeof(struct aml_resource_pin_group_config), /* ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG */ }; const u8 acpi_gbl_resource_struct_sizes[] = { @@ -230,7 +249,12 @@ const u8 acpi_gbl_resource_struct_sizes[] = { ACPI_RS_SIZE(struct acpi_resource_address64), ACPI_RS_SIZE(struct acpi_resource_extended_address64), ACPI_RS_SIZE(struct acpi_resource_gpio), - ACPI_RS_SIZE(struct acpi_resource_common_serialbus) + ACPI_RS_SIZE(struct acpi_resource_pin_function), + ACPI_RS_SIZE(struct acpi_resource_common_serialbus), + ACPI_RS_SIZE(struct acpi_resource_pin_config), + ACPI_RS_SIZE(struct acpi_resource_pin_group), + ACPI_RS_SIZE(struct acpi_resource_pin_group_function), + ACPI_RS_SIZE(struct acpi_resource_pin_group_config), }; const u8 acpi_gbl_aml_resource_serial_bus_sizes[] = { diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index 2ae79613f6b7..cc4b5486c4bc 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -596,9 +596,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, /* Set vendor offset only if there is vendor data */ - if (resource->data.gpio.vendor_length) { - ACPI_SET16(target, aml_length); - } + ACPI_SET16(target, aml_length); acpi_rs_set_resource_length(aml_length, aml); break; diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c index c20e6d07928d..14d12d6eb716 100644 --- a/drivers/acpi/acpica/rsserial.c +++ b/drivers/acpi/acpica/rsserial.c @@ -147,6 +147,82 @@ struct acpi_rsconvert_info acpi_rs_convert_gpio[18] = { /******************************************************************************* * + * acpi_rs_convert_pinfunction + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_pin_function[13] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_PIN_FUNCTION, + ACPI_RS_SIZE(struct acpi_resource_pin_function), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_pin_function)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_PIN_FUNCTION, + sizeof(struct aml_resource_pin_function), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_function.revision_id), + AML_OFFSET(pin_function.revision_id), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.pin_function.sharable), + AML_OFFSET(pin_function.flags), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_function.pin_config), + AML_OFFSET(pin_function.pin_config), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.pin_function.function_number), + AML_OFFSET(pin_function.function_number), + 2}, + + /* Pin Table */ + + /* + * It is OK to use GPIO operations here because none of them refer GPIO + * structures directly but instead use offsets given here. + */ + + {ACPI_RSC_COUNT_GPIO_PIN, + ACPI_RS_OFFSET(data.pin_function.pin_table_length), + AML_OFFSET(pin_function.pin_table_offset), + AML_OFFSET(pin_function.res_source_offset)}, + + {ACPI_RSC_MOVE_GPIO_PIN, ACPI_RS_OFFSET(data.pin_function.pin_table), + AML_OFFSET(pin_function.pin_table_offset), + 0}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.pin_function.resource_source.index), + AML_OFFSET(pin_function.res_source_index), + 1}, + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_function.resource_source.string_length), + AML_OFFSET(pin_function.res_source_offset), + AML_OFFSET(pin_function.vendor_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_function.resource_source.string_ptr), + AML_OFFSET(pin_function.res_source_offset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, + ACPI_RS_OFFSET(data.pin_function.vendor_length), + AML_OFFSET(pin_function.vendor_length), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, ACPI_RS_OFFSET(data.pin_function.vendor_data), + AML_OFFSET(pin_function.vendor_offset), + 0}, +}; + +/******************************************************************************* + * * acpi_rs_convert_i2c_serial_bus * ******************************************************************************/ @@ -458,3 +534,300 @@ struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[23] = { AML_OFFSET(uart_serial_bus.default_baud_rate), 1}, }; + +/******************************************************************************* + * + * acpi_rs_convert_pin_config + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_pin_config[14] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_PIN_CONFIG, + ACPI_RS_SIZE(struct acpi_resource_pin_config), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_pin_config)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_PIN_CONFIG, + sizeof(struct aml_resource_pin_config), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_config.revision_id), + AML_OFFSET(pin_config.revision_id), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.pin_config.sharable), + AML_OFFSET(pin_config.flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.pin_config.producer_consumer), + AML_OFFSET(pin_config.flags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_config.pin_config_type), + AML_OFFSET(pin_config.pin_config_type), + 1}, + + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.pin_config.pin_config_value), + AML_OFFSET(pin_config.pin_config_value), + 1}, + + /* Pin Table */ + + /* + * It is OK to use GPIO operations here because none of them refer GPIO + * structures directly but instead use offsets given here. + */ + + {ACPI_RSC_COUNT_GPIO_PIN, + ACPI_RS_OFFSET(data.pin_config.pin_table_length), + AML_OFFSET(pin_config.pin_table_offset), + AML_OFFSET(pin_config.res_source_offset)}, + + {ACPI_RSC_MOVE_GPIO_PIN, ACPI_RS_OFFSET(data.pin_config.pin_table), + AML_OFFSET(pin_config.pin_table_offset), + 0}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_config.resource_source.index), + AML_OFFSET(pin_config.res_source_index), + 1}, + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_config.resource_source.string_length), + AML_OFFSET(pin_config.res_source_offset), + AML_OFFSET(pin_config.vendor_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_config.resource_source.string_ptr), + AML_OFFSET(pin_config.res_source_offset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, ACPI_RS_OFFSET(data.pin_config.vendor_length), + AML_OFFSET(pin_config.vendor_length), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, ACPI_RS_OFFSET(data.pin_config.vendor_data), + AML_OFFSET(pin_config.vendor_offset), + 0}, +}; + +/******************************************************************************* + * + * acpi_rs_convert_pin_group + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_pin_group[10] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_PIN_GROUP, + ACPI_RS_SIZE(struct acpi_resource_pin_group), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_pin_group)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_PIN_GROUP, + sizeof(struct aml_resource_pin_group), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_group.revision_id), + AML_OFFSET(pin_group.revision_id), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.pin_group.producer_consumer), + AML_OFFSET(pin_group.flags), + 0}, + + /* Pin Table */ + + /* + * It is OK to use GPIO operations here because none of them refer GPIO + * structures directly but instead use offsets given here. + */ + + {ACPI_RSC_COUNT_GPIO_PIN, + ACPI_RS_OFFSET(data.pin_group.pin_table_length), + AML_OFFSET(pin_group.pin_table_offset), + AML_OFFSET(pin_group.label_offset)}, + + {ACPI_RSC_MOVE_GPIO_PIN, ACPI_RS_OFFSET(data.pin_group.pin_table), + AML_OFFSET(pin_group.pin_table_offset), + 0}, + + /* Resource Label */ + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group.resource_label.string_length), + AML_OFFSET(pin_group.label_offset), + AML_OFFSET(pin_group.vendor_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group.resource_label.string_ptr), + AML_OFFSET(pin_group.label_offset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, ACPI_RS_OFFSET(data.pin_group.vendor_length), + AML_OFFSET(pin_group.vendor_length), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, ACPI_RS_OFFSET(data.pin_group.vendor_data), + AML_OFFSET(pin_group.vendor_offset), + 0}, +}; + +/******************************************************************************* + * + * acpi_rs_convert_pin_group_function + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_pin_group_function[13] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION, + ACPI_RS_SIZE(struct acpi_resource_pin_group_function), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_pin_group_function)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_PIN_GROUP_FUNCTION, + sizeof(struct aml_resource_pin_group_function), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_group_function.revision_id), + AML_OFFSET(pin_group_function.revision_id), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.pin_group_function.sharable), + AML_OFFSET(pin_group_function.flags), + 0}, + + {ACPI_RSC_1BITFLAG, + ACPI_RS_OFFSET(data.pin_group_function.producer_consumer), + AML_OFFSET(pin_group_function.flags), + 1}, + + {ACPI_RSC_MOVE16, + ACPI_RS_OFFSET(data.pin_group_function.function_number), + AML_OFFSET(pin_group_function.function_number), + 1}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.pin_group_function.resource_source.index), + AML_OFFSET(pin_group_function.res_source_index), + 1}, + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_function.resource_source.string_length), + AML_OFFSET(pin_group_function.res_source_offset), + AML_OFFSET(pin_group_function.res_source_label_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_function.resource_source.string_ptr), + AML_OFFSET(pin_group_function.res_source_offset), + 0}, + + /* Resource Source Label */ + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_function.resource_source_label. + string_length), + AML_OFFSET(pin_group_function.res_source_label_offset), + AML_OFFSET(pin_group_function.vendor_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_function.resource_source_label. + string_ptr), + AML_OFFSET(pin_group_function.res_source_label_offset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, + ACPI_RS_OFFSET(data.pin_group_function.vendor_length), + AML_OFFSET(pin_group_function.vendor_length), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_function.vendor_data), + AML_OFFSET(pin_group_function.vendor_offset), + 0}, +}; + +/******************************************************************************* + * + * acpi_rs_convert_pin_group_config + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_pin_group_config[14] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG, + ACPI_RS_SIZE(struct acpi_resource_pin_group_config), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_pin_group_config)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG, + sizeof(struct aml_resource_pin_group_config), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_group_config.revision_id), + AML_OFFSET(pin_group_config.revision_id), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.pin_group_config.sharable), + AML_OFFSET(pin_group_config.flags), + 0}, + + {ACPI_RSC_1BITFLAG, + ACPI_RS_OFFSET(data.pin_group_config.producer_consumer), + AML_OFFSET(pin_group_config.flags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_group_config.pin_config_type), + AML_OFFSET(pin_group_config.pin_config_type), + 1}, + + {ACPI_RSC_MOVE32, + ACPI_RS_OFFSET(data.pin_group_config.pin_config_value), + AML_OFFSET(pin_group_config.pin_config_value), + 1}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.pin_group_config.resource_source.index), + AML_OFFSET(pin_group_config.res_source_index), + 1}, + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_config.resource_source.string_length), + AML_OFFSET(pin_group_config.res_source_offset), + AML_OFFSET(pin_group_config.res_source_label_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_config.resource_source.string_ptr), + AML_OFFSET(pin_group_config.res_source_offset), + 0}, + + /* Resource Source Label */ + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_config.resource_source_label. + string_length), + AML_OFFSET(pin_group_config.res_source_label_offset), + AML_OFFSET(pin_group_config.vendor_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_config.resource_source_label.string_ptr), + AML_OFFSET(pin_group_config.res_source_label_offset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, + ACPI_RS_OFFSET(data.pin_group_config.vendor_length), + AML_OFFSET(pin_group_config.vendor_length), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_config.vendor_data), + AML_OFFSET(pin_group_config.vendor_offset), + 0}, +}; diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 51860bfc111e..5f051d82188d 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -449,8 +449,8 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) * The 64-bit X fields are optional extensions to the original 32-bit FADT * V1.0 fields. Even if they are present in the FADT, they are optional and * are unused if the BIOS sets them to zero. Therefore, we must copy/expand - * 32-bit V1.0 fields to the 64-bit X fields if the the 64-bit X field is - * originally zero. + * 32-bit V1.0 fields to the 64-bit X fields if the 64-bit X field is originally + * zero. * * For ACPI 1.0 FADTs (that contain no 64-bit addresses), all 32-bit address * fields are expanded to the corresponding 64-bit X fields in the internal diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 0d2e98920069..0c6768d20395 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -141,9 +141,9 @@ void acpi_tb_check_dsdt_header(void) * * FUNCTION: acpi_tb_copy_dsdt * - * PARAMETERS: table_desc - Installed table to copy + * PARAMETERS: table_index - Index of installed table to copy * - * RETURN: None + * RETURN: The copied DSDT * * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory. * Some very bad BIOSs are known to either corrupt the DSDT or @@ -239,7 +239,7 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size) * * FUNCTION: acpi_tb_parse_root_table * - * PARAMETERS: rsdp - Pointer to the RSDP + * PARAMETERS: rsdp_address - Pointer to the RSDP * * RETURN: Status * diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index 60868309e326..02cd2c2d961a 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -460,9 +460,11 @@ static const char *acpi_gbl_generic_notify[ACPI_GENERIC_NOTIFY_MAX + 1] = { /* 09 */ "Device PLD Check", /* 0A */ "Reserved", /* 0B */ "System Locality Update", - /* 0C */ "Shutdown Request", - /* Reserved in ACPI 6.0 */ - /* 0D */ "System Resource Affinity Update" + /* 0C */ "Reserved (was previously Shutdown Request)", + /* Reserved in ACPI 6.0 */ + /* 0D */ "System Resource Affinity Update", + /* 0E */ "Heterogeneous Memory Attributes Update" + /* ACPI 6.2 */ }; static const char *acpi_gbl_device_notify[5] = { diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c index c82399f9b456..1b3ee74a87eb 100644 --- a/drivers/acpi/acpica/utownerid.c +++ b/drivers/acpi/acpica/utownerid.c @@ -104,13 +104,19 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id *owner_id) break; } - if (!(acpi_gbl_owner_id_mask[j] & (1 << k))) { + /* + * Note: the u32 cast ensures that 1 is stored as a unsigned + * integer. Omitting the cast may result in 1 being stored as an + * int. Some compilers or runtime error detection may flag this as + * an error. + */ + if (!(acpi_gbl_owner_id_mask[j] & ((u32)1 << k))) { /* * Found a free ID. The actual ID is the bit index plus one, * making zero an invalid Owner ID. Save this as the last ID * allocated and update the global ID mask. */ - acpi_gbl_owner_id_mask[j] |= (1 << k); + acpi_gbl_owner_id_mask[j] |= ((u32)1 << k); acpi_gbl_last_owner_id_index = (u8)j; acpi_gbl_next_owner_id_offset = (u8)(k + 1); @@ -201,7 +207,7 @@ void acpi_ut_release_owner_id(acpi_owner_id *owner_id_ptr) /* Decode ID to index/offset pair */ index = ACPI_DIV_32(owner_id); - bit = 1 << ACPI_MOD_32(owner_id); + bit = (u32)1 << ACPI_MOD_32(owner_id); /* Free the owner ID only if it is valid */ diff --git a/drivers/acpi/acpica/utresdecode.c b/drivers/acpi/acpica/utresdecode.c new file mode 100644 index 000000000000..e15a2538558b --- /dev/null +++ b/drivers/acpi/acpica/utresdecode.c @@ -0,0 +1,315 @@ +/******************************************************************************* + * + * Module Name: utresdecode - Resource descriptor keyword strings + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2017, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <acpi/acpi.h> +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utresdecode") + +#if defined (ACPI_DEBUG_OUTPUT) || \ + defined (ACPI_DISASSEMBLER) || \ + defined (ACPI_DEBUGGER) +/* + * Strings used to decode resource descriptors. + * Used by both the disassembler and the debugger resource dump routines + */ +const char *acpi_gbl_bm_decode[] = { + "NotBusMaster", + "BusMaster" +}; + +const char *acpi_gbl_config_decode[] = { + "0 - Good Configuration", + "1 - Acceptable Configuration", + "2 - Suboptimal Configuration", + "3 - ***Invalid Configuration***", +}; + +const char *acpi_gbl_consume_decode[] = { + "ResourceProducer", + "ResourceConsumer" +}; + +const char *acpi_gbl_dec_decode[] = { + "PosDecode", + "SubDecode" +}; + +const char *acpi_gbl_he_decode[] = { + "Level", + "Edge" +}; + +const char *acpi_gbl_io_decode[] = { + "Decode10", + "Decode16" +}; + +const char *acpi_gbl_ll_decode[] = { + "ActiveHigh", + "ActiveLow", + "ActiveBoth", + "Reserved" +}; + +const char *acpi_gbl_max_decode[] = { + "MaxNotFixed", + "MaxFixed" +}; + +const char *acpi_gbl_mem_decode[] = { + "NonCacheable", + "Cacheable", + "WriteCombining", + "Prefetchable" +}; + +const char *acpi_gbl_min_decode[] = { + "MinNotFixed", + "MinFixed" +}; + +const char *acpi_gbl_mtp_decode[] = { + "AddressRangeMemory", + "AddressRangeReserved", + "AddressRangeACPI", + "AddressRangeNVS" +}; + +const char *acpi_gbl_rng_decode[] = { + "InvalidRanges", + "NonISAOnlyRanges", + "ISAOnlyRanges", + "EntireRange" +}; + +const char *acpi_gbl_rw_decode[] = { + "ReadOnly", + "ReadWrite" +}; + +const char *acpi_gbl_shr_decode[] = { + "Exclusive", + "Shared", + "ExclusiveAndWake", /* ACPI 5.0 */ + "SharedAndWake" /* ACPI 5.0 */ +}; + +const char *acpi_gbl_siz_decode[] = { + "Transfer8", + "Transfer8_16", + "Transfer16", + "InvalidSize" +}; + +const char *acpi_gbl_trs_decode[] = { + "DenseTranslation", + "SparseTranslation" +}; + +const char *acpi_gbl_ttp_decode[] = { + "TypeStatic", + "TypeTranslation" +}; + +const char *acpi_gbl_typ_decode[] = { + "Compatibility", + "TypeA", + "TypeB", + "TypeF" +}; + +const char *acpi_gbl_ppc_decode[] = { + "PullDefault", + "PullUp", + "PullDown", + "PullNone" +}; + +const char *acpi_gbl_ior_decode[] = { + "IoRestrictionNone", + "IoRestrictionInputOnly", + "IoRestrictionOutputOnly", + "IoRestrictionNoneAndPreserve" +}; + +const char *acpi_gbl_dts_decode[] = { + "Width8bit", + "Width16bit", + "Width32bit", + "Width64bit", + "Width128bit", + "Width256bit", +}; + +/* GPIO connection type */ + +const char *acpi_gbl_ct_decode[] = { + "Interrupt", + "I/O" +}; + +/* Serial bus type */ + +const char *acpi_gbl_sbt_decode[] = { + "/* UNKNOWN serial bus type */", + "I2C", + "SPI", + "UART" +}; + +/* I2C serial bus access mode */ + +const char *acpi_gbl_am_decode[] = { + "AddressingMode7Bit", + "AddressingMode10Bit" +}; + +/* I2C serial bus slave mode */ + +const char *acpi_gbl_sm_decode[] = { + "ControllerInitiated", + "DeviceInitiated" +}; + +/* SPI serial bus wire mode */ + +const char *acpi_gbl_wm_decode[] = { + "FourWireMode", + "ThreeWireMode" +}; + +/* SPI serial clock phase */ + +const char *acpi_gbl_cph_decode[] = { + "ClockPhaseFirst", + "ClockPhaseSecond" +}; + +/* SPI serial bus clock polarity */ + +const char *acpi_gbl_cpo_decode[] = { + "ClockPolarityLow", + "ClockPolarityHigh" +}; + +/* SPI serial bus device polarity */ + +const char *acpi_gbl_dp_decode[] = { + "PolarityLow", + "PolarityHigh" +}; + +/* UART serial bus endian */ + +const char *acpi_gbl_ed_decode[] = { + "LittleEndian", + "BigEndian" +}; + +/* UART serial bus bits per byte */ + +const char *acpi_gbl_bpb_decode[] = { + "DataBitsFive", + "DataBitsSix", + "DataBitsSeven", + "DataBitsEight", + "DataBitsNine", + "/* UNKNOWN Bits per byte */", + "/* UNKNOWN Bits per byte */", + "/* UNKNOWN Bits per byte */" +}; + +/* UART serial bus stop bits */ + +const char *acpi_gbl_sb_decode[] = { + "StopBitsZero", + "StopBitsOne", + "StopBitsOnePlusHalf", + "StopBitsTwo" +}; + +/* UART serial bus flow control */ + +const char *acpi_gbl_fc_decode[] = { + "FlowControlNone", + "FlowControlHardware", + "FlowControlXON", + "/* UNKNOWN flow control keyword */" +}; + +/* UART serial bus parity type */ + +const char *acpi_gbl_pt_decode[] = { + "ParityTypeNone", + "ParityTypeEven", + "ParityTypeOdd", + "ParityTypeMark", + "ParityTypeSpace", + "/* UNKNOWN parity keyword */", + "/* UNKNOWN parity keyword */", + "/* UNKNOWN parity keyword */" +}; + +/* pin_config type */ + +const char *acpi_gbl_ptyp_decode[] = { + "Default", + "Bias Pull-up", + "Bias Pull-down", + "Bias Default", + "Bias Disable", + "Bias High Impedance", + "Bias Bus Hold", + "Drive Open Drain", + "Drive Open Source", + "Drive Push Pull", + "Drive Strength", + "Slew Rate", + "Input Debounce", + "Input Schmitt Trigger", +}; + +#endif diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index ff096d9755b9..70f78a4bf13b 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -48,251 +48,6 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utresrc") -#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER) -/* - * Strings used to decode resource descriptors. - * Used by both the disassembler and the debugger resource dump routines - */ -const char *acpi_gbl_bm_decode[] = { - "NotBusMaster", - "BusMaster" -}; - -const char *acpi_gbl_config_decode[] = { - "0 - Good Configuration", - "1 - Acceptable Configuration", - "2 - Suboptimal Configuration", - "3 - ***Invalid Configuration***", -}; - -const char *acpi_gbl_consume_decode[] = { - "ResourceProducer", - "ResourceConsumer" -}; - -const char *acpi_gbl_dec_decode[] = { - "PosDecode", - "SubDecode" -}; - -const char *acpi_gbl_he_decode[] = { - "Level", - "Edge" -}; - -const char *acpi_gbl_io_decode[] = { - "Decode10", - "Decode16" -}; - -const char *acpi_gbl_ll_decode[] = { - "ActiveHigh", - "ActiveLow", - "ActiveBoth", - "Reserved" -}; - -const char *acpi_gbl_max_decode[] = { - "MaxNotFixed", - "MaxFixed" -}; - -const char *acpi_gbl_mem_decode[] = { - "NonCacheable", - "Cacheable", - "WriteCombining", - "Prefetchable" -}; - -const char *acpi_gbl_min_decode[] = { - "MinNotFixed", - "MinFixed" -}; - -const char *acpi_gbl_mtp_decode[] = { - "AddressRangeMemory", - "AddressRangeReserved", - "AddressRangeACPI", - "AddressRangeNVS" -}; - -const char *acpi_gbl_rng_decode[] = { - "InvalidRanges", - "NonISAOnlyRanges", - "ISAOnlyRanges", - "EntireRange" -}; - -const char *acpi_gbl_rw_decode[] = { - "ReadOnly", - "ReadWrite" -}; - -const char *acpi_gbl_shr_decode[] = { - "Exclusive", - "Shared", - "ExclusiveAndWake", /* ACPI 5.0 */ - "SharedAndWake" /* ACPI 5.0 */ -}; - -const char *acpi_gbl_siz_decode[] = { - "Transfer8", - "Transfer8_16", - "Transfer16", - "InvalidSize" -}; - -const char *acpi_gbl_trs_decode[] = { - "DenseTranslation", - "SparseTranslation" -}; - -const char *acpi_gbl_ttp_decode[] = { - "TypeStatic", - "TypeTranslation" -}; - -const char *acpi_gbl_typ_decode[] = { - "Compatibility", - "TypeA", - "TypeB", - "TypeF" -}; - -const char *acpi_gbl_ppc_decode[] = { - "PullDefault", - "PullUp", - "PullDown", - "PullNone" -}; - -const char *acpi_gbl_ior_decode[] = { - "IoRestrictionNone", - "IoRestrictionInputOnly", - "IoRestrictionOutputOnly", - "IoRestrictionNoneAndPreserve" -}; - -const char *acpi_gbl_dts_decode[] = { - "Width8bit", - "Width16bit", - "Width32bit", - "Width64bit", - "Width128bit", - "Width256bit", -}; - -/* GPIO connection type */ - -const char *acpi_gbl_ct_decode[] = { - "Interrupt", - "I/O" -}; - -/* Serial bus type */ - -const char *acpi_gbl_sbt_decode[] = { - "/* UNKNOWN serial bus type */", - "I2C", - "SPI", - "UART" -}; - -/* I2C serial bus access mode */ - -const char *acpi_gbl_am_decode[] = { - "AddressingMode7Bit", - "AddressingMode10Bit" -}; - -/* I2C serial bus slave mode */ - -const char *acpi_gbl_sm_decode[] = { - "ControllerInitiated", - "DeviceInitiated" -}; - -/* SPI serial bus wire mode */ - -const char *acpi_gbl_wm_decode[] = { - "FourWireMode", - "ThreeWireMode" -}; - -/* SPI serial clock phase */ - -const char *acpi_gbl_cph_decode[] = { - "ClockPhaseFirst", - "ClockPhaseSecond" -}; - -/* SPI serial bus clock polarity */ - -const char *acpi_gbl_cpo_decode[] = { - "ClockPolarityLow", - "ClockPolarityHigh" -}; - -/* SPI serial bus device polarity */ - -const char *acpi_gbl_dp_decode[] = { - "PolarityLow", - "PolarityHigh" -}; - -/* UART serial bus endian */ - -const char *acpi_gbl_ed_decode[] = { - "LittleEndian", - "BigEndian" -}; - -/* UART serial bus bits per byte */ - -const char *acpi_gbl_bpb_decode[] = { - "DataBitsFive", - "DataBitsSix", - "DataBitsSeven", - "DataBitsEight", - "DataBitsNine", - "/* UNKNOWN Bits per byte */", - "/* UNKNOWN Bits per byte */", - "/* UNKNOWN Bits per byte */" -}; - -/* UART serial bus stop bits */ - -const char *acpi_gbl_sb_decode[] = { - "StopBitsZero", - "StopBitsOne", - "StopBitsOnePlusHalf", - "StopBitsTwo" -}; - -/* UART serial bus flow control */ - -const char *acpi_gbl_fc_decode[] = { - "FlowControlNone", - "FlowControlHardware", - "FlowControlXON", - "/* UNKNOWN flow control keyword */" -}; - -/* UART serial bus parity type */ - -const char *acpi_gbl_pt_decode[] = { - "ParityTypeNone", - "ParityTypeEven", - "ParityTypeOdd", - "ParityTypeMark", - "ParityTypeSpace", - "/* UNKNOWN parity keyword */", - "/* UNKNOWN parity keyword */", - "/* UNKNOWN parity keyword */" -}; - -#endif - /* * Base sizes of the raw AML resource descriptors, indexed by resource type. * Zero indicates a reserved (and therefore invalid) resource type. @@ -332,8 +87,12 @@ const u8 acpi_gbl_resource_aml_sizes[] = { ACPI_AML_SIZE_LARGE(struct aml_resource_address64), ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64), ACPI_AML_SIZE_LARGE(struct aml_resource_gpio), - 0, + ACPI_AML_SIZE_LARGE(struct aml_resource_pin_function), ACPI_AML_SIZE_LARGE(struct aml_resource_common_serialbus), + ACPI_AML_SIZE_LARGE(struct aml_resource_pin_config), + ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group), + ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_function), + ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_config), }; const u8 acpi_gbl_resource_aml_serial_bus_sizes[] = { @@ -384,8 +143,12 @@ static const u8 acpi_gbl_resource_types[] = { ACPI_VARIABLE_LENGTH, /* 0A Qword* address */ ACPI_FIXED_LENGTH, /* 0B Extended* address */ ACPI_VARIABLE_LENGTH, /* 0C Gpio* */ - 0, - ACPI_VARIABLE_LENGTH /* 0E *serial_bus */ + ACPI_VARIABLE_LENGTH, /* 0D pin_function */ + ACPI_VARIABLE_LENGTH, /* 0E *serial_bus */ + ACPI_VARIABLE_LENGTH, /* 0F pin_config */ + ACPI_VARIABLE_LENGTH, /* 10 pin_group */ + ACPI_VARIABLE_LENGTH, /* 11 pin_group_function */ + ACPI_VARIABLE_LENGTH, /* 12 pin_group_config */ }; /******************************************************************************* diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c index c016211c35ae..0b85f113f726 100644 --- a/drivers/acpi/acpica/utxfmutex.c +++ b/drivers/acpi/acpica/utxfmutex.c @@ -151,6 +151,8 @@ acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout) return (status); } +ACPI_EXPORT_SYMBOL(acpi_acquire_mutex) + /******************************************************************************* * * FUNCTION: acpi_release_mutex @@ -167,7 +169,6 @@ acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout) * not both. * ******************************************************************************/ - acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname) { acpi_status status; @@ -185,3 +186,5 @@ acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname) acpi_os_release_mutex(mutex_obj->mutex.os_mutex); return (AE_OK); } + +ACPI_EXPORT_SYMBOL(acpi_release_mutex) diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index ec4f507b524f..2c462beee551 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -513,7 +513,7 @@ retry: if (i < erst_record_id_cache.len) goto retry; if (erst_record_id_cache.len >= erst_record_id_cache.size) { - int new_size, alloc_size; + int new_size; u64 *new_entries; new_size = erst_record_id_cache.size * 2; @@ -524,11 +524,7 @@ retry: pr_warn(FW_WARN "too many record IDs!\n"); return 0; } - alloc_size = new_size * sizeof(entries[0]); - if (alloc_size < PAGE_SIZE) - new_entries = kmalloc(alloc_size, GFP_KERNEL); - else - new_entries = vmalloc(alloc_size); + new_entries = kvmalloc(new_size * sizeof(entries[0]), GFP_KERNEL); if (!new_entries) return -ENOMEM; memcpy(new_entries, entries, @@ -925,15 +921,9 @@ static int erst_check_table(struct acpi_table_erst *erst_tab) static int erst_open_pstore(struct pstore_info *psi); static int erst_close_pstore(struct pstore_info *psi); -static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, - struct timespec *time, char **buf, - bool *compressed, ssize_t *ecc_notice_size, - struct pstore_info *psi); -static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason, - u64 *id, unsigned int part, int count, bool compressed, - size_t size, struct pstore_info *psi); -static int erst_clearer(enum pstore_type_id type, u64 id, int count, - struct timespec time, struct pstore_info *psi); +static ssize_t erst_reader(struct pstore_record *record); +static int erst_writer(struct pstore_record *record); +static int erst_clearer(struct pstore_record *record); static struct pstore_info erst_info = { .owner = THIS_MODULE, @@ -986,10 +976,7 @@ static int erst_close_pstore(struct pstore_info *psi) return 0; } -static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, - struct timespec *time, char **buf, - bool *compressed, ssize_t *ecc_notice_size, - struct pstore_info *psi) +static ssize_t erst_reader(struct pstore_record *record) { int rc; ssize_t len = 0; @@ -1027,42 +1014,40 @@ skip: if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0) goto skip; - *buf = kmalloc(len, GFP_KERNEL); - if (*buf == NULL) { + record->buf = kmalloc(len, GFP_KERNEL); + if (record->buf == NULL) { rc = -ENOMEM; goto out; } - memcpy(*buf, rcd->data, len - sizeof(*rcd)); - *id = record_id; - *compressed = false; - *ecc_notice_size = 0; + memcpy(record->buf, rcd->data, len - sizeof(*rcd)); + record->id = record_id; + record->compressed = false; + record->ecc_notice_size = 0; if (uuid_le_cmp(rcd->sec_hdr.section_type, CPER_SECTION_TYPE_DMESG_Z) == 0) { - *type = PSTORE_TYPE_DMESG; - *compressed = true; + record->type = PSTORE_TYPE_DMESG; + record->compressed = true; } else if (uuid_le_cmp(rcd->sec_hdr.section_type, CPER_SECTION_TYPE_DMESG) == 0) - *type = PSTORE_TYPE_DMESG; + record->type = PSTORE_TYPE_DMESG; else if (uuid_le_cmp(rcd->sec_hdr.section_type, CPER_SECTION_TYPE_MCE) == 0) - *type = PSTORE_TYPE_MCE; + record->type = PSTORE_TYPE_MCE; else - *type = PSTORE_TYPE_UNKNOWN; + record->type = PSTORE_TYPE_UNKNOWN; if (rcd->hdr.validation_bits & CPER_VALID_TIMESTAMP) - time->tv_sec = rcd->hdr.timestamp; + record->time.tv_sec = rcd->hdr.timestamp; else - time->tv_sec = 0; - time->tv_nsec = 0; + record->time.tv_sec = 0; + record->time.tv_nsec = 0; out: kfree(rcd); return (rc < 0) ? rc : (len - sizeof(*rcd)); } -static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason, - u64 *id, unsigned int part, int count, bool compressed, - size_t size, struct pstore_info *psi) +static int erst_writer(struct pstore_record *record) { struct cper_pstore_record *rcd = (struct cper_pstore_record *) (erst_info.buf - sizeof(*rcd)); @@ -1077,21 +1062,21 @@ static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason, /* timestamp valid. platform_id, partition_id are invalid */ rcd->hdr.validation_bits = CPER_VALID_TIMESTAMP; rcd->hdr.timestamp = get_seconds(); - rcd->hdr.record_length = sizeof(*rcd) + size; + rcd->hdr.record_length = sizeof(*rcd) + record->size; rcd->hdr.creator_id = CPER_CREATOR_PSTORE; rcd->hdr.notification_type = CPER_NOTIFY_MCE; rcd->hdr.record_id = cper_next_record_id(); rcd->hdr.flags = CPER_HW_ERROR_FLAGS_PREVERR; rcd->sec_hdr.section_offset = sizeof(*rcd); - rcd->sec_hdr.section_length = size; + rcd->sec_hdr.section_length = record->size; rcd->sec_hdr.revision = CPER_SEC_REV; /* fru_id and fru_text is invalid */ rcd->sec_hdr.validation_bits = 0; rcd->sec_hdr.flags = CPER_SEC_PRIMARY; - switch (type) { + switch (record->type) { case PSTORE_TYPE_DMESG: - if (compressed) + if (record->compressed) rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG_Z; else rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG; @@ -1105,15 +1090,14 @@ static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason, rcd->sec_hdr.section_severity = CPER_SEV_FATAL; ret = erst_write(&rcd->hdr); - *id = rcd->hdr.record_id; + record->id = rcd->hdr.record_id; return ret; } -static int erst_clearer(enum pstore_type_id type, u64 id, int count, - struct timespec time, struct pstore_info *psi) +static int erst_clearer(struct pstore_record *record) { - return erst_clear(id); + return erst_clear(record->id); } static int __init erst_init(void) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 79b3c9c5a3bc..d0855c09f32f 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -1005,9 +1005,8 @@ static int ghes_probe(struct platform_device *ghes_dev) switch (generic->notify.type) { case ACPI_HEST_NOTIFY_POLLED: - ghes->timer.function = ghes_poll_func; - ghes->timer.data = (unsigned long)ghes; - init_timer_deferrable(&ghes->timer); + setup_deferrable_timer(&ghes->timer, ghes_poll_func, + (unsigned long)ghes); ghes_add_timer(ghes); break; case ACPI_HEST_NOTIFY_EXTERNAL: diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig index 4616da4c15be..5a6f80fce0d6 100644 --- a/drivers/acpi/arm64/Kconfig +++ b/drivers/acpi/arm64/Kconfig @@ -4,3 +4,6 @@ config ACPI_IORT bool + +config ACPI_GTDT + bool diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile index 72331f2ce0e9..1017def2ea12 100644 --- a/drivers/acpi/arm64/Makefile +++ b/drivers/acpi/arm64/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_ACPI_IORT) += iort.o +obj-$(CONFIG_ACPI_GTDT) += gtdt.o diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c new file mode 100644 index 000000000000..597a737d538f --- /dev/null +++ b/drivers/acpi/arm64/gtdt.c @@ -0,0 +1,417 @@ +/* + * ARM Specific GTDT table Support + * + * Copyright (C) 2016, Linaro Ltd. + * Author: Daniel Lezcano <daniel.lezcano@linaro.org> + * Fu Wei <fu.wei@linaro.org> + * Hanjun Guo <hanjun.guo@linaro.org> + * + * 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. + */ + +#include <linux/acpi.h> +#include <linux/init.h> +#include <linux/irqdomain.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <clocksource/arm_arch_timer.h> + +#undef pr_fmt +#define pr_fmt(fmt) "ACPI GTDT: " fmt + +/** + * struct acpi_gtdt_descriptor - Store the key info of GTDT for all functions + * @gtdt: The pointer to the struct acpi_table_gtdt of GTDT table. + * @gtdt_end: The pointer to the end of GTDT table. + * @platform_timer: The pointer to the start of Platform Timer Structure + * + * The struct store the key info of GTDT table, it should be initialized by + * acpi_gtdt_init. + */ +struct acpi_gtdt_descriptor { + struct acpi_table_gtdt *gtdt; + void *gtdt_end; + void *platform_timer; +}; + +static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata; + +static inline void *next_platform_timer(void *platform_timer) +{ + struct acpi_gtdt_header *gh = platform_timer; + + platform_timer += gh->length; + if (platform_timer < acpi_gtdt_desc.gtdt_end) + return platform_timer; + + return NULL; +} + +#define for_each_platform_timer(_g) \ + for (_g = acpi_gtdt_desc.platform_timer; _g; \ + _g = next_platform_timer(_g)) + +static inline bool is_timer_block(void *platform_timer) +{ + struct acpi_gtdt_header *gh = platform_timer; + + return gh->type == ACPI_GTDT_TYPE_TIMER_BLOCK; +} + +static inline bool is_non_secure_watchdog(void *platform_timer) +{ + struct acpi_gtdt_header *gh = platform_timer; + struct acpi_gtdt_watchdog *wd = platform_timer; + + if (gh->type != ACPI_GTDT_TYPE_WATCHDOG) + return false; + + return !(wd->timer_flags & ACPI_GTDT_WATCHDOG_SECURE); +} + +static int __init map_gt_gsi(u32 interrupt, u32 flags) +{ + int trigger, polarity; + + trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE + : ACPI_LEVEL_SENSITIVE; + + polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW + : ACPI_ACTIVE_HIGH; + + return acpi_register_gsi(NULL, interrupt, trigger, polarity); +} + +/** + * acpi_gtdt_map_ppi() - Map the PPIs of per-cpu arch_timer. + * @type: the type of PPI. + * + * Note: Secure state is not managed by the kernel on ARM64 systems. + * So we only handle the non-secure timer PPIs, + * ARCH_TIMER_PHYS_SECURE_PPI is treated as invalid type. + * + * Return: the mapped PPI value, 0 if error. + */ +int __init acpi_gtdt_map_ppi(int type) +{ + struct acpi_table_gtdt *gtdt = acpi_gtdt_desc.gtdt; + + switch (type) { + case ARCH_TIMER_PHYS_NONSECURE_PPI: + return map_gt_gsi(gtdt->non_secure_el1_interrupt, + gtdt->non_secure_el1_flags); + case ARCH_TIMER_VIRT_PPI: + return map_gt_gsi(gtdt->virtual_timer_interrupt, + gtdt->virtual_timer_flags); + + case ARCH_TIMER_HYP_PPI: + return map_gt_gsi(gtdt->non_secure_el2_interrupt, + gtdt->non_secure_el2_flags); + default: + pr_err("Failed to map timer interrupt: invalid type.\n"); + } + + return 0; +} + +/** + * acpi_gtdt_c3stop() - Got c3stop info from GTDT according to the type of PPI. + * @type: the type of PPI. + * + * Return: true if the timer HW state is lost when a CPU enters an idle state, + * false otherwise + */ +bool __init acpi_gtdt_c3stop(int type) +{ + struct acpi_table_gtdt *gtdt = acpi_gtdt_desc.gtdt; + + switch (type) { + case ARCH_TIMER_PHYS_NONSECURE_PPI: + return !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON); + + case ARCH_TIMER_VIRT_PPI: + return !(gtdt->virtual_timer_flags & ACPI_GTDT_ALWAYS_ON); + + case ARCH_TIMER_HYP_PPI: + return !(gtdt->non_secure_el2_flags & ACPI_GTDT_ALWAYS_ON); + + default: + pr_err("Failed to get c3stop info: invalid type.\n"); + } + + return false; +} + +/** + * acpi_gtdt_init() - Get the info of GTDT table to prepare for further init. + * @table: The pointer to GTDT table. + * @platform_timer_count: It points to a integer variable which is used + * for storing the number of platform timers. + * This pointer could be NULL, if the caller + * doesn't need this info. + * + * Return: 0 if success, -EINVAL if error. + */ +int __init acpi_gtdt_init(struct acpi_table_header *table, + int *platform_timer_count) +{ + void *platform_timer; + struct acpi_table_gtdt *gtdt; + + gtdt = container_of(table, struct acpi_table_gtdt, header); + acpi_gtdt_desc.gtdt = gtdt; + acpi_gtdt_desc.gtdt_end = (void *)table + table->length; + acpi_gtdt_desc.platform_timer = NULL; + if (platform_timer_count) + *platform_timer_count = 0; + + if (table->revision < 2) { + pr_warn("Revision:%d doesn't support Platform Timers.\n", + table->revision); + return 0; + } + + if (!gtdt->platform_timer_count) { + pr_debug("No Platform Timer.\n"); + return 0; + } + + platform_timer = (void *)gtdt + gtdt->platform_timer_offset; + if (platform_timer < (void *)table + sizeof(struct acpi_table_gtdt)) { + pr_err(FW_BUG "invalid timer data.\n"); + return -EINVAL; + } + acpi_gtdt_desc.platform_timer = platform_timer; + if (platform_timer_count) + *platform_timer_count = gtdt->platform_timer_count; + + return 0; +} + +static int __init gtdt_parse_timer_block(struct acpi_gtdt_timer_block *block, + struct arch_timer_mem *timer_mem) +{ + int i; + struct arch_timer_mem_frame *frame; + struct acpi_gtdt_timer_entry *gtdt_frame; + + if (!block->timer_count) { + pr_err(FW_BUG "GT block present, but frame count is zero."); + return -ENODEV; + } + + if (block->timer_count > ARCH_TIMER_MEM_MAX_FRAMES) { + pr_err(FW_BUG "GT block lists %d frames, ACPI spec only allows 8\n", + block->timer_count); + return -EINVAL; + } + + timer_mem->cntctlbase = (phys_addr_t)block->block_address; + /* + * The CNTCTLBase frame is 4KB (register offsets 0x000 - 0xFFC). + * See ARM DDI 0487A.k_iss10775, page I1-5129, Table I1-3 + * "CNTCTLBase memory map". + */ + timer_mem->size = SZ_4K; + + gtdt_frame = (void *)block + block->timer_offset; + if (gtdt_frame + block->timer_count != (void *)block + block->header.length) + return -EINVAL; + + /* + * Get the GT timer Frame data for every GT Block Timer + */ + for (i = 0; i < block->timer_count; i++, gtdt_frame++) { + if (gtdt_frame->common_flags & ACPI_GTDT_GT_IS_SECURE_TIMER) + continue; + if (gtdt_frame->frame_number >= ARCH_TIMER_MEM_MAX_FRAMES || + !gtdt_frame->base_address || !gtdt_frame->timer_interrupt) + goto error; + + frame = &timer_mem->frame[gtdt_frame->frame_number]; + + /* duplicate frame */ + if (frame->valid) + goto error; + + frame->phys_irq = map_gt_gsi(gtdt_frame->timer_interrupt, + gtdt_frame->timer_flags); + if (frame->phys_irq <= 0) { + pr_warn("failed to map physical timer irq in frame %d.\n", + gtdt_frame->frame_number); + goto error; + } + + if (gtdt_frame->virtual_timer_interrupt) { + frame->virt_irq = + map_gt_gsi(gtdt_frame->virtual_timer_interrupt, + gtdt_frame->virtual_timer_flags); + if (frame->virt_irq <= 0) { + pr_warn("failed to map virtual timer irq in frame %d.\n", + gtdt_frame->frame_number); + goto error; + } + } else { + pr_debug("virtual timer in frame %d not implemented.\n", + gtdt_frame->frame_number); + } + + frame->cntbase = gtdt_frame->base_address; + /* + * The CNTBaseN frame is 4KB (register offsets 0x000 - 0xFFC). + * See ARM DDI 0487A.k_iss10775, page I1-5130, Table I1-4 + * "CNTBaseN memory map". + */ + frame->size = SZ_4K; + frame->valid = true; + } + + return 0; + +error: + do { + if (gtdt_frame->common_flags & ACPI_GTDT_GT_IS_SECURE_TIMER || + gtdt_frame->frame_number >= ARCH_TIMER_MEM_MAX_FRAMES) + continue; + + frame = &timer_mem->frame[gtdt_frame->frame_number]; + + if (frame->phys_irq > 0) + acpi_unregister_gsi(gtdt_frame->timer_interrupt); + frame->phys_irq = 0; + + if (frame->virt_irq > 0) + acpi_unregister_gsi(gtdt_frame->virtual_timer_interrupt); + frame->virt_irq = 0; + } while (i-- >= 0 && gtdt_frame--); + + return -EINVAL; +} + +/** + * acpi_arch_timer_mem_init() - Get the info of all GT blocks in GTDT table. + * @timer_mem: The pointer to the array of struct arch_timer_mem for returning + * the result of parsing. The element number of this array should + * be platform_timer_count(the total number of platform timers). + * @timer_count: It points to a integer variable which is used for storing the + * number of GT blocks we have parsed. + * + * Return: 0 if success, -EINVAL/-ENODEV if error. + */ +int __init acpi_arch_timer_mem_init(struct arch_timer_mem *timer_mem, + int *timer_count) +{ + int ret; + void *platform_timer; + + *timer_count = 0; + for_each_platform_timer(platform_timer) { + if (is_timer_block(platform_timer)) { + ret = gtdt_parse_timer_block(platform_timer, timer_mem); + if (ret) + return ret; + timer_mem++; + (*timer_count)++; + } + } + + if (*timer_count) + pr_info("found %d memory-mapped timer block(s).\n", + *timer_count); + + return 0; +} + +/* + * Initialize a SBSA generic Watchdog platform device info from GTDT + */ +static int __init gtdt_import_sbsa_gwdt(struct acpi_gtdt_watchdog *wd, + int index) +{ + struct platform_device *pdev; + int irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags); + + /* + * According to SBSA specification the size of refresh and control + * frames of SBSA Generic Watchdog is SZ_4K(Offset 0x000 – 0xFFF). + */ + struct resource res[] = { + DEFINE_RES_MEM(wd->control_frame_address, SZ_4K), + DEFINE_RES_MEM(wd->refresh_frame_address, SZ_4K), + DEFINE_RES_IRQ(irq), + }; + int nr_res = ARRAY_SIZE(res); + + pr_debug("found a Watchdog (0x%llx/0x%llx gsi:%u flags:0x%x).\n", + wd->refresh_frame_address, wd->control_frame_address, + wd->timer_interrupt, wd->timer_flags); + + if (!(wd->refresh_frame_address && wd->control_frame_address)) { + pr_err(FW_BUG "failed to get the Watchdog base address.\n"); + acpi_unregister_gsi(wd->timer_interrupt); + return -EINVAL; + } + + if (irq <= 0) { + pr_warn("failed to map the Watchdog interrupt.\n"); + nr_res--; + } + + /* + * Add a platform device named "sbsa-gwdt" to match the platform driver. + * "sbsa-gwdt": SBSA(Server Base System Architecture) Generic Watchdog + * The platform driver can get device info below by matching this name. + */ + pdev = platform_device_register_simple("sbsa-gwdt", index, res, nr_res); + if (IS_ERR(pdev)) { + acpi_unregister_gsi(wd->timer_interrupt); + return PTR_ERR(pdev); + } + + return 0; +} + +static int __init gtdt_sbsa_gwdt_init(void) +{ + void *platform_timer; + struct acpi_table_header *table; + int ret, timer_count, gwdt_count = 0; + + if (acpi_disabled) + return 0; + + if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0, &table))) + return -EINVAL; + + /* + * Note: Even though the global variable acpi_gtdt_desc has been + * initialized by acpi_gtdt_init() while initializing the arch timers, + * when we call this function to get SBSA watchdogs info from GTDT, the + * pointers stashed in it are stale (since they are early temporary + * mappings carried out before acpi_permanent_mmap is set) and we need + * to re-initialize them with permanent mapped pointer values to let the + * GTDT parsing possible. + */ + ret = acpi_gtdt_init(table, &timer_count); + if (ret || !timer_count) + return ret; + + for_each_platform_timer(platform_timer) { + if (is_non_secure_watchdog(platform_timer)) { + ret = gtdt_import_sbsa_gwdt(platform_timer, gwdt_count); + if (ret) + break; + gwdt_count++; + } + } + + if (gwdt_count) + pr_info("found %d SBSA generic Watchdog(s).\n", gwdt_count); + + return ret; +} + +device_initcall(gtdt_sbsa_gwdt_init); diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 4a5bb967250b..797b28dc7b34 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -225,7 +225,7 @@ static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type, if (iort_node->type == type && ACPI_SUCCESS(callback(iort_node, context))) - return iort_node; + return iort_node; iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node, iort_node->length); @@ -253,17 +253,15 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node, void *context) { struct device *dev = context; - acpi_status status; + acpi_status status = AE_NOT_FOUND; if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) { struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_device *adev = to_acpi_device_node(dev->fwnode); struct acpi_iort_named_component *ncomp; - if (!adev) { - status = AE_NOT_FOUND; + if (!adev) goto out; - } status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf); if (ACPI_FAILURE(status)) { @@ -289,8 +287,6 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node, */ status = pci_rc->pci_segment_number == pci_domain_nr(bus) ? AE_OK : AE_NOT_FOUND; - } else { - status = AE_NOT_FOUND; } out: return status; @@ -322,8 +318,7 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in, static struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node, - u32 *id_out, u8 type_mask, - int index) + u32 *id_out, int index) { struct acpi_iort_node *parent; struct acpi_iort_id_mapping *map; @@ -345,9 +340,6 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node, parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table, map->output_reference); - if (!(IORT_TYPE_MASK(parent->type) & type_mask)) - return NULL; - if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) { if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT || node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) { @@ -359,11 +351,11 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node, return NULL; } -static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node, - u32 rid_in, u32 *rid_out, - u8 type_mask) +static struct acpi_iort_node *iort_node_map_id(struct acpi_iort_node *node, + u32 id_in, u32 *id_out, + u8 type_mask) { - u32 rid = rid_in; + u32 id = id_in; /* Parse the ID mapping tree to find specified node type */ while (node) { @@ -371,8 +363,8 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node, int i; if (IORT_TYPE_MASK(node->type) & type_mask) { - if (rid_out) - *rid_out = rid; + if (id_out) + *id_out = id; return node; } @@ -389,9 +381,9 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node, goto fail_map; } - /* Do the RID translation */ + /* Do the ID translation */ for (i = 0; i < node->mapping_count; i++, map++) { - if (!iort_id_map(map, node->type, rid, &rid)) + if (!iort_id_map(map, node->type, id, &id)) break; } @@ -403,13 +395,41 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node, } fail_map: - /* Map input RID to output RID unchanged on mapping failure*/ - if (rid_out) - *rid_out = rid_in; + /* Map input ID to output ID unchanged on mapping failure */ + if (id_out) + *id_out = id_in; return NULL; } +static +struct acpi_iort_node *iort_node_map_platform_id(struct acpi_iort_node *node, + u32 *id_out, u8 type_mask, + int index) +{ + struct acpi_iort_node *parent; + u32 id; + + /* step 1: retrieve the initial dev id */ + parent = iort_node_get_id(node, &id, index); + if (!parent) + return NULL; + + /* + * optional step 2: map the initial dev id if its parent is not + * the target type we want, map it again for the use cases such + * as NC (named component) -> SMMU -> ITS. If the type is matched, + * return the initial dev id and its parent pointer directly. + */ + if (!(IORT_TYPE_MASK(parent->type) & type_mask)) + parent = iort_node_map_id(parent, id, id_out, type_mask); + else + if (id_out) + *id_out = id; + + return parent; +} + static struct acpi_iort_node *iort_find_dev_node(struct device *dev) { struct pci_bus *pbus; @@ -443,13 +463,38 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id) if (!node) return req_id; - iort_node_map_rid(node, req_id, &dev_id, IORT_MSI_TYPE); + iort_node_map_id(node, req_id, &dev_id, IORT_MSI_TYPE); return dev_id; } /** + * iort_pmsi_get_dev_id() - Get the device id for a device + * @dev: The device for which the mapping is to be done. + * @dev_id: The device ID found. + * + * Returns: 0 for successful find a dev id, -ENODEV on error + */ +int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id) +{ + int i; + struct acpi_iort_node *node; + + node = iort_find_dev_node(dev); + if (!node) + return -ENODEV; + + for (i = 0; i < node->mapping_count; i++) { + if (iort_node_map_platform_id(node, dev_id, IORT_MSI_TYPE, i)) + return 0; + } + + return -ENODEV; +} + +/** * iort_dev_find_its_id() - Find the ITS identifier for a device * @dev: The device. + * @req_id: Device's requester ID * @idx: Index of the ITS identifier list. * @its_id: ITS identifier. * @@ -465,7 +510,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id, if (!node) return -ENXIO; - node = iort_node_map_rid(node, req_id, NULL, IORT_MSI_TYPE); + node = iort_node_map_id(node, req_id, NULL, IORT_MSI_TYPE); if (!node) return -ENXIO; @@ -503,6 +548,56 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id) return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI); } +/** + * iort_get_platform_device_domain() - Find MSI domain related to a + * platform device + * @dev: the dev pointer associated with the platform device + * + * Returns: the MSI domain for this device, NULL otherwise + */ +static struct irq_domain *iort_get_platform_device_domain(struct device *dev) +{ + struct acpi_iort_node *node, *msi_parent; + struct fwnode_handle *iort_fwnode; + struct acpi_iort_its_group *its; + int i; + + /* find its associated iort node */ + node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT, + iort_match_node_callback, dev); + if (!node) + return NULL; + + /* then find its msi parent node */ + for (i = 0; i < node->mapping_count; i++) { + msi_parent = iort_node_map_platform_id(node, NULL, + IORT_MSI_TYPE, i); + if (msi_parent) + break; + } + + if (!msi_parent) + return NULL; + + /* Move to ITS specific data */ + its = (struct acpi_iort_its_group *)msi_parent->node_data; + + iort_fwnode = iort_find_domain_token(its->identifiers[0]); + if (!iort_fwnode) + return NULL; + + return irq_find_matching_fwnode(iort_fwnode, DOMAIN_BUS_PLATFORM_MSI); +} + +void acpi_configure_pmsi_domain(struct device *dev) +{ + struct irq_domain *msi_domain; + + msi_domain = iort_get_platform_device_domain(dev); + if (msi_domain) + dev_set_msi_domain(dev, msi_domain); +} + static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data) { u32 *rid = data; @@ -523,6 +618,46 @@ static int arm_smmu_iort_xlate(struct device *dev, u32 streamid, return ret; } +static inline bool iort_iommu_driver_enabled(u8 type) +{ + switch (type) { + case ACPI_IORT_NODE_SMMU_V3: + return IS_BUILTIN(CONFIG_ARM_SMMU_V3); + case ACPI_IORT_NODE_SMMU: + return IS_BUILTIN(CONFIG_ARM_SMMU); + default: + pr_warn("IORT node type %u does not describe an SMMU\n", type); + return false; + } +} + +#ifdef CONFIG_IOMMU_API +static inline +const struct iommu_ops *iort_fwspec_iommu_ops(struct iommu_fwspec *fwspec) +{ + return (fwspec && fwspec->ops) ? fwspec->ops : NULL; +} + +static inline +int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev) +{ + int err = 0; + + if (!IS_ERR_OR_NULL(ops) && ops->add_device && dev->bus && + !dev->iommu_group) + err = ops->add_device(dev); + + return err; +} +#else +static inline +const struct iommu_ops *iort_fwspec_iommu_ops(struct iommu_fwspec *fwspec) +{ return NULL; } +static inline +int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev) +{ return 0; } +#endif + static const struct iommu_ops *iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node, u32 streamid) @@ -537,8 +672,17 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev, return NULL; ops = iommu_ops_from_fwnode(iort_fwnode); + /* + * If the ops look-up fails, this means that either + * the SMMU drivers have not been probed yet or that + * the SMMU drivers are not built in the kernel; + * Depending on whether the SMMU drivers are built-in + * in the kernel or not, defer the IOMMU configuration + * or just abort it. + */ if (!ops) - return NULL; + return iort_iommu_driver_enabled(node->type) ? + ERR_PTR(-EPROBE_DEFER) : NULL; ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops); } @@ -581,6 +725,15 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) struct acpi_iort_node *node, *parent; const struct iommu_ops *ops = NULL; u32 streamid = 0; + int err; + + /* + * If we already translated the fwspec there + * is nothing left to do, return the iommu_ops. + */ + ops = iort_fwspec_iommu_ops(dev->iommu_fwspec); + if (ops) + return ops; if (dev_is_pci(dev)) { struct pci_bus *bus = to_pci_dev(dev)->bus; @@ -594,8 +747,8 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) if (!node) return NULL; - parent = iort_node_map_rid(node, rid, &streamid, - IORT_IOMMU_TYPE); + parent = iort_node_map_id(node, rid, &streamid, + IORT_IOMMU_TYPE); ops = iort_iommu_xlate(dev, parent, streamid); @@ -607,17 +760,34 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) if (!node) return NULL; - parent = iort_node_get_id(node, &streamid, - IORT_IOMMU_TYPE, i++); + parent = iort_node_map_platform_id(node, &streamid, + IORT_IOMMU_TYPE, i++); while (parent) { ops = iort_iommu_xlate(dev, parent, streamid); + if (IS_ERR_OR_NULL(ops)) + return ops; - parent = iort_node_get_id(node, &streamid, - IORT_IOMMU_TYPE, i++); + parent = iort_node_map_platform_id(node, &streamid, + IORT_IOMMU_TYPE, + i++); } } + /* + * If we have reason to believe the IOMMU driver missed the initial + * add_device callback for dev, replay it to get things in order. + */ + err = iort_add_device_replay(ops, dev); + if (err) + ops = ERR_PTR(err); + + /* Ignore all other errors apart from EPROBE_DEFER */ + if (IS_ERR(ops) && (PTR_ERR(ops) != -EPROBE_DEFER)) { + dev_dbg(dev, "Adding to IOMMU failed: %ld\n", PTR_ERR(ops)); + ops = NULL; + } + return ops; } @@ -956,6 +1126,4 @@ void __init acpi_iort_init(void) } iort_init_platform_devices(); - - acpi_probe_device_table(iort); } 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/bgrt.c b/drivers/acpi/bgrt.c index ca28aa572aa9..df1c629205e7 100644 --- a/drivers/acpi/bgrt.c +++ b/drivers/acpi/bgrt.c @@ -81,6 +81,12 @@ static struct attribute_group bgrt_attribute_group = { .bin_attrs = bgrt_bin_attributes, }; +int __init acpi_parse_bgrt(struct acpi_table_header *table) +{ + efi_bgrt_init(table); + return 0; +} + static int __init bgrt_init(void) { int ret; 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/bus.c b/drivers/acpi/bus.c index 34fbe027e73a..784bda663d16 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -114,6 +114,11 @@ int acpi_bus_get_status(struct acpi_device *device) acpi_status status; unsigned long long sta; + if (acpi_device_always_present(device)) { + acpi_set_device_status(device, ACPI_STA_DEFAULT); + return 0; + } + status = acpi_bus_get_status_handle(device->handle, &sta); if (ACPI_FAILURE(status)) return -ENODEV; diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 668137e4a069..e19f530f1083 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -57,6 +57,7 @@ #define ACPI_BUTTON_LID_INIT_IGNORE 0x00 #define ACPI_BUTTON_LID_INIT_OPEN 0x01 +#define ACPI_BUTTON_LID_INIT_METHOD 0x02 #define _COMPONENT ACPI_BUTTON_COMPONENT ACPI_MODULE_NAME("button"); @@ -112,7 +113,7 @@ struct acpi_button { static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); static struct acpi_device *lid_device; -static u8 lid_init_state = ACPI_BUTTON_LID_INIT_OPEN; +static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; static unsigned long lid_report_interval __read_mostly = 500; module_param(lid_report_interval, ulong, 0644); @@ -376,6 +377,9 @@ static void acpi_lid_initialize_state(struct acpi_device *device) case ACPI_BUTTON_LID_INIT_OPEN: (void)acpi_lid_notify_state(device, 1); break; + case ACPI_BUTTON_LID_INIT_METHOD: + (void)acpi_lid_update_state(device); + break; case ACPI_BUTTON_LID_INIT_IGNORE: default: break; @@ -559,6 +563,9 @@ static int param_set_lid_init_state(const char *val, struct kernel_param *kp) if (!strncmp(val, "open", sizeof("open") - 1)) { lid_init_state = ACPI_BUTTON_LID_INIT_OPEN; pr_info("Notify initial lid state as open\n"); + } else if (!strncmp(val, "method", sizeof("method") - 1)) { + lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; + pr_info("Notify initial lid state with _LID return value\n"); } else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) { lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE; pr_info("Do not notify initial lid state\n"); @@ -572,6 +579,8 @@ static int param_get_lid_init_state(char *buffer, struct kernel_param *kp) switch (lid_init_state) { case ACPI_BUTTON_LID_INIT_OPEN: return sprintf(buffer, "open"); + case ACPI_BUTTON_LID_INIT_METHOD: + return sprintf(buffer, "method"); case ACPI_BUTTON_LID_INIT_IGNORE: return sprintf(buffer, "ignore"); default: diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 3ca0729f7e0e..e5b47f032d9a 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -95,7 +95,7 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr); /* pcc mapped address + header size + offset within PCC subspace */ #define GET_PCC_VADDR(offs) (pcc_data.pcc_comm_addr + 0x8 + (offs)) -/* Check if a CPC regsiter is in PCC */ +/* Check if a CPC register is in PCC */ #define CPC_IN_PCC(cpc) ((cpc)->type == ACPI_TYPE_BUFFER && \ (cpc)->cpc_entry.reg.space_id == \ ACPI_ADR_SPACE_PLATFORM_COMM) @@ -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 edc8663b5db3..3be1433853bf 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -6,6 +6,8 @@ * * This file is released under the GPLv2. */ + +#include <linux/acpi_iort.h> #include <linux/export.h> #include <linux/init.h> #include <linux/list.h> @@ -14,6 +16,7 @@ #include <linux/rwsem.h> #include <linux/acpi.h> #include <linux/dma-mapping.h> +#include <linux/platform_device.h> #include "internal.h" @@ -176,7 +179,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) struct list_head *physnode_list; unsigned int node_id; int retval = -EINVAL; - enum dev_dma_attr attr; if (has_acpi_companion(dev)) { if (acpi_dev) { @@ -233,10 +235,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) if (!has_acpi_companion(dev)) ACPI_COMPANION_SET(dev, acpi_dev); - attr = acpi_get_dma_attr(acpi_dev); - if (attr != DEV_DMA_NOT_SUPPORTED) - acpi_dma_configure(dev, attr); - acpi_physnode_link_name(physical_node_name, node_id); retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, physical_node_name); @@ -322,6 +320,9 @@ static int acpi_platform_notify(struct device *dev) if (!adev) goto out; + if (dev->bus == &platform_bus_type) + acpi_configure_pmsi_domain(dev); + if (type && type->setup) type->setup(dev); else if (adev->handler && adev->handler->bind) 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/nfit/Kconfig b/drivers/acpi/nfit/Kconfig index dd0d53c52552..6d3351452ea2 100644 --- a/drivers/acpi/nfit/Kconfig +++ b/drivers/acpi/nfit/Kconfig @@ -12,15 +12,3 @@ config ACPI_NFIT To compile this driver as a module, choose M here: the module will be called nfit. - -config ACPI_NFIT_DEBUG - bool "NFIT DSM debug" - depends on ACPI_NFIT - depends on DYNAMIC_DEBUG - default n - help - Enabling this option causes the nfit driver to dump the - input and output buffers of _DSM operations on the ACPI0012 - device and its children. This can be very verbose, so leave - it disabled unless you are debugging a hardware / firmware - issue. diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 662036bdc65e..656acb5d7166 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -49,7 +49,16 @@ MODULE_PARM_DESC(scrub_overflow_abort, static bool disable_vendor_specific; module_param(disable_vendor_specific, bool, S_IRUGO); MODULE_PARM_DESC(disable_vendor_specific, - "Limit commands to the publicly specified set\n"); + "Limit commands to the publicly specified set"); + +static unsigned long override_dsm_mask; +module_param(override_dsm_mask, ulong, S_IRUGO); +MODULE_PARM_DESC(override_dsm_mask, "Bitmask of allowed NVDIMM DSM functions"); + +static int default_dsm_family = -1; +module_param(default_dsm_family, int, S_IRUGO); +MODULE_PARM_DESC(default_dsm_family, + "Try this DSM type first when identifying NVDIMM family"); LIST_HEAD(acpi_descs); DEFINE_MUTEX(acpi_desc_lock); @@ -175,14 +184,29 @@ static int xlat_bus_status(void *buf, unsigned int cmd, u32 status) return 0; } +static int xlat_nvdimm_status(void *buf, unsigned int cmd, u32 status) +{ + switch (cmd) { + case ND_CMD_GET_CONFIG_SIZE: + if (status >> 16 & ND_CONFIG_LOCKED) + return -EACCES; + break; + default: + break; + } + + /* all other non-zero status results in an error */ + if (status) + return -EIO; + return 0; +} + static int xlat_status(struct nvdimm *nvdimm, void *buf, unsigned int cmd, u32 status) { if (!nvdimm) return xlat_bus_status(buf, cmd, status); - if (status) - return -EIO; - return 0; + return xlat_nvdimm_status(buf, cmd, status); } int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, @@ -259,14 +283,11 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, in_buf.buffer.length = call_pkg->nd_size_in; } - if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) { - dev_dbg(dev, "%s:%s cmd: %d: func: %d input length: %d\n", - __func__, dimm_name, cmd, func, - in_buf.buffer.length); - print_hex_dump_debug("nvdimm in ", DUMP_PREFIX_OFFSET, 4, 4, + dev_dbg(dev, "%s:%s cmd: %d: func: %d input length: %d\n", + __func__, dimm_name, cmd, func, in_buf.buffer.length); + print_hex_dump_debug("nvdimm in ", DUMP_PREFIX_OFFSET, 4, 4, in_buf.buffer.pointer, min_t(u32, 256, in_buf.buffer.length), true); - } out_obj = acpi_evaluate_dsm(handle, uuid, 1, func, &in_obj); if (!out_obj) { @@ -298,13 +319,11 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, goto out; } - if (IS_ENABLED(CONFIG_ACPI_NFIT_DEBUG)) { - dev_dbg(dev, "%s:%s cmd: %s output length: %d\n", __func__, - dimm_name, cmd_name, out_obj->buffer.length); - print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4, - 4, out_obj->buffer.pointer, min_t(u32, 128, - out_obj->buffer.length), true); - } + dev_dbg(dev, "%s:%s cmd: %s output length: %d\n", __func__, dimm_name, + cmd_name, out_obj->buffer.length); + print_hex_dump_debug(cmd_name, DUMP_PREFIX_OFFSET, 4, 4, + out_obj->buffer.pointer, + min_t(u32, 128, out_obj->buffer.length), true); for (i = 0, offset = 0; i < desc->out_num; i++) { u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, buf, @@ -448,9 +467,9 @@ static bool add_memdev(struct acpi_nfit_desc *acpi_desc, INIT_LIST_HEAD(&nfit_memdev->list); memcpy(nfit_memdev->memdev, memdev, sizeof(*memdev)); list_add_tail(&nfit_memdev->list, &acpi_desc->memdevs); - dev_dbg(dev, "%s: memdev handle: %#x spa: %d dcr: %d\n", + dev_dbg(dev, "%s: memdev handle: %#x spa: %d dcr: %d flags: %#x\n", __func__, memdev->device_handle, memdev->range_index, - memdev->region_index); + memdev->region_index, memdev->flags); return true; } @@ -729,28 +748,38 @@ static void nfit_mem_init_bdw(struct acpi_nfit_desc *acpi_desc, } } -static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc, +static int __nfit_mem_init(struct acpi_nfit_desc *acpi_desc, struct acpi_nfit_system_address *spa) { struct nfit_mem *nfit_mem, *found; struct nfit_memdev *nfit_memdev; - int type = nfit_spa_type(spa); + int type = spa ? nfit_spa_type(spa) : 0; switch (type) { case NFIT_SPA_DCR: case NFIT_SPA_PM: break; default: - return 0; + if (spa) + return 0; } + /* + * This loop runs in two modes, when a dimm is mapped the loop + * adds memdev associations to an existing dimm, or creates a + * dimm. In the unmapped dimm case this loop sweeps for memdev + * instances with an invalid / zero range_index and adds those + * dimms without spa associations. + */ list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) { struct nfit_flush *nfit_flush; struct nfit_dcr *nfit_dcr; u32 device_handle; u16 dcr; - if (nfit_memdev->memdev->range_index != spa->range_index) + if (spa && nfit_memdev->memdev->range_index != spa->range_index) + continue; + if (!spa && nfit_memdev->memdev->range_index) continue; found = NULL; dcr = nfit_memdev->memdev->region_index; @@ -835,14 +864,15 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc, break; } nfit_mem_init_bdw(acpi_desc, nfit_mem, spa); - } else { + } else if (type == NFIT_SPA_PM) { /* * A single dimm may belong to multiple SPA-PM * ranges, record at least one in addition to * any SPA-DCR range. */ nfit_mem->memdev_pmem = nfit_memdev->memdev; - } + } else + nfit_mem->memdev_dcr = nfit_memdev->memdev; } return 0; @@ -866,6 +896,8 @@ static int nfit_mem_cmp(void *priv, struct list_head *_a, struct list_head *_b) static int nfit_mem_init(struct acpi_nfit_desc *acpi_desc) { struct nfit_spa *nfit_spa; + int rc; + /* * For each SPA-DCR or SPA-PMEM address range find its @@ -876,13 +908,20 @@ static int nfit_mem_init(struct acpi_nfit_desc *acpi_desc) * BDWs are optional. */ list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { - int rc; - - rc = nfit_mem_dcr_init(acpi_desc, nfit_spa->spa); + rc = __nfit_mem_init(acpi_desc, nfit_spa->spa); if (rc) return rc; } + /* + * If a DIMM has failed to be mapped into SPA there will be no + * SPA entries above. Find and register all the unmapped DIMMs + * for reporting and recovery purposes. + */ + rc = __nfit_mem_init(acpi_desc, NULL); + if (rc) + return rc; + list_sort(NULL, &acpi_desc->dimms, nfit_mem_cmp); return 0; @@ -1237,12 +1276,14 @@ static ssize_t flags_show(struct device *dev, { u16 flags = to_nfit_memdev(dev)->flags; - return sprintf(buf, "%s%s%s%s%s\n", + return sprintf(buf, "%s%s%s%s%s%s%s\n", flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save_fail " : "", flags & ACPI_NFIT_MEM_RESTORE_FAILED ? "restore_fail " : "", flags & ACPI_NFIT_MEM_FLUSH_FAILED ? "flush_fail " : "", flags & ACPI_NFIT_MEM_NOT_ARMED ? "not_armed " : "", - flags & ACPI_NFIT_MEM_HEALTH_OBSERVED ? "smart_event " : ""); + flags & ACPI_NFIT_MEM_HEALTH_OBSERVED ? "smart_event " : "", + flags & ACPI_NFIT_MEM_MAP_FAILED ? "map_fail " : "", + flags & ACPI_NFIT_MEM_HEALTH_ENABLED ? "smart_notify " : ""); } static DEVICE_ATTR_RO(flags); @@ -1290,8 +1331,16 @@ static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj, struct device *dev = container_of(kobj, struct device, kobj); struct nvdimm *nvdimm = to_nvdimm(dev); - if (!to_nfit_dcr(dev)) + if (!to_nfit_dcr(dev)) { + /* Without a dcr only the memdev attributes can be surfaced */ + if (a == &dev_attr_handle.attr || a == &dev_attr_phys_id.attr + || a == &dev_attr_flags.attr + || a == &dev_attr_family.attr + || a == &dev_attr_dsm_mask.attr) + return a->mode; return 0; + } + if (a == &dev_attr_format1.attr && num_nvdimm_formats(nvdimm) <= 1) return 0; return a->mode; @@ -1368,6 +1417,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, unsigned long dsm_mask; const u8 *uuid; int i; + int family = -1; /* nfit test assumes 1:1 relationship between commands and dsms */ nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en; @@ -1398,11 +1448,14 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, */ for (i = NVDIMM_FAMILY_INTEL; i <= NVDIMM_FAMILY_MSFT; i++) if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1)) - break; + if (family < 0 || i == default_dsm_family) + family = i; /* limit the supported commands to those that are publicly documented */ - nfit_mem->family = i; - if (nfit_mem->family == NVDIMM_FAMILY_INTEL) { + nfit_mem->family = family; + if (override_dsm_mask && !disable_vendor_specific) + dsm_mask = override_dsm_mask; + else if (nfit_mem->family == NVDIMM_FAMILY_INTEL) { dsm_mask = 0x3fe; if (disable_vendor_specific) dsm_mask &= ~(1 << ND_CMD_VENDOR); @@ -1462,6 +1515,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) { struct acpi_nfit_flush_address *flush; unsigned long flags = 0, cmd_mask; + struct nfit_memdev *nfit_memdev; u32 device_handle; u16 mem_flags; @@ -1473,11 +1527,22 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) } if (nfit_mem->bdw && nfit_mem->memdev_pmem) - flags |= NDD_ALIASING; + set_bit(NDD_ALIASING, &flags); + + /* collate flags across all memdevs for this dimm */ + list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) { + struct acpi_nfit_memory_map *dimm_memdev; + + dimm_memdev = __to_nfit_memdev(nfit_mem); + if (dimm_memdev->device_handle + != nfit_memdev->memdev->device_handle) + continue; + dimm_memdev->flags |= nfit_memdev->memdev->flags; + } mem_flags = __to_nfit_memdev(nfit_mem)->flags; if (mem_flags & ACPI_NFIT_MEM_NOT_ARMED) - flags |= NDD_UNARMED; + set_bit(NDD_UNARMED, &flags); rc = acpi_nfit_add_dimm(acpi_desc, nfit_mem, device_handle); if (rc) @@ -1507,12 +1572,13 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) if ((mem_flags & ACPI_NFIT_MEM_FAILED_MASK) == 0) continue; - dev_info(acpi_desc->dev, "%s flags:%s%s%s%s\n", + dev_info(acpi_desc->dev, "%s flags:%s%s%s%s%s\n", nvdimm_name(nvdimm), mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? " save_fail" : "", mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? " restore_fail":"", mem_flags & ACPI_NFIT_MEM_FLUSH_FAILED ? " flush_fail" : "", - mem_flags & ACPI_NFIT_MEM_NOT_ARMED ? " not_armed" : ""); + mem_flags & ACPI_NFIT_MEM_NOT_ARMED ? " not_armed" : "", + mem_flags & ACPI_NFIT_MEM_MAP_FAILED ? " map_fail" : ""); } @@ -1617,7 +1683,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 */ @@ -1779,8 +1849,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, mmio_flush_range((void __force *) mmio->addr.aperture + offset, c); - memcpy_from_pmem(iobuf + copied, - mmio->addr.aperture + offset, c); + memcpy(iobuf + copied, mmio->addr.aperture + offset, c); } copied += c; @@ -2521,6 +2590,7 @@ static void acpi_nfit_scrub(struct work_struct *work) acpi_nfit_register_region(acpi_desc, nfit_spa); } } + acpi_desc->init_complete = 1; list_for_each_entry(nfit_spa, &acpi_desc->spas, list) acpi_nfit_async_scrub(acpi_desc, nfit_spa); @@ -2543,7 +2613,8 @@ static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc) return rc; } - queue_work(nfit_wq, &acpi_desc->work); + if (!acpi_desc->cancel) + queue_work(nfit_wq, &acpi_desc->work); return 0; } @@ -2589,32 +2660,11 @@ static int acpi_nfit_desc_init_scrub_attr(struct acpi_nfit_desc *acpi_desc) return 0; } -static void acpi_nfit_destruct(void *data) +static void acpi_nfit_unregister(void *data) { struct acpi_nfit_desc *acpi_desc = data; - struct device *bus_dev = to_nvdimm_bus_dev(acpi_desc->nvdimm_bus); - /* - * Destruct under acpi_desc_lock so that nfit_handle_mce does not - * race teardown - */ - mutex_lock(&acpi_desc_lock); - acpi_desc->cancel = 1; - /* - * Bounce the nvdimm bus lock to make sure any in-flight - * acpi_nfit_ars_rescan() submissions have had a chance to - * either submit or see ->cancel set. - */ - device_lock(bus_dev); - device_unlock(bus_dev); - - flush_workqueue(nfit_wq); - if (acpi_desc->scrub_count_state) - sysfs_put(acpi_desc->scrub_count_state); nvdimm_bus_unregister(acpi_desc->nvdimm_bus); - acpi_desc->nvdimm_bus = NULL; - list_del(&acpi_desc->list); - mutex_unlock(&acpi_desc_lock); } int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *data, acpi_size sz) @@ -2632,7 +2682,7 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *data, acpi_size sz) if (!acpi_desc->nvdimm_bus) return -ENOMEM; - rc = devm_add_action_or_reset(dev, acpi_nfit_destruct, + rc = devm_add_action_or_reset(dev, acpi_nfit_unregister, acpi_desc); if (rc) return rc; @@ -2724,6 +2774,13 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) device_lock(dev); device_unlock(dev); + /* bounce the init_mutex to make init_complete valid */ + mutex_lock(&acpi_desc->init_mutex); + if (acpi_desc->cancel || acpi_desc->init_complete) { + mutex_unlock(&acpi_desc->init_mutex); + return 0; + } + /* * Scrub work could take 10s of seconds, userspace may give up so we * need to be interruptible while waiting. @@ -2731,6 +2788,7 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) INIT_WORK_ONSTACK(&flush.work, flush_probe); COMPLETION_INITIALIZER_ONSTACK(flush.cmp); queue_work(nfit_wq, &flush.work); + mutex_unlock(&acpi_desc->init_mutex); rc = wait_for_completion_interruptible(&flush.cmp); cancel_work_sync(&flush.work); @@ -2767,10 +2825,12 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc) if (work_busy(&acpi_desc->work)) return -EBUSY; - if (acpi_desc->cancel) + mutex_lock(&acpi_desc->init_mutex); + if (acpi_desc->cancel) { + mutex_unlock(&acpi_desc->init_mutex); return 0; + } - mutex_lock(&acpi_desc->init_mutex); list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { struct acpi_nfit_system_address *spa = nfit_spa->spa; @@ -2814,6 +2874,40 @@ void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev) } EXPORT_SYMBOL_GPL(acpi_nfit_desc_init); +static void acpi_nfit_put_table(void *table) +{ + acpi_put_table(table); +} + +void acpi_nfit_shutdown(void *data) +{ + struct acpi_nfit_desc *acpi_desc = data; + struct device *bus_dev = to_nvdimm_bus_dev(acpi_desc->nvdimm_bus); + + /* + * Destruct under acpi_desc_lock so that nfit_handle_mce does not + * race teardown + */ + mutex_lock(&acpi_desc_lock); + list_del(&acpi_desc->list); + mutex_unlock(&acpi_desc_lock); + + mutex_lock(&acpi_desc->init_mutex); + acpi_desc->cancel = 1; + mutex_unlock(&acpi_desc->init_mutex); + + /* + * Bounce the nvdimm bus lock to make sure any in-flight + * acpi_nfit_ars_rescan() submissions have had a chance to + * either submit or see ->cancel set. + */ + device_lock(bus_dev); + device_unlock(bus_dev); + + flush_workqueue(nfit_wq); +} +EXPORT_SYMBOL_GPL(acpi_nfit_shutdown); + static int acpi_nfit_add(struct acpi_device *adev) { struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -2830,6 +2924,10 @@ static int acpi_nfit_add(struct acpi_device *adev) dev_dbg(dev, "failed to find NFIT at startup\n"); return 0; } + + rc = devm_add_action_or_reset(dev, acpi_nfit_put_table, tbl); + if (rc) + return rc; sz = tbl->length; acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL); @@ -2857,12 +2955,15 @@ static int acpi_nfit_add(struct acpi_device *adev) rc = acpi_nfit_init(acpi_desc, (void *) tbl + sizeof(struct acpi_table_nfit), sz - sizeof(struct acpi_table_nfit)); - return rc; + + if (rc) + return rc; + return devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc); } static int acpi_nfit_remove(struct acpi_device *adev) { - /* see acpi_nfit_destruct */ + /* see acpi_nfit_unregister */ return 0; } diff --git a/drivers/acpi/nfit/mce.c b/drivers/acpi/nfit/mce.c index 3ba1c3472cf9..fd86bec98dea 100644 --- a/drivers/acpi/nfit/mce.c +++ b/drivers/acpi/nfit/mce.c @@ -26,7 +26,7 @@ static int nfit_handle_mce(struct notifier_block *nb, unsigned long val, struct nfit_spa *nfit_spa; /* We only care about memory errors */ - if (!(mce->status & MCACOD)) + if (!mce_is_memory_error(mce)) return NOTIFY_DONE; /* diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index fc29c2e9832e..58fb7d68e04a 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -37,7 +37,7 @@ #define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \ | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \ - | ACPI_NFIT_MEM_NOT_ARMED) + | ACPI_NFIT_MEM_NOT_ARMED | ACPI_NFIT_MEM_MAP_FAILED) enum nfit_uuids { /* for simplicity alias the uuid index with the family id */ @@ -163,6 +163,7 @@ struct acpi_nfit_desc { unsigned int scrub_count; unsigned int scrub_mode; unsigned int cancel:1; + unsigned int init_complete:1; unsigned long dimm_cmd_force_en; unsigned long bus_cmd_force_en; int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa, @@ -238,6 +239,7 @@ static inline struct acpi_nfit_desc *to_acpi_desc( const u8 *to_nfit_uuid(enum nfit_uuids id); int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *nfit, acpi_size sz); +void acpi_nfit_shutdown(void *data); void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event); void __acpi_nvdimm_notify(struct device *dev, u32 event); int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index 2944353253ed..a4e8432fc2fb 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -54,6 +54,7 @@ static struct mcfg_fixup mcfg_quirks[] = { #define QCOM_ECAM32(seg) \ { "QCOM ", "QDF2432 ", 1, seg, MCFG_BUS_ANY, &pci_32b_ops } + QCOM_ECAM32(0), QCOM_ECAM32(1), QCOM_ECAM32(2), @@ -68,6 +69,7 @@ static struct mcfg_fixup mcfg_quirks[] = { { "HISI ", table_id, 0, (seg) + 1, MCFG_BUS_ANY, ops }, \ { "HISI ", table_id, 0, (seg) + 2, MCFG_BUS_ANY, ops }, \ { "HISI ", table_id, 0, (seg) + 3, MCFG_BUS_ANY, ops } + HISI_QUAD_DOM("HIP05 ", 0, &hisi_pcie_ops), HISI_QUAD_DOM("HIP06 ", 0, &hisi_pcie_ops), HISI_QUAD_DOM("HIP07 ", 0, &hisi_pcie_ops), @@ -77,6 +79,7 @@ static struct mcfg_fixup mcfg_quirks[] = { #define THUNDER_PEM_RES(addr, node) \ DEFINE_RES_MEM((addr) + ((u64) (node) << 44), 0x39 * SZ_16M) + #define THUNDER_PEM_QUIRK(rev, node) \ { "CAVIUM", "THUNDERX", rev, 4 + (10 * (node)), MCFG_BUS_ANY, \ &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x88001f000000UL, node) }, \ @@ -90,13 +93,16 @@ static struct mcfg_fixup mcfg_quirks[] = { &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x894057000000UL, node) }, \ { "CAVIUM", "THUNDERX", rev, 9 + (10 * (node)), MCFG_BUS_ANY, \ &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x89808f000000UL, node) } - /* SoC pass2.x */ - THUNDER_PEM_QUIRK(1, 0), - THUNDER_PEM_QUIRK(1, 1), #define THUNDER_ECAM_QUIRK(rev, seg) \ { "CAVIUM", "THUNDERX", rev, seg, MCFG_BUS_ANY, \ &pci_thunder_ecam_ops } + + /* SoC pass2.x */ + THUNDER_PEM_QUIRK(1, 0), + THUNDER_PEM_QUIRK(1, 1), + THUNDER_ECAM_QUIRK(1, 10), + /* SoC pass1.x */ THUNDER_PEM_QUIRK(2, 0), /* off-chip devices */ THUNDER_PEM_QUIRK(2, 1), /* off-chip devices */ @@ -112,9 +118,11 @@ static struct mcfg_fixup mcfg_quirks[] = { #define XGENE_V1_ECAM_MCFG(rev, seg) \ {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \ &xgene_v1_pcie_ecam_ops } + #define XGENE_V2_ECAM_MCFG(rev, seg) \ {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \ &xgene_v2_pcie_ecam_ops } + /* X-Gene SoC with v1 PCIe controller */ XGENE_V1_ECAM_MCFG(1, 0), XGENE_V1_ECAM_MCFG(1, 1), 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..1a76c784cd4c 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 @@ -28,97 +27,97 @@ static struct pmic_table power_table[] = { .address = 0x00, .reg = 0x13, .bit = 0x05, - }, + }, /* ALD1 */ { .address = 0x04, .reg = 0x13, .bit = 0x06, - }, + }, /* ALD2 */ { .address = 0x08, .reg = 0x13, .bit = 0x07, - }, + }, /* ALD3 */ { .address = 0x0c, .reg = 0x12, .bit = 0x03, - }, + }, /* DLD1 */ { .address = 0x10, .reg = 0x12, .bit = 0x04, - }, + }, /* DLD2 */ { .address = 0x14, .reg = 0x12, .bit = 0x05, - }, + }, /* DLD3 */ { .address = 0x18, .reg = 0x12, .bit = 0x06, - }, + }, /* DLD4 */ { .address = 0x1c, .reg = 0x12, .bit = 0x00, - }, + }, /* ELD1 */ { .address = 0x20, .reg = 0x12, .bit = 0x01, - }, + }, /* ELD2 */ { .address = 0x24, .reg = 0x12, .bit = 0x02, - }, + }, /* ELD3 */ { .address = 0x28, .reg = 0x13, .bit = 0x02, - }, + }, /* FLD1 */ { .address = 0x2c, .reg = 0x13, .bit = 0x03, - }, + }, /* FLD2 */ { .address = 0x30, .reg = 0x13, .bit = 0x04, - }, + }, /* FLD3 */ { - .address = 0x38, + .address = 0x34, .reg = 0x10, .bit = 0x03, - }, + }, /* BUC1 */ { - .address = 0x3c, + .address = 0x38, .reg = 0x10, .bit = 0x06, - }, + }, /* BUC2 */ { - .address = 0x40, + .address = 0x3c, .reg = 0x10, .bit = 0x05, - }, + }, /* BUC3 */ { - .address = 0x44, + .address = 0x40, .reg = 0x10, .bit = 0x04, - }, + }, /* BUC4 */ { - .address = 0x48, + .address = 0x44, .reg = 0x10, .bit = 0x01, - }, + }, /* BUC5 */ { - .address = 0x4c, + .address = 0x48, .reg = 0x10, .bit = 0x00 - }, + }, /* BUC6 */ }; /* TMP0 - TMP5 are the same, all from GPADC */ @@ -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; + u8 buf[2]; - gpadc_chan = iio_channel_get(NULL, "axp288-system-temp"); - if (IS_ERR_OR_NULL(gpadc_chan)) - return -EACCES; - - 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..3a6c9b741b23 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; @@ -863,6 +864,16 @@ void acpi_resume_power_resources(void) mutex_unlock(&resource->resource_lock); } + + mutex_unlock(&power_resource_list_lock); +} + +void acpi_turn_off_unused_power_resources(void) +{ + struct acpi_power_resource *resource; + + mutex_lock(&power_resource_list_lock); + list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) { int result, state; diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 9d5f0c7ed3f7..8697a82bd465 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -251,6 +251,9 @@ static int __acpi_processor_start(struct acpi_device *device) if (ACPI_SUCCESS(status)) return 0; + result = -ENODEV; + acpi_pss_perf_exit(pr, device); + err_power_exit: acpi_processor_power_exit(pr); return result; @@ -259,11 +262,16 @@ err_power_exit: static int acpi_processor_start(struct device *dev) { struct acpi_device *device = ACPI_COMPANION(dev); + int ret; if (!device) return -ENODEV; - return __acpi_processor_start(device); + /* Protect against concurrent CPU hotplug operations */ + get_online_cpus(); + ret = __acpi_processor_start(device); + put_online_cpus(); + return ret; } static int acpi_processor_stop(struct device *dev) diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index a12f96cc93ff..3de34633f7f9 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -62,8 +62,8 @@ struct acpi_processor_throttling_arg { #define THROTTLING_POSTCHANGE (2) static int acpi_processor_get_throttling(struct acpi_processor *pr); -int acpi_processor_set_throttling(struct acpi_processor *pr, - int state, bool force); +static int __acpi_processor_set_throttling(struct acpi_processor *pr, + int state, bool force, bool direct); static int acpi_processor_update_tsd_coord(void) { @@ -891,7 +891,8 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid throttling state, reset\n")); state = 0; - ret = acpi_processor_set_throttling(pr, state, true); + ret = __acpi_processor_set_throttling(pr, state, true, + true); if (ret) return ret; } @@ -901,36 +902,31 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr) return 0; } -static int acpi_processor_get_throttling(struct acpi_processor *pr) +static long __acpi_processor_get_throttling(void *data) { - cpumask_var_t saved_mask; - int ret; + struct acpi_processor *pr = data; + + return pr->throttling.acpi_processor_get_throttling(pr); +} +static int acpi_processor_get_throttling(struct acpi_processor *pr) +{ if (!pr) return -EINVAL; if (!pr->flags.throttling) return -ENODEV; - if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL)) - return -ENOMEM; - /* - * Migrate task to the cpu pointed by pr. + * This is either called from the CPU hotplug callback of + * processor_driver or via the ACPI probe function. In the latter + * case the CPU is not guaranteed to be online. Both call sites are + * protected against CPU hotplug. */ - cpumask_copy(saved_mask, ¤t->cpus_allowed); - /* FIXME: use work_on_cpu() */ - if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { - /* Can't migrate to the target pr->id CPU. Exit */ - free_cpumask_var(saved_mask); + if (!cpu_online(pr->id)) return -ENODEV; - } - ret = pr->throttling.acpi_processor_get_throttling(pr); - /* restore the previous state */ - set_cpus_allowed_ptr(current, saved_mask); - free_cpumask_var(saved_mask); - return ret; + return work_on_cpu(pr->id, __acpi_processor_get_throttling, pr); } static int acpi_processor_get_fadt_info(struct acpi_processor *pr) @@ -1080,8 +1076,15 @@ static long acpi_processor_throttling_fn(void *data) arg->target_state, arg->force); } -int acpi_processor_set_throttling(struct acpi_processor *pr, - int state, bool force) +static int call_on_cpu(int cpu, long (*fn)(void *), void *arg, bool direct) +{ + if (direct) + return fn(arg); + return work_on_cpu(cpu, fn, arg); +} + +static int __acpi_processor_set_throttling(struct acpi_processor *pr, + int state, bool force, bool direct) { int ret = 0; unsigned int i; @@ -1130,7 +1133,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, arg.pr = pr; arg.target_state = state; arg.force = force; - ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg); + ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, &arg, + direct); } else { /* * When the T-state coordination is SW_ALL or HW_ALL, @@ -1163,8 +1167,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, arg.pr = match_pr; arg.target_state = state; arg.force = force; - ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, - &arg); + ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, + &arg, direct); } } /* @@ -1182,6 +1186,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, return ret; } +int acpi_processor_set_throttling(struct acpi_processor *pr, int state, + bool force) +{ + return __acpi_processor_set_throttling(pr, state, force, false); +} + int acpi_processor_get_throttling_info(struct acpi_processor *pr) { int result = 0; 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..3a10d7573477 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 { @@ -1373,20 +1363,25 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) * @dev: The pointer to the device * @attr: device dma attributes */ -void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) +int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) { const struct iommu_ops *iommu; + u64 size; iort_set_dma_mask(dev); iommu = iort_iommu_configure(dev); + if (IS_ERR(iommu) && PTR_ERR(iommu) == -EPROBE_DEFER) + return -EPROBE_DEFER; + size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); /* * Assume dma valid range starts at 0 and covers the whole * coherent_dma_mask. */ - arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu, - attr == DEV_DMA_COHERENT); + arch_setup_dma_ops(dev, 0, size, iommu, attr == DEV_DMA_COHERENT); + + return 0; } EXPORT_SYMBOL_GPL(acpi_dma_configure); @@ -1850,6 +1845,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 +1854,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/sleep.c b/drivers/acpi/sleep.c index a4327af676fe..097d630ab886 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -474,6 +474,7 @@ static void acpi_pm_start(u32 acpi_state) */ static void acpi_pm_end(void) { + acpi_turn_off_unused_power_resources(); acpi_scan_lock_release(); /* * This is necessary in case acpi_pm_finish() is not called during a diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h index a9cc34e663f9..a82ff74faf7a 100644 --- a/drivers/acpi/sleep.h +++ b/drivers/acpi/sleep.h @@ -6,6 +6,7 @@ extern struct list_head acpi_wakeup_device_list; extern struct mutex acpi_device_lock; extern void acpi_resume_power_resources(void); +extern void acpi_turn_off_unused_power_resources(void); static inline acpi_status acpi_set_waking_vector(u32 wakeup_address) { diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index cf05ae973381..e414fabf7315 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -333,14 +333,17 @@ static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj, container_of(bin_attr, struct acpi_table_attr, attr); struct acpi_table_header *table_header = NULL; acpi_status status; + ssize_t rc; status = acpi_get_table(table_attr->name, table_attr->instance, &table_header); if (ACPI_FAILURE(status)) return -ENODEV; - return memory_read_from_buffer(buf, count, &offset, - table_header, table_header->length); + rc = memory_read_from_buffer(buf, count, &offset, table_header, + table_header->length); + acpi_put_table(table_header); + return rc; } static int acpi_table_attr_init(struct kobject *tables_obj, @@ -921,7 +924,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 +938,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..ff425390bfa8 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, @@ -556,7 +540,7 @@ void __init acpi_table_upgrade(void) * But it's not enough on X86 because ioremap will * complain later (used by acpi_os_map_memory) that the pages * that should get mapped are not marked "reserved". - * Both memblock_reserve and e820_add_region (via arch_reserve_mem_area) + * Both memblock_reserve and e820__range_add (via arch_reserve_mem_area) * works fine. */ memblock_reserve(acpi_tables_addr, all_tables_size); 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. diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c new file mode 100644 index 000000000000..bd86b809c848 --- /dev/null +++ b/drivers/acpi/x86/utils.c @@ -0,0 +1,90 @@ +/* + * X86 ACPI Utility Functions + * + * 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. + */ + +#include <linux/acpi.h> +#include <asm/cpu_device_id.h> +#include <asm/intel-family.h> +#include "../internal.h" + +/* + * Some ACPI devices are hidden (status == 0x0) in recent BIOS-es because + * some recent Windows drivers bind to one device but poke at multiple + * devices at the same time, so the others get hidden. + * We work around this by always reporting ACPI_STA_DEFAULT for these + * devices. Note this MUST only be done for devices where this is safe. + * + * This forcing of devices to be present is limited to specific CPU (SoC) + * models both to avoid potentially causing trouble on other models and + * because some HIDs are re-used on different SoCs for completely + * different devices. + */ +struct always_present_id { + struct acpi_device_id hid[2]; + struct x86_cpu_id cpu_ids[2]; + const char *uid; +}; + +#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } + +#define ENTRY(hid, uid, cpu_models) { \ + { { hid, }, {} }, \ + { cpu_models, {} }, \ + uid, \ +} + +static const struct always_present_id always_present_ids[] = { + /* + * Bay / Cherry Trail PWM directly poked by GPU driver in win10, + * but Linux uses a separate PWM driver, harmless if not used. + */ + ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT1)), + ENTRY("80862288", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT)), + /* + * The INT0002 device is necessary to clear wakeup interrupt sources + * on Cherry Trail devices, without it we get nobody cared IRQ msgs. + */ + ENTRY("INT0002", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT)), +}; + +bool acpi_device_always_present(struct acpi_device *adev) +{ + u32 *status = (u32 *)&adev->status; + u32 old_status = *status; + bool ret = false; + unsigned int i; + + /* acpi_match_device_ids checks status, so set it to default */ + *status = ACPI_STA_DEFAULT; + for (i = 0; i < ARRAY_SIZE(always_present_ids); i++) { + if (acpi_match_device_ids(adev, always_present_ids[i].hid)) + continue; + + if (!adev->pnp.unique_id || + strcmp(adev->pnp.unique_id, always_present_ids[i].uid)) + continue; + + if (!x86_match_cpu(always_present_ids[i].cpu_ids)) + continue; + + if (old_status != ACPI_STA_DEFAULT) /* Log only once */ + dev_info(&adev->dev, + "Device [%s] is in always present list\n", + adev->pnp.bus_id); + + ret = true; + break; + } + *status = old_status; + + return ret; +} |