--- /dev/null
- int coresight_device_fwnode_match(struct device *dev, void *fwnode)
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * Copyright (c) 2012, The Linux Foundation. All rights reserved.
 + */
 +
 +#include <linux/acpi.h>
 +#include <linux/types.h>
 +#include <linux/err.h>
 +#include <linux/slab.h>
 +#include <linux/clk.h>
 +#include <linux/of.h>
 +#include <linux/of_address.h>
 +#include <linux/of_graph.h>
 +#include <linux/of_platform.h>
 +#include <linux/platform_device.h>
 +#include <linux/amba/bus.h>
 +#include <linux/coresight.h>
 +#include <linux/cpumask.h>
 +#include <asm/smp_plat.h>
 +
 +#include "coresight-priv.h"
 +/*
 + * coresight_alloc_conns: Allocate connections record for each output
 + * port from the device.
 + */
 +static int coresight_alloc_conns(struct device *dev,
 +                               struct coresight_platform_data *pdata)
 +{
 +      if (pdata->nr_outport) {
 +              pdata->conns = devm_kzalloc(dev, pdata->nr_outport *
 +                                          sizeof(*pdata->conns),
 +                                          GFP_KERNEL);
 +              if (!pdata->conns)
 +                      return -ENOMEM;
 +      }
 +
 +      return 0;
 +}
 +
