Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9349e81e authored by Catalin Marinas's avatar Catalin Marinas
Browse files

Merge tag 'acpi-arm64-for-v4.12' of...

Merge tag 'acpi-arm64-for-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux into for-next/core

ACPI ARM64 specific changes for v4.12.

Patches contain:

- IORT kernel interface misc clean-ups
- IORT id mapping interface refactoring in preparation for platform
  MSI (IORT named components -> GIC ITS mappings) devid mapping code
- IORT id mapping implementation for named components nodes to ITS nodes,
  in order to provide the kernel with a firmware interface to map
  platform devices devids to GIC ITS components

* tag 'acpi-arm64-for-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux:
  ACPI: platform: setup MSI domain for ACPI based platform device
  ACPI: platform-msi: retrieve devid from IORT
  ACPI/IORT: Introduce iort_node_map_platform_id() to retrieve dev id
  ACPI/IORT: Rename iort_node_map_rid() to make it generic
  ACPI/IORT: Rework iort_match_node_callback() return value handling
  ACPI/IORT: Add missing comment for iort_dev_find_its_id()
  ACPI/IORT: Fix the indentation in iort_scan_node()
parents cad27ef2 d4f54a18
Loading
Loading
Loading
Loading
+127 −31
Original line number Original line Diff line number Diff line
@@ -253,17 +253,15 @@ static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
					    void *context)
					    void *context)
{
{
	struct device *dev = context;
	struct device *dev = context;
	acpi_status status;
	acpi_status status = AE_NOT_FOUND;


	if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
	if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
		struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
		struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
		struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
		struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
		struct acpi_iort_named_component *ncomp;
		struct acpi_iort_named_component *ncomp;


		if (!adev) {
		if (!adev)
			status = AE_NOT_FOUND;
			goto out;
			goto out;
		}


		status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
		status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
		if (ACPI_FAILURE(status)) {
		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) ?
		status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
							AE_OK : AE_NOT_FOUND;
							AE_OK : AE_NOT_FOUND;
	} else {
		status = AE_NOT_FOUND;
	}
	}
out:
out:
	return status;
	return status;
@@ -322,8 +318,7 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,


static
static
struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
					u32 *id_out, u8 type_mask,
					u32 *id_out, int index)
					int index)
{
{
	struct acpi_iort_node *parent;
	struct acpi_iort_node *parent;
	struct acpi_iort_id_mapping *map;
	struct acpi_iort_id_mapping *map;
@@ -345,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,
	parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
			       map->output_reference);
			       map->output_reference);


	if (!(IORT_TYPE_MASK(parent->type) & type_mask))
		return NULL;

	if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
	if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
		if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
		if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
		    node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
		    node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
@@ -359,11 +351,11 @@ struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
	return NULL;
	return NULL;
}
}


static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
static struct acpi_iort_node *iort_node_map_id(struct acpi_iort_node *node,
						u32 rid_in, u32 *rid_out,
					       u32 id_in, u32 *id_out,
					       u8 type_mask)
					       u8 type_mask)
{
{
	u32 rid = rid_in;
	u32 id = id_in;


	/* Parse the ID mapping tree to find specified node type */
	/* Parse the ID mapping tree to find specified node type */
	while (node) {
	while (node) {
@@ -371,8 +363,8 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
		int i;
		int i;


		if (IORT_TYPE_MASK(node->type) & type_mask) {
		if (IORT_TYPE_MASK(node->type) & type_mask) {
			if (rid_out)
			if (id_out)
				*rid_out = rid;
				*id_out = id;
			return node;
			return node;
		}
		}


@@ -389,9 +381,9 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
			goto fail_map;
			goto fail_map;
		}
		}


		/* Do the RID translation */
		/* Do the ID translation */
		for (i = 0; i < node->mapping_count; i++, map++) {
		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;
				break;
		}
		}


@@ -403,11 +395,39 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
	}
	}


fail_map:
fail_map:
	/* Map input RID to output RID unchanged on mapping failure*/
	/* Map input ID to output ID unchanged on mapping failure */
	if (rid_out)
	if (id_out)
		*rid_out = rid_in;
		*id_out = id_in;

	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;
		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)
