On 07/06/16 15:34, Tomasz Nowicki wrote:
> On 04.06.2016 13:15, Marc Zyngier wrote:
>> On Tue, 31 May 2016 13:19:38 +0200
>> Tomasz Nowicki <[email protected]> wrote:
>>
>>> IORT shows representation of IO topology for ARM based systems.
>>> It describes how various components are connected together on
>>> parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
>>>
>>> Initial support allows to:
>>> - register ITS MSI chip along with ITS translation ID and domain token
>>> - deregister ITS MSI chip based on ITS translation ID
>>> - find registered domain token based on ITS translation ID
>>> - map MSI RID based on PCI device and requester ID
>>> - find domain token based on PCI device and requester ID
>>>
>>> Signed-off-by: Tomasz Nowicki <[email protected]>
>>> ---
>>>   drivers/acpi/Kconfig  |   3 +
>>>   drivers/acpi/Makefile |   1 +
>>>   drivers/acpi/iort.c   | 344 
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>>   include/linux/iort.h  |  38 ++++++
>>>   4 files changed, 386 insertions(+)
>>>   create mode 100644 drivers/acpi/iort.c
>>>   create mode 100644 include/linux/iort.h
>>>
>>> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
>>> index b7e2e77..848471f 100644
>>> --- a/drivers/acpi/Kconfig
>>> +++ b/drivers/acpi/Kconfig
>>> @@ -57,6 +57,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
>>>   config ACPI_CCA_REQUIRED
>>>     bool
>>>
>>> +config IORT_TABLE
>>> +   bool
>>> +
>>>   config ACPI_DEBUGGER
>>>     bool "AML debugger interface"
>>>     select ACPI_DEBUG
>>> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
>>> index 251ce85..c7c9b29 100644
>>> --- a/drivers/acpi/Makefile
>>> +++ b/drivers/acpi/Makefile
>>> @@ -82,6 +82,7 @@ obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
>>>   obj-$(CONFIG_ACPI_BGRT)           += bgrt.o
>>>   obj-$(CONFIG_ACPI_CPPC_LIB)       += cppc_acpi.o
>>>   obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o
>>> +obj-$(CONFIG_IORT_TABLE)   += iort.o
>>>
>>>   # processor has its own "processor." module_param namespace
>>>   processor-y                       := processor_driver.o
>>> diff --git a/drivers/acpi/iort.c b/drivers/acpi/iort.c
>>> new file mode 100644
>>> index 0000000..226eb6d
>>> --- /dev/null
>>> +++ b/drivers/acpi/iort.c
>>> @@ -0,0 +1,344 @@
>>> +/*
>>> + * Copyright (C) 2016, Semihalf
>>> + * Author: Tomasz Nowicki <[email protected]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify it
>>> + * under the terms and conditions of the GNU General Public License,
>>> + * version 2, as published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope it will be useful, but WITHOUT
>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
>>> for
>>> + * more details.
>>> + *
>>> + * This file implements early detection/parsing of I/O mapping
>>> + * reported to OS through firmware via I/O Remapping Table (IORT)
>>> + * IORT document number: ARM DEN 0049A
>>> + */
>>> +
>>> +#define pr_fmt(fmt)        "ACPI: IORT: " fmt
>>> +
>>> +#include <linux/export.h>
>>> +#include <linux/iort.h>
>>> +#include <linux/irqdomain.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/pci.h>
>>> +
>>> +struct iort_its_msi_chip {
>>> +   struct list_head        list;
>>> +   struct fwnode_handle    *fw_node;
>>> +   u32                     translation_id;
>>> +};
>>> +
>>> +typedef acpi_status (*iort_find_node_callback)
>>> +   (struct acpi_iort_node *node, void *context);
>>> +
>>> +/* Root pointer to the mapped IORT table */
>>> +static struct acpi_table_header *iort_table;
>>> +
>>> +static LIST_HEAD(iort_msi_chip_list);
>>> +
>>> +/**
>>> + * iort_register_domain_token() - register domain token and related ITS ID
>>> + *                                   to the list from where we can get it 
>>> back
>>> + *                                   later on.
>>> + * @translation_id: ITS ID
>>> + * @token: domain token
>>> + *
>>> + * Returns: 0 on success, -ENOMEM if not memory when allocating list 
>>> element.
>>> + */
>>> +int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
>>> +{
>>> +   struct iort_its_msi_chip *its_msi_chip;
>>> +
>>> +   its_msi_chip = kzalloc(sizeof(*its_msi_chip), GFP_KERNEL);
>>> +   if (!its_msi_chip)
>>> +           return -ENOMEM;
>>> +
>>> +   its_msi_chip->fw_node = fw_node;
>>> +   its_msi_chip->translation_id = trans_id;
>>> +
>>> +   list_add(&its_msi_chip->list, &iort_msi_chip_list);
>>
>> No locking? How do you handle concurrent accesses?
> 
> I wandered if we need locking here but at the end I did not find 
> worst-case scenario.
> 
> 1. Adding elements to list is done in first place here (later on list is 
> not modified):
> start_kernel -> init_IRQ -> [...] - > gic_acpi_parse_madt_its -> 
> iort_register_domain_token
> 
> 2. Then we only retrieving elements form list:
> 
> start_kernel -> rest_init -> kernel_init -> [...] -> do_initcalls -> 
> its_pci_msi_init -> its_pci_acpi_msi_init -> iort_its_find_domain_token
> 
> pci_set_msi_domain -> iort_get_device_domain -> iort_its_find_domain_token
> 
> Do you mean some specific case?

Not right now, but as a matter of principle, shared data structures
should be protected (law of minimal surprise). And that will still work
if someone comes up with a fancy hot-pluggable socket that has an ITS on it.

[...]

>>> +static struct acpi_iort_node *
>>> +iort_dev_map_rid(struct acpi_iort_node *node, u32 rid_in,
>>> +                       u32 *rid_out)
>>
>> Given that there is no "dev" involved in this functions, but only
>> nodes, consider renaming this to iort_node_map_rid.
> 
> +1
> 
>>
>>> +{
>>> +
>>> +   if (!node)
>>> +           goto out;
>>> +
>>> +   /* Go upstream */
>>> +   while (node->type != ACPI_IORT_NODE_ITS_GROUP) {
>>> +           struct acpi_iort_id_mapping *id;
>>> +           int i, found = 0;
>>> +
>>> +           /* Exit when no mapping array */
>>> +           if (!node->mapping_offset || !node->mapping_count)
>>> +                   return NULL;
>>> +
>>> +           id = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
>>> +                             node->mapping_offset);
>>> +
>>> +           for (i = 0, found = 0; i < node->mapping_count; i++, id++) {
>>> +                   /*
>>> +                    * Single mapping is not translation rule,
>>> +                    * lets move on for this case
>>> +                    */
>>> +                   if (id->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
>>> +                           if (node->type != ACPI_IORT_NODE_SMMU) {
>>> +                                   rid_in = id->output_base;
>>> +                                   found = 1;
>>> +                                   break;
>>> +                           }
>>> +
>>> +                           pr_warn(FW_BUG "[node %p type %d] SINGLE 
>>> MAPPING flag not allowed for SMMU node, skipping ID map\n",
>>> +                                   node, node->type);
>>> +                           continue;
>>> +                   }
>>> +
>>> +                   if (rid_in < id->input_base ||
>>> +                       (rid_in > id->input_base + id->id_count))
>>> +                           continue;
>>> +
>>> +                   rid_in = id->output_base + (rid_in - id->input_base);
>>> +                   found = 1;
>>> +                   break;
>>> +           }
>>> +
>>> +           if (!found)
>>> +                   return NULL;
>>> +
>>> +           /* Firmware bug! */
>>> +           if (!id->output_reference) {
>>> +                   pr_err(FW_BUG "[node %p type %d] ID map has NULL parent 
>>> reference\n",
>>> +                          node, node->type);
>>> +                   return NULL;
>>> +           }
>>> +
>>> +           node = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
>>> +                               id->output_reference);
>>> +   }
>>
>> Do we always want to resolve an ID from the device down to the last
>> possible transformation? While this works fine for the ITS (which is
>> supposed to be the last user of the RID), this may not work that well
>> for intermediate remapping elements (IOMMU, for example).
>>
>> So I'm wondering if what we actually want is something that would say
>> iort_node_map_rid(from_node, to_node, rid_in, &rid_out)?
> 
> Good point. Actually Lorenzo improved that function in his SMMU ACPI 
> series addressing your comment. So we can make it more generic from day one.

Indeed. He also has a couple of fixes that you could directly include in
the next drop.

Thanks,

        M.
-- 
Jazz is not dead. It just smells funny...

Reply via email to