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

coresight-tmc: change tmc_drvdata spinlock's type to raw_spinlock_t

In coresight-tmc drivers, tmc_drvdata->spinlock can be held
during __schedule() by perf_event_task_sched_out()/in().

Since tmc_drvdata->spinlock type is spinlock_t and
perf_event_task_sched_out()/in() is called after acquiring rq_lock,
which is raw_spinlock_t (an unsleepable lock),
this poses an issue in PREEMPT_RT kernel where spinlock_t is sleepable.

To address this, change type tmc_drvdata->spinlock in coresight-tmc drivers,
which can be called by perf_event_task_sched_out()/in(),
from spinlock_t to raw_spinlock_t.

Reviewed-by: James Clark <james.clark@linaro.org>
Reviewed-by: Mike Leach <mike.leach@linaro.org>
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20250306121110.1647948-9-yeoreum.yun@arm.com

authored by

Yeoreum Yun and committed by
Suzuki K Poulose
db11f75b 982d0a0e

+54 -54
+7 -7
drivers/hwtracing/coresight/coresight-tmc-core.c
··· 358 358 mdata = drvdata->crash_mdata.vaddr; 359 359 rbuf = &drvdata->resrv_buf; 360 360 361 - spin_lock_irqsave(&drvdata->spinlock, flags); 361 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 362 362 if (mdata->valid) 363 363 rbuf->reading = true; 364 364 else 365 365 err = -ENOENT; 366 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 366 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 367 367 if (err) 368 368 goto exit; 369 369 ··· 408 408 crashdev); 409 409 410 410 rbuf = &drvdata->resrv_buf; 411 - spin_lock_irqsave(&drvdata->spinlock, flags); 411 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 412 412 rbuf->reading = false; 413 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 413 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 414 414 415 415 dev_dbg(&drvdata->csdev->dev, "%s: released\n", __func__); 416 416 return ret; ··· 801 801 drvdata->base = base; 802 802 desc.access = CSDEV_ACCESS_IOMEM(base); 803 803 804 - spin_lock_init(&drvdata->spinlock); 804 + raw_spin_lock_init(&drvdata->spinlock); 805 805 806 806 devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID); 807 807 drvdata->config_type = BMVAL(devid, 6, 7); ··· 913 913 unsigned long flags; 914 914 struct tmc_drvdata *drvdata = amba_get_drvdata(adev); 915 915 916 - spin_lock_irqsave(&drvdata->spinlock, flags); 916 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 917 917 918 918 if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED) 919 919 goto out; ··· 927 927 * the system is going down after this. 928 928 */ 929 929 out: 930 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 930 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 931 931 } 932 932 933 933 static void __tmc_remove(struct device *dev)
+24 -24
drivers/hwtracing/coresight/coresight-tmc-etf.c
··· 185 185 * If we don't have a buffer release the lock and allocate memory. 186 186 * Otherwise keep the lock and move along. 187 187 */ 188 - spin_lock_irqsave(&drvdata->spinlock, flags); 188 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 189 189 if (!drvdata->buf) { 190 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 190 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 191 191 192 192 /* Allocating the memory here while outside of the spinlock */ 193 193 buf = kzalloc(drvdata->size, GFP_KERNEL); ··· 195 195 return -ENOMEM; 196 196 197 197 /* Let's try again */ 198 - spin_lock_irqsave(&drvdata->spinlock, flags); 198 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 199 199 } 200 200 201 201 if (drvdata->reading) { ··· 237 237 used = false; 238 238 } 239 239 out: 240 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 240 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 241 241 242 242 /* Free memory outside the spinlock if need be */ 243 243 if (!used) ··· 255 255 struct perf_output_handle *handle = data; 256 256 struct cs_buffers *buf = etm_perf_sink_config(handle); 257 257 258 - spin_lock_irqsave(&drvdata->spinlock, flags); 258 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 259 259 do { 260 260 ret = -EINVAL; 261 261 if (drvdata->reading) ··· 298 298 csdev->refcnt++; 299 299 } 300 300 } while (0); 301 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 301 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 302 302 303 303 return ret; 304 304 } ··· 333 333 unsigned long flags; 334 334 struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 335 335 336 - spin_lock_irqsave(&drvdata->spinlock, flags); 336 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 337 337 338 338 if (drvdata->reading) { 339 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 339 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 340 340 return -EBUSY; 341 341 } 342 342 343 343 csdev->refcnt--; 344 344 if (csdev->refcnt) { 345 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 345 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 346 346 return -EBUSY; 347 347 } 348 348 ··· 353 353 drvdata->pid = -1; 354 354 coresight_set_mode(csdev, CS_MODE_DISABLED); 355 355 356 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 356 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 357 357 358 358 dev_dbg(&csdev->dev, "TMC-ETB/ETF disabled\n"); 359 359 return 0; ··· 368 368 struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 369 369 bool first_enable = false; 370 370 371 - spin_lock_irqsave(&drvdata->spinlock, flags); 371 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 372 372 if (drvdata->reading) { 373 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 373 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 374 374 return -EBUSY; 375 375 } 376 376 ··· 383 383 } 384 384 if (!ret) 385 385 csdev->refcnt++; 386 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 386 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 387 387 388 388 if (first_enable) 389 389 dev_dbg(&csdev->dev, "TMC-ETF enabled\n"); ··· 398 398 struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 399 399 bool last_disable = false; 400 400 401 - spin_lock_irqsave(&drvdata->spinlock, flags); 401 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 402 402 if (drvdata->reading) { 403 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 403 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 404 404 return; 405 405 } 406 406 ··· 410 410 coresight_set_mode(csdev, CS_MODE_DISABLED); 411 411 last_disable = true; 412 412 } 413 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 413 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 414 414 415 415 if (last_disable) 416 416 dev_dbg(&csdev->dev, "TMC-ETF disabled\n"); ··· 490 490 if (WARN_ON_ONCE(coresight_get_mode(csdev) != CS_MODE_PERF)) 491 491 return 0; 492 492 493 - spin_lock_irqsave(&drvdata->spinlock, flags); 493 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 494 494 495 495 /* Don't do anything if another tracer is using this sink */ 496 496 if (csdev->refcnt != 1) ··· 587 587 */ 588 588 CS_LOCK(drvdata->base); 589 589 out: 590 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 590 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 591 591 592 592 return to_read; 593 593 } ··· 705 705 drvdata->config_type != TMC_CONFIG_TYPE_ETF)) 706 706 return -EINVAL; 707 707 708 - spin_lock_irqsave(&drvdata->spinlock, flags); 708 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 709 709 710 710 if (drvdata->reading) { 711 711 ret = -EBUSY; ··· 737 737 738 738 drvdata->reading = true; 739 739 out: 740 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 740 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 741 741 742 742 return ret; 743 743 } ··· 754 754 drvdata->config_type != TMC_CONFIG_TYPE_ETF)) 755 755 return -EINVAL; 756 756 757 - spin_lock_irqsave(&drvdata->spinlock, flags); 757 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 758 758 759 759 /* Re-enable the TMC if need be */ 760 760 if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { 761 761 /* There is no point in reading a TMC in HW FIFO mode */ 762 762 mode = readl_relaxed(drvdata->base + TMC_MODE); 763 763 if (mode != TMC_MODE_CIRCULAR_BUFFER) { 764 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 764 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 765 765 return -EINVAL; 766 766 } 767 767 /* ··· 775 775 memset(drvdata->buf, 0, drvdata->size); 776 776 rc = __tmc_etb_enable_hw(drvdata); 777 777 if (rc) { 778 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 778 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 779 779 return rc; 780 780 } 781 781 } else { ··· 788 788 } 789 789 790 790 drvdata->reading = false; 791 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 791 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 792 792 793 793 /* 794 794 * Free allocated memory outside of the spinlock. There is no need
+22 -22
drivers/hwtracing/coresight/coresight-tmc-etr.c
··· 1251 1251 * buffer, provided the size matches. Any allocation has to be done 1252 1252 * with the lock released. 1253 1253 */ 1254 - spin_lock_irqsave(&drvdata->spinlock, flags); 1254 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 1255 1255 sysfs_buf = READ_ONCE(drvdata->sysfs_buf); 1256 1256 if (!sysfs_buf || (sysfs_buf->size != drvdata->size)) { 1257 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 1257 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 1258 1258 1259 1259 /* Allocate memory with the locks released */ 1260 1260 free_buf = new_buf = tmc_etr_setup_sysfs_buf(drvdata); ··· 1262 1262 return new_buf; 1263 1263 1264 1264 /* Let's try again */ 1265 - spin_lock_irqsave(&drvdata->spinlock, flags); 1265 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 1266 1266 } 1267 1267 1268 1268 if (drvdata->reading || coresight_get_mode(csdev) == CS_MODE_PERF) { ··· 1281 1281 } 1282 1282 1283 1283 out: 1284 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 1284 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 1285 1285 1286 1286 /* Free memory outside the spinlock if need be */ 1287 1287 if (free_buf) ··· 1299 1299 if (IS_ERR(sysfs_buf)) 1300 1300 return PTR_ERR(sysfs_buf); 1301 1301 1302 - spin_lock_irqsave(&drvdata->spinlock, flags); 1302 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 1303 1303 1304 1304 /* 1305 1305 * In sysFS mode we can have multiple writers per sink. Since this ··· 1318 1318 } 1319 1319 1320 1320 out: 1321 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 1321 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 1322 1322 1323 1323 if (!ret) 1324 1324 dev_dbg(&csdev->dev, "TMC-ETR enabled\n"); ··· 1637 1637 struct etr_perf_buffer *etr_perf = config; 1638 1638 struct etr_buf *etr_buf = etr_perf->etr_buf; 1639 1639 1640 - spin_lock_irqsave(&drvdata->spinlock, flags); 1640 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 1641 1641 1642 1642 /* Don't do anything if another tracer is using this sink */ 1643 1643 if (csdev->refcnt != 1) { 1644 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 1644 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 1645 1645 goto out; 1646 1646 } 1647 1647 1648 1648 if (WARN_ON(drvdata->perf_buf != etr_buf)) { 1649 1649 lost = true; 1650 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 1650 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 1651 1651 goto out; 1652 1652 } 1653 1653 ··· 1657 1657 tmc_sync_etr_buf(drvdata); 1658 1658 1659 1659 CS_LOCK(drvdata->base); 1660 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 1660 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 1661 1661 1662 1662 lost = etr_buf->full; 1663 1663 offset = etr_buf->offset; ··· 1726 1726 struct perf_output_handle *handle = data; 1727 1727 struct etr_perf_buffer *etr_perf = etm_perf_sink_config(handle); 1728 1728 1729 - spin_lock_irqsave(&drvdata->spinlock, flags); 1729 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 1730 1730 /* Don't use this sink if it is already claimed by sysFS */ 1731 1731 if (coresight_get_mode(csdev) == CS_MODE_SYSFS) { 1732 1732 rc = -EBUSY; ··· 1766 1766 } 1767 1767 1768 1768 unlock_out: 1769 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 1769 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 1770 1770 return rc; 1771 1771 } 1772 1772 ··· 1788 1788 unsigned long flags; 1789 1789 struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); 1790 1790 1791 - spin_lock_irqsave(&drvdata->spinlock, flags); 1791 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 1792 1792 1793 1793 if (drvdata->reading) { 1794 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 1794 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 1795 1795 return -EBUSY; 1796 1796 } 1797 1797 1798 1798 csdev->refcnt--; 1799 1799 if (csdev->refcnt) { 1800 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 1800 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 1801 1801 return -EBUSY; 1802 1802 } 1803 1803 ··· 1810 1810 /* Reset perf specific data */ 1811 1811 drvdata->perf_buf = NULL; 1812 1812 1813 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 1813 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 1814 1814 1815 1815 dev_dbg(&csdev->dev, "TMC-ETR disabled\n"); 1816 1816 return 0; ··· 1910 1910 if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR)) 1911 1911 return -EINVAL; 1912 1912 1913 - spin_lock_irqsave(&drvdata->spinlock, flags); 1913 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 1914 1914 if (drvdata->reading) { 1915 1915 ret = -EBUSY; 1916 1916 goto out; ··· 1932 1932 1933 1933 drvdata->reading = true; 1934 1934 out: 1935 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 1935 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 1936 1936 1937 1937 return ret; 1938 1938 } ··· 1946 1946 if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR)) 1947 1947 return -EINVAL; 1948 1948 1949 - spin_lock_irqsave(&drvdata->spinlock, flags); 1949 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 1950 1950 1951 1951 /* RE-enable the TMC if need be */ 1952 1952 if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) { ··· 1966 1966 } 1967 1967 1968 1968 drvdata->reading = false; 1969 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 1969 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 1970 1970 1971 1971 /* Free allocated memory out side of the spinlock */ 1972 1972 if (sysfs_buf) ··· 2023 2023 rbuf = &drvdata->resrv_buf; 2024 2024 2025 2025 /* Ensure there are no active crashdata read sessions */ 2026 - spin_lock_irqsave(&drvdata->spinlock, flags); 2026 + raw_spin_lock_irqsave(&drvdata->spinlock, flags); 2027 2027 if (!rbuf->reading) { 2028 2028 tmc_crashdata_set_invalid(drvdata); 2029 2029 rbuf->len = 0; 2030 2030 drvdata->etr_mode = ETR_MODE_RESRV; 2031 2031 err = 0; 2032 2032 } 2033 - spin_unlock_irqrestore(&drvdata->spinlock, flags); 2033 + raw_spin_unlock_irqrestore(&drvdata->spinlock, flags); 2034 2034 return err; 2035 2035 } 2036 2036
+1 -1
drivers/hwtracing/coresight/coresight-tmc.h
··· 249 249 struct coresight_device *csdev; 250 250 struct miscdevice miscdev; 251 251 struct miscdevice crashdev; 252 - spinlock_t spinlock; 252 + raw_spinlock_t spinlock; 253 253 pid_t pid; 254 254 bool reading; 255 255 bool stop_on_flush;