Commit 58a02287 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ACPI updates from Rafael Wysocki:
 "These fix ACPICA issues related to the handling of module-level AML,
  fix an ordering issue during ACPI initialization, update ACPICA to
  upstream revision 20181003 (including fixes mostly), fix issues with
  system-wide suspend/resume related to the ACPI driver for Intel SoCs
  (LPSS), fix device enumeration issues on boards with Dollar Cove or
  Whiskey Cove Intel PMICs, prevent ACPICA from calling ktime_get() in
  unsuitable conditions, update a few drivers and clean up some code in
  several places.

  Specifics:

   - Fix ACPICA issues related to the handling of module-level AML and
     make the ACPI initialization code parse ECDT before loading the
     definition block tables (Erik Schmauss).

   - Update ACPICA to upstream revision 20181003 including fixes related
     to the ill-defined "generic serial bus" and the handling of the
     _REG object (Bob Moore).

   - Fix some issues with system-wide suspend/resume on Intel BYT/CHT
     related to the handling of I2C controllers in the ACPI LPSS driver
     for Intel SoCs (Hans de Goede).

   - Modify the ACPI namespace scanning code to enumerate INT33FE HID
     devices as platform devices with I2C resources to avoid device
     enumeration problems on boards with Dollar Cove or Whiskey Cove
     Intel PMICs (Hans de Goede).

   - Prevent ACPICA from using ktime_get() during early resume from
     system-wide suspend before resuming the timekeeping which generally
     is unsafe and triggers a warning from the timekeeping code (Bart
     Van Assche).

   - Add low-level real time clock support to the ACPI Time and Aalarm
     Device (TAD) driver (Rafael Wysocki).

   - Fix the ACPI SBS driver to avoid GPE storms on MacBook Pro and
     Oopses when removing modules (Ronald Tschalär).

   - Fix the ACPI PPTT parsing code to handle architecturally unknown
     cache types properly (Jeffrey Hugo).

   - Fix initialization issue in the ACPI processor driver (Dou Liyang).

   - Clean up the code in several places (Andy Shevchenko, Bartlomiej
     Zolnierkiewicz, David Arcari, zhong jiang)"

* tag 'acpi-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (33 commits)
  ACPI / scan: Create platform device for INT33FE ACPI nodes
  ACPI / OSL: Use 'jiffies' as the time bassis for acpi_os_get_timer()
  ACPI: probe ECDT before loading AML tables regardless of module-level code flag
  ACPICA: Remove acpi_gbl_group_module_level_code and only use acpi_gbl_execute_tables_as_methods instead
  ACPICA: AML Parser: fix parse loop to correctly skip erroneous extended opcodes
  ACPICA: AML interpreter: add region addresses in global list during initialization
  ACPI: TAD: Add low-level support for real time capability
  ACPI: remove redundant 'default n' from Kconfig
  ACPI / SBS: Fix rare oops when removing modules
  ACPI / SBS: Fix GPE storm on recent MacBookPro's
  ACPI/PPTT: Handle architecturally unknown cache types
  drivers: base: cacheinfo: Do not populate sysfs for unknown cache types
  ACPICA: Update version to 20181003
  ACPICA: Never run _REG on system_memory and system_IO
  ACPICA: Split large interpreter file
  ACPICA: Update for field unit access
  ACPICA: Rename some of the Field Attribute defines
  ACPICA: Update for generic_serial_bus and attrib_raw_process_bytes protocol
  ACPI / processor: Fix the return value of acpi_processor_ids_walk()
  ACPI / LPSS: Resume BYT/CHT I2C controllers from resume_noirq
  ...
parents 12dd08fa 0a1875ad
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -138,7 +138,6 @@ config ACPI_REV_OVERRIDE_POSSIBLE

config ACPI_EC_DEBUGFS
	tristate "EC read/write access through /sys/kernel/debug/ec"
	default n
	help
	  Say N to disable Embedded Controller /sys/kernel/debug interface

