From d89cf2e4182603a04e34bdf5622b21a287986bea Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 7 Mar 2017 20:39:56 +0800 Subject: ACPI/IORT: Fix the indentation in iort_scan_node() The indentation in the iort_scan_node() function is wrong, fix it. Signed-off-by: Hanjun Guo [lorenzo.pieralisi@arm.com: massaged commit log] Signed-off-by: Lorenzo Pieralisi Tested-by: Ming Lei Tested-by: Wei Xu Tested-by: Sinan Kaya --- drivers/acpi/arm64/iort.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/acpi/arm64') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 4a5bb967250b..2e368a6aebda 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -225,7 +225,7 @@ static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type, if (iort_node->type == type && ACPI_SUCCESS(callback(iort_node, context))) - return iort_node; + return iort_node; iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node, iort_node->length); -- cgit v1.2.3 From 6cb6bf56dc15ec3954186524cd9a41347a18ebc8 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 7 Mar 2017 20:39:57 +0800 Subject: ACPI/IORT: Add missing comment for iort_dev_find_its_id() Add missing req_id parameter to the iort_dev_find_its_id() function kernel-doc comment. Signed-off-by: Hanjun Guo Signed-off-by: Lorenzo Pieralisi Tested-by: Ming Lei Tested-by: Wei Xu Tested-by: Sinan Kaya Cc: Lorenzo Pieralisi Cc: Tomasz Nowicki --- drivers/acpi/arm64/iort.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/acpi/arm64') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 2e368a6aebda..abc5774148d7 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -450,6 +450,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id) /** * iort_dev_find_its_id() - Find the ITS identifier for a device * @dev: The device. + * @req_id: Device's requester ID * @idx: Index of the ITS identifier list. * @its_id: ITS identifier. * -- cgit v1.2.3 From c92bdfe8e7a6133fdbe8a2a08c68446dc2e52a17 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 7 Mar 2017 20:39:58 +0800 Subject: ACPI/IORT: Rework iort_match_node_callback() return value handling The return value handling in iort_match_node_callback() is too convoluted; update the iort_match_node_callback() return value handling to make code easier to read. Signed-off-by: Hanjun Guo [lorenzo.pieralisi@arm.com: rewrote commit log] Signed-off-by: Lorenzo Pieralisi Tested-by: Ming Lei Tested-by: Wei Xu Tested-by: Sinan Kaya Cc: Lorenzo Pieralisi Cc: Tomasz Nowicki --- drivers/acpi/arm64/iort.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/acpi/arm64') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index abc5774148d7..a6b807d64565 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -253,17 +253,15 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node, void *context) { struct device *dev = context; - acpi_status status; + acpi_status status = AE_NOT_FOUND; if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) { struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_device *adev = to_acpi_device_node(dev->fwnode); struct acpi_iort_named_component *ncomp; - if (!adev) { - status = AE_NOT_FOUND; + if (!adev) goto out; - } status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf); if (ACPI_FAILURE(status)) { @@ -289,8 +287,6 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node, */ status = pci_rc->pci_segment_number == pci_domain_nr(bus) ? AE_OK : AE_NOT_FOUND; - } else { - status = AE_NOT_FOUND; } out: return status; -- cgit v1.2.3 From 697f609358685f20a798e0af2dc869b8c40bda32 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 7 Mar 2017 20:40:03 +0800 Subject: ACPI/IORT: Rename iort_node_map_rid() to make it generic iort_node_map_rid() was designed to take an input id (that is not necessarily a PCI requester id) and map it to an output id (eg an SMMU streamid or an ITS deviceid) according to the mappings provided by an IORT node mapping entries. This means that the iort_node_map_rid() input id is not always a PCI requester id as its name, parameters and local variables suggest, which is misleading. Apply the s/rid/id substitution to the iort_node_map_rid() mapping function and its users to make sure its intended usage is clearer. Suggested-by: Lorenzo Pieralisi Signed-off-by: Hanjun Guo Signed-off-by: Lorenzo Pieralisi Tested-by: Ming Lei Tested-by: Wei Xu Tested-by: Sinan Kaya Cc: Lorenzo Pieralisi Cc: Tomasz Nowicki --- drivers/acpi/arm64/iort.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/acpi/arm64') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index a6b807d64565..28d0088e71d5 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -355,11 +355,11 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node, return NULL; } -static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node, - u32 rid_in, u32 *rid_out, - u8 type_mask) +static struct acpi_iort_node *iort_node_map_id(struct acpi_iort_node *node, + u32 id_in, u32 *id_out, + u8 type_mask) { - u32 rid = rid_in; + u32 id = id_in; /* Parse the ID mapping tree to find specified node type */ while (node) { @@ -367,8 +367,8 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node, int i; if (IORT_TYPE_MASK(node->type) & type_mask) { - if (rid_out) - *rid_out = rid; + if (id_out) + *id_out = id; return node; } @@ -385,9 +385,9 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node, goto fail_map; } - /* Do the RID translation */ + /* Do the ID translation */ for (i = 0; i < node->mapping_count; i++, map++) { - if (!iort_id_map(map, node->type, rid, &rid)) + if (!iort_id_map(map, node->type, id, &id)) break; } @@ -399,9 +399,9 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node, } fail_map: - /* Map input RID to output RID unchanged on mapping failure*/ - if (rid_out) - *rid_out = rid_in; + /* Map input ID to output ID unchanged on mapping failure */ + if (id_out) + *id_out = id_in; return NULL; } @@ -439,7 +439,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id) if (!node) return req_id; - iort_node_map_rid(node, req_id, &dev_id, IORT_MSI_TYPE); + iort_node_map_id(node, req_id, &dev_id, IORT_MSI_TYPE); return dev_id; } @@ -462,7 +462,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id, if (!node) return -ENXIO; - node = iort_node_map_rid(node, req_id, NULL, IORT_MSI_TYPE); + node = iort_node_map_id(node, req_id, NULL, IORT_MSI_TYPE); if (!node) return -ENXIO; @@ -591,8 +591,8 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) if (!node) return NULL; - parent = iort_node_map_rid(node, rid, &streamid, - IORT_IOMMU_TYPE); + parent = iort_node_map_id(node, rid, &streamid, + IORT_IOMMU_TYPE); ops = iort_iommu_xlate(dev, parent, streamid); -- cgit v1.2.3 From 8ca4f1d3fbb85d8d87ca293500a69c3dc901beb9 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 7 Mar 2017 20:40:04 +0800 Subject: ACPI/IORT: Introduce iort_node_map_platform_id() to retrieve dev id To retrieve dev id for IORT named components nodes there are two steps involved (second is optional): (1) Retrieve the initial id (this may well provide the final mapping) (2) Map the id (optional if (1) represents the map type we need), this is needed for use cases such as NC (named component) -> SMMU -> ITS mappings. the iort_node_get_id() function was created for step (1) above and iort_node_map_rid() for step (2). Create a wrapper, named iort_node_map_platform_id(), that encompasses the two steps at once to retrieve the dev id to provide steps (1)-(2) functionality. iort_node_map_platform_id() will handle the parent type so type handling in iort_node_get_id() is duplicated, remove it and update current iort_node_get_id() users to move them over to iort_node_map_platform_id(). Suggested-by: Lorenzo Pieralisi Suggested-by: Tomasz Nowicki Signed-off-by: Hanjun Guo [lorenzo.pieralisi@arm.com: rewrote commit log] Signed-off-by: Lorenzo Pieralisi Tested-by: Ming Lei Tested-by: Wei Xu Tested-by: Sinan Kaya Cc: Lorenzo Pieralisi Cc: Tomasz Nowicki --- drivers/acpi/arm64/iort.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) (limited to 'drivers/acpi/arm64') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 28d0088e71d5..83cd59dcb8b3 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -318,8 +318,7 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in, static struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node, - u32 *id_out, u8 type_mask, - int index) + u32 *id_out, int index) { struct acpi_iort_node *parent; struct acpi_iort_id_mapping *map; @@ -341,9 +340,6 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node, parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table, map->output_reference); - if (!(IORT_TYPE_MASK(parent->type) & type_mask)) - return NULL; - if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) { if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT || node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) { @@ -406,6 +402,34 @@ fail_map: return NULL; } +static +struct acpi_iort_node *iort_node_map_platform_id(struct acpi_iort_node *node, + u32 *id_out, u8 type_mask, + int index) +{ + struct acpi_iort_node *parent; + u32 id; + + /* step 1: retrieve the initial dev id */ + parent = iort_node_get_id(node, &id, index); + if (!parent) + return NULL; + + /* + * optional step 2: map the initial dev id if its parent is not + * the target type we want, map it again for the use cases such + * as NC (named component) -> SMMU -> ITS. If the type is matched, + * return the initial dev id and its parent pointer directly. + */ + if (!(IORT_TYPE_MASK(parent->type) & type_mask)) + parent = iort_node_map_id(parent, id, id_out, type_mask); + else + if (id_out) + *id_out = id; + + return parent; +} + static struct acpi_iort_node *iort_find_dev_node(struct device *dev) { struct pci_bus *pbus; @@ -604,14 +628,15 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev) if (!node) return NULL; - parent = iort_node_get_id(node, &streamid, - IORT_IOMMU_TYPE, i++); + parent = iort_node_map_platform_id(node, &streamid, + IORT_IOMMU_TYPE, i++); while (parent) { ops = iort_iommu_xlate(dev, parent, streamid); - parent = iort_node_get_id(node, &streamid, - IORT_IOMMU_TYPE, i++); + parent = iort_node_map_platform_id(node, &streamid, + IORT_IOMMU_TYPE, + i++); } } -- cgit v1.2.3 From ae7c18380495ac5c14a614fdb6c452c3bf9148ac Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 7 Mar 2017 20:40:05 +0800 Subject: ACPI: platform-msi: retrieve devid from IORT For devices connecting to an ITS, the devices need to identify themself through a devid; this devid is represented in the IORT table in named component node [1] for platform devices, so this patch adds code that scans the IORT table to retrieve the devices devid. Add an IORT interface to collect ITS devices devid to carry out platform devices MSI mappings with IORT tables. [1]: https://static.docs.arm.com/den0049/b/DEN0049B_IO_Remapping_Table.pdf Signed-off-by: Hanjun Guo [lorenzo.pieralisi@arm.com: rewrote commit log/dropped ITS changes] Signed-off-by: Lorenzo Pieralisi Tested-by: Ming Lei Tested-by: Wei Xu Tested-by: Sinan Kaya Cc: Marc Zyngier Cc: Lorenzo Pieralisi Cc: Tomasz Nowicki Cc: Thomas Gleixner --- drivers/acpi/arm64/iort.c | 24 ++++++++++++++++++++++++ include/linux/acpi_iort.h | 1 + 2 files changed, 25 insertions(+) (limited to 'drivers/acpi/arm64') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 83cd59dcb8b3..fb95ceb3840d 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -467,6 +467,30 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id) return dev_id; } +/** + * iort_pmsi_get_dev_id() - Get the device id for a device + * @dev: The device for which the mapping is to be done. + * @dev_id: The device ID found. + * + * Returns: 0 for successful find a dev id, -ENODEV on error + */ +int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id) +{ + int i; + struct acpi_iort_node *node; + + node = iort_find_dev_node(dev); + if (!node) + return -ENODEV; + + for (i = 0; i < node->mapping_count; i++) { + if (iort_node_map_platform_id(node, dev_id, IORT_MSI_TYPE, i)) + return 0; + } + + return -ENODEV; +} + /** * iort_dev_find_its_id() - Find the ITS identifier for a device * @dev: The device. diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index 77e08099e554..fd8b9698e1d1 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -34,6 +34,7 @@ void acpi_iort_init(void); bool iort_node_match(u8 type); u32 iort_msi_map_rid(struct device *dev, u32 req_id); struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id); +int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id); /* IOMMU interface */ void iort_set_dma_mask(struct device *dev); const struct iommu_ops *iort_iommu_configure(struct device *dev); -- cgit v1.2.3 From d4f54a186667ffd19eac8e3f48c51d940a9b9784 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 7 Mar 2017 20:40:06 +0800 Subject: ACPI: platform: setup MSI domain for ACPI based platform device By allowing platform MSI domain to be created on ACPI platforms, a platform device MSI domain can be set-up when it is probed. In order to do that, the MSI domain the platform device connects to should be retrieved, so the iort_get_platform_device_domain() is introduced to retrieve the domain from the IORT kernel layer. With the domain retrieved, we need a proper way to set the domain to platform device. Given that some platform devices (irqchips) require the MSI irqdomain to be their interrupt parent domain, the MSI irqdomain should be determined before platform device is probed but after the platform device is allocated which means that the code setting up the MSI irqdomain, ie acpi_configure_pmsi_domain() should be called in acpi_platform_notify() (that is triggered after adding a device but before the respective driver is probed) for the platform MSI domain code set-up path to work properly. Acked-by: Rafael J. Wysocki [for glue.c] Signed-off-by: Hanjun Guo [lorenzo.pieralisi@arm.com: rewrote commit log] Signed-off-by: Lorenzo Pieralisi Tested-by: Ming Lei Tested-by: Wei Xu Tested-by: Sinan Kaya Cc: Marc Zyngier Cc: Lorenzo Pieralisi Cc: Tomasz Nowicki --- drivers/acpi/arm64/iort.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/glue.c | 6 ++++++ include/linux/acpi_iort.h | 2 ++ 3 files changed, 58 insertions(+) (limited to 'drivers/acpi/arm64') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index fb95ceb3840d..22e08d272db7 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -548,6 +548,56 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id) return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI); } +/** + * iort_get_platform_device_domain() - Find MSI domain related to a + * platform device + * @dev: the dev pointer associated with the platform device + * + * Returns: the MSI domain for this device, NULL otherwise + */ +static struct irq_domain *iort_get_platform_device_domain(struct device *dev) +{ + struct acpi_iort_node *node, *msi_parent; + struct fwnode_handle *iort_fwnode; + struct acpi_iort_its_group *its; + int i; + + /* find its associated iort node */ + node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT, + iort_match_node_callback, dev); + if (!node) + return NULL; + + /* then find its msi parent node */ + for (i = 0; i < node->mapping_count; i++) { + msi_parent = iort_node_map_platform_id(node, NULL, + IORT_MSI_TYPE, i); + if (msi_parent) + break; + } + + if (!msi_parent) + return NULL; + + /* Move to ITS specific data */ + its = (struct acpi_iort_its_group *)msi_parent->node_data; + + iort_fwnode = iort_find_domain_token(its->identifiers[0]); + if (!iort_fwnode) + return NULL; + + return irq_find_matching_fwnode(iort_fwnode, DOMAIN_BUS_PLATFORM_MSI); +} + +void acpi_configure_pmsi_domain(struct device *dev) +{ + struct irq_domain *msi_domain; + + msi_domain = iort_get_platform_device_domain(dev); + if (msi_domain) + dev_set_msi_domain(dev, msi_domain); +} + static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data) { u32 *rid = data; diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index fb19e1cdb641..ec31b439b4c8 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -6,6 +6,8 @@ * * This file is released under the GPLv2. */ + +#include #include #include #include @@ -14,6 +16,7 @@ #include #include #include +#include #include "internal.h" @@ -322,6 +325,9 @@ static int acpi_platform_notify(struct device *dev) if (!adev) goto out; + if (dev->bus == &platform_bus_type) + acpi_configure_pmsi_domain(dev); + if (type && type->setup) type->setup(dev); else if (adev->handler && adev->handler->bind) diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index fd8b9698e1d1..26e25d85eb3e 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -34,6 +34,7 @@ void acpi_iort_init(void); bool iort_node_match(u8 type); u32 iort_msi_map_rid(struct device *dev, u32 req_id); struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id); +void acpi_configure_pmsi_domain(struct device *dev); int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id); /* IOMMU interface */ void iort_set_dma_mask(struct device *dev); @@ -46,6 +47,7 @@ static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id) static inline struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id) { return NULL; } +static inline void acpi_configure_pmsi_domain(struct device *dev) { } /* IOMMU interface */ static inline void iort_set_dma_mask(struct device *dev) { } static inline -- cgit v1.2.3