From: Alexander Shishkin alexander.shishkin@linux.intel.com
mainline inclusion from mainline-v5.2-rc1 commit aad14ad3cf3a63bd258b65e18d49c3eb8472d344 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I47H3V CVE: NA
--------------------------------
Now that we have a way to switch between MSC buffer windows, add code to track the current window. The hardware register NWSA that contains the address of the next window is unfortunately not always usable, and since the driver has full control of the window switching, there is no reason not to keep this on the software side.
Signed-off-by: Alexander Shishkin alexander.shishkin@linux.intel.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Jackie Liu liuyun01@kylinos.cn Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Reviewed-by: Xie XiuQi xiexiuqi@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/hwtracing/intel_th/msu.c | 79 ++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 30 deletions(-)
diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c index 49e965ac81be1..2fdc0f6268b86 100644 --- a/drivers/hwtracing/intel_th/msu.c +++ b/drivers/hwtracing/intel_th/msu.c @@ -75,6 +75,7 @@ struct msc_iter { * @thdev: intel_th_device pointer * @win_list: list of windows in multiblock mode * @single_sgt: single mode buffer + * @cur_win: current window * @nr_pages: total number of pages allocated for this buffer * @single_sz: amount of data in single mode * @single_wrap: single mode wrap occurred @@ -97,6 +98,7 @@ struct msc {
struct list_head win_list; struct sg_table single_sgt; + struct msc_window *cur_win; unsigned long nr_pages; unsigned long single_sz; unsigned int single_wrap : 1; @@ -151,6 +153,31 @@ msc_win_bpfn(struct msc_window *win, unsigned int block) return msc_win_baddr(win, block) >> PAGE_SHIFT; }
+/** + * msc_is_last_win() - check if a window is the last one for a given MSC + * @win: window + * Return: true if @win is the last window in MSC's multiblock buffer + */ +static inline bool msc_is_last_win(struct msc_window *win) +{ + return win->entry.next == &win->msc->win_list; +} + +/** + * msc_next_window() - return next window in the multiblock buffer + * @win: current window + * + * Return: window following the current one + */ +static struct msc_window *msc_next_window(struct msc_window *win) +{ + if (msc_is_last_win(win)) + return list_first_entry(&win->msc->win_list, struct msc_window, + entry); + + return list_next_entry(win, entry); +} + /** * msc_oldest_window() - locate the window with oldest data * @msc: MSC device @@ -162,9 +189,7 @@ msc_win_bpfn(struct msc_window *win, unsigned int block) */ static struct msc_window *msc_oldest_window(struct msc *msc) { - struct msc_window *win; - u32 reg = ioread32(msc->reg_base + REG_MSU_MSC0NWSA); - unsigned long win_addr = (unsigned long)reg << PAGE_SHIFT; + struct msc_window *win, *next = msc_next_window(msc->cur_win); unsigned int found = 0;
if (list_empty(&msc->win_list)) @@ -176,7 +201,7 @@ static struct msc_window *msc_oldest_window(struct msc *msc) * something like 2, in which case we're good */ list_for_each_entry(win, &msc->win_list, entry) { - if (sg_dma_address(win->sgt.sgl) == win_addr) + if (win == next) found++;
/* skip the empty ones */ @@ -219,31 +244,6 @@ static unsigned int msc_win_oldest_block(struct msc_window *win) return 0; }
-/** - * msc_is_last_win() - check if a window is the last one for a given MSC - * @win: window - * Return: true if @win is the last window in MSC's multiblock buffer - */ -static inline bool msc_is_last_win(struct msc_window *win) -{ - return win->entry.next == &win->msc->win_list; -} - -/** - * msc_next_window() - return next window in the multiblock buffer - * @win: current window - * - * Return: window following the current one - */ -static struct msc_window *msc_next_window(struct msc_window *win) -{ - if (msc_is_last_win(win)) - return list_first_entry(&win->msc->win_list, struct msc_window, - entry); - - return list_next_entry(win, entry); -} - static struct msc_block_desc *msc_iter_bdesc(struct msc_iter *iter) { return msc_win_block(iter->win, iter->block); @@ -822,6 +822,7 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks) if (list_empty(&msc->win_list)) { msc->base = msc_win_block(win, 0); msc->base_addr = msc_win_baddr(win, 0); + msc->cur_win = win; }
list_add_tail(&win->entry, &msc->win_list); @@ -1383,6 +1384,24 @@ static int intel_th_msc_init(struct msc *msc) return 0; }
+static void msc_win_switch(struct msc *msc) +{ + struct msc_window *last, *first; + + first = list_first_entry(&msc->win_list, struct msc_window, entry); + last = list_last_entry(&msc->win_list, struct msc_window, entry); + + if (msc_is_last_win(msc->cur_win)) + msc->cur_win = first; + else + msc->cur_win = list_next_entry(msc->cur_win, entry); + + msc->base = msc_win_block(msc->cur_win, 0); + msc->base_addr = msc_win_baddr(msc->cur_win, 0); + + intel_th_trace_switch(msc->thdev); +} + static irqreturn_t intel_th_msc_interrupt(struct intel_th_device *thdev) { struct msc *msc = dev_get_drvdata(&thdev->dev); @@ -1591,7 +1610,7 @@ win_switch_store(struct device *dev, struct device_attribute *attr, if (msc->mode != MSC_MODE_MULTI) ret = -ENOTSUPP; else - ret = intel_th_trace_switch(msc->thdev); + msc_win_switch(msc); mutex_unlock(&msc->buf_mutex);
return ret ? ret : size;