Skip to content

Commit 05bff34

Browse files
Lorenzo Pieralisirafaeljw
authored andcommitted
irqchip/gic-v5: Add ACPI IWB probing
To probe an IWB in an ACPI based system it is required: - to implement the IORT functions handling the IWB IORT node and create functions to retrieve IWB firmware information - to augment the driver to match the DSDT ACPI "ARMH0003" device and retrieve the IWB wire and trigger mask from the GSI interrupt descriptor in the IWB msi_domain_ops.msi_translate() function Make the required driver changes to enable IWB probing in ACPI systems. The GICv5 GSI format requires special handling for IWB routed IRQs. Add IWB GSI detection to the top level driver gic_v5_get_gsi_domain_id() function so that the correct IRQ domain for a GSI can be detected by parsing the GSI and check whether it is an IWB-backed IRQ or not. Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Acked-by: Thomas Gleixner <tglx@kernel.org> Link: https://patch.msgid.link/20260115-gicv5-host-acpi-v3-6-c13a9a150388@kernel.org Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent a97efa5 commit 05bff34

5 files changed

Lines changed: 123 additions & 25 deletions

File tree

drivers/acpi/arm64/iort.c

Lines changed: 80 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -264,39 +264,47 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
264264
struct device *dev = context;
265265
acpi_status status = AE_NOT_FOUND;
266266

267-
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
267+
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
268+
node->type == ACPI_IORT_NODE_IWB) {
268269
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
269-
struct acpi_device *adev;
270270
struct acpi_iort_named_component *ncomp;
271-
struct device *nc_dev = dev;
271+
struct acpi_iort_iwb *iwb;
272+
struct device *cdev = dev;
273+
struct acpi_device *adev;
274+
const char *device_name;
272275

273276
/*
274277
* Walk the device tree to find a device with an
275278
* ACPI companion; there is no point in scanning
276-
* IORT for a device matching a named component if
279+
* IORT for a device matching a named component or IWB if
277280
* the device does not have an ACPI companion to
278281
* start with.
279282
*/
280283
do {
281-
adev = ACPI_COMPANION(nc_dev);
284+
adev = ACPI_COMPANION(cdev);
282285
if (adev)
283286
break;
284287

285-
nc_dev = nc_dev->parent;
286-
} while (nc_dev);
288+
cdev = cdev->parent;
289+
} while (cdev);
287290

288291
if (!adev)
289292
goto out;
290293

291294
status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
292295
if (ACPI_FAILURE(status)) {
293-
dev_warn(nc_dev, "Can't get device full path name\n");
296+
dev_warn(cdev, "Can't get device full path name\n");
294297
goto out;
295298
}
296299

297-
ncomp = (struct acpi_iort_named_component *)node->node_data;
298-
status = !strcmp(ncomp->device_name, buf.pointer) ?
299-
AE_OK : AE_NOT_FOUND;
300+
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
301+
ncomp = (struct acpi_iort_named_component *)node->node_data;
302+
device_name = ncomp->device_name;
303+
} else {
304+
iwb = (struct acpi_iort_iwb *)node->node_data;
305+
device_name = iwb->device_name;
306+
}
307+
status = !strcmp(device_name, buf.pointer) ? AE_OK : AE_NOT_FOUND;
300308
acpi_os_free(buf.pointer);
301309
} else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
302310
struct acpi_iort_root_complex *pci_rc;
@@ -317,12 +325,28 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
317325
return status;
318326
}
319327

328+
static acpi_status iort_match_iwb_callback(struct acpi_iort_node *node, void *context)
329+
{
330+
struct acpi_iort_iwb *iwb;
331+
u32 *id = context;
332+
333+
if (node->type != ACPI_IORT_NODE_IWB)
334+
return AE_NOT_FOUND;
335+
336+
iwb = (struct acpi_iort_iwb *)node->node_data;
337+
if (iwb->iwb_index != *id)
338+
return AE_NOT_FOUND;
339+
340+
return AE_OK;
341+
}
342+
320343
static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
321344
u32 *rid_out, bool check_overlap)
322345
{
323346
/* Single mapping does not care for input id */
324347
if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
325348
if (type == ACPI_IORT_NODE_NAMED_COMPONENT ||
349+
type == ACPI_IORT_NODE_IWB ||
326350
type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
327351
*rid_out = map->output_base;
328352
return 0;
@@ -392,6 +416,7 @@ static struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
392416

393417
if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
394418
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
419+
node->type == ACPI_IORT_NODE_IWB ||
395420
node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX ||
396421
node->type == ACPI_IORT_NODE_SMMU_V3 ||
397422
node->type == ACPI_IORT_NODE_PMCG) {
@@ -562,9 +587,14 @@ static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
562587
return node;
563588
/*
564589
* if not, then it should be a platform device defined in
565-
* DSDT/SSDT (with Named Component node in IORT)
590+
* DSDT/SSDT (with Named Component node in IORT) or an
591+
* IWB device in the DSDT/SSDT.
566592
*/
567-
return iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
593+
node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
594+
iort_match_node_callback, dev);
595+
if (node)
596+
return node;
597+
return iort_scan_node(ACPI_IORT_NODE_IWB,
568598
iort_match_node_callback, dev);
569599
}
570600

@@ -759,6 +789,35 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,
759789
return irq_find_matching_fwnode(handle, bus_token);
760790
}
761791