@@ -283,7 +282,6 @@ config ACPI_PROCESSOR
config ACPI_IPMI
	tristate "IPMI"
	depends on IPMI_HANDLER
	default n
	help
	  This driver enables the ACPI to access the BMC controller. And it
	  uses the IPMI request/response message to communicate with BMC
@@ -361,7 +359,6 @@ config ACPI_TABLE_UPGRADE

config ACPI_DEBUG
	bool "Debug Statements"
	default n
	help
	  The ACPI subsystem can produce debug output.  Saying Y enables this
	  output and increases the kernel size by around 50K.
@@ -374,7 +371,6 @@ config ACPI_DEBUG
config ACPI_PCI_SLOT
	bool "PCI slot detection driver"
	depends on SYSFS
	default n
	help
	  This driver creates entries in /sys/bus/pci/slots/ for all PCI
	  slots in the system.  This can help correlate PCI bus addresses,
@@ -436,7 +432,6 @@ config ACPI_HED
config ACPI_CUSTOM_METHOD
	tristate "Allow ACPI methods to be inserted/replaced at run time"
	depends on DEBUG_FS
	default n
	help
	  This debug facility allows ACPI AML methods to be inserted and/or
	  replaced without rebooting the system. For details refer to:
@@ -481,7 +476,6 @@ config ACPI_EXTLOG
	tristate "Extended Error Log support"
	depends on X86_MCE && X86_LOCAL_APIC && EDAC
	select UEFI_CPER
	default n
	help
	  Certain usages such as Predictive Failure Analysis (PFA) require
	  more information about the error than what can be described in
+103 −15
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/platform_data/clk-lpss.h>
#include <linux/platform_data/x86/pmc_atom.h>
@@ -83,6 +84,7 @@ struct lpss_device_desc {
	size_t prv_size_override;
	struct property_entry *properties;
	void (*setup)(struct lpss_private_data *pdata);
	bool resume_from_noirq;
};

static const struct lpss_device_desc lpss_dma_desc = {
@@ -99,6 +101,9 @@ struct lpss_private_data {
	u32 prv_reg_ctx[LPSS_PRV_REG_COUNT];
};

/* Devices which need to be in D3 before lpss_iosf_enter_d3_state() proceeds */
static u32 pmc_atom_d3_mask = 0xfe000ffe;

/* LPSS run time quirks */
static unsigned int lpss_quirks;

@@ -175,6 +180,21 @@ static void byt_pwm_setup(struct lpss_private_data *pdata)

static void byt_i2c_setup(struct lpss_private_data *pdata)
{
	const char *uid_str = acpi_device_uid(pdata->adev);
	acpi_handle handle = pdata->adev->handle;
	unsigned long long shared_host = 0;
	acpi_status status;
	long uid = 0;

	/* Expected to always be true, but better safe then sorry */
	if (uid_str)
		uid = simple_strtol(uid_str, NULL, 10);

	/* Detect I2C bus shared with PUNIT and ignore its d3 status */
	status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
	if (ACPI_SUCCESS(status) && shared_host && uid)
		pmc_atom_d3_mask &= ~(BIT_LPSS2_F1_I2C1 << (uid - 1));

	lpss_deassert_reset(pdata);

	if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset))
@@ -274,12 +294,14 @@ static const struct lpss_device_desc byt_i2c_dev_desc = {
	.flags = LPSS_CLK | LPSS_SAVE_CTX,
	.prv_offset = 0x800,
	.setup = byt_i2c_setup,
	.resume_from_noirq = true,
};

static const struct lpss_device_desc bsw_i2c_dev_desc = {
	.flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
	.prv_offset = 0x800,
	.setup = byt_i2c_setup,
	.resume_from_noirq = true,
};

