[PATCH v5 06/13] coresight: Dynamically add connections

Mike Leach mike.leach at linaro.org
Wed Apr 12 07:35:18 PDT 2023


On Tue, 4 Apr 2023 at 16:52, James Clark <james.clark at arm.com> wrote:
>
> Add a function for adding connections dynamically. This also removes
> the 1:1 mapping between port number and the index into the connections
> array. The only place this mapping was used was in the warning for
> duplicate output ports, which has been replaced by a search. Other
> uses of the port number already use the port member variable.
>
> Being able to dynamically add connections will allow other devices like
> CTI to re-use the connection mechanism despite not having explicit
> connections described in the DT.
>
> The connections array is now no longer sparse, so child_fwnode doesn't
> need to be checked as all connections have a target node. Because the
> array is no longer sparse, the high in and out port numbers are required
> for the refcount arrays. But these will also be removed in a later
> commit when the refcount is made a property of the connection.
>
> Signed-off-by: James Clark <james.clark at arm.com>
> ---
>  drivers/hwtracing/coresight/coresight-core.c  |  23 ++--
>  .../hwtracing/coresight/coresight-platform.c  | 124 +++++++++---------
>  include/linux/coresight.h                     |   8 +-
>  3 files changed, 77 insertions(+), 78 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index f3dc320b374c..91274e7e6944 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -397,9 +397,9 @@ static void coresight_disable_link(struct coresight_device *csdev,
>         link_subtype = csdev->subtype.link_subtype;
>
>         if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
> -               nr_conns = csdev->pdata->nr_inconns;
> +               nr_conns = csdev->pdata->high_inport;
>         } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
> -               nr_conns = csdev->pdata->nr_outconns;
> +               nr_conns = csdev->pdata->high_outport;
>         } else {
>                 nr_conns = 1;
>         }
> @@ -1336,9 +1336,6 @@ static int coresight_orphan_match(struct device *dev, void *data)
>         for (i = 0; i < i_csdev->pdata->nr_outconns; i++) {
>                 conn = &i_csdev->pdata->out_conns[i];
>
> -               /* Skip the port if FW doesn't describe it */
> -               if (!conn->dest_fwnode)
> -                       continue;
>                 /* We have found at least one orphan connection */
>                 if (conn->dest_dev == NULL) {
>                         /* Does it match this newly added device? */
> @@ -1377,8 +1374,6 @@ static int coresight_fixup_device_conns(struct coresight_device *csdev)
>         for (i = 0; i < csdev->pdata->nr_outconns; i++) {
>                 struct coresight_connection *conn = &csdev->pdata->out_conns[i];
>
> -               if (!conn->dest_fwnode)
> -                       continue;
>                 conn->dest_dev =
>                         coresight_find_csdev_by_fwnode(conn->dest_fwnode);
>                 if (conn->dest_dev && conn->dest_dev->has_conns_grp) {
> @@ -1413,7 +1408,7 @@ static int coresight_remove_match(struct device *dev, void *data)
>         for (i = 0; i < iterator->pdata->nr_outconns; i++) {
>                 conn = &iterator->pdata->out_conns[i];
>
> -               if (conn->dest_dev == NULL || conn->dest_fwnode == NULL)
> +               if (conn->dest_dev == NULL)
>                         continue;
>
>                 if (csdev->dev.fwnode == conn->dest_fwnode) {
> @@ -1445,7 +1440,7 @@ static void coresight_remove_conns(struct coresight_device *csdev)
>          * doesn't have at least one input port, there is no point
>          * in searching all the devices.
>          */
> -       if (csdev->pdata->nr_inconns)
> +       if (csdev->pdata->high_inport)
>                 bus_for_each_dev(&coresight_bustype, NULL,
>                                  csdev, coresight_remove_match);
>  }
> @@ -1552,10 +1547,8 @@ void coresight_release_platform_data(struct coresight_device *csdev,
>                  * Drop the refcount and clear the handle as this device
>                  * is going away
>                  */
> -               if (conns[i].dest_fwnode) {
> -                       fwnode_handle_put(conns[i].dest_fwnode);
> -                       conns[i].dest_fwnode = NULL;
> -               }
> +               fwnode_handle_put(conns[i].dest_fwnode);
> +               conns[i].dest_fwnode = NULL;
>         }
>         if (csdev)
>                 coresight_remove_conns_sysfs_group(csdev);
> @@ -1581,9 +1574,9 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
>                 link_subtype = desc->subtype.link_subtype;
>
>                 if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
> -                       nr_refcnts = desc->pdata->nr_inconns;
> +                       nr_refcnts = desc->pdata->high_inport;
>                 else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
> -                       nr_refcnts = desc->pdata->nr_outconns;
> +                       nr_refcnts = desc->pdata->high_outport;
>         }
>
>         refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL);
> diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
> index 566cc99a2c34..8c2029336161 100644
> --- a/drivers/hwtracing/coresight/coresight-platform.c
> +++ b/drivers/hwtracing/coresight/coresight-platform.c
> @@ -19,22 +19,45 @@
>  #include <asm/smp_plat.h>
>
>  #include "coresight-priv.h"
> +
>  /*
> - * coresight_alloc_conns: Allocate connections record for each output
> - * port from the device.
> + * Add an entry to the connection list and assign @conn's contents to it.
> + *
> + * If the output port is already assigned on this device, return -EINVAL
>   */
> -static int coresight_alloc_conns(struct device *dev,
> -                                struct coresight_platform_data *pdata)
> +struct coresight_connection *
> +coresight_add_out_conn(struct device *dev,
> +                      struct coresight_platform_data *pdata,
> +                      const struct coresight_connection *new_conn)
>  {
> -       if (pdata->nr_outconns) {
> -               pdata->out_conns = devm_kcalloc(dev, pdata->nr_outconns,
> -                                           sizeof(*pdata->out_conns), GFP_KERNEL);
> -               if (!pdata->out_conns)
> -                       return -ENOMEM;
> +       int i;
> +       struct coresight_connection *conn;
> +
> +       /*
> +        * Warn on any existing duplicate output port.
> +        */
> +       for (i = 0; i < pdata->nr_outconns; ++i) {
> +               conn = &pdata->out_conns[i];
> +               /* Output == -1 means ignore the port for example for helpers */
> +               if (conn->src_port != -1 &&
> +                   conn->src_port == new_conn->src_port) {
> +                       dev_warn(dev, "Duplicate output port %d\n",
> +                                conn->src_port);
> +                       return ERR_PTR(-EINVAL);
> +               }
>         }
>
> -       return 0;
> +       pdata->nr_outconns++;
> +       pdata->out_conns =
> +               devm_krealloc_array(dev, pdata->out_conns, pdata->nr_outconns,
> +                                   sizeof(*pdata->out_conns), GFP_KERNEL);
> +       if (!pdata->out_conns)
> +               return ERR_PTR(-ENOMEM);
> +
> +       pdata->out_conns[pdata->nr_outconns - 1] = *new_conn;
> +       return &pdata->out_conns[pdata->nr_outconns - 1];
>  }
> +EXPORT_SYMBOL_GPL(coresight_add_out_conn);
>
>  static struct device *
>  coresight_find_device_by_fwnode(struct fwnode_handle *fwnode)
> @@ -224,7 +247,8 @@ static int of_coresight_parse_endpoint(struct device *dev,
>         struct device_node *rep = NULL;
>         struct device *rdev = NULL;
>         struct fwnode_handle *rdev_fwnode;
> -       struct coresight_connection *conn;
> +       struct coresight_connection conn = {};
> +       struct coresight_connection *new_conn;
>
>         do {
>                 /* Parse the local port details */
> @@ -251,14 +275,7 @@ static int of_coresight_parse_endpoint(struct device *dev,
>                         break;
>                 }
>
> -               conn = &pdata->out_conns[endpoint.port];
> -               if (conn->dest_fwnode) {
> -                       dev_warn(dev, "Duplicate output port %d\n",
> -                                endpoint.port);
> -                       ret = -EINVAL;
> -                       break;
> -               }
> -               conn->src_port = endpoint.port;
> +               conn.src_port = endpoint.port;
>                 /*
>                  * Hold the refcount to the target device. This could be
>                  * released via:
> @@ -267,8 +284,14 @@ static int of_coresight_parse_endpoint(struct device *dev,
>                  * 2) While removing the target device via
>                  *    coresight_remove_match()
>                  */
> -               conn->dest_fwnode = fwnode_handle_get(rdev_fwnode);
> -               conn->dest_port = rendpoint.port;
> +               conn.dest_fwnode = fwnode_handle_get(rdev_fwnode);
> +               conn.dest_port = rendpoint.port;
> +
> +               new_conn = coresight_add_out_conn(dev, pdata, &conn);
> +               if (IS_ERR_VALUE(new_conn)) {
> +                       fwnode_handle_put(conn.dest_fwnode);
> +                       return PTR_ERR(new_conn);
> +               }
>                 /* Connection record updated */
>         } while (0);
>
> @@ -289,16 +312,12 @@ static int of_get_coresight_platform_data(struct device *dev,
>         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_inconns, &pdata->nr_outconns);
> +       of_coresight_get_ports(node, &pdata->high_inport, &pdata->high_outport);
>
>         /* If there are no output connections, we are done */
> -       if (!pdata->nr_outconns)
> +       if (!pdata->high_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
> @@ -683,12 +702,14 @@ static int acpi_coresight_parse_link(struct acpi_device *adev,
>   * connection information and populate the supplied coresight_platform_data
>   * instance.
>   */
> -static int acpi_coresight_parse_graph(struct acpi_device *adev,
> +static int acpi_coresight_parse_graph(struct device *dev,
> +                                     struct acpi_device *adev,
>                                       struct coresight_platform_data *pdata)
>  {
> -       int rc, i, nlinks;
> +       int i, nlinks;
>         const union acpi_object *graph;
> -       struct coresight_connection *conns, *ptr;
> +       struct coresight_connection conn, zero_conn = {};
> +       struct coresight_connection *new_conn;
>
>         pdata->nr_inconns = pdata->nr_outconns = 0;
>         graph = acpi_get_coresight_graph(adev);
> @@ -699,30 +720,23 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
>         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);
> +               conn = zero_conn;
> +               dir = acpi_coresight_parse_link(adev, link, &conn);
>                 if (dir < 0)
>                         return dir;
>
>                 if (dir == ACPI_CORESIGHT_LINK_MASTER) {
> -                       if (ptr->src_port >= pdata->nr_outconns)
> -                               pdata->nr_outconns = ptr->src_port + 1;
> -                       ptr++;
> +                       if (conn.src_port >= pdata->high_outport)
> +                               pdata->high_outport = conn.src_port + 1;
> +                       new_conn = coresight_add_out_conn(dev, pdata, &conn);
> +                       if (IS_ERR(new_conn))
> +                               return PTR_ERR(new_conn);
>                 } else {
> -                       WARN_ON(pdata->nr_inconns == ptr->dest_port + 1);
> +                       WARN_ON(pdata->high_inport == conn.dest_port + 1);
>                         /*
>                          * We do not track input port connections for a device.
>                          * However we need the highest port number described,
> @@ -730,25 +744,11 @@ static int acpi_coresight_parse_graph(struct acpi_device *adev,
>                          * record for an output connection. Hence, do not move
>                          * the ptr for input connections
>                          */
> -                       if (ptr->dest_port >= pdata->nr_inconns)
> -                               pdata->nr_inconns = ptr->dest_port + 1;
> +                       if (conn.dest_port >= pdata->high_inport)
> +                               pdata->high_inport = conn.dest_port + 1;
>                 }
>         }
>
> -       rc = coresight_alloc_conns(&adev->dev, pdata);
> -       if (rc)
> -               return rc;
> -
> -       /* Copy the connection information to the final location */
> -       for (i = 0; conns + i < ptr; i++) {
> -               int port = conns[i].src_port;
> -
> -               /* Duplicate output port */
> -               WARN_ON(pdata->out_conns[port].dest_fwnode);
> -               pdata->out_conns[port] = conns[i];
> -       }
> -
> -       devm_kfree(&adev->dev, conns);
>         return 0;
>  }
>
> @@ -809,7 +809,7 @@ acpi_get_coresight_platform_data(struct device *dev,
>         if (!adev)
>                 return -EINVAL;
>
> -       return acpi_coresight_parse_graph(adev, pdata);
> +       return acpi_coresight_parse_graph(dev, adev, pdata);
>  }
>
>  #else
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index b6f444804bf3..12fdbd03e2f7 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -104,9 +104,11 @@ union coresight_dev_subtype {
>   *
>   * @nr_inconns: Number of elements for the input connections.
>   * @nr_outconns: Number of elements for the output connections.
> - * @out_conns: Sparse array of nr_outconns connections from this component.
> + * @out_conns: Array of nr_outconns connections from this component.
>   */
>  struct coresight_platform_data {
> +       int high_inport;
> +       int high_outport;
>         int nr_inconns;
>         int nr_outconns;
>         struct coresight_connection *out_conns;
> @@ -609,5 +611,9 @@ static inline void coresight_write64(struct coresight_device *csdev, u64 val, u3
>  extern int coresight_get_cpu(struct device *dev);
>
>  struct coresight_platform_data *coresight_get_platform_data(struct device *dev);
> +struct coresight_connection *
> +coresight_add_out_conn(struct device *dev,
> +                      struct coresight_platform_data *pdata,
> +                      const struct coresight_connection *new_conn);
>
>  #endif         /* _LINUX_COREISGHT_H */
> --
> 2.34.1
>

Reviewed-by: Mike Leach <mike.leach at linaro.org>

-- 
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK



More information about the linux-arm-kernel mailing list