Эх сурвалжийг харах

Merge branches 'acpi-numa', 'acpi-sysfs', 'acpi-pmic', 'acpi-soc' and 'acpi-ged'

* acpi-numa:
  ACPI / NUMA: ia64: Parse all entries of SRAT memory affinity table

* acpi-sysfs:
  ACPI: sysfs: Make ACPI GPE mask kernel parameter cover all GPEs

* acpi-pmic:
  ACPI / PMIC: Convert to use builtin_platform_driver() macro
  ACPI / PMIC: constify platform_device_id

* acpi-soc:
  ACPI / LPSS: Do not instiate platform_dev for devs without MMIO resources
  ACPI / LPSS: Add device link for CHT SD card dependency on I2C

* acpi-ged:
  ACPI: GED: unregister interrupts during shutdown
Rafael J. Wysocki 7 жил өмнө

+ 0 - 1
Documentation/admin-guide/kernel-parameters.txt

@@ -114,7 +114,6 @@
 			This facility can be used to prevent such uncontrolled
 			This facility can be used to prevent such uncontrolled
 			GPE floodings.
 			GPE floodings.
 			Format: <int>
 			Format: <int>
-			Support masking of GPEs numbered from 0x00 to 0x7f.
 
 
 	acpi_no_auto_serialize	[HW,ACPI]
 	acpi_no_auto_serialize	[HW,ACPI]
 			Disable auto-serialization of AML methods
 			Disable auto-serialization of AML methods

+ 5 - 0
arch/ia64/kernel/acpi.c

@@ -504,6 +504,11 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 	if (!(ma->flags & ACPI_SRAT_MEM_ENABLED))
 	if (!(ma->flags & ACPI_SRAT_MEM_ENABLED))
 		return -1;
 		return -1;
 
 
+	if (num_node_memblks >= NR_NODE_MEMBLKS) {
+		pr_err("NUMA: too many memblk ranges\n");
+		return -EINVAL;
+	}
+
 	/* record this node in proximity bitmap */
 	/* record this node in proximity bitmap */
 	pxm_bit_set(pxm);
 	pxm_bit_set(pxm);
 
 

+ 139 - 0
drivers/acpi/acpi_lpss.c

@@ -427,6 +427,142 @@ out:
 	return 0;
 	return 0;
 }
 }
 
 
