linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v4 1/2] PCI/ACPI: Add stacked IRQ domain support to PCI Interrupt Link
@ 2020-11-23  7:33 Chen Baozi
  2020-11-23  7:33 ` [RFC PATCH v4 2/2] ACPI: Advertise Interrupt ResourceSource support Chen Baozi
  0 siblings, 1 reply; 2+ messages in thread
From: Chen Baozi @ 2020-11-23  7:33 UTC (permalink / raw)
  To: Ard Biesheuvel, Marc Zyngier, Bjorn Helgaas
  Cc: linux-acpi, linux-pci, linux-arm-kernel, linux-kernel,
	Hanjun Guo, Lorenzo Pieralisi, Rafael J. Wysocki

The ResourceSource field of an Extended Interrupt Descriptor was ignored
when the driver is parsing _PRS method of PNP0C0F PCI Interrupt Link
devices, which means PCI INTx would be always registered under the GSI
domain. This patch introduces stacked IRQ domain support to PCI Interrupt
Link devices for ACPI.

With this support, we can populate the ResourceSource field in _PRS method
of PCI Interrupt Link devices to refer to a device object that describes
an interrupt controller as the following examples:

  Device (IXIU) {
    ...
  }

  Device(LINKA) {
    Name(_HID, EISAID("PNP0C0F"))
    Name(_PRS, ResourceTemplate(){
      Interrupt(ResourceProducer, Level, ActiveHigh, Exclusive,
                0, "\\SB.IXIU") { 60 }
    })
    ...
  }

Signed-off-by: Chen Baozi <chenbaozi@phytium.com.cn>
---
v3->v4:
  Include "internal.h" in drivers/acpi/irq.c to avoid the warning because
  of lacking prototype for 'acpi_register_irq'

 drivers/acpi/internal.h     | 12 ++++++++++++
 drivers/acpi/irq.c          | 36 ++++++++++++++++++++++--------------
 drivers/acpi/pci_irq.c      |  8 ++++++--
 drivers/acpi/pci_link.c     | 17 +++++++++++++++--
 include/acpi/acpi_drivers.h |  2 +-
 include/linux/acpi.h        | 10 ++++++++++
 6 files changed, 66 insertions(+), 19 deletions(-)

diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index e3638bafb941..38ebe24bce3b 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -88,6 +88,18 @@ bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);
 acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context);
 void acpi_scan_table_handler(u32 event, void *table, void *context);
 
+#ifdef CONFIG_ACPI_GENERIC_GSI
+int acpi_register_irq(struct device *dev, u32 hwirq, int trigger,
+		      int polarity, struct fwnode_handle *fwnode);
+#else
+static inline
+int acpi_register_irq(struct device *dev, u32 hwirq, int trigger,
+		      int polarity, struct fwnode_handle *fwnode)
+{
+	return acpi_register_gsi(dev, hwirq, trigger, polarity);
+}
+#endif
+
 /* --------------------------------------------------------------------------
                      Device Node Initialization / Removal
    -------------------------------------------------------------------------- */
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
index e209081d644b..86336a89f73e 100644
--- a/drivers/acpi/irq.c
+++ b/drivers/acpi/irq.c
@@ -10,6 +10,8 @@
 #include <linux/irqdomain.h>
 #include <linux/of.h>
 
+#include "internal.h"
+
 enum acpi_irq_model_id acpi_irq_model;
 
 static struct fwnode_handle *acpi_gsi_domain_id;
@@ -38,6 +40,24 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
 }
 EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
 
+int acpi_register_irq(struct device *dev, u32 hwirq, int trigger,
+		      int polarity, struct fwnode_handle *fwnode)
+{
+	struct irq_fwspec fwspec;
+
+	if (!fwnode) {
+		dev_warn(dev, "No registered irqchip for hwirq %d\n", hwirq);
+		return -EINVAL;
+	}
+
+	fwspec.fwnode = fwnode;
+	fwspec.param[0] = hwirq;
+	fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
+	fwspec.param_count = 2;
+
+	return irq_create_fwspec_mapping(&fwspec);
+}
+
 /**
  * acpi_register_gsi() - Map a GSI to a linux IRQ number
  * @dev: device for which IRQ has to be mapped
@@ -51,19 +71,7 @@ EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
 int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
 		      int polarity)
 {
-	struct irq_fwspec fwspec;
-
-	if (WARN_ON(!acpi_gsi_domain_id)) {
-		pr_warn("GSI: No registered irqchip, giving up\n");
-		return -EINVAL;
-	}
-
-	fwspec.fwnode = acpi_gsi_domain_id;
-	fwspec.param[0] = gsi;
-	fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
-	fwspec.param_count = 2;
-
-	return irq_create_fwspec_mapping(&fwspec);
+	return acpi_register_irq(dev, gsi, trigger, polarity, acpi_gsi_domain_id);
 }
 EXPORT_SYMBOL_GPL(acpi_register_gsi);
 
@@ -92,7 +100,7 @@ EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
  * Return:
  * The referenced device fwhandle or NULL on failure
  */
-static struct fwnode_handle *
+struct fwnode_handle *
 acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source)
 {
 	struct fwnode_handle *result;
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 14ee631cb7cf..5cccc0f70781 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -22,6 +22,8 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 
+#include "internal.h"
+
 #define PREFIX "ACPI: "
 
 #define _COMPONENT		ACPI_PCI_COMPONENT
@@ -410,6 +412,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
 	char *link = NULL;
 	char link_desc[16];
 	int rc;
+	struct fwnode_handle *rs_fwnode;
 
 	pin = dev->pin;
 	if (!pin) {
@@ -438,7 +441,8 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
 			gsi = acpi_pci_link_allocate_irq(entry->link,
 							 entry->index,
 							 &triggering, &polarity,
-							 &link);
+							 &link,
+							 &rs_fwnode);
 		else
 			gsi = entry->index;
 	} else
@@ -462,7 +466,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
 		return 0;
 	}
 
-	rc = acpi_register_gsi(&dev->dev, gsi, triggering, polarity);
+	rc = acpi_register_irq(&dev->dev, gsi, triggering, polarity, rs_fwnode);
 	if (rc < 0) {
 		dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
 			 pin_name(pin));
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index fb4c5632a232..2b6f6478bb30 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -59,6 +59,7 @@ struct acpi_pci_link_irq {
 	u8 resource_type;
 	u8 possible_count;
 	u32 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
+	struct acpi_resource_source resource_source;
 	u8 initialized:1;
 	u8 reserved:7;
 };
@@ -120,6 +121,8 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
 		{
 			struct acpi_resource_extended_irq *p =
 			    &resource->data.extended_irq;
+			struct acpi_resource_source *rs =
+			    &link->irq.resource_source;
 			if (!p || !p->interrupt_count) {
 				printk(KERN_WARNING PREFIX
 					      "Blank _PRS EXT IRQ resource\n");
@@ -140,6 +143,12 @@ static acpi_status acpi_pci_link_check_possible(struct acpi_resource *resource,
 			link->irq.triggering = p->triggering;
 			link->irq.polarity = p->polarity;
 			link->irq.resource_type = ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
+			if (p->resource_source.string_length) {
+				rs->index = p->resource_source.index;
+				rs->string_length = p->resource_source.string_length;
+				rs->string_ptr = kstrdup(p->resource_source.string_ptr,
+							 GFP_KERNEL);
+			}
 			break;
 		}
 	default:
@@ -326,7 +335,8 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
 			resource->res.data.extended_irq.shareable = ACPI_SHARED;
 		resource->res.data.extended_irq.interrupt_count = 1;
 		resource->res.data.extended_irq.interrupts[0] = irq;
-		/* ignore resource_source, it's optional */
+		resource->res.data.extended_irq.resource_source =
+			link->irq.resource_source;
 		break;
 	default:
 		printk(KERN_ERR PREFIX "Invalid Resource_type %d\n", link->irq.resource_type);
@@ -612,7 +622,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
  * failure: return -1
  */
 int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
-			       int *polarity, char **name)
+			       int *polarity, char **name, struct fwnode_handle **rs_fwnode)
 {
 	int result;
 	struct acpi_device *device;
@@ -656,6 +666,9 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
 		*polarity = link->irq.polarity;
 	if (name)
 		*name = acpi_device_bid(link->device);
+	if (rs_fwnode)
+		*rs_fwnode = acpi_get_irq_source_fwhandle(&link->irq.resource_source);
+
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			  "Link %s is referenced\n",
 			  acpi_device_bid(link->device)));
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index d4f39a20aa2a..36f1eb6df6fb 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -68,7 +68,7 @@
 
 int acpi_irq_penalty_init(void);
 int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
-			       int *polarity, char **name);
+			       int *polarity, char **name, struct fwnode_handle **rs_fwnode);
 int acpi_pci_link_free_irq(acpi_handle handle);
 
 /* ACPI PCI Device Binding */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 39263c6b52e1..b182a267fe66 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -336,6 +336,16 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
 					     const struct irq_domain_ops *ops,
 					     void *host_data);
 
+#ifdef CONFIG_ACPI_GENERIC_GSI
+struct fwnode_handle *acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source);
+#else
+static inline
+struct fwnode_handle *acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source)
+{
+	return NULL;
+}
+#endif
+
 #ifdef CONFIG_X86_IO_APIC
 extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);
 #else
-- 
2.28.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* [RFC PATCH v4 2/2] ACPI: Advertise Interrupt ResourceSource support
  2020-11-23  7:33 [RFC PATCH v4 1/2] PCI/ACPI: Add stacked IRQ domain support to PCI Interrupt Link Chen Baozi
@ 2020-11-23  7:33 ` Chen Baozi
  0 siblings, 0 replies; 2+ messages in thread
