static void __etb_dump(void) { int i; uint8_t *buf_ptr; uint32_t read_data; uint32_t read_ptr; uint32_t write_ptr; ETB_UNLOCK(); read_ptr = etb_readl(etb, ETB_RAM_READ_POINTER); write_ptr = etb_readl(etb, ETB_RAM_WRITE_POINTER); if ((etb_readl(etb, ETB_STATUS_REG) & BIT(0)) == 0) etb_writel(etb, 0x0, ETB_RAM_READ_POINTER); else etb_writel(etb, write_ptr, ETB_RAM_READ_POINTER); buf_ptr = etb.buf; for (i = 0; i < ETB_SIZE_WORDS; i++) { read_data = etb_readl(etb, ETB_RAM_READ_DATA_REG); *buf_ptr = read_data >> 0; buf_ptr++; *buf_ptr = read_data >> 8; buf_ptr++; *buf_ptr = read_data >> 16; buf_ptr++; *buf_ptr = read_data >> 24; buf_ptr++; } etb_writel(etb, read_ptr, ETB_RAM_READ_POINTER); ETB_LOCK(); }
static void __etb_disable(void) { int count; uint32_t ffcr; ETB_UNLOCK(); ffcr = etb_readl(etb, ETB_FFCR); ffcr |= (BIT(12) | BIT(6)); etb_writel(etb, ffcr, ETB_FFCR); for (count = TIMEOUT_US; BVAL(etb_readl(etb, ETB_FFCR), 6) != 0 && count > 0; count--) udelay(1); WARN(count == 0, "timeout while flushing ETB, ETB_FFCR: %#x\n", etb_readl(etb, ETB_FFCR)); etb_writel(etb, 0x0, ETB_CTL_REG); for (count = TIMEOUT_US; BVAL(etb_readl(etb, ETB_FFSR), 1) != 1 && count > 0; count--) udelay(1); WARN(count == 0, "timeout while disabling ETB, ETB_FFSR: %#x\n", etb_readl(etb, ETB_FFSR)); ETB_LOCK(); }
static void __etb_disable(void) { int count; uint32_t ffcr; /* Avoid oopsing in panic() if called before the device is probed. */ if (!etb.base) return; ETB_UNLOCK(); ffcr = etb_readl(etb, ETB_FFCR); ffcr |= (BIT(12) | BIT(6)); etb_writel(etb, ffcr, ETB_FFCR); for (count = TIMEOUT_US; BVAL(etb_readl(etb, ETB_FFCR), 6) != 0 && count > 0; count--) udelay(1); WARN(count == 0, "timeout while flushing ETB, ETB_FFCR: %#x\n", etb_readl(etb, ETB_FFCR)); etb_writel(etb, 0x0, ETB_CTL_REG); for (count = TIMEOUT_US; BVAL(etb_readl(etb, ETB_FFSR), 1) != 1 && count > 0; count--) udelay(1); WARN(count == 0, "timeout while disabling ETB, ETB_FFSR: %#x\n", etb_readl(etb, ETB_FFSR)); ETB_LOCK(); }
int etb_get_data_length(const struct etm_trace_context_t *t) { unsigned int v; int rp, wp; v = etb_readl(t, ETBSTS); rp = etb_readl(t, ETBRRP); wp = etb_readl(t, ETBRWP); pr_info("ETB status = 0x%x, rp = 0x%x, wp = 0x%x\n", v, rp, wp); if (v & 1) { /* full */ return t->etb_total_buf_size; } else { if (t->use_etr) { if (wp == 0) { /* The trace is never started yet. Return 0 */ return 0; } else { return (wp - tracer.etr_phys) / 4; } } else { return wp; } } }
static void __etb_dump(void) { int i; uint8_t *buf_ptr; uint32_t read_data; uint32_t read_ptr; uint32_t write_ptr; uint32_t frame_off; uint32_t frame_endoff; ETB_UNLOCK(); read_ptr = etb_readl(etb, ETB_RAM_READ_POINTER); write_ptr = etb_readl(etb, ETB_RAM_WRITE_POINTER); frame_off = write_ptr % FRAME_SIZE_WORDS; frame_endoff = FRAME_SIZE_WORDS - frame_off; if (frame_off) { dev_err(etb.dev, "write_ptr: %lu not aligned to formatter " "frame size\n", (unsigned long)write_ptr); dev_err(etb.dev, "frameoff: %lu, frame_endoff: %lu\n", (unsigned long)frame_off, (unsigned long)frame_endoff); write_ptr += frame_endoff; } if ((etb_readl(etb, ETB_STATUS_REG) & BIT(0)) == 0) etb_writel(etb, 0x0, ETB_RAM_READ_POINTER); else etb_writel(etb, write_ptr, ETB_RAM_READ_POINTER); buf_ptr = etb.buf; for (i = 0; i < ETB_SIZE_WORDS; i++) { read_data = etb_readl(etb, ETB_RAM_READ_DATA_REG); *buf_ptr++ = read_data >> 0; *buf_ptr++ = read_data >> 8; *buf_ptr++ = read_data >> 16; *buf_ptr++ = read_data >> 24; } if (frame_off) { buf_ptr -= (frame_endoff * BYTES_PER_WORD); for (i = 0; i < frame_endoff; i++) { *buf_ptr++ = 0x0; *buf_ptr++ = 0x0; *buf_ptr++ = 0x0; *buf_ptr++ = 0x0; } } etb_writel(etb, read_ptr, ETB_RAM_READ_POINTER); ETB_LOCK(); }
static ssize_t etb_read(struct file *file, char __user *data, size_t len, loff_t *ppos) { int total, i; long length; struct tracectx *t = file->private_data; u32 first = 0; u32 *buf; mutex_lock(&t->mutex); if (trace_isrunning(t)) { length = 0; goto out; } etb_unlock(t); total = etb_getdatalen(t); if (total == t->etb_bufsz) first = etb_readl(t, ETBR_WRITEADDR); etb_writel(t, first, ETBR_READADDR); length = min(total * 4, (int)len); buf = vmalloc(length); dev_dbg(t->dev, "ETB buffer length: %d\n", total); dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS)); for (i = 0; i < length / 4; i++) buf[i] = etb_readl(t, ETBR_READMEM); /* the only way to deassert overflow bit in ETB status is this */ etb_writel(t, 1, ETBR_CTRL); etb_writel(t, 0, ETBR_CTRL); etb_writel(t, 0, ETBR_WRITEADDR); etb_writel(t, 0, ETBR_READADDR); etb_writel(t, 0, ETBR_TRIGGERCOUNT); etb_lock(t); length -= copy_to_user(data, buf, length); vfree(buf); out: mutex_unlock(&t->mutex); return length; }
static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id) { struct tracectx *t = &tracer; int ret = 0; ret = amba_request_regions(dev, NULL); if (ret) goto out; t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res)); if (!t->etb_regs) { ret = -ENOMEM; goto out_release; } amba_set_drvdata(dev, t); etb_miscdev.parent = &dev->dev; ret = misc_register(&etb_miscdev); if (ret) goto out_unmap; t->emu_clk = clk_get(&dev->dev, "emu_src_ck"); if (IS_ERR(t->emu_clk)) { dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n"); return -EFAULT; } clk_enable(t->emu_clk); etb_unlock(t); t->etb_bufsz = etb_readl(t, ETBR_DEPTH); dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz); /* make sure trace capture is disabled */ etb_writel(t, 0, ETBR_CTRL); etb_writel(t, 0x1000, ETBR_FORMATTERCTRL); etb_lock(t); dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n"); out: return ret; out_unmap: amba_set_drvdata(dev, NULL); iounmap(t->etb_regs); out_release: amba_release_regions(dev); return ret; }
/* sysrq+v will always stop the running trace and leave it at that */ static void etm_dump(void) { struct tracectx *t = &tracer; u32 first = 0; int length; if (!t->etb_regs) { printk(KERN_INFO "No tracing hardware found\n"); return; } if (trace_isrunning(t)) trace_stop(t); etb_unlock(t); length = etb_getdatalen(t); if (length == t->etb_bufsz) first = etb_readl(t, ETBR_WRITEADDR); etb_writel(t, first, ETBR_READADDR); printk(KERN_INFO "Trace buffer contents length: %d\n", length); printk(KERN_INFO "--- ETB buffer begin ---\n"); for (; length; length--) printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM))); printk(KERN_INFO "\n--- ETB buffer end ---\n"); /* deassert the overflow bit */ etb_writel(t, 1, ETBR_CTRL); etb_writel(t, 0, ETBR_CTRL); etb_writel(t, 0, ETBR_TRIGGERCOUNT); etb_writel(t, 0, ETBR_READADDR); etb_writel(t, 0, ETBR_WRITEADDR); etb_lock(t); }
static int etb_getdatalen(struct tracectx *t) { u32 v; int rp, wp; v = etb_readl(t, ETBR_STATUS); if (v & 1) return t->etb_bufsz; rp = etb_readl(t, ETBR_READADDR); wp = etb_readl(t, ETBR_WRITEADDR); if (rp > wp) { etb_writel(t, 0, ETBR_READADDR); etb_writel(t, 0, ETBR_WRITEADDR); return 0; } return wp - rp; }
static ssize_t trace_info_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st; int datalen; etb_unlock(&tracer); datalen = etb_getdatalen(&tracer); etb_wa = etb_readl(&tracer, ETBR_WRITEADDR); etb_ra = etb_readl(&tracer, ETBR_READADDR); etb_st = etb_readl(&tracer, ETBR_STATUS); etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL); etb_lock(&tracer); etm_unlock(&tracer); etm_ctrl = etm_readl(&tracer, ETMR_CTRL); etm_st = etm_readl(&tracer, ETMR_STATUS); etm_lock(&tracer); return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n" "ETBR_WRITEADDR:\t%08x\n" "ETBR_READADDR:\t%08x\n" "ETBR_STATUS:\t%08x\n" "ETBR_FORMATTERCTRL:\t%08x\n" "ETMR_CTRL:\t%08x\n" "ETMR_STATUS:\t%08x\n", datalen, tracer.ncmppairs, etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st ); }
static void __etb_disable(void) { int count; ETB_UNLOCK(); etb_writel(etb, BIT(12) | BIT(13), ETB_FFCR); etb_writel(etb, 0x0, ETB_CTL_REG); for (count = TIMEOUT_US; BVAL(etb_readl(etb, ETB_FFSR), 1) != 1 && count > 0; count--) udelay(1); WARN(count == 0, "timeout while disabling etb\n"); ETB_LOCK(); }
static int etb_probe(struct platform_device *pdev) { struct etb_driver_data *data = dev_get_platdata(&pdev->dev); mutex_lock(&tracer.mutex); tracer.etb_regs = data->etb_regs; tracer.funnel_regs = data->funnel_regs; tracer.tpiu_regs = data->tpiu_regs; tracer.dem_regs = data->dem_regs; tracer.etr_virt = data->etr_virt; tracer.etr_phys = data->etr_phys; tracer.etr_len = data->etr_len; tracer.use_etr = data->use_etr; if (unlikely(misc_register(&etb_device) != 0)) { pr_err("Fail to register etb device\n"); } /* AHBAP_EN to enable master port, then ETR could write the trace to bus */ __raw_writel(DEM_UNLOCK_MAGIC, DEM_UNLOCK); mt65xx_reg_sync_writel(AHB_EN, AHBAP_EN); etb_unlock(&tracer); if (tracer.use_etr) { pr_info("ETR virt = 0x%x, phys = 0x%x\n", tracer.etr_virt, tracer.etr_phys); /* Set up ETR memory buffer address */ etb_writel(&tracer, tracer.etr_phys, 0x118); /* Set up ETR memory buffer size */ etb_writel(&tracer, tracer.etr_len, 0x4); } /* Disable ETB capture (ETB_CTL bit0 = 0x0) */ /* For wdt reset */ cs_cpu_write(tracer.etb_regs, 0x20, 0x0); tracer.etb_total_buf_size = etb_readl(&tracer, ETBRDP); tracer.state = TRACE_STATE_STOP; mutex_unlock(&tracer.mutex); return 0; }
static int trace_stop(struct tracectx *t) { unsigned long timeout = TRACER_TIMEOUT; etm_unlock(t); etm_writel(t, 0x440, ETMR_CTRL); while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout) ; if (!timeout) { dev_dbg(t->dev, "Waiting for progbit to assert timed out\n"); etm_lock(t); return -EFAULT; } etm_lock(t); etb_unlock(t); etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL); timeout = TRACER_TIMEOUT; while (etb_readl(t, ETBR_FORMATTERCTRL) & ETBFF_MANUAL_FLUSH && --timeout) ; if (!timeout) { dev_dbg(t->dev, "Waiting for formatter flush to commence " "timed out\n"); etb_lock(t); return -EFAULT; } etb_writel(t, 0, ETBR_CTRL); etb_lock(t); t->flags &= ~TRACER_RUNNING; return 0; }
static ssize_t etb_read(struct file *file, char __user *data, size_t len, loff_t *ppos) { int total, i; long length; struct etm_trace_context_t *t = file->private_data; u32 first = 0, buffer_end = 0; u32 *buf; int wpos; int skip; long wlength; loff_t pos = *ppos; mutex_lock(&t->mutex); if (t->state == TRACE_STATE_TRACING) { length = 0; pr_err("Need to stop trace\n"); goto out; } etb_unlock(t); total = etb_get_data_length(t); if (total == t->etb_total_buf_size) { first = etb_readl(t, ETBRWP); if (t->use_etr) { first = (first - t->etr_phys) / 4; } } if (pos > total * 4) { skip = 0; wpos = total; } else { skip = (int)pos % 4; wpos = (int)pos / 4; } total -= wpos; first = (first + wpos) % t->etb_total_buf_size; etb_writel(t, first, ETBRRP); wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4)); length = min(total * 4 - skip, (int)len); if (wlength == 0) { goto out; } buf = vmalloc(wlength * 4); pr_info("ETB read %ld bytes to %lld from %ld words at %d\n", length, pos, wlength, first); pr_info("ETB buffer length: %d\n", total + wpos); pr_info("ETB status reg: 0x%x\n", etb_readl(t, ETBSTS)); if (t->use_etr) { /* * XXX: ETBRRP cannot wrap around correctly on ETR. * The workaround is to read the buffer from WTBRWP directly. */ pr_info("ETR virt = 0x%x, phys = 0x%x\n", t->etr_virt, t->etr_phys); /* translate first and buffer_end from phys to virt */ first *= 4; first += t->etr_virt; buffer_end = t->etr_virt + (t->etr_len * 4); pr_info("first(virt) = 0x%x\n\n", first); for (i = 0; i < wlength; i++) { buf[i] = *((unsigned int*)(first)); first += 4; if (first >= buffer_end) { first = t->etr_virt; } } } else { for (i = 0; i < wlength; i++) { buf[i] = etb_readl(t, ETBRRD); } } etb_lock(t); length -= copy_to_user(data, (u8 *)buf + skip, length); vfree(buf); *ppos = pos + length; out: mutex_unlock(&t->mutex); return length; }
/** * check whether ETB registers are locked * @param ctx trace context * @return 1:locked, 0:aren't */ int etb_is_locked(const struct etm_trace_context_t *ctx) { return etb_readl(ctx, ETBLS) & 0x2; }
/** * check whether ETB supports lock * @param ctx trace context * @return 1:supports lock, 0:doesn't */ int etb_supports_lock(const struct etm_trace_context_t *ctx) { return etb_readl(ctx, ETBLS) & 0x1; }