+struct lpss_device_links {
+	const char *supplier_hid;
+	const char *supplier_uid;
+	const char *consumer_hid;
+	const char *consumer_uid;
+	u32 flags;
+};
+
+/*
+ * The _DEP method is used to identify dependencies but instead of creating
+ * device links for every handle in _DEP, only links in the following list are
+ * created. That is necessary because, in the general case, _DEP can refer to
+ * devices that might not have drivers, or that are on different buses, or where
+ * the supplier is not enumerated until after the consumer is probed.
+ */
+static const struct lpss_device_links lpss_device_links[] = {
+	{"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME},
+};
+
+static bool hid_uid_match(const char *hid1, const char *uid1,
+			  const char *hid2, const char *uid2)
+{
+	return !strcmp(hid1, hid2) && uid1 && uid2 && !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);
+}
+
+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);
+}
+
+struct hid_uid {
+	const char *hid;
+	const char *uid;
+};
+
+static int match_hid_uid(struct device *dev, void *data)
+{
+	struct acpi_device *adev = ACPI_COMPANION(dev);
+	struct hid_uid *id = data;
+
+	if (!adev)
+		return 0;
+
+	return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
+			     id->hid, id->uid);
+}
+
+static struct device *acpi_lpss_find_device(const char *hid, const char *uid)
+{
+	struct hid_uid data = {
+		.hid = hid,
+		.uid = uid,
+	};
+
+	return bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid);
+}
+
+static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle)
+{
+	struct acpi_handle_list dep_devices;
+	acpi_status status;
+	int i;
+
+	if (!acpi_has_method(adev->handle, "_DEP"))
+		return false;
+
+	status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
+					 &dep_devices);
+	if (ACPI_FAILURE(status)) {
+		dev_dbg(&adev->dev, "Failed to evaluate _DEP.\n");
+		return false;
+	}
+
+	for (i = 0; i < dep_devices.count; i++) {
+		if (dep_devices.handles[i] == handle)
+			return true;
+	}
+
+	return false;
+}
+
+static void acpi_lpss_link_consumer(struct device *dev1,
+				    const struct lpss_device_links *link)
+{
+	struct device *dev2;
+
+	dev2 = acpi_lpss_find_device(link->consumer_hid, link->consumer_uid);
+	if (!dev2)
+		return;
+
+	if (acpi_lpss_dep(ACPI_COMPANION(dev2), ACPI_HANDLE(dev1)))
+		device_link_add(dev2, dev1, link->flags);
+
+	put_device(dev2);
+}
+
+static void acpi_lpss_link_supplier(struct device *dev1,
+				    const struct lpss_device_links *link)
+{
+	struct device *dev2;
+
+	dev2 = acpi_lpss_find_device(link->supplier_hid, link->supplier_uid);
+	if (!dev2)
+		return;
+
+	if (acpi_lpss_dep(ACPI_COMPANION(dev1), ACPI_HANDLE(dev2)))
+		device_link_add(dev1, dev2, link->flags);
+
+	put_device(dev2);
+}
+
+static void acpi_lpss_create_device_links(struct acpi_device *adev,
+					  struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(lpss_device_links); i++) {
+		const struct lpss_device_links *link = &lpss_device_links[i];
+
+		if (acpi_lpss_is_supplier(adev, link))
+			acpi_lpss_link_consumer(&pdev->dev, link);
+
+		if (acpi_lpss_is_consumer(adev, link))
+			acpi_lpss_link_supplier(&pdev->dev, link);
+	}
+}
+
 static int acpi_lpss_create_device(struct acpi_device *adev,
 static int acpi_lpss_create_device(struct acpi_device *adev,
 				   const struct acpi_device_id *id)
 				   const struct acpi_device_id *id)
 {
 {
@@ -465,6 +601,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
 	acpi_dev_free_resource_list(&resource_list);
 	acpi_dev_free_resource_list(&resource_list);
 
 
 	if (!pdata->mmio_base) {
 	if (!pdata->mmio_base) {
+		/* Avoid acpi_bus_attach() instantiating a pdev for this dev. */
+		adev->pnp.type.platform_id = 0;
 		/* Skip the device, but continue the namespace scan. */
 		/* Skip the device, but continue the namespace scan. */
 		ret = 0;
 		ret = 0;
 		goto err_out;
 		goto err_out;
@@ -500,6 +638,7 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
 	adev->driver_data = pdata;
 	adev->driver_data = pdata;
 	pdev = acpi_create_platform_device(adev, dev_desc->properties);
 	pdev = acpi_create_platform_device(adev, dev_desc->properties);
 	if (!IS_ERR_OR_NULL(pdev)) {
 	if (!IS_ERR_OR_NULL(pdev)) {
+		acpi_lpss_create_device_links(adev, pdev);
 		return 1;
 		return 1;
 	}
 	}
 
 

+ 41 - 6
drivers/acpi/evged.c

@@ -49,6 +49,11 @@
 
 
 #define MODULE_NAME	"acpi-ged"
 #define MODULE_NAME	"acpi-ged"
 
 
+struct acpi_ged_device {
+	struct device *dev;
+	struct list_head event_list;
+};
+
 struct acpi_ged_event {
 struct acpi_ged_event {
 	struct list_head node;
 	struct list_head node;
 	struct device *dev;
 	struct device *dev;
@@ -76,7 +81,8 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares,
 	unsigned int irq;
 	unsigned int irq;
 	unsigned int gsi;
 	unsigned int gsi;
 	unsigned int irqflags = IRQF_ONESHOT;
 	unsigned int irqflags = IRQF_ONESHOT;
-	struct device *dev = context;
+	struct acpi_ged_device *geddev = context;
+	struct device *dev = geddev->dev;
 	acpi_handle handle = ACPI_HANDLE(dev);
 	acpi_handle handle = ACPI_HANDLE(dev);
 	acpi_handle evt_handle;
 	acpi_handle evt_handle;
 	struct resource r;
 	struct resource r;
@@ -102,8 +108,6 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares,
 		return AE_ERROR;
 		return AE_ERROR;
 	}
 	}
 
 
-	dev_info(dev, "GED listening GSI %u @ IRQ %u\n", gsi, irq);
-
 	event = devm_kzalloc(dev, sizeof(*event), GFP_KERNEL);
 	event = devm_kzalloc(dev, sizeof(*event), GFP_KERNEL);
 	if (!event)
 	if (!event)
 		return AE_ERROR;
 		return AE_ERROR;
@@ -116,29 +120,58 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares,
 	if (r.flags & IORESOURCE_IRQ_SHAREABLE)
 	if (r.flags & IORESOURCE_IRQ_SHAREABLE)
 		irqflags |= IRQF_SHARED;
 		irqflags |= IRQF_SHARED;
 
 
-	if (devm_request_threaded_irq(dev, irq, NULL, acpi_ged_irq_handler,
-				      irqflags, "ACPI:Ged", event)) {
+	if (request_threaded_irq(irq, NULL, acpi_ged_irq_handler,
+				 irqflags, "ACPI:Ged", event)) {
 		dev_err(dev, "failed to setup event handler for irq %u\n", irq);
 		dev_err(dev, "failed to setup event handler for irq %u\n", irq);
 		return AE_ERROR;
 		return AE_ERROR;
 	}
 	}
 
 
+	dev_dbg(dev, "GED listening GSI %u @ IRQ %u\n", gsi, irq);
+	list_add_tail(&event->node, &geddev->event_list);
 	return AE_OK;
 	return AE_OK;
 }
 }
 
 
 static int ged_probe(struct platform_device *pdev)
 static int ged_probe(struct platform_device *pdev)
 {
 {
+	struct acpi_ged_device *geddev;
 	acpi_status acpi_ret;
 	acpi_status acpi_ret;
 
 
+	geddev = devm_kzalloc(&pdev->dev, sizeof(*geddev), GFP_KERNEL);
+	if (!geddev)
+		return -ENOMEM;
+
+	geddev->dev = &pdev->dev;
+	INIT_LIST_HEAD(&geddev->event_list);
 	acpi_ret = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), "_CRS",
 	acpi_ret = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), "_CRS",
-				       acpi_ged_request_interrupt, &pdev->dev);
+				       acpi_ged_request_interrupt, geddev);
 	if (ACPI_FAILURE(acpi_ret)) {
 	if (ACPI_FAILURE(acpi_ret)) {
 		dev_err(&pdev->dev, "unable to parse the _CRS record\n");
 		dev_err(&pdev->dev, "unable to parse the _CRS record\n");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
+	platform_set_drvdata(pdev, geddev);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
+static void ged_shutdown(struct platform_device *pdev)
+{
+	struct acpi_ged_device *geddev = platform_get_drvdata(pdev);
+	struct acpi_ged_event *event, *next;
+
+	list_for_each_entry_safe(event, next, &geddev->event_list, node) {
+		free_irq(event->irq, event);
+		list_del(&event->node);
+		dev_dbg(geddev->dev, "GED releasing GSI %u @ IRQ %u\n",
+			 event->gsi, event->irq);
+	}
+}
+
+static int ged_remove(struct platform_device *pdev)
+{
+	ged_shutdown(pdev);
+	return 0;
+}
+
 static const struct acpi_device_id ged_acpi_ids[] = {
 static const struct acpi_device_id ged_acpi_ids[] = {
 	{"ACPI0013"},
 	{"ACPI0013"},
 	{},
 	{},
@@ -146,6 +179,8 @@ static const struct acpi_device_id ged_acpi_ids[] = {
 
 
 static struct platform_driver ged_driver = {
 static struct platform_driver ged_driver = {
 	.probe = ged_probe,
 	.probe = ged_probe,
+	.remove = ged_remove,
+	.shutdown = ged_shutdown,
 	.driver = {
 	.driver = {
 		.name = MODULE_NAME,
 		.name = MODULE_NAME,
 		.acpi_match_table = ACPI_PTR(ged_acpi_ids),
 		.acpi_match_table = ACPI_PTR(ged_acpi_ids),

+ 1 - 2
drivers/acpi/numa.c

@@ -460,8 +460,7 @@ int __init acpi_numa_init(void)
 					srat_proc, ARRAY_SIZE(srat_proc), 0);
 					srat_proc, ARRAY_SIZE(srat_proc), 0);
 
 
 		cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
 		cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
-					    acpi_parse_memory_affinity,
-					    NR_NODE_MEMBLKS);
+					    acpi_parse_memory_affinity, 0);
 	}
 	}
 
 
 	/* SLIT: System Locality Information Table */
 	/* SLIT: System Locality Information Table */

+ 2 - 7
drivers/acpi/pmic/intel_pmic_bxtwc.c

@@ -400,7 +400,7 @@ static int intel_bxtwc_pmic_opregion_probe(struct platform_device *pdev)
 			&intel_bxtwc_pmic_opregion_data);
 			&intel_bxtwc_pmic_opregion_data);
 }
 }
 
 
