| .. | .. |
|---|
| 205 | 205 | * started state. ARM recommends start-stop logic is set before |
|---|
| 206 | 206 | * each trace run. |
|---|
| 207 | 207 | */ |
|---|
| 208 | | - config->vinst_ctrl |= BIT(0); |
|---|
| 209 | | - if (drvdata->nr_addr_cmp == true) { |
|---|
| 208 | + config->vinst_ctrl = BIT(0); |
|---|
| 209 | + if (drvdata->nr_addr_cmp > 0) { |
|---|
| 210 | 210 | config->mode |= ETM_MODE_VIEWINST_STARTSTOP; |
|---|
| 211 | 211 | /* SSSTATUS, bit[9] */ |
|---|
| 212 | 212 | config->vinst_ctrl |= BIT(9); |
|---|
| .. | .. |
|---|
| 217 | 217 | |
|---|
| 218 | 218 | /* No start-stop filtering for ViewInst */ |
|---|
| 219 | 219 | config->vissctlr = 0x0; |
|---|
| 220 | + config->vipcssctlr = 0x0; |
|---|
| 220 | 221 | |
|---|
| 221 | 222 | /* Disable seq events */ |
|---|
| 222 | 223 | for (i = 0; i < drvdata->nrseqstate-1; i++) |
|---|
| .. | .. |
|---|
| 235 | 236 | } |
|---|
| 236 | 237 | |
|---|
| 237 | 238 | config->res_idx = 0x0; |
|---|
| 238 | | - for (i = 0; i < drvdata->nr_resource; i++) |
|---|
| 239 | + for (i = 2; i < 2 * drvdata->nr_resource; i++) |
|---|
| 239 | 240 | config->res_ctrl[i] = 0x0; |
|---|
| 240 | 241 | |
|---|
| 242 | + config->ss_idx = 0x0; |
|---|
| 241 | 243 | for (i = 0; i < drvdata->nr_ss_cmp; i++) { |
|---|
| 242 | 244 | config->ss_ctrl[i] = 0x0; |
|---|
| 243 | 245 | config->ss_pe_cmp[i] = 0x0; |
|---|
| .. | .. |
|---|
| 296 | 298 | |
|---|
| 297 | 299 | spin_lock(&drvdata->spinlock); |
|---|
| 298 | 300 | config->mode = val & ETMv4_MODE_ALL; |
|---|
| 299 | | - |
|---|
| 300 | | - if (config->mode & ETM_MODE_EXCLUDE) |
|---|
| 301 | | - etm4_set_mode_exclude(drvdata, true); |
|---|
| 302 | | - else |
|---|
| 303 | | - etm4_set_mode_exclude(drvdata, false); |
|---|
| 304 | 301 | |
|---|
| 305 | 302 | if (drvdata->instrp0 == true) { |
|---|
| 306 | 303 | /* start by clearing instruction P0 field */ |
|---|
| .. | .. |
|---|
| 367 | 364 | mode = ETM_MODE_QELEM(config->mode); |
|---|
| 368 | 365 | /* start by clearing QE bits */ |
|---|
| 369 | 366 | config->cfg &= ~(BIT(13) | BIT(14)); |
|---|
| 370 | | - /* if supported, Q elements with instruction counts are enabled */ |
|---|
| 371 | | - if ((mode & BIT(0)) && (drvdata->q_support & BIT(0))) |
|---|
| 367 | + /* |
|---|
| 368 | + * if supported, Q elements with instruction counts are enabled. |
|---|
| 369 | + * Always set the low bit for any requested mode. Valid combos are |
|---|
| 370 | + * 0b00, 0b01 and 0b11. |
|---|
| 371 | + */ |
|---|
| 372 | + if (mode && drvdata->q_support) |
|---|
| 372 | 373 | config->cfg |= BIT(13); |
|---|
| 373 | 374 | /* |
|---|
| 374 | 375 | * if supported, Q elements with and without instruction |
|---|
| .. | .. |
|---|
| 392 | 393 | config->eventctrl1 &= ~BIT(12); |
|---|
| 393 | 394 | |
|---|
| 394 | 395 | /* bit[8], Instruction stall bit */ |
|---|
| 395 | | - if (config->mode & ETM_MODE_ISTALL_EN) |
|---|
| 396 | + if ((config->mode & ETM_MODE_ISTALL_EN) && (drvdata->stallctl == true)) |
|---|
| 396 | 397 | config->stall_ctrl |= BIT(8); |
|---|
| 397 | 398 | else |
|---|
| 398 | 399 | config->stall_ctrl &= ~BIT(8); |
|---|
| .. | .. |
|---|
| 746 | 747 | struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 747 | 748 | struct etmv4_config *config = &drvdata->config; |
|---|
| 748 | 749 | |
|---|
| 749 | | - val = BMVAL(config->vinst_ctrl, 16, 19); |
|---|
| 750 | + val = (config->vinst_ctrl & TRCVICTLR_EXLEVEL_S_MASK) >> TRCVICTLR_EXLEVEL_S_SHIFT; |
|---|
| 750 | 751 | return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); |
|---|
| 751 | 752 | } |
|---|
| 752 | 753 | |
|---|
| .. | .. |
|---|
| 762 | 763 | return -EINVAL; |
|---|
| 763 | 764 | |
|---|
| 764 | 765 | spin_lock(&drvdata->spinlock); |
|---|
| 765 | | - /* clear all EXLEVEL_S bits (bit[18] is never implemented) */ |
|---|
| 766 | | - config->vinst_ctrl &= ~(BIT(16) | BIT(17) | BIT(19)); |
|---|
| 766 | + /* clear all EXLEVEL_S bits */ |
|---|
| 767 | + config->vinst_ctrl &= ~(TRCVICTLR_EXLEVEL_S_MASK); |
|---|
| 767 | 768 | /* enable instruction tracing for corresponding exception level */ |
|---|
| 768 | 769 | val &= drvdata->s_ex_level; |
|---|
| 769 | | - config->vinst_ctrl |= (val << 16); |
|---|
| 770 | + config->vinst_ctrl |= (val << TRCVICTLR_EXLEVEL_S_SHIFT); |
|---|
| 770 | 771 | spin_unlock(&drvdata->spinlock); |
|---|
| 771 | 772 | return size; |
|---|
| 772 | 773 | } |
|---|
| .. | .. |
|---|
| 781 | 782 | struct etmv4_config *config = &drvdata->config; |
|---|
| 782 | 783 | |
|---|
| 783 | 784 | /* EXLEVEL_NS, bits[23:20] */ |
|---|
| 784 | | - val = BMVAL(config->vinst_ctrl, 20, 23); |
|---|
| 785 | + val = (config->vinst_ctrl & TRCVICTLR_EXLEVEL_NS_MASK) >> TRCVICTLR_EXLEVEL_NS_SHIFT; |
|---|
| 785 | 786 | return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); |
|---|
| 786 | 787 | } |
|---|
| 787 | 788 | |
|---|
| .. | .. |
|---|
| 797 | 798 | return -EINVAL; |
|---|
| 798 | 799 | |
|---|
| 799 | 800 | spin_lock(&drvdata->spinlock); |
|---|
| 800 | | - /* clear EXLEVEL_NS bits (bit[23] is never implemented */ |
|---|
| 801 | | - config->vinst_ctrl &= ~(BIT(20) | BIT(21) | BIT(22)); |
|---|
| 801 | + /* clear EXLEVEL_NS bits */ |
|---|
| 802 | + config->vinst_ctrl &= ~(TRCVICTLR_EXLEVEL_NS_MASK); |
|---|
| 802 | 803 | /* enable instruction tracing for corresponding exception level */ |
|---|
| 803 | 804 | val &= drvdata->ns_ex_level; |
|---|
| 804 | | - config->vinst_ctrl |= (val << 20); |
|---|
| 805 | + config->vinst_ctrl |= (val << TRCVICTLR_EXLEVEL_NS_SHIFT); |
|---|
| 805 | 806 | spin_unlock(&drvdata->spinlock); |
|---|
| 806 | 807 | return size; |
|---|
| 807 | 808 | } |
|---|
| .. | .. |
|---|
| 974 | 975 | unsigned long val1, val2; |
|---|
| 975 | 976 | struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 976 | 977 | struct etmv4_config *config = &drvdata->config; |
|---|
| 978 | + int elements, exclude; |
|---|
| 977 | 979 | |
|---|
| 978 | | - if (sscanf(buf, "%lx %lx", &val1, &val2) != 2) |
|---|
| 980 | + elements = sscanf(buf, "%lx %lx %x", &val1, &val2, &exclude); |
|---|
| 981 | + |
|---|
| 982 | + /* exclude is optional, but need at least two parameter */ |
|---|
| 983 | + if (elements < 2) |
|---|
| 979 | 984 | return -EINVAL; |
|---|
| 980 | 985 | /* lower address comparator cannot have a higher address value */ |
|---|
| 981 | 986 | if (val1 > val2) |
|---|
| .. | .. |
|---|
| 1003 | 1008 | /* |
|---|
| 1004 | 1009 | * Program include or exclude control bits for vinst or vdata |
|---|
| 1005 | 1010 | * whenever we change addr comparators to ETM_ADDR_TYPE_RANGE |
|---|
| 1011 | + * use supplied value, or default to bit set in 'mode' |
|---|
| 1006 | 1012 | */ |
|---|
| 1007 | | - if (config->mode & ETM_MODE_EXCLUDE) |
|---|
| 1008 | | - etm4_set_mode_exclude(drvdata, true); |
|---|
| 1009 | | - else |
|---|
| 1010 | | - etm4_set_mode_exclude(drvdata, false); |
|---|
| 1013 | + if (elements != 3) |
|---|
| 1014 | + exclude = config->mode & ETM_MODE_EXCLUDE; |
|---|
| 1015 | + etm4_set_mode_exclude(drvdata, exclude ? true : false); |
|---|
| 1011 | 1016 | |
|---|
| 1012 | 1017 | spin_unlock(&drvdata->spinlock); |
|---|
| 1013 | 1018 | return size; |
|---|
| .. | .. |
|---|
| 1064 | 1069 | config->addr_val[idx] = (u64)val; |
|---|
| 1065 | 1070 | config->addr_type[idx] = ETM_ADDR_TYPE_START; |
|---|
| 1066 | 1071 | config->vissctlr |= BIT(idx); |
|---|
| 1067 | | - /* SSSTATUS, bit[9] - turn on start/stop logic */ |
|---|
| 1068 | | - config->vinst_ctrl |= BIT(9); |
|---|
| 1069 | 1072 | spin_unlock(&drvdata->spinlock); |
|---|
| 1070 | 1073 | return size; |
|---|
| 1071 | 1074 | } |
|---|
| .. | .. |
|---|
| 1121 | 1124 | config->addr_val[idx] = (u64)val; |
|---|
| 1122 | 1125 | config->addr_type[idx] = ETM_ADDR_TYPE_STOP; |
|---|
| 1123 | 1126 | config->vissctlr |= BIT(idx + 16); |
|---|
| 1124 | | - /* SSSTATUS, bit[9] - turn on start/stop logic */ |
|---|
| 1125 | | - config->vinst_ctrl |= BIT(9); |
|---|
| 1126 | 1127 | spin_unlock(&drvdata->spinlock); |
|---|
| 1127 | 1128 | return size; |
|---|
| 1128 | 1129 | } |
|---|
| .. | .. |
|---|
| 1237 | 1238 | return size; |
|---|
| 1238 | 1239 | } |
|---|
| 1239 | 1240 | static DEVICE_ATTR_RW(addr_context); |
|---|
| 1241 | + |
|---|
| 1242 | +static ssize_t addr_exlevel_s_ns_show(struct device *dev, |
|---|
| 1243 | + struct device_attribute *attr, |
|---|
| 1244 | + char *buf) |
|---|
| 1245 | +{ |
|---|
| 1246 | + u8 idx; |
|---|
| 1247 | + unsigned long val; |
|---|
| 1248 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1249 | + struct etmv4_config *config = &drvdata->config; |
|---|
| 1250 | + |
|---|
| 1251 | + spin_lock(&drvdata->spinlock); |
|---|
| 1252 | + idx = config->addr_idx; |
|---|
| 1253 | + val = BMVAL(config->addr_acc[idx], 8, 14); |
|---|
| 1254 | + spin_unlock(&drvdata->spinlock); |
|---|
| 1255 | + return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); |
|---|
| 1256 | +} |
|---|
| 1257 | + |
|---|
| 1258 | +static ssize_t addr_exlevel_s_ns_store(struct device *dev, |
|---|
| 1259 | + struct device_attribute *attr, |
|---|
| 1260 | + const char *buf, size_t size) |
|---|
| 1261 | +{ |
|---|
| 1262 | + u8 idx; |
|---|
| 1263 | + unsigned long val; |
|---|
| 1264 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1265 | + struct etmv4_config *config = &drvdata->config; |
|---|
| 1266 | + |
|---|
| 1267 | + if (kstrtoul(buf, 0, &val)) |
|---|
| 1268 | + return -EINVAL; |
|---|
| 1269 | + |
|---|
| 1270 | + if (val & ~((GENMASK(14, 8) >> 8))) |
|---|
| 1271 | + return -EINVAL; |
|---|
| 1272 | + |
|---|
| 1273 | + spin_lock(&drvdata->spinlock); |
|---|
| 1274 | + idx = config->addr_idx; |
|---|
| 1275 | + /* clear Exlevel_ns & Exlevel_s bits[14:12, 11:8], bit[15] is res0 */ |
|---|
| 1276 | + config->addr_acc[idx] &= ~(GENMASK(14, 8)); |
|---|
| 1277 | + config->addr_acc[idx] |= (val << 8); |
|---|
| 1278 | + spin_unlock(&drvdata->spinlock); |
|---|
| 1279 | + return size; |
|---|
| 1280 | +} |
|---|
| 1281 | +static DEVICE_ATTR_RW(addr_exlevel_s_ns); |
|---|
| 1282 | + |
|---|
| 1283 | +static const char * const addr_type_names[] = { |
|---|
| 1284 | + "unused", |
|---|
| 1285 | + "single", |
|---|
| 1286 | + "range", |
|---|
| 1287 | + "start", |
|---|
| 1288 | + "stop" |
|---|
| 1289 | +}; |
|---|
| 1290 | + |
|---|
| 1291 | +static ssize_t addr_cmp_view_show(struct device *dev, |
|---|
| 1292 | + struct device_attribute *attr, char *buf) |
|---|
| 1293 | +{ |
|---|
| 1294 | + u8 idx, addr_type; |
|---|
| 1295 | + unsigned long addr_v, addr_v2, addr_ctrl; |
|---|
| 1296 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1297 | + struct etmv4_config *config = &drvdata->config; |
|---|
| 1298 | + int size = 0; |
|---|
| 1299 | + bool exclude = false; |
|---|
| 1300 | + |
|---|
| 1301 | + spin_lock(&drvdata->spinlock); |
|---|
| 1302 | + idx = config->addr_idx; |
|---|
| 1303 | + addr_v = config->addr_val[idx]; |
|---|
| 1304 | + addr_ctrl = config->addr_acc[idx]; |
|---|
| 1305 | + addr_type = config->addr_type[idx]; |
|---|
| 1306 | + if (addr_type == ETM_ADDR_TYPE_RANGE) { |
|---|
| 1307 | + if (idx & 0x1) { |
|---|
| 1308 | + idx -= 1; |
|---|
| 1309 | + addr_v2 = addr_v; |
|---|
| 1310 | + addr_v = config->addr_val[idx]; |
|---|
| 1311 | + } else { |
|---|
| 1312 | + addr_v2 = config->addr_val[idx + 1]; |
|---|
| 1313 | + } |
|---|
| 1314 | + exclude = config->viiectlr & BIT(idx / 2 + 16); |
|---|
| 1315 | + } |
|---|
| 1316 | + spin_unlock(&drvdata->spinlock); |
|---|
| 1317 | + if (addr_type) { |
|---|
| 1318 | + size = scnprintf(buf, PAGE_SIZE, "addr_cmp[%i] %s %#lx", idx, |
|---|
| 1319 | + addr_type_names[addr_type], addr_v); |
|---|
| 1320 | + if (addr_type == ETM_ADDR_TYPE_RANGE) { |
|---|
| 1321 | + size += scnprintf(buf + size, PAGE_SIZE - size, |
|---|
| 1322 | + " %#lx %s", addr_v2, |
|---|
| 1323 | + exclude ? "exclude" : "include"); |
|---|
| 1324 | + } |
|---|
| 1325 | + size += scnprintf(buf + size, PAGE_SIZE - size, |
|---|
| 1326 | + " ctrl(%#lx)\n", addr_ctrl); |
|---|
| 1327 | + } else { |
|---|
| 1328 | + size = scnprintf(buf, PAGE_SIZE, "addr_cmp[%i] unused\n", idx); |
|---|
| 1329 | + } |
|---|
| 1330 | + return size; |
|---|
| 1331 | +} |
|---|
| 1332 | +static DEVICE_ATTR_RO(addr_cmp_view); |
|---|
| 1333 | + |
|---|
| 1334 | +static ssize_t vinst_pe_cmp_start_stop_show(struct device *dev, |
|---|
| 1335 | + struct device_attribute *attr, |
|---|
| 1336 | + char *buf) |
|---|
| 1337 | +{ |
|---|
| 1338 | + unsigned long val; |
|---|
| 1339 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1340 | + struct etmv4_config *config = &drvdata->config; |
|---|
| 1341 | + |
|---|
| 1342 | + if (!drvdata->nr_pe_cmp) |
|---|
| 1343 | + return -EINVAL; |
|---|
| 1344 | + val = config->vipcssctlr; |
|---|
| 1345 | + return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); |
|---|
| 1346 | +} |
|---|
| 1347 | +static ssize_t vinst_pe_cmp_start_stop_store(struct device *dev, |
|---|
| 1348 | + struct device_attribute *attr, |
|---|
| 1349 | + const char *buf, size_t size) |
|---|
| 1350 | +{ |
|---|
| 1351 | + unsigned long val; |
|---|
| 1352 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1353 | + struct etmv4_config *config = &drvdata->config; |
|---|
| 1354 | + |
|---|
| 1355 | + if (kstrtoul(buf, 16, &val)) |
|---|
| 1356 | + return -EINVAL; |
|---|
| 1357 | + if (!drvdata->nr_pe_cmp) |
|---|
| 1358 | + return -EINVAL; |
|---|
| 1359 | + |
|---|
| 1360 | + spin_lock(&drvdata->spinlock); |
|---|
| 1361 | + config->vipcssctlr = val; |
|---|
| 1362 | + spin_unlock(&drvdata->spinlock); |
|---|
| 1363 | + return size; |
|---|
| 1364 | +} |
|---|
| 1365 | +static DEVICE_ATTR_RW(vinst_pe_cmp_start_stop); |
|---|
| 1240 | 1366 | |
|---|
| 1241 | 1367 | static ssize_t seq_idx_show(struct device *dev, |
|---|
| 1242 | 1368 | struct device_attribute *attr, |
|---|
| .. | .. |
|---|
| 1541 | 1667 | |
|---|
| 1542 | 1668 | if (kstrtoul(buf, 16, &val)) |
|---|
| 1543 | 1669 | return -EINVAL; |
|---|
| 1544 | | - /* Resource selector pair 0 is always implemented and reserved */ |
|---|
| 1545 | | - if ((val == 0) || (val >= drvdata->nr_resource)) |
|---|
| 1670 | + /* |
|---|
| 1671 | + * Resource selector pair 0 is always implemented and reserved, |
|---|
| 1672 | + * namely an idx with 0 and 1 is illegal. |
|---|
| 1673 | + */ |
|---|
| 1674 | + if ((val < 2) || (val >= 2 * drvdata->nr_resource)) |
|---|
| 1546 | 1675 | return -EINVAL; |
|---|
| 1547 | 1676 | |
|---|
| 1548 | 1677 | /* |
|---|
| .. | .. |
|---|
| 1595 | 1724 | return size; |
|---|
| 1596 | 1725 | } |
|---|
| 1597 | 1726 | static DEVICE_ATTR_RW(res_ctrl); |
|---|
| 1727 | + |
|---|
| 1728 | +static ssize_t sshot_idx_show(struct device *dev, |
|---|
| 1729 | + struct device_attribute *attr, char *buf) |
|---|
| 1730 | +{ |
|---|
| 1731 | + unsigned long val; |
|---|
| 1732 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1733 | + struct etmv4_config *config = &drvdata->config; |
|---|
| 1734 | + |
|---|
| 1735 | + val = config->ss_idx; |
|---|
| 1736 | + return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); |
|---|
| 1737 | +} |
|---|
| 1738 | + |
|---|
| 1739 | +static ssize_t sshot_idx_store(struct device *dev, |
|---|
| 1740 | + struct device_attribute *attr, |
|---|
| 1741 | + const char *buf, size_t size) |
|---|
| 1742 | +{ |
|---|
| 1743 | + unsigned long val; |
|---|
| 1744 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1745 | + struct etmv4_config *config = &drvdata->config; |
|---|
| 1746 | + |
|---|
| 1747 | + if (kstrtoul(buf, 16, &val)) |
|---|
| 1748 | + return -EINVAL; |
|---|
| 1749 | + if (val >= drvdata->nr_ss_cmp) |
|---|
| 1750 | + return -EINVAL; |
|---|
| 1751 | + |
|---|
| 1752 | + spin_lock(&drvdata->spinlock); |
|---|
| 1753 | + config->ss_idx = val; |
|---|
| 1754 | + spin_unlock(&drvdata->spinlock); |
|---|
| 1755 | + return size; |
|---|
| 1756 | +} |
|---|
| 1757 | +static DEVICE_ATTR_RW(sshot_idx); |
|---|
| 1758 | + |
|---|
| 1759 | +static ssize_t sshot_ctrl_show(struct device *dev, |
|---|
| 1760 | + struct device_attribute *attr, |
|---|
| 1761 | + char *buf) |
|---|
| 1762 | +{ |
|---|
| 1763 | + unsigned long val; |
|---|
| 1764 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1765 | + struct etmv4_config *config = &drvdata->config; |
|---|
| 1766 | + |
|---|
| 1767 | + spin_lock(&drvdata->spinlock); |
|---|
| 1768 | + val = config->ss_ctrl[config->ss_idx]; |
|---|
| 1769 | + spin_unlock(&drvdata->spinlock); |
|---|
| 1770 | + return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); |
|---|
| 1771 | +} |
|---|
| 1772 | + |
|---|
| 1773 | +static ssize_t sshot_ctrl_store(struct device *dev, |
|---|
| 1774 | + struct device_attribute *attr, |
|---|
| 1775 | + const char *buf, size_t size) |
|---|
| 1776 | +{ |
|---|
| 1777 | + u8 idx; |
|---|
| 1778 | + unsigned long val; |
|---|
| 1779 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1780 | + struct etmv4_config *config = &drvdata->config; |
|---|
| 1781 | + |
|---|
| 1782 | + if (kstrtoul(buf, 16, &val)) |
|---|
| 1783 | + return -EINVAL; |
|---|
| 1784 | + |
|---|
| 1785 | + spin_lock(&drvdata->spinlock); |
|---|
| 1786 | + idx = config->ss_idx; |
|---|
| 1787 | + config->ss_ctrl[idx] = val & GENMASK(24, 0); |
|---|
| 1788 | + /* must clear bit 31 in related status register on programming */ |
|---|
| 1789 | + config->ss_status[idx] &= ~BIT(31); |
|---|
| 1790 | + spin_unlock(&drvdata->spinlock); |
|---|
| 1791 | + return size; |
|---|
| 1792 | +} |
|---|
| 1793 | +static DEVICE_ATTR_RW(sshot_ctrl); |
|---|
| 1794 | + |
|---|
| 1795 | +static ssize_t sshot_status_show(struct device *dev, |
|---|
| 1796 | + struct device_attribute *attr, char *buf) |
|---|
| 1797 | +{ |
|---|
| 1798 | + unsigned long val; |
|---|
| 1799 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1800 | + struct etmv4_config *config = &drvdata->config; |
|---|
| 1801 | + |
|---|
| 1802 | + spin_lock(&drvdata->spinlock); |
|---|
| 1803 | + val = config->ss_status[config->ss_idx]; |
|---|
| 1804 | + spin_unlock(&drvdata->spinlock); |
|---|
| 1805 | + return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); |
|---|
| 1806 | +} |
|---|
| 1807 | +static DEVICE_ATTR_RO(sshot_status); |
|---|
| 1808 | + |
|---|
| 1809 | +static ssize_t sshot_pe_ctrl_show(struct device *dev, |
|---|
| 1810 | + struct device_attribute *attr, |
|---|
| 1811 | + char *buf) |
|---|
| 1812 | +{ |
|---|
| 1813 | + unsigned long val; |
|---|
| 1814 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1815 | + struct etmv4_config *config = &drvdata->config; |
|---|
| 1816 | + |
|---|
| 1817 | + spin_lock(&drvdata->spinlock); |
|---|
| 1818 | + val = config->ss_pe_cmp[config->ss_idx]; |
|---|
| 1819 | + spin_unlock(&drvdata->spinlock); |
|---|
| 1820 | + return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); |
|---|
| 1821 | +} |
|---|
| 1822 | + |
|---|
| 1823 | +static ssize_t sshot_pe_ctrl_store(struct device *dev, |
|---|
| 1824 | + struct device_attribute *attr, |
|---|
| 1825 | + const char *buf, size_t size) |
|---|
| 1826 | +{ |
|---|
| 1827 | + u8 idx; |
|---|
| 1828 | + unsigned long val; |
|---|
| 1829 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1830 | + struct etmv4_config *config = &drvdata->config; |
|---|
| 1831 | + |
|---|
| 1832 | + if (kstrtoul(buf, 16, &val)) |
|---|
| 1833 | + return -EINVAL; |
|---|
| 1834 | + |
|---|
| 1835 | + spin_lock(&drvdata->spinlock); |
|---|
| 1836 | + idx = config->ss_idx; |
|---|
| 1837 | + config->ss_pe_cmp[idx] = val & GENMASK(7, 0); |
|---|
| 1838 | + /* must clear bit 31 in related status register on programming */ |
|---|
| 1839 | + config->ss_status[idx] &= ~BIT(31); |
|---|
| 1840 | + spin_unlock(&drvdata->spinlock); |
|---|
| 1841 | + return size; |
|---|
| 1842 | +} |
|---|
| 1843 | +static DEVICE_ATTR_RW(sshot_pe_ctrl); |
|---|
| 1598 | 1844 | |
|---|
| 1599 | 1845 | static ssize_t ctxid_idx_show(struct device *dev, |
|---|
| 1600 | 1846 | struct device_attribute *attr, |
|---|
| .. | .. |
|---|
| 1724 | 1970 | unsigned long val1, val2, mask; |
|---|
| 1725 | 1971 | struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1726 | 1972 | struct etmv4_config *config = &drvdata->config; |
|---|
| 1973 | + int nr_inputs; |
|---|
| 1727 | 1974 | |
|---|
| 1728 | 1975 | /* |
|---|
| 1729 | 1976 | * Don't use contextID tracing if coming from a PID namespace. See |
|---|
| .. | .. |
|---|
| 1739 | 1986 | */ |
|---|
| 1740 | 1987 | if (!drvdata->ctxid_size || !drvdata->numcidc) |
|---|
| 1741 | 1988 | return -EINVAL; |
|---|
| 1742 | | - if (sscanf(buf, "%lx %lx", &val1, &val2) != 2) |
|---|
| 1989 | + /* one mask if <= 4 comparators, two for up to 8 */ |
|---|
| 1990 | + nr_inputs = sscanf(buf, "%lx %lx", &val1, &val2); |
|---|
| 1991 | + if ((drvdata->numcidc > 4) && (nr_inputs != 2)) |
|---|
| 1743 | 1992 | return -EINVAL; |
|---|
| 1744 | 1993 | |
|---|
| 1745 | 1994 | spin_lock(&drvdata->spinlock); |
|---|
| .. | .. |
|---|
| 1913 | 2162 | unsigned long val1, val2, mask; |
|---|
| 1914 | 2163 | struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 1915 | 2164 | struct etmv4_config *config = &drvdata->config; |
|---|
| 2165 | + int nr_inputs; |
|---|
| 1916 | 2166 | |
|---|
| 1917 | 2167 | /* |
|---|
| 1918 | 2168 | * only implemented when vmid tracing is enabled, i.e. at least one |
|---|
| .. | .. |
|---|
| 1920 | 2170 | */ |
|---|
| 1921 | 2171 | if (!drvdata->vmid_size || !drvdata->numvmidc) |
|---|
| 1922 | 2172 | return -EINVAL; |
|---|
| 1923 | | - if (sscanf(buf, "%lx %lx", &val1, &val2) != 2) |
|---|
| 2173 | + /* one mask if <= 4 comparators, two for up to 8 */ |
|---|
| 2174 | + nr_inputs = sscanf(buf, "%lx %lx", &val1, &val2); |
|---|
| 2175 | + if ((drvdata->numvmidc > 4) && (nr_inputs != 2)) |
|---|
| 1924 | 2176 | return -EINVAL; |
|---|
| 1925 | 2177 | |
|---|
| 1926 | 2178 | spin_lock(&drvdata->spinlock); |
|---|
| .. | .. |
|---|
| 2043 | 2295 | &dev_attr_addr_stop.attr, |
|---|
| 2044 | 2296 | &dev_attr_addr_ctxtype.attr, |
|---|
| 2045 | 2297 | &dev_attr_addr_context.attr, |
|---|
| 2298 | + &dev_attr_addr_exlevel_s_ns.attr, |
|---|
| 2299 | + &dev_attr_addr_cmp_view.attr, |
|---|
| 2300 | + &dev_attr_vinst_pe_cmp_start_stop.attr, |
|---|
| 2301 | + &dev_attr_sshot_idx.attr, |
|---|
| 2302 | + &dev_attr_sshot_ctrl.attr, |
|---|
| 2303 | + &dev_attr_sshot_pe_ctrl.attr, |
|---|
| 2304 | + &dev_attr_sshot_status.attr, |
|---|
| 2046 | 2305 | &dev_attr_seq_idx.attr, |
|---|
| 2047 | 2306 | &dev_attr_seq_state.attr, |
|---|
| 2048 | 2307 | &dev_attr_seq_event.attr, |
|---|
| .. | .. |
|---|
| 2064 | 2323 | }; |
|---|
| 2065 | 2324 | |
|---|
| 2066 | 2325 | struct etmv4_reg { |
|---|
| 2067 | | - void __iomem *addr; |
|---|
| 2326 | + struct coresight_device *csdev; |
|---|
| 2327 | + u32 offset; |
|---|
| 2068 | 2328 | u32 data; |
|---|
| 2069 | 2329 | }; |
|---|
| 2070 | 2330 | |
|---|
| .. | .. |
|---|
| 2072 | 2332 | { |
|---|
| 2073 | 2333 | struct etmv4_reg *reg = data; |
|---|
| 2074 | 2334 | |
|---|
| 2075 | | - reg->data = readl_relaxed(reg->addr); |
|---|
| 2335 | + reg->data = etm4x_relaxed_read32(®->csdev->access, reg->offset); |
|---|
| 2076 | 2336 | } |
|---|
| 2077 | 2337 | |
|---|
| 2078 | | -static u32 etmv4_cross_read(const struct device *dev, u32 offset) |
|---|
| 2338 | +static u32 etmv4_cross_read(const struct etmv4_drvdata *drvdata, u32 offset) |
|---|
| 2079 | 2339 | { |
|---|
| 2080 | | - struct etmv4_drvdata *drvdata = dev_get_drvdata(dev); |
|---|
| 2081 | 2340 | struct etmv4_reg reg; |
|---|
| 2082 | 2341 | |
|---|
| 2083 | | - reg.addr = drvdata->base + offset; |
|---|
| 2342 | + reg.offset = offset; |
|---|
| 2343 | + reg.csdev = drvdata->csdev; |
|---|
| 2344 | + |
|---|
| 2084 | 2345 | /* |
|---|
| 2085 | 2346 | * smp cross call ensures the CPU will be powered up before |
|---|
| 2086 | 2347 | * accessing the ETMv4 trace core registers |
|---|
| .. | .. |
|---|
| 2089 | 2350 | return reg.data; |
|---|
| 2090 | 2351 | } |
|---|
| 2091 | 2352 | |
|---|
| 2092 | | -#define coresight_etm4x_reg(name, offset) \ |
|---|
| 2093 | | - coresight_simple_reg32(struct etmv4_drvdata, name, offset) |
|---|
| 2353 | +static inline u32 coresight_etm4x_attr_to_offset(struct device_attribute *attr) |
|---|
| 2354 | +{ |
|---|
| 2355 | + struct dev_ext_attribute *eattr; |
|---|
| 2094 | 2356 | |
|---|
| 2095 | | -#define coresight_etm4x_cross_read(name, offset) \ |
|---|
| 2096 | | - coresight_simple_func(struct etmv4_drvdata, etmv4_cross_read, \ |
|---|
| 2097 | | - name, offset) |
|---|
| 2357 | + eattr = container_of(attr, struct dev_ext_attribute, attr); |
|---|
| 2358 | + return (u32)(unsigned long)eattr->var; |
|---|
| 2359 | +} |
|---|
| 2098 | 2360 | |
|---|
| 2099 | | -coresight_etm4x_reg(trcpdcr, TRCPDCR); |
|---|
| 2100 | | -coresight_etm4x_reg(trcpdsr, TRCPDSR); |
|---|
| 2101 | | -coresight_etm4x_reg(trclsr, TRCLSR); |
|---|
| 2102 | | -coresight_etm4x_reg(trcauthstatus, TRCAUTHSTATUS); |
|---|
| 2103 | | -coresight_etm4x_reg(trcdevid, TRCDEVID); |
|---|
| 2104 | | -coresight_etm4x_reg(trcdevtype, TRCDEVTYPE); |
|---|
| 2105 | | -coresight_etm4x_reg(trcpidr0, TRCPIDR0); |
|---|
| 2106 | | -coresight_etm4x_reg(trcpidr1, TRCPIDR1); |
|---|
| 2107 | | -coresight_etm4x_reg(trcpidr2, TRCPIDR2); |
|---|
| 2108 | | -coresight_etm4x_reg(trcpidr3, TRCPIDR3); |
|---|
| 2109 | | -coresight_etm4x_cross_read(trcoslsr, TRCOSLSR); |
|---|
| 2110 | | -coresight_etm4x_cross_read(trcconfig, TRCCONFIGR); |
|---|
| 2111 | | -coresight_etm4x_cross_read(trctraceid, TRCTRACEIDR); |
|---|
| 2361 | +static ssize_t coresight_etm4x_reg_show(struct device *dev, |
|---|
| 2362 | + struct device_attribute *d_attr, |
|---|
| 2363 | + char *buf) |
|---|
| 2364 | +{ |
|---|
| 2365 | + u32 val, offset; |
|---|
| 2366 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 2367 | + |
|---|
| 2368 | + offset = coresight_etm4x_attr_to_offset(d_attr); |
|---|
| 2369 | + |
|---|
| 2370 | + pm_runtime_get_sync(dev->parent); |
|---|
| 2371 | + val = etmv4_cross_read(drvdata, offset); |
|---|
| 2372 | + pm_runtime_put_sync(dev->parent); |
|---|
| 2373 | + |
|---|
| 2374 | + return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); |
|---|
| 2375 | +} |
|---|
| 2376 | + |
|---|
| 2377 | +static inline bool |
|---|
| 2378 | +etm4x_register_implemented(struct etmv4_drvdata *drvdata, u32 offset) |
|---|
| 2379 | +{ |
|---|
| 2380 | + switch (offset) { |
|---|
| 2381 | + ETM_COMMON_SYSREG_LIST_CASES |
|---|
| 2382 | + /* |
|---|
| 2383 | + * Common registers to ETE & ETM4x accessible via system |
|---|
| 2384 | + * instructions are always implemented. |
|---|
| 2385 | + */ |
|---|
| 2386 | + return true; |
|---|
| 2387 | + |
|---|
| 2388 | + ETM4x_ONLY_SYSREG_LIST_CASES |
|---|
| 2389 | + /* |
|---|
| 2390 | + * We only support etm4x and ete. So if the device is not |
|---|
| 2391 | + * ETE, it must be ETMv4x. |
|---|
| 2392 | + */ |
|---|
| 2393 | + return !etm4x_is_ete(drvdata); |
|---|
| 2394 | + |
|---|
| 2395 | + ETM4x_MMAP_LIST_CASES |
|---|
| 2396 | + /* |
|---|
| 2397 | + * Registers accessible only via memory-mapped registers |
|---|
| 2398 | + * must not be accessed via system instructions. |
|---|
| 2399 | + * We cannot access the drvdata->csdev here, as this |
|---|
| 2400 | + * function is called during the device creation, via |
|---|
| 2401 | + * coresight_register() and the csdev is not initialized |
|---|
| 2402 | + * until that is done. So rely on the drvdata->base to |
|---|
| 2403 | + * detect if we have a memory mapped access. |
|---|
| 2404 | + * Also ETE doesn't implement memory mapped access, thus |
|---|
| 2405 | + * it is sufficient to check that we are using mmio. |
|---|
| 2406 | + */ |
|---|
| 2407 | + return !!drvdata->base; |
|---|
| 2408 | + |
|---|
| 2409 | + ETE_ONLY_SYSREG_LIST_CASES |
|---|
| 2410 | + return etm4x_is_ete(drvdata); |
|---|
| 2411 | + } |
|---|
| 2412 | + |
|---|
| 2413 | + return false; |
|---|
| 2414 | +} |
|---|
| 2415 | + |
|---|
| 2416 | +/* |
|---|
| 2417 | + * Hide the ETM4x registers that may not be available on the |
|---|
| 2418 | + * hardware. |
|---|
| 2419 | + * There are certain management registers unavailable via system |
|---|
| 2420 | + * instructions. Make those sysfs attributes hidden on such |
|---|
| 2421 | + * systems. |
|---|
| 2422 | + */ |
|---|
| 2423 | +static umode_t |
|---|
| 2424 | +coresight_etm4x_attr_reg_implemented(struct kobject *kobj, |
|---|
| 2425 | + struct attribute *attr, int unused) |
|---|
| 2426 | +{ |
|---|
| 2427 | + struct device *dev = kobj_to_dev(kobj); |
|---|
| 2428 | + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 2429 | + struct device_attribute *d_attr; |
|---|
| 2430 | + u32 offset; |
|---|
| 2431 | + |
|---|
| 2432 | + d_attr = container_of(attr, struct device_attribute, attr); |
|---|
| 2433 | + offset = coresight_etm4x_attr_to_offset(d_attr); |
|---|
| 2434 | + |
|---|
| 2435 | + if (etm4x_register_implemented(drvdata, offset)) |
|---|
| 2436 | + return attr->mode; |
|---|
| 2437 | + return 0; |
|---|
| 2438 | +} |
|---|
| 2439 | + |
|---|
| 2440 | +#define coresight_etm4x_reg(name, offset) \ |
|---|
| 2441 | + &((struct dev_ext_attribute[]) { \ |
|---|
| 2442 | + { \ |
|---|
| 2443 | + __ATTR(name, 0444, coresight_etm4x_reg_show, NULL), \ |
|---|
| 2444 | + (void *)(unsigned long)offset \ |
|---|
| 2445 | + } \ |
|---|
| 2446 | + })[0].attr.attr |
|---|
| 2112 | 2447 | |
|---|
| 2113 | 2448 | static struct attribute *coresight_etmv4_mgmt_attrs[] = { |
|---|
| 2114 | | - &dev_attr_trcoslsr.attr, |
|---|
| 2115 | | - &dev_attr_trcpdcr.attr, |
|---|
| 2116 | | - &dev_attr_trcpdsr.attr, |
|---|
| 2117 | | - &dev_attr_trclsr.attr, |
|---|
| 2118 | | - &dev_attr_trcconfig.attr, |
|---|
| 2119 | | - &dev_attr_trctraceid.attr, |
|---|
| 2120 | | - &dev_attr_trcauthstatus.attr, |
|---|
| 2121 | | - &dev_attr_trcdevid.attr, |
|---|
| 2122 | | - &dev_attr_trcdevtype.attr, |
|---|
| 2123 | | - &dev_attr_trcpidr0.attr, |
|---|
| 2124 | | - &dev_attr_trcpidr1.attr, |
|---|
| 2125 | | - &dev_attr_trcpidr2.attr, |
|---|
| 2126 | | - &dev_attr_trcpidr3.attr, |
|---|
| 2449 | + coresight_etm4x_reg(trcpdcr, TRCPDCR), |
|---|
| 2450 | + coresight_etm4x_reg(trcpdsr, TRCPDSR), |
|---|
| 2451 | + coresight_etm4x_reg(trclsr, TRCLSR), |
|---|
| 2452 | + coresight_etm4x_reg(trcauthstatus, TRCAUTHSTATUS), |
|---|
| 2453 | + coresight_etm4x_reg(trcdevid, TRCDEVID), |
|---|
| 2454 | + coresight_etm4x_reg(trcdevtype, TRCDEVTYPE), |
|---|
| 2455 | + coresight_etm4x_reg(trcpidr0, TRCPIDR0), |
|---|
| 2456 | + coresight_etm4x_reg(trcpidr1, TRCPIDR1), |
|---|
| 2457 | + coresight_etm4x_reg(trcpidr2, TRCPIDR2), |
|---|
| 2458 | + coresight_etm4x_reg(trcpidr3, TRCPIDR3), |
|---|
| 2459 | + coresight_etm4x_reg(trcoslsr, TRCOSLSR), |
|---|
| 2460 | + coresight_etm4x_reg(trcconfig, TRCCONFIGR), |
|---|
| 2461 | + coresight_etm4x_reg(trctraceid, TRCTRACEIDR), |
|---|
| 2462 | + coresight_etm4x_reg(trcdevarch, TRCDEVARCH), |
|---|
| 2127 | 2463 | NULL, |
|---|
| 2128 | 2464 | }; |
|---|
| 2129 | 2465 | |
|---|
| 2130 | | -coresight_etm4x_cross_read(trcidr0, TRCIDR0); |
|---|
| 2131 | | -coresight_etm4x_cross_read(trcidr1, TRCIDR1); |
|---|
| 2132 | | -coresight_etm4x_cross_read(trcidr2, TRCIDR2); |
|---|
| 2133 | | -coresight_etm4x_cross_read(trcidr3, TRCIDR3); |
|---|
| 2134 | | -coresight_etm4x_cross_read(trcidr4, TRCIDR4); |
|---|
| 2135 | | -coresight_etm4x_cross_read(trcidr5, TRCIDR5); |
|---|
| 2136 | | -/* trcidr[6,7] are reserved */ |
|---|
| 2137 | | -coresight_etm4x_cross_read(trcidr8, TRCIDR8); |
|---|
| 2138 | | -coresight_etm4x_cross_read(trcidr9, TRCIDR9); |
|---|
| 2139 | | -coresight_etm4x_cross_read(trcidr10, TRCIDR10); |
|---|
| 2140 | | -coresight_etm4x_cross_read(trcidr11, TRCIDR11); |
|---|
| 2141 | | -coresight_etm4x_cross_read(trcidr12, TRCIDR12); |
|---|
| 2142 | | -coresight_etm4x_cross_read(trcidr13, TRCIDR13); |
|---|
| 2143 | | - |
|---|
| 2144 | 2466 | static struct attribute *coresight_etmv4_trcidr_attrs[] = { |
|---|
| 2145 | | - &dev_attr_trcidr0.attr, |
|---|
| 2146 | | - &dev_attr_trcidr1.attr, |
|---|
| 2147 | | - &dev_attr_trcidr2.attr, |
|---|
| 2148 | | - &dev_attr_trcidr3.attr, |
|---|
| 2149 | | - &dev_attr_trcidr4.attr, |
|---|
| 2150 | | - &dev_attr_trcidr5.attr, |
|---|
| 2467 | + coresight_etm4x_reg(trcidr0, TRCIDR0), |
|---|
| 2468 | + coresight_etm4x_reg(trcidr1, TRCIDR1), |
|---|
| 2469 | + coresight_etm4x_reg(trcidr2, TRCIDR2), |
|---|
| 2470 | + coresight_etm4x_reg(trcidr3, TRCIDR3), |
|---|
| 2471 | + coresight_etm4x_reg(trcidr4, TRCIDR4), |
|---|
| 2472 | + coresight_etm4x_reg(trcidr5, TRCIDR5), |
|---|
| 2151 | 2473 | /* trcidr[6,7] are reserved */ |
|---|
| 2152 | | - &dev_attr_trcidr8.attr, |
|---|
| 2153 | | - &dev_attr_trcidr9.attr, |
|---|
| 2154 | | - &dev_attr_trcidr10.attr, |
|---|
| 2155 | | - &dev_attr_trcidr11.attr, |
|---|
| 2156 | | - &dev_attr_trcidr12.attr, |
|---|
| 2157 | | - &dev_attr_trcidr13.attr, |
|---|
| 2474 | + coresight_etm4x_reg(trcidr8, TRCIDR8), |
|---|
| 2475 | + coresight_etm4x_reg(trcidr9, TRCIDR9), |
|---|
| 2476 | + coresight_etm4x_reg(trcidr10, TRCIDR10), |
|---|
| 2477 | + coresight_etm4x_reg(trcidr11, TRCIDR11), |
|---|
| 2478 | + coresight_etm4x_reg(trcidr12, TRCIDR12), |
|---|
| 2479 | + coresight_etm4x_reg(trcidr13, TRCIDR13), |
|---|
| 2158 | 2480 | NULL, |
|---|
| 2159 | 2481 | }; |
|---|
| 2160 | 2482 | |
|---|
| .. | .. |
|---|
| 2163 | 2485 | }; |
|---|
| 2164 | 2486 | |
|---|
| 2165 | 2487 | static const struct attribute_group coresight_etmv4_mgmt_group = { |
|---|
| 2488 | + .is_visible = coresight_etm4x_attr_reg_implemented, |
|---|
| 2166 | 2489 | .attrs = coresight_etmv4_mgmt_attrs, |
|---|
| 2167 | 2490 | .name = "mgmt", |
|---|
| 2168 | 2491 | }; |
|---|