792+
struct fwnode_handle *iort_iwb_handle(u32 iwb_id)
793+
{
794+
struct fwnode_handle *fwnode;
795+
struct acpi_iort_node *node;
796+
struct acpi_device *device;
797+
struct acpi_iort_iwb *iwb;
798+
acpi_status status;
799+
acpi_handle handle;
800+
801+
/* find its associated IWB node */
802+
node = iort_scan_node(ACPI_IORT_NODE_IWB, iort_match_iwb_callback, &iwb_id);
803+
if (!node)
804+
return NULL;
805+
806+
iwb = (struct acpi_iort_iwb *)node->node_data;
807+
status = acpi_get_handle(NULL, iwb->device_name, &handle);
808+
if (ACPI_FAILURE(status))
809+
return NULL;
810+
811+
device = acpi_get_acpi_dev(handle);
812+
if (!device)
813+
return NULL;
814+
815+
fwnode = acpi_fwnode_handle(device);
816+
acpi_put_acpi_dev(device);
817+
818+
return fwnode;
819+
}
820+
762821
static void iort_set_device_domain(struct device *dev,
763822
struct acpi_iort_node *node)
764823
{
@@ -819,8 +878,14 @@ static struct irq_domain *iort_get_platform_device_domain(struct device *dev)
819878
/* find its associated iort node */
820879
node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
821880
iort_match_node_callback, dev);
822-
if (!node)
823-
return NULL;
881+
if (!node) {
882+
/* find its associated iort node */
883+
node = iort_scan_node(ACPI_IORT_NODE_IWB,
884+
iort_match_node_callback, dev);
885+
886+
if (!node)
887+
return NULL;
888+
}
824889

825890
/* then find its msi parent node */
826891
for (i = 0; i < node->mapping_count; i++) {

drivers/irqchip/irq-gic-v5-iwb.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
#define pr_fmt(fmt) "GICv5 IWB: " fmt
66

7+
#include <linux/acpi.h>
78
#include <linux/init.h>
89
#include <linux/kernel.h>
910
#include <linux/msi.h>
@@ -136,18 +137,31 @@ static int gicv5_iwb_irq_domain_translate(struct irq_domain *d, struct irq_fwspe
136137
irq_hw_number_t *hwirq,
137138
unsigned int *type)
138139
{
139-
if (!is_of_node(fwspec->fwnode))
140-
return -EINVAL;
140+
if (is_of_node(fwspec->fwnode)) {
141141

142-
if (fwspec->param_count < 2)
143-
return -EINVAL;
142+
if (fwspec->param_count < 2)
143+
return -EINVAL;
144144

145-
/*
146-
* param[0] is be the wire
147-
* param[1] is the interrupt type
148-
*/
149-
*hwirq = fwspec->param[0];
150-
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
145+
/*
146+
* param[0] is be the wire
147+
* param[1] is the interrupt type
148+
*/
149+
*hwirq = fwspec->param[0];
150+
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
151+
}
152+
153+
if (is_acpi_device_node(fwspec->fwnode)) {
154+
155+
if (fwspec->param_count < 2)
156+
return -EINVAL;
157+
158+
/*
159+
* Extract the wire from param[0]
160+
* param[1] is the interrupt type
161+
*/
162+
*hwirq = FIELD_GET(GICV5_GSI_IWB_WIRE, fwspec->param[0]);
163+
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
164+
}
151165

152166
return 0;
153167
}
@@ -265,10 +279,18 @@ static const struct of_device_id gicv5_iwb_of_match[] = {
265279
};
266280
MODULE_DEVICE_TABLE(of, gicv5_iwb_of_match);
267281

282+
#ifdef CONFIG_ACPI
283+
static const struct acpi_device_id iwb_acpi_match[] = {
284+
{ "ARMH0003", 0 },
285+
{}
286+
};
287+
#endif
288+
268289
static struct platform_driver gicv5_iwb_platform_driver = {
269290
.driver = {
270291
.name = "GICv5 IWB",
271292
.of_match_table = gicv5_iwb_of_match,
293+
.acpi_match_table = ACPI_PTR(iwb_acpi_match),
272294
.suppress_bind_attrs = true,
273295
},
274296
.probe = gicv5_iwb_device_probe,

drivers/irqchip/irq-gic-v5.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#define pr_fmt(fmt) "GICv5: " fmt
77

8+
#include <linux/acpi_iort.h>
89
#include <linux/cpuhotplug.h>
910
#include <linux/idr.h>
1011
#include <linux/irqdomain.h>
@@ -1187,6 +1188,9 @@ static struct fwnode_handle *gsi_domain_handle;
11871188

11881189
static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi)
11891190
{
1191+
if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
1192+
return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
1193+
11901194
return gsi_domain_handle;
11911195
}
11921196

include/linux/acpi_iort.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ int iort_register_domain_token(int trans_id, phys_addr_t base,
2727
struct fwnode_handle *fw_node);
2828
void iort_deregister_domain_token(int trans_id);
2929
struct fwnode_handle *iort_find_domain_token(int trans_id);
30+
struct fwnode_handle *iort_iwb_handle(u32 iwb_id);
3031

3132
#ifdef CONFIG_ACPI_IORT
3233
u32 iort_msi_map_id(struct device *dev, u32 id);

include/linux/irqchip/arm-gic-v5.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,12 @@
265265

266266
#define GICV5_IWB_WENABLE_STATUSR_IDLE BIT(0)
267267

268+
#define GICV5_GSI_IC_TYPE GENMASK(31, 29)
269+
#define GICV5_GSI_IWB_TYPE 0x7
270+
271+
#define GICV5_GSI_IWB_FRAME_ID GENMASK(28, 16)
272+
#define GICV5_GSI_IWB_WIRE GENMASK(15, 0)
273+
268274
/*
269275
* Global Data structures and functions
270276
*/

0 commit comments

Comments
 (0)