-static struct platform_device_id bxt_wc_opregion_id_table[] = {
+static const struct platform_device_id bxt_wc_opregion_id_table[] = {
 	{ .name = "bxt_wcove_region" },
 	{ .name = "bxt_wcove_region" },
 	{},
 	{},
 };
 };
@@ -412,9 +412,4 @@ static struct platform_driver intel_bxtwc_pmic_opregion_driver = {
 	},
 	},
 	.id_table = bxt_wc_opregion_id_table,
 	.id_table = bxt_wc_opregion_id_table,
 };
 };
-
-static int __init intel_bxtwc_pmic_opregion_driver_init(void)
-{
-	return platform_driver_register(&intel_bxtwc_pmic_opregion_driver);
-}
-device_initcall(intel_bxtwc_pmic_opregion_driver_init);
+builtin_platform_driver(intel_bxtwc_pmic_opregion_driver);

+ 1 - 4
drivers/acpi/pmic/intel_pmic_chtdc_ti.c

@@ -131,7 +131,4 @@ static struct platform_driver chtdc_ti_pmic_opregion_driver = {
 	},
 	},
 	.id_table = chtdc_ti_pmic_opregion_id_table,
 	.id_table = chtdc_ti_pmic_opregion_id_table,
 };
 };
-module_platform_driver(chtdc_ti_pmic_opregion_driver);
-
-MODULE_DESCRIPTION("Dollar Cove TI PMIC opregion driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(chtdc_ti_pmic_opregion_driver);

+ 2 - 7
drivers/acpi/pmic/intel_pmic_chtwc.c

@@ -260,11 +260,10 @@ static int intel_cht_wc_pmic_opregion_probe(struct platform_device *pdev)
 			&intel_cht_wc_pmic_opregion_data);
 			&intel_cht_wc_pmic_opregion_data);
 }
 }
 
 
