Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'coresight-next-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux into char-misc-next

Suzuki writes:

coresight: Updates for v6.5

CoreSight and hwtracing subsystem updates for v6.5 includes:

- Fixes to the CTI module reference leaks. This involves,
redesign of how the helper devices are tracked and CTI
devices have been converted to helper devices.
- Fix removal of the trctraceidr file from sysfs for ETMs.
- Match all ETMv4 instances based on the ETMv4 architected
registers and the CoreSight Component ID (CID), than having
to add individual PIDs for CPUs.
- Add support for Dummy CoreSight source and sink drivers.
- Add James Clark as Reviewer for the CoreSight kernel drivers
- Fixes to HiSilicon PCIe Tune and Trace Device driver

Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>

* tag 'coresight-next-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux: (27 commits)
hwtracing: hisi_ptt: Fix potential sleep in atomic context
hwtracing: hisi_ptt: Advertise PERF_PMU_CAP_NO_EXCLUDE for PTT PMU
hwtracing: hisi_ptt: Export available filters through sysfs
hwtracing: hisi_ptt: Add support for dynamically updating the filter list
hwtracing: hisi_ptt: Factor out filter allocation and release operation
coresight: dummy: Update type of mode parameter in dummy_{sink,source}_enable()
Documentation: trace: Add documentation for Coresight Dummy Trace
dt-bindings: arm: Add support for Coresight dummy trace
Coresight: Add coresight dummy driver
MAINTAINERS: coresight: Add James Clark as Reviewer
coresight: etm4x: Match all ETM4 instances based on DEVARCH and DEVTYPE
coresight: etm4x: Make etm4_remove_dev() return void
coresight: etm4x: Fix missing trctraceidr file in sysfs
coresight: Fix CTI module refcount leak by making it a helper device
coresight: Enable and disable helper devices adjacent to the path
coresight: Refactor out buffer allocation function for ETR
coresight: Make refcount a property of the connection
coresight: Store in-connections as well as out-connections
coresight: Simplify connection fixup mechanism
coresight: Store pointers to connections rather than an array of them
...