static const struct lpss_device_desc bsw_spi_dev_desc = {
@@ -327,9 +349,11 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
	{ "INT33FC", },

	/* Braswell LPSS devices */
	{ "80862286", LPSS_ADDR(lpss_dma_desc) },
	{ "80862288", LPSS_ADDR(bsw_pwm_dev_desc) },
	{ "8086228A", LPSS_ADDR(bsw_uart_dev_desc) },
	{ "8086228E", LPSS_ADDR(bsw_spi_dev_desc) },
	{ "808622C0", LPSS_ADDR(lpss_dma_desc) },
	{ "808622C1", LPSS_ADDR(bsw_i2c_dev_desc) },

	/* Broadwell LPSS devices */
@@ -451,26 +475,35 @@ struct lpss_device_links {
 */
static const struct lpss_device_links lpss_device_links[] = {
	{"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME},
	{"808622C1", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
	{"80860F41", "5", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
};

static bool hid_uid_match(const char *hid1, const char *uid1,
static bool hid_uid_match(struct acpi_device *adev,
			  const char *hid2, const char *uid2)
{
	return !strcmp(hid1, hid2) && uid1 && uid2 && !strcmp(uid1, uid2);
	const char *hid1 = acpi_device_hid(adev);
	const char *uid1 = acpi_device_uid(adev);

	if (strcmp(hid1, hid2))
		return false;

	if (!uid2)
		return true;

	return uid1 && !strcmp(uid1, uid2);
}

static bool acpi_lpss_is_supplier(struct acpi_device *adev,
				  const struct lpss_device_links *link)
{
	return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
			     link->supplier_hid, link->supplier_uid);
	return hid_uid_match(adev, link->supplier_hid, link->supplier_uid);
}

static bool acpi_lpss_is_consumer(struct acpi_device *adev,
				  const struct lpss_device_links *link)
{
	return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
			     link->consumer_hid, link->consumer_uid);
	return hid_uid_match(adev, link->consumer_hid, link->consumer_uid);
}

struct hid_uid {
@@ -486,18 +519,23 @@ static int match_hid_uid(struct device *dev, void *data)
	if (!adev)
		return 0;

	return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
			     id->hid, id->uid);
	return hid_uid_match(adev, id->hid, id->uid);
}

static struct device *acpi_lpss_find_device(const char *hid, const char *uid)
{
	struct device *dev;

	struct hid_uid data = {
		.hid = hid,
		.uid = uid,
	};

	return bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid);
	dev = bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid);
	if (dev)
		return dev;

	return bus_find_device(&pci_bus_type, NULL, &data, match_hid_uid);
}

static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle)
@@ -892,7 +930,7 @@ static void lpss_iosf_enter_d3_state(void)
	 * Here we read the values related to LPSS power island, i.e. LPSS
	 * devices, excluding both LPSS DMA controllers, along with SCC domain.
	 */
	u32 func_dis, d3_sts_0, pmc_status, pmc_mask = 0xfe000ffe;
	u32 func_dis, d3_sts_0, pmc_status;
	int ret;

	ret = pmc_atom_read(PMC_FUNC_DIS, &func_dis);
@@ -910,7 +948,7 @@ static void lpss_iosf_enter_d3_state(void)
	 * Shutdown both LPSS DMA controllers if and only if all other devices
	 * are already in D3hot.
	 */
	pmc_status = (~(d3_sts_0 | func_dis)) & pmc_mask;
	pmc_status = (~(d3_sts_0 | func_dis)) & pmc_atom_d3_mask;
	if (pmc_status)
		goto exit;

@@ -1004,7 +1042,7 @@ static int acpi_lpss_resume(struct device *dev)
}

#ifdef CONFIG_PM_SLEEP
static int acpi_lpss_suspend_late(struct device *dev)
static int acpi_lpss_do_suspend_late(struct device *dev)
{
	int ret;

@@ -1015,12 +1053,62 @@ static int acpi_lpss_suspend_late(struct device *dev)
	return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev));
}

static int acpi_lpss_resume_early(struct device *dev)
static int acpi_lpss_suspend_late(struct device *dev)
{
	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));

	if (pdata->dev_desc->resume_from_noirq)
		return 0;

	return acpi_lpss_do_suspend_late(dev);
}

static int acpi_lpss_suspend_noirq(struct device *dev)
{
	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
	int ret;

	if (pdata->dev_desc->resume_from_noirq) {
		ret = acpi_lpss_do_suspend_late(dev);
		if (ret)
			return ret;
	}

	return acpi_subsys_suspend_noirq(dev);
}