-static struct platform_device_id cht_wc_opregion_id_table[] = {
+static const struct platform_device_id cht_wc_opregion_id_table[] = {
 	{ .name = "cht_wcove_region" },
 	{ .name = "cht_wcove_region" },
 	{},
 	{},
 };
 };
-MODULE_DEVICE_TABLE(platform, cht_wc_opregion_id_table);
 
 
 static struct platform_driver intel_cht_wc_pmic_opregion_driver = {
 static struct platform_driver intel_cht_wc_pmic_opregion_driver = {
 	.probe = intel_cht_wc_pmic_opregion_probe,
 	.probe = intel_cht_wc_pmic_opregion_probe,
@@ -273,8 +272,4 @@ static struct platform_driver intel_cht_wc_pmic_opregion_driver = {
 	},
 	},
 	.id_table = cht_wc_opregion_id_table,
 	.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");
+builtin_platform_driver(intel_cht_wc_pmic_opregion_driver);

+ 1 - 6
drivers/acpi/pmic/intel_pmic_crc.c

@@ -201,9 +201,4 @@ static struct platform_driver intel_crc_pmic_opregion_driver = {
 		.name = "crystal_cove_pmic",
 		.name = "crystal_cove_pmic",
 	},
 	},
 };
 };
-
-static int __init intel_crc_pmic_opregion_driver_init(void)
-{
-	return platform_driver_register(&intel_crc_pmic_opregion_driver);
-}
-device_initcall(intel_crc_pmic_opregion_driver_init);
+builtin_platform_driver(intel_crc_pmic_opregion_driver);

