summaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2026-02-05 12:42:18 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2026-02-05 12:42:18 +0100
commit04cd14ff02d618e42be21f4b7ab3822c10ce97df (patch)
tree5445bc4a49c240e4cfe8be6f7bbbaff23b37f8ec /drivers/acpi
parent0e8ac1d3be35e51e38c263f3b46f91fb79c51e22 (diff)
parent05bff3419adaa272713be4c07d287756a4b2c5f5 (diff)
Merge branch 'acpi-irq'
Merge ARM-related irq subsystem changes based on the recent ACPICA updates for 6.20-rc1/7.0-rc1: - Add support for GICv5 ACPI probing on ARM which is based on the GICv5 MADT structures and ARM IORT IWB node definitions recently added to ACPICA (Lorenzo Pieralisi) * acpi-irq: irqchip/gic-v5: Add ACPI IWB probing irqchip/gic-v5: Add ACPI ITS probing irqchip/gic-v5: Add ACPI IRS probing irqchip/gic-v5: Split IRS probing into OF and generic portions PCI/MSI: Make the pci_msi_map_rid_ctlr_node() interface firmware agnostic irqdomain: Add parent field to struct irqchip_fwid
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/arm64/iort.c193
-rw-r--r--drivers/acpi/bus.c3
2 files changed, 160 insertions, 36 deletions
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index 65f0f56ad753..ed827b2fc437 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -264,39 +264,47 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
struct device *dev = context;
acpi_status status = AE_NOT_FOUND;
- if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
+ if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+ node->type == ACPI_IORT_NODE_IWB) {
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
- struct acpi_device *adev;
struct acpi_iort_named_component *ncomp;
- struct device *nc_dev = dev;
+ struct acpi_iort_iwb *iwb;
+ struct device *cdev = dev;
+ struct acpi_device *adev;
+ const char *device_name;
/*
* Walk the device tree to find a device with an
* ACPI companion; there is no point in scanning
- * IORT for a device matching a named component if
+ * IORT for a device matching a named component or IWB if
* the device does not have an ACPI companion to
* start with.
*/
do {
- adev = ACPI_COMPANION(nc_dev);
+ adev = ACPI_COMPANION(cdev);
if (adev)
break;
- nc_dev = nc_dev->parent;
- } while (nc_dev);
+ cdev = cdev->parent;
+ } while (cdev);
if (!adev)
goto out;
status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
if (ACPI_FAILURE(status)) {
- dev_warn(nc_dev, "Can't get device full path name\n");
+ dev_warn(cdev, "Can't get device full path name\n");
goto out;
}
- ncomp = (struct acpi_iort_named_component *)node->node_data;
- status = !strcmp(ncomp->device_name, buf.pointer) ?
- AE_OK : AE_NOT_FOUND;
+ if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
+ ncomp = (struct acpi_iort_named_component *)node->node_data;
+ device_name = ncomp->device_name;
+ } else {
+ iwb = (struct acpi_iort_iwb *)node->node_data;
+ device_name = iwb->device_name;
+ }
+ status = !strcmp(device_name, buf.pointer) ? AE_OK : AE_NOT_FOUND;
acpi_os_free(buf.pointer);
} else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
struct acpi_iort_root_complex *pci_rc;
@@ -317,12 +325,28 @@ out:
return status;
}
+static acpi_status iort_match_iwb_callback(struct acpi_iort_node *node, void *context)
+{
+ struct acpi_iort_iwb *iwb;
+ u32 *id = context;
+
+ if (node->type != ACPI_IORT_NODE_IWB)
+ return AE_NOT_FOUND;
+
+ iwb = (struct acpi_iort_iwb *)node->node_data;
+ if (iwb->iwb_index != *id)
+ return AE_NOT_FOUND;
+
+ return AE_OK;
+}
+
static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
u32 *rid_out, bool check_overlap)
{
/* Single mapping does not care for input id */
if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
if (type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+ type == ACPI_IORT_NODE_IWB ||
type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
*rid_out = map->output_base;
return 0;
@@ -392,6 +416,7 @@ static struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
+ node->type == ACPI_IORT_NODE_IWB ||
node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX ||
node->type == ACPI_IORT_NODE_SMMU_V3 ||
node->type == ACPI_IORT_NODE_PMCG) {
@@ -562,9 +587,14 @@ static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
return node;
/*
* if not, then it should be a platform device defined in
- * DSDT/SSDT (with Named Component node in IORT)
+ * DSDT/SSDT (with Named Component node in IORT) or an
+ * IWB device in the DSDT/SSDT.
*/
- return iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+ node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
+ iort_match_node_callback, dev);
+ if (node)
+ return node;
+ return iort_scan_node(ACPI_IORT_NODE_IWB,
iort_match_node_callback, dev);
}
@@ -595,45 +625,45 @@ u32 iort_msi_map_id(struct device *dev, u32 input_id)
}
/**
- * iort_pmsi_get_dev_id() - Get the device id for a device
+ * iort_msi_xlate() - Map a MSI input ID for a device
* @dev: The device for which the mapping is to be done.
- * @dev_id: The device ID found.
+ * @input_id: The device input ID.
+ * @fwnode: Pointer to store the fwnode.
*
- * Returns: 0 for successful find a dev id, -ENODEV on error
+ * Returns: mapped MSI ID on success, input ID otherwise
+ * On success, the fwnode pointer is initialized to the MSI
+ * controller fwnode handle.
*/
-int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
+u32 iort_msi_xlate(struct device *dev, u32 input_id, struct fwnode_handle **fwnode)
{
- int i, index;
+ struct acpi_iort_its_group *its;
struct acpi_iort_node *node;
+ u32 dev_id;
node = iort_find_dev_node(dev);
if (!node)
- return -ENODEV;
+ return input_id;
- index = iort_get_id_mapping_index(node);
- /* if there is a valid index, go get the dev_id directly */
- if (index >= 0) {
- if (iort_node_get_id(node, dev_id, index))
- return 0;
- } else {
- for (i = 0; i < node->mapping_count; i++) {
- if (iort_node_map_platform_id(node, dev_id,
- IORT_MSI_TYPE, i))
- return 0;
- }
- }
+ node = iort_node_map_id(node, input_id, &dev_id, IORT_MSI_TYPE);
+ if (!node)
+ return input_id;
- return -ENODEV;
+ /* Move to ITS specific data */
+ its = (struct acpi_iort_its_group *)node->node_data;
+
+ *fwnode = iort_find_domain_token(its->identifiers[0]);
+
+ return dev_id;
}
-static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base)
+int iort_its_translate_pa(struct fwnode_handle *node, phys_addr_t *base)
{
struct iort_its_msi_chip *its_msi_chip;
int ret = -ENODEV;
spin_lock(&iort_msi_chip_lock);
list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
- if (its_msi_chip->translation_id == its_id) {
+ if (its_msi_chip->fw_node == node) {
*base = its_msi_chip->base_addr;
ret = 0;
break;
@@ -644,6 +674,62 @@ static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base)
return ret;
}
+static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base)
+{
+ struct fwnode_handle *fwnode = iort_find_domain_token(its_id);
+
+ if (!fwnode)
+ return -ENODEV;
+
+ return iort_its_translate_pa(fwnode, base);
+}
+
+/**
+ * iort_pmsi_get_msi_info() - Get the device id and translate frame PA for a device
+ * @dev: The device for which the mapping is to be done.
+ * @dev_id: The device ID found.
+ * @pa: optional pointer to store translate frame address.
+ *
+ * Returns: 0 for successful devid and pa retrieval, -ENODEV on error
+ */
+int iort_pmsi_get_msi_info(struct device *dev, u32 *dev_id, phys_addr_t *pa)
+{
+ struct acpi_iort_node *node, *parent = NULL;
+ struct acpi_iort_its_group *its;
+ int i, index;
+
+ node = iort_find_dev_node(dev);
+ if (!node)
+ return -ENODEV;
+
+ index = iort_get_id_mapping_index(node);
+ /* if there is a valid index, go get the dev_id directly */
+ if (index >= 0) {
+ parent = iort_node_get_id(node, dev_id, index);
+ } else {
+ for (i = 0; i < node->mapping_count; i++) {
+ parent = iort_node_map_platform_id(node, dev_id,
+ IORT_MSI_TYPE, i);
+ if (parent)
+ break;
+ }
+ }
+
+ if (!parent)
+ return -ENODEV;
+
+ if (pa) {
+ int ret;
+
+ its = (struct acpi_iort_its_group *)node->node_data;
+ ret = iort_find_its_base(its->identifiers[0], pa);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
/**
* iort_dev_find_its_id() - Find the ITS identifier for a device
* @dev: The device.
@@ -703,6 +789,35 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,
return irq_find_matching_fwnode(handle, bus_token);
}
+struct fwnode_handle *iort_iwb_handle(u32 iwb_id)
+{
+ struct fwnode_handle *fwnode;
+ struct acpi_iort_node *node;
+ struct acpi_device *device;
+ struct acpi_iort_iwb *iwb;
+ acpi_status status;
+ acpi_handle handle;
+
+ /* find its associated IWB node */
+ node = iort_scan_node(ACPI_IORT_NODE_IWB, iort_match_iwb_callback, &iwb_id);
+ if (!node)
+ return NULL;
+
+ iwb = (struct acpi_iort_iwb *)node->node_data;
+ status = acpi_get_handle(NULL, iwb->device_name, &handle);
+ if (ACPI_FAILURE(status))
+ return NULL;
+
+ device = acpi_get_acpi_dev(handle);
+ if (!device)
+ return NULL;
+
+ fwnode = acpi_fwnode_handle(device);
+ acpi_put_acpi_dev(device);
+
+ return fwnode;
+}
+
static void iort_set_device_domain(struct device *dev,
struct acpi_iort_node *node)
{
@@ -763,8 +878,14 @@ static struct irq_domain *iort_get_platform_device_domain(struct device *dev)
/* find its associated iort node */
node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
iort_match_node_callback, dev);
- if (!node)
- return NULL;
+ if (!node) {
+ /* find its associated iort node */
+ node = iort_scan_node(ACPI_IORT_NODE_IWB,
+ iort_match_node_callback, dev);
+
+ if (!node)
+ return NULL;
+ }
/* then find its msi parent node */
for (i = 0; i < node->mapping_count; i++) {
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a984ccd4a2a0..e4f4059c4f1d 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1197,6 +1197,9 @@ static int __init acpi_bus_init_irq(void)
case ACPI_IRQ_MODEL_GIC:
message = "GIC";
break;
+ case ACPI_IRQ_MODEL_GIC_V5:
+ message = "GICv5";
+ break;
case ACPI_IRQ_MODEL_PLATFORM:
message = "platform specific model";
break;