static int acpi_lpss_do_resume_early(struct device *dev)
{
	int ret = acpi_lpss_resume(dev);

	return ret ? ret : pm_generic_resume_early(dev);
}

static int acpi_lpss_resume_early(struct device *dev)
{
	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));

	if (pdata->dev_desc->resume_from_noirq)
		return 0;

	return acpi_lpss_do_resume_early(dev);
}

static int acpi_lpss_resume_noirq(struct device *dev)
{
	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
	int ret;

	ret = acpi_subsys_resume_noirq(dev);
	if (ret)
		return ret;

	if (!dev_pm_may_skip_resume(dev) && pdata->dev_desc->resume_from_noirq)
		ret = acpi_lpss_do_resume_early(dev);

	return ret;
}

#endif /* CONFIG_PM_SLEEP */

static int acpi_lpss_runtime_suspend(struct device *dev)
@@ -1050,8 +1138,8 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
		.complete = acpi_subsys_complete,
		.suspend = acpi_subsys_suspend,
		.suspend_late = acpi_lpss_suspend_late,
		.suspend_noirq = acpi_subsys_suspend_noirq,
		.resume_noirq = acpi_subsys_resume_noirq,
		.suspend_noirq = acpi_lpss_suspend_noirq,
		.resume_noirq = acpi_lpss_resume_noirq,
		.resume_early = acpi_lpss_resume_early,
		.freeze = acpi_subsys_freeze,
		.freeze_late = acpi_subsys_freeze_late,
+4 −3
Original line number Diff line number Diff line
@@ -643,7 +643,7 @@ static acpi_status __init acpi_processor_ids_walk(acpi_handle handle,

	status = acpi_get_type(handle, &acpi_type);
	if (ACPI_FAILURE(status))
		return false;
		return status;

	switch (acpi_type) {
	case ACPI_TYPE_PROCESSOR:
@@ -663,11 +663,12 @@ static acpi_status __init acpi_processor_ids_walk(acpi_handle handle,
	}

	processor_validated_ids_update(uid);
	return true;
	return AE_OK;

err:
	/* Exit on error, but don't abort the namespace walk */
	acpi_handle_info(handle, "Invalid processor object\n");
	return false;
	return AE_OK;

}

+201 −0
Original line number Diff line number Diff line
@@ -52,6 +52,201 @@ struct acpi_tad_driver_data {
	u32 capabilities;
};

struct acpi_tad_rt {
	u16 year;  /* 1900 - 9999 */
	u8 month;  /* 1 - 12 */
	u8 day;    /* 1 - 31 */
	u8 hour;   /* 0 - 23 */
	u8 minute; /* 0 - 59 */
	u8 second; /* 0 - 59 */
	u8 valid;  /* 0 (failed) or 1 (success) for reads, 0 for writes */
	u16 msec;  /* 1 - 1000 */
	s16 tz;    /* -1440 to 1440 or 2047 (unspecified) */
	u8 daylight;
	u8 padding[3]; /* must be 0 */
} __packed;

static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt)
{
	acpi_handle handle = ACPI_HANDLE(dev);
	union acpi_object args[] = {
		{ .type = ACPI_TYPE_BUFFER, },
	};
	struct acpi_object_list arg_list = {
		.pointer = args,
		.count = ARRAY_SIZE(args),
	};
	unsigned long long retval;
	acpi_status status;

	if (rt->year < 1900 || rt->year > 9999 ||
	    rt->month < 1 || rt->month > 12 ||
	    rt->hour > 23 || rt->minute > 59 || rt->second > 59 ||
	    rt->tz < -1440 || (rt->tz > 1440 && rt->tz != 2047) ||
	    rt->daylight > 3)
		return -ERANGE;

	args[0].buffer.pointer = (u8 *)rt;
	args[0].buffer.length = sizeof(*rt);

	pm_runtime_get_sync(dev);

	status = acpi_evaluate_integer(handle, "_SRT", &arg_list, &retval);

	pm_runtime_put_sync(dev);

	if (ACPI_FAILURE(status) || retval)
		return -EIO;

	return 0;
}