static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
@@ -443,13 +463,38 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
	if (!node)
	if (!node)
		return req_id;
		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;
	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
 * iort_dev_find_its_id() - Find the ITS identifier for a device
 * @dev: The device.
 * @dev: The device.
 * @req_id: Device's requester ID
 * @idx: Index of the ITS identifier list.
 * @idx: Index of the ITS identifier list.
 * @its_id: ITS identifier.
 * @its_id: ITS identifier.
 *
 *
@@ -465,7 +510,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
	if (!node)
	if (!node)
		return -ENXIO;
		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)
	if (!node)
		return -ENXIO;
		return -ENXIO;


@@ -503,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);
	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)
static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
{
{
	u32 *rid = data;
	u32 *rid = data;
@@ -594,7 +689,7 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
		if (!node)
		if (!node)
			return NULL;
			return NULL;


		parent = iort_node_map_rid(node, rid, &streamid,
		parent = iort_node_map_id(node, rid, &streamid,
					  IORT_IOMMU_TYPE);
					  IORT_IOMMU_TYPE);


		ops = iort_iommu_xlate(dev, parent, streamid);
		ops = iort_iommu_xlate(dev, parent, streamid);
@@ -607,14 +702,15 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
		if (!node)
		if (!node)
			return NULL;
			return NULL;


		parent = iort_node_get_id(node, &streamid,
		parent = iort_node_map_platform_id(node, &streamid,
						   IORT_IOMMU_TYPE, i++);
						   IORT_IOMMU_TYPE, i++);


		while (parent) {
		while (parent) {
			ops = iort_iommu_xlate(dev, parent, streamid);
			ops = iort_iommu_xlate(dev, parent, streamid);


			parent = iort_node_get_id(node, &streamid,
			parent = iort_node_map_platform_id(node, &streamid,
						  IORT_IOMMU_TYPE, i++);
							   IORT_IOMMU_TYPE,
							   i++);
		}
		}
	}
	}


+6 −0
Original line number Original line Diff line number Diff line
@@ -6,6 +6,8 @@
 *
 *
 * This file is released under the GPLv2.
 * This file is released under the GPLv2.
 */
 */

#include <linux/acpi_iort.h>
#include <linux/export.h>
#include <linux/export.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/list.h>
@@ -14,6 +16,7 @@
#include <linux/rwsem.h>
#include <linux/rwsem.h>
#include <linux/acpi.h>
#include <linux/acpi.h>
#include <linux/dma-mapping.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>


#include "internal.h"
#include "internal.h"


@@ -322,6 +325,9 @@ static int acpi_platform_notify(struct device *dev)
	if (!adev)
	if (!adev)
		goto out;
		goto out;


	if (dev->bus == &platform_bus_type)
		acpi_configure_pmsi_domain(dev);

	if (type && type->setup)
	if (type && type->setup)
		type->setup(dev);
		type->setup(dev);
	else if (adev->handler && adev->handler->bind)
	else if (adev->handler && adev->handler->bind)
+3 −0
Original line number Original line Diff line number Diff line
@@ -34,6 +34,8 @@ void acpi_iort_init(void);
bool iort_node_match(u8 type);
bool iort_node_match(u8 type);
u32 iort_msi_map_rid(struct device *dev, u32 req_id);
u32 iort_msi_map_rid(struct device *dev, u32 req_id);
struct irq_domain *iort_get_device_domain(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 */
/* IOMMU interface */
void iort_set_dma_mask(struct device *dev);
void iort_set_dma_mask(struct device *dev);
const struct iommu_ops *iort_iommu_configure(struct device *dev);
const struct iommu_ops *iort_iommu_configure(struct device *dev);
@@ -45,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,
static inline struct irq_domain *iort_get_device_domain(struct device *dev,
							u32 req_id)
							u32 req_id)
{ return NULL; }
{ return NULL; }
static inline void acpi_configure_pmsi_domain(struct device *dev) { }
/* IOMMU interface */
/* IOMMU interface */
static inline void iort_set_dma_mask(struct device *dev) { }
static inline void iort_set_dma_mask(struct device *dev) { }
static inline
static inline