+ 1 - 6
drivers/acpi/pmic/intel_pmic_xpower.c

@@ -278,9 +278,4 @@ static struct platform_driver intel_xpower_pmic_opregion_driver = {
 		.name = "axp288_pmic_acpi",
 		.name = "axp288_pmic_acpi",
 	},
 	},
 };
 };
-
-static int __init intel_xpower_pmic_opregion_driver_init(void)
-{
-	return platform_driver_register(&intel_xpower_pmic_opregion_driver);
-}
-device_initcall(intel_xpower_pmic_opregion_driver_init);
+builtin_platform_driver(intel_xpower_pmic_opregion_driver);

+ 8 - 18
drivers/acpi/sysfs.c

@@ -816,14 +816,8 @@ end:
  * interface:
  * interface:
  *   echo unmask > /sys/firmware/acpi/interrupts/gpe00
  *   echo unmask > /sys/firmware/acpi/interrupts/gpe00
  */
  */
-
-/*
- * Currently, the GPE flooding prevention only supports to mask the GPEs
- * numbered from 00 to 7f.
- */
-#define ACPI_MASKABLE_GPE_MAX	0x80
-
-static u64 __initdata acpi_masked_gpes;
+#define ACPI_MASKABLE_GPE_MAX	0xFF
+static DECLARE_BITMAP(acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) __initdata;
 
 
 static int __init acpi_gpe_set_masked_gpes(char *val)
 static int __init acpi_gpe_set_masked_gpes(char *val)
 {
 {
@@ -831,7 +825,7 @@ static int __init acpi_gpe_set_masked_gpes(char *val)
 
 
 	if (kstrtou8(val, 0, &gpe) || gpe > ACPI_MASKABLE_GPE_MAX)
 	if (kstrtou8(val, 0, &gpe) || gpe > ACPI_MASKABLE_GPE_MAX)
 		return -EINVAL;
 		return -EINVAL;
-	acpi_masked_gpes |= ((u64)1<<gpe);
+	set_bit(gpe, acpi_masked_gpes_map);
 
 
 	return 1;
 	return 1;
 }
 }
@@ -843,15 +837,11 @@ void __init acpi_gpe_apply_masked_gpes(void)
 	acpi_status status;
 	acpi_status status;
 	u8 gpe;
 	u8 gpe;
 
 
-	for (gpe = 0;
-	     gpe < min_t(u8, ACPI_MASKABLE_GPE_MAX, acpi_current_gpe_count);
-	     gpe++) {
-		if (acpi_masked_gpes & ((u64)1<<gpe)) {
-			status = acpi_get_gpe_device(gpe, &handle);
-			if (ACPI_SUCCESS(status)) {
-				pr_info("Masking GPE 0x%x.\n", gpe);
-				(void)acpi_mask_gpe(handle, gpe, TRUE);
-			}
+	for_each_set_bit(gpe, acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) {
+		status = acpi_get_gpe_device(gpe, &handle);
+		if (ACPI_SUCCESS(status)) {
+			pr_info("Masking GPE 0x%x.\n", gpe);
+			(void)acpi_mask_gpe(handle, gpe, TRUE);
 		}
 		}
 	}
 	}
 }
 }