++int coresight_device_fwnode_match(struct device *dev, const void *fwnode)
 +{
 +      return dev_fwnode(dev) == fwnode;
 +}
 +
 +static struct device *
 +coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
 +{
 +      struct device *dev = NULL;
 +
 +      /*
 +       * If we have a non-configurable replicator, it will be found on the
 +       * platform bus.
 +       */
 +      dev = bus_find_device(&platform_bus_type, NULL,
 +                            fwnode, coresight_device_fwnode_match);
 +      if (dev)
 +              return dev;
 +
 +      /*
 +       * We have a configurable component - circle through the AMBA bus
 +       * looking for the device that matches the endpoint node.
 +       */
 +      return bus_find_device(&amba_bustype, NULL,
 +                             fwnode, coresight_device_fwnode_match);
 +}
 +
 +#ifdef CONFIG_OF
 +static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
 +{
 +      return of_property_read_bool(ep, "slave-mode");
 +}
 +
 +static void of_coresight_get_ports_legacy(const struct device_node *node,
 +                                        int *nr_inport, int *nr_outport)
 +{
 +      struct device_node *ep = NULL;
 +      int in = 0, out = 0;
 +
 +      do {
 +              ep = of_graph_get_next_endpoint(node, ep);
 +              if (!ep)
 +                      break;
 +
 +              if (of_coresight_legacy_ep_is_input(ep))
 +                      in++;
 +              else
 +                      out++;
 +
 +      } while (ep);
 +
 +      *nr_inport = in;
 +      *nr_outport = out;
 +}
 +
 +static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
 +{
 +      struct device_node *parent = of_graph_get_port_parent(ep);
 +
 +      /*
 +       * Skip one-level up to the real device node, if we
 +       * are using the new bindings.
 +       */
 +      if (of_node_name_eq(parent, "in-ports") ||
 +          of_node_name_eq(parent, "out-ports"))
 +              parent = of_get_next_parent(parent);
 +
 +      return parent;
 +}
 +
 +static inline struct device_node *
 +of_coresight_get_input_ports_node(const struct device_node *node)
 +{
 +      return of_get_child_by_name(node, "in-ports");
 +}
 +
 +static inline struct device_node *
 +of_coresight_get_output_ports_node(const struct device_node *node)
 +{
 +      return of_get_child_by_name(node, "out-ports");
 +}
 +
 +static inline int
 +of_coresight_count_ports(struct device_node *port_parent)
 +{
 +      int i = 0;
 +      struct device_node *ep = NULL;
 +
 +      while ((ep = of_graph_get_next_endpoint(port_parent, ep)))
 +              i++;
 +      return i;
 +}
 +
 +static void of_coresight_get_ports(const struct device_node *node,
 +                                 int *nr_inport, int *nr_outport)
 +{
 +      struct device_node *input_ports = NULL, *output_ports = NULL;
 +
 +      input_ports = of_coresight_get_input_ports_node(node);
 +      output_ports = of_coresight_get_output_ports_node(node);
 +
 +      if (input_ports || output_ports) {
 +              if (input_ports) {
 +                      *nr_inport = of_coresight_count_ports(input_ports);
 +                      of_node_put(input_ports);
 +              }
 +              if (output_ports) {
 +                      *nr_outport = of_coresight_count_ports(output_ports);
 +                      of_node_put(output_ports);
 +              }
 +      } else {
 +              /* Fall back to legacy DT bindings parsing */
 +              of_coresight_get_ports_legacy(node, nr_inport, nr_outport);
 +      }
 +}
 +
 +static int of_coresight_get_cpu(struct device *dev)
 +{
 +      int cpu;
 +      struct device_node *dn;
 +
 +      if (!dev->of_node)
 +              return -ENODEV;
 +
 +      dn = of_parse_phandle(dev->of_node, "cpu", 0);
 +      if (!dn)
 +              return -ENODEV;
 +
 +      cpu = of_cpu_node_to_id(dn);
 +      of_node_put(dn);
 +
 +      return cpu;
 +}
 +
 +/*
 + * of_coresight_parse_endpoint : Parse the given output endpoint @ep
 + * and fill the connection information in @conn
 + *
 + * Parses the local port, remote device name and the remote port.
 + *
 + * Returns :
 + *     1      - If the parsing is successful and a connection record
 + *              was created for an output connection.
 + *     0      - If the parsing completed without any fatal errors.
 + *    -Errno  - Fatal error, abort the scanning.
 + */
 +static int of_coresight_parse_endpoint(struct device *dev,
 +                                     struct device_node *ep,
 +                                     struct coresight_connection *conn)
 +{
 +      int ret = 0;
 +      struct of_endpoint endpoint, rendpoint;
 +      struct device_node *rparent = NULL;
 +      struct device_node *rep = NULL;
 +      struct device *rdev = NULL;
 +      struct fwnode_handle *rdev_fwnode;
 +
 +      do {
 +              /* Parse the local port details */
 +              if (of_graph_parse_endpoint(ep, &endpoint))
 +                      break;
 +              /*
 +               * Get a handle on the remote endpoint and the device it is
 +               * attached to.
 +               */
 +              rep = of_graph_get_remote_endpoint(ep);
 +              if (!rep)
 +                      break;
 +              rparent = of_coresight_get_port_parent(rep);
 +              if (!rparent)
 +                      break;
 +              if (of_graph_parse_endpoint(rep, &rendpoint))
 +                      break;
 +
 +              rdev_fwnode = of_fwnode_handle(rparent);
 +              /* If the remote device is not available, defer probing */
 +              rdev = coresight_find_device_by_fwnode(rdev_fwnode);
 +              if (!rdev) {
 +                      ret = -EPROBE_DEFER;
 +                      break;
 +              }
 +
 +              conn->outport = endpoint.port;
 +              /*
 +               * Hold the refcount to the target device. This could be
 +               * released via:
 +               * 1) coresight_release_platform_data() if the probe fails or
 +               *    this device is unregistered.
 +               * 2) While removing the target device via
 +               *    coresight_remove_match()
 +               */
 +              conn->child_fwnode = fwnode_handle_get(rdev_fwnode);
 +              conn->child_port = rendpoint.port;
 +              /* Connection record updated */
 +              ret = 1;
 +      } while (0);
 +
 +      of_node_put(rparent);
 +      of_node_put(rep);
 +      put_device(rdev);
 +
 +      return ret;
 +}
 +
 +static int of_get_coresight_platform_data(struct device *dev,
 +                                        struct coresight_platform_data *pdata)
 +{
 +      int ret = 0;
 +      struct coresight_connection *conn;
 +      struct device_node *ep = NULL;
 +      const struct device_node *parent = NULL;
 +      bool legacy_binding = false;
 +      struct device_node *node = dev->of_node;
 +
 +      /* Get the number of input and output port for this component */
 +      of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);
 +
 +      /* If there are no output connections, we are done */
 +      if (!pdata->nr_outport)
 +              return 0;
 +
 +      ret = coresight_alloc_conns(dev, pdata);
 +      if (ret)
 +              return ret;
 +
 +      parent = of_coresight_get_output_ports_node(node);
 +      /*
 +       * If the DT uses obsoleted bindings, the ports are listed
 +       * under the device and we need to filter out the input
 +       * ports.
 +       */
 +      if (!parent) {
 +              legacy_binding = true;
 +              parent = node;
 +              dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n");
 +      }
 +
 +      conn = pdata->conns;
 +
 +      /* Iterate through each output port to discover topology */
 +      while ((ep = of_graph_get_next_endpoint(parent, ep))) {
 +              /*
 +               * Legacy binding mixes input/output ports under the
 +               * same parent. So, skip the input ports if we are dealing
 +               * with legacy binding, as they processed with their
 +               * connected output ports.
 +               */
 +              if (legacy_binding && of_coresight_legacy_ep_is_input(ep))
 +                      continue;
 +
 +              ret = of_coresight_parse_endpoint(dev, ep, conn);
 +              switch (ret) {
 +              case 1:
 +                      conn++;         /* Fall through */
 +              case 0:
 +                      break;
 +              default:
 +                      return ret;
 +              }
 +      }
 +
 +      return 0;
 +}
 +#else
 +static inline int
 +of_get_coresight_platform_data(struct device *dev,
 +                             struct coresight_platform_data *pdata)
 +{
 +      return -ENOENT;
 +}
 +
 +static inline int of_coresight_get_cpu(struct device *dev)
 +{
 +      return -ENODEV;
 +}
 +#endif
 +
 +#ifdef CONFIG_ACPI
 +
 +#include <acpi/actypes.h>
 +#include <acpi/processor.h>
 +
 +/* ACPI Graph _DSD UUID : "ab02a46b-74c7-45a2-bd68-f7d344ef2153" */
 +static const guid_t acpi_graph_uuid = GUID_INIT(0xab02a46b, 0x74c7, 0x45a2,
 +                                              0xbd, 0x68, 0xf7, 0xd3,
 +                                              0x44, 0xef, 0x21, 0x53);
 +/* Coresight ACPI Graph UUID : "3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd" */
 +static const guid_t coresight_graph_uuid = GUID_INIT(0x3ecbc8b6, 0x1d0e, 0x4fb3,
 +                                                   0x81, 0x07, 0xe6, 0x27,
 +                                                   0xf8, 0x05, 0xc6, 0xcd);
 +#define ACPI_CORESIGHT_LINK_SLAVE     0
 +#define ACPI_CORESIGHT_LINK_MASTER    1
 +
 +static inline bool is_acpi_guid(const union acpi_object *obj)
 +{
 +      return (obj->type == ACPI_TYPE_BUFFER) && (obj->buffer.length == 16);
 +}
 +
 +/*
 + * acpi_guid_matches  - Checks if the given object is a GUID object and
 + * that it matches the supplied the GUID.
 + */
 +static inline bool acpi_guid_matches(const union acpi_object *obj,
 +                                 const guid_t *guid)
 +{
 +      return is_acpi_guid(obj) &&
 +             guid_equal((guid_t *)obj->buffer.pointer, guid);
 +}
 +
 +static inline bool is_acpi_dsd_graph_guid(const union acpi_object *obj)
 +{
 +      return acpi_guid_matches(obj, &acpi_graph_uuid);
 +}
 +
 +static inline bool is_acpi_coresight_graph_guid(const union acpi_object *obj)
 +{
 +      return acpi_guid_matches(obj, &coresight_graph_uuid);
 +}
 +
 +static inline bool is_acpi_coresight_graph(const union acpi_object *obj)
 +{
 +      const union acpi_object *graphid, *guid, *links;
 +
 +      if (obj->type != ACPI_TYPE_PACKAGE ||
 +          obj->package.count < 3)
 +              return false;
 +
 +      graphid = &obj->package.elements[0];
 +      guid = &obj->package.elements[1];
 +      links = &obj->package.elements[2];
 +
 +      if (graphid->type != ACPI_TYPE_INTEGER ||
 +          links->type != ACPI_TYPE_INTEGER)
 +              return false;
 +
 +      return is_acpi_coresight_graph_guid(guid);
 +}
 +
 +/*
 + * acpi_validate_dsd_graph    - Make sure the given _DSD graph conforms
 + * to the ACPI _DSD Graph specification.
 + *
 + * ACPI Devices Graph property has the following format:
 + *  {
 + *    Revision        - Integer, must be 0
 + *    NumberOfGraphs  - Integer, N indicating the following list.
 + *    Graph[1],
 + *     ...
 + *    Graph[N]
 + *  }
 + *
 + * And each Graph entry has the following format:
 + *  {
 + *    GraphID         - Integer, identifying a graph the device belongs to.
 + *    UUID            - UUID identifying the specification that governs
 + *                      this graph. (e.g, see is_acpi_coresight_graph())
 + *    NumberOfLinks   - Number "N" of connections on this node of the graph.
 + *    Links[1]
 + *    ...
 + *    Links[N]
 + *  }
 + *
 + * Where each "Links" entry has the following format:
 + *
 + * {
 + *    SourcePortAddress       - Integer
 + *    DestinationPortAddress  - Integer
 + *    DestinationDeviceName   - Reference to another device
 + *    ( --- CoreSight specific extensions below ---)
 + *    DirectionOfFlow         - Integer 1 for output(master)
 + *                              0 for input(slave)
 + * }
 + *
 + * e.g:
 + * For a Funnel device
 + *
 + * Device(MFUN) {
 + *   ...
 + *
 + *   Name (_DSD, Package() {
 + *    // DSD Package contains tuples of {  Proeprty_Type_UUID, Package() }
 + *    ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), //Std. Property UUID
 + *    Package() {
 + *            Package(2) { "property-name", <property-value> }
 + *    },
 + *
 + *    ToUUID("ab02a46b-74c7-45a2-bd68-f7d344ef2153"), // ACPI Graph UUID
 + *    Package() {
 + *      0,            // Revision
 + *      1,            // NumberOfGraphs.
 + *      Package() {   // Graph[0] Package
 + *         1,         // GraphID
 + *         // Coresight Graph UUID
 + *         ToUUID("3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd"),
 + *         3,         // NumberOfLinks aka ports
 + *         // Link[0]: Output_0 -> Replicator:Input_0
 + *         Package () { 0, 0, \_SB_.RPL0, 1 },
 + *         // Link[1]: Input_0 <- Cluster0_Funnel0:Output_0
 + *         Package () { 0, 0, \_SB_.CLU0.FUN0, 0 },
 + *         // Link[2]: Input_1 <- Cluster1_Funnel0:Output_0
 + *          Package () { 1, 0, \_SB_.CLU1.FUN0, 0 },
 + *      }     // End of Graph[0] Package
 + *
 + *    }, // End of ACPI Graph Property
 + *  })
 + */
 +static inline bool acpi_validate_dsd_graph(const union acpi_object *graph)
 +{
 +      int i, n;
 +      const union acpi_object *rev, *nr_graphs;
 +
 +      /* The graph must contain at least the Revision and Number of Graphs */
 +      if (graph->package.count < 2)
 +              return false;
 +
 +      rev = &graph->package.elements[0];
 +      nr_graphs = &graph->package.elements[1];
 +
 +      if (rev->type != ACPI_TYPE_INTEGER ||
 +          nr_graphs->type != ACPI_TYPE_INTEGER)
 +              return false;
 +
 +      /* We only support revision 0 */
 +      if (rev->integer.value != 0)
 +              return false;
 +
 +      n = nr_graphs->integer.value;
 +      /* CoreSight devices are only part of a single Graph */
 +      if (n != 1)
 +              return false;
 +
 +      /* Make sure the ACPI graph package has right number of elements */
 +      if (graph->package.count != (n + 2))
 +              return false;
 +
 +      /*
 +       * Each entry must be a graph package with at least 3 members :
 +       * { GraphID, UUID, NumberOfLinks(n), Links[.],... }
 +       */
 +      for (i = 2; i < n + 2; i++) {
 +              const union acpi_object *obj = &graph->package.elements[i];
 +
 +              if (obj->type != ACPI_TYPE_PACKAGE ||
 +                  obj->package.count < 3)
 +                      return false;
 +      }
 +
 +      return true;
 +}
 +
 +/* acpi_get_dsd_graph - Find the _DSD Graph property for the given device. */
 +const union acpi_object *
 +acpi_get_dsd_graph(struct acpi_device *adev)
 +{
 +      int i;
 +      struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
 +      acpi_status status;
 +      const union acpi_object *dsd;
 +
 +      status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL,
 +                                          &buf, ACPI_TYPE_PACKAGE);
 +      if (ACPI_FAILURE(status))
 +              return NULL;
 +
 +      dsd = buf.pointer;
 +
 +      /*
 +       * _DSD property consists tuples { Prop_UUID, Package() }
 +       * Iterate through all the packages and find the Graph.
 +       */
 +      for (i = 0; i + 1 < dsd->package.count; i += 2) {
 +              const union acpi_object *guid, *package;
 +
 +              guid = &dsd->package.elements[i];
 +              package = &dsd->package.elements[i + 1];
 +
 +              /* All _DSD elements must have a UUID and a Package */
 +              if (!is_acpi_guid(guid) || package->type != ACPI_TYPE_PACKAGE)
 +                      break;
 +              /* Skip the non-Graph _DSD packages */
 +              if (!is_acpi_dsd_graph_guid(guid))
 +                      continue;
 +              if (acpi_validate_dsd_graph(package))
 +                      return package;
 +              /* Invalid graph format, continue */
 +              dev_warn(&adev->dev, "Invalid Graph _DSD property\n");
 +      }
 +
 +      return NULL;
 +}
 +
 +static inline bool
 +acpi_validate_coresight_graph(const union acpi_object *cs_graph)
 +{
 +      int nlinks;
 +
 +      nlinks = cs_graph->package.elements[2].integer.value;
 +      /*
 +       * Graph must have the following fields :
 +       * { GraphID, GraphUUID, NumberOfLinks, Links... }
 +       */
 +      if (cs_graph->package.count != (nlinks + 3))
 +              return false;
 +      /* The links are validated in acpi_coresight_parse_link() */
 +      return true;
 +}
 +
 +/*
 + * acpi_get_coresight_graph   - Parse the device _DSD tables and find
 + * the Graph property matching the CoreSight Graphs.
 + *
 + * Returns the pointer to the CoreSight Graph Package when found. Otherwise
 + * returns NULL.
 + */
 +const union acpi_object *
 +acpi_get_coresight_graph(struct acpi_device *adev)
 +{
 +      const union acpi_object *graph_list, *graph;
 +      int i, nr_graphs;
 +
 +      graph_list = acpi_get_dsd_graph(adev);
 +      if (!graph_list)
 +              return graph_list;
 +
 +      nr_graphs = graph_list->package.elements[1].integer.value;
 +
 +      for (i = 2; i < nr_graphs + 2; i++) {
 +              graph = &graph_list->package.elements[i];
 +              if (!is_acpi_coresight_graph(graph))
 +                      continue;
 +              if (acpi_validate_coresight_graph(graph))
 +                      return graph;
 +              /* Invalid graph format */
 +              break;
 +      }
 +
 +      return NULL;
 +}
 +
 +/*
 + * acpi_coresight_parse_link  - Parse the given Graph connection
 + * of the device and populate the coresight_connection for an output
 + * connection.
 + *
 + * CoreSight Graph specification mandates that the direction of the data
 + * flow must be specified in the link. i.e,
 + *
 + *    SourcePortAddress,      // Integer
 + *    DestinationPortAddress, // Integer
 + *    DestinationDeviceName,  // Reference to another device
 + *    DirectionOfFlow,        // 1 for output(master), 0 for input(slave)
 + *
 + * Returns the direction of the data flow [ Input(slave) or Output(master) ]
 + * upon success.
 + * Returns an negative error number otherwise.
 + */
 +static int acpi_coresight_parse_link(struct acpi_device *adev,
 +                                   const union acpi_object *link,
 +                                   struct coresight_connection *conn)
 +{
 +      int rc, dir;
 +      const union acpi_object *fields;
 +      struct acpi_device *r_adev;
 +      struct device *rdev;
 +
 +      if (link->type != ACPI_TYPE_PACKAGE ||
 +          link->package.count != 4)
 +              return -EINVAL;
 +
 +      fields = link->package.elements;
 +
 +      if (fields[0].type != ACPI_TYPE_INTEGER ||
 +          fields[1].type != ACPI_TYPE_INTEGER ||
 +          fields[2].type != ACPI_TYPE_LOCAL_REFERENCE ||
 +          fields[3].type != ACPI_TYPE_INTEGER)
 +              return -EINVAL;
 +
 +      rc = acpi_bus_get_device(fields[2].reference.handle, &r_adev);
 +      if (rc)
 +              return rc;
 +
 +      dir = fields[3].integer.value;
 +      if (dir == ACPI_CORESIGHT_LINK_MASTER) {
 +              conn->outport = fields[0].integer.value;
 +              conn->child_port = fields[1].integer.value;
 +              rdev = coresight_find_device_by_fwnode(&r_adev->fwnode);
 +              if (!rdev)
 +                      return -EPROBE_DEFER;
 +              /*
 +               * Hold the refcount to the target device. This could be
 +               * released via:
 +               * 1) coresight_release_platform_data() if the probe fails or
 +               *    this device is unregistered.
 +               * 2) While removing the target device via
 +               *    coresight_remove_match().
 +               */
 +              conn->child_fwnode = fwnode_handle_get(&r_adev->fwnode);
 +      }
 +
 +      return dir;
 +}
 +
 +/*
 + * acpi_coresight_parse_graph - Parse the _DSD CoreSight graph
 + * connection information and populate the supplied coresight_platform_data
 + * instance.
 + */
 +static int acpi_coresight_parse_graph(struct acpi_device *adev,
 +                                    struct coresight_platform_data *pdata)
 +{
 +      int rc, i, nlinks;
 +      const union acpi_object *graph;
 +      struct coresight_connection *conns, *ptr;
 +
 +      pdata->nr_inport = pdata->nr_outport = 0;
 +      graph = acpi_get_coresight_graph(adev);
 +      if (!graph)
 +              return -ENOENT;
 +
 +      nlinks = graph->package.elements[2].integer.value;
 +      if (!nlinks)
 +              return 0;
 +
 +      /*
 +       * To avoid scanning the table twice (once for finding the number of
 +       * output links and then later for parsing the output links),
 +       * cache the links information in one go and then later copy
 +       * it to the pdata.
 +       */
 +      conns = devm_kcalloc(&adev->dev, nlinks, sizeof(*conns), GFP_KERNEL);
 +      if (!conns)
 +              return -ENOMEM;
 +      ptr = conns;
 +      for (i = 0; i < nlinks; i++) {
 +              const union acpi_object *link = &graph->package.elements[3 + i];
 +              int dir;
 +
 +              dir = acpi_coresight_parse_link(adev, link, ptr);
 +              if (dir < 0)
 +                      return dir;
 +
 +              if (dir == ACPI_CORESIGHT_LINK_MASTER) {
 +                      pdata->nr_outport++;
 +                      ptr++;
 +              } else {
 +                      pdata->nr_inport++;
 +              }
 +      }
 +
 +      rc = coresight_alloc_conns(&adev->dev, pdata);
 +      if (rc)
 +              return rc;
 +
 +      /* Copy the connection information to the final location */
 +      for (i = 0; i < pdata->nr_outport; i++)
 +              pdata->conns[i] = conns[i];
 +
 +      devm_kfree(&adev->dev, conns);
 +      return 0;
 +}
 +
 +/*
 + * acpi_handle_to_logical_cpuid - Map a given acpi_handle to the
 + * logical CPU id of the corresponding CPU device.
 + *
 + * Returns the logical CPU id when found. Otherwise returns >= nr_cpus_id.
 + */
 +static int
 +acpi_handle_to_logical_cpuid(acpi_handle handle)
 +{
 +      int i;
 +      struct acpi_processor *pr;
 +
 +      for_each_possible_cpu(i) {
 +              pr = per_cpu(processors, i);
 +              if (pr && pr->handle == handle)
 +                      break;
 +      }
 +
 +      return i;
 +}
 +
 +/*
 + * acpi_coresigh_get_cpu - Find the logical CPU id of the CPU associated
 + * with this coresight device. With ACPI bindings, the CoreSight components
 + * are listed as child device of the associated CPU.
 + *
 + * Returns the logical CPU id when found. Otherwise returns 0.
 + */
 +static int acpi_coresight_get_cpu(struct device *dev)
 +{
 +      int cpu;
 +      acpi_handle cpu_handle;
 +      acpi_status status;
 +      struct acpi_device *adev = ACPI_COMPANION(dev);
 +
 +      if (!adev)
 +              return -ENODEV;
 +      status = acpi_get_parent(adev->handle, &cpu_handle);
 +      if (ACPI_FAILURE(status))
 +              return -ENODEV;
 +
 +      cpu = acpi_handle_to_logical_cpuid(cpu_handle);
 +      if (cpu >= nr_cpu_ids)
 +              return -ENODEV;
 +      return cpu;
 +}
 +
 +static int
 +acpi_get_coresight_platform_data(struct device *dev,
 +                               struct coresight_platform_data *pdata)
 +{
 +      struct acpi_device *adev;
 +
 +      adev = ACPI_COMPANION(dev);
 +      if (!adev)
 +              return -EINVAL;
 +
 +      return acpi_coresight_parse_graph(adev, pdata);
 +}
 +
 +#else
 +
 +static inline int
 +acpi_get_coresight_platform_data(struct device *dev,
 +                               struct coresight_platform_data *pdata)
 +{
 +      return -ENOENT;
 +}
 +
 +static inline int acpi_coresight_get_cpu(struct device *dev)
 +{
 +      return -ENODEV;
 +}
 +#endif
 +
 +int coresight_get_cpu(struct device *dev)
 +{
 +      if (is_of_node(dev->fwnode))
 +              return of_coresight_get_cpu(dev);
 +      else if (is_acpi_device_node(dev->fwnode))
 +              return acpi_coresight_get_cpu(dev);
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(coresight_get_cpu);
 +
 +struct coresight_platform_data *
 +coresight_get_platform_data(struct device *dev)
 +{
 +      int ret = -ENOENT;
 +      struct coresight_platform_data *pdata = NULL;
 +      struct fwnode_handle *fwnode = dev_fwnode(dev);
 +
 +      if (IS_ERR_OR_NULL(fwnode))
 +              goto error;
 +
 +      pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 +      if (!pdata) {
 +              ret = -ENOMEM;
 +              goto error;
 +      }
 +
 +      if (is_of_node(fwnode))
 +              ret = of_get_coresight_platform_data(dev, pdata);
 +      else if (is_acpi_device_node(fwnode))
 +              ret = acpi_get_coresight_platform_data(dev, pdata);
 +
 +      if (!ret)
 +              return pdata;
 +error:
 +      if (!IS_ERR_OR_NULL(pdata))
 +              /* Cleanup the connection information */
 +              coresight_release_platform_data(pdata);
 +      return ERR_PTR(ret);
 +}
 +EXPORT_SYMBOL_GPL(coresight_get_platform_data);
 
  #define VFIO_AP_MDEV_TYPE_HWVIRT "passthrough"
  #define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device"
  
- static int match_apqn(struct device *dev, void *data)
 +static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev);
 +
