mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-10 07:50:04 +00:00
intel_th: msu: Get rid of the window size limit
Currently, the window size is limited to the maximum number of sg entries in one table. This is because the code addresses individual blocks within the window by their numeric index. In reality, though, the blocks most often are iterated through sequentially. By rewriting the logic to use sg pointers instead of block indices we loose the necessity to dereference them directly and gain the ability to use multiple chained tables if necessary. Get rid of the limitation by replacing index-based block accesses with sequential block accesses. Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Link: https://lore.kernel.org/r/20190705141425.19894-4-alexander.shishkin@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
f220df66f6
commit
57b69a1f66
@ -95,8 +95,8 @@ struct msc_iter {
|
|||||||
struct msc_window *start_win;
|
struct msc_window *start_win;
|
||||||
struct msc_window *win;
|
struct msc_window *win;
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
int start_block;
|
struct scatterlist *start_block;
|
||||||
int block;
|
struct scatterlist *block;
|
||||||
unsigned int block_off;
|
unsigned int block_off;
|
||||||
unsigned int wrap_count;
|
unsigned int wrap_count;
|
||||||
unsigned int eof;
|
unsigned int eof;
|
||||||
@ -269,28 +269,25 @@ static inline bool msc_block_is_empty(struct msc_block_desc *bdesc)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct msc_block_desc *
|
static inline struct scatterlist *msc_win_base_sg(struct msc_window *win)
|
||||||
msc_win_block(struct msc_window *win, unsigned int block)
|
|
||||||
{
|
{
|
||||||
return sg_virt(&win->sgt->sgl[block]);
|
return win->sgt->sgl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t
|
static inline struct msc_block_desc *msc_win_base(struct msc_window *win)
|
||||||
msc_win_actual_bsz(struct msc_window *win, unsigned int block)
|
|
||||||
{
|
{
|
||||||
return win->sgt->sgl[block].length;
|
return sg_virt(msc_win_base_sg(win));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline dma_addr_t
|
static inline dma_addr_t msc_win_base_dma(struct msc_window *win)
|
||||||
msc_win_baddr(struct msc_window *win, unsigned int block)
|
|
||||||
{
|
{
|
||||||
return sg_dma_address(&win->sgt->sgl[block]);
|
return sg_dma_address(msc_win_base_sg(win));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long
|
static inline unsigned long
|
||||||
msc_win_bpfn(struct msc_window *win, unsigned int block)
|
msc_win_base_pfn(struct msc_window *win)
|
||||||
{
|
{
|
||||||
return msc_win_baddr(win, block) >> PAGE_SHIFT;
|
return PFN_DOWN(msc_win_base_dma(win));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -320,11 +317,12 @@ static struct msc_window *msc_next_window(struct msc_window *win)
|
|||||||
|
|
||||||
static size_t msc_win_total_sz(struct msc_window *win)
|
static size_t msc_win_total_sz(struct msc_window *win)
|
||||||
{
|
{
|
||||||
|
struct scatterlist *sg;
|
||||||
unsigned int blk;
|
unsigned int blk;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
|
||||||
for (blk = 0; blk < win->nr_segs; blk++) {
|
for_each_sg(win->sgt->sgl, sg, win->nr_segs, blk) {
|
||||||
struct msc_block_desc *bdesc = msc_win_block(win, blk);
|
struct msc_block_desc *bdesc = sg_virt(sg);
|
||||||
|
|
||||||
if (msc_block_wrapped(bdesc))
|
if (msc_block_wrapped(bdesc))
|
||||||
return win->nr_blocks << PAGE_SHIFT;
|
return win->nr_blocks << PAGE_SHIFT;
|
||||||
@ -365,7 +363,7 @@ msc_find_window(struct msc *msc, struct sg_table *sgt, bool nonempty)
|
|||||||
found++;
|
found++;
|
||||||
|
|
||||||
/* skip the empty ones */
|
/* skip the empty ones */
|
||||||
if (nonempty && msc_block_is_empty(msc_win_block(win, 0)))
|
if (nonempty && msc_block_is_empty(msc_win_base(win)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (found)
|
if (found)
|
||||||
@ -399,44 +397,38 @@ static struct msc_window *msc_oldest_window(struct msc *msc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* msc_win_oldest_block() - locate the oldest block in a given window
|
* msc_win_oldest_sg() - locate the oldest block in a given window
|
||||||
* @win: window to look at
|
* @win: window to look at
|
||||||
*
|
*
|
||||||
* Return: index of the block with the oldest data
|
* Return: index of the block with the oldest data
|
||||||
*/
|
*/
|
||||||
static unsigned int msc_win_oldest_block(struct msc_window *win)
|
static struct scatterlist *msc_win_oldest_sg(struct msc_window *win)
|
||||||
{
|
{
|
||||||
unsigned int blk;
|
unsigned int blk;
|
||||||
struct msc_block_desc *bdesc = msc_win_block(win, 0);
|
struct scatterlist *sg;
|
||||||
|
struct msc_block_desc *bdesc = msc_win_base(win);
|
||||||
|
|
||||||
/* without wrapping, first block is the oldest */
|
/* without wrapping, first block is the oldest */
|
||||||
if (!msc_block_wrapped(bdesc))
|
if (!msc_block_wrapped(bdesc))
|
||||||
return 0;
|
return msc_win_base_sg(win);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* with wrapping, last written block contains both the newest and the
|
* with wrapping, last written block contains both the newest and the
|
||||||
* oldest data for this window.
|
* oldest data for this window.
|
||||||
*/
|
*/
|
||||||
for (blk = 0; blk < win->nr_segs; blk++) {
|
for_each_sg(win->sgt->sgl, sg, win->nr_segs, blk) {
|
||||||
bdesc = msc_win_block(win, blk);
|
struct msc_block_desc *bdesc = sg_virt(sg);
|
||||||
|
|
||||||
if (msc_block_last_written(bdesc))
|
if (msc_block_last_written(bdesc))
|
||||||
return blk;
|
return sg;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return msc_win_base_sg(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct msc_block_desc *msc_iter_bdesc(struct msc_iter *iter)
|
static struct msc_block_desc *msc_iter_bdesc(struct msc_iter *iter)
|
||||||
{
|
{
|
||||||
return msc_win_block(iter->win, iter->block);
|
return sg_virt(iter->block);
|
||||||
}
|
|
||||||
|
|
||||||
static void msc_iter_init(struct msc_iter *iter)
|
|
||||||
{
|
|
||||||
memset(iter, 0, sizeof(*iter));
|
|
||||||
iter->start_block = -1;
|
|
||||||
iter->block = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct msc_iter *msc_iter_install(struct msc *msc)
|
static struct msc_iter *msc_iter_install(struct msc *msc)
|
||||||
@ -461,7 +453,6 @@ static struct msc_iter *msc_iter_install(struct msc *msc)
|
|||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
msc_iter_init(iter);
|
|
||||||
iter->msc = msc;
|
iter->msc = msc;
|
||||||
|
|
||||||
list_add_tail(&iter->entry, &msc->iter_list);
|
list_add_tail(&iter->entry, &msc->iter_list);
|
||||||
@ -482,10 +473,10 @@ static void msc_iter_remove(struct msc_iter *iter, struct msc *msc)
|
|||||||
|
|
||||||
static void msc_iter_block_start(struct msc_iter *iter)
|
static void msc_iter_block_start(struct msc_iter *iter)
|
||||||
{
|
{
|
||||||
if (iter->start_block != -1)
|
if (iter->start_block)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
iter->start_block = msc_win_oldest_block(iter->win);
|
iter->start_block = msc_win_oldest_sg(iter->win);
|
||||||
iter->block = iter->start_block;
|
iter->block = iter->start_block;
|
||||||
iter->wrap_count = 0;
|
iter->wrap_count = 0;
|
||||||
|
|
||||||
@ -509,7 +500,7 @@ static int msc_iter_win_start(struct msc_iter *iter, struct msc *msc)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
iter->win = iter->start_win;
|
iter->win = iter->start_win;
|
||||||
iter->start_block = -1;
|
iter->start_block = NULL;
|
||||||
|
|
||||||
msc_iter_block_start(iter);
|
msc_iter_block_start(iter);
|
||||||
|
|
||||||
@ -519,7 +510,7 @@ static int msc_iter_win_start(struct msc_iter *iter, struct msc *msc)
|
|||||||
static int msc_iter_win_advance(struct msc_iter *iter)
|
static int msc_iter_win_advance(struct msc_iter *iter)
|
||||||
{
|
{
|
||||||
iter->win = msc_next_window(iter->win);
|
iter->win = msc_next_window(iter->win);
|
||||||
iter->start_block = -1;
|
iter->start_block = NULL;
|
||||||
|
|
||||||
if (iter->win == iter->start_win) {
|
if (iter->win == iter->start_win) {
|
||||||
iter->eof++;
|
iter->eof++;
|
||||||
@ -549,8 +540,10 @@ static int msc_iter_block_advance(struct msc_iter *iter)
|
|||||||
return msc_iter_win_advance(iter);
|
return msc_iter_win_advance(iter);
|
||||||
|
|
||||||
/* block advance */
|
/* block advance */
|
||||||
if (++iter->block == iter->win->nr_segs)
|
if (sg_is_last(iter->block))
|
||||||
iter->block = 0;
|
iter->block = msc_win_base_sg(iter->win);
|
||||||
|
else
|
||||||
|
iter->block = sg_next(iter->block);
|
||||||
|
|
||||||
/* no wrapping, sanity check in case there is no last written block */
|
/* no wrapping, sanity check in case there is no last written block */
|
||||||
if (!iter->wrap_count && iter->block == iter->start_block)
|
if (!iter->wrap_count && iter->block == iter->start_block)
|
||||||
@ -655,14 +648,15 @@ next_block:
|
|||||||
static void msc_buffer_clear_hw_header(struct msc *msc)
|
static void msc_buffer_clear_hw_header(struct msc *msc)
|
||||||
{
|
{
|
||||||
struct msc_window *win;
|
struct msc_window *win;
|
||||||
|
struct scatterlist *sg;
|
||||||
|
|
||||||
list_for_each_entry(win, &msc->win_list, entry) {
|
list_for_each_entry(win, &msc->win_list, entry) {
|
||||||
unsigned int blk;
|
unsigned int blk;
|
||||||
size_t hw_sz = sizeof(struct msc_block_desc) -
|
size_t hw_sz = sizeof(struct msc_block_desc) -
|
||||||
offsetof(struct msc_block_desc, hw_tag);
|
offsetof(struct msc_block_desc, hw_tag);
|
||||||
|
|
||||||
for (blk = 0; blk < win->nr_segs; blk++) {
|
for_each_sg(win->sgt->sgl, sg, win->nr_segs, blk) {
|
||||||
struct msc_block_desc *bdesc = msc_win_block(win, blk);
|
struct msc_block_desc *bdesc = sg_virt(sg);
|
||||||
|
|
||||||
memset(&bdesc->hw_tag, 0, hw_sz);
|
memset(&bdesc->hw_tag, 0, hw_sz);
|
||||||
}
|
}
|
||||||
@ -1005,10 +999,9 @@ static int __msc_buffer_win_alloc(struct msc_window *win,
|
|||||||
return nr_segs;
|
return nr_segs;
|
||||||
|
|
||||||
err_nomem:
|
err_nomem:
|
||||||
for (i--; i >= 0; i--)
|
for_each_sg(win->sgt->sgl, sg_ptr, i, ret)
|
||||||
dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE,
|
dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE,
|
||||||
msc_win_block(win, i),
|
sg_virt(sg_ptr), sg_dma_address(sg_ptr));
|
||||||
msc_win_baddr(win, i));
|
|
||||||
|
|
||||||
sg_free_table(win->sgt);
|
sg_free_table(win->sgt);
|
||||||
|
|
||||||
@ -1018,20 +1011,26 @@ err_nomem:
|
|||||||
#ifdef CONFIG_X86
|
#ifdef CONFIG_X86
|
||||||
static void msc_buffer_set_uc(struct msc_window *win, unsigned int nr_segs)
|
static void msc_buffer_set_uc(struct msc_window *win, unsigned int nr_segs)
|
||||||
{
|
{
|
||||||
|
struct scatterlist *sg_ptr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < nr_segs; i++)
|
for_each_sg(win->sgt->sgl, sg_ptr, nr_segs, i) {
|
||||||
/* Set the page as uncached */
|
/* Set the page as uncached */
|
||||||
set_memory_uc((unsigned long)msc_win_block(win, i), 1);
|
set_memory_uc((unsigned long)sg_virt(sg_ptr),
|
||||||
|
PFN_DOWN(sg_ptr->length));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void msc_buffer_set_wb(struct msc_window *win)
|
static void msc_buffer_set_wb(struct msc_window *win)
|
||||||
{
|
{
|
||||||
|
struct scatterlist *sg_ptr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < win->nr_segs; i++)
|
for_each_sg(win->sgt->sgl, sg_ptr, win->nr_segs, i) {
|
||||||
/* Reset the page to write-back */
|
/* Reset the page to write-back */
|
||||||
set_memory_wb((unsigned long)msc_win_block(win, i), 1);
|
set_memory_wb((unsigned long)sg_virt(sg_ptr),
|
||||||
|
PFN_DOWN(sg_ptr->length));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else /* !X86 */
|
#else /* !X86 */
|
||||||
static inline void
|
static inline void
|
||||||
@ -1057,13 +1056,6 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks)
|
|||||||
if (!nr_blocks)
|
if (!nr_blocks)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
|
||||||
* This limitation hold as long as we need random access to the
|
|
||||||
* block. When that changes, this can go away.
|
|
||||||
*/
|
|
||||||
if (nr_blocks > SG_MAX_SINGLE_ALLOC)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
win = kzalloc(sizeof(*win), GFP_KERNEL);
|
win = kzalloc(sizeof(*win), GFP_KERNEL);
|
||||||
if (!win)
|
if (!win)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -1096,8 +1088,8 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks)
|
|||||||
win->nr_blocks = nr_blocks;
|
win->nr_blocks = nr_blocks;
|
||||||
|
|
||||||
if (list_empty(&msc->win_list)) {
|
if (list_empty(&msc->win_list)) {
|
||||||
msc->base = msc_win_block(win, 0);
|
msc->base = msc_win_base(win);
|
||||||
msc->base_addr = msc_win_baddr(win, 0);
|
msc->base_addr = msc_win_base_dma(win);
|
||||||
msc->cur_win = win;
|
msc->cur_win = win;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1114,14 +1106,15 @@ err_nomem:
|
|||||||
|
|
||||||
static void __msc_buffer_win_free(struct msc *msc, struct msc_window *win)
|
static void __msc_buffer_win_free(struct msc *msc, struct msc_window *win)
|
||||||
{
|
{
|
||||||
|
struct scatterlist *sg;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < win->nr_segs; i++) {
|
for_each_sg(win->sgt->sgl, sg, win->nr_segs, i) {
|
||||||
struct page *page = sg_page(&win->sgt->sgl[i]);
|
struct page *page = sg_page(sg);
|
||||||
|
|
||||||
page->mapping = NULL;
|
page->mapping = NULL;
|
||||||
dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE,
|
dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE,
|
||||||
msc_win_block(win, i), msc_win_baddr(win, i));
|
sg_virt(sg), sg_dma_address(sg));
|
||||||
}
|
}
|
||||||
sg_free_table(win->sgt);
|
sg_free_table(win->sgt);
|
||||||
}
|
}
|
||||||
@ -1167,6 +1160,7 @@ static void msc_buffer_relink(struct msc *msc)
|
|||||||
|
|
||||||
/* call with msc::mutex locked */
|
/* call with msc::mutex locked */
|
||||||
list_for_each_entry(win, &msc->win_list, entry) {
|
list_for_each_entry(win, &msc->win_list, entry) {
|
||||||
|
struct scatterlist *sg;
|
||||||
unsigned int blk;
|
unsigned int blk;
|
||||||
u32 sw_tag = 0;
|
u32 sw_tag = 0;
|
||||||
|
|
||||||
@ -1182,12 +1176,12 @@ static void msc_buffer_relink(struct msc *msc)
|
|||||||
next_win = list_next_entry(win, entry);
|
next_win = list_next_entry(win, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (blk = 0; blk < win->nr_segs; blk++) {
|
for_each_sg(win->sgt->sgl, sg, win->nr_segs, blk) {
|
||||||
struct msc_block_desc *bdesc = msc_win_block(win, blk);
|
struct msc_block_desc *bdesc = sg_virt(sg);
|
||||||
|
|
||||||
memset(bdesc, 0, sizeof(*bdesc));
|
memset(bdesc, 0, sizeof(*bdesc));
|
||||||
|
|
||||||
bdesc->next_win = msc_win_bpfn(next_win, 0);
|
bdesc->next_win = msc_win_base_pfn(next_win);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Similarly to last window, last block should point
|
* Similarly to last window, last block should point
|
||||||
@ -1195,13 +1189,15 @@ static void msc_buffer_relink(struct msc *msc)
|
|||||||
*/
|
*/
|
||||||
if (blk == win->nr_segs - 1) {
|
if (blk == win->nr_segs - 1) {
|
||||||
sw_tag |= MSC_SW_TAG_LASTBLK;
|
sw_tag |= MSC_SW_TAG_LASTBLK;
|
||||||
bdesc->next_blk = msc_win_bpfn(win, 0);
|
bdesc->next_blk = msc_win_base_pfn(win);
|
||||||
} else {
|
} else {
|
||||||
bdesc->next_blk = msc_win_bpfn(win, blk + 1);
|
dma_addr_t addr = sg_dma_address(sg_next(sg));
|
||||||
|
|
||||||
|
bdesc->next_blk = PFN_DOWN(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bdesc->sw_tag = sw_tag;
|
bdesc->sw_tag = sw_tag;
|
||||||
bdesc->block_sz = msc_win_actual_bsz(win, blk) / 64;
|
bdesc->block_sz = sg->length / 64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1360,6 +1356,7 @@ static int msc_buffer_free_unless_used(struct msc *msc)
|
|||||||
static struct page *msc_buffer_get_page(struct msc *msc, unsigned long pgoff)
|
static struct page *msc_buffer_get_page(struct msc *msc, unsigned long pgoff)
|
||||||
{
|
{
|
||||||
struct msc_window *win;
|
struct msc_window *win;
|
||||||
|
struct scatterlist *sg;
|
||||||
unsigned int blk;
|
unsigned int blk;
|
||||||
|
|
||||||
if (msc->mode == MSC_MODE_SINGLE)
|
if (msc->mode == MSC_MODE_SINGLE)
|
||||||
@ -1374,9 +1371,9 @@ static struct page *msc_buffer_get_page(struct msc *msc, unsigned long pgoff)
|
|||||||
found:
|
found:
|
||||||
pgoff -= win->pgoff;
|
pgoff -= win->pgoff;
|
||||||
|
|
||||||
for (blk = 0; blk < win->nr_segs; blk++) {
|
for_each_sg(win->sgt->sgl, sg, win->nr_segs, blk) {
|
||||||
struct page *page = sg_page(&win->sgt->sgl[blk]);
|
struct page *page = sg_page(sg);
|
||||||
size_t pgsz = PFN_DOWN(msc_win_actual_bsz(win, blk));
|
size_t pgsz = PFN_DOWN(sg->length);
|
||||||
|
|
||||||
if (pgoff < pgsz)
|
if (pgoff < pgsz)
|
||||||
return page + pgoff;
|
return page + pgoff;
|
||||||
@ -1680,8 +1677,8 @@ static void msc_win_switch(struct msc *msc)
|
|||||||
else
|
else
|
||||||
msc->cur_win = list_next_entry(msc->cur_win, entry);
|
msc->cur_win = list_next_entry(msc->cur_win, entry);
|
||||||
|
|
||||||
msc->base = msc_win_block(msc->cur_win, 0);
|
msc->base = msc_win_base(msc->cur_win);
|
||||||
msc->base_addr = msc_win_baddr(msc->cur_win, 0);
|
msc->base_addr = msc_win_base_dma(msc->cur_win);
|
||||||
|
|
||||||
intel_th_trace_switch(msc->thdev);
|
intel_th_trace_switch(msc->thdev);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user