diff --git a/Documentation/ABI/testing/sysfs-bus-intel_th-devices-msc b/Documentation/ABI/testing/sysfs-bus-intel_th-devices-msc index 456cb62b384c..7fd2601c2831 100644 --- a/Documentation/ABI/testing/sysfs-bus-intel_th-devices-msc +++ b/Documentation/ABI/testing/sysfs-bus-intel_th-devices-msc @@ -40,3 +40,11 @@ Description: (RW) Trigger window switch for the MSC's buffer, in triggering a window switch for the buffer. Returns an error in any other operating mode or attempts to write something other than "1". +What: /sys/bus/intel_th/devices/-msc/stop_on_full +Date: March 2020 +KernelVersion: 5.7 +Contact: Alexander Shishkin +Description: (RW) Configure whether trace stops when the last available window + becomes full (1/y/Y) or wraps around and continues until the next + window becomes available again (0/n/N). + diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c index 3cd2489d398c..3a77551fb4fc 100644 --- a/drivers/hwtracing/intel_th/msu.c +++ b/drivers/hwtracing/intel_th/msu.c @@ -138,6 +138,7 @@ struct msc { struct list_head win_list; struct sg_table single_sgt; struct msc_window *cur_win; + struct msc_window *switch_on_unlock; unsigned long nr_pages; unsigned long single_sz; unsigned int single_wrap : 1; @@ -154,6 +155,8 @@ struct msc { struct list_head iter_list; + bool stop_on_full; + /* config */ unsigned int enabled : 1, wrap : 1, @@ -1718,6 +1721,10 @@ void intel_th_msc_window_unlock(struct device *dev, struct sg_table *sgt) return; msc_win_set_lockout(win, WIN_LOCKED, WIN_READY); + if (msc->switch_on_unlock == win) { + msc->switch_on_unlock = NULL; + msc_win_switch(msc); + } } EXPORT_SYMBOL_GPL(intel_th_msc_window_unlock); @@ -1758,7 +1765,11 @@ static irqreturn_t intel_th_msc_interrupt(struct intel_th_device *thdev) /* next window: if READY, proceed, if LOCKED, stop the trace */ if (msc_win_set_lockout(next_win, WIN_READY, WIN_INUSE)) { - schedule_work(&msc->work); + if (msc->stop_on_full) + schedule_work(&msc->work); + else + msc->switch_on_unlock = next_win; + return IRQ_HANDLED; } @@ -2051,11 +2062,36 @@ win_switch_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_WO(win_switch); +static ssize_t stop_on_full_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct msc *msc = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", msc->stop_on_full); +} + +static ssize_t stop_on_full_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct msc *msc = dev_get_drvdata(dev); + int ret; + + ret = kstrtobool(buf, &msc->stop_on_full); + if (ret) + return ret; + + return size; +} + +static DEVICE_ATTR_RW(stop_on_full); + static struct attribute *msc_output_attrs[] = { &dev_attr_wrap.attr, &dev_attr_mode.attr, &dev_attr_nr_pages.attr, &dev_attr_win_switch.attr, + &dev_attr_stop_on_full.attr, NULL, };