From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_PASS,USER_AGENT_MUTT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 82DBFC04AA7 for ; Mon, 13 May 2019 22:28:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 38A6D208C3 for ; Mon, 13 May 2019 22:28:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="Oagj62j8" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726598AbfEMW22 (ORCPT ); Mon, 13 May 2019 18:28:28 -0400 Received: from mail-pl1-f196.google.com ([209.85.214.196]:37380 "EHLO mail-pl1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726407AbfEMW21 (ORCPT ); Mon, 13 May 2019 18:28:27 -0400 Received: by mail-pl1-f196.google.com with SMTP id p15so7170473pll.4 for ; Mon, 13 May 2019 15:28:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=HD0prNQU/6k2kvaT2+6gEeHszvWUqSnKk/U630cQTJU=; b=Oagj62j8AxX6ijq+26rfysxBxmc32hR0TplKFGW5f0gpGrpXlVZEGL/4fe1w9iiaWn rp5i/7Z5vpI+eGfDfvdp4HGqJLruy/8yHu3mAuwFTABy4RDTEpXhDa6mb6WTulyjG+rn aPbKHhZtUbae50e7f31DohjEma+9/MP+qZtyijvHzlb++GOt4PljX1/I8RpUsa9/zkfd odzZL0Yqrb7pCkv1s7l7BAYHjnRTMzxGOppc0nR9x2janOyfmcV7Yf5dlTMHpuExyhou KWj8qvHdeQeXiUy6c8JNgBaxTdZ0C8cAdSrQSoabJN3h5bugCBtt6RAbDnxp+l70kiVZ WgTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=HD0prNQU/6k2kvaT2+6gEeHszvWUqSnKk/U630cQTJU=; b=kbCuQg1jYluEQ9MdTI3KArP7AfvSNWUXxFYUs3Ecz++PRUUYfv+UTTxCisyFQqpwcx ydkAMPXyCqxhs5DXfVtz5CGX4PTamVhAakwkj/ctPfNGOedRMUfgPR5RMqOmvLGO6Zvc BC4qD3/kuUUvmOHfH7FN0xhApqWyvCgboiXtqBguPSDC7aQH3BE+zf2MEzQBJWen3uXY 3Vi5wC2uNDlO8ys28Gjm5KbwmTiUHoGRvu9rceQWU/5ZJ2NGAhW4QqrLzwK9ErD3rc5L yZGD/BUZ0RSDYJYBwunDbX92tekJJ9kEqUNYbTeFIftrNc+8GLL8yO4XANyDVWMDD9Xx CaYA== X-Gm-Message-State: APjAAAUsXHuvHkLotfNR9QwAL8aguHPGunXKIKEUBF23ZOnSC1L4kU81 S0LSPHb9l+i1wd52T9XkJW7p/g== X-Google-Smtp-Source: APXvYqw18RS1wdIAlIpBZK+lov/Xv24OgSSrtqs2QCKkmP9OUiwrKD5HOnWM7bsxc6RJ35OyUso82Q== X-Received: by 2002:a17:902:9f83:: with SMTP id g3mr18022845plq.330.1557786506296; Mon, 13 May 2019 15:28:26 -0700 (PDT) Received: from xps15 (S0106002369de4dac.cg.shawcable.net. [68.147.8.254]) by smtp.gmail.com with ESMTPSA id k64sm45204316pfc.97.2019.05.13.15.28.25 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 13 May 2019 15:28:25 -0700 (PDT) Date: Mon, 13 May 2019 16:28:23 -0600 From: Mathieu Poirier To: Suzuki K Poulose Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, coresight@lists.linaro.org, rjw@rjwysocki.net Subject: Re: [PATCH v3 28/30] coresight: Support for ACPI bindings Message-ID: <20190513222823.GF16162@xps15> References: <1557226378-10131-1-git-send-email-suzuki.poulose@arm.com> <1557226378-10131-29-git-send-email-suzuki.poulose@arm.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1557226378-10131-29-git-send-email-suzuki.poulose@arm.com> User-Agent: Mutt/1.9.4 (2018-02-28) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, May 07, 2019 at 11:52:55AM +0100, Suzuki K Poulose wrote: > Add support for parsing the ACPI platform description > for CoreSight. The connections are encoded in a DSD graph > property with CoreSight specific variation of the property. > > The ETMs are listed as the children device of the respective > CPU. > > Cc: "Rafael J. Wysocki" > Cc: Mathieu Poirier > Signed-off-by: Suzuki K Poulose > --- > drivers/hwtracing/coresight/coresight-platform.c | 464 +++++++++++++++++++++++ > 1 file changed, 464 insertions(+) > > diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c > index 49112a5..6fef873 100644 > --- a/drivers/hwtracing/coresight/coresight-platform.c > +++ b/drivers/hwtracing/coresight/coresight-platform.c > @@ -3,6 +3,7 @@ > * Copyright (c) 2012, The Linux Foundation. All rights reserved. > */ > > +#include > #include > #include > #include > @@ -308,10 +309,471 @@ of_get_coresight_platform_data(struct device *dev, > } > #endif > > +#ifdef CONFIG_ACPI > + > +#include > +#include > + > +/* 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", } > + * }, > + * > + * 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 0; > + status = acpi_get_parent(adev->handle, &cpu_handle); > + if (ACPI_FAILURE(status)) > + return 0; > + > + cpu = acpi_handle_to_logical_cpuid(cpu_handle); > + if (cpu >= nr_cpu_ids) > + return 0; > + 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 0; > +} > +#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); > @@ -334,6 +796,8 @@ coresight_get_platform_data(struct device *dev) > > 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; Reviewed-by: Mathieu Poirier > -- > 2.7.4 >