Loading drivers/hwtracing/coresight/coresight-tmc-etr.c +202 −1 Original line number Diff line number Diff line Loading @@ -495,7 +495,7 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata) } } static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) { CS_UNLOCK(drvdata->base); Loading Loading @@ -557,6 +557,207 @@ static void tmc_etr_free_mem(struct tmc_drvdata *drvdata) } } static void tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; get_qdss_bam_connection_info(&bamdata->dest, &bamdata->dest_pipe_idx, &bamdata->src_pipe_idx, &bamdata->desc_fifo, &bamdata->data_fifo, NULL); } static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; uint32_t axictl; if (drvdata->enable_to_bam) return; /* Configure and enable required CSR registers */ msm_qdss_csr_enable_bam_to_usb(); /* Configure and enable ETR for usb bam output */ CS_UNLOCK(drvdata->base); writel_relaxed(bamdata->data_fifo.size / 4, drvdata->base + TMC_RSZ); writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); axictl = readl_relaxed(drvdata->base + TMC_AXICTL); axictl |= (0xF << 8); writel_relaxed(axictl, drvdata->base + TMC_AXICTL); axictl &= ~(0x1 << 7); writel_relaxed(axictl, drvdata->base + TMC_AXICTL); axictl = (axictl & ~0x3) | 0x2; writel_relaxed(axictl, drvdata->base + TMC_AXICTL); writel_relaxed((uint32_t)bamdata->data_fifo.phys_base, drvdata->base + TMC_DBALO); writel_relaxed((((uint64_t)bamdata->data_fifo.phys_base) >> 32) & 0xFF, drvdata->base + TMC_DBAHI); /* Set FOnFlIn for periodic flush */ writel_relaxed(0x133, drvdata->base + TMC_FFCR); writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG); tmc_enable_hw(drvdata); CS_LOCK(drvdata->base); drvdata->enable_to_bam = true; } static int tmc_etr_bam_enable(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; int ret; if (bamdata->enable) return 0; /* Reset bam to start with */ ret = sps_device_reset(bamdata->handle); if (ret) goto err0; /* Now configure and enable bam */ bamdata->pipe = sps_alloc_endpoint(); if (!bamdata->pipe) return -ENOMEM; ret = sps_get_config(bamdata->pipe, &bamdata->connect); if (ret) goto err1; bamdata->connect.mode = SPS_MODE_SRC; bamdata->connect.source = bamdata->handle; bamdata->connect.event_thresh = 0x4; bamdata->connect.src_pipe_index = TMC_ETR_BAM_PIPE_INDEX; bamdata->connect.options = SPS_O_AUTO_ENABLE; bamdata->connect.destination = bamdata->dest; bamdata->connect.dest_pipe_index = bamdata->dest_pipe_idx; bamdata->connect.desc = bamdata->desc_fifo; bamdata->connect.data = bamdata->data_fifo; ret = sps_connect(bamdata->pipe, &bamdata->connect); if (ret) goto err1; bamdata->enable = true; return 0; err1: sps_free_endpoint(bamdata->pipe); err0: return ret; } static void tmc_wait_for_flush(struct tmc_drvdata *drvdata) { int count; /* Ensure no flush is in progress */ for (count = TIMEOUT_US; BVAL(readl_relaxed(drvdata->base + TMC_FFSR), 0) != 0 && count > 0; count--) udelay(1); WARN(count == 0, "timeout while waiting for TMC flush, TMC_FFSR: %#x\n", readl_relaxed(drvdata->base + TMC_FFSR)); } void __tmc_etr_disable_to_bam(struct tmc_drvdata *drvdata) { if (!drvdata->enable_to_bam) return; /* Ensure periodic flush is disabled in CSR block */ msm_qdss_csr_disable_flush(); CS_UNLOCK(drvdata->base); tmc_wait_for_flush(drvdata); tmc_disable_hw(drvdata); CS_LOCK(drvdata); /* Disable CSR configuration */ msm_qdss_csr_disable_bam_to_usb(); drvdata->enable_to_bam = false; } void tmc_etr_bam_disable(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; if (!bamdata->enable) return; sps_disconnect(bamdata->pipe); sps_free_endpoint(bamdata->pipe); bamdata->enable = false; } void usb_notifier(void *priv, unsigned int event, struct qdss_request *d_req, struct usb_qdss_ch *ch) { struct tmc_drvdata *drvdata = priv; unsigned long flags; int ret = 0; mutex_lock(&drvdata->mem_lock); if (event == USB_QDSS_CONNECT) { tmc_etr_fill_usb_bam_data(drvdata); ret = tmc_etr_bam_enable(drvdata); if (ret) dev_err(drvdata->dev, "ETR BAM enable failed\n"); spin_lock_irqsave(&drvdata->spinlock, flags); __tmc_etr_enable_to_bam(drvdata); spin_unlock_irqrestore(&drvdata->spinlock, flags); } else if (event == USB_QDSS_DISCONNECT) { spin_lock_irqsave(&drvdata->spinlock, flags); __tmc_etr_disable_to_bam(drvdata); spin_unlock_irqrestore(&drvdata->spinlock, flags); tmc_etr_bam_disable(drvdata); } mutex_unlock(&drvdata->mem_lock); } int tmc_etr_bam_init(struct amba_device *adev, struct tmc_drvdata *drvdata) { int ret; struct device *dev = &adev->dev; struct resource res; struct tmc_etr_bam_data *bamdata; bamdata = devm_kzalloc(dev, sizeof(*bamdata), GFP_KERNEL); if (!bamdata) return -ENOMEM; drvdata->bamdata = bamdata; ret = of_address_to_resource(adev->dev.of_node, 1, &res); if (ret) return -ENODEV; bamdata->props.phys_addr = res.start; bamdata->props.virt_addr = devm_ioremap(dev, res.start, resource_size(&res)); if (!bamdata->props.virt_addr) return -ENOMEM; bamdata->props.virt_size = resource_size(&res); bamdata->props.event_threshold = 0x4; /* Pipe event threshold */ bamdata->props.summing_threshold = 0x10; /* BAM event threshold */ bamdata->props.irq = 0; bamdata->props.num_pipes = TMC_ETR_BAM_NR_PIPES; return sps_register_bam_device(&bamdata->props, &bamdata->handle); } static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 mode) { int ret = 0; Loading drivers/hwtracing/coresight/coresight-tmc.c +102 −0 Original line number Diff line number Diff line Loading @@ -63,11 +63,13 @@ void tmc_flush_and_stop(struct tmc_drvdata *drvdata) void tmc_enable_hw(struct tmc_drvdata *drvdata) { drvdata->enable = true; writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL); } void tmc_disable_hw(struct tmc_drvdata *drvdata) { drvdata->enable = false; writel_relaxed(0x0, drvdata->base + TMC_CTL); } Loading Loading @@ -309,6 +311,100 @@ static ssize_t mem_size_store(struct device *dev, } static DEVICE_ATTR_RW(mem_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[10] = ""; unsigned long flags; int ret; if (strlen(buf) >= 10) return -EINVAL; if (sscanf(buf, "%10s", str) != 1) return -EINVAL; mutex_lock(&drvdata->mem_lock); if (!strcmp(str, str_tmc_etr_out_mode[TMC_ETR_OUT_MODE_MEM])) { if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) goto out; spin_lock_irqsave(&drvdata->spinlock, flags); if (!drvdata->enable) { drvdata->out_mode = TMC_ETR_OUT_MODE_MEM; spin_unlock_irqrestore(&drvdata->spinlock, flags); goto out; } __tmc_etr_disable_to_bam(drvdata); tmc_etr_enable_hw(drvdata); drvdata->out_mode = TMC_ETR_OUT_MODE_MEM; spin_unlock_irqrestore(&drvdata->spinlock, flags); tmc_etr_bam_disable(drvdata); usb_qdss_close(drvdata->usbch); } else if (!strcmp(str, str_tmc_etr_out_mode[TMC_ETR_OUT_MODE_USB])) { if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) goto out; spin_lock_irqsave(&drvdata->spinlock, flags); if (!drvdata->enable) { drvdata->out_mode = TMC_ETR_OUT_MODE_USB; spin_unlock_irqrestore(&drvdata->spinlock, flags); goto out; } if (drvdata->reading) { ret = -EBUSY; goto err1; } tmc_etr_disable_hw(drvdata); drvdata->out_mode = TMC_ETR_OUT_MODE_USB; spin_unlock_irqrestore(&drvdata->spinlock, flags); drvdata->usbch = usb_qdss_open("qdss", drvdata, usb_notifier); if (IS_ERR(drvdata->usbch)) { dev_err(drvdata->dev, "usb_qdss_open failed\n"); ret = PTR_ERR(drvdata->usbch); goto err0; } } out: mutex_unlock(&drvdata->mem_lock); return size; err1: spin_unlock_irqrestore(&drvdata->spinlock, flags); err0: mutex_unlock(&drvdata->mem_lock); return ret; } 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 ssize_t mem_type_show(struct device *dev, struct device_attribute *attr, char *buf) Loading Loading @@ -355,6 +451,8 @@ static struct attribute *coresight_tmc_etr_attrs[] = { &dev_attr_mem_size.attr, &dev_attr_mem_type.attr, &dev_attr_trigger_cntr.attr, &dev_attr_out_mode.attr, &dev_attr_available_out_modes.attr, NULL, }; Loading Loading @@ -460,6 +558,10 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) desc.ops = &tmc_etr_cs_ops; desc.groups = coresight_tmc_etr_groups; desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; ret = tmc_etr_bam_init(adev, drvdata); if (ret) goto out; } else { desc.type = CORESIGHT_DEV_TYPE_LINKSINK; desc.ops = &tmc_etf_cs_ops; Loading drivers/hwtracing/coresight/coresight-tmc.h +45 −0 Original line number Diff line number Diff line Loading @@ -19,7 +19,12 @@ #define _CORESIGHT_TMC_H #include <linux/miscdevice.h> #include <linux/delay.h> #include <asm/cacheflush.h> #include <linux/of_address.h> #include <linux/amba/bus.h> #include <linux/usb_bam.h> #include <linux/usb/usb_qdss.h> #define TMC_RSZ 0x004 #define TMC_STS 0x00c Loading Loading @@ -77,6 +82,8 @@ #define TMC_ETR_SG_NXT_TBL(phys_pte) (((phys_pte >> PAGE_SHIFT) << 4) | 0x3) #define TMC_ETR_SG_LST_ENT(phys_pte) (((phys_pte >> PAGE_SHIFT) << 4) | 0x1) #define TMC_ETR_BAM_PIPE_INDEX 0 #define TMC_ETR_BAM_NR_PIPES 2 enum tmc_config_type { TMC_CONFIG_TYPE_ETB, Loading Loading @@ -107,6 +114,30 @@ static const char * const str_tmc_etr_mem_type[] = { [TMC_ETR_MEM_TYPE_SG] = "sg", }; enum tmc_etr_out_mode { TMC_ETR_OUT_MODE_NONE, TMC_ETR_OUT_MODE_MEM, TMC_ETR_OUT_MODE_USB, }; static const char * const str_tmc_etr_out_mode[] = { [TMC_ETR_OUT_MODE_NONE] = "none", [TMC_ETR_OUT_MODE_MEM] = "mem", [TMC_ETR_OUT_MODE_USB] = "usb", }; struct tmc_etr_bam_data { struct sps_bam_props props; unsigned long handle; struct sps_pipe *pipe; struct sps_connect connect; uint32_t src_pipe_idx; unsigned long dest; uint32_t dest_pipe_idx; struct sps_mem_buffer desc_fifo; struct sps_mem_buffer data_fifo; bool enable; }; /** * struct tmc_drvdata - specifics associated to an TMC component Loading @@ -132,6 +163,7 @@ struct tmc_drvdata { struct miscdevice miscdev; spinlock_t spinlock; bool reading; bool enable; char *buf; dma_addr_t paddr; void __iomem *vaddr; Loading @@ -147,6 +179,11 @@ struct tmc_drvdata { enum tmc_etr_mem_type memtype; u32 delta_bottom; int sg_blk_num; enum tmc_etr_out_mode out_mode; struct usb_qdss_ch *usbch; struct tmc_etr_bam_data *bamdata; bool enable_to_bam; }; /* Generic functions */ Loading @@ -166,5 +203,13 @@ void tmc_etr_sg_compute_read(struct tmc_drvdata *drvdata, loff_t *ppos, char **bufpp, size_t *len); int tmc_read_prepare_etr(struct tmc_drvdata *drvdata); int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata); void __tmc_etr_disable_to_bam(struct tmc_drvdata *drvdata); void tmc_etr_bam_disable(struct tmc_drvdata *drvdata); void tmc_etr_enable_hw(struct tmc_drvdata *drvdata); void tmc_etr_disable_hw(struct tmc_drvdata *drvdata); void usb_notifier(void *priv, unsigned int event, struct qdss_request *d_req, struct usb_qdss_ch *ch); int tmc_etr_bam_init(struct amba_device *adev, struct tmc_drvdata *drvdata); extern const struct coresight_ops tmc_etr_cs_ops; #endif Loading
drivers/hwtracing/coresight/coresight-tmc-etr.c +202 −1 Original line number Diff line number Diff line Loading @@ -495,7 +495,7 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata) } } static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) { CS_UNLOCK(drvdata->base); Loading Loading @@ -557,6 +557,207 @@ static void tmc_etr_free_mem(struct tmc_drvdata *drvdata) } } static void tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; get_qdss_bam_connection_info(&bamdata->dest, &bamdata->dest_pipe_idx, &bamdata->src_pipe_idx, &bamdata->desc_fifo, &bamdata->data_fifo, NULL); } static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; uint32_t axictl; if (drvdata->enable_to_bam) return; /* Configure and enable required CSR registers */ msm_qdss_csr_enable_bam_to_usb(); /* Configure and enable ETR for usb bam output */ CS_UNLOCK(drvdata->base); writel_relaxed(bamdata->data_fifo.size / 4, drvdata->base + TMC_RSZ); writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); axictl = readl_relaxed(drvdata->base + TMC_AXICTL); axictl |= (0xF << 8); writel_relaxed(axictl, drvdata->base + TMC_AXICTL); axictl &= ~(0x1 << 7); writel_relaxed(axictl, drvdata->base + TMC_AXICTL); axictl = (axictl & ~0x3) | 0x2; writel_relaxed(axictl, drvdata->base + TMC_AXICTL); writel_relaxed((uint32_t)bamdata->data_fifo.phys_base, drvdata->base + TMC_DBALO); writel_relaxed((((uint64_t)bamdata->data_fifo.phys_base) >> 32) & 0xFF, drvdata->base + TMC_DBAHI); /* Set FOnFlIn for periodic flush */ writel_relaxed(0x133, drvdata->base + TMC_FFCR); writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG); tmc_enable_hw(drvdata); CS_LOCK(drvdata->base); drvdata->enable_to_bam = true; } static int tmc_etr_bam_enable(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; int ret; if (bamdata->enable) return 0; /* Reset bam to start with */ ret = sps_device_reset(bamdata->handle); if (ret) goto err0; /* Now configure and enable bam */ bamdata->pipe = sps_alloc_endpoint(); if (!bamdata->pipe) return -ENOMEM; ret = sps_get_config(bamdata->pipe, &bamdata->connect); if (ret) goto err1; bamdata->connect.mode = SPS_MODE_SRC; bamdata->connect.source = bamdata->handle; bamdata->connect.event_thresh = 0x4; bamdata->connect.src_pipe_index = TMC_ETR_BAM_PIPE_INDEX; bamdata->connect.options = SPS_O_AUTO_ENABLE; bamdata->connect.destination = bamdata->dest; bamdata->connect.dest_pipe_index = bamdata->dest_pipe_idx; bamdata->connect.desc = bamdata->desc_fifo; bamdata->connect.data = bamdata->data_fifo; ret = sps_connect(bamdata->pipe, &bamdata->connect); if (ret) goto err1; bamdata->enable = true; return 0; err1: sps_free_endpoint(bamdata->pipe); err0: return ret; } static void tmc_wait_for_flush(struct tmc_drvdata *drvdata) { int count; /* Ensure no flush is in progress */ for (count = TIMEOUT_US; BVAL(readl_relaxed(drvdata->base + TMC_FFSR), 0) != 0 && count > 0; count--) udelay(1); WARN(count == 0, "timeout while waiting for TMC flush, TMC_FFSR: %#x\n", readl_relaxed(drvdata->base + TMC_FFSR)); } void __tmc_etr_disable_to_bam(struct tmc_drvdata *drvdata) { if (!drvdata->enable_to_bam) return; /* Ensure periodic flush is disabled in CSR block */ msm_qdss_csr_disable_flush(); CS_UNLOCK(drvdata->base); tmc_wait_for_flush(drvdata); tmc_disable_hw(drvdata); CS_LOCK(drvdata); /* Disable CSR configuration */ msm_qdss_csr_disable_bam_to_usb(); drvdata->enable_to_bam = false; } void tmc_etr_bam_disable(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; if (!bamdata->enable) return; sps_disconnect(bamdata->pipe); sps_free_endpoint(bamdata->pipe); bamdata->enable = false; } void usb_notifier(void *priv, unsigned int event, struct qdss_request *d_req, struct usb_qdss_ch *ch) { struct tmc_drvdata *drvdata = priv; unsigned long flags; int ret = 0; mutex_lock(&drvdata->mem_lock); if (event == USB_QDSS_CONNECT) { tmc_etr_fill_usb_bam_data(drvdata); ret = tmc_etr_bam_enable(drvdata); if (ret) dev_err(drvdata->dev, "ETR BAM enable failed\n"); spin_lock_irqsave(&drvdata->spinlock, flags); __tmc_etr_enable_to_bam(drvdata); spin_unlock_irqrestore(&drvdata->spinlock, flags); } else if (event == USB_QDSS_DISCONNECT) { spin_lock_irqsave(&drvdata->spinlock, flags); __tmc_etr_disable_to_bam(drvdata); spin_unlock_irqrestore(&drvdata->spinlock, flags); tmc_etr_bam_disable(drvdata); } mutex_unlock(&drvdata->mem_lock); } int tmc_etr_bam_init(struct amba_device *adev, struct tmc_drvdata *drvdata) { int ret; struct device *dev = &adev->dev; struct resource res; struct tmc_etr_bam_data *bamdata; bamdata = devm_kzalloc(dev, sizeof(*bamdata), GFP_KERNEL); if (!bamdata) return -ENOMEM; drvdata->bamdata = bamdata; ret = of_address_to_resource(adev->dev.of_node, 1, &res); if (ret) return -ENODEV; bamdata->props.phys_addr = res.start; bamdata->props.virt_addr = devm_ioremap(dev, res.start, resource_size(&res)); if (!bamdata->props.virt_addr) return -ENOMEM; bamdata->props.virt_size = resource_size(&res); bamdata->props.event_threshold = 0x4; /* Pipe event threshold */ bamdata->props.summing_threshold = 0x10; /* BAM event threshold */ bamdata->props.irq = 0; bamdata->props.num_pipes = TMC_ETR_BAM_NR_PIPES; return sps_register_bam_device(&bamdata->props, &bamdata->handle); } static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 mode) { int ret = 0; Loading
drivers/hwtracing/coresight/coresight-tmc.c +102 −0 Original line number Diff line number Diff line Loading @@ -63,11 +63,13 @@ void tmc_flush_and_stop(struct tmc_drvdata *drvdata) void tmc_enable_hw(struct tmc_drvdata *drvdata) { drvdata->enable = true; writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL); } void tmc_disable_hw(struct tmc_drvdata *drvdata) { drvdata->enable = false; writel_relaxed(0x0, drvdata->base + TMC_CTL); } Loading Loading @@ -309,6 +311,100 @@ static ssize_t mem_size_store(struct device *dev, } static DEVICE_ATTR_RW(mem_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[10] = ""; unsigned long flags; int ret; if (strlen(buf) >= 10) return -EINVAL; if (sscanf(buf, "%10s", str) != 1) return -EINVAL; mutex_lock(&drvdata->mem_lock); if (!strcmp(str, str_tmc_etr_out_mode[TMC_ETR_OUT_MODE_MEM])) { if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) goto out; spin_lock_irqsave(&drvdata->spinlock, flags); if (!drvdata->enable) { drvdata->out_mode = TMC_ETR_OUT_MODE_MEM; spin_unlock_irqrestore(&drvdata->spinlock, flags); goto out; } __tmc_etr_disable_to_bam(drvdata); tmc_etr_enable_hw(drvdata); drvdata->out_mode = TMC_ETR_OUT_MODE_MEM; spin_unlock_irqrestore(&drvdata->spinlock, flags); tmc_etr_bam_disable(drvdata); usb_qdss_close(drvdata->usbch); } else if (!strcmp(str, str_tmc_etr_out_mode[TMC_ETR_OUT_MODE_USB])) { if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) goto out; spin_lock_irqsave(&drvdata->spinlock, flags); if (!drvdata->enable) { drvdata->out_mode = TMC_ETR_OUT_MODE_USB; spin_unlock_irqrestore(&drvdata->spinlock, flags); goto out; } if (drvdata->reading) { ret = -EBUSY; goto err1; } tmc_etr_disable_hw(drvdata); drvdata->out_mode = TMC_ETR_OUT_MODE_USB; spin_unlock_irqrestore(&drvdata->spinlock, flags); drvdata->usbch = usb_qdss_open("qdss", drvdata, usb_notifier); if (IS_ERR(drvdata->usbch)) { dev_err(drvdata->dev, "usb_qdss_open failed\n"); ret = PTR_ERR(drvdata->usbch); goto err0; } } out: mutex_unlock(&drvdata->mem_lock); return size; err1: spin_unlock_irqrestore(&drvdata->spinlock, flags); err0: mutex_unlock(&drvdata->mem_lock); return ret; } 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 ssize_t mem_type_show(struct device *dev, struct device_attribute *attr, char *buf) Loading Loading @@ -355,6 +451,8 @@ static struct attribute *coresight_tmc_etr_attrs[] = { &dev_attr_mem_size.attr, &dev_attr_mem_type.attr, &dev_attr_trigger_cntr.attr, &dev_attr_out_mode.attr, &dev_attr_available_out_modes.attr, NULL, }; Loading Loading @@ -460,6 +558,10 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) desc.ops = &tmc_etr_cs_ops; desc.groups = coresight_tmc_etr_groups; desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; ret = tmc_etr_bam_init(adev, drvdata); if (ret) goto out; } else { desc.type = CORESIGHT_DEV_TYPE_LINKSINK; desc.ops = &tmc_etf_cs_ops; Loading
drivers/hwtracing/coresight/coresight-tmc.h +45 −0 Original line number Diff line number Diff line Loading @@ -19,7 +19,12 @@ #define _CORESIGHT_TMC_H #include <linux/miscdevice.h> #include <linux/delay.h> #include <asm/cacheflush.h> #include <linux/of_address.h> #include <linux/amba/bus.h> #include <linux/usb_bam.h> #include <linux/usb/usb_qdss.h> #define TMC_RSZ 0x004 #define TMC_STS 0x00c Loading Loading @@ -77,6 +82,8 @@ #define TMC_ETR_SG_NXT_TBL(phys_pte) (((phys_pte >> PAGE_SHIFT) << 4) | 0x3) #define TMC_ETR_SG_LST_ENT(phys_pte) (((phys_pte >> PAGE_SHIFT) << 4) | 0x1) #define TMC_ETR_BAM_PIPE_INDEX 0 #define TMC_ETR_BAM_NR_PIPES 2 enum tmc_config_type { TMC_CONFIG_TYPE_ETB, Loading Loading @@ -107,6 +114,30 @@ static const char * const str_tmc_etr_mem_type[] = { [TMC_ETR_MEM_TYPE_SG] = "sg", }; enum tmc_etr_out_mode { TMC_ETR_OUT_MODE_NONE, TMC_ETR_OUT_MODE_MEM, TMC_ETR_OUT_MODE_USB, }; static const char * const str_tmc_etr_out_mode[] = { [TMC_ETR_OUT_MODE_NONE] = "none", [TMC_ETR_OUT_MODE_MEM] = "mem", [TMC_ETR_OUT_MODE_USB] = "usb", }; struct tmc_etr_bam_data { struct sps_bam_props props; unsigned long handle; struct sps_pipe *pipe; struct sps_connect connect; uint32_t src_pipe_idx; unsigned long dest; uint32_t dest_pipe_idx; struct sps_mem_buffer desc_fifo; struct sps_mem_buffer data_fifo; bool enable; }; /** * struct tmc_drvdata - specifics associated to an TMC component Loading @@ -132,6 +163,7 @@ struct tmc_drvdata { struct miscdevice miscdev; spinlock_t spinlock; bool reading; bool enable; char *buf; dma_addr_t paddr; void __iomem *vaddr; Loading @@ -147,6 +179,11 @@ struct tmc_drvdata { enum tmc_etr_mem_type memtype; u32 delta_bottom; int sg_blk_num; enum tmc_etr_out_mode out_mode; struct usb_qdss_ch *usbch; struct tmc_etr_bam_data *bamdata; bool enable_to_bam; }; /* Generic functions */ Loading @@ -166,5 +203,13 @@ void tmc_etr_sg_compute_read(struct tmc_drvdata *drvdata, loff_t *ppos, char **bufpp, size_t *len); int tmc_read_prepare_etr(struct tmc_drvdata *drvdata); int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata); void __tmc_etr_disable_to_bam(struct tmc_drvdata *drvdata); void tmc_etr_bam_disable(struct tmc_drvdata *drvdata); void tmc_etr_enable_hw(struct tmc_drvdata *drvdata); void tmc_etr_disable_hw(struct tmc_drvdata *drvdata); void usb_notifier(void *priv, unsigned int event, struct qdss_request *d_req, struct usb_qdss_ch *ch); int tmc_etr_bam_init(struct amba_device *adev, struct tmc_drvdata *drvdata); extern const struct coresight_ops tmc_etr_cs_ops; #endif