static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt)
{
	acpi_handle handle = ACPI_HANDLE(dev);
	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER };
	union acpi_object *out_obj;
	struct acpi_tad_rt *data;
	acpi_status status;
	int ret = -EIO;

	pm_runtime_get_sync(dev);

	status = acpi_evaluate_object(handle, "_GRT", NULL, &output);

	pm_runtime_put_sync(dev);

	if (ACPI_FAILURE(status))
		goto out_free;

	out_obj = output.pointer;
	if (out_obj->type != ACPI_TYPE_BUFFER)
		goto out_free;

	if (out_obj->buffer.length != sizeof(*rt))
		goto out_free;

	data = (struct acpi_tad_rt *)(out_obj->buffer.pointer);
	if (!data->valid)
		goto out_free;

	memcpy(rt, data, sizeof(*rt));
	ret = 0;

out_free:
	ACPI_FREE(output.pointer);
	return ret;
}

static char *acpi_tad_rt_next_field(char *s, int *val)
{
	char *p;

	p = strchr(s, ':');
	if (!p)
		return NULL;

	*p = '\0';
	if (kstrtoint(s, 10, val))
		return NULL;

	return p + 1;
}

static ssize_t time_store(struct device *dev, struct device_attribute *attr,
			  const char *buf, size_t count)
{
	struct acpi_tad_rt rt;
	char *str, *s;
	int val, ret = -ENODATA;

	str = kmemdup_nul(buf, count, GFP_KERNEL);
	if (!str)
		return -ENOMEM;

	s = acpi_tad_rt_next_field(str, &val);
	if (!s)
		goto out_free;

	rt.year = val;

	s = acpi_tad_rt_next_field(s, &val);
	if (!s)
		goto out_free;

	rt.month = val;

	s = acpi_tad_rt_next_field(s, &val);
	if (!s)
		goto out_free;

	rt.day = val;

	s = acpi_tad_rt_next_field(s, &val);
	if (!s)
		goto out_free;

	rt.hour = val;

	s = acpi_tad_rt_next_field(s, &val);
	if (!s)
		goto out_free;

	rt.minute = val;

	s = acpi_tad_rt_next_field(s, &val);
	if (!s)
		goto out_free;

	rt.second = val;

	s = acpi_tad_rt_next_field(s, &val);
	if (!s)
		goto out_free;

	rt.tz = val;

	if (kstrtoint(s, 10, &val))
		goto out_free;

	rt.daylight = val;

	rt.valid = 0;
	rt.msec = 0;
	memset(rt.padding, 0, 3);

	ret = acpi_tad_set_real_time(dev, &rt);

out_free:
	kfree(str);
	return ret ? ret : count;
}

static ssize_t time_show(struct device *dev, struct device_attribute *attr,
			 char *buf)
{
	struct acpi_tad_rt rt;
	int ret;

	ret = acpi_tad_get_real_time(dev, &rt);
	if (ret)
		return ret;

	return sprintf(buf, "%u:%u:%u:%u:%u:%u:%d:%u\n",
		       rt.year, rt.month, rt.day, rt.hour, rt.minute, rt.second,
		       rt.tz, rt.daylight);
}

static DEVICE_ATTR(time, S_IRUSR | S_IWUSR, time_show, time_store);

static struct attribute *acpi_tad_time_attrs[] = {
	&dev_attr_time.attr,
	NULL,
};
static const struct attribute_group acpi_tad_time_attr_group = {
	.attrs	= acpi_tad_time_attrs,
};

static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id,
			     u32 value)
{
@@ -448,6 +643,12 @@ static int acpi_tad_probe(struct platform_device *pdev)
			goto fail;
	}

	if (caps & ACPI_TAD_RT) {
		ret = sysfs_create_group(&dev->kobj, &acpi_tad_time_attr_group);
		if (ret)
			goto fail;
	}

	return 0;

fail:
+1 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ acpi-y += \
	exresnte.o	\
	exresolv.o	\
	exresop.o	\
	exserial.o	\
	exstore.o	\
	exstoren.o	\
	exstorob.o	\
Loading