linux/drivers/acpi/arm64/iort.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016, Semihalf
   3 *      Author: Tomasz Nowicki <tn@semihalf.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * This file implements early detection/parsing of I/O mapping
  15 * reported to OS through firmware via I/O Remapping Table (IORT)
  16 * IORT document number: ARM DEN 0049A
  17 */
  18
  19#define pr_fmt(fmt)     "ACPI: IORT: " fmt
  20
  21#include <linux/acpi_iort.h>
  22#include <linux/kernel.h>
  23#include <linux/pci.h>
  24
  25struct iort_its_msi_chip {
  26        struct list_head        list;
  27        struct fwnode_handle    *fw_node;
  28        u32                     translation_id;
  29};
  30
  31typedef acpi_status (*iort_find_node_callback)
  32        (struct acpi_iort_node *node, void *context);
  33
  34/* Root pointer to the mapped IORT table */
  35static struct acpi_table_header *iort_table;
  36
  37static LIST_HEAD(iort_msi_chip_list);
  38static DEFINE_SPINLOCK(iort_msi_chip_lock);
  39
  40/**
  41 * iort_register_domain_token() - register domain token and related ITS ID
  42 * to the list from where we can get it back later on.
  43 * @trans_id: ITS ID.
  44 * @fw_node: Domain token.
  45 *
  46 * Returns: 0 on success, -ENOMEM if no memory when allocating list element
  47 */
  48int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
  49{
  50        struct iort_its_msi_chip *its_msi_chip;
  51
  52        its_msi_chip = kzalloc(sizeof(*its_msi_chip), GFP_KERNEL);
  53        if (!its_msi_chip)
  54                return -ENOMEM;
  55
  56        its_msi_chip->fw_node = fw_node;
  57        its_msi_chip->translation_id = trans_id;
  58
  59        spin_lock(&iort_msi_chip_lock);
  60        list_add(&its_msi_chip->list, &iort_msi_chip_list);
  61        spin_unlock(&iort_msi_chip_lock);
  62
  63        return 0;
  64}
  65
  66/**
  67 * iort_deregister_domain_token() - Deregister domain token based on ITS ID
  68 * @trans_id: ITS ID.
  69 *
  70 * Returns: none.
  71 */
  72void iort_deregister_domain_token(int trans_id)
  73{
  74        struct iort_its_msi_chip *its_msi_chip, *t;
  75
  76        spin_lock(&iort_msi_chip_lock);
  77        list_for_each_entry_safe(its_msi_chip, t, &iort_msi_chip_list, list) {
  78                if (its_msi_chip->translation_id == trans_id) {
  79                        list_del(&its_msi_chip->list);
  80                        kfree(its_msi_chip);
  81                        break;
  82                }
  83        }
  84        spin_unlock(&iort_msi_chip_lock);
  85}
  86
  87/**
  88 * iort_find_domain_token() - Find domain token based on given ITS ID
  89 * @trans_id: ITS ID.
  90 *
  91 * Returns: domain token when find on the list, NULL otherwise
  92 */
  93struct fwnode_handle *iort_find_domain_token(int trans_id)
  94{
  95        struct fwnode_handle *fw_node = NULL;
  96        struct iort_its_msi_chip *its_msi_chip;
  97
  98        spin_lock(&iort_msi_chip_lock);
  99        list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
 100                if (its_msi_chip->translation_id == trans_id) {
 101                        fw_node = its_msi_chip->fw_node;
 102                        break;
 103                }
 104        }
 105        spin_unlock(&iort_msi_chip_lock);
 106
 107        return fw_node;
 108}
 109
 110static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
 111                                             iort_find_node_callback callback,
 112                                             void *context)
 113{
 114        struct acpi_iort_node *iort_node, *iort_end;
 115        struct acpi_table_iort *iort;
 116        int i;
 117
 118        if (!iort_table)
 119                return NULL;
 120
 121        /* Get the first IORT node */
 122        iort = (struct acpi_table_iort *)iort_table;
 123        iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
 124                                 iort->node_offset);
 125        iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
 126                                iort_table->length);
 127
 128        for (i = 0; i < iort->node_count; i++) {
 129                if (WARN_TAINT(iort_node >= iort_end, TAINT_FIRMWARE_WORKAROUND,
 130                               "IORT node pointer overflows, bad table!\n"))
 131                        return NULL;
 132
 133                if (iort_node->type == type &&
 134                    ACPI_SUCCESS(callback(iort_node, context)))
 135                                return iort_node;
 136
 137                iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
 138                                         iort_node->length);
 139        }
 140
 141        return NULL;
 142}
 143
 144static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
 145                                            void *context)
 146{
 147        struct device *dev = context;
 148        acpi_status status;
 149
 150        if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT) {
 151                struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
 152                struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
 153                struct acpi_iort_named_component *ncomp;
 154
 155                if (!adev) {
 156                        status = AE_NOT_FOUND;
 157                        goto out;
 158                }
 159
 160                status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buf);
 161                if (ACPI_FAILURE(status)) {
 162                        dev_warn(dev, "Can't get device full path name\n");
 163                        goto out;
 164                }
 165
 166                ncomp = (struct acpi_iort_named_component *)node->node_data;
 167                status = !strcmp(ncomp->device_name, buf.pointer) ?
 168                                                        AE_OK : AE_NOT_FOUND;
 169                acpi_os_free(buf.pointer);
 170        } else if (node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
 171                struct acpi_iort_root_complex *pci_rc;
 172                struct pci_bus *bus;
 173
 174                bus = to_pci_bus(dev);
 175                pci_rc = (struct acpi_iort_root_complex *)node->node_data;
 176
 177                /*
 178                 * It is assumed that PCI segment numbers maps one-to-one
 179                 * with root complexes. Each segment number can represent only
 180                 * one root complex.
 181                 */
 182                status = pci_rc->pci_segment_number == pci_domain_nr(bus) ?
 183                                                        AE_OK : AE_NOT_FOUND;
 184        } else {
 185                status = AE_NOT_FOUND;
 186        }
 187out:
 188        return status;
 189}
 190
 191static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
 192                       u32 *rid_out)
 193{
 194        /* Single mapping does not care for input id */
 195        if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) {
 196                if (type == ACPI_IORT_NODE_NAMED_COMPONENT ||
 197                    type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
 198                        *rid_out = map->output_base;
 199                        return 0;
 200                }
 201
 202                pr_warn(FW_BUG "[map %p] SINGLE MAPPING flag not allowed for node type %d, skipping ID map\n",
 203                        map, type);
 204                return -ENXIO;
 205        }
 206
 207        if (rid_in < map->input_base ||
 208            (rid_in >= map->input_base + map->id_count))
 209                return -ENXIO;
 210
 211        *rid_out = map->output_base + (rid_in - map->input_base);
 212        return 0;
 213}
 214
 215static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
 216                                                u32 rid_in, u32 *rid_out,
 217                                                u8 type)
 218{
 219        u32 rid = rid_in;
 220
 221        /* Parse the ID mapping tree to find specified node type */
 222        while (node) {
 223                struct acpi_iort_id_mapping *map;
 224                int i;
 225
 226                if (node->type == type) {
 227                        if (rid_out)
 228                                *rid_out = rid;
 229                        return node;
 230                }
 231
 232                if (!node->mapping_offset || !node->mapping_count)
 233                        goto fail_map;
 234
 235                map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
 236                                   node->mapping_offset);
 237
 238                /* Firmware bug! */
 239                if (!map->output_reference) {
 240                        pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
 241                               node, node->type);
 242                        goto fail_map;
 243                }
 244
 245                /* Do the RID translation */
 246                for (i = 0; i < node->mapping_count; i++, map++) {
 247                        if (!iort_id_map(map, node->type, rid, &rid))
 248                                break;
 249                }
 250
 251                if (i == node->mapping_count)
 252                        goto fail_map;
 253
 254                node = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
 255                                    map->output_reference);
 256        }
 257
 258fail_map:
 259        /* Map input RID to output RID unchanged on mapping failure*/
 260        if (rid_out)
 261                *rid_out = rid_in;
 262
 263        return NULL;
 264}
 265
 266static struct acpi_iort_node *iort_find_dev_node(struct device *dev)
 267{
 268        struct pci_bus *pbus;
 269
 270        if (!dev_is_pci(dev))
 271                return iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
 272                                      iort_match_node_callback, dev);
 273
 274        /* Find a PCI root bus */
 275        pbus = to_pci_dev(dev)->bus;
 276        while (!pci_is_root_bus(pbus))
 277                pbus = pbus->parent;
 278
 279        return iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
 280                              iort_match_node_callback, &pbus->dev);
 281}
 282
 283/**
 284 * iort_msi_map_rid() - Map a MSI requester ID for a device
 285 * @dev: The device for which the mapping is to be done.
 286 * @req_id: The device requester ID.
 287 *
 288 * Returns: mapped MSI RID on success, input requester ID otherwise
 289 */
 290u32 iort_msi_map_rid(struct device *dev, u32 req_id)
 291{
 292        struct acpi_iort_node *node;
 293        u32 dev_id;
 294
 295        node = iort_find_dev_node(dev);
 296        if (!node)
 297                return req_id;
 298
 299        iort_node_map_rid(node, req_id, &dev_id, ACPI_IORT_NODE_ITS_GROUP);
 300        return dev_id;
 301}
 302
 303/**
 304 * iort_dev_find_its_id() - Find the ITS identifier for a device
 305 * @dev: The device.
 306 * @idx: Index of the ITS identifier list.
 307 * @its_id: ITS identifier.
 308 *
 309 * Returns: 0 on success, appropriate error value otherwise
 310 */
 311static int iort_dev_find_its_id(struct device *dev, u32 req_id,
 312                                unsigned int idx, int *its_id)
 313{
 314        struct acpi_iort_its_group *its;
 315        struct acpi_iort_node *node;
 316
 317        node = iort_find_dev_node(dev);
 318        if (!node)
 319                return -ENXIO;
 320
 321        node = iort_node_map_rid(node, req_id, NULL, ACPI_IORT_NODE_ITS_GROUP);
 322        if (!node)
 323                return -ENXIO;
 324
 325        /* Move to ITS specific data */
 326        its = (struct acpi_iort_its_group *)node->node_data;
 327        if (idx > its->its_count) {
 328                dev_err(dev, "requested ITS ID index [%d] is greater than available [%d]\n",
 329                        idx, its->its_count);
 330                return -ENXIO;
 331        }
 332
 333        *its_id = its->identifiers[idx];
 334        return 0;
 335}
 336
 337/**
 338 * iort_get_device_domain() - Find MSI domain related to a device
 339 * @dev: The device.
 340 * @req_id: Requester ID for the device.
 341 *
 342 * Returns: the MSI domain for this device, NULL otherwise
 343 */
 344struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
 345{
 346        struct fwnode_handle *handle;
 347        int its_id;
 348
 349        if (iort_dev_find_its_id(dev, req_id, 0, &its_id))
 350                return NULL;
 351
 352        handle = iort_find_domain_token(its_id);
 353        if (!handle)
 354                return NULL;
 355
 356        return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
 357}
 358
 359void __init acpi_iort_init(void)
 360{
 361        acpi_status status;
 362
 363        status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
 364        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
 365                const char *msg = acpi_format_exception(status);
 366                pr_err("Failed to get table, %s\n", msg);
 367        }
 368}
 369