+1657 -737
+52
Documentation/ABI/testing/sysfs-devices-hisi_ptt
··· 59 59 The available tune data is [0, 1, 2]. Writing a negative value 60 60 will return an error, and out of range values will be converted 61 61 to 2. The value indicates a probable level of the event. 62 + 63 + What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters 64 + Date: May 2023 65 + KernelVersion: 6.5 66 + Contact: Yicong Yang <yangyicong@hisilicon.com> 67 + Description: This directory contains the files providing the PCIe Root Port filters 68 + information used for PTT trace. Each file is named after the supported 69 + Root Port device name <domain>:<bus>:<device>.<function>. 70 + 71 + See the description of the "filter" in Documentation/trace/hisi-ptt.rst 72 + for more information. 73 + 74 + What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters/multiselect 75 + Date: May 2023 76 + KernelVersion: 6.5 77 + Contact: Yicong Yang <yangyicong@hisilicon.com> 78 + Description: (Read) Indicates if this kind of filter can be selected at the same 79 + time as others filters, or must be used on it's own. 1 indicates 80 + the former case and 0 indicates the latter. 81 + 82 + What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters/<bdf> 83 + Date: May 2023 84 + KernelVersion: 6.5 85 + Contact: Yicong Yang <yangyicong@hisilicon.com> 86 + Description: (Read) Indicates the filter value of this Root Port filter, which 87 + can be used to control the TLP headers to trace by the PTT trace. 88 + 89 + What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters 90 + Date: May 2023 91 + KernelVersion: 6.5 92 + Contact: Yicong Yang <yangyicong@hisilicon.com> 93 + Description: This directory contains the files providing the PCIe Requester filters 94 + information used for PTT trace. Each file is named after the supported 95 + Endpoint device name <domain>:<bus>:<device>.<function>. 96 + 97 + See the description of the "filter" in Documentation/trace/hisi-ptt.rst 98 + for more information. 99 + 100 + What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters/multiselect 101 + Date: May 2023 102 + KernelVersion: 6.5 103 + Contact: Yicong Yang <yangyicong@hisilicon.com> 104 + Description: (Read) Indicates if this kind of filter can be selected at the same 105 + time as others filters, or must be used on it's own. 1 indicates 106 + the former case and 0 indicates the latter. 107 + 108 + What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters/<bdf> 109 + Date: May 2023 110 + KernelVersion: 6.5 111 + Contact: Yicong Yang <yangyicong@hisilicon.com> 112 + Description: (Read) Indicates the filter value of this Requester filter, which 113 + can be used to control the TLP headers to trace by the PTT trace.
+73
Documentation/devicetree/bindings/arm/arm,coresight-dummy-sink.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/arm/arm,coresight-dummy-sink.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: ARM Coresight Dummy sink component 8 + 9 + description: | 10 + CoreSight components are compliant with the ARM CoreSight architecture 11 + specification and can be connected in various topologies to suit a particular 12 + SoCs tracing needs. These trace components can generally be classified as 13 + sinks, links and sources. Trace data produced by one or more sources flows 14 + through the intermediate links connecting the source to the currently selected 15 + sink. 16 + 17 + The Coresight dummy sink component is for the specific coresight sink devices 18 + kernel don't have permission to access or configure, e.g., CoreSight EUD on 19 + Qualcomm platforms. It is a mini-USB hub implemented to support the USB-based 20 + debug and trace capabilities. For this device, a dummy driver is needed to 21 + register it as Coresight sink device in kernel side, so that path can be 22 + created in the driver. Then the trace flow would be transferred to EUD via 23 + coresight link of AP processor. It provides Coresight API for operations on 24 + dummy source devices, such as enabling and disabling them. It also provides 25 + the Coresight dummy source paths for debugging. 26 + 27 + The primary use case of the coresight dummy sink is to build path in kernel 28 + side for dummy sink component. 29 + 30 + maintainers: 31 + - Mike Leach <mike.leach@linaro.org> 32 + - Suzuki K Poulose <suzuki.poulose@arm.com> 33 + - James Clark <james.clark@arm.com> 34 + - Mao Jinlong <quic_jinlmao@quicinc.com> 35 + - Hao Zhang <quic_hazha@quicinc.com> 36 + 37 + properties: 38 + compatible: 39 + enum: 40 + - arm,coresight-dummy-sink 41 + 42 + in-ports: 43 + $ref: /schemas/graph.yaml#/properties/ports 44 + 45 + properties: 46 + port: 47 + description: Input connection from the Coresight Trace bus to 48 + dummy sink, such as Embedded USB debugger(EUD). 49 + 50 + $ref: /schemas/graph.yaml#/properties/port 51 + 52 + required: 53 + - compatible 54 + - in-ports 55 + 56 + additionalProperties: false 57 + 58 + examples: 59 + # Minimum dummy sink definition. Dummy sink connect to coresight replicator. 60 + - | 61 + sink { 62 + compatible = "arm,coresight-dummy-sink"; 63 + 64 + in-ports { 65 + port { 66 + eud_in_replicator_swao: endpoint { 67 + remote-endpoint = <&replicator_swao_out_eud>; 68 + }; 69 + }; 70 + }; 71 + }; 72 + 73 + ...
+71
Documentation/devicetree/bindings/arm/arm,coresight-dummy-source.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/arm/arm,coresight-dummy-source.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: ARM Coresight Dummy source component 8 + 9 + description: | 10 + CoreSight components are compliant with the ARM CoreSight architecture 11 + specification and can be connected in various topologies to suit a particular 12 + SoCs tracing needs. These trace components can generally be classified as 13 + sinks, links and sources. Trace data produced by one or more sources flows 14 + through the intermediate links connecting the source to the currently selected 15 + sink. 16 + 17 + The Coresight dummy source component is for the specific coresight source 18 + devices kernel don't have permission to access or configure. For some SOCs, 19 + there would be Coresight source trace components on sub-processor which 20 + are conneted to AP processor via debug bus. For these devices, a dummy driver 21 + is needed to register them as Coresight source devices, so that paths can be 22 + created in the driver. It provides Coresight API for operations on dummy 23 + source devices, such as enabling and disabling them. It also provides the 24 + Coresight dummy source paths for debugging. 25 + 26 + The primary use case of the coresight dummy source is to build path in kernel 27 + side for dummy source component. 28 + 29 + maintainers: 30 + - Mike Leach <mike.leach@linaro.org> 31 + - Suzuki K Poulose <suzuki.poulose@arm.com> 32 + - James Clark <james.clark@arm.com> 33 + - Mao Jinlong <quic_jinlmao@quicinc.com> 34 + - Hao Zhang <quic_hazha@quicinc.com> 35 + 36 + properties: 37 + compatible: 38 + enum: 39 + - arm,coresight-dummy-source 40 + 41 + out-ports: 42 + $ref: /schemas/graph.yaml#/properties/ports 43 + 44 + properties: 45 + port: 46 + description: Output connection from the source to Coresight 47 + Trace bus. 48 + $ref: /schemas/graph.yaml#/properties/port 49 + 50 + required: 51 + - compatible 52 + - out-ports 53 + 54 + additionalProperties: false 55 + 56 + examples: 57 + # Minimum dummy source definition. Dummy source connect to coresight funnel. 58 + - | 59 + source { 60 + compatible = "arm,coresight-dummy-source"; 61 + 62 + out-ports { 63 + port { 64 + dummy_riscv_out_funnel_swao: endpoint { 65 + remote-endpoint = <&funnel_swao_in_dummy_riscv>; 66 + }; 67 + }; 68 + }; 69 + }; 70 + 71 + ...
+1
Documentation/driver-api/driver-model/devres.rst
··· 364 364 devm_kmalloc_array() 365 365 devm_kmemdup() 366 366 devm_krealloc() 367 + devm_krealloc_array() 367 368 devm_kstrdup() 368 369 devm_kstrdup_const() 369 370 devm_kvasprintf()
+32
Documentation/trace/coresight/coresight-dummy.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + ============================= 4 + Coresight Dummy Trace Module 5 + ============================= 6 + 7 + :Author: Hao Zhang <quic_hazha@quicinc.com> 8 + :Date: June 2023 9 + 10 + Introduction 11 + ------------ 12 + 13 + The Coresight dummy trace module is for the specific devices that kernel don't 14 + have permission to access or configure, e.g., CoreSight TPDMs on Qualcomm 15 + platforms. For these devices, a dummy driver is needed to register them as 16 + Coresight devices. The module may also be used to define components that may 17 + not have any programming interfaces, so that paths can be created in the driver. 18 + It provides Coresight API for operations on dummy devices, such as enabling and 19 + disabling them. It also provides the Coresight dummy sink/source paths for 20 + debugging. 21 + 22 + Config details 23 + -------------- 24 + 25 + There are two types of nodes, dummy sink and dummy source. These nodes 26 + are available at ``/sys/bus/coresight/devices``. 27 + 28 + Example output:: 29 + 30 + $ ls -l /sys/bus/coresight/devices | grep dummy 31 + dummy_sink0 -> ../../../devices/platform/soc@0/soc@0:sink/dummy_sink0 32 + dummy_source0 -> ../../../devices/platform/soc@0/soc@0:source/dummy_source0
+9 -3
Documentation/trace/hisi-ptt.rst
··· 148 148 value will be 0x00101. If the desired filter is Root Port 0000:00:10.0 then 149 149 then filter value is calculated as 0x80001. 150 150 151 + The driver also presents every supported Root Port and Requester filter through 152 + sysfs. Each filter will be an individual file with name of its related PCIe 153 + device name (domain:bus:device.function). The files of Root Port filters are 154 + under $(PTT PMU dir)/root_port_filters and files of Requester filters 155 + are under $(PTT PMU dir)/requester_filters. 156 + 151 157 Note that multiple Root Ports can be specified at one time, but only one 152 158 Endpoint function can be specified in one trace. Specifying both Root Port 153 159 and function at the same time is not supported. Driver maintains a list of 154 160 available filters and will check the invalid inputs. 155 161 156 - Currently the available filters are detected in driver's probe. If the supported 157 - devices are removed/added after probe, you may need to reload the driver to update 158 - the filters. 162 + The available filters will be dynamically updated, which means you will always 163 + get correct filter information when hotplug events happen, or when you manually 164 + remove/rescan the devices. 159 165 160 166 2. Type 161 167 -------
+1
MAINTAINERS
··· 2098 2098 ARM/CORESIGHT FRAMEWORK AND DRIVERS 2099 2099 M: Suzuki K Poulose <suzuki.poulose@arm.com> 2100 2100 R: Mike Leach <mike.leach@linaro.org> 2101 + R: James Clark <james.clark@arm.com> 2101 2102 R: Leo Yan <leo.yan@linaro.org> 2102 2103 L: coresight@lists.linaro.org (moderated for non-subscribers) 2103 2104 L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+11
drivers/hwtracing/coresight/Kconfig
··· 236 236 237 237 To compile this driver as a module, choose M here: the module will be 238 238 called coresight-tpda. 239 + 240 + config CORESIGHT_DUMMY 241 + tristate "Dummy driver support" 242 + help 243 + Enables support for dummy driver. Dummy driver can be used for 244 + CoreSight sources/sinks that are owned and configured by some 245 + other subsystem and use Linux drivers to configure rest of trace 246 + path. 247 + 248 + To compile this driver as a module, choose M here: the module will be 249 + called coresight-dummy. 239 250 endif
+1
drivers/hwtracing/coresight/Makefile
··· 30 30 coresight-cti-y := coresight-cti-core.o coresight-cti-platform.o \ 31 31 coresight-cti-sysfs.o 32 32 obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o 33 + obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
+17 -4
drivers/hwtracing/coresight/coresight-catu.c
··· 395 395 return coresight_timeout(csa, CATU_STATUS, CATU_STATUS_READY, 1); 396 396 } 397 397 398 - static int catu_enable_hw(struct catu_drvdata *drvdata, void *data) 398 + static int catu_enable_hw(struct catu_drvdata *drvdata, enum cs_mode cs_mode, 399 + void *data) 399 400 { 400 401 int rc; 401 402 u32 control, mode; 402 - struct etr_buf *etr_buf = data; 403 + struct etr_buf *etr_buf = NULL; 403 404 struct device *dev = &drvdata->csdev->dev; 404 405 struct coresight_device *csdev = drvdata->csdev; 406 + struct coresight_device *etrdev; 407 + union coresight_dev_subtype etr_subtype = { 408 + .sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM 409 + }; 405 410 406 411 if (catu_wait_for_ready(drvdata)) 407 412 dev_warn(dev, "Timeout while waiting for READY\n"); ··· 421 416 if (rc) 422 417 return rc; 423 418 419 + etrdev = coresight_find_input_type( 420 + csdev->pdata, CORESIGHT_DEV_TYPE_SINK, etr_subtype); 421 + if (etrdev) { 422 + etr_buf = tmc_etr_get_buffer(etrdev, cs_mode, data); 423 + if (IS_ERR(etr_buf)) 424 + return PTR_ERR(etr_buf); 425 + } 424 426 control |= BIT(CATU_CONTROL_ENABLE); 425 427 426 428 if (etr_buf && etr_buf->mode == ETR_MODE_CATU) { ··· 453 441 return 0; 454 442 } 455 443 456 - static int catu_enable(struct coresight_device *csdev, void *data) 444 + static int catu_enable(struct coresight_device *csdev, enum cs_mode mode, 445 + void *data) 457 446 { 458 447 int rc; 459 448 struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev); 460 449 461 450 CS_UNLOCK(catu_drvdata->base); 462 - rc = catu_enable_hw(catu_drvdata, data); 451 + rc = catu_enable_hw(catu_drvdata, mode, data); 463 452 CS_LOCK(catu_drvdata->base); 464 453 return rc; 465 454 }
+329 -294
drivers/hwtracing/coresight/coresight-core.c
··· 3 3 * Copyright (c) 2012, The Linux Foundation. All rights reserved. 4 4 */ 5 5 6 + #include <linux/build_bug.h> 6 7 #include <linux/kernel.h> 7 8 #include <linux/init.h> 8 9 #include <linux/types.h> ··· 113 112 } 114 113 EXPORT_SYMBOL_GPL(coresight_get_percpu_sink); 115 114 116 - static int coresight_find_link_inport(struct coresight_device *csdev, 117 - struct coresight_device *parent) 115 + static struct coresight_connection * 116 + coresight_find_out_connection(struct coresight_device *src_dev, 117 + struct coresight_device *dest_dev) 118 118 { 119 119 int i; 120 120 struct coresight_connection *conn; 121 121 122 - for (i = 0; i < parent->pdata->nr_outport; i++) { 123 - conn = &parent->pdata->conns[i]; 124 - if (conn->child_dev == csdev) 125 - return conn->child_port; 122 + for (i = 0; i < src_dev->pdata->nr_outconns; i++) { 123 + conn = src_dev->pdata->out_conns[i]; 124 + if (conn->dest_dev == dest_dev) 125 + return conn; 126 126 } 127 127 128 - dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n", 129 - dev_name(&parent->dev), dev_name(&csdev->dev)); 128 + dev_err(&src_dev->dev, 129 + "couldn't find output connection, src_dev: %s, dest_dev: %s\n", 130 + dev_name(&src_dev->dev), dev_name(&dest_dev->dev)); 130 131 131 - return -ENODEV; 132 - } 133 - 134 - static int coresight_find_link_outport(struct coresight_device *csdev, 135 - struct coresight_device *child) 136 - { 137 - int i; 138 - struct coresight_connection *conn; 139 - 140 - for (i = 0; i < csdev->pdata->nr_outport; i++) { 141 - conn = &csdev->pdata->conns[i]; 142 - if (conn->child_dev == child) 143 - return conn->outport; 144 - } 145 - 146 - dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n", 147 - dev_name(&csdev->dev), dev_name(&child->dev)); 148 - 149 - return -ENODEV; 132 + return ERR_PTR(-ENODEV); 150 133 } 151 134 152 135 static inline u32 coresight_read_claim_tags(struct coresight_device *csdev) ··· 237 252 } 238 253 EXPORT_SYMBOL_GPL(coresight_disclaim_device); 239 254 240 - /* enable or disable an associated CTI device of the supplied CS device */ 241 - static int 242 - coresight_control_assoc_ectdev(struct coresight_device *csdev, bool enable) 243 - { 244 - int ect_ret = 0; 245 - struct coresight_device *ect_csdev = csdev->ect_dev; 246 - struct module *mod; 247 - 248 - if (!ect_csdev) 249 - return 0; 250 - if ((!ect_ops(ect_csdev)->enable) || (!ect_ops(ect_csdev)->disable)) 251 - return 0; 252 - 253 - mod = ect_csdev->dev.parent->driver->owner; 254 - if (enable) { 255 - if (try_module_get(mod)) { 256 - ect_ret = ect_ops(ect_csdev)->enable(ect_csdev); 257 - if (ect_ret) { 258 - module_put(mod); 259 - } else { 260 - get_device(ect_csdev->dev.parent); 261 - csdev->ect_enabled = true; 262 - } 263 - } else 264 - ect_ret = -ENODEV; 265 - } else { 266 - if (csdev->ect_enabled) { 267 - ect_ret = ect_ops(ect_csdev)->disable(ect_csdev); 268 - put_device(ect_csdev->dev.parent); 269 - module_put(mod); 270 - csdev->ect_enabled = false; 271 - } 272 - } 273 - 274 - /* output warning if ECT enable is preventing trace operation */ 275 - if (ect_ret) 276 - dev_info(&csdev->dev, "Associated ECT device (%s) %s failed\n", 277 - dev_name(&ect_csdev->dev), 278 - enable ? "enable" : "disable"); 279 - return ect_ret; 280 - } 281 - 282 255 /* 283 - * Set the associated ect / cti device while holding the coresight_mutex 284 - * to avoid a race with coresight_enable that may try to use this value. 256 + * Add a helper as an output device. This function takes the @coresight_mutex 257 + * because it's assumed that it's called from the helper device, outside of the 258 + * core code where the mutex would already be held. Don't add new calls to this 259 + * from inside the core code, instead try to add the new helper to the DT and 260 + * ACPI where it will be picked up and linked automatically. 285 261 */ 286 - void coresight_set_assoc_ectdev_mutex(struct coresight_device *csdev, 287 - struct coresight_device *ect_csdev) 262 + void coresight_add_helper(struct coresight_device *csdev, 263 + struct coresight_device *helper) 288 264 { 265 + int i; 266 + struct coresight_connection conn = {}; 267 + struct coresight_connection *new_conn; 268 + 289 269 mutex_lock(&coresight_mutex); 290 - csdev->ect_dev = ect_csdev; 270 + conn.dest_fwnode = fwnode_handle_get(dev_fwnode(&helper->dev)); 271 + conn.dest_dev = helper; 272 + conn.dest_port = conn.src_port = -1; 273 + conn.src_dev = csdev; 274 + 275 + /* 276 + * Check for duplicates because this is called every time a helper 277 + * device is re-loaded. Existing connections will get re-linked 278 + * automatically. 279 + */ 280 + for (i = 0; i < csdev->pdata->nr_outconns; ++i) 281 + if (csdev->pdata->out_conns[i]->dest_fwnode == conn.dest_fwnode) 282 + goto unlock; 283 + 284 + new_conn = coresight_add_out_conn(csdev->dev.parent, csdev->pdata, 285 + &conn); 286 + if (!IS_ERR(new_conn)) 287 + coresight_add_in_conn(new_conn); 288 + 289 + unlock: 291 290 mutex_unlock(&coresight_mutex); 292 291 } 293 - EXPORT_SYMBOL_GPL(coresight_set_assoc_ectdev_mutex); 292 + EXPORT_SYMBOL_GPL(coresight_add_helper); 294 293 295 294 static int coresight_enable_sink(struct coresight_device *csdev, 296 - u32 mode, void *data) 295 + enum cs_mode mode, void *data) 297 296 { 298 297 int ret; 299 298 ··· 288 319 if (!sink_ops(csdev)->enable) 289 320 return -EINVAL; 290 321 291 - ret = coresight_control_assoc_ectdev(csdev, true); 322 + ret = sink_ops(csdev)->enable(csdev, mode, data); 292 323 if (ret) 293 324 return ret; 294 - ret = sink_ops(csdev)->enable(csdev, mode, data); 295 - if (ret) { 296 - coresight_control_assoc_ectdev(csdev, false); 297 - return ret; 298 - } 325 + 299 326 csdev->enable = true; 300 327 301 328 return 0; ··· 307 342 ret = sink_ops(csdev)->disable(csdev); 308 343 if (ret) 309 344 return; 310 - coresight_control_assoc_ectdev(csdev, false); 311 345 csdev->enable = false; 312 346 } 313 347 ··· 316 352 { 317 353 int ret = 0; 318 354 int link_subtype; 319 - int inport, outport; 355 + struct coresight_connection *inconn, *outconn; 320 356 321 357 if (!parent || !child) 322 358 return -EINVAL; 323 359 324 - inport = coresight_find_link_inport(csdev, parent); 325 - outport = coresight_find_link_outport(csdev, child); 360 + inconn = coresight_find_out_connection(parent, csdev); 361 + outconn = coresight_find_out_connection(csdev, child); 326 362 link_subtype = csdev->subtype.link_subtype; 327 363 328 - if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && inport < 0) 329 - return inport; 330 - if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && outport < 0) 331 - return outport; 364 + if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && IS_ERR(inconn)) 365 + return PTR_ERR(inconn); 366 + if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn)) 367 + return PTR_ERR(outconn); 332 368 333 369 if (link_ops(csdev)->enable) { 334 - ret = coresight_control_assoc_ectdev(csdev, true); 335 - if (!ret) { 336 - ret = link_ops(csdev)->enable(csdev, inport, outport); 337 - if (ret) 338 - coresight_control_assoc_ectdev(csdev, false); 339 - } 370 + ret = link_ops(csdev)->enable(csdev, inconn, outconn); 371 + if (!ret) 372 + csdev->enable = true; 340 373 } 341 - 342 - if (!ret) 343 - csdev->enable = true; 344 374 345 375 return ret; 346 376 } ··· 343 385 struct coresight_device *parent, 344 386 struct coresight_device *child) 345 387 { 346 - int i, nr_conns; 388 + int i; 347 389 int link_subtype; 348 - int inport, outport; 390 + struct coresight_connection *inconn, *outconn; 349 391 350 392 if (!parent || !child) 351 393 return; 352 394 353 - inport = coresight_find_link_inport(csdev, parent); 354 - outport = coresight_find_link_outport(csdev, child); 395 + inconn = coresight_find_out_connection(parent, csdev); 396 + outconn = coresight_find_out_connection(csdev, child); 355 397 link_subtype = csdev->subtype.link_subtype; 356 398 357 - if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) { 358 - nr_conns = csdev->pdata->nr_inport; 359 - } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) { 360 - nr_conns = csdev->pdata->nr_outport; 361 - } else { 362 - nr_conns = 1; 363 - } 364 - 365 399 if (link_ops(csdev)->disable) { 366 - link_ops(csdev)->disable(csdev, inport, outport); 367 - coresight_control_assoc_ectdev(csdev, false); 400 + link_ops(csdev)->disable(csdev, inconn, outconn); 368 401 } 369 402 370 - for (i = 0; i < nr_conns; i++) 371 - if (atomic_read(&csdev->refcnt[i]) != 0) 403 + if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) { 404 + for (i = 0; i < csdev->pdata->nr_inconns; i++) 405 + if (atomic_read(&csdev->pdata->in_conns[i]->dest_refcnt) != 406 + 0) 407 + return; 408 + } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) { 409 + for (i = 0; i < csdev->pdata->nr_outconns; i++) 410 + if (atomic_read(&csdev->pdata->out_conns[i]->src_refcnt) != 411 + 0) 412 + return; 413 + } else { 414 + if (atomic_read(&csdev->refcnt) != 0) 372 415 return; 416 + } 373 417 374 418 csdev->enable = false; 375 419 } 376 420 377 - static int coresight_enable_source(struct coresight_device *csdev, u32 mode) 421 + int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, 422 + void *data) 378 423 { 379 424 int ret; 380 425 381 426 if (!csdev->enable) { 382 427 if (source_ops(csdev)->enable) { 383 - ret = coresight_control_assoc_ectdev(csdev, true); 428 + ret = source_ops(csdev)->enable(csdev, data, mode); 384 429 if (ret) 385 430 return ret; 386 - ret = source_ops(csdev)->enable(csdev, NULL, mode); 387 - if (ret) { 388 - coresight_control_assoc_ectdev(csdev, false); 389 - return ret; 390 - } 391 431 } 392 432 csdev->enable = true; 393 433 } 394 434 395 - atomic_inc(csdev->refcnt); 435 + atomic_inc(&csdev->refcnt); 396 436 397 437 return 0; 438 + } 439 + EXPORT_SYMBOL_GPL(coresight_enable_source); 440 + 441 + static bool coresight_is_helper(struct coresight_device *csdev) 442 + { 443 + return csdev->type == CORESIGHT_DEV_TYPE_HELPER; 444 + } 445 + 446 + static int coresight_enable_helper(struct coresight_device *csdev, 447 + enum cs_mode mode, void *data) 448 + { 449 + int ret; 450 + 451 + if (!helper_ops(csdev)->enable) 452 + return 0; 453 + ret = helper_ops(csdev)->enable(csdev, mode, data); 454 + if (ret) 455 + return ret; 456 + 457 + csdev->enable = true; 458 + return 0; 459 + } 460 + 461 + static void coresight_disable_helper(struct coresight_device *csdev) 462 + { 463 + int ret; 464 + 465 + if (!helper_ops(csdev)->disable) 466 + return; 467 + 468 + ret = helper_ops(csdev)->disable(csdev, NULL); 469 + if (ret) 470 + return; 471 + csdev->enable = false; 472 + } 473 + 474 + static void coresight_disable_helpers(struct coresight_device *csdev) 475 + { 476 + int i; 477 + struct coresight_device *helper; 478 + 479 + for (i = 0; i < csdev->pdata->nr_outconns; ++i) { 480 + helper = csdev->pdata->out_conns[i]->dest_dev; 481 + if (helper && coresight_is_helper(helper)) 482 + coresight_disable_helper(helper); 483 + } 398 484 } 399 485 400 486 /** ··· 446 444 * the device if there are no users left. 447 445 * 448 446 * @csdev: The coresight device to disable 447 + * @data: Opaque data to pass on to the disable function of the source device. 448 + * For example in perf mode this is a pointer to the struct perf_event. 449 449 * 450 450 * Returns true if the device has been disabled. 451 451 */ 452 - static bool coresight_disable_source(struct coresight_device *csdev) 452 + bool coresight_disable_source(struct coresight_device *csdev, void *data) 453 453 { 454 - if (atomic_dec_return(csdev->refcnt) == 0) { 454 + if (atomic_dec_return(&csdev->refcnt) == 0) { 455 455 if (source_ops(csdev)->disable) 456 - source_ops(csdev)->disable(csdev, NULL); 457 - coresight_control_assoc_ectdev(csdev, false); 456 + source_ops(csdev)->disable(csdev, data); 457 + coresight_disable_helpers(csdev); 458 458 csdev->enable = false; 459 459 } 460 460 return !csdev->enable; 461 461 } 462 + EXPORT_SYMBOL_GPL(coresight_disable_source); 462 463 463 464 /* 464 465 * coresight_disable_path_from : Disable components in the given path beyond ··· 512 507 default: 513 508 break; 514 509 } 510 + 511 + /* Disable all helpers adjacent along the path last */ 512 + coresight_disable_helpers(csdev); 515 513 } 516 514 } 517 515 ··· 524 516 } 525 517 EXPORT_SYMBOL_GPL(coresight_disable_path); 526 518 527 - int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data) 519 + static int coresight_enable_helpers(struct coresight_device *csdev, 520 + enum cs_mode mode, void *data) 528 521 { 522 + int i, ret = 0; 523 + struct coresight_device *helper; 529 524 525 + for (i = 0; i < csdev->pdata->nr_outconns; ++i) { 526 + helper = csdev->pdata->out_conns[i]->dest_dev; 527 + if (!helper || !coresight_is_helper(helper)) 528 + continue; 529 + 530 + ret = coresight_enable_helper(helper, mode, data); 531 + if (ret) 532 + return ret; 533 + } 534 + 535 + return 0; 536 + } 537 + 538 + int coresight_enable_path(struct list_head *path, enum cs_mode mode, 539 + void *sink_data) 540 + { 530 541 int ret = 0; 531 542 u32 type; 532 543 struct coresight_node *nd; ··· 555 528 csdev = nd->csdev; 556 529 type = csdev->type; 557 530 531 + /* Enable all helpers adjacent to the path first */ 532 + ret = coresight_enable_helpers(csdev, mode, sink_data); 533 + if (ret) 534 + goto err; 558 535 /* 559 536 * ETF devices are tricky... They can be a link or a sink, 560 537 * depending on how they are configured. If an ETF has been ··· 633 602 /* 634 603 * Recursively explore each port found on this element. 635 604 */ 636 - for (i = 0; i < csdev->pdata->nr_outport; i++) { 605 + for (i = 0; i < csdev->pdata->nr_outconns; i++) { 637 606 struct coresight_device *child_dev; 638 607 639 - child_dev = csdev->pdata->conns[i].child_dev; 608 + child_dev = csdev->pdata->out_conns[i]->dest_dev; 640 609 if (child_dev) 641 610 sink = coresight_find_enabled_sink(child_dev); 642 611 if (sink) ··· 749 718 { 750 719 int i; 751 720 752 - for (i = 0; i < csdev->pdata->nr_outport; i++) { 721 + for (i = 0; i < csdev->pdata->nr_outconns; i++) { 753 722 struct coresight_device *child; 754 723 755 - child = csdev->pdata->conns[i].child_dev; 756 - if (child && child->type == CORESIGHT_DEV_TYPE_HELPER) 724 + child = csdev->pdata->out_conns[i]->dest_dev; 725 + if (child && coresight_is_helper(child)) 757 726 if (!coresight_get_ref(child)) 758 727 goto err; 759 728 } ··· 763 732 for (i--; i >= 0; i--) { 764 733 struct coresight_device *child; 765 734 766 - child = csdev->pdata->conns[i].child_dev; 767 - if (child && child->type == CORESIGHT_DEV_TYPE_HELPER) 735 + child = csdev->pdata->out_conns[i]->dest_dev; 736 + if (child && coresight_is_helper(child)) 768 737 coresight_put_ref(child); 769 738 } 770 739 return -ENODEV; ··· 779 748 int i; 780 749 781 750 coresight_put_ref(csdev); 782 - for (i = 0; i < csdev->pdata->nr_outport; i++) { 751 + for (i = 0; i < csdev->pdata->nr_outconns; i++) { 783 752 struct coresight_device *child; 784 753 785 - child = csdev->pdata->conns[i].child_dev; 786 - if (child && child->type == CORESIGHT_DEV_TYPE_HELPER) 754 + child = csdev->pdata->out_conns[i]->dest_dev; 755 + if (child && coresight_is_helper(child)) 787 756 coresight_put_ref(child); 788 757 } 789 758 } ··· 821 790 } 822 791 823 792 /* Not a sink - recursively explore each port found on this element */ 824 - for (i = 0; i < csdev->pdata->nr_outport; i++) { 793 + for (i = 0; i < csdev->pdata->nr_outconns; i++) { 825 794 struct coresight_device *child_dev; 826 795 827 - child_dev = csdev->pdata->conns[i].child_dev; 796 + child_dev = csdev->pdata->out_conns[i]->dest_dev; 828 797 if (child_dev && 829 798 _coresight_build_path(child_dev, sink, path) == 0) { 830 799 found = true; ··· 990 959 * Not a sink we want - or possible child sink may be better. 991 960 * recursively explore each port found on this element. 992 961 */ 993 - for (i = 0; i < csdev->pdata->nr_outport; i++) { 962 + for (i = 0; i < csdev->pdata->nr_outconns; i++) { 994 963 struct coresight_device *child_dev, *sink = NULL; 995 964 int child_depth = curr_depth; 996 965 997 - child_dev = csdev->pdata->conns[i].child_dev; 966 + child_dev = csdev->pdata->out_conns[i]->dest_dev; 998 967 if (child_dev) 999 968 sink = coresight_find_sink(child_dev, &child_depth); 1000 969 ··· 1124 1093 * source is already enabled. 1125 1094 */ 1126 1095 if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) 1127 - atomic_inc(csdev->refcnt); 1096 + atomic_inc(&csdev->refcnt); 1128 1097 goto out; 1129 1098 } 1130 1099 ··· 1145 1114 if (ret) 1146 1115 goto err_path; 1147 1116 1148 - ret = coresight_enable_source(csdev, CS_MODE_SYSFS); 1117 + ret = coresight_enable_source(csdev, CS_MODE_SYSFS, NULL); 1149 1118 if (ret) 1150 1119 goto err_source; 1151 1120 ··· 1202 1171 if (ret) 1203 1172 goto out; 1204 1173 1205 - if (!csdev->enable || !coresight_disable_source(csdev)) 1174 + if (!csdev->enable || !coresight_disable_source(csdev, NULL)) 1206 1175 goto out; 1207 1176 1208 1177 switch (csdev->subtype.source_subtype) { ··· 1327 1296 }, 1328 1297 { 1329 1298 .name = "helper", 1330 - }, 1331 - { 1332 - .name = "ect", 1333 - }, 1299 + } 1334 1300 }; 1301 + /* Ensure the enum matches the names and groups */ 1302 + static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX); 1335 1303 1336 1304 static void coresight_device_release(struct device *dev) 1337 1305 { 1338 1306 struct coresight_device *csdev = to_coresight_device(dev); 1339 1307 1340 1308 fwnode_handle_put(csdev->dev.fwnode); 1341 - kfree(csdev->refcnt); 1342 1309 kfree(csdev); 1343 1310 } 1344 1311 ··· 1344 1315 { 1345 1316 int i, ret = 0; 1346 1317 bool still_orphan = false; 1347 - struct coresight_device *csdev, *i_csdev; 1318 + struct coresight_device *dst_csdev = data; 1319 + struct coresight_device *src_csdev = to_coresight_device(dev); 1348 1320 struct coresight_connection *conn; 1349 - 1350 - csdev = data; 1351 - i_csdev = to_coresight_device(dev); 1352 - 1353 - /* No need to check oneself */ 1354 - if (csdev == i_csdev) 1355 - return 0; 1321 + bool fixup_self = (src_csdev == dst_csdev); 1356 1322 1357 1323 /* Move on to another component if no connection is orphan */ 1358 - if (!i_csdev->orphan) 1324 + if (!src_csdev->orphan) 1359 1325 return 0; 1360 1326 /* 1361 - * Circle throuch all the connection of that component. If we find 1362 - * an orphan connection whose name matches @csdev, link it. 1327 + * Circle through all the connections of that component. If we find 1328 + * an orphan connection whose name matches @dst_csdev, link it. 1363 1329 */ 1364 - for (i = 0; i < i_csdev->pdata->nr_outport; i++) { 1365 - conn = &i_csdev->pdata->conns[i]; 1330 + for (i = 0; i < src_csdev->pdata->nr_outconns; i++) { 1331 + conn = src_csdev->pdata->out_conns[i]; 1366 1332 1367 - /* Skip the port if FW doesn't describe it */ 1368 - if (!conn->child_fwnode) 1333 + /* Skip the port if it's already connected. */ 1334 + if (conn->dest_dev) 1369 1335 continue; 1370 - /* We have found at least one orphan connection */ 1371 - if (conn->child_dev == NULL) { 1372 - /* Does it match this newly added device? */ 1373 - if (conn->child_fwnode == csdev->dev.fwnode) { 1374 - ret = coresight_make_links(i_csdev, 1375 - conn, csdev); 1376 - if (ret) 1377 - return ret; 1378 - } else { 1379 - /* This component still has an orphan */ 1380 - still_orphan = true; 1381 - } 1336 + 1337 + /* 1338 + * If we are at the "new" device, which triggered this search, 1339 + * we must find the remote device from the fwnode in the 1340 + * connection. 1341 + */ 1342 + if (fixup_self) 1343 + dst_csdev = coresight_find_csdev_by_fwnode( 1344 + conn->dest_fwnode); 1345 + 1346 + /* Does it match this newly added device? */ 1347 + if (dst_csdev && conn->dest_fwnode == dst_csdev->dev.fwnode) { 1348 + ret = coresight_make_links(src_csdev, conn, dst_csdev); 1349 + if (ret) 1350 + return ret; 1351 + 1352 + /* 1353 + * Install the device connection. This also indicates that 1354 + * the links are operational on both ends. 1355 + */ 1356 + conn->dest_dev = dst_csdev; 1357 + conn->src_dev = src_csdev; 1358 + 1359 + ret = coresight_add_in_conn(conn); 1360 + if (ret) 1361 + return ret; 1362 + } else { 1363 + /* This component still has an orphan */ 1364 + still_orphan = true; 1382 1365 } 1383 1366 } 1384 1367 1385 - i_csdev->orphan = still_orphan; 1368 + src_csdev->orphan = still_orphan; 1386 1369 1387 1370 /* 1388 1371 * Returning '0' in case we didn't encounter any error, ··· 1409 1368 csdev, coresight_orphan_match); 1410 1369 } 1411 1370 1412 - 1413 - static int coresight_fixup_device_conns(struct coresight_device *csdev) 1414 - { 1415 - int i, ret = 0; 1416 - 1417 - for (i = 0; i < csdev->pdata->nr_outport; i++) { 1418 - struct coresight_connection *conn = &csdev->pdata->conns[i]; 1419 - 1420 - if (!conn->child_fwnode) 1421 - continue; 1422 - conn->child_dev = 1423 - coresight_find_csdev_by_fwnode(conn->child_fwnode); 1424 - if (conn->child_dev && conn->child_dev->has_conns_grp) { 1425 - ret = coresight_make_links(csdev, conn, 1426 - conn->child_dev); 1427 - if (ret) 1428 - break; 1429 - } else { 1430 - csdev->orphan = true; 1431 - } 1432 - } 1433 - 1434 - return ret; 1435 - } 1436 - 1437 - static int coresight_remove_match(struct device *dev, void *data) 1438 - { 1439 - int i; 1440 - struct coresight_device *csdev, *iterator; 1441 - struct coresight_connection *conn; 1442 - 1443 - csdev = data; 1444 - iterator = to_coresight_device(dev); 1445 - 1446 - /* No need to check oneself */ 1447 - if (csdev == iterator) 1448 - return 0; 1449 - 1450 - /* 1451 - * Circle throuch all the connection of that component. If we find 1452 - * a connection whose name matches @csdev, remove it. 1453 - */ 1454 - for (i = 0; i < iterator->pdata->nr_outport; i++) { 1455 - conn = &iterator->pdata->conns[i]; 1456 - 1457 - if (conn->child_dev == NULL || conn->child_fwnode == NULL) 1458 - continue; 1459 - 1460 - if (csdev->dev.fwnode == conn->child_fwnode) { 1461 - iterator->orphan = true; 1462 - coresight_remove_links(iterator, conn); 1463 - /* 1464 - * Drop the reference to the handle for the remote 1465 - * device acquired in parsing the connections from 1466 - * platform data. 1467 - */ 1468 - fwnode_handle_put(conn->child_fwnode); 1469 - conn->child_fwnode = NULL; 1470 - /* No need to continue */ 1471 - break; 1472 - } 1473 - } 1474 - 1475 - /* 1476 - * Returning '0' ensures that all known component on the 1477 - * bus will be checked. 1478 - */ 1479 - return 0; 1480 - } 1481 - 1482 - /* 1483 - * coresight_remove_conns - Remove references to this given devices 1484 - * from the connections of other devices. 1485 - */ 1371 + /* coresight_remove_conns - Remove other device's references to this device */ 1486 1372 static void coresight_remove_conns(struct coresight_device *csdev) 1487 1373 { 1374 + int i, j; 1375 + struct coresight_connection *conn; 1376 + 1488 1377 /* 1489 - * Another device will point to this device only if there is 1490 - * an output port connected to this one. i.e, if the device 1491 - * doesn't have at least one input port, there is no point 1492 - * in searching all the devices. 1378 + * Remove the input connection references from the destination device 1379 + * for each output connection. 1493 1380 */ 1494 - if (csdev->pdata->nr_inport) 1495 - bus_for_each_dev(&coresight_bustype, NULL, 1496 - csdev, coresight_remove_match); 1381 + for (i = 0; i < csdev->pdata->nr_outconns; i++) { 1382 + conn = csdev->pdata->out_conns[i]; 1383 + if (!conn->dest_dev) 1384 + continue; 1385 + 1386 + for (j = 0; j < conn->dest_dev->pdata->nr_inconns; ++j) 1387 + if (conn->dest_dev->pdata->in_conns[j] == conn) { 1388 + conn->dest_dev->pdata->in_conns[j] = NULL; 1389 + break; 1390 + } 1391 + } 1392 + 1393 + /* 1394 + * For all input connections, remove references to this device. 1395 + * Connection objects are shared so modifying this device's input 1396 + * connections affects the other device's output connection. 1397 + */ 1398 + for (i = 0; i < csdev->pdata->nr_inconns; ++i) { 1399 + conn = csdev->pdata->in_conns[i]; 1400 + /* Input conns array is sparse */ 1401 + if (!conn) 1402 + continue; 1403 + 1404 + conn->src_dev->orphan = true; 1405 + coresight_remove_links(conn->src_dev, conn); 1406 + conn->dest_dev = NULL; 1407 + } 1497 1408 } 1498 1409 1499 1410 /** ··· 1537 1544 * to the output port of this device. 1538 1545 */ 1539 1546 void coresight_release_platform_data(struct coresight_device *csdev, 1547 + struct device *dev, 1540 1548 struct coresight_platform_data *pdata) 1541 1549 { 1542 1550 int i; 1543 - struct coresight_connection *conns = pdata->conns; 1551 + struct coresight_connection **conns = pdata->out_conns; 1544 1552 1545 - for (i = 0; i < pdata->nr_outport; i++) { 1553 + for (i = 0; i < pdata->nr_outconns; i++) { 1546 1554 /* If we have made the links, remove them now */ 1547 - if (csdev && conns[i].child_dev) 1548 - coresight_remove_links(csdev, &conns[i]); 1555 + if (csdev && conns[i]->dest_dev) 1556 + coresight_remove_links(csdev, conns[i]); 1549 1557 /* 1550 1558 * Drop the refcount and clear the handle as this device 1551 1559 * is going away 1552 1560 */ 1553 - if (conns[i].child_fwnode) { 1554 - fwnode_handle_put(conns[i].child_fwnode); 1555 - pdata->conns[i].child_fwnode = NULL; 1556 - } 1561 + fwnode_handle_put(conns[i]->dest_fwnode); 1562 + conns[i]->dest_fwnode = NULL; 1563 + devm_kfree(dev, conns[i]); 1557 1564 } 1565 + devm_kfree(dev, pdata->out_conns); 1566 + devm_kfree(dev, pdata->in_conns); 1567 + devm_kfree(dev, pdata); 1558 1568 if (csdev) 1559 1569 coresight_remove_conns_sysfs_group(csdev); 1560 1570 } ··· 1565 1569 struct coresight_device *coresight_register(struct coresight_desc *desc) 1566 1570 { 1567 1571 int ret; 1568 - int link_subtype; 1569 - int nr_refcnts = 1; 1570 - atomic_t *refcnts = NULL; 1571 1572 struct coresight_device *csdev; 1572 1573 bool registered = false; 1573 1574 ··· 1574 1581 goto err_out; 1575 1582 } 1576 1583 1577 - if (desc->type == CORESIGHT_DEV_TYPE_LINK || 1578 - desc->type == CORESIGHT_DEV_TYPE_LINKSINK) { 1579 - link_subtype = desc->subtype.link_subtype; 1580 - 1581 - if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) 1582 - nr_refcnts = desc->pdata->nr_inport; 1583 - else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) 1584 - nr_refcnts = desc->pdata->nr_outport; 1585 - } 1586 - 1587 - refcnts = kcalloc(nr_refcnts, sizeof(*refcnts), GFP_KERNEL); 1588 - if (!refcnts) { 1589 - ret = -ENOMEM; 1590 - kfree(csdev); 1591 - goto err_out; 1592 - } 1593 - 1594 - csdev->refcnt = refcnts; 1595 - 1596 1584 csdev->pdata = desc->pdata; 1597 1585 1598 1586 csdev->type = desc->type; 1599 1587 csdev->subtype = desc->subtype; 1600 1588 csdev->ops = desc->ops; 1601 1589 csdev->access = desc->access; 1602 - csdev->orphan = false; 1590 + csdev->orphan = true; 1603 1591 1604 1592 csdev->dev.type = &coresight_dev_type[desc->type]; 1605 1593 csdev->dev.groups = desc->groups; ··· 1631 1657 1632 1658 ret = coresight_create_conns_sysfs_group(csdev); 1633 1659 if (!ret) 1634 - ret = coresight_fixup_device_conns(csdev); 1635 - if (!ret) 1636 1660 ret = coresight_fixup_orphan_conns(csdev); 1637 1661 1638 1662 out_unlock: ··· 1650 1678 1651 1679 err_out: 1652 1680 /* Cleanup the connection information */ 1653 - coresight_release_platform_data(NULL, desc->pdata); 1681 + coresight_release_platform_data(NULL, desc->dev, desc->pdata); 1654 1682 return ERR_PTR(ret); 1655 1683 } 1656 1684 EXPORT_SYMBOL_GPL(coresight_register); ··· 1663 1691 cti_assoc_ops->remove(csdev); 1664 1692 coresight_remove_conns(csdev); 1665 1693 coresight_clear_default_sink(csdev); 1666 - coresight_release_platform_data(csdev, csdev->pdata); 1694 + coresight_release_platform_data(csdev, csdev->dev.parent, csdev->pdata); 1667 1695 device_unregister(&csdev->dev); 1668 1696 } 1669 1697 EXPORT_SYMBOL_GPL(coresight_unregister); ··· 1685 1713 return i; 1686 1714 return -ENOENT; 1687 1715 } 1716 + 1717 + static bool coresight_compare_type(enum coresight_dev_type type_a, 1718 + union coresight_dev_subtype subtype_a, 1719 + enum coresight_dev_type type_b, 1720 + union coresight_dev_subtype subtype_b) 1721 + { 1722 + if (type_a != type_b) 1723 + return false; 1724 + 1725 + switch (type_a) { 1726 + case CORESIGHT_DEV_TYPE_SINK: 1727 + return subtype_a.sink_subtype == subtype_b.sink_subtype; 1728 + case CORESIGHT_DEV_TYPE_LINK: 1729 + return subtype_a.link_subtype == subtype_b.link_subtype; 1730 + case CORESIGHT_DEV_TYPE_LINKSINK: 1731 + return subtype_a.link_subtype == subtype_b.link_subtype && 1732 + subtype_a.sink_subtype == subtype_b.sink_subtype; 1733 + case CORESIGHT_DEV_TYPE_SOURCE: 1734 + return subtype_a.source_subtype == subtype_b.source_subtype; 1735 + case CORESIGHT_DEV_TYPE_HELPER: 1736 + return subtype_a.helper_subtype == subtype_b.helper_subtype; 1737 + default: 1738 + return false; 1739 + } 1740 + } 1741 + 1742 + struct coresight_device * 1743 + coresight_find_input_type(struct coresight_platform_data *pdata, 1744 + enum coresight_dev_type type, 1745 + union coresight_dev_subtype subtype) 1746 + { 1747 + int i; 1748 + struct coresight_connection *conn; 1749 + 1750 + for (i = 0; i < pdata->nr_inconns; ++i) { 1751 + conn = pdata->in_conns[i]; 1752 + if (conn && 1753 + coresight_compare_type(type, subtype, conn->src_dev->type, 1754 + conn->src_dev->subtype)) 1755 + return conn->src_dev; 1756 + } 1757 + return NULL; 1758 + } 1759 + EXPORT_SYMBOL_GPL(coresight_find_input_type); 1760 + 1761 + struct coresight_device * 1762 + coresight_find_output_type(struct coresight_platform_data *pdata, 1763 + enum coresight_dev_type type, 1764 + union coresight_dev_subtype subtype) 1765 + { 1766 + int i; 1767 + struct coresight_connection *conn; 1768 + 1769 + for (i = 0; i < pdata->nr_outconns; ++i) { 1770 + conn = pdata->out_conns[i]; 1771 + if (conn->dest_dev && 1772 + coresight_compare_type(type, subtype, conn->dest_dev->type, 1773 + conn->dest_dev->subtype)) 1774 + return conn->dest_dev; 1775 + } 1776 + return NULL; 1777 + } 1778 + EXPORT_SYMBOL_GPL(coresight_find_output_type); 1688 1779 1689 1780 bool coresight_loses_context_with_cpu(struct device *dev) 1690 1781 {
+28 -24
drivers/hwtracing/coresight/coresight-cti-core.c
··· 555 555 mutex_lock(&ect_mutex); 556 556 557 557 /* exit if current is an ECT device.*/ 558 - if ((csdev->type == CORESIGHT_DEV_TYPE_ECT) || list_empty(&ect_net)) 558 + if ((csdev->type == CORESIGHT_DEV_TYPE_HELPER && 559 + csdev->subtype.helper_subtype == 560 + CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI) || 561 + list_empty(&ect_net)) 559 562 goto cti_add_done; 560 563 561 564 /* if we didn't find the csdev previously we used the fwnode name */ ··· 574 571 * if we found a matching csdev then update the ECT 575 572 * association pointer for the device with this CTI. 576 573 */ 577 - coresight_set_assoc_ectdev_mutex(csdev, 578 - ect_item->csdev); 574 + coresight_add_helper(csdev, ect_item->csdev); 579 575 break; 580 576 } 581 577 } ··· 584 582 585 583 /* 586 584 * Removing the associated devices is easier. 587 - * A CTI will not have a value for csdev->ect_dev. 588 585 */ 589 586 static void cti_remove_assoc_from_csdev(struct coresight_device *csdev) 590 587 { 591 588 struct cti_drvdata *ctidrv; 592 589 struct cti_trig_con *tc; 593 590 struct cti_device *ctidev; 591 + union coresight_dev_subtype cti_subtype = { 592 + .helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI 593 + }; 594 + struct coresight_device *cti_csdev = coresight_find_output_type( 595 + csdev->pdata, CORESIGHT_DEV_TYPE_HELPER, cti_subtype); 596 + 597 + if (!cti_csdev) 598 + return; 594 599 595 600 mutex_lock(&ect_mutex); 596 - if (csdev->ect_dev) { 597 - ctidrv = csdev_to_cti_drvdata(csdev->ect_dev); 598 - ctidev = &ctidrv->ctidev; 599 - list_for_each_entry(tc, &ctidev->trig_cons, node) { 600 - if (tc->con_dev == csdev) { 601 - cti_remove_sysfs_link(ctidrv, tc); 602 - tc->con_dev = NULL; 603 - break; 604 - } 601 + ctidrv = csdev_to_cti_drvdata(cti_csdev); 602 + ctidev = &ctidrv->ctidev; 603 + list_for_each_entry(tc, &ctidev->trig_cons, node) { 604 + if (tc->con_dev == csdev) { 605 + cti_remove_sysfs_link(ctidrv, tc); 606 + tc->con_dev = NULL; 607 + break; 605 608 } 606 - csdev->ect_dev = NULL; 607 609 } 608 610 mutex_unlock(&ect_mutex); 609 611 } ··· 636 630 /* if we can set the sysfs link */ 637 631 if (cti_add_sysfs_link(drvdata, tc)) 638 632 /* set the CTI/csdev association */ 639 - coresight_set_assoc_ectdev_mutex(tc->con_dev, 640 - drvdata->csdev); 633 + coresight_add_helper(tc->con_dev, 634 + drvdata->csdev); 641 635 else 642 636 /* otherwise remove reference from CTI */ 643 637 tc->con_dev = NULL; ··· 652 646 653 647 list_for_each_entry(tc, &ctidev->trig_cons, node) { 654 648 if (tc->con_dev) { 655 - coresight_set_assoc_ectdev_mutex(tc->con_dev, 656 - NULL); 657 649 cti_remove_sysfs_link(drvdata, tc); 658 650 tc->con_dev = NULL; 659 651 } ··· 799 795 } 800 796 801 797 /** cti ect operations **/ 802 - int cti_enable(struct coresight_device *csdev) 798 + int cti_enable(struct coresight_device *csdev, enum cs_mode mode, void *data) 803 799 { 804 800 struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev); 805 801 806 802 return cti_enable_hw(drvdata); 807 803 } 808 804 809 - int cti_disable(struct coresight_device *csdev) 805 + int cti_disable(struct coresight_device *csdev, void *data) 810 806 { 811 807 struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev); 812 808 813 809 return cti_disable_hw(drvdata); 814 810 } 815 811 816 - static const struct coresight_ops_ect cti_ops_ect = { 812 + static const struct coresight_ops_helper cti_ops_ect = { 817 813 .enable = cti_enable, 818 814 .disable = cti_disable, 819 815 }; 820 816 821 817 static const struct coresight_ops cti_ops = { 822 - .ect_ops = &cti_ops_ect, 818 + .helper_ops = &cti_ops_ect, 823 819 }; 824 820 825 821 /* ··· 926 922 927 923 /* set up coresight component description */ 928 924 cti_desc.pdata = pdata; 929 - cti_desc.type = CORESIGHT_DEV_TYPE_ECT; 930 - cti_desc.subtype.ect_subtype = CORESIGHT_DEV_SUBTYPE_ECT_CTI; 925 + cti_desc.type = CORESIGHT_DEV_TYPE_HELPER; 926 + cti_desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI; 931 927 cti_desc.ops = &cti_ops; 932 928 cti_desc.groups = drvdata->ctidev.con_groups; 933 929 cti_desc.dev = dev;
+2 -2
drivers/hwtracing/coresight/coresight-cti-sysfs.c
··· 112 112 ret = pm_runtime_resume_and_get(dev->parent); 113 113 if (ret) 114 114 return ret; 115 - ret = cti_enable(drvdata->csdev); 115 + ret = cti_enable(drvdata->csdev, CS_MODE_SYSFS, NULL); 116 116 if (ret) 117 117 pm_runtime_put(dev->parent); 118 118 } else { 119 - ret = cti_disable(drvdata->csdev); 119 + ret = cti_disable(drvdata->csdev, NULL); 120 120 if (!ret) 121 121 pm_runtime_put(dev->parent); 122 122 }
+2 -2
drivers/hwtracing/coresight/coresight-cti.h
··· 215 215 const char *assoc_dev_name); 216 216 struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs, 217 217 int out_sigs); 218 - int cti_enable(struct coresight_device *csdev); 219 - int cti_disable(struct coresight_device *csdev); 218 + int cti_enable(struct coresight_device *csdev, enum cs_mode mode, void *data); 219 + int cti_disable(struct coresight_device *csdev, void *data); 220 220 void cti_write_all_hw_regs(struct cti_drvdata *drvdata); 221 221 void cti_write_intack(struct device *dev, u32 ackval); 222 222 void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value);
+163
drivers/hwtracing/coresight/coresight-dummy.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 + */ 5 + 6 + #include <linux/coresight.h> 7 + #include <linux/kernel.h> 8 + #include <linux/module.h> 9 + #include <linux/of.h> 10 + #include <linux/platform_device.h> 11 + #include <linux/pm_runtime.h> 12 + 13 + #include "coresight-priv.h" 14 + 15 + struct dummy_drvdata { 16 + struct device *dev; 17 + struct coresight_device *csdev; 18 + }; 19 + 20 + DEFINE_CORESIGHT_DEVLIST(source_devs, "dummy_source"); 21 + DEFINE_CORESIGHT_DEVLIST(sink_devs, "dummy_sink"); 22 + 23 + static int dummy_source_enable(struct coresight_device *csdev, 24 + struct perf_event *event, enum cs_mode mode) 25 + { 26 + dev_dbg(csdev->dev.parent, "Dummy source enabled\n"); 27 + 28 + return 0; 29 + } 30 + 31 + static void dummy_source_disable(struct coresight_device *csdev, 32 + struct perf_event *event) 33 + { 34 + dev_dbg(csdev->dev.parent, "Dummy source disabled\n"); 35 + } 36 + 37 + static int dummy_sink_enable(struct coresight_device *csdev, enum cs_mode mode, 38 + void *data) 39 + { 40 + dev_dbg(csdev->dev.parent, "Dummy sink enabled\n"); 41 + 42 + return 0; 43 + } 44 + 45 + static int dummy_sink_disable(struct coresight_device *csdev) 46 + { 47 + dev_dbg(csdev->dev.parent, "Dummy sink disabled\n"); 48 + 49 + return 0; 50 + } 51 + 52 + static const struct coresight_ops_source dummy_source_ops = { 53 + .enable = dummy_source_enable, 54 + .disable = dummy_source_disable, 55 + }; 56 + 57 + static const struct coresight_ops dummy_source_cs_ops = { 58 + .source_ops = &dummy_source_ops, 59 + }; 60 + 61 + static const struct coresight_ops_sink dummy_sink_ops = { 62 + .enable = dummy_sink_enable, 63 + .disable = dummy_sink_disable, 64 + }; 65 + 66 + static const struct coresight_ops dummy_sink_cs_ops = { 67 + .sink_ops = &dummy_sink_ops, 68 + }; 69 + 70 + static int dummy_probe(struct platform_device *pdev) 71 + { 72 + struct device *dev = &pdev->dev; 73 + struct device_node *node = dev->of_node; 74 + struct coresight_platform_data *pdata; 75 + struct dummy_drvdata *drvdata; 76 + struct coresight_desc desc = { 0 }; 77 + 78 + if (of_device_is_compatible(node, "arm,coresight-dummy-source")) { 79 + 80 + desc.name = coresight_alloc_device_name(&source_devs, dev); 81 + if (!desc.name) 82 + return -ENOMEM; 83 + 84 + desc.type = CORESIGHT_DEV_TYPE_SOURCE; 85 + desc.subtype.source_subtype = 86 + CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS; 87 + desc.ops = &dummy_source_cs_ops; 88 + } else if (of_device_is_compatible(node, "arm,coresight-dummy-sink")) { 89 + desc.name = coresight_alloc_device_name(&sink_devs, dev); 90 + if (!desc.name) 91 + return -ENOMEM; 92 + 93 + desc.type = CORESIGHT_DEV_TYPE_SINK; 94 + desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_DUMMY; 95 + desc.ops = &dummy_sink_cs_ops; 96 + } else { 97 + dev_err(dev, "Device type not set\n"); 98 + return -EINVAL; 99 + } 100 + 101 + pdata = coresight_get_platform_data(dev); 102 + if (IS_ERR(pdata)) 103 + return PTR_ERR(pdata); 104 + pdev->dev.platform_data = pdata; 105 + 106 + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); 107 + if (!drvdata) 108 + return -ENOMEM; 109 + 110 + drvdata->dev = &pdev->dev; 111 + platform_set_drvdata(pdev, drvdata); 112 + 113 + desc.pdata = pdev->dev.platform_data; 114 + desc.dev = &pdev->dev; 115 + drvdata->csdev = coresight_register(&desc); 116 + if (IS_ERR(drvdata->csdev)) 117 + return PTR_ERR(drvdata->csdev); 118 + 119 + pm_runtime_enable(dev); 120 + dev_dbg(dev, "Dummy device initialized\n"); 121 + 122 + return 0; 123 + } 124 + 125 + static int dummy_remove(struct platform_device *pdev) 126 + { 127 + struct dummy_drvdata *drvdata = platform_get_drvdata(pdev); 128 + struct device *dev = &pdev->dev; 129 + 130 + pm_runtime_disable(dev); 131 + coresight_unregister(drvdata->csdev); 132 + return 0; 133 + } 134 + 135 + static const struct of_device_id dummy_match[] = { 136 + {.compatible = "arm,coresight-dummy-source"}, 137 + {.compatible = "arm,coresight-dummy-sink"}, 138 + {}, 139 + }; 140 + 141 + static struct platform_driver dummy_driver = { 142 + .probe = dummy_probe, 143 + .remove = dummy_remove, 144 + .driver = { 145 + .name = "coresight-dummy", 146 + .of_match_table = dummy_match, 147 + }, 148 + }; 149 + 150 + static int __init dummy_init(void) 151 + { 152 + return platform_driver_register(&dummy_driver); 153 + } 154 + module_init(dummy_init); 155 + 156 + static void __exit dummy_exit(void) 157 + { 158 + platform_driver_unregister(&dummy_driver); 159 + } 160 + module_exit(dummy_exit); 161 + 162 + MODULE_LICENSE("GPL"); 163 + MODULE_DESCRIPTION("CoreSight dummy driver");
+7 -6
drivers/hwtracing/coresight/coresight-etb10.c
··· 163 163 drvdata->mode = CS_MODE_SYSFS; 164 164 } 165 165 166 - atomic_inc(csdev->refcnt); 166 + atomic_inc(&csdev->refcnt); 167 167 out: 168 168 spin_unlock_irqrestore(&drvdata->spinlock, flags); 169 169 return ret; ··· 199 199 * use for this session. 200 200 */ 201 201 if (drvdata->pid == pid) { 202 - atomic_inc(csdev->refcnt); 202 + atomic_inc(&csdev->refcnt); 203 203 goto out; 204 204 } 205 205 ··· 217 217 /* Associate with monitored process. */ 218 218 drvdata->pid = pid; 219 219 drvdata->mode = CS_MODE_PERF; 220 - atomic_inc(csdev->refcnt); 220 + atomic_inc(&csdev->refcnt); 221 221 } 222 222 223 223 out: ··· 225 225 return ret; 226 226 } 227 227 228 - static int etb_enable(struct coresight_device *csdev, u32 mode, void *data) 228 + static int etb_enable(struct coresight_device *csdev, enum cs_mode mode, 229 + void *data) 229 230 { 230 231 int ret; 231 232 ··· 356 355 357 356 spin_lock_irqsave(&drvdata->spinlock, flags); 358 357 359 - if (atomic_dec_return(csdev->refcnt)) { 358 + if (atomic_dec_return(&csdev->refcnt)) { 360 359 spin_unlock_irqrestore(&drvdata->spinlock, flags); 361 360 return -EBUSY; 362 361 } ··· 447 446 spin_lock_irqsave(&drvdata->spinlock, flags); 448 447 449 448 /* Don't do anything if another tracer is using this sink */ 450 - if (atomic_read(csdev->refcnt) != 1) 449 + if (atomic_read(&csdev->refcnt) != 1) 451 450 goto out; 452 451 453 452 __etb_disable_hw(drvdata);
+2 -2
drivers/hwtracing/coresight/coresight-etm-perf.c
··· 493 493 goto fail_end_stop; 494 494 495 495 /* Finally enable the tracer */ 496 - if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF)) 496 + if (coresight_enable_source(csdev, CS_MODE_PERF, event)) 497 497 goto fail_disable_path; 498 498 499 499 /* ··· 587 587 return; 588 588 589 589 /* stop tracer */ 590 - source_ops(csdev)->disable(csdev, event); 590 + coresight_disable_source(csdev, event); 591 591 592 592 /* tell the core */ 593 593 event->hw.state = PERF_HES_STOPPED;
+3 -3
drivers/hwtracing/coresight/coresight-etm3x-core.c
··· 552 552 return ret; 553 553 } 554 554 555 - static int etm_enable(struct coresight_device *csdev, 556 - struct perf_event *event, u32 mode) 555 + static int etm_enable(struct coresight_device *csdev, struct perf_event *event, 556 + enum cs_mode mode) 557 557 { 558 558 int ret; 559 559 u32 val; ··· 671 671 static void etm_disable(struct coresight_device *csdev, 672 672 struct perf_event *event) 673 673 { 674 - u32 mode; 674 + enum cs_mode mode; 675 675 struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 676 676 677 677 /*
+11 -9
drivers/hwtracing/coresight/coresight-etm4x-core.c
··· 822 822 return ret; 823 823 } 824 824 825 - static int etm4_enable(struct coresight_device *csdev, 826 - struct perf_event *event, u32 mode) 825 + static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, 826 + enum cs_mode mode) 827 827 { 828 828 int ret; 829 829 u32 val; ··· 989 989 static void etm4_disable(struct coresight_device *csdev, 990 990 struct perf_event *event) 991 991 { 992 - u32 mode; 992 + enum cs_mode mode; 993 993 struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 994 994 995 995 /* ··· 2190 2190 per_cpu(delayed_probe, cpu) = NULL; 2191 2191 } 2192 2192 2193 - static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata) 2193 + static void __exit etm4_remove_dev(struct etmv4_drvdata *drvdata) 2194 2194 { 2195 2195 bool had_delayed_probe; 2196 2196 /* ··· 2217 2217 cscfg_unregister_csdev(drvdata->csdev); 2218 2218 coresight_unregister(drvdata->csdev); 2219 2219 } 2220 - 2221 - return 0; 2222 2220 } 2223 2221 2224 2222 static void __exit etm4_remove_amba(struct amba_device *adev) ··· 2229 2231 2230 2232 static int __exit etm4_remove_platform_dev(struct platform_device *pdev) 2231 2233 { 2232 - int ret = 0; 2233 2234 struct etmv4_drvdata *drvdata = dev_get_drvdata(&pdev->dev); 2234 2235 2235 2236 if (drvdata) 2236 - ret = etm4_remove_dev(drvdata); 2237 + etm4_remove_dev(drvdata); 2237 2238 pm_runtime_disable(&pdev->dev); 2238 - return ret; 2239 + return 0; 2239 2240 } 2240 2241 2241 2242 static const struct amba_id etm4_ids[] = { ··· 2257 2260 CS_AMBA_UCI_ID(0x000cc0af, uci_id_etm4),/* Marvell ThunderX2 */ 2258 2261 CS_AMBA_UCI_ID(0x000b6d01, uci_id_etm4),/* HiSilicon-Hip08 */ 2259 2262 CS_AMBA_UCI_ID(0x000b6d02, uci_id_etm4),/* HiSilicon-Hip09 */ 2263 + /* 2264 + * Match all PIDs with ETM4 DEVARCH. No need for adding any of the new 2265 + * CPUs to the list here. 2266 + */ 2267 + CS_AMBA_MATCH_ALL_UCI(uci_id_etm4), 2260 2268 {}, 2261 2269 }; 2262 2270
+18 -9
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
··· 2411 2411 2412 2412 return sysfs_emit(buf, "0x%x\n", trace_id); 2413 2413 } 2414 - static DEVICE_ATTR_RO(trctraceid); 2415 2414 2416 2415 struct etmv4_reg { 2417 2416 struct coresight_device *csdev; ··· 2527 2528 return 0; 2528 2529 } 2529 2530 2530 - #define coresight_etm4x_reg(name, offset) \ 2531 - &((struct dev_ext_attribute[]) { \ 2532 - { \ 2533 - __ATTR(name, 0444, coresight_etm4x_reg_show, NULL), \ 2534 - (void *)(unsigned long)offset \ 2535 - } \ 2536 - })[0].attr.attr 2531 + /* 2532 + * Macro to set an RO ext attribute with offset and show function. 2533 + * Offset is used in mgmt group to ensure only correct registers for 2534 + * the ETM / ETE variant are visible. 2535 + */ 2536 + #define coresight_etm4x_reg_showfn(name, offset, showfn) ( \ 2537 + &((struct dev_ext_attribute[]) { \ 2538 + { \ 2539 + __ATTR(name, 0444, showfn, NULL), \ 2540 + (void *)(unsigned long)offset \ 2541 + } \ 2542 + })[0].attr.attr \ 2543 + ) 2544 + 2545 + /* macro using the default coresight_etm4x_reg_show function */ 2546 + #define coresight_etm4x_reg(name, offset) \ 2547 + coresight_etm4x_reg_showfn(name, offset, coresight_etm4x_reg_show) 2537 2548 2538 2549 static struct attribute *coresight_etmv4_mgmt_attrs[] = { 2539 2550 coresight_etm4x_reg(trcpdcr, TRCPDCR), ··· 2558 2549 coresight_etm4x_reg(trcpidr3, TRCPIDR3), 2559 2550 coresight_etm4x_reg(trcoslsr, TRCOSLSR), 2560 2551 coresight_etm4x_reg(trcconfig, TRCCONFIGR), 2561 - &dev_attr_trctraceid.attr, 2552 + coresight_etm4x_reg_showfn(trctraceid, TRCTRACEIDR, trctraceid_show), 2562 2553 coresight_etm4x_reg(trcdevarch, TRCDEVARCH), 2563 2554 NULL, 2564 2555 };
+15 -11
drivers/hwtracing/coresight/coresight-funnel.c
··· 74 74 return rc; 75 75 } 76 76 77 - static int funnel_enable(struct coresight_device *csdev, int inport, 78 - int outport) 77 + static int funnel_enable(struct coresight_device *csdev, 78 + struct coresight_connection *in, 79 + struct coresight_connection *out) 79 80 { 80 81 int rc = 0; 81 82 struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); ··· 84 83 bool first_enable = false; 85 84 86 85 spin_lock_irqsave(&drvdata->spinlock, flags); 87 - if (atomic_read(&csdev->refcnt[inport]) == 0) { 86 + if (atomic_read(&in->dest_refcnt) == 0) { 88 87 if (drvdata->base) 89 - rc = dynamic_funnel_enable_hw(drvdata, inport); 88 + rc = dynamic_funnel_enable_hw(drvdata, in->dest_port); 90 89 if (!rc) 91 90 first_enable = true; 92 91 } 93 92 if (!rc) 94 - atomic_inc(&csdev->refcnt[inport]); 93 + atomic_inc(&in->dest_refcnt); 95 94 spin_unlock_irqrestore(&drvdata->spinlock, flags); 96 95 97 96 if (first_enable) 98 - dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", inport); 97 + dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", 98 + in->dest_port); 99 99 return rc; 100 100 } 101 101 ··· 119 117 CS_LOCK(drvdata->base); 120 118 } 121 119 122 - static void funnel_disable(struct coresight_device *csdev, int inport, 123 - int outport) 120 + static void funnel_disable(struct coresight_device *csdev, 121 + struct coresight_connection *in, 122 + struct coresight_connection *out) 124 123 { 125 124 struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 126 125 unsigned long flags; 127 126 bool last_disable = false; 128 127 129 128 spin_lock_irqsave(&drvdata->spinlock, flags); 130 - if (atomic_dec_return(&csdev->refcnt[inport]) == 0) { 129 + if (atomic_dec_return(&in->dest_refcnt) == 0) { 131 130 if (drvdata->base) 132 - dynamic_funnel_disable_hw(drvdata, inport); 131 + dynamic_funnel_disable_hw(drvdata, in->dest_port); 133 132 last_disable = true; 134 133 } 135 134 spin_unlock_irqrestore(&drvdata->spinlock, flags); 136 135 137 136 if (last_disable) 138 - dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", inport); 137 + dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", 138 + in->dest_port); 139 139 } 140 140 141 141 static const struct coresight_ops_link funnel_link_ops = {
+106 -163
drivers/hwtracing/coresight/coresight-platform.c
··· 19 19 #include <asm/smp_plat.h> 20 20 21 21 #include "coresight-priv.h" 22 + 22 23 /* 23 - * coresight_alloc_conns: Allocate connections record for each output 24 - * port from the device. 24 + * Add an entry to the connection list and assign @conn's contents to it. 25 + * 26 + * If the output port is already assigned on this device, return -EINVAL 25 27 */ 26 - static int coresight_alloc_conns(struct device *dev, 27 - struct coresight_platform_data *pdata) 28 + struct coresight_connection * 29 + coresight_add_out_conn(struct device *dev, 30 + struct coresight_platform_data *pdata, 31 + const struct coresight_connection *new_conn) 28 32 { 29 - if (pdata->nr_outport) { 30 - pdata->conns = devm_kcalloc(dev, pdata->nr_outport, 31 - sizeof(*pdata->conns), GFP_KERNEL); 32 - if (!pdata->conns) 33 - return -ENOMEM; 33 + int i; 34 + struct coresight_connection *conn; 35 + 36 + /* 37 + * Warn on any existing duplicate output port. 38 + */ 39 + for (i = 0; i < pdata->nr_outconns; ++i) { 40 + conn = pdata->out_conns[i]; 41 + /* Output == -1 means ignore the port for example for helpers */ 42 + if (conn->src_port != -1 && 43 + conn->src_port == new_conn->src_port) { 44 + dev_warn(dev, "Duplicate output port %d\n", 45 + conn->src_port); 46 + return ERR_PTR(-EINVAL); 47 + } 34 48 } 35 49 50 + pdata->nr_outconns++; 51 + pdata->out_conns = 52 + devm_krealloc_array(dev, pdata->out_conns, pdata->nr_outconns, 53 + sizeof(*pdata->out_conns), GFP_KERNEL); 54 + if (!pdata->out_conns) 55 + return ERR_PTR(-ENOMEM); 56 + 57 + conn = devm_kmalloc(dev, sizeof(struct coresight_connection), 58 + GFP_KERNEL); 59 + if (!conn) 60 + return ERR_PTR(-ENOMEM); 61 + 62 + /* 63 + * Copy the new connection into the allocation, save the pointer to the 64 + * end of the connection array and also return it in case it needs to be 65 + * used right away. 66 + */ 67 + *conn = *new_conn; 68 + pdata->out_conns[pdata->nr_outconns - 1] = conn; 69 + return conn; 70 + } 71 + EXPORT_SYMBOL_GPL(coresight_add_out_conn); 72 + 73 + /* 74 + * Add an input connection reference to @out_conn in the target's in_conns array 75 + * 76 + * @out_conn: Existing output connection to store as an input on the 77 + * connection's remote device. 78 + */ 79 + int coresight_add_in_conn(struct coresight_connection *out_conn) 80 + { 81 + int i; 82 + struct device *dev = out_conn->dest_dev->dev.parent; 83 + struct coresight_platform_data *pdata = out_conn->dest_dev->pdata; 84 + 85 + for (i = 0; i < pdata->nr_inconns; ++i) 86 + if (!pdata->in_conns[i]) { 87 + pdata->in_conns[i] = out_conn; 88 + return 0; 89 + } 90 + 91 + pdata->nr_inconns++; 92 + pdata->in_conns = 93 + devm_krealloc_array(dev, pdata->in_conns, pdata->nr_inconns, 94 + sizeof(*pdata->in_conns), GFP_KERNEL); 95 + if (!pdata->in_conns) 96 + return -ENOMEM; 97 + pdata->in_conns[pdata->nr_inconns - 1] = out_conn; 36 98 return 0; 37 99 } 100 + EXPORT_SYMBOL_GPL(coresight_add_in_conn); 38 101 39 102 static struct device * 40 103 coresight_find_device_by_fwnode(struct fwnode_handle *fwnode) ··· 146 83 return of_property_read_bool(ep, "slave-mode"); 147 84 } 148 85 149 - static void of_coresight_get_ports_legacy(const struct device_node *node, 150 - int *nr_inport, int *nr_outport) 151 - { 152 - struct device_node *ep = NULL; 153 - struct of_endpoint endpoint; 154 - int in = 0, out = 0; 155 - 156 - /* 157 - * Avoid warnings in of_graph_get_next_endpoint() 158 - * if the device doesn't have any graph connections 159 - */ 160 - if (!of_graph_is_present(node)) 161 - return; 162 - do { 163 - ep = of_graph_get_next_endpoint(node, ep); 164 - if (!ep) 165 - break; 166 - 167 - if (of_graph_parse_endpoint(ep, &endpoint)) 168 - continue; 169 - 170 - if (of_coresight_legacy_ep_is_input(ep)) { 171 - in = (endpoint.port + 1 > in) ? 172 - endpoint.port + 1 : in; 173 - } else { 174 - out = (endpoint.port + 1) > out ? 175 - endpoint.port + 1 : out; 176 - } 177 - 178 - } while (ep); 179 - 180 - *nr_inport = in; 181 - *nr_outport = out; 182 - } 183 - 184 86 static struct device_node *of_coresight_get_port_parent(struct device_node *ep) 185 87 { 186 88 struct device_node *parent = of_graph_get_port_parent(ep); ··· 162 134 } 163 135 164 136 static inline struct device_node * 165 - of_coresight_get_input_ports_node(const struct device_node *node) 166 - { 167 - return of_get_child_by_name(node, "in-ports"); 168 - } 169 - 170 - static inline struct device_node * 171 137 of_coresight_get_output_ports_node(const struct device_node *node) 172 138 { 173 139 return of_get_child_by_name(node, "out-ports"); 174 - } 175 - 176 - static inline int 177 - of_coresight_count_ports(struct device_node *port_parent) 178 - { 179 - int i = 0; 180 - struct device_node *ep = NULL; 181 - struct of_endpoint endpoint; 182 - 183 - while ((ep = of_graph_get_next_endpoint(port_parent, ep))) { 184 - /* Defer error handling to parsing */ 185 - if (of_graph_parse_endpoint(ep, &endpoint)) 186 - continue; 187 - if (endpoint.port + 1 > i) 188 - i = endpoint.port + 1; 189 - } 190 - 191 - return i; 192 - } 193 - 194 - static void of_coresight_get_ports(const struct device_node *node, 195 - int *nr_inport, int *nr_outport) 196 - { 197 - struct device_node *input_ports = NULL, *output_ports = NULL; 198 - 199 - input_ports = of_coresight_get_input_ports_node(node); 200 - output_ports = of_coresight_get_output_ports_node(node); 201 - 202 - if (input_ports || output_ports) { 203 - if (input_ports) { 204 - *nr_inport = of_coresight_count_ports(input_ports); 205 - of_node_put(input_ports); 206 - } 207 - if (output_ports) { 208 - *nr_outport = of_coresight_count_ports(output_ports); 209 - of_node_put(output_ports); 210 - } 211 - } else { 212 - /* Fall back to legacy DT bindings parsing */ 213 - of_coresight_get_ports_legacy(node, nr_inport, nr_outport); 214 - } 215 140 } 216 141 217 142 static int of_coresight_get_cpu(struct device *dev) ··· 187 206 188 207 /* 189 208 * of_coresight_parse_endpoint : Parse the given output endpoint @ep 190 - * and fill the connection information in @conn 209 + * and fill the connection information in @pdata->out_conns 191 210 * 192 211 * Parses the local port, remote device name and the remote port. 193 212 * ··· 205 224 struct device_node *rep = NULL; 206 225 struct device *rdev = NULL; 207 226 struct fwnode_handle *rdev_fwnode; 208 - struct coresight_connection *conn; 227 + struct coresight_connection conn = {}; 228 + struct coresight_connection *new_conn; 209 229 210 230 do { 211 231 /* Parse the local port details */ ··· 233 251 break; 234 252 } 235 253 236 - conn = &pdata->conns[endpoint.port]; 237 - if (conn->child_fwnode) { 238 - dev_warn(dev, "Duplicate output port %d\n", 239 - endpoint.port); 240 - ret = -EINVAL; 241 - break; 242 - } 243 - conn->outport = endpoint.port; 254 + conn.src_port = endpoint.port; 244 255 /* 245 256 * Hold the refcount to the target device. This could be 246 257 * released via: ··· 242 267 * 2) While removing the target device via 243 268 * coresight_remove_match() 244 269 */ 245 - conn->child_fwnode = fwnode_handle_get(rdev_fwnode); 246 - conn->child_port = rendpoint.port; 270 + conn.dest_fwnode = fwnode_handle_get(rdev_fwnode); 271 + conn.dest_port = rendpoint.port; 272 + 273 + new_conn = coresight_add_out_conn(dev, pdata, &conn); 274 + if (IS_ERR_VALUE(new_conn)) { 275 + fwnode_handle_put(conn.dest_fwnode); 276 + return PTR_ERR(new_conn); 277 + } 247 278 /* Connection record updated */ 248 279 } while (0); 249 280 ··· 269 288 bool legacy_binding = false; 270 289 struct device_node *node = dev->of_node; 271 290 272 - /* Get the number of input and output port for this component */ 273 - of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport); 274 - 275 - /* If there are no output connections, we are done */ 276 - if (!pdata->nr_outport) 277 - return 0; 278 - 279 - ret = coresight_alloc_conns(dev, pdata); 280 - if (ret) 281 - return ret; 282 - 283 291 parent = of_coresight_get_output_ports_node(node); 284 292 /* 285 293 * If the DT uses obsoleted bindings, the ports are listed ··· 276 306 * ports. 277 307 */ 278 308 if (!parent) { 309 + /* 310 + * Avoid warnings in of_graph_get_next_endpoint() 311 + * if the device doesn't have any graph connections 312 + */ 313 + if (!of_graph_is_present(node)) 314 + return 0; 279 315 legacy_binding = true; 280 316 parent = node; 281 317 dev_warn_once(dev, "Uses obsolete Coresight DT bindings\n"); ··· 625 649 626 650 dir = fields[3].integer.value; 627 651 if (dir == ACPI_CORESIGHT_LINK_MASTER) { 628 - conn->outport = fields[0].integer.value; 629 - conn->child_port = fields[1].integer.value; 652 + conn->src_port = fields[0].integer.value; 653 + conn->dest_port = fields[1].integer.value; 630 654 rdev = coresight_find_device_by_fwnode(&r_adev->fwnode); 631 655 if (!rdev) 632 656 return -EPROBE_DEFER; ··· 638 662 * 2) While removing the target device via 639 663 * coresight_remove_match(). 640 664 */ 641 - conn->child_fwnode = fwnode_handle_get(&r_adev->fwnode); 665 + conn->dest_fwnode = fwnode_handle_get(&r_adev->fwnode); 642 666 } else if (dir == ACPI_CORESIGHT_LINK_SLAVE) { 643 667 /* 644 668 * We are only interested in the port number 645 669 * for the input ports at this component. 646 670 * Store the port number in child_port. 647 671 */ 648 - conn->child_port = fields[0].integer.value; 672 + conn->dest_port = fields[0].integer.value; 649 673 } else { 650 674 /* Invalid direction */ 651 675 return -EINVAL; ··· 659 683 * connection information and populate the supplied coresight_platform_data 660 684 * instance. 661 685 */ 662 - static int acpi_coresight_parse_graph(struct acpi_device *adev, 686 + static int acpi_coresight_parse_graph(struct device *dev, 687 + struct acpi_device *adev, 663 688 struct coresight_platform_data *pdata) 664 689 { 665 - int rc, i, nlinks; 690 + int i, nlinks; 666 691 const union acpi_object *graph; 667 - struct coresight_connection *conns, *ptr; 692 + struct coresight_connection conn, zero_conn = {}; 693 + struct coresight_connection *new_conn; 668 694 669 - pdata->nr_inport = pdata->nr_outport = 0; 670 695 graph = acpi_get_coresight_graph(adev); 671 696 if (!graph) 672 697 return -ENOENT; ··· 676 699 if (!nlinks) 677 700 return 0; 678 701 679 - /* 680 - * To avoid scanning the table twice (once for finding the number of 681 - * output links and then later for parsing the output links), 682 - * cache the links information in one go and then later copy 683 - * it to the pdata. 684 - */ 685 - conns = devm_kcalloc(&adev->dev, nlinks, sizeof(*conns), GFP_KERNEL); 686 - if (!conns) 687 - return -ENOMEM; 688 - ptr = conns; 689 702 for (i = 0; i < nlinks; i++) { 690 703 const union acpi_object *link = &graph->package.elements[3 + i]; 691 704 int dir; 692 705 693 - dir = acpi_coresight_parse_link(adev, link, ptr); 706 + conn = zero_conn; 707 + dir = acpi_coresight_parse_link(adev, link, &conn); 694 708 if (dir < 0) 695 709 return dir; 696 710 697 711 if (dir == ACPI_CORESIGHT_LINK_MASTER) { 698 - if (ptr->outport >= pdata->nr_outport) 699 - pdata->nr_outport = ptr->outport + 1; 700 - ptr++; 701 - } else { 702 - WARN_ON(pdata->nr_inport == ptr->child_port + 1); 703 - /* 704 - * We do not track input port connections for a device. 705 - * However we need the highest port number described, 706 - * which can be recorded now and reuse this connection 707 - * record for an output connection. Hence, do not move 708 - * the ptr for input connections 709 - */ 710 - if (ptr->child_port >= pdata->nr_inport) 711 - pdata->nr_inport = ptr->child_port + 1; 712 + new_conn = coresight_add_out_conn(dev, pdata, &conn); 713 + if (IS_ERR(new_conn)) 714 + return PTR_ERR(new_conn); 712 715 } 713 716 } 714 717 715 - rc = coresight_alloc_conns(&adev->dev, pdata); 716 - if (rc) 717 - return rc; 718 - 719 - /* Copy the connection information to the final location */ 720 - for (i = 0; conns + i < ptr; i++) { 721 - int port = conns[i].outport; 722 - 723 - /* Duplicate output port */ 724 - WARN_ON(pdata->conns[port].child_fwnode); 725 - pdata->conns[port] = conns[i]; 726 - } 727 - 728 - devm_kfree(&adev->dev, conns); 729 718 return 0; 730 719 } 731 720 ··· 752 809 if (!adev) 753 810 return -EINVAL; 754 811 755 - return acpi_coresight_parse_graph(adev, pdata); 812 + return acpi_coresight_parse_graph(dev, adev, pdata); 756 813 } 757 814 758 815 #else ··· 806 863 error: 807 864 if (!IS_ERR_OR_NULL(pdata)) 808 865 /* Cleanup the connection information */ 809 - coresight_release_platform_data(NULL, pdata); 866 + coresight_release_platform_data(NULL, dev, pdata); 810 867 return ERR_PTR(ret); 811 868 } 812 869 EXPORT_SYMBOL_GPL(coresight_get_platform_data);
+25 -11
drivers/hwtracing/coresight/coresight-priv.h
··· 82 82 ETM_ADDR_TYPE_STOP, 83 83 }; 84 84 85 - enum cs_mode { 86 - CS_MODE_DISABLED, 87 - CS_MODE_SYSFS, 88 - CS_MODE_PERF, 89 - }; 90 - 91 85 /** 92 86 * struct cs_buffer - keep track of a recording session' specifics 93 87 * @cur: index of the current buffer ··· 127 133 } 128 134 129 135 void coresight_disable_path(struct list_head *path); 130 - int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data); 136 + int coresight_enable_path(struct list_head *path, enum cs_mode mode, 137 + void *sink_data); 131 138 struct coresight_device *coresight_get_sink(struct list_head *path); 132 139 struct coresight_device * 133 140 coresight_get_enabled_sink(struct coresight_device *source); ··· 188 193 } 189 194 190 195 /* coresight AMBA ID, full UCI structure: id table entry. */ 191 - #define CS_AMBA_UCI_ID(pid, uci_ptr) \ 196 + #define __CS_AMBA_UCI_ID(pid, m, uci_ptr) \ 192 197 { \ 193 198 .id = pid, \ 194 - .mask = 0x000fffff, \ 199 + .mask = m, \ 195 200 .data = (void *)uci_ptr \ 196 201 } 202 + #define CS_AMBA_UCI_ID(pid, uci) __CS_AMBA_UCI_ID(pid, 0x000fffff, uci) 203 + /* 204 + * PIDR2[JEDEC], BIT(3) must be 1 (Read As One) to indicate that rest of the 205 + * PIDR1, PIDR2 DES_* fields follow JEDEC encoding for the designer. Use that 206 + * as a match value for blanket matching all devices in the given CoreSight 207 + * device type and architecture. 208 + */ 209 + #define PIDR2_JEDEC BIT(3) 210 + #define PID_PIDR2_JEDEC (PIDR2_JEDEC << 16) 211 + /* 212 + * Match all PIDs in a given CoreSight device type and architecture, defined 213 + * by the uci. 214 + */ 215 + #define CS_AMBA_MATCH_ALL_UCI(uci) \ 216 + __CS_AMBA_UCI_ID(PID_PIDR2_JEDEC, PID_PIDR2_JEDEC, uci) 197 217 198 218 /* extract the data value from a UCI structure given amba_id pointer. */ 199 219 static inline void *coresight_get_uci_data(const struct amba_id *id) ··· 222 212 } 223 213 224 214 void coresight_release_platform_data(struct coresight_device *csdev, 215 + struct device *dev, 225 216 struct coresight_platform_data *pdata); 226 217 struct coresight_device * 227 218 coresight_find_csdev_by_fwnode(struct fwnode_handle *r_fwnode); 228 - void coresight_set_assoc_ectdev_mutex(struct coresight_device *csdev, 229 - struct coresight_device *ect_csdev); 219 + void coresight_add_helper(struct coresight_device *csdev, 220 + struct coresight_device *helper); 230 221 231 222 void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev); 232 223 struct coresight_device *coresight_get_percpu_sink(int cpu); 224 + int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, 225 + void *data); 226 + bool coresight_disable_source(struct coresight_device *csdev, void *data); 233 227 234 228 #endif
+13 -10
drivers/hwtracing/coresight/coresight-replicator.c
··· 114 114 return rc; 115 115 } 116 116 117 - static int replicator_enable(struct coresight_device *csdev, int inport, 118 - int outport) 117 + static int replicator_enable(struct coresight_device *csdev, 118 + struct coresight_connection *in, 119 + struct coresight_connection *out) 119 120 { 120 121 int rc = 0; 121 122 struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); ··· 124 123 bool first_enable = false; 125 124 126 125 spin_lock_irqsave(&drvdata->spinlock, flags); 127 - if (atomic_read(&csdev->refcnt[outport]) == 0) { 126 + if (atomic_read(&out->src_refcnt) == 0) { 128 127 if (drvdata->base) 129 - rc = dynamic_replicator_enable(drvdata, inport, 130 - outport); 128 + rc = dynamic_replicator_enable(drvdata, in->dest_port, 129 + out->src_port); 131 130 if (!rc) 132 131 first_enable = true; 133 132 } 134 133 if (!rc) 135 - atomic_inc(&csdev->refcnt[outport]); 134 + atomic_inc(&out->src_refcnt); 136 135 spin_unlock_irqrestore(&drvdata->spinlock, flags); 137 136 138 137 if (first_enable) ··· 169 168 CS_LOCK(drvdata->base); 170 169 } 171 170 172 - static void replicator_disable(struct coresight_device *csdev, int inport, 173 - int outport) 171 + static void replicator_disable(struct coresight_device *csdev, 172 + struct coresight_connection *in, 173 + struct coresight_connection *out) 174 174 { 175 175 struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 176 176 unsigned long flags; 177 177 bool last_disable = false; 178 178 179 179 spin_lock_irqsave(&drvdata->spinlock, flags); 180 - if (atomic_dec_return(&csdev->refcnt[outport]) == 0) { 180 + if (atomic_dec_return(&out->src_refcnt) == 0) { 181 181 if (drvdata->base) 182 - dynamic_replicator_disable(drvdata, inport, outport); 182 + dynamic_replicator_disable(drvdata, in->dest_port, 183 + out->src_port); 183 184 last_disable = true; 184 185 } 185 186 spin_unlock_irqrestore(&drvdata->spinlock, flags);
+3 -3
drivers/hwtracing/coresight/coresight-stm.c
··· 119 119 * @spinlock: only one at a time pls. 120 120 * @chs: the channels accociated to this STM. 121 121 * @stm: structure associated to the generic STM interface. 122 - * @mode: this tracer's mode, i.e sysFS, or disabled. 122 + * @mode: this tracer's mode (enum cs_mode), i.e sysFS, or disabled. 123 123 * @traceid: value of the current ID for this component. 124 124 * @write_bytes: Maximus bytes this STM can write at a time. 125 125 * @stmsper: settings for register STMSPER. ··· 192 192 CS_LOCK(drvdata->base); 193 193 } 194 194 195 - static int stm_enable(struct coresight_device *csdev, 196 - struct perf_event *event, u32 mode) 195 + static int stm_enable(struct coresight_device *csdev, struct perf_event *event, 196 + enum cs_mode mode) 197 197 { 198 198 u32 val; 199 199 struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+7 -10
drivers/hwtracing/coresight/coresight-sysfs.c
··· 148 148 char *outs = NULL, *ins = NULL; 149 149 struct coresight_sysfs_link *link = NULL; 150 150 151 + /* Helper devices aren't shown in sysfs */ 152 + if (conn->dest_port == -1 && conn->src_port == -1) 153 + return 0; 154 + 151 155 do { 152 156 outs = devm_kasprintf(&orig->dev, GFP_KERNEL, 153 - "out:%d", conn->outport); 157 + "out:%d", conn->src_port); 154 158 if (!outs) 155 159 break; 156 160 ins = devm_kasprintf(&target->dev, GFP_KERNEL, 157 - "in:%d", conn->child_port); 161 + "in:%d", conn->dest_port); 158 162 if (!ins) 159 163 break; 160 164 link = devm_kzalloc(&orig->dev, ··· 177 173 break; 178 174 179 175 conn->link = link; 180 - 181 - /* 182 - * Install the device connection. This also indicates that 183 - * the links are operational on both ends. 184 - */ 185 - conn->child_dev = target; 186 176 return 0; 187 177 } while (0); 188 178 ··· 196 198 197 199 coresight_remove_sysfs_link(conn->link); 198 200 199 - devm_kfree(&conn->child_dev->dev, conn->link->target_name); 201 + devm_kfree(&conn->dest_dev->dev, conn->link->target_name); 200 202 devm_kfree(&orig->dev, conn->link->orig_name); 201 203 devm_kfree(&orig->dev, conn->link); 202 204 conn->link = NULL; 203 - conn->child_dev = NULL; 204 205 }
+14 -12
drivers/hwtracing/coresight/coresight-tmc-etf.c
··· 206 206 * touched. 207 207 */ 208 208 if (drvdata->mode == CS_MODE_SYSFS) { 209 - atomic_inc(csdev->refcnt); 209 + atomic_inc(&csdev->refcnt); 210 210 goto out; 211 211 } 212 212 ··· 229 229 ret = tmc_etb_enable_hw(drvdata); 230 230 if (!ret) { 231 231 drvdata->mode = CS_MODE_SYSFS; 232 - atomic_inc(csdev->refcnt); 232 + atomic_inc(&csdev->refcnt); 233 233 } else { 234 234 /* Free up the buffer if we failed to enable */ 235 235 used = false; ··· 284 284 * use for this session. 285 285 */ 286 286 if (drvdata->pid == pid) { 287 - atomic_inc(csdev->refcnt); 287 + atomic_inc(&csdev->refcnt); 288 288 break; 289 289 } 290 290 ··· 293 293 /* Associate with monitored process. */ 294 294 drvdata->pid = pid; 295 295 drvdata->mode = CS_MODE_PERF; 296 - atomic_inc(csdev->refcnt); 296 + atomic_inc(&csdev->refcnt); 297 297 } 298 298 } while (0); 299 299 spin_unlock_irqrestore(&drvdata->spinlock, flags); ··· 302 302 } 303 303 304 304 static int tmc_enable_etf_sink(struct coresight_device *csdev, 305 - u32 mode, void *data) 305 + enum cs_mode mode, void *data) 306 306 { 307 307 int ret; 308 308 ··· 338 338 return -EBUSY; 339 339 } 340 340 341 - if (atomic_dec_return(csdev->refcnt)) { 341 + if (atomic_dec_return(&csdev->refcnt)) { 342 342 spin_unlock_irqrestore(&drvdata->spinlock, flags); 343 343 return -EBUSY; 344 344 } ··· 357 357 } 358 358 359 359 static int tmc_enable_etf_link(struct coresight_device *csdev, 360 - int inport, int outport) 360 + struct coresight_connection *in, 361 + struct coresight_connection *out) 361 362 { 362 363 int ret = 0; 363 364 unsigned long flags; ··· 371 370 return -EBUSY; 372 371 } 373 372 374 - if (atomic_read(&csdev->refcnt[0]) == 0) { 373 + if (atomic_read(&csdev->refcnt) == 0) { 375 374 ret = tmc_etf_enable_hw(drvdata); 376 375 if (!ret) { 377 376 drvdata->mode = CS_MODE_SYSFS; ··· 379 378 } 380 379 } 381 380 if (!ret) 382 - atomic_inc(&csdev->refcnt[0]); 381 + atomic_inc(&csdev->refcnt); 383 382 spin_unlock_irqrestore(&drvdata->spinlock, flags); 384 383 385 384 if (first_enable) ··· 388 387 } 389 388 390 389 static void tmc_disable_etf_link(struct coresight_device *csdev, 391 - int inport, int outport) 390 + struct coresight_connection *in, 391 + struct coresight_connection *out) 392 392 { 393 393 unsigned long flags; 394 394 struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); ··· 401 399 return; 402 400 } 403 401 404 - if (atomic_dec_return(&csdev->refcnt[0]) == 0) { 402 + if (atomic_dec_return(&csdev->refcnt) == 0) { 405 403 tmc_etf_disable_hw(drvdata); 406 404 drvdata->mode = CS_MODE_DISABLED; 407 405 last_disable = true; ··· 489 487 spin_lock_irqsave(&drvdata->spinlock, flags); 490 488 491 489 /* Don't do anything if another tracer is using this sink */ 492 - if (atomic_read(csdev->refcnt) != 1) 490 + if (atomic_read(&csdev->refcnt) != 1) 493 491 goto out; 494 492 495 493 CS_UNLOCK(drvdata->base);
+57 -53
drivers/hwtracing/coresight/coresight-tmc-etr.c
··· 775 775 struct coresight_device * 776 776 tmc_etr_get_catu_device(struct tmc_drvdata *drvdata) 777 777 { 778 - int i; 779 - struct coresight_device *tmp, *etr = drvdata->csdev; 778 + struct coresight_device *etr = drvdata->csdev; 779 + union coresight_dev_subtype catu_subtype = { 780 + .helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CATU 781 + }; 780 782 781 783 if (!IS_ENABLED(CONFIG_CORESIGHT_CATU)) 782 784 return NULL; 783 785 784 - for (i = 0; i < etr->pdata->nr_outport; i++) { 785 - tmp = etr->pdata->conns[i].child_dev; 786 - if (tmp && coresight_is_catu_device(tmp)) 787 - return tmp; 788 - } 789 - 790 - return NULL; 786 + return coresight_find_output_type(etr->pdata, CORESIGHT_DEV_TYPE_HELPER, 787 + catu_subtype); 791 788 } 792 789 EXPORT_SYMBOL_GPL(tmc_etr_get_catu_device); 793 - 794 - static inline int tmc_etr_enable_catu(struct tmc_drvdata *drvdata, 795 - struct etr_buf *etr_buf) 796 - { 797 - struct coresight_device *catu = tmc_etr_get_catu_device(drvdata); 798 - 799 - if (catu && helper_ops(catu)->enable) 800 - return helper_ops(catu)->enable(catu, etr_buf); 801 - return 0; 802 - } 803 - 804 - static inline void tmc_etr_disable_catu(struct tmc_drvdata *drvdata) 805 - { 806 - struct coresight_device *catu = tmc_etr_get_catu_device(drvdata); 807 - 808 - if (catu && helper_ops(catu)->disable) 809 - helper_ops(catu)->disable(catu, drvdata->etr_buf); 810 - } 811 790 812 791 static const struct etr_buf_operations *etr_buf_ops[] = { 813 792 [ETR_MODE_FLAT] = &etr_flat_buf_ops, ··· 1037 1058 if (WARN_ON(drvdata->etr_buf)) 1038 1059 return -EBUSY; 1039 1060 1040 - /* 1041 - * If this ETR is connected to a CATU, enable it before we turn 1042 - * this on. 1043 - */ 1044 - rc = tmc_etr_enable_catu(drvdata, etr_buf); 1045 - if (rc) 1046 - return rc; 1047 1061 rc = coresight_claim_device(drvdata->csdev); 1048 1062 if (!rc) { 1049 1063 drvdata->etr_buf = etr_buf; ··· 1044 1072 if (rc) { 1045 1073 drvdata->etr_buf = NULL; 1046 1074 coresight_disclaim_device(drvdata->csdev); 1047 - tmc_etr_disable_catu(drvdata); 1048 1075 } 1049 1076 } 1050 1077 ··· 1133 1162 void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) 1134 1163 { 1135 1164 __tmc_etr_disable_hw(drvdata); 1136 - /* Disable CATU device if this ETR is connected to one */ 1137 - tmc_etr_disable_catu(drvdata); 1138 1165 coresight_disclaim_device(drvdata->csdev); 1139 1166 /* Reset the ETR buf used by hardware */ 1140 1167 drvdata->etr_buf = NULL; 1141 1168 } 1142 1169 1143 - static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) 1170 + static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev) 1144 1171 { 1145 1172 int ret = 0; 1146 1173 unsigned long flags; ··· 1161 1192 /* Allocate memory with the locks released */ 1162 1193 free_buf = new_buf = tmc_etr_setup_sysfs_buf(drvdata); 1163 1194 if (IS_ERR(new_buf)) 1164 - return PTR_ERR(new_buf); 1195 + return new_buf; 1165 1196 1166 1197 /* Let's try again */ 1167 1198 spin_lock_irqsave(&drvdata->spinlock, flags); ··· 1178 1209 * touched, even if the buffer size has changed. 1179 1210 */ 1180 1211 if (drvdata->mode == CS_MODE_SYSFS) { 1181 - atomic_inc(csdev->refcnt); 1212 + atomic_inc(&csdev->refcnt); 1182 1213 goto out; 1183 1214 } 1184 1215 ··· 1192 1223 drvdata->sysfs_buf = new_buf; 1193 1224 } 1194 1225 1195 - ret = tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf); 1196 - if (!ret) { 1197 - drvdata->mode = CS_MODE_SYSFS; 1198 - atomic_inc(csdev->refcnt); 1199 - } 1200 1226 out: 1201 1227 spin_unlock_irqrestore(&drvdata->spinlock, flags); 1202 1228 1203 1229 /* Free memory outside the spinlock if need be */ 1204 1230 if (free_buf) 1205 1231 tmc_etr_free_sysfs_buf(free_buf); 1232 + return ret ? ERR_PTR(ret) : drvdata->sysfs_buf; 1233 + } 1234 + 1235 + static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) 1236 + { 1237 + int ret; 1238 + unsigned long flags; 1239 + struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 1240 + struct etr_buf *sysfs_buf = tmc_etr_get_sysfs_buffer(csdev); 1241 + 1242 + if (IS_ERR(sysfs_buf)) 1243 + return PTR_ERR(sysfs_buf); 1244 + 1245 + spin_lock_irqsave(&drvdata->spinlock, flags); 1246 + ret = tmc_etr_enable_hw(drvdata, sysfs_buf); 1247 + if (!ret) { 1248 + drvdata->mode = CS_MODE_SYSFS; 1249 + atomic_inc(&csdev->refcnt); 1250 + } 1251 + 1252 + spin_unlock_irqrestore(&drvdata->spinlock, flags); 1206 1253 1207 1254 if (!ret) 1208 1255 dev_dbg(&csdev->dev, "TMC-ETR enabled\n"); 1209 1256 1210 1257 return ret; 1211 1258 } 1259 + 1260 + struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev, 1261 + enum cs_mode mode, void *data) 1262 + { 1263 + struct perf_output_handle *handle = data; 1264 + struct etr_perf_buffer *etr_perf; 1265 + 1266 + switch (mode) { 1267 + case CS_MODE_SYSFS: 1268 + return tmc_etr_get_sysfs_buffer(csdev); 1269 + case CS_MODE_PERF: 1270 + etr_perf = etm_perf_sink_config(handle); 1271 + if (WARN_ON(!etr_perf || !etr_perf->etr_buf)) 1272 + return ERR_PTR(-EINVAL); 1273 + return etr_perf->etr_buf; 1274 + default: 1275 + return ERR_PTR(-EINVAL); 1276 + } 1277 + } 1278 + EXPORT_SYMBOL_GPL(tmc_etr_get_buffer); 1212 1279 1213 1280 /* 1214 1281 * alloc_etr_buf: Allocate ETR buffer for use by perf. ··· 1540 1535 spin_lock_irqsave(&drvdata->spinlock, flags); 1541 1536 1542 1537 /* Don't do anything if another tracer is using this sink */ 1543 - if (atomic_read(csdev->refcnt) != 1) { 1538 + if (atomic_read(&csdev->refcnt) != 1) { 1544 1539 spin_unlock_irqrestore(&drvdata->spinlock, flags); 1545 1540 goto out; 1546 1541 } ··· 1652 1647 * use for this session. 1653 1648 */ 1654 1649 if (drvdata->pid == pid) { 1655 - atomic_inc(csdev->refcnt); 1650 + atomic_inc(&csdev->refcnt); 1656 1651 goto unlock_out; 1657 1652 } 1658 1653 ··· 1662 1657 drvdata->pid = pid; 1663 1658 drvdata->mode = CS_MODE_PERF; 1664 1659 drvdata->perf_buf = etr_perf->etr_buf; 1665 - atomic_inc(csdev->refcnt); 1660 + atomic_inc(&csdev->refcnt); 1666 1661 } 1667 1662 1668 1663 unlock_out: ··· 1671 1666 } 1672 1667 1673 1668 static int tmc_enable_etr_sink(struct coresight_device *csdev, 1674 - u32 mode, void *data) 1669 + enum cs_mode mode, void *data) 1675 1670 { 1676 1671 switch (mode) { 1677 1672 case CS_MODE_SYSFS: 1678 1673 return tmc_enable_etr_sink_sysfs(csdev); 1679 1674 case CS_MODE_PERF: 1680 1675 return tmc_enable_etr_sink_perf(csdev, data); 1676 + default: 1677 + return -EINVAL; 1681 1678 } 1682 - 1683 - /* We shouldn't be here */ 1684 - return -EINVAL; 1685 1679 } 1686 1680 1687 1681 static int tmc_disable_etr_sink(struct coresight_device *csdev) ··· 1695 1691 return -EBUSY; 1696 1692 } 1697 1693 1698 - if (atomic_dec_return(csdev->refcnt)) { 1694 + if (atomic_dec_return(&csdev->refcnt)) { 1699 1695 spin_unlock_irqrestore(&drvdata->spinlock, flags); 1700 1696 return -EBUSY; 1701 1697 }
+2
drivers/hwtracing/coresight/coresight-tmc.h
··· 332 332 333 333 void tmc_etr_set_catu_ops(const struct etr_buf_operations *catu); 334 334 void tmc_etr_remove_catu_ops(void); 335 + struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev, 336 + enum cs_mode mode, void *data); 335 337 336 338 #endif
+13 -10
drivers/hwtracing/coresight/coresight-tpda.c
··· 54 54 CS_LOCK(drvdata->base); 55 55 } 56 56 57 - static int tpda_enable(struct coresight_device *csdev, int inport, int outport) 57 + static int tpda_enable(struct coresight_device *csdev, 58 + struct coresight_connection *in, 59 + struct coresight_connection *out) 58 60 { 59 61 struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 60 62 61 63 spin_lock(&drvdata->spinlock); 62 - if (atomic_read(&csdev->refcnt[inport]) == 0) 63 - __tpda_enable(drvdata, inport); 64 + if (atomic_read(&in->dest_refcnt) == 0) 65 + __tpda_enable(drvdata, in->dest_port); 64 66 65 - atomic_inc(&csdev->refcnt[inport]); 67 + atomic_inc(&in->dest_refcnt); 66 68 spin_unlock(&drvdata->spinlock); 67 69 68 - dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", inport); 70 + dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port); 69 71 return 0; 70 72 } 71 73 ··· 84 82 CS_LOCK(drvdata->base); 85 83 } 86 84 87 - static void tpda_disable(struct coresight_device *csdev, int inport, 88 - int outport) 85 + static void tpda_disable(struct coresight_device *csdev, 86 + struct coresight_connection *in, 87 + struct coresight_connection *out) 89 88 { 90 89 struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 91 90 92 91 spin_lock(&drvdata->spinlock); 93 - if (atomic_dec_return(&csdev->refcnt[inport]) == 0) 94 - __tpda_disable(drvdata, inport); 92 + if (atomic_dec_return(&in->dest_refcnt) == 0) 93 + __tpda_disable(drvdata, in->dest_port); 95 94 96 95 spin_unlock(&drvdata->spinlock); 97 96 98 - dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", inport); 97 + dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port); 99 98 } 100 99 101 100 static const struct coresight_ops_link tpda_link_ops = {
+2 -2
drivers/hwtracing/coresight/coresight-tpdm.c
··· 42 42 CS_LOCK(drvdata->base); 43 43 } 44 44 45 - static int tpdm_enable(struct coresight_device *csdev, 46 - struct perf_event *event, u32 mode) 45 + static int tpdm_enable(struct coresight_device *csdev, struct perf_event *event, 46 + enum cs_mode mode) 47 47 { 48 48 struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 49 49
+4 -3
drivers/hwtracing/coresight/coresight-tpiu.c
··· 69 69 CS_LOCK(csa->base); 70 70 } 71 71 72 - static int tpiu_enable(struct coresight_device *csdev, u32 mode, void *__unused) 72 + static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode, 73 + void *__unused) 73 74 { 74 75 tpiu_enable_hw(&csdev->access); 75 - atomic_inc(csdev->refcnt); 76 + atomic_inc(&csdev->refcnt); 76 77 dev_dbg(&csdev->dev, "TPIU enabled\n"); 77 78 return 0; 78 79 } ··· 96 95 97 96 static int tpiu_disable(struct coresight_device *csdev) 98 97 { 99 - if (atomic_dec_return(csdev->refcnt)) 98 + if (atomic_dec_return(&csdev->refcnt)) 100 99 return -EBUSY; 101 100 102 101 tpiu_disable_hw(&csdev->access);
+2 -1
drivers/hwtracing/coresight/coresight-trbe.c
··· 1005 1005 return ret; 1006 1006 } 1007 1007 1008 - static int arm_trbe_enable(struct coresight_device *csdev, u32 mode, void *data) 1008 + static int arm_trbe_enable(struct coresight_device *csdev, enum cs_mode mode, 1009 + void *data) 1009 1010 { 1010 1011 struct trbe_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 1011 1012 struct trbe_cpudata *cpudata = dev_get_drvdata(&csdev->dev);
+6 -5
drivers/hwtracing/coresight/ultrasoc-smb.c
··· 106 106 goto out; 107 107 } 108 108 109 - if (atomic_read(drvdata->csdev->refcnt)) { 109 + if (atomic_read(&drvdata->csdev->refcnt)) { 110 110 ret = -EBUSY; 111 111 goto out; 112 112 } ··· 256 256 return 0; 257 257 } 258 258 259 - static int smb_enable(struct coresight_device *csdev, u32 mode, void *data) 259 + static int smb_enable(struct coresight_device *csdev, enum cs_mode mode, 260 + void *data) 260 261 { 261 262 struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent); 262 263 int ret = 0; ··· 290 289 if (ret) 291 290 goto out; 292 291 293 - atomic_inc(csdev->refcnt); 292 + atomic_inc(&csdev->refcnt); 294 293 295 294 dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n"); 296 295 out: ··· 311 310 goto out; 312 311 } 313 312 314 - if (atomic_dec_return(csdev->refcnt)) { 313 + if (atomic_dec_return(&csdev->refcnt)) { 315 314 ret = -EBUSY; 316 315 goto out; 317 316 } ··· 411 410 mutex_lock(&drvdata->mutex); 412 411 413 412 /* Don't do anything if another tracer is using this sink. */ 414 - if (atomic_read(csdev->refcnt) != 1) 413 + if (atomic_read(&csdev->refcnt) != 1) 415 414 goto out; 416 415 417 416 smb_disable_hw(drvdata);
+1 -1
drivers/hwtracing/coresight/ultrasoc-smb.h
··· 119 119 struct mutex mutex; 120 120 bool reading; 121 121 pid_t pid; 122 - u32 mode; 122 + enum cs_mode mode; 123 123 }; 124 124 125 125 #endif
+409 -35
drivers/hwtracing/ptt/hisi_ptt.c
··· 341 341 if (ret < 0) 342 342 return ret; 343 343 344 - ret = devm_request_threaded_irq(&pdev->dev, 345 - pci_irq_vector(pdev, HISI_PTT_TRACE_DMA_IRQ), 344 + hisi_ptt->trace_irq = pci_irq_vector(pdev, HISI_PTT_TRACE_DMA_IRQ); 345 + ret = devm_request_threaded_irq(&pdev->dev, hisi_ptt->trace_irq, 346 346 NULL, hisi_ptt_isr, 0, 347 347 DRV_NAME, hisi_ptt); 348 348 if (ret) { 349 349 pci_err(pdev, "failed to request irq %d, ret = %d\n", 350 - pci_irq_vector(pdev, HISI_PTT_TRACE_DMA_IRQ), ret); 350 + hisi_ptt->trace_irq, ret); 351 351 return ret; 352 352 } 353 + 354 + return 0; 355 + } 356 + 357 + static void hisi_ptt_del_free_filter(struct hisi_ptt *hisi_ptt, 358 + struct hisi_ptt_filter_desc *filter) 359 + { 360 + if (filter->is_port) 361 + hisi_ptt->port_mask &= ~hisi_ptt_get_filter_val(filter->devid, true); 362 + 363 + list_del(&filter->list); 364 + kfree(filter->name); 365 + kfree(filter); 366 + } 367 + 368 + static struct hisi_ptt_filter_desc * 369 + hisi_ptt_alloc_add_filter(struct hisi_ptt *hisi_ptt, u16 devid, bool is_port) 370 + { 371 + struct hisi_ptt_filter_desc *filter; 372 + u8 devfn = devid & 0xff; 373 + char *filter_name; 374 + 375 + filter_name = kasprintf(GFP_KERNEL, "%04x:%02x:%02x.%d", pci_domain_nr(hisi_ptt->pdev->bus), 376 + PCI_BUS_NUM(devid), PCI_SLOT(devfn), PCI_FUNC(devfn)); 377 + if (!filter_name) { 378 + pci_err(hisi_ptt->pdev, "failed to allocate name for filter %04x:%02x:%02x.%d\n", 379 + pci_domain_nr(hisi_ptt->pdev->bus), PCI_BUS_NUM(devid), 380 + PCI_SLOT(devfn), PCI_FUNC(devfn)); 381 + return NULL; 382 + } 383 + 384 + filter = kzalloc(sizeof(*filter), GFP_KERNEL); 385 + if (!filter) { 386 + pci_err(hisi_ptt->pdev, "failed to add filter for %s\n", 387 + filter_name); 388 + kfree(filter_name); 389 + return NULL; 390 + } 391 + 392 + filter->name = filter_name; 393 + filter->is_port = is_port; 394 + filter->devid = devid; 395 + 396 + if (filter->is_port) { 397 + list_add_tail(&filter->list, &hisi_ptt->port_filters); 398 + 399 + /* Update the available port mask */ 400 + hisi_ptt->port_mask |= hisi_ptt_get_filter_val(filter->devid, true); 401 + } else { 402 + list_add_tail(&filter->list, &hisi_ptt->req_filters); 403 + } 404 + 405 + return filter; 406 + } 407 + 408 + static ssize_t hisi_ptt_filter_show(struct device *dev, struct device_attribute *attr, 409 + char *buf) 410 + { 411 + struct hisi_ptt_filter_desc *filter; 412 + unsigned long filter_val; 413 + 414 + filter = container_of(attr, struct hisi_ptt_filter_desc, attr); 415 + filter_val = hisi_ptt_get_filter_val(filter->devid, filter->is_port) | 416 + (filter->is_port ? HISI_PTT_PMU_FILTER_IS_PORT : 0); 417 + 418 + return sysfs_emit(buf, "0x%05lx\n", filter_val); 419 + } 420 + 421 + static int hisi_ptt_create_rp_filter_attr(struct hisi_ptt *hisi_ptt, 422 + struct hisi_ptt_filter_desc *filter) 423 + { 424 + struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj; 425 + 426 + sysfs_attr_init(&filter->attr.attr); 427 + filter->attr.attr.name = filter->name; 428 + filter->attr.attr.mode = 0400; /* DEVICE_ATTR_ADMIN_RO */ 429 + filter->attr.show = hisi_ptt_filter_show; 430 + 431 + return sysfs_add_file_to_group(kobj, &filter->attr.attr, 432 + HISI_PTT_RP_FILTERS_GRP_NAME); 433 + } 434 + 435 + static void hisi_ptt_remove_rp_filter_attr(struct hisi_ptt *hisi_ptt, 436 + struct hisi_ptt_filter_desc *filter) 437 + { 438 + struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj; 439 + 440 + sysfs_remove_file_from_group(kobj, &filter->attr.attr, 441 + HISI_PTT_RP_FILTERS_GRP_NAME); 442 + } 443 + 444 + static int hisi_ptt_create_req_filter_attr(struct hisi_ptt *hisi_ptt, 445 + struct hisi_ptt_filter_desc *filter) 446 + { 447 + struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj; 448 + 449 + sysfs_attr_init(&filter->attr.attr); 450 + filter->attr.attr.name = filter->name; 451 + filter->attr.attr.mode = 0400; /* DEVICE_ATTR_ADMIN_RO */ 452 + filter->attr.show = hisi_ptt_filter_show; 453 + 454 + return sysfs_add_file_to_group(kobj, &filter->attr.attr, 455 + HISI_PTT_REQ_FILTERS_GRP_NAME); 456 + } 457 + 458 + static void hisi_ptt_remove_req_filter_attr(struct hisi_ptt *hisi_ptt, 459 + struct hisi_ptt_filter_desc *filter) 460 + { 461 + struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj; 462 + 463 + sysfs_remove_file_from_group(kobj, &filter->attr.attr, 464 + HISI_PTT_REQ_FILTERS_GRP_NAME); 465 + } 466 + 467 + static int hisi_ptt_create_filter_attr(struct hisi_ptt *hisi_ptt, 468 + struct hisi_ptt_filter_desc *filter) 469 + { 470 + int ret; 471 + 472 + if (filter->is_port) 473 + ret = hisi_ptt_create_rp_filter_attr(hisi_ptt, filter); 474 + else 475 + ret = hisi_ptt_create_req_filter_attr(hisi_ptt, filter); 476 + 477 + if (ret) 478 + pci_err(hisi_ptt->pdev, "failed to create sysfs attribute for filter %s\n", 479 + filter->name); 480 + 481 + return ret; 482 + } 483 + 484 + static void hisi_ptt_remove_filter_attr(struct hisi_ptt *hisi_ptt, 485 + struct hisi_ptt_filter_desc *filter) 486 + { 487 + if (filter->is_port) 488 + hisi_ptt_remove_rp_filter_attr(hisi_ptt, filter); 489 + else 490 + hisi_ptt_remove_req_filter_attr(hisi_ptt, filter); 491 + } 492 + 493 + static void hisi_ptt_remove_all_filter_attributes(void *data) 494 + { 495 + struct hisi_ptt_filter_desc *filter; 496 + struct hisi_ptt *hisi_ptt = data; 497 + 498 + mutex_lock(&hisi_ptt->filter_lock); 499 + 500 + list_for_each_entry(filter, &hisi_ptt->req_filters, list) 501 + hisi_ptt_remove_filter_attr(hisi_ptt, filter); 502 + 503 + list_for_each_entry(filter, &hisi_ptt->port_filters, list) 504 + hisi_ptt_remove_filter_attr(hisi_ptt, filter); 505 + 506 + hisi_ptt->sysfs_inited = false; 507 + mutex_unlock(&hisi_ptt->filter_lock); 508 + } 509 + 510 + static int hisi_ptt_init_filter_attributes(struct hisi_ptt *hisi_ptt) 511 + { 512 + struct hisi_ptt_filter_desc *filter; 513 + int ret; 514 + 515 + mutex_lock(&hisi_ptt->filter_lock); 516 + 517 + /* 518 + * Register the reset callback in the first stage. In reset we traverse 519 + * the filters list to remove the sysfs attributes so the callback can 520 + * be called safely even without below filter attributes creation. 521 + */ 522 + ret = devm_add_action(&hisi_ptt->pdev->dev, 523 + hisi_ptt_remove_all_filter_attributes, 524 + hisi_ptt); 525 + if (ret) 526 + goto out; 527 + 528 + list_for_each_entry(filter, &hisi_ptt->port_filters, list) { 529 + ret = hisi_ptt_create_filter_attr(hisi_ptt, filter); 530 + if (ret) 531 + goto out; 532 + } 533 + 534 + list_for_each_entry(filter, &hisi_ptt->req_filters, list) { 535 + ret = hisi_ptt_create_filter_attr(hisi_ptt, filter); 536 + if (ret) 537 + goto out; 538 + } 539 + 540 + hisi_ptt->sysfs_inited = true; 541 + out: 542 + mutex_unlock(&hisi_ptt->filter_lock); 543 + return ret; 544 + } 545 + 546 + static void hisi_ptt_update_filters(struct work_struct *work) 547 + { 548 + struct delayed_work *delayed_work = to_delayed_work(work); 549 + struct hisi_ptt_filter_update_info info; 550 + struct hisi_ptt_filter_desc *filter; 551 + struct hisi_ptt *hisi_ptt; 552 + 553 + hisi_ptt = container_of(delayed_work, struct hisi_ptt, work); 554 + 555 + if (!mutex_trylock(&hisi_ptt->filter_lock)) { 556 + schedule_delayed_work(&hisi_ptt->work, HISI_PTT_WORK_DELAY_MS); 557 + return; 558 + } 559 + 560 + while (kfifo_get(&hisi_ptt->filter_update_kfifo, &info)) { 561 + if (info.is_add) { 562 + /* 563 + * Notify the users if failed to add this filter, others 564 + * still work and available. See the comments in 565 + * hisi_ptt_init_filters(). 566 + */ 567 + filter = hisi_ptt_alloc_add_filter(hisi_ptt, info.devid, info.is_port); 568 + if (!filter) 569 + continue; 570 + 571 + /* 572 + * If filters' sysfs entries hasn't been initialized, 573 + * then we're still at probe stage. Add the filters to 574 + * the list and later hisi_ptt_init_filter_attributes() 575 + * will create sysfs attributes for all the filters. 576 + */ 577 + if (hisi_ptt->sysfs_inited && 578 + hisi_ptt_create_filter_attr(hisi_ptt, filter)) { 579 + hisi_ptt_del_free_filter(hisi_ptt, filter); 580 + continue; 581 + } 582 + } else { 583 + struct hisi_ptt_filter_desc *tmp; 584 + struct list_head *target_list; 585 + 586 + target_list = info.is_port ? &hisi_ptt->port_filters : 587 + &hisi_ptt->req_filters; 588 + 589 + list_for_each_entry_safe(filter, tmp, target_list, list) 590 + if (filter->devid == info.devid) { 591 + if (hisi_ptt->sysfs_inited) 592 + hisi_ptt_remove_filter_attr(hisi_ptt, filter); 593 + 594 + hisi_ptt_del_free_filter(hisi_ptt, filter); 595 + break; 596 + } 597 + } 598 + } 599 + 600 + mutex_unlock(&hisi_ptt->filter_lock); 601 + } 602 + 603 + /* 604 + * A PCI bus notifier is used here for dynamically updating the filter 605 + * list. 606 + */ 607 + static int hisi_ptt_notifier_call(struct notifier_block *nb, unsigned long action, 608 + void *data) 609 + { 610 + struct hisi_ptt *hisi_ptt = container_of(nb, struct hisi_ptt, hisi_ptt_nb); 611 + struct hisi_ptt_filter_update_info info; 612 + struct pci_dev *pdev, *root_port; 613 + struct device *dev = data; 614 + u32 port_devid; 615 + 616 + pdev = to_pci_dev(dev); 617 + root_port = pcie_find_root_port(pdev); 618 + if (!root_port) 619 + return 0; 620 + 621 + port_devid = PCI_DEVID(root_port->bus->number, root_port->devfn); 622 + if (port_devid < hisi_ptt->lower_bdf || 623 + port_devid > hisi_ptt->upper_bdf) 624 + return 0; 625 + 626 + info.is_port = pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT; 627 + info.devid = PCI_DEVID(pdev->bus->number, pdev->devfn); 628 + 629 + switch (action) { 630 + case BUS_NOTIFY_ADD_DEVICE: 631 + info.is_add = true; 632 + break; 633 + case BUS_NOTIFY_DEL_DEVICE: 634 + info.is_add = false; 635 + break; 636 + default: 637 + return 0; 638 + } 639 + 640 + /* 641 + * The FIFO size is 16 which is sufficient for almost all the cases, 642 + * since each PCIe core will have most 8 Root Ports (typically only 643 + * 1~4 Root Ports). On failure log the failed filter and let user 644 + * handle it. 645 + */ 646 + if (kfifo_in_spinlocked(&hisi_ptt->filter_update_kfifo, &info, 1, 647 + &hisi_ptt->filter_update_lock)) 648 + schedule_delayed_work(&hisi_ptt->work, 0); 649 + else 650 + pci_warn(hisi_ptt->pdev, 651 + "filter update fifo overflow for target %s\n", 652 + pci_name(pdev)); 353 653 354 654 return 0; 355 655 } ··· 674 374 * should be partial initialized and users would know which filter fails 675 375 * through the log. Other functions of PTT device are still available. 676 376 */ 677 - filter = kzalloc(sizeof(*filter), GFP_KERNEL); 678 - if (!filter) { 679 - pci_err(hisi_ptt->pdev, "failed to add filter %s\n", pci_name(pdev)); 377 + filter = hisi_ptt_alloc_add_filter(hisi_ptt, PCI_DEVID(pdev->bus->number, pdev->devfn), 378 + pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT); 379 + if (!filter) 680 380 return -ENOMEM; 681 - } 682 - 683 - filter->devid = PCI_DEVID(pdev->bus->number, pdev->devfn); 684 - 685 - if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) { 686 - filter->is_port = true; 687 - list_add_tail(&filter->list, &hisi_ptt->port_filters); 688 - 689 - /* Update the available port mask */ 690 - hisi_ptt->port_mask |= hisi_ptt_get_filter_val(filter->devid, true); 691 - } else { 692 - list_add_tail(&filter->list, &hisi_ptt->req_filters); 693 - } 694 381 695 382 return 0; 696 383 } ··· 687 400 struct hisi_ptt_filter_desc *filter, *tmp; 688 401 struct hisi_ptt *hisi_ptt = data; 689 402 690 - list_for_each_entry_safe(filter, tmp, &hisi_ptt->req_filters, list) { 691 - list_del(&filter->list); 692 - kfree(filter); 693 - } 403 + list_for_each_entry_safe(filter, tmp, &hisi_ptt->req_filters, list) 404 + hisi_ptt_del_free_filter(hisi_ptt, filter); 694 405 695 - list_for_each_entry_safe(filter, tmp, &hisi_ptt->port_filters, list) { 696 - list_del(&filter->list); 697 - kfree(filter); 698 - } 406 + list_for_each_entry_safe(filter, tmp, &hisi_ptt->port_filters, list) 407 + hisi_ptt_del_free_filter(hisi_ptt, filter); 699 408 } 700 409 701 410 static int hisi_ptt_config_trace_buf(struct hisi_ptt *hisi_ptt) ··· 734 451 int ret; 735 452 u32 reg; 736 453 454 + INIT_DELAYED_WORK(&hisi_ptt->work, hisi_ptt_update_filters); 455 + INIT_KFIFO(hisi_ptt->filter_update_kfifo); 456 + spin_lock_init(&hisi_ptt->filter_update_lock); 457 + 737 458 INIT_LIST_HEAD(&hisi_ptt->port_filters); 738 459 INIT_LIST_HEAD(&hisi_ptt->req_filters); 460 + mutex_init(&hisi_ptt->filter_lock); 739 461 740 462 ret = hisi_ptt_config_trace_buf(hisi_ptt); 741 463 if (ret) ··· 816 528 .attrs = hisi_ptt_pmu_format_attrs, 817 529 }; 818 530 531 + static ssize_t hisi_ptt_filter_multiselect_show(struct device *dev, 532 + struct device_attribute *attr, 533 + char *buf) 534 + { 535 + struct dev_ext_attribute *ext_attr; 536 + 537 + ext_attr = container_of(attr, struct dev_ext_attribute, attr); 538 + return sysfs_emit(buf, "%s\n", (char *)ext_attr->var); 539 + } 540 + 541 + static struct dev_ext_attribute root_port_filters_multiselect = { 542 + .attr = { 543 + .attr = { .name = "multiselect", .mode = 0400 }, 544 + .show = hisi_ptt_filter_multiselect_show, 545 + }, 546 + .var = "1", 547 + }; 548 + 549 + static struct attribute *hisi_ptt_pmu_root_ports_attrs[] = { 550 + &root_port_filters_multiselect.attr.attr, 551 + NULL 552 + }; 553 + 554 + static struct attribute_group hisi_ptt_pmu_root_ports_group = { 555 + .name = HISI_PTT_RP_FILTERS_GRP_NAME, 556 + .attrs = hisi_ptt_pmu_root_ports_attrs, 557 + }; 558 + 559 + static struct dev_ext_attribute requester_filters_multiselect = { 560 + .attr = { 561 + .attr = { .name = "multiselect", .mode = 0400 }, 562 + .show = hisi_ptt_filter_multiselect_show, 563 + }, 564 + .var = "0", 565 + }; 566 + 567 + static struct attribute *hisi_ptt_pmu_requesters_attrs[] = { 568 + &requester_filters_multiselect.attr.attr, 569 + NULL 570 + }; 571 + 572 + static struct attribute_group hisi_ptt_pmu_requesters_group = { 573 + .name = HISI_PTT_REQ_FILTERS_GRP_NAME, 574 + .attrs = hisi_ptt_pmu_requesters_attrs, 575 + }; 576 + 819 577 static const struct attribute_group *hisi_ptt_pmu_groups[] = { 820 578 &hisi_ptt_cpumask_attr_group, 821 579 &hisi_ptt_pmu_format_group, 822 580 &hisi_ptt_tune_group, 581 + &hisi_ptt_pmu_root_ports_group, 582 + &hisi_ptt_pmu_requesters_group, 823 583 NULL 824 584 }; 825 585 ··· 941 605 { 942 606 unsigned long val, port_mask = hisi_ptt->port_mask; 943 607 struct hisi_ptt_filter_desc *filter; 608 + int ret = 0; 944 609 945 610 hisi_ptt->trace_ctrl.is_port = FIELD_GET(HISI_PTT_PMU_FILTER_IS_PORT, config); 946 611 val = FIELD_GET(HISI_PTT_PMU_FILTER_VAL_MASK, config); ··· 955 618 * For Requester ID filters, walk the available filter list to see 956 619 * whether we have one matched. 957 620 */ 621 + mutex_lock(&hisi_ptt->filter_lock); 958 622 if (!hisi_ptt->trace_ctrl.is_port) { 959 623 list_for_each_entry(filter, &hisi_ptt->req_filters, list) { 960 624 if (val == hisi_ptt_get_filter_val(filter->devid, filter->is_port)) 961 - return 0; 625 + goto out; 962 626 } 963 627 } else if (bitmap_subset(&val, &port_mask, BITS_PER_LONG)) { 964 - return 0; 628 + goto out; 965 629 } 966 630 967 - return -EINVAL; 631 + ret = -EINVAL; 632 + out: 633 + mutex_unlock(&hisi_ptt->filter_lock); 634 + return ret; 968 635 } 969 636 970 637 static void hisi_ptt_pmu_init_configs(struct hisi_ptt *hisi_ptt, struct perf_event *event) ··· 1098 757 * core in event_function_local(). If CPU passed is offline we'll fail 1099 758 * here, just log it since we can do nothing here. 1100 759 */ 1101 - ret = irq_set_affinity(pci_irq_vector(hisi_ptt->pdev, HISI_PTT_TRACE_DMA_IRQ), 1102 - cpumask_of(cpu)); 760 + ret = irq_set_affinity(hisi_ptt->trace_irq, cpumask_of(cpu)); 1103 761 if (ret) 1104 762 dev_warn(dev, "failed to set the affinity of trace interrupt\n"); 1105 763 ··· 1211 871 1212 872 hisi_ptt->hisi_ptt_pmu = (struct pmu) { 1213 873 .module = THIS_MODULE, 1214 - .capabilities = PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE, 874 + .capabilities = PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_NO_EXCLUDE, 1215 875 .task_ctx_nr = perf_sw_context, 1216 876 .attr_groups = hisi_ptt_pmu_groups, 1217 877 .event_init = hisi_ptt_pmu_event_init, ··· 1239 899 return devm_add_action_or_reset(&hisi_ptt->pdev->dev, 1240 900 hisi_ptt_unregister_pmu, 1241 901 &hisi_ptt->hisi_ptt_pmu); 902 + } 903 + 904 + static void hisi_ptt_unregister_filter_update_notifier(void *data) 905 + { 906 + struct hisi_ptt *hisi_ptt = data; 907 + 908 + bus_unregister_notifier(&pci_bus_type, &hisi_ptt->hisi_ptt_nb); 909 + 910 + /* Cancel any work that has been queued */ 911 + cancel_delayed_work_sync(&hisi_ptt->work); 912 + } 913 + 914 + /* Register the bus notifier for dynamically updating the filter list */ 915 + static int hisi_ptt_register_filter_update_notifier(struct hisi_ptt *hisi_ptt) 916 + { 917 + int ret; 918 + 919 + hisi_ptt->hisi_ptt_nb.notifier_call = hisi_ptt_notifier_call; 920 + ret = bus_register_notifier(&pci_bus_type, &hisi_ptt->hisi_ptt_nb); 921 + if (ret) 922 + return ret; 923 + 924 + return devm_add_action_or_reset(&hisi_ptt->pdev->dev, 925 + hisi_ptt_unregister_filter_update_notifier, 926 + hisi_ptt); 1242 927 } 1243 928 1244 929 /* ··· 1337 972 return ret; 1338 973 } 1339 974 975 + ret = hisi_ptt_register_filter_update_notifier(hisi_ptt); 976 + if (ret) 977 + pci_warn(pdev, "failed to register filter update notifier, ret = %d", ret); 978 + 1340 979 ret = hisi_ptt_register_pmu(hisi_ptt); 1341 980 if (ret) { 1342 981 pci_err(pdev, "failed to register PMU device, ret = %d", ret); 982 + return ret; 983 + } 984 + 985 + ret = hisi_ptt_init_filter_attributes(hisi_ptt); 986 + if (ret) { 987 + pci_err(pdev, "failed to init sysfs filter attributes, ret = %d", ret); 1343 988 return ret; 1344 989 } 1345 990 ··· 1393 1018 * Also make sure the interrupt bind to the migrated CPU as well. Warn 1394 1019 * the user on failure here. 1395 1020 */ 1396 - if (irq_set_affinity(pci_irq_vector(hisi_ptt->pdev, HISI_PTT_TRACE_DMA_IRQ), 1397 - cpumask_of(target))) 1021 + if (irq_set_affinity(hisi_ptt->trace_irq, cpumask_of(target))) 1398 1022 dev_warn(dev, "failed to set the affinity of trace interrupt\n"); 1399 1023 1400 1024 hisi_ptt->trace_ctrl.on_cpu = target;
+56
drivers/hwtracing/ptt/hisi_ptt.h
··· 11 11 12 12 #include <linux/bits.h> 13 13 #include <linux/cpumask.h> 14 + #include <linux/device.h> 15 + #include <linux/kfifo.h> 14 16 #include <linux/list.h> 15 17 #include <linux/mutex.h> 18 + #include <linux/notifier.h> 16 19 #include <linux/pci.h> 17 20 #include <linux/perf_event.h> 18 21 #include <linux/spinlock.h> 19 22 #include <linux/types.h> 23 + #include <linux/workqueue.h> 20 24 21 25 #define DRV_NAME "hisi_ptt" 22 26 ··· 74 70 #define HISI_PTT_WAIT_TUNE_TIMEOUT_US 1000000UL 75 71 #define HISI_PTT_WAIT_TRACE_TIMEOUT_US 100UL 76 72 #define HISI_PTT_WAIT_POLL_INTERVAL_US 10UL 73 + 74 + /* FIFO size for dynamically updating the PTT trace filter list. */ 75 + #define HISI_PTT_FILTER_UPDATE_FIFO_SIZE 16 76 + /* Delay time for filter updating work */ 77 + #define HISI_PTT_WORK_DELAY_MS 100UL 77 78 78 79 #define HISI_PCIE_CORE_PORT_ID(devfn) ((PCI_SLOT(devfn) & 0x7) << 1) 79 80 ··· 140 131 u32 type:4; 141 132 }; 142 133 134 + /* 135 + * sysfs attribute group name for root port filters and requester filters: 136 + * /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters 137 + * and 138 + * /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters 139 + */ 140 + #define HISI_PTT_RP_FILTERS_GRP_NAME "root_port_filters" 141 + #define HISI_PTT_REQ_FILTERS_GRP_NAME "requester_filters" 142 + 143 143 /** 144 144 * struct hisi_ptt_filter_desc - Descriptor of the PTT trace filter 145 + * @attr: sysfs attribute of this filter 145 146 * @list: entry of this descriptor in the filter list 146 147 * @is_port: the PCI device of the filter is a Root Port or not 148 + * @name: name of this filter, same as the name of the related PCI device 147 149 * @devid: the PCI device's devid of the filter 148 150 */ 149 151 struct hisi_ptt_filter_desc { 152 + struct device_attribute attr; 150 153 struct list_head list; 151 154 bool is_port; 155 + char *name; 156 + u16 devid; 157 + }; 158 + 159 + /** 160 + * struct hisi_ptt_filter_update_info - Information for PTT filter updating 161 + * @is_port: the PCI device to update is a Root Port or not 162 + * @is_add: adding to the filter or not 163 + * @devid: the PCI device's devid of the filter 164 + */ 165 + struct hisi_ptt_filter_update_info { 166 + bool is_port; 167 + bool is_add; 152 168 u16 devid; 153 169 }; 154 170 ··· 194 160 /** 195 161 * struct hisi_ptt - Per PTT device data 196 162 * @trace_ctrl: the control information of PTT trace 163 + * @hisi_ptt_nb: dynamic filter update notifier 197 164 * @hotplug_node: node for register cpu hotplug event 198 165 * @hisi_ptt_pmu: the pum device of trace 199 166 * @iobase: base IO address of the device 200 167 * @pdev: pci_dev of this PTT device 201 168 * @tune_lock: lock to serialize the tune process 202 169 * @pmu_lock: lock to serialize the perf process 170 + * @trace_irq: interrupt number used by trace 203 171 * @upper_bdf: the upper BDF range of the PCI devices managed by this PTT device 204 172 * @lower_bdf: the lower BDF range of the PCI devices managed by this PTT device 205 173 * @port_filters: the filter list of root ports 206 174 * @req_filters: the filter list of requester ID 175 + * @filter_lock: lock to protect the filters 176 + * @sysfs_inited: whether the filters' sysfs entries has been initialized 207 177 * @port_mask: port mask of the managed root ports 178 + * @work: delayed work for filter updating 179 + * @filter_update_lock: spinlock to protect the filter update fifo 180 + * @filter_update_fifo: fifo of the filters waiting to update the filter list 208 181 */ 209 182 struct hisi_ptt { 210 183 struct hisi_ptt_trace_ctrl trace_ctrl; 184 + struct notifier_block hisi_ptt_nb; 211 185 struct hlist_node hotplug_node; 212 186 struct pmu hisi_ptt_pmu; 213 187 void __iomem *iobase; 214 188 struct pci_dev *pdev; 215 189 struct mutex tune_lock; 216 190 spinlock_t pmu_lock; 191 + int trace_irq; 217 192 u32 upper_bdf; 218 193 u32 lower_bdf; 219 194 ··· 235 192 */ 236 193 struct list_head port_filters; 237 194 struct list_head req_filters; 195 + struct mutex filter_lock; 196 + bool sysfs_inited; 238 197 u16 port_mask; 198 + 199 + /* 200 + * We use a delayed work here to avoid indefinitely waiting for 201 + * the hisi_ptt->mutex which protecting the filter list. The 202 + * work will be delayed only if the mutex can not be held, 203 + * otherwise no delay will be applied. 204 + */ 205 + struct delayed_work work; 206 + spinlock_t filter_update_lock; 207 + DECLARE_KFIFO(filter_update_kfifo, struct hisi_ptt_filter_update_info, 208 + HISI_PTT_FILTER_UPDATE_FIFO_SIZE); 239 209 }; 240 210 241 211 #define to_hisi_ptt(pmu) container_of(pmu, struct hisi_ptt, hisi_ptt_pmu)
+78 -49
include/linux/coresight.h
··· 41 41 CORESIGHT_DEV_TYPE_LINKSINK, 42 42 CORESIGHT_DEV_TYPE_SOURCE, 43 43 CORESIGHT_DEV_TYPE_HELPER, 44 - CORESIGHT_DEV_TYPE_ECT, 44 + CORESIGHT_DEV_TYPE_MAX 45 45 }; 46 46 47 47 enum coresight_dev_subtype_sink { 48 + CORESIGHT_DEV_SUBTYPE_SINK_DUMMY, 48 49 CORESIGHT_DEV_SUBTYPE_SINK_PORT, 49 50 CORESIGHT_DEV_SUBTYPE_SINK_BUFFER, 50 51 CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM, ··· 67 66 68 67 enum coresight_dev_subtype_helper { 69 68 CORESIGHT_DEV_SUBTYPE_HELPER_CATU, 70 - }; 71 - 72 - /* Embedded Cross Trigger (ECT) sub-types */ 73 - enum coresight_dev_subtype_ect { 74 - CORESIGHT_DEV_SUBTYPE_ECT_NONE, 75 - CORESIGHT_DEV_SUBTYPE_ECT_CTI, 69 + CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI 76 70 }; 77 71 78 72 /** ··· 80 84 * by @coresight_dev_subtype_source. 81 85 * @helper_subtype: type of helper this component is, as defined 82 86 * by @coresight_dev_subtype_helper. 83 - * @ect_subtype: type of cross trigger this component is, as 84 - * defined by @coresight_dev_subtype_ect 85 87 */ 86 88 union coresight_dev_subtype { 87 89 /* We have some devices which acts as LINK and SINK */ ··· 89 95 }; 90 96 enum coresight_dev_subtype_source source_subtype; 91 97 enum coresight_dev_subtype_helper helper_subtype; 92 - enum coresight_dev_subtype_ect ect_subtype; 93 98 }; 94 99 95 100 /** 96 101 * struct coresight_platform_data - data harvested from the firmware 97 102 * specification. 98 103 * 99 - * @nr_inport: Number of elements for the input connections. 100 - * @nr_outport: Number of elements for the output connections. 101 - * @conns: Sparse array of nr_outport connections from this component. 104 + * @nr_inconns: Number of elements for the input connections. 105 + * @nr_outconns: Number of elements for the output connections. 106 + * @out_conns: Array of nr_outconns pointers to connections from this 107 + * component. 108 + * @in_conns: Sparse array of pointers to input connections. Sparse 109 + * because the source device owns the connection so when it's 110 + * unloaded the connection leaves an empty slot. 102 111 */ 103 112 struct coresight_platform_data { 104 - int nr_inport; 105 - int nr_outport; 106 - struct coresight_connection *conns; 113 + int nr_inconns; 114 + int nr_outconns; 115 + struct coresight_connection **out_conns; 116 + struct coresight_connection **in_conns; 107 117 }; 108 118 109 119 /** ··· 162 164 163 165 /** 164 166 * struct coresight_connection - representation of a single connection 165 - * @outport: a connection's output port number. 166 - * @child_port: remote component's port number @output is connected to. 167 - * @chid_fwnode: remote component's fwnode handle. 168 - * @child_dev: a @coresight_device representation of the component 169 - connected to @outport. 167 + * @src_port: a connection's output port number. 168 + * @dest_port: destination's input port number @src_port is connected to. 169 + * @dest_fwnode: destination component's fwnode handle. 170 + * @dest_dev: a @coresight_device representation of the component 171 + connected to @src_port. NULL until the device is created 170 172 * @link: Representation of the connection as a sysfs link. 173 + * 174 + * The full connection structure looks like this, where in_conns store 175 + * references to same connection as the source device's out_conns. 176 + * 177 + * +-----------------------------+ +-----------------------------+ 178 + * |coresight_device | |coresight_connection | 179 + * |-----------------------------| |-----------------------------| 180 + * | | | | 181 + * | | | dest_dev*|<-- 182 + * |pdata->out_conns[nr_outconns]|<->|src_dev* | | 183 + * | | | | | 184 + * +-----------------------------+ +-----------------------------+ | 185 + * | 186 + * +-----------------------------+ | 187 + * |coresight_device | | 188 + * |------------------------------ | 189 + * | | | 190 + * | pdata->in_conns[nr_inconns]|<-- 191 + * | | 192 + * +-----------------------------+ 171 193 */ 172 194 struct coresight_connection { 173 - int outport; 174 - int child_port; 175 - struct fwnode_handle *child_fwnode; 176 - struct coresight_device *child_dev; 195 + int src_port; 196 + int dest_port; 197 + struct fwnode_handle *dest_fwnode; 198 + struct coresight_device *dest_dev; 177 199 struct coresight_sysfs_link *link; 200 + struct coresight_device *src_dev; 201 + atomic_t src_refcnt; 202 + atomic_t dest_refcnt; 178 203 }; 179 204 180 205 /** ··· 232 211 * from source to that sink. 233 212 * @ea: Device attribute for sink representation under PMU directory. 234 213 * @def_sink: cached reference to default sink found for this device. 235 - * @ect_dev: Associated cross trigger device. Not part of the trace data 236 - * path or connections. 237 214 * @nr_links: number of sysfs links created to other components from this 238 215 * device. These will appear in the "connections" group. 239 216 * @has_conns_grp: Have added a "connections" group for sysfs links. ··· 247 228 const struct coresight_ops *ops; 248 229 struct csdev_access access; 249 230 struct device dev; 250 - atomic_t *refcnt; 231 + atomic_t refcnt; 251 232 bool orphan; 252 233 bool enable; /* true only if configured as part of a path */ 253 234 /* sink specific fields */ 254 235 bool activated; /* true only if a sink is part of a path */ 255 236 struct dev_ext_attribute *ea; 256 237 struct coresight_device *def_sink; 257 - /* cross trigger handling */ 258 - struct coresight_device *ect_dev; 259 238 /* sysfs links between components */ 260 239 int nr_links; 261 240 bool has_conns_grp; 262 - bool ect_enabled; /* true only if associated ect device is enabled */ 263 241 /* system configuration and feature lists */ 264 242 struct list_head feature_csdev_list; 265 243 struct list_head config_csdev_list; ··· 288 272 289 273 #define to_coresight_device(d) container_of(d, struct coresight_device, dev) 290 274 275 + enum cs_mode { 276 + CS_MODE_DISABLED, 277 + CS_MODE_SYSFS, 278 + CS_MODE_PERF, 279 + }; 280 + 291 281 #define source_ops(csdev) csdev->ops->source_ops 292 282 #define sink_ops(csdev) csdev->ops->sink_ops 293 283 #define link_ops(csdev) csdev->ops->link_ops ··· 310 288 * @update_buffer: update buffer pointers after a trace session. 311 289 */ 312 290 struct coresight_ops_sink { 313 - int (*enable)(struct coresight_device *csdev, u32 mode, void *data); 291 + int (*enable)(struct coresight_device *csdev, enum cs_mode mode, 292 + void *data); 314 293 int (*disable)(struct coresight_device *csdev); 315 294 void *(*alloc_buffer)(struct coresight_device *csdev, 316 295 struct perf_event *event, void **pages, ··· 329 306 * @disable: disables flow between iport and oport. 330 307 */ 331 308 struct coresight_ops_link { 332 - int (*enable)(struct coresight_device *csdev, int iport, int oport); 333 - void (*disable)(struct coresight_device *csdev, int iport, int oport); 309 + int (*enable)(struct coresight_device *csdev, 310 + struct coresight_connection *in, 311 + struct coresight_connection *out); 312 + void (*disable)(struct coresight_device *csdev, 313 + struct coresight_connection *in, 314 + struct coresight_connection *out); 334 315 }; 335 316 336 317 /** ··· 347 320 */ 348 321 struct coresight_ops_source { 349 322 int (*cpu_id)(struct coresight_device *csdev); 350 - int (*enable)(struct coresight_device *csdev, 351 - struct perf_event *event, u32 mode); 323 + int (*enable)(struct coresight_device *csdev, struct perf_event *event, 324 + enum cs_mode mode); 352 325 void (*disable)(struct coresight_device *csdev, 353 326 struct perf_event *event); 354 327 }; ··· 363 336 * @disable : Disable the device 364 337 */ 365 338 struct coresight_ops_helper { 366 - int (*enable)(struct coresight_device *csdev, void *data); 339 + int (*enable)(struct coresight_device *csdev, enum cs_mode mode, 340 + void *data); 367 341 int (*disable)(struct coresight_device *csdev, void *data); 368 - }; 369 - 370 - /** 371 - * struct coresight_ops_ect - Ops for an embedded cross trigger device 372 - * 373 - * @enable : Enable the device 374 - * @disable : Disable the device 375 - */ 376 - struct coresight_ops_ect { 377 - int (*enable)(struct coresight_device *csdev); 378 - int (*disable)(struct coresight_device *csdev); 379 342 }; 380 343 381 344 struct coresight_ops { ··· 373 356 const struct coresight_ops_link *link_ops; 374 357 const struct coresight_ops_source *source_ops; 375 358 const struct coresight_ops_helper *helper_ops; 376 - const struct coresight_ops_ect *ect_ops; 377 359 }; 378 360 379 361 #if IS_ENABLED(CONFIG_CORESIGHT) ··· 618 602 extern int coresight_get_cpu(struct device *dev); 619 603 620 604 struct coresight_platform_data *coresight_get_platform_data(struct device *dev); 605 + struct coresight_connection * 606 + coresight_add_out_conn(struct device *dev, 607 + struct coresight_platform_data *pdata, 608 + const struct coresight_connection *new_conn); 609 + int coresight_add_in_conn(struct coresight_connection *conn); 610 + struct coresight_device * 611 + coresight_find_input_type(struct coresight_platform_data *pdata, 612 + enum coresight_dev_type type, 613 + union coresight_dev_subtype subtype); 614 + struct coresight_device * 615 + coresight_find_output_type(struct coresight_platform_data *pdata, 616 + enum coresight_dev_type type, 617 + union coresight_dev_subtype subtype); 621 618 622 619 #endif /* _LINUX_COREISGHT_H */
+11
include/linux/device.h
··· 223 223 { 224 224 return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO); 225 225 } 226 + static inline __realloc_size(3, 4) void * __must_check 227 + devm_krealloc_array(struct device *dev, void *p, size_t new_n, size_t new_size, gfp_t flags) 228 + { 229 + size_t bytes; 230 + 231 + if (unlikely(check_mul_overflow(new_n, new_size, &bytes))) 232 + return NULL; 233 + 234 + return devm_krealloc(dev, p, bytes, flags); 235 + } 236 + 226 237 void devm_kfree(struct device *dev, const void *p); 227 238 char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc; 228 239 const char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp);