--- zzzz-none-000/linux-5.4.213/drivers/hwtracing/coresight/coresight-tmc.c 2022-09-15 10:04:56.000000000 +0000 +++ alder-5690pro-762/linux-5.4.213/drivers/hwtracing/coresight/coresight-tmc.c 2024-08-14 09:01:58.000000000 +0000 @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012,2017-2020 The Linux Foundation. All rights reserved. * * Description: CoreSight Trace Memory Controller driver */ @@ -23,9 +23,12 @@ #include #include #include +#include +#include #include "coresight-priv.h" #include "coresight-tmc.h" +#include "coresight-common.h" DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb"); DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf"); @@ -62,11 +65,14 @@ void tmc_enable_hw(struct tmc_drvdata *drvdata) { + drvdata->enable = true; writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL); } +EXPORT_SYMBOL(tmc_enable_hw); void tmc_disable_hw(struct tmc_drvdata *drvdata) { + drvdata->enable = false; writel_relaxed(0x0, drvdata->base + TMC_CTL); } @@ -102,6 +108,9 @@ { int ret = 0; + if (!drvdata->enable) + return -EPERM; + switch (drvdata->config_type) { case TMC_CONFIG_TYPE_ETB: case TMC_CONFIG_TYPE_ETF: @@ -179,19 +188,24 @@ ssize_t actual; struct tmc_drvdata *drvdata = container_of(file->private_data, struct tmc_drvdata, miscdev); + mutex_lock(&drvdata->mem_lock); actual = tmc_get_sysfs_trace(drvdata, *ppos, len, &bufp); - if (actual <= 0) + if (actual <= 0) { + mutex_unlock(&drvdata->mem_lock); return 0; + } if (copy_to_user(data, bufp, actual)) { dev_dbg(&drvdata->csdev->dev, "%s: copy_to_user failed\n", __func__); + mutex_unlock(&drvdata->mem_lock); return -EFAULT; } *ppos += actual; dev_dbg(&drvdata->csdev->dev, "%zu bytes copied\n", actual); + mutex_unlock(&drvdata->mem_lock); return actual; } @@ -319,7 +333,7 @@ { struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); - return sprintf(buf, "%#x\n", drvdata->size); + return scnprintf(buf, PAGE_SIZE, "%#x\n", drvdata->size); } static ssize_t buffer_size_store(struct device *dev, @@ -330,30 +344,129 @@ unsigned long val; struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + if (drvdata->enable) { + pr_err("ETR is in use, disable it to change the mem_size\n"); + return -EINVAL; + } /* Only permitted for TMC-ETRs */ if (drvdata->config_type != TMC_CONFIG_TYPE_ETR) return -EPERM; - ret = kstrtoul(buf, 0, &val); if (ret) return ret; /* The buffer size should be page aligned */ if (val & (PAGE_SIZE - 1)) return -EINVAL; + drvdata->size = val; return size; } static DEVICE_ATTR_RW(buffer_size); -static struct attribute *coresight_tmc_attrs[] = { +static ssize_t block_size_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + uint32_t val = 0; + + if (drvdata->byte_cntr) + val = drvdata->byte_cntr->block_size; + + return scnprintf(buf, PAGE_SIZE, "%d\n", + val); +} + +static ssize_t block_size_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (!drvdata->byte_cntr) + return -EINVAL; + + if (val && val < 4096) { + pr_err("Assign minimum block size of 4096 bytes\n"); + return -EINVAL; + } + + mutex_lock(&drvdata->byte_cntr->byte_cntr_lock); + drvdata->byte_cntr->block_size = val; + mutex_unlock(&drvdata->byte_cntr->byte_cntr_lock); + + return size; +} +static DEVICE_ATTR_RW(block_size); + +static ssize_t out_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return scnprintf(buf, PAGE_SIZE, "%s\n", + str_tmc_etr_out_mode[drvdata->out_mode]); +} + +static ssize_t out_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + char str[16] = ""; + int ret; + + if (strlen(buf) >= 16) + return -EINVAL; + if (sscanf(buf, "%16s", str) != 1) + return -EINVAL; + ret = tmc_etr_switch_mode(drvdata, str); + return ret ? ret : size; +} +static DEVICE_ATTR_RW(out_mode); + +static ssize_t available_out_modes_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(str_tmc_etr_out_mode); i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%s ", + str_tmc_etr_out_mode[i]); + + len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); + return len; +} +static DEVICE_ATTR_RO(available_out_modes); + +static struct attribute *coresight_tmc_etf_attrs[] = { + &dev_attr_trigger_cntr.attr, + NULL, +}; + +static struct attribute *coresight_tmc_etr_attrs[] = { &dev_attr_trigger_cntr.attr, &dev_attr_buffer_size.attr, + &dev_attr_block_size.attr, + &dev_attr_out_mode.attr, + &dev_attr_available_out_modes.attr, NULL, }; -static const struct attribute_group coresight_tmc_group = { - .attrs = coresight_tmc_attrs, +static const struct attribute_group coresight_tmc_etf_group = { + .attrs = coresight_tmc_etf_attrs, +}; + +static const struct attribute_group coresight_tmc_etr_group = { + .attrs = coresight_tmc_etr_attrs, }; static const struct attribute_group coresight_tmc_mgmt_group = { @@ -361,8 +474,14 @@ .name = "mgmt", }; -const struct attribute_group *coresight_tmc_groups[] = { - &coresight_tmc_group, +static const struct attribute_group *coresight_tmc_etf_groups[] = { + &coresight_tmc_etf_group, + &coresight_tmc_mgmt_group, + NULL, +}; + +static const struct attribute_group *coresight_tmc_etr_groups[] = { + &coresight_tmc_etr_group, &coresight_tmc_mgmt_group, NULL, }; @@ -431,6 +550,56 @@ return size; } +static void tmc_get_q6_etr_region(struct device *dev) +{ + struct device_node *np; + struct reserved_mem *rmem; + struct tmc_drvdata *drvdata = dev_get_drvdata(dev); + + np = of_parse_phandle(dev->of_node, "memory-region", 0); + if (!np) { + dev_info(dev, "No Q6 ETR memory region specified\n"); + return; + } + + rmem = of_reserved_mem_lookup(np); + of_node_put(np); + if (!rmem) { + dev_err(dev, "unable to acquire Q6 ETR memory-region\n"); + return; + } + + drvdata->q6_etr_vaddr = devm_ioremap_nocache(dev, rmem->base, + rmem->size); + if (drvdata->q6_etr_vaddr) { + drvdata->q6_etr_paddr = rmem->base; + drvdata->q6_size = rmem->size; + } +} + +static irqreturn_t etr_handler(int irq, void *data) +{ + struct tmc_drvdata *drvdata = data; + unsigned long flags; + + spin_lock_irqsave(&drvdata->spinlock, flags); + if (drvdata->out_mode == TMC_ETR_OUT_MODE_Q6MEM_STREAM) { + CS_UNLOCK(drvdata->base); + atomic_add(PAGES_PER_DATA, &drvdata->seq_no); + if (atomic_read(&drvdata->seq_no) > COMP_PAGES_PER_DATA) + tmc_disable_hw(drvdata); + else + tmc_enable_hw(drvdata); + schedule_work(&drvdata->qld_stream_work); + CS_LOCK(drvdata->base); + } + spin_unlock_irqrestore(&drvdata->spinlock, flags); + return IRQ_HANDLED; +} + +struct tmc_drvdata *tmc_drvdata_stream; +EXPORT_SYMBOL(tmc_drvdata_stream); + static int tmc_probe(struct amba_device *adev, const struct amba_id *id) { int ret = 0; @@ -442,12 +611,22 @@ struct resource *res = &adev->res; struct coresight_desc desc = { 0 }; struct coresight_dev_list *dev_list = NULL; + struct coresight_cti_data *ctidata; + int irq; + u32 in_funnel_addr[2]; ret = -ENOMEM; drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) goto out; + drvdata->etr_usb_clk = devm_clk_get(&adev->dev, "etr_usb_clk"); + if (!IS_ERR(drvdata->etr_usb_clk)) { + ret = clk_prepare_enable(drvdata->etr_usb_clk); + if (ret) + return ret; + } + dev_set_drvdata(dev, drvdata); /* Validity for the resource is already checked by the AMBA core */ @@ -460,6 +639,7 @@ drvdata->base = base; spin_lock_init(&drvdata->spinlock); + mutex_init(&drvdata->mem_lock); devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); drvdata->config_type = BMVAL(devid, 6, 7); @@ -467,36 +647,98 @@ /* This device is not associated with a session */ drvdata->pid = -1; - if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) + if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { + drvdata->out_mode = TMC_ETR_OUT_MODE_MEM; drvdata->size = tmc_etr_get_default_buffer_size(dev); - else + + tmc_get_q6_etr_region(dev); + } else { drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4; + } - desc.dev = dev; - desc.groups = coresight_tmc_groups; + ret = of_get_coresight_csr_name(adev->dev.of_node, &drvdata->csr_name); + if (ret) + dev_dbg(dev, "No csr data\n"); + else { + drvdata->csr = coresight_csr_get(drvdata->csr_name); + if (IS_ERR(drvdata->csr)) { + dev_dbg(dev, "failed to get csr, defer probe\n"); + return -EPROBE_DEFER; + } + } + + ctidata = of_get_coresight_cti_data(dev, adev->dev.of_node); + if (IS_ERR(ctidata)) { + dev_err(dev, "invalid cti data\n"); + } else if (ctidata && ctidata->nr_ctis == 2) { + drvdata->cti_flush = coresight_cti_get(ctidata->names[0]); + if (IS_ERR(drvdata->cti_flush)) { + dev_err(dev, "failed to get flush cti, defer probe\n"); + return -EPROBE_DEFER; + } + + drvdata->cti_reset = coresight_cti_get(ctidata->names[1]); + if (IS_ERR(drvdata->cti_reset)) { + dev_err(dev, "failed to get reset cti, defer probe\n"); + return -EPROBE_DEFER; + } + } + + if (!of_property_read_u32_array(adev->dev.of_node, "funnel-address", + in_funnel_addr, ARRAY_SIZE(in_funnel_addr))) { + drvdata->in_funnel_base = ioremap(in_funnel_addr[0], + in_funnel_addr[1]); + if(IS_ERR(drvdata->in_funnel_base)) + dev_err(dev, "unable to ioremap the funnel address\n"); + } + desc.dev = dev; switch (drvdata->config_type) { case TMC_CONFIG_TYPE_ETB: desc.type = CORESIGHT_DEV_TYPE_SINK; desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; + desc.groups = coresight_tmc_etf_groups; desc.ops = &tmc_etb_cs_ops; dev_list = &etb_devs; break; case TMC_CONFIG_TYPE_ETR: desc.type = CORESIGHT_DEV_TYPE_SINK; desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; + desc.groups = coresight_tmc_etr_groups; desc.ops = &tmc_etr_cs_ops; ret = tmc_etr_setup_caps(dev, devid, coresight_get_uci_data(id)); if (ret) goto out; + drvdata->byte_cntr = NULL; + irq = of_irq_get_byname(adev->dev.of_node, "byte-cntr-irq"); + if (irq > 0) { + if (devm_request_irq(dev, irq, etr_handler, + IRQF_TRIGGER_RISING | + IRQF_SHARED, + "tmc-etr", + drvdata)) + dev_err(dev, "Byte_cntr interrupt registration failed\n"); + } + atomic_set(&drvdata->completed_seq_no, 0); + atomic_set(&drvdata->seq_no, 0); + tmc_drvdata_stream = drvdata; + ret = tmc_etr_bam_init(adev, drvdata); + if (ret) + goto out; idr_init(&drvdata->idr); mutex_init(&drvdata->idr_mutex); dev_list = &etr_devs; + + if (!of_property_read_u32(dev->of_node, "csr-atid-offset", + &drvdata->atid_offset)) + coresight_set_csr_ops(&csr_atid_ops); + break; case TMC_CONFIG_TYPE_ETF: desc.type = CORESIGHT_DEV_TYPE_LINKSINK; desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO; + desc.groups = coresight_tmc_etf_groups; desc.ops = &tmc_etf_cs_ops; dev_list = &etf_devs; break; @@ -506,7 +748,8 @@ goto out; } - desc.name = coresight_alloc_device_name(dev_list, dev); + if (of_property_read_string(dev->of_node, "coresight-name", &desc.name)) + desc.name = coresight_alloc_device_name(dev_list, dev); if (!desc.name) { ret = -ENOMEM; goto out;