++static int match_apqn(struct device *dev, const void *data)
 +{
 +      struct vfio_ap_queue *q = dev_get_drvdata(dev);
 +
 +      return (q->apqn == *(int *)(data)) ? 1 : 0;
 +}
 +
 +/**
 + * vfio_ap_get_queue: Retrieve a queue with a specific APQN from a list
 + * @matrix_mdev: the associated mediated matrix
 + * @apqn: The queue APQN
 + *
 + * Retrieve a queue with a specific APQN from the list of the
 + * devices of the vfio_ap_drv.
 + * Verify that the APID and the APQI are set in the matrix.
 + *
 + * Returns the pointer to the associated vfio_ap_queue
 + */
 +static struct vfio_ap_queue *vfio_ap_get_queue(
 +                                      struct ap_matrix_mdev *matrix_mdev,
 +                                      int apqn)
 +{
 +      struct vfio_ap_queue *q;
 +      struct device *dev;
 +
 +      if (!test_bit_inv(AP_QID_CARD(apqn), matrix_mdev->matrix.apm))
 +              return NULL;
 +      if (!test_bit_inv(AP_QID_QUEUE(apqn), matrix_mdev->matrix.aqm))
 +              return NULL;
 +
 +      dev = driver_find_device(&matrix_dev->vfio_ap_drv->driver, NULL,
 +                               &apqn, match_apqn);
 +      if (!dev)
 +              return NULL;
 +      q = dev_get_drvdata(dev);
 +      q->matrix_mdev = matrix_mdev;
 +      put_device(dev);
 +
 +      return q;
 +}
 +
 +/**
 + * vfio_ap_wait_for_irqclear
 + * @apqn: The AP Queue number
 + *
 + * Checks the IRQ bit for the status of this APQN using ap_tapq.
 + * Returns if the ap_tapq function succeeded and the bit is clear.
 + * Returns if ap_tapq function failed with invalid, deconfigured or
 + * checkstopped AP.
 + * Otherwise retries up to 5 times after waiting 20ms.
 + *
 + */
 +static void vfio_ap_wait_for_irqclear(int apqn)
 +{
 +      struct ap_queue_status status;
 +      int retry = 5;
 +
 +      do {
 +              status = ap_tapq(apqn, NULL);
 +              switch (status.response_code) {
 +              case AP_RESPONSE_NORMAL:
 +              case AP_RESPONSE_RESET_IN_PROGRESS:
 +                      if (!status.irq_enabled)
 +                              return;
 +                      /* Fall through */
 +              case AP_RESPONSE_BUSY:
 +                      msleep(20);
 +                      break;
 +              case AP_RESPONSE_Q_NOT_AVAIL:
 +              case AP_RESPONSE_DECONFIGURED:
 +              case AP_RESPONSE_CHECKSTOPPED:
 +              default:
 +                      WARN_ONCE(1, "%s: tapq rc %02x: %04x\n", __func__,
 +                                status.response_code, apqn);
 +                      return;
 +              }
 +      } while (--retry);
 +
 +      WARN_ONCE(1, "%s: tapq rc %02x: %04x could not clear IR bit\n",
 +                __func__, status.response_code, apqn);
 +}
 +
 +/**
 + * vfio_ap_free_aqic_resources
 + * @q: The vfio_ap_queue
 + *
 + * Unregisters the ISC in the GIB when the saved ISC not invalid.
 + * Unpin the guest's page holding the NIB when it exist.
 + * Reset the saved_pfn and saved_isc to invalid values.
 + * Clear the pointer to the matrix mediated device.
 + *
 + */
 +static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q)
 +{
 +      if (q->saved_isc != VFIO_AP_ISC_INVALID && q->matrix_mdev)
 +              kvm_s390_gisc_unregister(q->matrix_mdev->kvm, q->saved_isc);
 +      if (q->saved_pfn && q->matrix_mdev)
 +              vfio_unpin_pages(mdev_dev(q->matrix_mdev->mdev),
 +                               &q->saved_pfn, 1);
 +      q->saved_pfn = 0;
 +      q->saved_isc = VFIO_AP_ISC_INVALID;
 +      q->matrix_mdev = NULL;
 +}
 +
 +/**
 + * vfio_ap_irq_disable
 + * @q: The vfio_ap_queue
 + *
 + * Uses ap_aqic to disable the interruption and in case of success, reset
 + * in progress or IRQ disable command already proceeded: calls
 + * vfio_ap_wait_for_irqclear() to check for the IRQ bit to be clear
 + * and calls vfio_ap_free_aqic_resources() to free the resources associated
 + * with the AP interrupt handling.
 + *
 + * In the case the AP is busy, or a reset is in progress,
 + * retries after 20ms, up to 5 times.
 + *
 + * Returns if ap_aqic function failed with invalid, deconfigured or
 + * checkstopped AP.
 + */
 +struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q)
 +{
 +      struct ap_qirq_ctrl aqic_gisa = {};
 +      struct ap_queue_status status;
 +      int retries = 5;
 +
 +      do {
 +              status = ap_aqic(q->apqn, aqic_gisa, NULL);
 +              switch (status.response_code) {
 +              case AP_RESPONSE_OTHERWISE_CHANGED:
 +              case AP_RESPONSE_NORMAL:
 +                      vfio_ap_wait_for_irqclear(q->apqn);
 +                      goto end_free;
 +              case AP_RESPONSE_RESET_IN_PROGRESS:
 +              case AP_RESPONSE_BUSY:
 +                      msleep(20);
 +                      break;
 +              case AP_RESPONSE_Q_NOT_AVAIL:
 +              case AP_RESPONSE_DECONFIGURED:
 +              case AP_RESPONSE_CHECKSTOPPED:
 +              case AP_RESPONSE_INVALID_ADDRESS:
 +              default:
 +                      /* All cases in default means AP not operational */
 +                      WARN_ONCE(1, "%s: ap_aqic status %d\n", __func__,
 +                                status.response_code);
 +                      goto end_free;
 +              }
 +      } while (retries--);
 +
 +      WARN_ONCE(1, "%s: ap_aqic status %d\n", __func__,
 +                status.response_code);
 +end_free:
 +      vfio_ap_free_aqic_resources(q);
 +      return status;
 +}
 +
 +/**
 + * vfio_ap_setirq: Enable Interruption for a APQN
 + *
 + * @dev: the device associated with the ap_queue
 + * @q:         the vfio_ap_queue holding AQIC parameters
 + *
 + * Pin the NIB saved in *q
 + * Register the guest ISC to GIB interface and retrieve the
 + * host ISC to issue the host side PQAP/AQIC
 + *
 + * Response.status may be set to AP_RESPONSE_INVALID_ADDRESS in case the
 + * vfio_pin_pages failed.
 + *
 + * Otherwise return the ap_queue_status returned by the ap_aqic(),
 + * all retry handling will be done by the guest.
 + */
 +static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q,
 +                                               int isc,
 +                                               unsigned long nib)
 +{
 +      struct ap_qirq_ctrl aqic_gisa = {};
 +      struct ap_queue_status status = {};
 +      struct kvm_s390_gisa *gisa;
 +      struct kvm *kvm;
 +      unsigned long h_nib, g_pfn, h_pfn;
 +      int ret;
 +
 +      g_pfn = nib >> PAGE_SHIFT;
 +      ret = vfio_pin_pages(mdev_dev(q->matrix_mdev->mdev), &g_pfn, 1,
 +                           IOMMU_READ | IOMMU_WRITE, &h_pfn);
 +      switch (ret) {
 +      case 1:
 +              break;
 +      default:
 +              status.response_code = AP_RESPONSE_INVALID_ADDRESS;
 +              return status;
 +      }
 +
 +      kvm = q->matrix_mdev->kvm;
 +      gisa = kvm->arch.gisa_int.origin;
 +
 +      h_nib = (h_pfn << PAGE_SHIFT) | (nib & ~PAGE_MASK);
 +      aqic_gisa.gisc = isc;
 +      aqic_gisa.isc = kvm_s390_gisc_register(kvm, isc);
 +      aqic_gisa.ir = 1;
 +      aqic_gisa.gisa = (uint64_t)gisa >> 4;
 +
 +      status = ap_aqic(q->apqn, aqic_gisa, (void *)h_nib);
 +      switch (status.response_code) {
 +      case AP_RESPONSE_NORMAL:
 +              /* See if we did clear older IRQ configuration */
 +              vfio_ap_free_aqic_resources(q);
 +              q->saved_pfn = g_pfn;
 +              q->saved_isc = isc;
 +              break;
 +      case AP_RESPONSE_OTHERWISE_CHANGED:
 +              /* We could not modify IRQ setings: clear new configuration */
 +              vfio_unpin_pages(mdev_dev(q->matrix_mdev->mdev), &g_pfn, 1);
 +              kvm_s390_gisc_unregister(kvm, isc);
 +              break;
 +      default:
 +              pr_warn("%s: apqn %04x: response: %02x\n", __func__, q->apqn,
 +                      status.response_code);
 +              vfio_ap_irq_disable(q);
 +              break;
 +      }
 +
 +      return status;
 +}
 +
 +/**
 + * handle_pqap: PQAP instruction callback
 + *
 + * @vcpu: The vcpu on which we received the PQAP instruction
 + *
 + * Get the general register contents to initialize internal variables.
 + * REG[0]: APQN
 + * REG[1]: IR and ISC
 + * REG[2]: NIB
 + *
 + * Response.status may be set to following Response Code:
 + * - AP_RESPONSE_Q_NOT_AVAIL: if the queue is not available
 + * - AP_RESPONSE_DECONFIGURED: if the queue is not configured
 + * - AP_RESPONSE_NORMAL (0) : in case of successs
 + *   Check vfio_ap_setirq() and vfio_ap_clrirq() for other possible RC.
 + * We take the matrix_dev lock to ensure serialization on queues and
 + * mediated device access.
 + *
 + * Return 0 if we could handle the request inside KVM.
 + * otherwise, returns -EOPNOTSUPP to let QEMU handle the fault.
 + */
 +static int handle_pqap(struct kvm_vcpu *vcpu)
 +{
 +      uint64_t status;
 +      uint16_t apqn;
 +      struct vfio_ap_queue *q;
 +      struct ap_queue_status qstatus = {
 +                             .response_code = AP_RESPONSE_Q_NOT_AVAIL, };
 +      struct ap_matrix_mdev *matrix_mdev;
 +
 +      /* If we do not use the AIV facility just go to userland */
 +      if (!(vcpu->arch.sie_block->eca & ECA_AIV))
 +              return -EOPNOTSUPP;
 +
 +      apqn = vcpu->run->s.regs.gprs[0] & 0xffff;
 +      mutex_lock(&matrix_dev->lock);
 +
 +      if (!vcpu->kvm->arch.crypto.pqap_hook)
 +              goto out_unlock;
 +      matrix_mdev = container_of(vcpu->kvm->arch.crypto.pqap_hook,
 +                                 struct ap_matrix_mdev, pqap_hook);
 +
 +      q = vfio_ap_get_queue(matrix_mdev, apqn);
 +      if (!q)
 +              goto out_unlock;
 +
 +      status = vcpu->run->s.regs.gprs[1];
 +
 +      /* If IR bit(16) is set we enable the interrupt */
 +      if ((status >> (63 - 16)) & 0x01)
 +              qstatus = vfio_ap_irq_enable(q, status & 0x07,
 +                                           vcpu->run->s.regs.gprs[2]);
 +      else
 +              qstatus = vfio_ap_irq_disable(q);
 +
 +out_unlock:
 +      memcpy(&vcpu->run->s.regs.gprs[1], &qstatus, sizeof(qstatus));
 +      vcpu->run->s.regs.gprs[1] >>= 32;
 +      mutex_unlock(&matrix_dev->lock);
 +      return 0;
 +}
 +
  static void vfio_ap_matrix_init(struct ap_config_info *info,
                                struct ap_matrix *matrix)
  {