From: Chen Baozi @ 2020-11-23  7:33 UTC (permalink / raw)
  To: Ard Biesheuvel, Marc Zyngier, Bjorn Helgaas
  Cc: linux-acpi, linux-pci, linux-arm-kernel, linux-kernel,
	Hanjun Guo, Lorenzo Pieralisi, Rafael J. Wysocki,
	Jonathan Cameron

As mentioned in ACPI v6.3, Table 6-200, the platform will indicate
to the OS whether or not it supports usage of ResourceSource. If
not set, the OS may choose to ignore the ResourceSource parameter
in the extended interrupt descriptor. Since we support parsing
ResoureSource field of interrupts both for platform devices and
PCI Interrupt Link devices now, this patch sets the relevant OSC
bit and checks the capability as described in ACPI specification.

Signed-off-by: Chen Baozi <chenbaozi@phytium.com.cn>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 drivers/acpi/bus.c   | 5 +++++
 drivers/acpi/irq.c   | 3 ++-
 include/linux/acpi.h | 4 +++-
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 1682f8b454a2..a6af1270bea6 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -281,6 +281,8 @@ bool osc_sb_apei_support_acked;
 bool osc_pc_lpi_support_confirmed;
 EXPORT_SYMBOL_GPL(osc_pc_lpi_support_confirmed);
 
+bool osc_sb_intr_ressrc_support_confirmed;
+
 static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
 static void acpi_bus_osc_support(void)
 {
@@ -303,6 +305,7 @@ static void acpi_bus_osc_support(void)
 	capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT;
 	capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PCLPI_SUPPORT;
 
+	capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_INTR_RESSRC_SUPPORT;
 #ifdef CONFIG_ARM64
 	capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_GENERIC_INITIATOR_SUPPORT;
 #endif
@@ -328,6 +331,8 @@ static void acpi_bus_osc_support(void)
 				capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT;
 			osc_pc_lpi_support_confirmed =
 				capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_PCLPI_SUPPORT;
+			osc_sb_intr_ressrc_support_confirmed =
+				capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_INTR_RESSRC_SUPPORT;
 		}
 		kfree(context.ret.pointer);
 	}
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
index 86336a89f73e..8f4d2dff5538 100644
--- a/drivers/acpi/irq.c
+++ b/drivers/acpi/irq.c
@@ -108,7 +108,8 @@ acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source)
 	acpi_handle handle;
 	acpi_status status;
 
-	if (!source->string_length)
+	if (!osc_sb_intr_ressrc_support_confirmed ||
+	    !source->string_length)
 		return acpi_gsi_domain_id;
 
 	status = acpi_get_handle(NULL, source->string_ptr, &handle);
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index b182a267fe66..f9ca8e117f31 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -555,10 +555,12 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 #define OSC_SB_PCLPI_SUPPORT			0x00000080
 #define OSC_SB_OSLPI_SUPPORT			0x00000100
 #define OSC_SB_CPC_DIVERSE_HIGH_SUPPORT		0x00001000
-#define OSC_SB_GENERIC_INITIATOR_SUPPORT	0x00002000
+#define OSC_SB_INTR_RESSRC_SUPPORT		0x00002000
+#define OSC_SB_GENERIC_INITIATOR_SUPPORT	0x00020000
 
 extern bool osc_sb_apei_support_acked;
 extern bool osc_pc_lpi_support_confirmed;
+extern bool osc_sb_intr_ressrc_support_confirmed;
 
 /* PCI Host Bridge _OSC: Capabilities DWORD 2: Support Field */
 #define OSC_PCI_EXT_CONFIG_SUPPORT		0x00000001
-- 
2.28.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2020-11-23  7:34 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-23  7:33 [RFC PATCH v4 1/2] PCI/ACPI: Add stacked IRQ domain support to PCI Interrupt Link Chen Baozi
2020-11-23  7:33 ` [RFC PATCH v4 2/2] ACPI: Advertise Interrupt ResourceSource support Chen Baozi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).