From 77b6f79df66ed2919dedb834edea630f40079f12 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 6 Jan 2022 16:06:21 -0800 Subject: drm/i915/guc: Update to GuC version 69.0.3 Update to the latest GuC release. The latest GuC firmware introduces a number of interface changes: GuC may return NO_RESPONSE_RETRY message for requests sent over CTB. Add support for this reply and try resending the request again as a new CTB message. A KLV (key-length-value) mechanism is now used for passing configuration data such as CTB management. With the new KLV scheme, the old CTB management actions are no longer used and are removed. Register capture on hang is now supported by GuC. Full i915 support for this will be added by a later patch. A minimum support of providing capture memory and register lists is required though, so add that in. The device id of the current platform needs to be provided at init time. The 'poll CS' w/a (Wa_22012773006) was blanket enabled by previous versions of GuC. It must now be explicitly requested by the KMD. So, add in the code to turn it on when relevant. The GuC log entry format has changed. This requires adding a new field to the log header structure to mark the wrap point at the end of the buffer (as the buffer size is no longer a multiple of the log entry size). New CTB notification messages are now sent for some things that were previously only sent via MMIO notifications. Of these, the crash dump notification was not really being handled by i915. It called the log flush code but that only flushed the regular debug log and then only if relay logging was enabled. So just report an error message instead. The 'exception' notification was just being ignored completely. So add an error message for that as well. Note that in either the crash dump or the exception case, the GuC is basically dead. The KMD will detect this via the heartbeat and trigger both an error log (which will include the crash dump as part of the GuC log) and a GT reset. So no other processing is really required. Signed-off-by: John Harrison Signed-off-by: Michal Wajdeczko Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20220107000622.292081-3-John.C.Harrison@Intel.com --- Documentation/gpu/i915.rst | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation/gpu') diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst index b7d801993bfa..bcaefc952764 100644 --- a/Documentation/gpu/i915.rst +++ b/Documentation/gpu/i915.rst @@ -539,6 +539,7 @@ GuC ABI .. kernel-doc:: drivers/gpu/drm/i915/gt/uc/abi/guc_communication_mmio_abi.h .. kernel-doc:: drivers/gpu/drm/i915/gt/uc/abi/guc_communication_ctb_abi.h .. kernel-doc:: drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h +.. kernel-doc:: drivers/gpu/drm/i915/gt/uc/abi/guc_klvs_abi.h HuC --- -- cgit v1.2.3 From 1148836fd3226c20de841084aba24184d4fbbe77 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 2 Feb 2022 14:55:29 +0100 Subject: Revert "fbdev: Garbage collect fbdev scrolling acceleration, part 1 (from TODO list)" This reverts commit b3ec8cdf457e5e63d396fe1346cc788cf7c1b578. Revert the second (of 2) commits which disabled scrolling acceleration in fbcon/fbdev. It introduced a regression for fbdev-supported graphic cards because of the performance penalty by doing screen scrolling by software instead of using the existing graphic card 2D hardware acceleration. Console scrolling acceleration was disabled by dropping code which checked at runtime the driver hardware capabilities for the BINFO_HWACCEL_COPYAREA or FBINFO_HWACCEL_FILLRECT flags and if set, it enabled scrollmode SCROLL_MOVE which uses hardware acceleration to move screen contents. After dropping those checks scrollmode was hard-wired to SCROLL_REDRAW instead, which forces all graphic cards to redraw every character at the new screen position when scrolling. This change effectively disabled all hardware-based scrolling acceleration for ALL drivers, because now all kind of 2D hardware acceleration (bitblt, fillrect) in the drivers isn't used any longer. The original commit message mentions that only 3 DRM drivers (nouveau, omapdrm and gma500) used hardware acceleration in the past and thus code for checking and using scrolling acceleration is obsolete. This statement is NOT TRUE, because beside the DRM drivers there are around 35 other fbdev drivers which depend on fbdev/fbcon and still provide hardware acceleration for fbdev/fbcon. The original commit message also states that syzbot found lots of bugs in fbcon and thus it's "often the solution to just delete code and remove features". This is true, and the bugs - which actually affected all users of fbcon, including DRM - were fixed, or code was dropped like e.g. the support for software scrollback in vgacon (commit 973c096f6a85). So to further analyze which bugs were found by syzbot, I've looked through all patches in drivers/video which were tagged with syzbot or syzkaller back to year 2005. The vast majority fixed the reported issues on a higher level, e.g. when screen is to be resized, or when font size is to be changed. The few ones which touched driver code fixed a real driver bug, e.g. by adding a check. But NONE of those patches touched code of either the SCROLL_MOVE or the SCROLL_REDRAW case. That means, there was no real reason why SCROLL_MOVE had to be ripped-out and just SCROLL_REDRAW had to be used instead. The only reason I can imagine so far was that SCROLL_MOVE wasn't used by DRM and as such it was assumed that it could go away. That argument completely missed the fact that SCROLL_MOVE is still heavily used by fbdev (non-DRM) drivers. Some people mention that using memcpy() instead of the hardware acceleration is pretty much the same speed. But that's not true, at least not for older graphic cards and machines where we see speed decreases by factor 10 and more and thus this change leads to console responsiveness way worse than before. That's why the original commit is to be reverted. By reverting we reintroduce hardware-based scrolling acceleration and fix the performance regression for fbdev drivers. There isn't any impact on DRM when reverting those patches. Signed-off-by: Helge Deller Acked-by: Geert Uytterhoeven Acked-by: Sven Schnelle Cc: stable@vger.kernel.org # v5.16+ Signed-off-by: Helge Deller Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220202135531.92183-2-deller@gmx.de --- Documentation/gpu/todo.rst | 13 +- drivers/video/fbdev/core/bitblit.c | 16 + drivers/video/fbdev/core/fbcon.c | 509 ++++++++++++++++++++++++++++++-- drivers/video/fbdev/core/fbcon.h | 59 ++++ drivers/video/fbdev/core/fbcon_ccw.c | 28 +- drivers/video/fbdev/core/fbcon_cw.c | 28 +- drivers/video/fbdev/core/fbcon_rotate.h | 9 + drivers/video/fbdev/core/fbcon_ud.c | 37 ++- drivers/video/fbdev/core/tileblit.c | 16 + drivers/video/fbdev/skeletonfb.c | 12 +- include/linux/fb.h | 2 +- 11 files changed, 678 insertions(+), 51 deletions(-) (limited to 'Documentation/gpu') diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index da138dd39883..29506815d24a 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -303,19 +303,16 @@ Level: Advanced Garbage collect fbdev scrolling acceleration -------------------------------------------- -Scroll acceleration has been disabled in fbcon. Now it works as the old -SCROLL_REDRAW mode. A ton of code was removed in fbcon.c and the hook bmove was -removed from fbcon_ops. -Remaining tasks: +Scroll acceleration is disabled in fbcon by hard-wiring p->scrollmode = +SCROLL_REDRAW. There's a ton of code this will allow us to remove: -- a bunch of the hooks in fbcon_ops could be removed or simplified by calling +- lots of code in fbcon.c + +- a bunch of the hooks in fbcon_ops, maybe the remaining hooks could be called directly instead of the function table (with a switch on p->rotate) - fb_copyarea is unused after this, and can be deleted from all drivers -- after that, fb_copyarea can be deleted from fb_ops in include/linux/fb.h as - well as cfb_copyarea - Note that not all acceleration code can be deleted, since clearing and cursor support is still accelerated, which might be good candidates for further deletion projects. diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c index 01fae2c96965..f98e8f298bc1 100644 --- a/drivers/video/fbdev/core/bitblit.c +++ b/drivers/video/fbdev/core/bitblit.c @@ -43,6 +43,21 @@ static void update_attr(u8 *dst, u8 *src, int attribute, } } +static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) +{ + struct fb_copyarea area; + + area.sx = sx * vc->vc_font.width; + area.sy = sy * vc->vc_font.height; + area.dx = dx * vc->vc_font.width; + area.dy = dy * vc->vc_font.height; + area.height = height * vc->vc_font.height; + area.width = width * vc->vc_font.width; + + info->fbops->fb_copyarea(info, &area); +} + static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx, int height, int width) { @@ -378,6 +393,7 @@ static int bit_update_start(struct fb_info *info) void fbcon_set_bitops(struct fbcon_ops *ops) { + ops->bmove = bit_bmove; ops->clear = bit_clear; ops->putcs = bit_putcs; ops->clear_margins = bit_clear_margins; diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 99ecd9a6d844..fc34caddf9cf 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -173,6 +173,8 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s, int count, int ypos, int xpos); static void fbcon_clear_margins(struct vc_data *vc, int bottom_only); static void fbcon_cursor(struct vc_data *vc, int mode); +static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, + int height, int width); static int fbcon_switch(struct vc_data *vc); static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table); @@ -180,8 +182,16 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table); /* * Internal routines */ +static __inline__ void ywrap_up(struct vc_data *vc, int count); +static __inline__ void ywrap_down(struct vc_data *vc, int count); +static __inline__ void ypan_up(struct vc_data *vc, int count); +static __inline__ void ypan_down(struct vc_data *vc, int count); +static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx, + int dy, int dx, int height, int width, u_int y_break); static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, int unit); +static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, + int line, int count, int dy); static void fbcon_modechanged(struct fb_info *info); static void fbcon_set_all_vcs(struct fb_info *info); static void fbcon_start(void); @@ -1125,6 +1135,14 @@ static void fbcon_init(struct vc_data *vc, int init) ops->graphics = 0; + /* + * No more hw acceleration for fbcon. + * + * FIXME: Garbage collect all the now dead code after sufficient time + * has passed. + */ + p->scrollmode = SCROLL_REDRAW; + /* * ++guenther: console.c:vc_allocate() relies on initializing * vc_{cols,rows}, but we must not set those if we are only @@ -1211,13 +1229,14 @@ finished: * This system is now divided into two levels because of complications * caused by hardware scrolling. Top level functions: * - * fbcon_clear(), fbcon_putc(), fbcon_clear_margins() + * fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins() * * handles y values in range [0, scr_height-1] that correspond to real * screen positions. y_wrap shift means that first line of bitmap may be * anywhere on this display. These functions convert lineoffsets to * bitmap offsets and deal with the wrap-around case by splitting blits. * + * fbcon_bmove_physical_8() -- These functions fast implementations * fbcon_clear_physical_8() -- of original fbcon_XXX fns. * fbcon_putc_physical_8() -- (font width != 8) may be added later * @@ -1390,6 +1409,224 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, } } +static __inline__ void ywrap_up(struct vc_data *vc, int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + p->yscroll += count; + if (p->yscroll >= p->vrows) /* Deal with wrap */ + p->yscroll -= p->vrows; + ops->var.xoffset = 0; + ops->var.yoffset = p->yscroll * vc->vc_font.height; + ops->var.vmode |= FB_VMODE_YWRAP; + ops->update_start(info); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; + scrollback_current = 0; +} + +static __inline__ void ywrap_down(struct vc_data *vc, int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + p->yscroll -= count; + if (p->yscroll < 0) /* Deal with wrap */ + p->yscroll += p->vrows; + ops->var.xoffset = 0; + ops->var.yoffset = p->yscroll * vc->vc_font.height; + ops->var.vmode |= FB_VMODE_YWRAP; + ops->update_start(info); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; + scrollback_current = 0; +} + +static __inline__ void ypan_up(struct vc_data *vc, int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_display *p = &fb_display[vc->vc_num]; + struct fbcon_ops *ops = info->fbcon_par; + + p->yscroll += count; + if (p->yscroll > p->vrows - vc->vc_rows) { + ops->bmove(vc, info, p->vrows - vc->vc_rows, + 0, 0, 0, vc->vc_rows, vc->vc_cols); + p->yscroll -= p->vrows - vc->vc_rows; + } + + ops->var.xoffset = 0; + ops->var.yoffset = p->yscroll * vc->vc_font.height; + ops->var.vmode &= ~FB_VMODE_YWRAP; + ops->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; + scrollback_current = 0; +} + +static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + p->yscroll += count; + + if (p->yscroll > p->vrows - vc->vc_rows) { + p->yscroll -= p->vrows - vc->vc_rows; + fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); + } + + ops->var.xoffset = 0; + ops->var.yoffset = p->yscroll * vc->vc_font.height; + ops->var.vmode &= ~FB_VMODE_YWRAP; + ops->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max += count; + if (scrollback_max > scrollback_phys_max) + scrollback_max = scrollback_phys_max; + scrollback_current = 0; +} + +static __inline__ void ypan_down(struct vc_data *vc, int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_display *p = &fb_display[vc->vc_num]; + struct fbcon_ops *ops = info->fbcon_par; + + p->yscroll -= count; + if (p->yscroll < 0) { + ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, + 0, vc->vc_rows, vc->vc_cols); + p->yscroll += p->vrows - vc->vc_rows; + } + + ops->var.xoffset = 0; + ops->var.yoffset = p->yscroll * vc->vc_font.height; + ops->var.vmode &= ~FB_VMODE_YWRAP; + ops->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; + scrollback_current = 0; +} + +static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + p->yscroll -= count; + + if (p->yscroll < 0) { + p->yscroll += p->vrows - vc->vc_rows; + fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); + } + + ops->var.xoffset = 0; + ops->var.yoffset = p->yscroll * vc->vc_font.height; + ops->var.vmode &= ~FB_VMODE_YWRAP; + ops->update_start(info); + fbcon_clear_margins(vc, 1); + scrollback_max -= count; + if (scrollback_max < 0) + scrollback_max = 0; + scrollback_current = 0; +} + +static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, + int line, int count, int dy) +{ + unsigned short *s = (unsigned short *) + (vc->vc_origin + vc->vc_size_row * line); + + while (count--) { + unsigned short *start = s; + unsigned short *le = advance_row(s, 1); + unsigned short c; + int x = 0; + unsigned short attr = 1; + + do { + c = scr_readw(s); + if (attr != (c & 0xff00)) { + attr = c & 0xff00; + if (s > start) { + fbcon_putcs(vc, start, s - start, + dy, x); + x += s - start; + start = s; + } + } + console_conditional_schedule(); + s++; + } while (s < le); + if (s > start) + fbcon_putcs(vc, start, s - start, dy, x); + console_conditional_schedule(); + dy++; + } +} + +static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, + struct fbcon_display *p, int line, int count, int ycount) +{ + int offset = ycount * vc->vc_cols; + unsigned short *d = (unsigned short *) + (vc->vc_origin + vc->vc_size_row * line); + unsigned short *s = d + offset; + struct fbcon_ops *ops = info->fbcon_par; + + while (count--) { + unsigned short *start = s; + unsigned short *le = advance_row(s, 1); + unsigned short c; + int x = 0; + + do { + c = scr_readw(s); + + if (c == scr_readw(d)) { + if (s > start) { + ops->bmove(vc, info, line + ycount, x, + line, x, 1, s-start); + x += s - start + 1; + start = s + 1; + } else { + x++; + start++; + } + } + + scr_writew(c, d); + console_conditional_schedule(); + s++; + d++; + } while (s < le); + if (s > start) + ops->bmove(vc, info, line + ycount, x, line, x, 1, + s-start); + console_conditional_schedule(); + if (ycount > 0) + line++; + else { + line--; + /* NOTE: We subtract two lines from these pointers */ + s -= vc->vc_size_row; + d -= vc->vc_size_row; + } + } +} + static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p, int line, int count, int offset) { @@ -1450,6 +1687,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_display *p = &fb_display[vc->vc_num]; + int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; if (fbcon_is_inactive(vc, info)) return true; @@ -1466,32 +1704,249 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, case SM_UP: if (count > vc->vc_rows) /* Maximum realistic size */ count = vc->vc_rows; - fbcon_redraw(vc, p, t, b - t - count, - count * vc->vc_cols); - fbcon_clear(vc, b - count, 0, count, vc->vc_cols); - scr_memsetw((unsigned short *) (vc->vc_origin + - vc->vc_size_row * - (b - count)), - vc->vc_video_erase_char, - vc->vc_size_row * count); - return true; + if (logo_shown >= 0) + goto redraw_up; + switch (p->scrollmode) { + case SCROLL_MOVE: + fbcon_redraw_blit(vc, info, p, t, b - t - count, + count); + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + scr_memsetw((unsigned short *) (vc->vc_origin + + vc->vc_size_row * + (b - count)), + vc->vc_video_erase_char, + vc->vc_size_row * count); + return true; + + case SCROLL_WRAP_MOVE: + if (b - t - count > 3 * vc->vc_rows >> 2) { + if (t > 0) + fbcon_bmove(vc, 0, 0, count, 0, t, + vc->vc_cols); + ywrap_up(vc, count); + if (vc->vc_rows - b > 0) + fbcon_bmove(vc, b - count, 0, b, 0, + vc->vc_rows - b, + vc->vc_cols); + } else if (info->flags & FBINFO_READS_FAST) + fbcon_bmove(vc, t + count, 0, t, 0, + b - t - count, vc->vc_cols); + else + goto redraw_up; + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + break; + + case SCROLL_PAN_REDRAW: + if ((p->yscroll + count <= + 2 * (p->vrows - vc->vc_rows)) + && ((!scroll_partial && (b - t == vc->vc_rows)) + || (scroll_partial + && (b - t - count > + 3 * vc->vc_rows >> 2)))) { + if (t > 0) + fbcon_redraw_move(vc, p, 0, t, count); + ypan_up_redraw(vc, t, count); + if (vc->vc_rows - b > 0) + fbcon_redraw_move(vc, p, b, + vc->vc_rows - b, b); + } else + fbcon_redraw_move(vc, p, t + count, b - t - count, t); + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + break; + + case SCROLL_PAN_MOVE: + if ((p->yscroll + count <= + 2 * (p->vrows - vc->vc_rows)) + && ((!scroll_partial && (b - t == vc->vc_rows)) + || (scroll_partial + && (b - t - count > + 3 * vc->vc_rows >> 2)))) { + if (t > 0) + fbcon_bmove(vc, 0, 0, count, 0, t, + vc->vc_cols); + ypan_up(vc, count); + if (vc->vc_rows - b > 0) + fbcon_bmove(vc, b - count, 0, b, 0, + vc->vc_rows - b, + vc->vc_cols); + } else if (info->flags & FBINFO_READS_FAST) + fbcon_bmove(vc, t + count, 0, t, 0, + b - t - count, vc->vc_cols); + else + goto redraw_up; + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + break; + + case SCROLL_REDRAW: + redraw_up: + fbcon_redraw(vc, p, t, b - t - count, + count * vc->vc_cols); + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); + scr_memsetw((unsigned short *) (vc->vc_origin + + vc->vc_size_row * + (b - count)), + vc->vc_video_erase_char, + vc->vc_size_row * count); + return true; + } + break; case SM_DOWN: if (count > vc->vc_rows) /* Maximum realistic size */ count = vc->vc_rows; - fbcon_redraw(vc, p, b - 1, b - t - count, - -count * vc->vc_cols); - fbcon_clear(vc, t, 0, count, vc->vc_cols); - scr_memsetw((unsigned short *) (vc->vc_origin + - vc->vc_size_row * - t), - vc->vc_video_erase_char, - vc->vc_size_row * count); - return true; + if (logo_shown >= 0) + goto redraw_down; + switch (p->scrollmode) { + case SCROLL_MOVE: + fbcon_redraw_blit(vc, info, p, b - 1, b - t - count, + -count); + fbcon_clear(vc, t, 0, count, vc->vc_cols); + scr_memsetw((unsigned short *) (vc->vc_origin + + vc->vc_size_row * + t), + vc->vc_video_erase_char, + vc->vc_size_row * count); + return true; + + case SCROLL_WRAP_MOVE: + if (b - t - count > 3 * vc->vc_rows >> 2) { + if (vc->vc_rows - b > 0) + fbcon_bmove(vc, b, 0, b - count, 0, + vc->vc_rows - b, + vc->vc_cols); + ywrap_down(vc, count); + if (t > 0) + fbcon_bmove(vc, count, 0, 0, 0, t, + vc->vc_cols); + } else if (info->flags & FBINFO_READS_FAST) + fbcon_bmove(vc, t, 0, t + count, 0, + b - t - count, vc->vc_cols); + else + goto redraw_down; + fbcon_clear(vc, t, 0, count, vc->vc_cols); + break; + + case SCROLL_PAN_MOVE: + if ((count - p->yscroll <= p->vrows - vc->vc_rows) + && ((!scroll_partial && (b - t == vc->vc_rows)) + || (scroll_partial + && (b - t - count > + 3 * vc->vc_rows >> 2)))) { + if (vc->vc_rows - b > 0) + fbcon_bmove(vc, b, 0, b - count, 0, + vc->vc_rows - b, + vc->vc_cols); + ypan_down(vc, count); + if (t > 0) + fbcon_bmove(vc, count, 0, 0, 0, t, + vc->vc_cols); + } else if (info->flags & FBINFO_READS_FAST) + fbcon_bmove(vc, t, 0, t + count, 0, + b - t - count, vc->vc_cols); + else + goto redraw_down; + fbcon_clear(vc, t, 0, count, vc->vc_cols); + break; + + case SCROLL_PAN_REDRAW: + if ((count - p->yscroll <= p->vrows - vc->vc_rows) + && ((!scroll_partial && (b - t == vc->vc_rows)) + || (scroll_partial + && (b - t - count > + 3 * vc->vc_rows >> 2)))) { + if (vc->vc_rows - b > 0) + fbcon_redraw_move(vc, p, b, vc->vc_rows - b, + b - count); + ypan_down_redraw(vc, t, count); + if (t > 0) + fbcon_redraw_move(vc, p, count, t, 0); + } else + fbcon_redraw_move(vc, p, t, b - t - count, t + count); + fbcon_clear(vc, t, 0, count, vc->vc_cols); + break; + + case SCROLL_REDRAW: + redraw_down: + fbcon_redraw(vc, p, b - 1, b - t - count, + -count * vc->vc_cols); + fbcon_clear(vc, t, 0, count, vc->vc_cols); + scr_memsetw((unsigned short *) (vc->vc_origin + + vc->vc_size_row * + t), + vc->vc_video_erase_char, + vc->vc_size_row * count); + return true; + } } return false; } + +static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, + int height, int width) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_display *p = &fb_display[vc->vc_num]; + + if (fbcon_is_inactive(vc, info)) + return; + + if (!width || !height) + return; + + /* Split blits that cross physical y_wrap case. + * Pathological case involves 4 blits, better to use recursive + * code rather than unrolled case + * + * Recursive invocations don't need to erase the cursor over and + * over again, so we use fbcon_bmove_rec() + */ + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width, + p->vrows - p->yscroll); +} + +static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx, + int dy, int dx, int height, int width, u_int y_break) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + u_int b; + + if (sy < y_break && sy + height > y_break) { + b = y_break - sy; + if (dy < sy) { /* Avoid trashing self */ + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, + y_break); + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, + height - b, width, y_break); + } else { + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, + height - b, width, y_break); + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, + y_break); + } + return; + } + + if (dy < y_break && dy + height > y_break) { + b = y_break - dy; + if (dy < sy) { /* Avoid trashing self */ + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, + y_break); + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, + height - b, width, y_break); + } else { + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, + height - b, width, y_break); + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, + y_break); + } + return; + } + ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, + height, width); +} + static void updatescrollmode(struct fbcon_display *p, struct fb_info *info, struct vc_data *vc) @@ -1664,7 +2119,21 @@ static int fbcon_switch(struct vc_data *vc) updatescrollmode(p, info, vc); - scrollback_phys_max = 0; + switch (p->scrollmode) { + case SCROLL_WRAP_MOVE: + scrollback_phys_max = p->vrows - vc->vc_rows; + break; + case SCROLL_PAN_MOVE: + case SCROLL_PAN_REDRAW: + scrollback_phys_max = p->vrows - 2 * vc->vc_rows; + if (scrollback_phys_max < 0) + scrollback_phys_max = 0; + break; + default: + scrollback_phys_max = 0; + break; + } + scrollback_max = 0; scrollback_current = 0; diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h index a00603b4451a..5246d0f2574b 100644 --- a/drivers/video/fbdev/core/fbcon.h +++ b/drivers/video/fbdev/core/fbcon.h @@ -29,6 +29,7 @@ struct fbcon_display { /* Filled in by the low-level console driver */ const u_char *fontdata; int userfont; /* != 0 if fontdata kmalloc()ed */ + u_short scrollmode; /* Scroll Method */ u_short inverse; /* != 0 text black on white as default */ short yscroll; /* Hardware scrolling */ int vrows; /* number of virtual rows */ @@ -51,6 +52,8 @@ struct fbcon_display { }; struct fbcon_ops { + void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width); void (*clear)(struct vc_data *vc, struct fb_info *info, int sy, int sx, int height, int width); void (*putcs)(struct vc_data *vc, struct fb_info *info, @@ -149,6 +152,62 @@ static inline int attr_col_ec(int shift, struct vc_data *vc, #define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0) #define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1) + /* + * Scroll Method + */ + +/* There are several methods fbcon can use to move text around the screen: + * + * Operation Pan Wrap + *--------------------------------------------- + * SCROLL_MOVE copyarea No No + * SCROLL_PAN_MOVE copyarea Yes No + * SCROLL_WRAP_MOVE copyarea No Yes + * SCROLL_REDRAW imageblit No No + * SCROLL_PAN_REDRAW imageblit Yes No + * SCROLL_WRAP_REDRAW imageblit No Yes + * + * (SCROLL_WRAP_REDRAW is not implemented yet) + * + * In general, fbcon will choose the best scrolling + * method based on the rule below: + * + * Pan/Wrap > accel imageblit > accel copyarea > + * soft imageblit > (soft copyarea) + * + * Exception to the rule: Pan + accel copyarea is + * preferred over Pan + accel imageblit. + * + * The above is typical for PCI/AGP cards. Unless + * overridden, fbcon will never use soft copyarea. + * + * If you need to override the above rule, set the + * appropriate flags in fb_info->flags. For example, + * to prefer copyarea over imageblit, set + * FBINFO_READS_FAST. + * + * Other notes: + * + use the hardware engine to move the text + * (hw-accelerated copyarea() and fillrect()) + * + use hardware-supported panning on a large virtual screen + * + amifb can not only pan, but also wrap the display by N lines + * (i.e. visible line i = physical line (i+N) % yres). + * + read what's already rendered on the screen and + * write it in a different place (this is cfb_copyarea()) + * + re-render the text to the screen + * + * Whether to use wrapping or panning can only be figured out at + * runtime (when we know whether our font height is a multiple + * of the pan/wrap step) + * + */ + +#define SCROLL_MOVE 0x001 +#define SCROLL_PAN_MOVE 0x002 +#define SCROLL_WRAP_MOVE 0x003 +#define SCROLL_REDRAW 0x004 +#define SCROLL_PAN_REDRAW 0x005 + #ifdef CONFIG_FB_TILEBLITTING extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info); #endif diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c index ffa78936eaab..9cd2c4b05c32 100644 --- a/drivers/video/fbdev/core/fbcon_ccw.c +++ b/drivers/video/fbdev/core/fbcon_ccw.c @@ -59,12 +59,31 @@ static void ccw_update_attr(u8 *dst, u8 *src, int attribute, } } + +static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct fb_copyarea area; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + + area.sx = sy * vc->vc_font.height; + area.sy = vyres - ((sx + width) * vc->vc_font.width); + area.dx = dy * vc->vc_font.height; + area.dy = vyres - ((dx + width) * vc->vc_font.width); + area.width = height * vc->vc_font.height; + area.height = width * vc->vc_font.width; + + info->fbops->fb_copyarea(info, &area); +} + static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx, int height, int width) { + struct fbcon_ops *ops = info->fbcon_par; struct fb_fillrect region; int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - u32 vyres = info->var.yres; + u32 vyres = GETVYRES(ops->p->scrollmode, info); region.color = attr_bgcol_ec(bgshift,vc,info); region.dx = sy * vc->vc_font.height; @@ -121,7 +140,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info, u32 cnt, pitch, size; u32 attribute = get_attribute(info, scr_readw(s)); u8 *dst, *buf = NULL; - u32 vyres = info->var.yres; + u32 vyres = GETVYRES(ops->p->scrollmode, info); if (!ops->fontbuffer) return; @@ -210,7 +229,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode, int attribute, use_sw = vc->vc_cursor_type & CUR_SW; int err = 1, dx, dy; char *src; - u32 vyres = info->var.yres; + u32 vyres = GETVYRES(ops->p->scrollmode, info); if (!ops->fontbuffer) return; @@ -368,7 +387,7 @@ static int ccw_update_start(struct fb_info *info) { struct fbcon_ops *ops = info->fbcon_par; u32 yoffset; - u32 vyres = info->var.yres; + u32 vyres = GETVYRES(ops->p->scrollmode, info); int err; yoffset = (vyres - info->var.yres) - ops->var.xoffset; @@ -383,6 +402,7 @@ static int ccw_update_start(struct fb_info *info) void fbcon_rotate_ccw(struct fbcon_ops *ops) { + ops->bmove = ccw_bmove; ops->clear = ccw_clear; ops->putcs = ccw_putcs; ops->clear_margins = ccw_clear_margins; diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c index 92e5b7fb51ee..88d89fad3f05 100644 --- a/drivers/video/fbdev/core/fbcon_cw.c +++ b/drivers/video/fbdev/core/fbcon_cw.c @@ -44,12 +44,31 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute, } } + +static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct fb_copyarea area; + u32 vxres = GETVXRES(ops->p->scrollmode, info); + + area.sx = vxres - ((sy + height) * vc->vc_font.height); + area.sy = sx * vc->vc_font.width; + area.dx = vxres - ((dy + height) * vc->vc_font.height); + area.dy = dx * vc->vc_font.width; + area.width = height * vc->vc_font.height; + area.height = width * vc->vc_font.width; + + info->fbops->fb_copyarea(info, &area); +} + static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx, int height, int width) { + struct fbcon_ops *ops = info->fbcon_par; struct fb_fillrect region; int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - u32 vxres = info->var.xres; + u32 vxres = GETVXRES(ops->p->scrollmode, info); region.color = attr_bgcol_ec(bgshift,vc,info); region.dx = vxres - ((sy + height) * vc->vc_font.height); @@ -106,7 +125,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info, u32 cnt, pitch, size; u32 attribute = get_attribute(info, scr_readw(s)); u8 *dst, *buf = NULL; - u32 vxres = info->var.xres; + u32 vxres = GETVXRES(ops->p->scrollmode, info); if (!ops->fontbuffer) return; @@ -193,7 +212,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode, int attribute, use_sw = vc->vc_cursor_type & CUR_SW; int err = 1, dx, dy; char *src; - u32 vxres = info->var.xres; + u32 vxres = GETVXRES(ops->p->scrollmode, info); if (!ops->fontbuffer) return; @@ -350,7 +369,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode, static int cw_update_start(struct fb_info *info) { struct fbcon_ops *ops = info->fbcon_par; - u32 vxres = info->var.xres; + u32 vxres = GETVXRES(ops->p->scrollmode, info); u32 xoffset; int err; @@ -366,6 +385,7 @@ static int cw_update_start(struct fb_info *info) void fbcon_rotate_cw(struct fbcon_ops *ops) { + ops->bmove = cw_bmove; ops->clear = cw_clear; ops->putcs = cw_putcs; ops->clear_margins = cw_clear_margins; diff --git a/drivers/video/fbdev/core/fbcon_rotate.h b/drivers/video/fbdev/core/fbcon_rotate.h index b528b2e54283..e233444cda66 100644 --- a/drivers/video/fbdev/core/fbcon_rotate.h +++ b/drivers/video/fbdev/core/fbcon_rotate.h @@ -11,6 +11,15 @@ #ifndef _FBCON_ROTATE_H #define _FBCON_ROTATE_H +#define GETVYRES(s,i) ({ \ + (s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \ + (i)->var.yres : (i)->var.yres_virtual; }) + +#define GETVXRES(s,i) ({ \ + (s == SCROLL_REDRAW || s == SCROLL_MOVE || !(i)->fix.xpanstep) ? \ + (i)->var.xres : (i)->var.xres_virtual; }) + + static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat) { u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8; diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c index 09619bd8e021..8d5e66b1bdfb 100644 --- a/drivers/video/fbdev/core/fbcon_ud.c +++ b/drivers/video/fbdev/core/fbcon_ud.c @@ -44,13 +44,33 @@ static void ud_update_attr(u8 *dst, u8 *src, int attribute, } } + +static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct fb_copyarea area; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + u32 vxres = GETVXRES(ops->p->scrollmode, info); + + area.sy = vyres - ((sy + height) * vc->vc_font.height); + area.sx = vxres - ((sx + width) * vc->vc_font.width); + area.dy = vyres - ((dy + height) * vc->vc_font.height); + area.dx = vxres - ((dx + width) * vc->vc_font.width); + area.height = height * vc->vc_font.height; + area.width = width * vc->vc_font.width; + + info->fbops->fb_copyarea(info, &area); +} + static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx, int height, int width) { + struct fbcon_ops *ops = info->fbcon_par; struct fb_fillrect region; int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - u32 vyres = info->var.yres; - u32 vxres = info->var.xres; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + u32 vxres = GETVXRES(ops->p->scrollmode, info); region.color = attr_bgcol_ec(bgshift,vc,info); region.dy = vyres - ((sy + height) * vc->vc_font.height); @@ -142,8 +162,8 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info, u32 mod = vc->vc_font.width % 8, cnt, pitch, size; u32 attribute = get_attribute(info, scr_readw(s)); u8 *dst, *buf = NULL; - u32 vyres = info->var.yres; - u32 vxres = info->var.xres; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + u32 vxres = GETVXRES(ops->p->scrollmode, info); if (!ops->fontbuffer) return; @@ -239,8 +259,8 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode, int attribute, use_sw = vc->vc_cursor_type & CUR_SW; int err = 1, dx, dy; char *src; - u32 vyres = info->var.yres; - u32 vxres = info->var.xres; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + u32 vxres = GETVXRES(ops->p->scrollmode, info); if (!ops->fontbuffer) return; @@ -390,8 +410,8 @@ static int ud_update_start(struct fb_info *info) { struct fbcon_ops *ops = info->fbcon_par; int xoffset, yoffset; - u32 vyres = info->var.yres; - u32 vxres = info->var.xres; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + u32 vxres = GETVXRES(ops->p->scrollmode, info); int err; xoffset = vxres - info->var.xres - ops->var.xoffset; @@ -409,6 +429,7 @@ static int ud_update_start(struct fb_info *info) void fbcon_rotate_ud(struct fbcon_ops *ops) { + ops->bmove = ud_bmove; ops->clear = ud_clear; ops->putcs = ud_putcs; ops->clear_margins = ud_clear_margins; diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c index 72af95053bcb..2768eff247ba 100644 --- a/drivers/video/fbdev/core/tileblit.c +++ b/drivers/video/fbdev/core/tileblit.c @@ -16,6 +16,21 @@ #include #include "fbcon.h" +static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) +{ + struct fb_tilearea area; + + area.sx = sx; + area.sy = sy; + area.dx = dx; + area.dy = dy; + area.height = height; + area.width = width; + + info->tileops->fb_tilecopy(info, &area); +} + static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy, int sx, int height, int width) { @@ -118,6 +133,7 @@ void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info) struct fb_tilemap map; struct fbcon_ops *ops = info->fbcon_par; + ops->bmove = tile_bmove; ops->clear = tile_clear; ops->putcs = tile_putcs; ops->clear_margins = tile_clear_margins; diff --git a/drivers/video/fbdev/skeletonfb.c b/drivers/video/fbdev/skeletonfb.c index 0fe922f726e9..bcacfb6934fa 100644 --- a/drivers/video/fbdev/skeletonfb.c +++ b/drivers/video/fbdev/skeletonfb.c @@ -505,15 +505,15 @@ void xxxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region) } /** - * xxxfb_copyarea - OBSOLETE function. + * xxxfb_copyarea - REQUIRED function. Can use generic routines if + * non acclerated hardware and packed pixel based. * Copies one area of the screen to another area. - * Will be deleted in a future version * * @info: frame buffer structure that represents a single frame buffer * @area: Structure providing the data to copy the framebuffer contents * from one region to another. * - * This drawing operation copied a rectangular area from one area of the + * This drawing operation copies a rectangular area from one area of the * screen to another area. */ void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) @@ -645,9 +645,9 @@ static const struct fb_ops xxxfb_ops = { .fb_setcolreg = xxxfb_setcolreg, .fb_blank = xxxfb_blank, .fb_pan_display = xxxfb_pan_display, - .fb_fillrect = xxxfb_fillrect, /* Needed !!! */ - .fb_copyarea = xxxfb_copyarea, /* Obsolete */ - .fb_imageblit = xxxfb_imageblit, /* Needed !!! */ + .fb_fillrect = xxxfb_fillrect, /* Needed !!! */ + .fb_copyarea = xxxfb_copyarea, /* Needed !!! */ + .fb_imageblit = xxxfb_imageblit, /* Needed !!! */ .fb_cursor = xxxfb_cursor, /* Optional !!! */ .fb_sync = xxxfb_sync, .fb_ioctl = xxxfb_ioctl, diff --git a/include/linux/fb.h b/include/linux/fb.h index 3da95842b207..02f362c661c8 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -262,7 +262,7 @@ struct fb_ops { /* Draws a rectangle */ void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect); - /* Copy data from area to another. Obsolete. */ + /* Copy data from area to another */ void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region); /* Draws a image to the display */ void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image); -- cgit v1.2.3 From 87ab9f6b7417349aa197a6c7098d4fdd4beebb74 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 2 Feb 2022 14:55:30 +0100 Subject: Revert "fbcon: Disable accelerated scrolling" This reverts commit 39aead8373b3c20bb5965c024dfb51a94e526151. Revert the first (of 2) commits which disabled scrolling acceleration in fbcon/fbdev. It introduced a regression for fbdev-supported graphic cards because of the performance penalty by doing screen scrolling by software instead of using the existing graphic card 2D hardware acceleration. Console scrolling acceleration was disabled by dropping code which checked at runtime the driver hardware capabilities for the BINFO_HWACCEL_COPYAREA or FBINFO_HWACCEL_FILLRECT flags and if set, it enabled scrollmode SCROLL_MOVE which uses hardware acceleration to move screen contents. After dropping those checks scrollmode was hard-wired to SCROLL_REDRAW instead, which forces all graphic cards to redraw every character at the new screen position when scrolling. This change effectively disabled all hardware-based scrolling acceleration for ALL drivers, because now all kind of 2D hardware acceleration (bitblt, fillrect) in the drivers isn't used any longer. The original commit message mentions that only 3 DRM drivers (nouveau, omapdrm and gma500) used hardware acceleration in the past and thus code for checking and using scrolling acceleration is obsolete. This statement is NOT TRUE, because beside the DRM drivers there are around 35 other fbdev drivers which depend on fbdev/fbcon and still provide hardware acceleration for fbdev/fbcon. The original commit message also states that syzbot found lots of bugs in fbcon and thus it's "often the solution to just delete code and remove features". This is true, and the bugs - which actually affected all users of fbcon, including DRM - were fixed, or code was dropped like e.g. the support for software scrollback in vgacon (commit 973c096f6a85). So to further analyze which bugs were found by syzbot, I've looked through all patches in drivers/video which were tagged with syzbot or syzkaller back to year 2005. The vast majority fixed the reported issues on a higher level, e.g. when screen is to be resized, or when font size is to be changed. The few ones which touched driver code fixed a real driver bug, e.g. by adding a check. But NONE of those patches touched code of either the SCROLL_MOVE or the SCROLL_REDRAW case. That means, there was no real reason why SCROLL_MOVE had to be ripped-out and just SCROLL_REDRAW had to be used instead. The only reason I can imagine so far was that SCROLL_MOVE wasn't used by DRM and as such it was assumed that it could go away. That argument completely missed the fact that SCROLL_MOVE is still heavily used by fbdev (non-DRM) drivers. Some people mention that using memcpy() instead of the hardware acceleration is pretty much the same speed. But that's not true, at least not for older graphic cards and machines where we see speed decreases by factor 10 and more and thus this change leads to console responsiveness way worse than before. That's why the original commit is to be reverted. By reverting we reintroduce hardware-based scrolling acceleration and fix the performance regression for fbdev drivers. There isn't any impact on DRM when reverting those patches. Signed-off-by: Helge Deller Acked-by: Geert Uytterhoeven Acked-by: Sven Schnelle Cc: stable@vger.kernel.org # v5.10+ Signed-off-by: Helge Deller Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220202135531.92183-3-deller@gmx.de --- Documentation/gpu/todo.rst | 21 ------------------- drivers/video/fbdev/core/fbcon.c | 45 +++++++++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 29 deletions(-) (limited to 'Documentation/gpu') diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 29506815d24a..a1212b5b3026 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -300,27 +300,6 @@ Contact: Daniel Vetter, Noralf Tronnes Level: Advanced -Garbage collect fbdev scrolling acceleration --------------------------------------------- - -Scroll acceleration is disabled in fbcon by hard-wiring p->scrollmode = -SCROLL_REDRAW. There's a ton of code this will allow us to remove: - -- lots of code in fbcon.c - -- a bunch of the hooks in fbcon_ops, maybe the remaining hooks could be called - directly instead of the function table (with a switch on p->rotate) - -- fb_copyarea is unused after this, and can be deleted from all drivers - -Note that not all acceleration code can be deleted, since clearing and cursor -support is still accelerated, which might be good candidates for further -deletion projects. - -Contact: Daniel Vetter - -Level: Intermediate - idr_init_base() --------------- diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index fc34caddf9cf..0cc2a36b674a 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -1025,7 +1025,7 @@ static void fbcon_init(struct vc_data *vc, int init) struct vc_data *svc = *default_mode; struct fbcon_display *t, *p = &fb_display[vc->vc_num]; int logo = 1, new_rows, new_cols, rows, cols; - int ret; + int cap, ret; if (WARN_ON(info_idx == -1)) return; @@ -1034,6 +1034,7 @@ static void fbcon_init(struct vc_data *vc, int init) con2fb_map[vc->vc_num] = info_idx; info = registered_fb[con2fb_map[vc->vc_num]]; + cap = info->flags; if (logo_shown < 0 && console_loglevel <= CONSOLE_LOGLEVEL_QUIET) logo_shown = FBCON_LOGO_DONTSHOW; @@ -1135,13 +1136,11 @@ static void fbcon_init(struct vc_data *vc, int init) ops->graphics = 0; - /* - * No more hw acceleration for fbcon. - * - * FIXME: Garbage collect all the now dead code after sufficient time - * has passed. - */ - p->scrollmode = SCROLL_REDRAW; + if ((cap & FBINFO_HWACCEL_COPYAREA) && + !(cap & FBINFO_HWACCEL_DISABLED)) + p->scrollmode = SCROLL_MOVE; + else /* default to something safe */ + p->scrollmode = SCROLL_REDRAW; /* * ++guenther: console.c:vc_allocate() relies on initializing @@ -1953,15 +1952,45 @@ static void updatescrollmode(struct fbcon_display *p, { struct fbcon_ops *ops = info->fbcon_par; int fh = vc->vc_font.height; + int cap = info->flags; + u16 t = 0; + int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep, + info->fix.xpanstep); + int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t); int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual, info->var.xres_virtual); + int good_pan = (cap & FBINFO_HWACCEL_YPAN) && + divides(ypan, vc->vc_font.height) && vyres > yres; + int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) && + divides(ywrap, vc->vc_font.height) && + divides(vc->vc_font.height, vyres) && + divides(vc->vc_font.height, yres); + int reading_fast = cap & FBINFO_READS_FAST; + int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && + !(cap & FBINFO_HWACCEL_DISABLED); + int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && + !(cap & FBINFO_HWACCEL_DISABLED); p->vrows = vyres/fh; if (yres > (fh * (vc->vc_rows + 1))) p->vrows -= (yres - (fh * vc->vc_rows)) / fh; if ((yres % fh) && (vyres % fh < yres % fh)) p->vrows--; + + if (good_wrap || good_pan) { + if (reading_fast || fast_copyarea) + p->scrollmode = good_wrap ? + SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE; + else + p->scrollmode = good_wrap ? SCROLL_REDRAW : + SCROLL_PAN_REDRAW; + } else { + if (reading_fast || (fast_copyarea && !fast_imageblit)) + p->scrollmode = SCROLL_MOVE; + else + p->scrollmode = SCROLL_REDRAW; + } } #define PITCH(w) (((w) + 7) >> 3) -- cgit v1.2.3 From 7938f4218168ae9fc4bdddb15976f9ebbae41999 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 4 Feb 2022 09:05:41 -0800 Subject: dma-buf-map: Rename to iosys-map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename struct dma_buf_map to struct iosys_map and corresponding APIs. Over time dma-buf-map grew up to more functionality than the one used by dma-buf: in fact it's just a shim layer to abstract system memory, that can be accessed via regular load and store, from IO memory that needs to be acessed via arch helpers. The idea is to extend this API so it can fulfill other needs, internal to a single driver. Example: in the i915 driver it's desired to share the implementation for integrated graphics, which uses mostly system memory, with discrete graphics, which may need to access IO memory. The conversion was mostly done with the following semantic patch: @r1@ @@ - struct dma_buf_map + struct iosys_map @r2@ @@ ( - DMA_BUF_MAP_INIT_VADDR + IOSYS_MAP_INIT_VADDR | - dma_buf_map_set_vaddr + iosys_map_set_vaddr | - dma_buf_map_set_vaddr_iomem + iosys_map_set_vaddr_iomem | - dma_buf_map_is_equal + iosys_map_is_equal | - dma_buf_map_is_null + iosys_map_is_null | - dma_buf_map_is_set + iosys_map_is_set | - dma_buf_map_clear + iosys_map_clear | - dma_buf_map_memcpy_to + iosys_map_memcpy_to | - dma_buf_map_incr + iosys_map_incr ) @@ @@ - #include + #include Then some files had their includes adjusted and some comments were update to remove mentions to dma-buf-map. Since this is not specific to dma-buf anymore, move the documentation to the "Bus-Independent Device Accesses" section. v2: - Squash patches v3: - Fix wrong removal of dma-buf.h from MAINTAINERS - Move documentation from dma-buf.rst to device-io.rst v4: - Change documentation title and level Signed-off-by: Lucas De Marchi Acked-by: Christian König Acked-by: Sumit Semwal Acked-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220204170541.829227-1-lucas.demarchi@intel.com --- Documentation/driver-api/device-io.rst | 9 + Documentation/driver-api/dma-buf.rst | 9 - Documentation/gpu/todo.rst | 20 +- MAINTAINERS | 9 +- drivers/dma-buf/dma-buf.c | 22 +- drivers/dma-buf/heaps/cma_heap.c | 10 +- drivers/dma-buf/heaps/system_heap.c | 10 +- drivers/gpu/drm/ast/ast_drv.h | 2 +- drivers/gpu/drm/ast/ast_mode.c | 8 +- drivers/gpu/drm/drm_cache.c | 18 +- drivers/gpu/drm/drm_client.c | 9 +- drivers/gpu/drm/drm_fb_helper.c | 12 +- drivers/gpu/drm/drm_gem.c | 12 +- drivers/gpu/drm/drm_gem_cma_helper.c | 9 +- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 16 +- drivers/gpu/drm/drm_gem_shmem_helper.c | 15 +- drivers/gpu/drm/drm_gem_ttm_helper.c | 4 +- drivers/gpu/drm/drm_gem_vram_helper.c | 25 +- drivers/gpu/drm/drm_internal.h | 6 +- drivers/gpu/drm/drm_mipi_dbi.c | 8 +- drivers/gpu/drm/drm_prime.c | 4 +- drivers/gpu/drm/etnaviv/etnaviv_drv.h | 2 +- drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c | 8 +- drivers/gpu/drm/gud/gud_pipe.c | 4 +- drivers/gpu/drm/hyperv/hyperv_drm_modeset.c | 5 +- drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c | 8 +- .../gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c | 6 +- drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c | 6 +- drivers/gpu/drm/lima/lima_gem.c | 3 +- drivers/gpu/drm/lima/lima_sched.c | 4 +- drivers/gpu/drm/mediatek/mtk_drm_gem.c | 7 +- drivers/gpu/drm/mediatek/mtk_drm_gem.h | 5 +- drivers/gpu/drm/mgag200/mgag200_mode.c | 4 +- drivers/gpu/drm/msm/msm_drv.h | 4 +- drivers/gpu/drm/msm/msm_gem_prime.c | 6 +- drivers/gpu/drm/panfrost/panfrost_perfcnt.c | 13 +- drivers/gpu/drm/qxl/qxl_display.c | 8 +- drivers/gpu/drm/qxl/qxl_draw.c | 6 +- drivers/gpu/drm/qxl/qxl_drv.h | 10 +- drivers/gpu/drm/qxl/qxl_object.c | 8 +- drivers/gpu/drm/qxl/qxl_object.h | 4 +- drivers/gpu/drm/qxl/qxl_prime.c | 4 +- drivers/gpu/drm/radeon/radeon_gem.c | 1 + drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 9 +- drivers/gpu/drm/rockchip/rockchip_drm_gem.h | 5 +- drivers/gpu/drm/tegra/gem.c | 10 +- drivers/gpu/drm/tiny/cirrus.c | 8 +- drivers/gpu/drm/tiny/gm12u320.c | 7 +- drivers/gpu/drm/ttm/ttm_bo_util.c | 16 +- drivers/gpu/drm/ttm/ttm_resource.c | 42 ++-- drivers/gpu/drm/ttm/ttm_tt.c | 8 +- drivers/gpu/drm/udl/udl_modeset.c | 3 +- drivers/gpu/drm/vboxvideo/vbox_mode.c | 4 +- drivers/gpu/drm/vkms/vkms_composer.c | 4 +- drivers/gpu/drm/vkms/vkms_drv.h | 6 +- drivers/gpu/drm/vkms/vkms_plane.c | 2 +- drivers/gpu/drm/vkms/vkms_writeback.c | 2 +- drivers/gpu/drm/xen/xen_drm_front_gem.c | 7 +- drivers/gpu/drm/xen/xen_drm_front_gem.h | 6 +- .../media/common/videobuf2/videobuf2-dma-contig.c | 8 +- drivers/media/common/videobuf2/videobuf2-dma-sg.c | 9 +- drivers/media/common/videobuf2/videobuf2-vmalloc.c | 11 +- drivers/misc/fastrpc.c | 4 +- include/drm/drm_cache.h | 6 +- include/drm/drm_client.h | 7 +- include/drm/drm_gem.h | 6 +- include/drm/drm_gem_atomic_helper.h | 6 +- include/drm/drm_gem_cma_helper.h | 6 +- include/drm/drm_gem_framebuffer_helper.h | 8 +- include/drm/drm_gem_shmem_helper.h | 12 +- include/drm/drm_gem_ttm_helper.h | 6 +- include/drm/drm_gem_vram_helper.h | 9 +- include/drm/drm_prime.h | 6 +- include/drm/ttm/ttm_bo_api.h | 10 +- include/drm/ttm/ttm_kmap_iter.h | 10 +- include/drm/ttm/ttm_resource.h | 6 +- include/linux/dma-buf-map.h | 266 --------------------- include/linux/dma-buf.h | 12 +- include/linux/iosys-map.h | 257 ++++++++++++++++++++ 79 files changed, 599 insertions(+), 568 deletions(-) delete mode 100644 include/linux/dma-buf-map.h create mode 100644 include/linux/iosys-map.h (limited to 'Documentation/gpu') diff --git a/Documentation/driver-api/device-io.rst b/Documentation/driver-api/device-io.rst index e9f04b1815d1..4d2baac0311c 100644 --- a/Documentation/driver-api/device-io.rst +++ b/Documentation/driver-api/device-io.rst @@ -502,6 +502,15 @@ pcim_iomap() Not using these wrappers may make drivers unusable on certain platforms with stricter rules for mapping I/O memory. +Generalizing Access to System and I/O Memory +============================================ + +.. kernel-doc:: include/linux/iosys-map.h + :doc: overview + +.. kernel-doc:: include/linux/iosys-map.h + :internal: + Public Functions Provided ========================= diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst index 2cd7db82d9fe..55006678394a 100644 --- a/Documentation/driver-api/dma-buf.rst +++ b/Documentation/driver-api/dma-buf.rst @@ -128,15 +128,6 @@ Kernel Functions and Structures Reference .. kernel-doc:: include/linux/dma-buf.h :internal: -Buffer Mapping Helpers -~~~~~~~~~~~~~~~~~~~~~~ - -.. kernel-doc:: include/linux/dma-buf-map.h - :doc: overview - -.. kernel-doc:: include/linux/dma-buf-map.h - :internal: - Reservation Objects ------------------- diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index da138dd39883..c8f39c1ef1ee 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -222,7 +222,7 @@ Convert drivers to use drm_fbdev_generic_setup() Most drivers can use drm_fbdev_generic_setup(). Driver have to implement atomic modesetting and GEM vmap support. Historically, generic fbdev emulation expected the framebuffer in system memory or system-like memory. By employing -struct dma_buf_map, drivers with frambuffers in I/O memory can be supported +struct iosys_map, drivers with frambuffers in I/O memory can be supported as well. Contact: Maintainer of the driver you plan to convert @@ -234,7 +234,7 @@ Reimplement functions in drm_fbdev_fb_ops without fbdev A number of callback functions in drm_fbdev_fb_ops could benefit from being rewritten without dependencies on the fbdev module. Some of the -helpers could further benefit from using struct dma_buf_map instead of +helpers could further benefit from using struct iosys_map instead of raw pointers. Contact: Thomas Zimmermann , Daniel Vetter @@ -434,19 +434,19 @@ Contact: Emil Velikov, respective driver maintainers Level: Intermediate -Use struct dma_buf_map throughout codebase ------------------------------------------- +Use struct iosys_map throughout codebase +---------------------------------------- -Pointers to shared device memory are stored in struct dma_buf_map. Each +Pointers to shared device memory are stored in struct iosys_map. Each instance knows whether it refers to system or I/O memory. Most of the DRM-wide -interface have been converted to use struct dma_buf_map, but implementations +interface have been converted to use struct iosys_map, but implementations often still use raw pointers. -The task is to use struct dma_buf_map where it makes sense. +The task is to use struct iosys_map where it makes sense. -* Memory managers should use struct dma_buf_map for dma-buf-imported buffers. -* TTM might benefit from using struct dma_buf_map internally. -* Framebuffer copying and blitting helpers should operate on struct dma_buf_map. +* Memory managers should use struct iosys_map for dma-buf-imported buffers. +* TTM might benefit from using struct iosys_map internally. +* Framebuffer copying and blitting helpers should operate on struct iosys_map. Contact: Thomas Zimmermann , Christian König, Daniel Vetter diff --git a/MAINTAINERS b/MAINTAINERS index f41088418aae..1a18eafee497 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5734,7 +5734,7 @@ T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/driver-api/dma-buf.rst F: drivers/dma-buf/ F: include/linux/*fence.h -F: include/linux/dma-buf* +F: include/linux/dma-buf.h F: include/linux/dma-resv.h K: \bdma_(?:buf|fence|resv)\b @@ -10050,6 +10050,13 @@ F: include/linux/iova.h F: include/linux/of_iommu.h F: include/uapi/linux/iommu.h +IOSYS-MAP HELPERS +M: Thomas Zimmermann +L: dri-devel@lists.freedesktop.org +S: Maintained +T: git git://anongit.freedesktop.org/drm/drm-misc +F: include/linux/iosys-map.h + IO_URING M: Jens Axboe R: Pavel Begunkov diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 602b12d7470d..df23239b04fc 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1047,8 +1047,8 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_move_notify, DMA_BUF); * * Interfaces:: * - * void \*dma_buf_vmap(struct dma_buf \*dmabuf, struct dma_buf_map \*map) - * void dma_buf_vunmap(struct dma_buf \*dmabuf, struct dma_buf_map \*map) + * void \*dma_buf_vmap(struct dma_buf \*dmabuf, struct iosys_map \*map) + * void dma_buf_vunmap(struct dma_buf \*dmabuf, struct iosys_map \*map) * * The vmap call can fail if there is no vmap support in the exporter, or if * it runs out of vmalloc space. Note that the dma-buf layer keeps a reference @@ -1260,12 +1260,12 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_mmap, DMA_BUF); * * Returns 0 on success, or a negative errno code otherwise. */ -int dma_buf_vmap(struct dma_buf *dmabuf, struct dma_buf_map *map) +int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map) { - struct dma_buf_map ptr; + struct iosys_map ptr; int ret = 0; - dma_buf_map_clear(map); + iosys_map_clear(map); if (WARN_ON(!dmabuf)) return -EINVAL; @@ -1276,12 +1276,12 @@ int dma_buf_vmap(struct dma_buf *dmabuf, struct dma_buf_map *map) mutex_lock(&dmabuf->lock); if (dmabuf->vmapping_counter) { dmabuf->vmapping_counter++; - BUG_ON(dma_buf_map_is_null(&dmabuf->vmap_ptr)); + BUG_ON(iosys_map_is_null(&dmabuf->vmap_ptr)); *map = dmabuf->vmap_ptr; goto out_unlock; } - BUG_ON(dma_buf_map_is_set(&dmabuf->vmap_ptr)); + BUG_ON(iosys_map_is_set(&dmabuf->vmap_ptr)); ret = dmabuf->ops->vmap(dmabuf, &ptr); if (WARN_ON_ONCE(ret)) @@ -1303,20 +1303,20 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_vmap, DMA_BUF); * @dmabuf: [in] buffer to vunmap * @map: [in] vmap pointer to vunmap */ -void dma_buf_vunmap(struct dma_buf *dmabuf, struct dma_buf_map *map) +void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map) { if (WARN_ON(!dmabuf)) return; - BUG_ON(dma_buf_map_is_null(&dmabuf->vmap_ptr)); + BUG_ON(iosys_map_is_null(&dmabuf->vmap_ptr)); BUG_ON(dmabuf->vmapping_counter == 0); - BUG_ON(!dma_buf_map_is_equal(&dmabuf->vmap_ptr, map)); + BUG_ON(!iosys_map_is_equal(&dmabuf->vmap_ptr, map)); mutex_lock(&dmabuf->lock); if (--dmabuf->vmapping_counter == 0) { if (dmabuf->ops->vunmap) dmabuf->ops->vunmap(dmabuf, map); - dma_buf_map_clear(&dmabuf->vmap_ptr); + iosys_map_clear(&dmabuf->vmap_ptr); } mutex_unlock(&dmabuf->lock); } diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c index 83f02bd51dda..28fb04eccdd0 100644 --- a/drivers/dma-buf/heaps/cma_heap.c +++ b/drivers/dma-buf/heaps/cma_heap.c @@ -202,7 +202,7 @@ static void *cma_heap_do_vmap(struct cma_heap_buffer *buffer) return vaddr; } -static int cma_heap_vmap(struct dma_buf *dmabuf, struct dma_buf_map *map) +static int cma_heap_vmap(struct dma_buf *dmabuf, struct iosys_map *map) { struct cma_heap_buffer *buffer = dmabuf->priv; void *vaddr; @@ -211,7 +211,7 @@ static int cma_heap_vmap(struct dma_buf *dmabuf, struct dma_buf_map *map) mutex_lock(&buffer->lock); if (buffer->vmap_cnt) { buffer->vmap_cnt++; - dma_buf_map_set_vaddr(map, buffer->vaddr); + iosys_map_set_vaddr(map, buffer->vaddr); goto out; } @@ -222,14 +222,14 @@ static int cma_heap_vmap(struct dma_buf *dmabuf, struct dma_buf_map *map) } buffer->vaddr = vaddr; buffer->vmap_cnt++; - dma_buf_map_set_vaddr(map, buffer->vaddr); + iosys_map_set_vaddr(map, buffer->vaddr); out: mutex_unlock(&buffer->lock); return ret; } -static void cma_heap_vunmap(struct dma_buf *dmabuf, struct dma_buf_map *map) +static void cma_heap_vunmap(struct dma_buf *dmabuf, struct iosys_map *map) { struct cma_heap_buffer *buffer = dmabuf->priv; @@ -239,7 +239,7 @@ static void cma_heap_vunmap(struct dma_buf *dmabuf, struct dma_buf_map *map) buffer->vaddr = NULL; } mutex_unlock(&buffer->lock); - dma_buf_map_clear(map); + iosys_map_clear(map); } static void cma_heap_dma_buf_release(struct dma_buf *dmabuf) diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c index ab7fd896d2c4..fcf836ba9c1f 100644 --- a/drivers/dma-buf/heaps/system_heap.c +++ b/drivers/dma-buf/heaps/system_heap.c @@ -241,7 +241,7 @@ static void *system_heap_do_vmap(struct system_heap_buffer *buffer) return vaddr; } -static int system_heap_vmap(struct dma_buf *dmabuf, struct dma_buf_map *map) +static int system_heap_vmap(struct dma_buf *dmabuf, struct iosys_map *map) { struct system_heap_buffer *buffer = dmabuf->priv; void *vaddr; @@ -250,7 +250,7 @@ static int system_heap_vmap(struct dma_buf *dmabuf, struct dma_buf_map *map) mutex_lock(&buffer->lock); if (buffer->vmap_cnt) { buffer->vmap_cnt++; - dma_buf_map_set_vaddr(map, buffer->vaddr); + iosys_map_set_vaddr(map, buffer->vaddr); goto out; } @@ -262,14 +262,14 @@ static int system_heap_vmap(struct dma_buf *dmabuf, struct dma_buf_map *map) buffer->vaddr = vaddr; buffer->vmap_cnt++; - dma_buf_map_set_vaddr(map, buffer->vaddr); + iosys_map_set_vaddr(map, buffer->vaddr); out: mutex_unlock(&buffer->lock); return ret; } -static void system_heap_vunmap(struct dma_buf *dmabuf, struct dma_buf_map *map) +static void system_heap_vunmap(struct dma_buf *dmabuf, struct iosys_map *map) { struct system_heap_buffer *buffer = dmabuf->priv; @@ -279,7 +279,7 @@ static void system_heap_vunmap(struct dma_buf *dmabuf, struct dma_buf_map *map) buffer->vaddr = NULL; } mutex_unlock(&buffer->lock); - dma_buf_map_clear(map); + iosys_map_clear(map); } static void system_heap_dma_buf_release(struct dma_buf *dmabuf) diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 00bfa41ff7cb..9c8d56b0a41b 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -107,7 +107,7 @@ struct ast_cursor_plane { struct { struct drm_gem_vram_object *gbo; - struct dma_buf_map map; + struct iosys_map map; u64 off; } hwc[AST_DEFAULT_HWC_NUM]; diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 956c8982192b..400845d4144c 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -801,11 +801,11 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(new_state); struct drm_framebuffer *fb = new_state->fb; struct ast_private *ast = to_ast_private(plane->dev); - struct dma_buf_map dst_map = + struct iosys_map dst_map = ast_cursor_plane->hwc[ast_cursor_plane->next_hwc_index].map; u64 dst_off = ast_cursor_plane->hwc[ast_cursor_plane->next_hwc_index].off; - struct dma_buf_map src_map = shadow_plane_state->data[0]; + struct iosys_map src_map = shadow_plane_state->data[0]; unsigned int offset_x, offset_y; u16 x, y; u8 x_offset, y_offset; @@ -883,7 +883,7 @@ static void ast_cursor_plane_destroy(struct drm_plane *plane) struct ast_cursor_plane *ast_cursor_plane = to_ast_cursor_plane(plane); size_t i; struct drm_gem_vram_object *gbo; - struct dma_buf_map map; + struct iosys_map map; for (i = 0; i < ARRAY_SIZE(ast_cursor_plane->hwc); ++i) { gbo = ast_cursor_plane->hwc[i].gbo; @@ -910,7 +910,7 @@ static int ast_cursor_plane_init(struct ast_private *ast) struct drm_plane *cursor_plane = &ast_cursor_plane->base; size_t size, i; struct drm_gem_vram_object *gbo; - struct dma_buf_map map; + struct iosys_map map; int ret; s64 off; diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index f19d9acbe959..4bb093ccf1b8 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -28,10 +28,10 @@ * Authors: Thomas Hellström */ -#include +#include #include #include -#include +#include #include #include @@ -214,14 +214,14 @@ bool drm_need_swiotlb(int dma_bits) } EXPORT_SYMBOL(drm_need_swiotlb); -static void memcpy_fallback(struct dma_buf_map *dst, - const struct dma_buf_map *src, +static void memcpy_fallback(struct iosys_map *dst, + const struct iosys_map *src, unsigned long len) { if (!dst->is_iomem && !src->is_iomem) { memcpy(dst->vaddr, src->vaddr, len); } else if (!src->is_iomem) { - dma_buf_map_memcpy_to(dst, src->vaddr, len); + iosys_map_memcpy_to(dst, src->vaddr, len); } else if (!dst->is_iomem) { memcpy_fromio(dst->vaddr, src->vaddr_iomem, len); } else { @@ -305,8 +305,8 @@ static void __drm_memcpy_from_wc(void *dst, const void *src, unsigned long len) * Tries an arch optimized memcpy for prefetching reading out of a WC region, * and if no such beast is available, falls back to a normal memcpy. */ -void drm_memcpy_from_wc(struct dma_buf_map *dst, - const struct dma_buf_map *src, +void drm_memcpy_from_wc(struct iosys_map *dst, + const struct iosys_map *src, unsigned long len) { if (WARN_ON(in_interrupt())) { @@ -343,8 +343,8 @@ void drm_memcpy_init_early(void) static_branch_enable(&has_movntdqa); } #else -void drm_memcpy_from_wc(struct dma_buf_map *dst, - const struct dma_buf_map *src, +void drm_memcpy_from_wc(struct iosys_map *dst, + const struct iosys_map *src, unsigned long len) { WARN_ON(in_interrupt()); diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index ce45e380f4a2..af3b7395bf69 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -3,7 +3,7 @@ * Copyright 2018 Noralf Trønnes */ -#include +#include #include #include #include @@ -309,9 +309,10 @@ err_delete: * 0 on success, or a negative errno code otherwise. */ int -drm_client_buffer_vmap(struct drm_client_buffer *buffer, struct dma_buf_map *map_copy) +drm_client_buffer_vmap(struct drm_client_buffer *buffer, + struct iosys_map *map_copy) { - struct dma_buf_map *map = &buffer->map; + struct iosys_map *map = &buffer->map; int ret; /* @@ -342,7 +343,7 @@ EXPORT_SYMBOL(drm_client_buffer_vmap); */ void drm_client_buffer_vunmap(struct drm_client_buffer *buffer) { - struct dma_buf_map *map = &buffer->map; + struct iosys_map *map = &buffer->map; drm_gem_vunmap(buffer->gem, map); } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index ed43b987d306..e9a9d35fbf5e 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -373,7 +373,7 @@ static void drm_fb_helper_resume_worker(struct work_struct *work) static void drm_fb_helper_damage_blit_real(struct drm_fb_helper *fb_helper, struct drm_clip_rect *clip, - struct dma_buf_map *dst) + struct iosys_map *dst) { struct drm_framebuffer *fb = fb_helper->fb; unsigned int cpp = fb->format->cpp[0]; @@ -382,11 +382,11 @@ static void drm_fb_helper_damage_blit_real(struct drm_fb_helper *fb_helper, size_t len = (clip->x2 - clip->x1) * cpp; unsigned int y; - dma_buf_map_incr(dst, offset); /* go to first pixel within clip rect */ + iosys_map_incr(dst, offset); /* go to first pixel within clip rect */ for (y = clip->y1; y < clip->y2; y++) { - dma_buf_map_memcpy_to(dst, src, len); - dma_buf_map_incr(dst, fb->pitches[0]); + iosys_map_memcpy_to(dst, src, len); + iosys_map_incr(dst, fb->pitches[0]); src += fb->pitches[0]; } } @@ -395,7 +395,7 @@ static int drm_fb_helper_damage_blit(struct drm_fb_helper *fb_helper, struct drm_clip_rect *clip) { struct drm_client_buffer *buffer = fb_helper->buffer; - struct dma_buf_map map, dst; + struct iosys_map map, dst; int ret; /* @@ -2322,7 +2322,7 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, struct drm_framebuffer *fb; struct fb_info *fbi; u32 format; - struct dma_buf_map map; + struct iosys_map map; int ret; drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n", diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 4dcdec6487bb..8c7b24f4b0e4 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include @@ -1165,7 +1165,7 @@ void drm_gem_unpin(struct drm_gem_object *obj) obj->funcs->unpin(obj); } -int drm_gem_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) +int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map) { int ret; @@ -1175,23 +1175,23 @@ int drm_gem_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) ret = obj->funcs->vmap(obj, map); if (ret) return ret; - else if (dma_buf_map_is_null(map)) + else if (iosys_map_is_null(map)) return -ENOMEM; return 0; } EXPORT_SYMBOL(drm_gem_vmap); -void drm_gem_vunmap(struct drm_gem_object *obj, struct dma_buf_map *map) +void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map) { - if (dma_buf_map_is_null(map)) + if (iosys_map_is_null(map)) return; if (obj->funcs->vunmap) obj->funcs->vunmap(obj, map); /* Always set the mapping to NULL. Callers may rely on this. */ - dma_buf_map_clear(map); + iosys_map_clear(map); } EXPORT_SYMBOL(drm_gem_vunmap); diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index cefd0cbf9deb..88c432a7cb3c 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -209,7 +209,7 @@ drm_gem_cma_create_with_handle(struct drm_file *file_priv, void drm_gem_cma_free(struct drm_gem_cma_object *cma_obj) { struct drm_gem_object *gem_obj = &cma_obj->base; - struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(cma_obj->vaddr); + struct iosys_map map = IOSYS_MAP_INIT_VADDR(cma_obj->vaddr); if (gem_obj->import_attach) { if (cma_obj->vaddr) @@ -480,9 +480,10 @@ EXPORT_SYMBOL_GPL(drm_gem_cma_prime_import_sg_table); * Returns: * 0 on success, or a negative error code otherwise. */ -int drm_gem_cma_vmap(struct drm_gem_cma_object *cma_obj, struct dma_buf_map *map) +int drm_gem_cma_vmap(struct drm_gem_cma_object *cma_obj, + struct iosys_map *map) { - dma_buf_map_set_vaddr(map, cma_obj->vaddr); + iosys_map_set_vaddr(map, cma_obj->vaddr); return 0; } @@ -557,7 +558,7 @@ drm_gem_cma_prime_import_sg_table_vmap(struct drm_device *dev, { struct drm_gem_cma_object *cma_obj; struct drm_gem_object *obj; - struct dma_buf_map map; + struct iosys_map map; int ret; ret = dma_buf_vmap(attach->dmabuf, &map); diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 746fd8c73845..f4619803acd0 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -321,7 +321,7 @@ EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); * @data: returns the data address for each BO, can be NULL * * This function maps all buffer objects of the given framebuffer into - * kernel address space and stores them in struct dma_buf_map. If the + * kernel address space and stores them in struct iosys_map. If the * mapping operation fails for one of the BOs, the function unmaps the * already established mappings automatically. * @@ -335,8 +335,8 @@ EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); * 0 on success, or a negative errno code otherwise. */ int drm_gem_fb_vmap(struct drm_framebuffer *fb, - struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES], - struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]) + struct iosys_map map[static DRM_FORMAT_MAX_PLANES], + struct iosys_map data[DRM_FORMAT_MAX_PLANES]) { struct drm_gem_object *obj; unsigned int i; @@ -345,7 +345,7 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) { obj = drm_gem_fb_get_obj(fb, i); if (!obj) { - dma_buf_map_clear(&map[i]); + iosys_map_clear(&map[i]); continue; } ret = drm_gem_vmap(obj, &map[i]); @@ -356,9 +356,9 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, if (data) { for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) { memcpy(&data[i], &map[i], sizeof(data[i])); - if (dma_buf_map_is_null(&data[i])) + if (iosys_map_is_null(&data[i])) continue; - dma_buf_map_incr(&data[i], fb->offsets[i]); + iosys_map_incr(&data[i], fb->offsets[i]); } } @@ -386,7 +386,7 @@ EXPORT_SYMBOL(drm_gem_fb_vmap); * See drm_gem_fb_vmap() for more information. */ void drm_gem_fb_vunmap(struct drm_framebuffer *fb, - struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]) + struct iosys_map map[static DRM_FORMAT_MAX_PLANES]) { unsigned int i = DRM_FORMAT_MAX_PLANES; struct drm_gem_object *obj; @@ -396,7 +396,7 @@ void drm_gem_fb_vunmap(struct drm_framebuffer *fb, obj = drm_gem_fb_get_obj(fb, i); if (!obj) continue; - if (dma_buf_map_is_null(&map[i])) + if (iosys_map_is_null(&map[i])) continue; drm_gem_vunmap(obj, &map[i]); } diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 621924116eb4..3e738aea2664 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -286,13 +286,14 @@ void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem) } EXPORT_SYMBOL(drm_gem_shmem_unpin); -static int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem, struct dma_buf_map *map) +static int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem, + struct iosys_map *map) { struct drm_gem_object *obj = &shmem->base; int ret = 0; if (shmem->vmap_use_count++ > 0) { - dma_buf_map_set_vaddr(map, shmem->vaddr); + iosys_map_set_vaddr(map, shmem->vaddr); return 0; } @@ -319,7 +320,7 @@ static int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem, struct if (!shmem->vaddr) ret = -ENOMEM; else - dma_buf_map_set_vaddr(map, shmem->vaddr); + iosys_map_set_vaddr(map, shmem->vaddr); } if (ret) { @@ -353,7 +354,8 @@ err_zero_use: * Returns: * 0 on success or a negative error code on failure. */ -int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem, struct dma_buf_map *map) +int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem, + struct iosys_map *map) { int ret; @@ -368,7 +370,7 @@ int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem, struct dma_buf_map *m EXPORT_SYMBOL(drm_gem_shmem_vmap); static void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem, - struct dma_buf_map *map) + struct iosys_map *map) { struct drm_gem_object *obj = &shmem->base; @@ -400,7 +402,8 @@ static void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem, * This function hides the differences between dma-buf imported and natively * allocated objects. */ -void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem, struct dma_buf_map *map) +void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem, + struct iosys_map *map) { mutex_lock(&shmem->vmap_lock); drm_gem_shmem_vunmap_locked(shmem, map); diff --git a/drivers/gpu/drm/drm_gem_ttm_helper.c b/drivers/gpu/drm/drm_gem_ttm_helper.c index ecf3d2a54a98..d5962a34c01d 100644 --- a/drivers/gpu/drm/drm_gem_ttm_helper.c +++ b/drivers/gpu/drm/drm_gem_ttm_helper.c @@ -61,7 +61,7 @@ EXPORT_SYMBOL(drm_gem_ttm_print_info); * 0 on success, or a negative errno code otherwise. */ int drm_gem_ttm_vmap(struct drm_gem_object *gem, - struct dma_buf_map *map) + struct iosys_map *map) { struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem); @@ -78,7 +78,7 @@ EXPORT_SYMBOL(drm_gem_ttm_vmap); * &drm_gem_object_funcs.vmap callback. */ void drm_gem_ttm_vunmap(struct drm_gem_object *gem, - struct dma_buf_map *map) + struct iosys_map *map) { struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem); diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 3f00192215d1..dc7f938bfff2 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later -#include +#include #include #include @@ -116,7 +116,7 @@ static void drm_gem_vram_cleanup(struct drm_gem_vram_object *gbo) */ WARN_ON(gbo->vmap_use_count); - WARN_ON(dma_buf_map_is_set(&gbo->map)); + WARN_ON(iosys_map_is_set(&gbo->map)); drm_gem_object_release(&gbo->bo.base); } @@ -365,7 +365,7 @@ int drm_gem_vram_unpin(struct drm_gem_vram_object *gbo) EXPORT_SYMBOL(drm_gem_vram_unpin); static int drm_gem_vram_kmap_locked(struct drm_gem_vram_object *gbo, - struct dma_buf_map *map) + struct iosys_map *map) { int ret; @@ -377,7 +377,7 @@ static int drm_gem_vram_kmap_locked(struct drm_gem_vram_object *gbo, * page mapping might still be around. Only vmap if the there's * no mapping present. */ - if (dma_buf_map_is_null(&gbo->map)) { + if (iosys_map_is_null(&gbo->map)) { ret = ttm_bo_vmap(&gbo->bo, &gbo->map); if (ret) return ret; @@ -391,14 +391,14 @@ out: } static void drm_gem_vram_kunmap_locked(struct drm_gem_vram_object *gbo, - struct dma_buf_map *map) + struct iosys_map *map) { struct drm_device *dev = gbo->bo.base.dev; if (drm_WARN_ON_ONCE(dev, !gbo->vmap_use_count)) return; - if (drm_WARN_ON_ONCE(dev, !dma_buf_map_is_equal(&gbo->map, map))) + if (drm_WARN_ON_ONCE(dev, !iosys_map_is_equal(&gbo->map, map))) return; /* BUG: map not mapped from this BO */ if (--gbo->vmap_use_count > 0) @@ -428,7 +428,7 @@ static void drm_gem_vram_kunmap_locked(struct drm_gem_vram_object *gbo, * Returns: * 0 on success, or a negative error code otherwise. */ -int drm_gem_vram_vmap(struct drm_gem_vram_object *gbo, struct dma_buf_map *map) +int drm_gem_vram_vmap(struct drm_gem_vram_object *gbo, struct iosys_map *map) { int ret; @@ -463,7 +463,8 @@ EXPORT_SYMBOL(drm_gem_vram_vmap); * A call to drm_gem_vram_vunmap() unmaps and unpins a GEM VRAM buffer. See * the documentation for drm_gem_vram_vmap() for more information. */ -void drm_gem_vram_vunmap(struct drm_gem_vram_object *gbo, struct dma_buf_map *map) +void drm_gem_vram_vunmap(struct drm_gem_vram_object *gbo, + struct iosys_map *map) { int ret; @@ -567,7 +568,7 @@ static void drm_gem_vram_bo_driver_move_notify(struct drm_gem_vram_object *gbo) return; ttm_bo_vunmap(bo, &gbo->map); - dma_buf_map_clear(&gbo->map); /* explicitly clear mapping for next vmap call */ + iosys_map_clear(&gbo->map); /* explicitly clear mapping for next vmap call */ } static int drm_gem_vram_bo_driver_move(struct drm_gem_vram_object *gbo, @@ -802,7 +803,8 @@ static void drm_gem_vram_object_unpin(struct drm_gem_object *gem) * Returns: * 0 on success, or a negative error code otherwise. */ -static int drm_gem_vram_object_vmap(struct drm_gem_object *gem, struct dma_buf_map *map) +static int drm_gem_vram_object_vmap(struct drm_gem_object *gem, + struct iosys_map *map) { struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); @@ -815,7 +817,8 @@ static int drm_gem_vram_object_vmap(struct drm_gem_object *gem, struct dma_buf_m * @gem: The GEM object to unmap * @map: Kernel virtual address where the VRAM GEM object was mapped */ -static void drm_gem_vram_object_vunmap(struct drm_gem_object *gem, struct dma_buf_map *map) +static void drm_gem_vram_object_vunmap(struct drm_gem_object *gem, + struct iosys_map *map) { struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 17f3548c8ed2..1fbbc19f1ac0 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -33,7 +33,7 @@ struct dentry; struct dma_buf; -struct dma_buf_map; +struct iosys_map; struct drm_connector; struct drm_crtc; struct drm_framebuffer; @@ -174,8 +174,8 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent, int drm_gem_pin(struct drm_gem_object *obj); void drm_gem_unpin(struct drm_gem_object *obj); -int drm_gem_vmap(struct drm_gem_object *obj, struct dma_buf_map *map); -void drm_gem_vunmap(struct drm_gem_object *obj, struct dma_buf_map *map); +int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map); +void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map); int drm_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, u32 handle); diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index 0327d595e028..9314f2ead79f 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -201,8 +201,8 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, struct drm_rect *clip, bool swap) { struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0); - struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; - struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]; + struct iosys_map map[DRM_FORMAT_MAX_PLANES]; + struct iosys_map data[DRM_FORMAT_MAX_PLANES]; void *src; int ret; @@ -258,8 +258,8 @@ static void mipi_dbi_set_window_address(struct mipi_dbi_dev *dbidev, static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect) { - struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; - struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]; + struct iosys_map map[DRM_FORMAT_MAX_PLANES]; + struct iosys_map data[DRM_FORMAT_MAX_PLANES]; struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); unsigned int height = rect->y2 - rect->y1; unsigned int width = rect->x2 - rect->x1; diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index c773d3dfb1ab..e3f09f18110c 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -674,7 +674,7 @@ EXPORT_SYMBOL(drm_gem_unmap_dma_buf); * * Returns 0 on success or a negative errno code otherwise. */ -int drm_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map) +int drm_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct iosys_map *map) { struct drm_gem_object *obj = dma_buf->priv; @@ -690,7 +690,7 @@ EXPORT_SYMBOL(drm_gem_dmabuf_vmap); * Releases a kernel virtual mapping. This can be used as the * &dma_buf_ops.vunmap callback. Calls into &drm_gem_object_funcs.vunmap for device specific handling. */ -void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, struct dma_buf_map *map) +void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, struct iosys_map *map) { struct drm_gem_object *obj = dma_buf->priv; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h index 049ae87de9be..f32f4771dada 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h @@ -49,7 +49,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset); struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj); -int etnaviv_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map); +int etnaviv_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map); struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sg); int etnaviv_gem_prime_pin(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c index 6788ea8490d1..3fa2da149639 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c @@ -25,14 +25,14 @@ struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj) return drm_prime_pages_to_sg(obj->dev, etnaviv_obj->pages, npages); } -int etnaviv_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) +int etnaviv_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) { void *vaddr; vaddr = etnaviv_gem_vmap(obj); if (!vaddr) return -ENOMEM; - dma_buf_map_set_vaddr(map, vaddr); + iosys_map_set_vaddr(map, vaddr); return 0; } @@ -62,7 +62,7 @@ void etnaviv_gem_prime_unpin(struct drm_gem_object *obj) static void etnaviv_gem_prime_release(struct etnaviv_gem_object *etnaviv_obj) { - struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(etnaviv_obj->vaddr); + struct iosys_map map = IOSYS_MAP_INIT_VADDR(etnaviv_obj->vaddr); if (etnaviv_obj->vaddr) dma_buf_vunmap(etnaviv_obj->base.import_attach->dmabuf, &map); @@ -77,7 +77,7 @@ static void etnaviv_gem_prime_release(struct etnaviv_gem_object *etnaviv_obj) static void *etnaviv_gem_prime_vmap_impl(struct etnaviv_gem_object *etnaviv_obj) { - struct dma_buf_map map; + struct iosys_map map; int ret; lockdep_assert_held(&etnaviv_obj->lock); diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index a150a5a4b5d4..4873f9799f41 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -152,8 +152,8 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb, { struct dma_buf_attachment *import_attach = fb->obj[0]->import_attach; u8 compression = gdrm->compression; - struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; - struct dma_buf_map map_data[DRM_FORMAT_MAX_PLANES]; + struct iosys_map map[DRM_FORMAT_MAX_PLANES]; + struct iosys_map map_data[DRM_FORMAT_MAX_PLANES]; void *vaddr, *buf; size_t pitch, len; int ret = 0; diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c index 93f51e70a951..e82b815f83a6 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c @@ -19,7 +19,7 @@ #include "hyperv_drm.h" static int hyperv_blit_to_vram_rect(struct drm_framebuffer *fb, - const struct dma_buf_map *map, + const struct iosys_map *map, struct drm_rect *rect) { struct hyperv_drm_device *hv = to_hv(fb->dev); @@ -38,7 +38,8 @@ static int hyperv_blit_to_vram_rect(struct drm_framebuffer *fb, return 0; } -static int hyperv_blit_to_vram_fullscreen(struct drm_framebuffer *fb, const struct dma_buf_map *map) +static int hyperv_blit_to_vram_fullscreen(struct drm_framebuffer *fb, + const struct iosys_map *map) { struct drm_rect fullscreen = { .x1 = 0, diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c index 1b526039a60d..14fdb0796c52 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c @@ -74,7 +74,8 @@ static void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment, kfree(sg); } -static int i915_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map) +static int i915_gem_dmabuf_vmap(struct dma_buf *dma_buf, + struct iosys_map *map) { struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); void *vaddr; @@ -83,12 +84,13 @@ static int i915_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map if (IS_ERR(vaddr)) return PTR_ERR(vaddr); - dma_buf_map_set_vaddr(map, vaddr); + iosys_map_set_vaddr(map, vaddr); return 0; } -static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, struct dma_buf_map *map) +static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, + struct iosys_map *map) { struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c index 3cc74b0fed06..b071a58dd6da 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c @@ -266,7 +266,7 @@ static int igt_dmabuf_import(void *arg) struct drm_i915_gem_object *obj; struct dma_buf *dmabuf; void *obj_map, *dma_map; - struct dma_buf_map map; + struct iosys_map map; u32 pattern[] = { 0, 0xaa, 0xcc, 0x55, 0xff }; int err, i; @@ -349,7 +349,7 @@ static int igt_dmabuf_import_ownership(void *arg) struct drm_i915_private *i915 = arg; struct drm_i915_gem_object *obj; struct dma_buf *dmabuf; - struct dma_buf_map map; + struct iosys_map map; void *ptr; int err; @@ -400,7 +400,7 @@ static int igt_dmabuf_export_vmap(void *arg) struct drm_i915_private *i915 = arg; struct drm_i915_gem_object *obj; struct dma_buf *dmabuf; - struct dma_buf_map map; + struct iosys_map map; void *ptr; int err; diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c index 2855d11c7a51..b2a5882b8f81 100644 --- a/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/selftests/mock_dmabuf.c @@ -61,7 +61,7 @@ static void mock_dmabuf_release(struct dma_buf *dma_buf) kfree(mock); } -static int mock_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map) +static int mock_dmabuf_vmap(struct dma_buf *dma_buf, struct iosys_map *map) { struct mock_dmabuf *mock = to_mock(dma_buf); void *vaddr; @@ -69,12 +69,12 @@ static int mock_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map) vaddr = vm_map_ram(mock->pages, mock->npages, 0); if (!vaddr) return -ENOMEM; - dma_buf_map_set_vaddr(map, vaddr); + iosys_map_set_vaddr(map, vaddr); return 0; } -static void mock_dmabuf_vunmap(struct dma_buf *dma_buf, struct dma_buf_map *map) +static void mock_dmabuf_vunmap(struct dma_buf *dma_buf, struct iosys_map *map) { struct mock_dmabuf *mock = to_mock(dma_buf); diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c index f9a9198ef198..d0c2b1422b3b 100644 --- a/drivers/gpu/drm/lima/lima_gem.c +++ b/drivers/gpu/drm/lima/lima_gem.c @@ -2,6 +2,7 @@ /* Copyright 2017-2019 Qiang Yu */ #include +#include #include #include #include @@ -182,7 +183,7 @@ static int lima_gem_pin(struct drm_gem_object *obj) return drm_gem_shmem_pin(&bo->base); } -static int lima_gem_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) +static int lima_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map) { struct lima_bo *bo = to_lima_bo(obj); diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c index 5612d73f238f..390c969f74ad 100644 --- a/drivers/gpu/drm/lima/lima_sched.c +++ b/drivers/gpu/drm/lima/lima_sched.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /* Copyright 2017-2019 Qiang Yu */ -#include +#include #include #include #include @@ -284,7 +284,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task) struct lima_dump_chunk_buffer *buffer_chunk; u32 size, task_size, mem_size; int i; - struct dma_buf_map map; + struct iosys_map map; int ret; mutex_lock(&dev->error_task_list_lock); diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c b/drivers/gpu/drm/mediatek/mtk_drm_gem.c index d0544962cfc1..139d7724c6d0 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c @@ -220,7 +220,7 @@ struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev, return &mtk_gem->base; } -int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) +int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) { struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj); struct sg_table *sgt = NULL; @@ -247,12 +247,13 @@ int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) out: kfree(sgt); - dma_buf_map_set_vaddr(map, mtk_gem->kvaddr); + iosys_map_set_vaddr(map, mtk_gem->kvaddr); return 0; } -void mtk_drm_gem_prime_vunmap(struct drm_gem_object *obj, struct dma_buf_map *map) +void mtk_drm_gem_prime_vunmap(struct drm_gem_object *obj, + struct iosys_map *map) { struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj); void *vaddr = map->vaddr; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.h b/drivers/gpu/drm/mediatek/mtk_drm_gem.h index 9a359a06cb73..78f23b07a02e 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_gem.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.h @@ -42,7 +42,8 @@ int mtk_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj); struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sg); -int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map); -void mtk_drm_gem_prime_vunmap(struct drm_gem_object *obj, struct dma_buf_map *map); +int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map); +void mtk_drm_gem_prime_vunmap(struct drm_gem_object *obj, + struct iosys_map *map); #endif diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index b983541a4c53..9c817b33c398 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -9,7 +9,7 @@ */ #include -#include +#include #include #include @@ -845,7 +845,7 @@ mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, static void mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb, - struct drm_rect *clip, const struct dma_buf_map *map) + struct drm_rect *clip, const struct iosys_map *map) { void __iomem *dst = mdev->vram; void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */ diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index d7574e6bd4e4..ae52412d529a 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -309,8 +309,8 @@ void msm_gem_shrinker_init(struct drm_device *dev); void msm_gem_shrinker_cleanup(struct drm_device *dev); struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj); -int msm_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map); -void msm_gem_prime_vunmap(struct drm_gem_object *obj, struct dma_buf_map *map); +int msm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map); +void msm_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map); struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sg); int msm_gem_prime_pin(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c index fc94e061d6a7..e8f1b7a2ca9c 100644 --- a/drivers/gpu/drm/msm/msm_gem_prime.c +++ b/drivers/gpu/drm/msm/msm_gem_prime.c @@ -22,19 +22,19 @@ struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj) return drm_prime_pages_to_sg(obj->dev, msm_obj->pages, npages); } -int msm_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) +int msm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) { void *vaddr; vaddr = msm_gem_get_vaddr(obj); if (IS_ERR(vaddr)) return PTR_ERR(vaddr); - dma_buf_map_set_vaddr(map, vaddr); + iosys_map_set_vaddr(map, vaddr); return 0; } -void msm_gem_prime_vunmap(struct drm_gem_object *obj, struct dma_buf_map *map) +void msm_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map) { msm_gem_put_vaddr(obj); } diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c index 1d36df5af98d..bc0df93f7f21 100644 --- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c +++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c @@ -1,16 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright 2019 Collabora Ltd */ -#include -#include -#include #include -#include #include +#include #include #include #include +#include +#include +#include + #include "panfrost_device.h" #include "panfrost_features.h" #include "panfrost_gem.h" @@ -73,7 +74,7 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev, { struct panfrost_file_priv *user = file_priv->driver_priv; struct panfrost_perfcnt *perfcnt = pfdev->perfcnt; - struct dma_buf_map map; + struct iosys_map map; struct drm_gem_shmem_object *bo; u32 cfg, as; int ret; @@ -181,7 +182,7 @@ static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev, { struct panfrost_file_priv *user = file_priv->driver_priv; struct panfrost_perfcnt *perfcnt = pfdev->perfcnt; - struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(perfcnt->buf); + struct iosys_map map = IOSYS_MAP_INIT_VADDR(perfcnt->buf); if (user != perfcnt->user) return -EINVAL; diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 9e0a1e836011..9a9c29b1d3e1 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include @@ -566,8 +566,8 @@ static struct qxl_bo *qxl_create_cursor(struct qxl_device *qdev, { static const u32 size = 64 * 64 * 4; struct qxl_bo *cursor_bo; - struct dma_buf_map cursor_map; - struct dma_buf_map user_map; + struct iosys_map cursor_map; + struct iosys_map user_map; struct qxl_cursor cursor; int ret; @@ -1183,7 +1183,7 @@ int qxl_create_monitors_object(struct qxl_device *qdev) { int ret; struct drm_gem_object *gobj; - struct dma_buf_map map; + struct iosys_map map; int monitors_config_size = sizeof(struct qxl_monitors_config) + qxl_num_crtc * sizeof(struct qxl_head); diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c index 7d27891e87fa..a93de9e1977a 100644 --- a/drivers/gpu/drm/qxl/qxl_draw.c +++ b/drivers/gpu/drm/qxl/qxl_draw.c @@ -20,7 +20,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include +#include #include @@ -44,7 +44,7 @@ static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev, unsigned int num_clips, struct qxl_bo *clips_bo) { - struct dma_buf_map map; + struct iosys_map map; struct qxl_clip_rects *dev_clips; int ret; @@ -146,7 +146,7 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, int stride = fb->pitches[0]; /* depth is not actually interesting, we don't mask with it */ int depth = fb->format->cpp[0] * 8; - struct dma_buf_map surface_map; + struct iosys_map surface_map; uint8_t *surface_base; struct qxl_release *release; struct qxl_bo *clips_bo; diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 359266d9e860..9796099ff18f 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -30,7 +30,7 @@ * Definitions taken from spice-protocol, plus kernel driver specific bits. */ -#include +#include #include #include #include @@ -50,7 +50,7 @@ #include "qxl_dev.h" -struct dma_buf_map; +struct iosys_map; #define DRIVER_AUTHOR "Dave Airlie" @@ -81,7 +81,7 @@ struct qxl_bo { /* Protected by tbo.reserved */ struct ttm_place placements[3]; struct ttm_placement placement; - struct dma_buf_map map; + struct iosys_map map; void *kptr; unsigned int map_count; int type; @@ -431,9 +431,9 @@ struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj); struct drm_gem_object *qxl_gem_prime_import_sg_table( struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt); -int qxl_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map); +int qxl_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map); void qxl_gem_prime_vunmap(struct drm_gem_object *obj, - struct dma_buf_map *map); + struct iosys_map *map); /* qxl_irq.c */ int qxl_irq_init(struct qxl_device *qdev); diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index fbb36e3e8564..b42a657e4c2f 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -23,7 +23,7 @@ * Alon Levy */ -#include +#include #include #include "qxl_drv.h" @@ -158,7 +158,7 @@ int qxl_bo_create(struct qxl_device *qdev, unsigned long size, return 0; } -int qxl_bo_vmap_locked(struct qxl_bo *bo, struct dma_buf_map *map) +int qxl_bo_vmap_locked(struct qxl_bo *bo, struct iosys_map *map) { int r; @@ -184,7 +184,7 @@ out: return 0; } -int qxl_bo_vmap(struct qxl_bo *bo, struct dma_buf_map *map) +int qxl_bo_vmap(struct qxl_bo *bo, struct iosys_map *map) { int r; @@ -210,7 +210,7 @@ void *qxl_bo_kmap_atomic_page(struct qxl_device *qdev, void *rptr; int ret; struct io_mapping *map; - struct dma_buf_map bo_map; + struct iosys_map bo_map; if (bo->tbo.resource->mem_type == TTM_PL_VRAM) map = qdev->vram_mapping; diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h index cee4b52b75dd..53392cb90eec 100644 --- a/drivers/gpu/drm/qxl/qxl_object.h +++ b/drivers/gpu/drm/qxl/qxl_object.h @@ -59,8 +59,8 @@ extern int qxl_bo_create(struct qxl_device *qdev, u32 priority, struct qxl_surface *surf, struct qxl_bo **bo_ptr); -int qxl_bo_vmap(struct qxl_bo *bo, struct dma_buf_map *map); -int qxl_bo_vmap_locked(struct qxl_bo *bo, struct dma_buf_map *map); +int qxl_bo_vmap(struct qxl_bo *bo, struct iosys_map *map); +int qxl_bo_vmap_locked(struct qxl_bo *bo, struct iosys_map *map); int qxl_bo_vunmap(struct qxl_bo *bo); void qxl_bo_vunmap_locked(struct qxl_bo *bo); void *qxl_bo_kmap_atomic_page(struct qxl_device *qdev, struct qxl_bo *bo, int page_offset); diff --git a/drivers/gpu/drm/qxl/qxl_prime.c b/drivers/gpu/drm/qxl/qxl_prime.c index 4a10cb0a413b..142d01415acb 100644 --- a/drivers/gpu/drm/qxl/qxl_prime.c +++ b/drivers/gpu/drm/qxl/qxl_prime.c @@ -54,7 +54,7 @@ struct drm_gem_object *qxl_gem_prime_import_sg_table( return ERR_PTR(-ENOSYS); } -int qxl_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) +int qxl_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) { struct qxl_bo *bo = gem_to_qxl_bo(obj); int ret; @@ -67,7 +67,7 @@ int qxl_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) } void qxl_gem_prime_vunmap(struct drm_gem_object *obj, - struct dma_buf_map *map) + struct iosys_map *map) { struct qxl_bo *bo = gem_to_qxl_bo(obj); diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index a36a4f2c76b0..f563284a7fac 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -26,6 +26,7 @@ * Jerome Glisse */ +#include #include #include diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 63eb73b624aa..985584147da1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -510,7 +510,7 @@ err_free_rk_obj: return ERR_PTR(ret); } -int rockchip_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) +int rockchip_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) { struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); @@ -519,18 +519,19 @@ int rockchip_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) pgprot_writecombine(PAGE_KERNEL)); if (!vaddr) return -ENOMEM; - dma_buf_map_set_vaddr(map, vaddr); + iosys_map_set_vaddr(map, vaddr); return 0; } if (rk_obj->dma_attrs & DMA_ATTR_NO_KERNEL_MAPPING) return -ENOMEM; - dma_buf_map_set_vaddr(map, rk_obj->kvaddr); + iosys_map_set_vaddr(map, rk_obj->kvaddr); return 0; } -void rockchip_gem_prime_vunmap(struct drm_gem_object *obj, struct dma_buf_map *map) +void rockchip_gem_prime_vunmap(struct drm_gem_object *obj, + struct iosys_map *map) { struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h index 47c1861eece0..72f59ac6d258 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h @@ -31,8 +31,9 @@ struct drm_gem_object * rockchip_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sg); -int rockchip_gem_prime_vmap(struct drm_gem_object *obj, struct dma_buf_map *map); -void rockchip_gem_prime_vunmap(struct drm_gem_object *obj, struct dma_buf_map *map); +int rockchip_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map); +void rockchip_gem_prime_vunmap(struct drm_gem_object *obj, + struct iosys_map *map); struct rockchip_gem_object * rockchip_gem_create_object(struct drm_device *drm, unsigned int size, diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index fce0e52973c2..0063403ab5e1 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -174,7 +174,7 @@ static void tegra_bo_unpin(struct host1x_bo_mapping *map) static void *tegra_bo_mmap(struct host1x_bo *bo) { struct tegra_bo *obj = host1x_to_tegra_bo(bo); - struct dma_buf_map map; + struct iosys_map map; int ret; if (obj->vaddr) { @@ -191,7 +191,7 @@ static void *tegra_bo_mmap(struct host1x_bo *bo) static void tegra_bo_munmap(struct host1x_bo *bo, void *addr) { struct tegra_bo *obj = host1x_to_tegra_bo(bo); - struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(addr); + struct iosys_map map = IOSYS_MAP_INIT_VADDR(addr); if (obj->vaddr) return; @@ -699,17 +699,17 @@ static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma) return __tegra_gem_mmap(gem, vma); } -static int tegra_gem_prime_vmap(struct dma_buf *buf, struct dma_buf_map *map) +static int tegra_gem_prime_vmap(struct dma_buf *buf, struct iosys_map *map) { struct drm_gem_object *gem = buf->priv; struct tegra_bo *bo = to_tegra_bo(gem); - dma_buf_map_set_vaddr(map, bo->vaddr); + iosys_map_set_vaddr(map, bo->vaddr); return 0; } -static void tegra_gem_prime_vunmap(struct dma_buf *buf, struct dma_buf_map *map) +static void tegra_gem_prime_vunmap(struct dma_buf *buf, struct iosys_map *map) { } diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c index c95d9ff7d600..2dc5ffecf191 100644 --- a/drivers/gpu/drm/tiny/cirrus.c +++ b/drivers/gpu/drm/tiny/cirrus.c @@ -16,7 +16,7 @@ * Copyright 1999-2001 Jeff Garzik */ -#include +#include #include #include @@ -312,7 +312,8 @@ static int cirrus_mode_set(struct cirrus_device *cirrus, return 0; } -static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, const struct dma_buf_map *map, +static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, + const struct iosys_map *map, struct drm_rect *rect) { struct cirrus_device *cirrus = to_cirrus(fb->dev); @@ -344,7 +345,8 @@ static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, const struct dma_buf_ return 0; } -static int cirrus_fb_blit_fullscreen(struct drm_framebuffer *fb, const struct dma_buf_map *map) +static int cirrus_fb_blit_fullscreen(struct drm_framebuffer *fb, + const struct iosys_map *map) { struct drm_rect fullscreen = { .x1 = 0, diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c index 6bc0c298739c..648e585d40a8 100644 --- a/drivers/gpu/drm/tiny/gm12u320.c +++ b/drivers/gpu/drm/tiny/gm12u320.c @@ -95,7 +95,7 @@ struct gm12u320_device { struct drm_rect rect; int frame; int draw_status_timeout; - struct dma_buf_map src_map; + struct iosys_map src_map; } fb_update; }; @@ -395,7 +395,8 @@ err: GM12U320_ERR("Frame update error: %d\n", ret); } -static void gm12u320_fb_mark_dirty(struct drm_framebuffer *fb, const struct dma_buf_map *map, +static void gm12u320_fb_mark_dirty(struct drm_framebuffer *fb, + const struct iosys_map *map, struct drm_rect *dirty) { struct gm12u320_device *gm12u320 = to_gm12u320(fb->dev); @@ -438,7 +439,7 @@ static void gm12u320_stop_fb_update(struct gm12u320_device *gm12u320) mutex_lock(&gm12u320->fb_update.lock); old_fb = gm12u320->fb_update.fb; gm12u320->fb_update.fb = NULL; - dma_buf_map_clear(&gm12u320->fb_update.src_map); + iosys_map_clear(&gm12u320->fb_update.src_map); mutex_unlock(&gm12u320->fb_update.lock); drm_framebuffer_put(old_fb); diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 72a94301bc95..4bf72470abef 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include @@ -93,7 +93,7 @@ void ttm_move_memcpy(bool clear, { const struct ttm_kmap_iter_ops *dst_ops = dst_iter->ops; const struct ttm_kmap_iter_ops *src_ops = src_iter->ops; - struct dma_buf_map src_map, dst_map; + struct iosys_map src_map, dst_map; pgoff_t i; /* Single TTM move. NOP */ @@ -385,7 +385,7 @@ void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map) } EXPORT_SYMBOL(ttm_bo_kunmap); -int ttm_bo_vmap(struct ttm_buffer_object *bo, struct dma_buf_map *map) +int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map) { struct ttm_resource *mem = bo->resource; int ret; @@ -413,7 +413,7 @@ int ttm_bo_vmap(struct ttm_buffer_object *bo, struct dma_buf_map *map) if (!vaddr_iomem) return -ENOMEM; - dma_buf_map_set_vaddr_iomem(map, vaddr_iomem); + iosys_map_set_vaddr_iomem(map, vaddr_iomem); } else { struct ttm_operation_ctx ctx = { @@ -437,25 +437,25 @@ int ttm_bo_vmap(struct ttm_buffer_object *bo, struct dma_buf_map *map) if (!vaddr) return -ENOMEM; - dma_buf_map_set_vaddr(map, vaddr); + iosys_map_set_vaddr(map, vaddr); } return 0; } EXPORT_SYMBOL(ttm_bo_vmap); -void ttm_bo_vunmap(struct ttm_buffer_object *bo, struct dma_buf_map *map) +void ttm_bo_vunmap(struct ttm_buffer_object *bo, struct iosys_map *map) { struct ttm_resource *mem = bo->resource; - if (dma_buf_map_is_null(map)) + if (iosys_map_is_null(map)) return; if (!map->is_iomem) vunmap(map->vaddr); else if (!mem->bus.addr) iounmap(map->vaddr_iomem); - dma_buf_map_clear(map); + iosys_map_clear(map); ttm_mem_io_free(bo->bdev, bo->resource); } diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c index 035d71332d18..df9efafa0f2f 100644 --- a/drivers/gpu/drm/ttm/ttm_resource.c +++ b/drivers/gpu/drm/ttm/ttm_resource.c @@ -22,7 +22,7 @@ * Authors: Christian König */ -#include +#include #include #include @@ -209,7 +209,7 @@ void ttm_resource_manager_debug(struct ttm_resource_manager *man, EXPORT_SYMBOL(ttm_resource_manager_debug); static void ttm_kmap_iter_iomap_map_local(struct ttm_kmap_iter *iter, - struct dma_buf_map *dmap, + struct iosys_map *dmap, pgoff_t i) { struct ttm_kmap_iter_iomap *iter_io = @@ -236,11 +236,11 @@ retry: addr = io_mapping_map_local_wc(iter_io->iomap, iter_io->cache.offs + (((resource_size_t)i - iter_io->cache.i) << PAGE_SHIFT)); - dma_buf_map_set_vaddr_iomem(dmap, addr); + iosys_map_set_vaddr_iomem(dmap, addr); } static void ttm_kmap_iter_iomap_unmap_local(struct ttm_kmap_iter *iter, - struct dma_buf_map *map) + struct iosys_map *map) { io_mapping_unmap_local(map->vaddr_iomem); } @@ -291,14 +291,14 @@ EXPORT_SYMBOL(ttm_kmap_iter_iomap_init); */ static void ttm_kmap_iter_linear_io_map_local(struct ttm_kmap_iter *iter, - struct dma_buf_map *dmap, + struct iosys_map *dmap, pgoff_t i) { struct ttm_kmap_iter_linear_io *iter_io = container_of(iter, typeof(*iter_io), base); *dmap = iter_io->dmap; - dma_buf_map_incr(dmap, i * PAGE_SIZE); + iosys_map_incr(dmap, i * PAGE_SIZE); } static const struct ttm_kmap_iter_ops ttm_kmap_iter_linear_io_ops = { @@ -334,7 +334,7 @@ ttm_kmap_iter_linear_io_init(struct ttm_kmap_iter_linear_io *iter_io, } if (mem->bus.addr) { - dma_buf_map_set_vaddr(&iter_io->dmap, mem->bus.addr); + iosys_map_set_vaddr(&iter_io->dmap, mem->bus.addr); iter_io->needs_unmap = false; } else { size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT; @@ -342,23 +342,23 @@ ttm_kmap_iter_linear_io_init(struct ttm_kmap_iter_linear_io *iter_io, iter_io->needs_unmap = true; memset(&iter_io->dmap, 0, sizeof(iter_io->dmap)); if (mem->bus.caching == ttm_write_combined) - dma_buf_map_set_vaddr_iomem(&iter_io->dmap, - ioremap_wc(mem->bus.offset, - bus_size)); + iosys_map_set_vaddr_iomem(&iter_io->dmap, + ioremap_wc(mem->bus.offset, + bus_size)); else if (mem->bus.caching == ttm_cached) - dma_buf_map_set_vaddr(&iter_io->dmap, - memremap(mem->bus.offset, bus_size, - MEMREMAP_WB | - MEMREMAP_WT | - MEMREMAP_WC)); + iosys_map_set_vaddr(&iter_io->dmap, + memremap(mem->bus.offset, bus_size, + MEMREMAP_WB | + MEMREMAP_WT | + MEMREMAP_WC)); /* If uncached requested or if mapping cached or wc failed */ - if (dma_buf_map_is_null(&iter_io->dmap)) - dma_buf_map_set_vaddr_iomem(&iter_io->dmap, - ioremap(mem->bus.offset, - bus_size)); + if (iosys_map_is_null(&iter_io->dmap)) + iosys_map_set_vaddr_iomem(&iter_io->dmap, + ioremap(mem->bus.offset, + bus_size)); - if (dma_buf_map_is_null(&iter_io->dmap)) { + if (iosys_map_is_null(&iter_io->dmap)) { ret = -ENOMEM; goto out_io_free; } @@ -387,7 +387,7 @@ ttm_kmap_iter_linear_io_fini(struct ttm_kmap_iter_linear_io *iter_io, struct ttm_device *bdev, struct ttm_resource *mem) { - if (iter_io->needs_unmap && dma_buf_map_is_set(&iter_io->dmap)) { + if (iter_io->needs_unmap && iosys_map_is_set(&iter_io->dmap)) { if (iter_io->dmap.is_iomem) iounmap(iter_io->dmap.vaddr_iomem); else diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 79c870a3bef8..d234aab800a0 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -406,18 +406,18 @@ void ttm_tt_mgr_init(unsigned long num_pages, unsigned long num_dma32_pages) } static void ttm_kmap_iter_tt_map_local(struct ttm_kmap_iter *iter, - struct dma_buf_map *dmap, + struct iosys_map *dmap, pgoff_t i) { struct ttm_kmap_iter_tt *iter_tt = container_of(iter, typeof(*iter_tt), base); - dma_buf_map_set_vaddr(dmap, kmap_local_page_prot(iter_tt->tt->pages[i], - iter_tt->prot)); + iosys_map_set_vaddr(dmap, kmap_local_page_prot(iter_tt->tt->pages[i], + iter_tt->prot)); } static void ttm_kmap_iter_tt_unmap_local(struct ttm_kmap_iter *iter, - struct dma_buf_map *map) + struct iosys_map *map) { kunmap_local(map->vaddr); } diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 32232228dae9..e67c40a48fb4 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -264,7 +264,8 @@ static int udl_aligned_damage_clip(struct drm_rect *clip, int x, int y, return 0; } -static int udl_handle_damage(struct drm_framebuffer *fb, const struct dma_buf_map *map, +static int udl_handle_damage(struct drm_framebuffer *fb, + const struct iosys_map *map, int x, int y, int width, int height) { struct drm_device *dev = fb->dev; diff --git a/drivers/gpu/drm/vboxvideo/vbox_mode.c b/drivers/gpu/drm/vboxvideo/vbox_mode.c index 4227a915b06a..4017b0a621fc 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_mode.c +++ b/drivers/gpu/drm/vboxvideo/vbox_mode.c @@ -10,7 +10,7 @@ * Hans de Goede */ -#include +#include #include #include @@ -398,7 +398,7 @@ static void vbox_cursor_atomic_update(struct drm_plane *plane, u32 height = new_state->crtc_h; struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(new_state); - struct dma_buf_map map = shadow_plane_state->data[0]; + struct iosys_map map = shadow_plane_state->data[0]; u8 *src = map.vaddr; /* TODO: Use mapping abstraction properly */ size_t data_size, mask_size; u32 flags; diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index 9e8204be9a14..c6a1036bf2ea 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -157,7 +157,7 @@ static void compose_plane(struct vkms_composer *primary_composer, void *vaddr; void (*pixel_blend)(const u8 *p_src, u8 *p_dst); - if (WARN_ON(dma_buf_map_is_null(&primary_composer->map[0]))) + if (WARN_ON(iosys_map_is_null(&primary_composer->map[0]))) return; vaddr = plane_composer->map[0].vaddr; @@ -187,7 +187,7 @@ static int compose_active_planes(void **vaddr_out, } } - if (WARN_ON(dma_buf_map_is_null(&primary_composer->map[0]))) + if (WARN_ON(iosys_map_is_null(&primary_composer->map[0]))) return -EINVAL; vaddr = primary_composer->map[0].vaddr; diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index d48c23d40ce5..18d944c57883 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -21,14 +21,14 @@ #define YRES_MAX 8192 struct vkms_writeback_job { - struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; - struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]; + struct iosys_map map[DRM_FORMAT_MAX_PLANES]; + struct iosys_map data[DRM_FORMAT_MAX_PLANES]; }; struct vkms_composer { struct drm_framebuffer fb; struct drm_rect src, dst; - struct dma_buf_map map[4]; + struct iosys_map map[4]; unsigned int offset; unsigned int pitch; unsigned int cpp; diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index 32409e15244b..d8eb674b49a6 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ -#include +#include #include #include diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c index 8694227f555f..af1604dfbbaf 100644 --- a/drivers/gpu/drm/vkms/vkms_writeback.c +++ b/drivers/gpu/drm/vkms/vkms_writeback.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ -#include +#include #include #include diff --git a/drivers/gpu/drm/xen/xen_drm_front_gem.c b/drivers/gpu/drm/xen/xen_drm_front_gem.c index dd358ba2bf8e..5a5bf4e5b717 100644 --- a/drivers/gpu/drm/xen/xen_drm_front_gem.c +++ b/drivers/gpu/drm/xen/xen_drm_front_gem.c @@ -280,7 +280,8 @@ xen_drm_front_gem_import_sg_table(struct drm_device *dev, return &xen_obj->base; } -int xen_drm_front_gem_prime_vmap(struct drm_gem_object *gem_obj, struct dma_buf_map *map) +int xen_drm_front_gem_prime_vmap(struct drm_gem_object *gem_obj, + struct iosys_map *map) { struct xen_gem_object *xen_obj = to_xen_gem_obj(gem_obj); void *vaddr; @@ -293,13 +294,13 @@ int xen_drm_front_gem_prime_vmap(struct drm_gem_object *gem_obj, struct dma_buf_ VM_MAP, PAGE_KERNEL); if (!vaddr) return -ENOMEM; - dma_buf_map_set_vaddr(map, vaddr); + iosys_map_set_vaddr(map, vaddr); return 0; } void xen_drm_front_gem_prime_vunmap(struct drm_gem_object *gem_obj, - struct dma_buf_map *map) + struct iosys_map *map) { vunmap(map->vaddr); } diff --git a/drivers/gpu/drm/xen/xen_drm_front_gem.h b/drivers/gpu/drm/xen/xen_drm_front_gem.h index eaea470f7001..a718a1f382a3 100644 --- a/drivers/gpu/drm/xen/xen_drm_front_gem.h +++ b/drivers/gpu/drm/xen/xen_drm_front_gem.h @@ -12,7 +12,7 @@ #define __XEN_DRM_FRONT_GEM_H struct dma_buf_attachment; -struct dma_buf_map; +struct iosys_map; struct drm_device; struct drm_gem_object; struct sg_table; @@ -32,9 +32,9 @@ struct page **xen_drm_front_gem_get_pages(struct drm_gem_object *obj); void xen_drm_front_gem_free_object_unlocked(struct drm_gem_object *gem_obj); int xen_drm_front_gem_prime_vmap(struct drm_gem_object *gem_obj, - struct dma_buf_map *map); + struct iosys_map *map); void xen_drm_front_gem_prime_vunmap(struct drm_gem_object *gem_obj, - struct dma_buf_map *map); + struct iosys_map *map); #endif /* __XEN_DRM_FRONT_GEM_H */ diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index 7c4096e62173..ecf065cd4a67 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -99,7 +99,7 @@ static void *vb2_dc_vaddr(struct vb2_buffer *vb, void *buf_priv) return buf->vaddr; if (buf->db_attach) { - struct dma_buf_map map; + struct iosys_map map; if (!dma_buf_vmap(buf->db_attach->dmabuf, &map)) buf->vaddr = map.vaddr; @@ -446,7 +446,7 @@ vb2_dc_dmabuf_ops_end_cpu_access(struct dma_buf *dbuf, return 0; } -static int vb2_dc_dmabuf_ops_vmap(struct dma_buf *dbuf, struct dma_buf_map *map) +static int vb2_dc_dmabuf_ops_vmap(struct dma_buf *dbuf, struct iosys_map *map) { struct vb2_dc_buf *buf; void *vaddr; @@ -456,7 +456,7 @@ static int vb2_dc_dmabuf_ops_vmap(struct dma_buf *dbuf, struct dma_buf_map *map) if (!vaddr) return -EINVAL; - dma_buf_map_set_vaddr(map, vaddr); + iosys_map_set_vaddr(map, vaddr); return 0; } @@ -737,7 +737,7 @@ static void vb2_dc_unmap_dmabuf(void *mem_priv) { struct vb2_dc_buf *buf = mem_priv; struct sg_table *sgt = buf->dma_sgt; - struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(buf->vaddr); + struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr); if (WARN_ON(!buf->db_attach)) { pr_err("trying to unpin a not attached buffer\n"); diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 90acafd9a290..f8a21c560ad2 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -303,7 +303,7 @@ static void vb2_dma_sg_put_userptr(void *buf_priv) static void *vb2_dma_sg_vaddr(struct vb2_buffer *vb, void *buf_priv) { struct vb2_dma_sg_buf *buf = buf_priv; - struct dma_buf_map map; + struct iosys_map map; int ret; BUG_ON(!buf); @@ -492,11 +492,12 @@ vb2_dma_sg_dmabuf_ops_end_cpu_access(struct dma_buf *dbuf, return 0; } -static int vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf, struct dma_buf_map *map) +static int vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf, + struct iosys_map *map) { struct vb2_dma_sg_buf *buf = dbuf->priv; - dma_buf_map_set_vaddr(map, buf->vaddr); + iosys_map_set_vaddr(map, buf->vaddr); return 0; } @@ -581,7 +582,7 @@ static void vb2_dma_sg_unmap_dmabuf(void *mem_priv) { struct vb2_dma_sg_buf *buf = mem_priv; struct sg_table *sgt = buf->dma_sgt; - struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(buf->vaddr); + struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr); if (WARN_ON(!buf->db_attach)) { pr_err("trying to unpin a not attached buffer\n"); diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 0bbfea66554f..948152f1596b 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -312,11 +312,12 @@ static void vb2_vmalloc_dmabuf_ops_release(struct dma_buf *dbuf) vb2_vmalloc_put(dbuf->priv); } -static int vb2_vmalloc_dmabuf_ops_vmap(struct dma_buf *dbuf, struct dma_buf_map *map) +static int vb2_vmalloc_dmabuf_ops_vmap(struct dma_buf *dbuf, + struct iosys_map *map) { struct vb2_vmalloc_buf *buf = dbuf->priv; - dma_buf_map_set_vaddr(map, buf->vaddr); + iosys_map_set_vaddr(map, buf->vaddr); return 0; } @@ -372,7 +373,7 @@ static struct dma_buf *vb2_vmalloc_get_dmabuf(struct vb2_buffer *vb, static int vb2_vmalloc_map_dmabuf(void *mem_priv) { struct vb2_vmalloc_buf *buf = mem_priv; - struct dma_buf_map map; + struct iosys_map map; int ret; ret = dma_buf_vmap(buf->dbuf, &map); @@ -386,7 +387,7 @@ static int vb2_vmalloc_map_dmabuf(void *mem_priv) static void vb2_vmalloc_unmap_dmabuf(void *mem_priv) { struct vb2_vmalloc_buf *buf = mem_priv; - struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(buf->vaddr); + struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr); dma_buf_vunmap(buf->dbuf, &map); buf->vaddr = NULL; @@ -395,7 +396,7 @@ static void vb2_vmalloc_unmap_dmabuf(void *mem_priv) static void vb2_vmalloc_detach_dmabuf(void *mem_priv) { struct vb2_vmalloc_buf *buf = mem_priv; - struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(buf->vaddr); + struct iosys_map map = IOSYS_MAP_INIT_VADDR(buf->vaddr); if (buf->vaddr) dma_buf_vunmap(buf->dbuf, &map); diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 4ccbf43e6bfa..5c0503655212 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -587,11 +587,11 @@ static void fastrpc_dma_buf_detatch(struct dma_buf *dmabuf, kfree(a); } -static int fastrpc_vmap(struct dma_buf *dmabuf, struct dma_buf_map *map) +static int fastrpc_vmap(struct dma_buf *dmabuf, struct iosys_map *map) { struct fastrpc_buf *buf = dmabuf->priv; - dma_buf_map_set_vaddr(map, buf->virt); + iosys_map_set_vaddr(map, buf->virt); return 0; } diff --git a/include/drm/drm_cache.h b/include/drm/drm_cache.h index cc9de1632dd3..22deb216b59c 100644 --- a/include/drm/drm_cache.h +++ b/include/drm/drm_cache.h @@ -35,7 +35,7 @@ #include -struct dma_buf_map; +struct iosys_map; void drm_clflush_pages(struct page *pages[], unsigned long num_pages); void drm_clflush_sg(struct sg_table *st); @@ -74,7 +74,7 @@ static inline bool drm_arch_can_wc_memory(void) void drm_memcpy_init_early(void); -void drm_memcpy_from_wc(struct dma_buf_map *dst, - const struct dma_buf_map *src, +void drm_memcpy_from_wc(struct iosys_map *dst, + const struct iosys_map *src, unsigned long len); #endif diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h index f07f2fb02e75..4fc8018eddda 100644 --- a/include/drm/drm_client.h +++ b/include/drm/drm_client.h @@ -3,7 +3,7 @@ #ifndef _DRM_CLIENT_H_ #define _DRM_CLIENT_H_ -#include +#include #include #include #include @@ -144,7 +144,7 @@ struct drm_client_buffer { /** * @map: Virtual address for the buffer */ - struct dma_buf_map map; + struct iosys_map map; /** * @fb: DRM framebuffer @@ -156,7 +156,8 @@ struct drm_client_buffer * drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format); void drm_client_framebuffer_delete(struct drm_client_buffer *buffer); int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect); -int drm_client_buffer_vmap(struct drm_client_buffer *buffer, struct dma_buf_map *map); +int drm_client_buffer_vmap(struct drm_client_buffer *buffer, + struct iosys_map *map); void drm_client_buffer_vunmap(struct drm_client_buffer *buffer); int drm_client_modeset_create(struct drm_client_dev *client); diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index 35e7f44c2a75..e2941cee14b6 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -39,7 +39,7 @@ #include -struct dma_buf_map; +struct iosys_map; struct drm_gem_object; /** @@ -139,7 +139,7 @@ struct drm_gem_object_funcs { * * This callback is optional. */ - int (*vmap)(struct drm_gem_object *obj, struct dma_buf_map *map); + int (*vmap)(struct drm_gem_object *obj, struct iosys_map *map); /** * @vunmap: @@ -149,7 +149,7 @@ struct drm_gem_object_funcs { * * This callback is optional. */ - void (*vunmap)(struct drm_gem_object *obj, struct dma_buf_map *map); + void (*vunmap)(struct drm_gem_object *obj, struct iosys_map *map); /** * @mmap: diff --git a/include/drm/drm_gem_atomic_helper.h b/include/drm/drm_gem_atomic_helper.h index 0b1e2dd2ac3f..6e3319e9001a 100644 --- a/include/drm/drm_gem_atomic_helper.h +++ b/include/drm/drm_gem_atomic_helper.h @@ -3,7 +3,7 @@ #ifndef __DRM_GEM_ATOMIC_HELPER_H__ #define __DRM_GEM_ATOMIC_HELPER_H__ -#include +#include #include #include @@ -59,7 +59,7 @@ struct drm_shadow_plane_state { * The memory mappings stored in map should be established in the plane's * prepare_fb callback and removed in the cleanup_fb callback. */ - struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; + struct iosys_map map[DRM_FORMAT_MAX_PLANES]; /** * @data: Address of each framebuffer BO's data @@ -67,7 +67,7 @@ struct drm_shadow_plane_state { * The address of the data stored in each mapping. This is different * for framebuffers with non-zero offset fields. */ - struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]; + struct iosys_map data[DRM_FORMAT_MAX_PLANES]; }; /** diff --git a/include/drm/drm_gem_cma_helper.h b/include/drm/drm_gem_cma_helper.h index adb507a9dbf0..fbda4ce5d5fb 100644 --- a/include/drm/drm_gem_cma_helper.h +++ b/include/drm/drm_gem_cma_helper.h @@ -38,7 +38,8 @@ void drm_gem_cma_free(struct drm_gem_cma_object *cma_obj); void drm_gem_cma_print_info(const struct drm_gem_cma_object *cma_obj, struct drm_printer *p, unsigned int indent); struct sg_table *drm_gem_cma_get_sg_table(struct drm_gem_cma_object *cma_obj); -int drm_gem_cma_vmap(struct drm_gem_cma_object *cma_obj, struct dma_buf_map *map); +int drm_gem_cma_vmap(struct drm_gem_cma_object *cma_obj, + struct iosys_map *map); int drm_gem_cma_mmap(struct drm_gem_cma_object *cma_obj, struct vm_area_struct *vma); extern const struct vm_operations_struct drm_gem_cma_vm_ops; @@ -106,7 +107,8 @@ static inline struct sg_table *drm_gem_cma_object_get_sg_table(struct drm_gem_ob * Returns: * 0 on success or a negative error code on failure. */ -static inline int drm_gem_cma_object_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) +static inline int drm_gem_cma_object_vmap(struct drm_gem_object *obj, + struct iosys_map *map) { struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj); diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h index 905727719ead..1091e4fa08cb 100644 --- a/include/drm/drm_gem_framebuffer_helper.h +++ b/include/drm/drm_gem_framebuffer_helper.h @@ -2,7 +2,7 @@ #define __DRM_GEM_FB_HELPER_H__ #include -#include +#include #include @@ -40,10 +40,10 @@ drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); int drm_gem_fb_vmap(struct drm_framebuffer *fb, - struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES], - struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]); + struct iosys_map map[static DRM_FORMAT_MAX_PLANES], + struct iosys_map data[DRM_FORMAT_MAX_PLANES]); void drm_gem_fb_vunmap(struct drm_framebuffer *fb, - struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES]); + struct iosys_map map[static DRM_FORMAT_MAX_PLANES]); int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h index 311d66c9cf4b..68347b63fc71 100644 --- a/include/drm/drm_gem_shmem_helper.h +++ b/include/drm/drm_gem_shmem_helper.h @@ -113,8 +113,10 @@ int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem); void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem); int drm_gem_shmem_pin(struct drm_gem_shmem_object *shmem); void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem); -int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem, struct dma_buf_map *map); -void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem, struct dma_buf_map *map); +int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem, + struct iosys_map *map); +void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem, + struct iosys_map *map); int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct *vma); int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv); @@ -226,7 +228,8 @@ static inline struct sg_table *drm_gem_shmem_object_get_sg_table(struct drm_gem_ * Returns: * 0 on success or a negative error code on failure. */ -static inline int drm_gem_shmem_object_vmap(struct drm_gem_object *obj, struct dma_buf_map *map) +static inline int drm_gem_shmem_object_vmap(struct drm_gem_object *obj, + struct iosys_map *map) { struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); @@ -241,7 +244,8 @@ static inline int drm_gem_shmem_object_vmap(struct drm_gem_object *obj, struct d * This function wraps drm_gem_shmem_vunmap(). Drivers that employ the shmem helpers should * use it as their &drm_gem_object_funcs.vunmap handler. */ -static inline void drm_gem_shmem_object_vunmap(struct drm_gem_object *obj, struct dma_buf_map *map) +static inline void drm_gem_shmem_object_vunmap(struct drm_gem_object *obj, + struct iosys_map *map) { struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); diff --git a/include/drm/drm_gem_ttm_helper.h b/include/drm/drm_gem_ttm_helper.h index 78040f6cc6f3..4c003b4f173e 100644 --- a/include/drm/drm_gem_ttm_helper.h +++ b/include/drm/drm_gem_ttm_helper.h @@ -10,7 +10,7 @@ #include #include -struct dma_buf_map; +struct iosys_map; #define drm_gem_ttm_of_gem(gem_obj) \ container_of(gem_obj, struct ttm_buffer_object, base) @@ -18,9 +18,9 @@ struct dma_buf_map; void drm_gem_ttm_print_info(struct drm_printer *p, unsigned int indent, const struct drm_gem_object *gem); int drm_gem_ttm_vmap(struct drm_gem_object *gem, - struct dma_buf_map *map); + struct iosys_map *map); void drm_gem_ttm_vunmap(struct drm_gem_object *gem, - struct dma_buf_map *map); + struct iosys_map *map); int drm_gem_ttm_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma); diff --git a/include/drm/drm_gem_vram_helper.h b/include/drm/drm_gem_vram_helper.h index b4ce27a72773..c083a1d71cf4 100644 --- a/include/drm/drm_gem_vram_helper.h +++ b/include/drm/drm_gem_vram_helper.h @@ -12,7 +12,7 @@ #include #include -#include +#include struct drm_mode_create_dumb; struct drm_plane; @@ -51,7 +51,7 @@ struct vm_area_struct; */ struct drm_gem_vram_object { struct ttm_buffer_object bo; - struct dma_buf_map map; + struct iosys_map map; /** * @vmap_use_count: @@ -97,8 +97,9 @@ void drm_gem_vram_put(struct drm_gem_vram_object *gbo); s64 drm_gem_vram_offset(struct drm_gem_vram_object *gbo); int drm_gem_vram_pin(struct drm_gem_vram_object *gbo, unsigned long pl_flag); int drm_gem_vram_unpin(struct drm_gem_vram_object *gbo); -int drm_gem_vram_vmap(struct drm_gem_vram_object *gbo, struct dma_buf_map *map); -void drm_gem_vram_vunmap(struct drm_gem_vram_object *gbo, struct dma_buf_map *map); +int drm_gem_vram_vmap(struct drm_gem_vram_object *gbo, struct iosys_map *map); +void drm_gem_vram_vunmap(struct drm_gem_vram_object *gbo, + struct iosys_map *map); int drm_gem_vram_fill_create_dumb(struct drm_file *file, struct drm_device *dev, diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h index 54f2c58305d2..2a1d01e5b56b 100644 --- a/include/drm/drm_prime.h +++ b/include/drm/drm_prime.h @@ -54,7 +54,7 @@ struct device; struct dma_buf_export_info; struct dma_buf; struct dma_buf_attachment; -struct dma_buf_map; +struct iosys_map; enum dma_data_direction; @@ -83,8 +83,8 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, struct sg_table *sgt, enum dma_data_direction dir); -int drm_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map); -void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, struct dma_buf_map *map); +int drm_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct iosys_map *map); +void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, struct iosys_map *map); int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma); diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index c17b2df9178b..155b19ee12fb 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -47,7 +47,7 @@ struct ttm_global; struct ttm_device; -struct dma_buf_map; +struct iosys_map; struct drm_mm_node; @@ -481,17 +481,17 @@ void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map); * ttm_bo_vmap * * @bo: The buffer object. - * @map: pointer to a struct dma_buf_map representing the map. + * @map: pointer to a struct iosys_map representing the map. * * Sets up a kernel virtual mapping, using ioremap or vmap to the * data in the buffer object. The parameter @map returns the virtual - * address as struct dma_buf_map. Unmap the buffer with ttm_bo_vunmap(). + * address as struct iosys_map. Unmap the buffer with ttm_bo_vunmap(). * * Returns * -ENOMEM: Out of memory. * -EINVAL: Invalid range. */ -int ttm_bo_vmap(struct ttm_buffer_object *bo, struct dma_buf_map *map); +int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map); /** * ttm_bo_vunmap @@ -501,7 +501,7 @@ int ttm_bo_vmap(struct ttm_buffer_object *bo, struct dma_buf_map *map); * * Unmaps a kernel map set up by ttm_bo_vmap(). */ -void ttm_bo_vunmap(struct ttm_buffer_object *bo, struct dma_buf_map *map); +void ttm_bo_vunmap(struct ttm_buffer_object *bo, struct iosys_map *map); /** * ttm_bo_mmap_obj - mmap memory backed by a ttm buffer object. diff --git a/include/drm/ttm/ttm_kmap_iter.h b/include/drm/ttm/ttm_kmap_iter.h index 8bb00fd39d6c..cc5c09a211b4 100644 --- a/include/drm/ttm/ttm_kmap_iter.h +++ b/include/drm/ttm/ttm_kmap_iter.h @@ -8,7 +8,7 @@ #include struct ttm_kmap_iter; -struct dma_buf_map; +struct iosys_map; /** * struct ttm_kmap_iter_ops - Ops structure for a struct @@ -24,22 +24,22 @@ struct ttm_kmap_iter_ops { * kmap_local semantics. * @res_iter: Pointer to the struct ttm_kmap_iter representing * the resource. - * @dmap: The struct dma_buf_map holding the virtual address after + * @dmap: The struct iosys_map holding the virtual address after * the operation. * @i: The location within the resource to map. PAGE_SIZE granularity. */ void (*map_local)(struct ttm_kmap_iter *res_iter, - struct dma_buf_map *dmap, pgoff_t i); + struct iosys_map *dmap, pgoff_t i); /** * unmap_local() - Unmap a PAGE_SIZE part of the resource previously * mapped using kmap_local. * @res_iter: Pointer to the struct ttm_kmap_iter representing * the resource. - * @dmap: The struct dma_buf_map holding the virtual address after + * @dmap: The struct iosys_map holding the virtual address after * the operation. */ void (*unmap_local)(struct ttm_kmap_iter *res_iter, - struct dma_buf_map *dmap); + struct iosys_map *dmap); bool maps_tt; }; diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h index 5952051091cd..6eae09e382d2 100644 --- a/include/drm/ttm/ttm_resource.h +++ b/include/drm/ttm/ttm_resource.h @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include @@ -41,7 +41,7 @@ struct ttm_resource; struct ttm_place; struct ttm_buffer_object; struct ttm_placement; -struct dma_buf_map; +struct iosys_map; struct io_mapping; struct sg_table; struct scatterlist; @@ -207,7 +207,7 @@ struct ttm_kmap_iter_iomap { */ struct ttm_kmap_iter_linear_io { struct ttm_kmap_iter base; - struct dma_buf_map dmap; + struct iosys_map dmap; bool needs_unmap; }; diff --git a/include/linux/dma-buf-map.h b/include/linux/dma-buf-map.h deleted file mode 100644 index 278d489e4bdd..000000000000 --- a/include/linux/dma-buf-map.h +++ /dev/null @@ -1,266 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Pointer to dma-buf-mapped memory, plus helpers. - */ - -#ifndef __DMA_BUF_MAP_H__ -#define __DMA_BUF_MAP_H__ - -#include -#include - -/** - * DOC: overview - * - * Calling dma-buf's vmap operation returns a pointer to the buffer's memory. - * Depending on the location of the buffer, users may have to access it with - * I/O operations or memory load/store operations. For example, copying to - * system memory could be done with memcpy(), copying to I/O memory would be - * done with memcpy_toio(). - * - * .. code-block:: c - * - * void *vaddr = ...; // pointer to system memory - * memcpy(vaddr, src, len); - * - * void *vaddr_iomem = ...; // pointer to I/O memory - * memcpy_toio(vaddr, _iomem, src, len); - * - * When using dma-buf's vmap operation, the returned pointer is encoded as - * :c:type:`struct dma_buf_map `. - * :c:type:`struct dma_buf_map ` stores the buffer's address in - * system or I/O memory and a flag that signals the required method of - * accessing the buffer. Use the returned instance and the helper functions - * to access the buffer's memory in the correct way. - * - * The type :c:type:`struct dma_buf_map ` and its helpers are - * actually independent from the dma-buf infrastructure. When sharing buffers - * among devices, drivers have to know the location of the memory to access - * the buffers in a safe way. :c:type:`struct dma_buf_map ` - * solves this problem for dma-buf and its users. If other drivers or - * sub-systems require similar functionality, the type could be generalized - * and moved to a more prominent header file. - * - * Open-coding access to :c:type:`struct dma_buf_map ` is - * considered bad style. Rather then accessing its fields directly, use one - * of the provided helper functions, or implement your own. For example, - * instances of :c:type:`struct dma_buf_map ` can be initialized - * statically with DMA_BUF_MAP_INIT_VADDR(), or at runtime with - * dma_buf_map_set_vaddr(). These helpers will set an address in system memory. - * - * .. code-block:: c - * - * struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(0xdeadbeaf); - * - * dma_buf_map_set_vaddr(&map. 0xdeadbeaf); - * - * To set an address in I/O memory, use dma_buf_map_set_vaddr_iomem(). - * - * .. code-block:: c - * - * dma_buf_map_set_vaddr_iomem(&map. 0xdeadbeaf); - * - * Instances of struct dma_buf_map do not have to be cleaned up, but - * can be cleared to NULL with dma_buf_map_clear(). Cleared mappings - * always refer to system memory. - * - * .. code-block:: c - * - * dma_buf_map_clear(&map); - * - * Test if a mapping is valid with either dma_buf_map_is_set() or - * dma_buf_map_is_null(). - * - * .. code-block:: c - * - * if (dma_buf_map_is_set(&map) != dma_buf_map_is_null(&map)) - * // always true - * - * Instances of :c:type:`struct dma_buf_map ` can be compared - * for equality with dma_buf_map_is_equal(). Mappings the point to different - * memory spaces, system or I/O, are never equal. That's even true if both - * spaces are located in the same address space, both mappings contain the - * same address value, or both mappings refer to NULL. - * - * .. code-block:: c - * - * struct dma_buf_map sys_map; // refers to system memory - * struct dma_buf_map io_map; // refers to I/O memory - * - * if (dma_buf_map_is_equal(&sys_map, &io_map)) - * // always false - * - * A set up instance of struct dma_buf_map can be used to access or manipulate - * the buffer memory. Depending on the location of the memory, the provided - * helpers will pick the correct operations. Data can be copied into the memory - * with dma_buf_map_memcpy_to(). The address can be manipulated with - * dma_buf_map_incr(). - * - * .. code-block:: c - * - * const void *src = ...; // source buffer - * size_t len = ...; // length of src - * - * dma_buf_map_memcpy_to(&map, src, len); - * dma_buf_map_incr(&map, len); // go to first byte after the memcpy - */ - -/** - * struct dma_buf_map - Pointer to vmap'ed dma-buf memory. - * @vaddr_iomem: The buffer's address if in I/O memory - * @vaddr: The buffer's address if in system memory - * @is_iomem: True if the dma-buf memory is located in I/O - * memory, or false otherwise. - */ -struct dma_buf_map { - union { - void __iomem *vaddr_iomem; - void *vaddr; - }; - bool is_iomem; -}; - -/** - * DMA_BUF_MAP_INIT_VADDR - Initializes struct dma_buf_map to an address in system memory - * @vaddr_: A system-memory address - */ -#define DMA_BUF_MAP_INIT_VADDR(vaddr_) \ - { \ - .vaddr = (vaddr_), \ - .is_iomem = false, \ - } - -/** - * dma_buf_map_set_vaddr - Sets a dma-buf mapping structure to an address in system memory - * @map: The dma-buf mapping structure - * @vaddr: A system-memory address - * - * Sets the address and clears the I/O-memory flag. - */ -static inline void dma_buf_map_set_vaddr(struct dma_buf_map *map, void *vaddr) -{ - map->vaddr = vaddr; - map->is_iomem = false; -} - -/** - * dma_buf_map_set_vaddr_iomem - Sets a dma-buf mapping structure to an address in I/O memory - * @map: The dma-buf mapping structure - * @vaddr_iomem: An I/O-memory address - * - * Sets the address and the I/O-memory flag. - */ -static inline void dma_buf_map_set_vaddr_iomem(struct dma_buf_map *map, - void __iomem *vaddr_iomem) -{ - map->vaddr_iomem = vaddr_iomem; - map->is_iomem = true; -} - -/** - * dma_buf_map_is_equal - Compares two dma-buf mapping structures for equality - * @lhs: The dma-buf mapping structure - * @rhs: A dma-buf mapping structure to compare with - * - * Two dma-buf mapping structures are equal if they both refer to the same type of memory - * and to the same address within that memory. - * - * Returns: - * True is both structures are equal, or false otherwise. - */ -static inline bool dma_buf_map_is_equal(const struct dma_buf_map *lhs, - const struct dma_buf_map *rhs) -{ - if (lhs->is_iomem != rhs->is_iomem) - return false; - else if (lhs->is_iomem) - return lhs->vaddr_iomem == rhs->vaddr_iomem; - else - return lhs->vaddr == rhs->vaddr; -} - -/** - * dma_buf_map_is_null - Tests for a dma-buf mapping to be NULL - * @map: The dma-buf mapping structure - * - * Depending on the state of struct dma_buf_map.is_iomem, tests if the - * mapping is NULL. - * - * Returns: - * True if the mapping is NULL, or false otherwise. - */ -static inline bool dma_buf_map_is_null(const struct dma_buf_map *map) -{ - if (map->is_iomem) - return !map->vaddr_iomem; - return !map->vaddr; -} - -/** - * dma_buf_map_is_set - Tests is the dma-buf mapping has been set - * @map: The dma-buf mapping structure - * - * Depending on the state of struct dma_buf_map.is_iomem, tests if the - * mapping has been set. - * - * Returns: - * True if the mapping is been set, or false otherwise. - */ -static inline bool dma_buf_map_is_set(const struct dma_buf_map *map) -{ - return !dma_buf_map_is_null(map); -} - -/** - * dma_buf_map_clear - Clears a dma-buf mapping structure - * @map: The dma-buf mapping structure - * - * Clears all fields to zero; including struct dma_buf_map.is_iomem. So - * mapping structures that were set to point to I/O memory are reset for - * system memory. Pointers are cleared to NULL. This is the default. - */ -static inline void dma_buf_map_clear(struct dma_buf_map *map) -{ - if (map->is_iomem) { - map->vaddr_iomem = NULL; - map->is_iomem = false; - } else { - map->vaddr = NULL; - } -} - -/** - * dma_buf_map_memcpy_to - Memcpy into dma-buf mapping - * @dst: The dma-buf mapping structure - * @src: The source buffer - * @len: The number of byte in src - * - * Copies data into a dma-buf mapping. The source buffer is in system - * memory. Depending on the buffer's location, the helper picks the correct - * method of accessing the memory. - */ -static inline void dma_buf_map_memcpy_to(struct dma_buf_map *dst, const void *src, size_t len) -{ - if (dst->is_iomem) - memcpy_toio(dst->vaddr_iomem, src, len); - else - memcpy(dst->vaddr, src, len); -} - -/** - * dma_buf_map_incr - Increments the address stored in a dma-buf mapping - * @map: The dma-buf mapping structure - * @incr: The number of bytes to increment - * - * Increments the address stored in a dma-buf mapping. Depending on the - * buffer's location, the correct value will be updated. - */ -static inline void dma_buf_map_incr(struct dma_buf_map *map, size_t incr) -{ - if (map->is_iomem) - map->vaddr_iomem += incr; - else - map->vaddr += incr; -} - -#endif /* __DMA_BUF_MAP_H__ */ diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 7ab50076e7a6..2097760e8e95 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -13,7 +13,7 @@ #ifndef __DMA_BUF_H__ #define __DMA_BUF_H__ -#include +#include #include #include #include @@ -283,8 +283,8 @@ struct dma_buf_ops { */ int (*mmap)(struct dma_buf *, struct vm_area_struct *vma); - int (*vmap)(struct dma_buf *dmabuf, struct dma_buf_map *map); - void (*vunmap)(struct dma_buf *dmabuf, struct dma_buf_map *map); + int (*vmap)(struct dma_buf *dmabuf, struct iosys_map *map); + void (*vunmap)(struct dma_buf *dmabuf, struct iosys_map *map); }; /** @@ -347,7 +347,7 @@ struct dma_buf { * @vmap_ptr: * The current vmap ptr if @vmapping_counter > 0. Protected by @lock. */ - struct dma_buf_map vmap_ptr; + struct iosys_map vmap_ptr; /** * @exp_name: @@ -628,6 +628,6 @@ int dma_buf_end_cpu_access(struct dma_buf *dma_buf, int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, unsigned long); -int dma_buf_vmap(struct dma_buf *dmabuf, struct dma_buf_map *map); -void dma_buf_vunmap(struct dma_buf *dmabuf, struct dma_buf_map *map); +int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map); +void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map); #endif /* __DMA_BUF_H__ */ diff --git a/include/linux/iosys-map.h b/include/linux/iosys-map.h new file mode 100644 index 000000000000..f4186f91caa6 --- /dev/null +++ b/include/linux/iosys-map.h @@ -0,0 +1,257 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Pointer abstraction for IO/system memory + */ + +#ifndef __IOSYS_MAP_H__ +#define __IOSYS_MAP_H__ + +#include +#include + +/** + * DOC: overview + * + * When accessing a memory region, depending on its location, users may have to + * access it with I/O operations or memory load/store operations. For example, + * copying to system memory could be done with memcpy(), copying to I/O memory + * would be done with memcpy_toio(). + * + * .. code-block:: c + * + * void *vaddr = ...; // pointer to system memory + * memcpy(vaddr, src, len); + * + * void *vaddr_iomem = ...; // pointer to I/O memory + * memcpy_toio(vaddr, _iomem, src, len); + * + * The user of such pointer may not have information about the mapping of that + * region or may want to have a single code path to handle operations on that + * buffer, regardless if it's located in system or IO memory. The type + * :c:type:`struct iosys_map ` and its helpers abstract that so the + * buffer can be passed around to other drivers or have separate duties inside + * the same driver for allocation, read and write operations. + * + * Open-coding access to :c:type:`struct iosys_map ` is considered + * bad style. Rather then accessing its fields directly, use one of the provided + * helper functions, or implement your own. For example, instances of + * :c:type:`struct iosys_map ` can be initialized statically with + * IOSYS_MAP_INIT_VADDR(), or at runtime with iosys_map_set_vaddr(). These + * helpers will set an address in system memory. + * + * .. code-block:: c + * + * struct iosys_map map = IOSYS_MAP_INIT_VADDR(0xdeadbeaf); + * + * iosys_map_set_vaddr(&map, 0xdeadbeaf); + * + * To set an address in I/O memory, use iosys_map_set_vaddr_iomem(). + * + * .. code-block:: c + * + * iosys_map_set_vaddr_iomem(&map, 0xdeadbeaf); + * + * Instances of struct iosys_map do not have to be cleaned up, but + * can be cleared to NULL with iosys_map_clear(). Cleared mappings + * always refer to system memory. + * + * .. code-block:: c + * + * iosys_map_clear(&map); + * + * Test if a mapping is valid with either iosys_map_is_set() or + * iosys_map_is_null(). + * + * .. code-block:: c + * + * if (iosys_map_is_set(&map) != iosys_map_is_null(&map)) + * // always true + * + * Instances of :c:type:`struct iosys_map ` can be compared for + * equality with iosys_map_is_equal(). Mappings that point to different memory + * spaces, system or I/O, are never equal. That's even true if both spaces are + * located in the same address space, both mappings contain the same address + * value, or both mappings refer to NULL. + * + * .. code-block:: c + * + * struct iosys_map sys_map; // refers to system memory + * struct iosys_map io_map; // refers to I/O memory + * + * if (iosys_map_is_equal(&sys_map, &io_map)) + * // always false + * + * A set up instance of struct iosys_map can be used to access or manipulate the + * buffer memory. Depending on the location of the memory, the provided helpers + * will pick the correct operations. Data can be copied into the memory with + * iosys_map_memcpy_to(). The address can be manipulated with iosys_map_incr(). + * + * .. code-block:: c + * + * const void *src = ...; // source buffer + * size_t len = ...; // length of src + * + * iosys_map_memcpy_to(&map, src, len); + * iosys_map_incr(&map, len); // go to first byte after the memcpy + */ + +/** + * struct iosys_map - Pointer to IO/system memory + * @vaddr_iomem: The buffer's address if in I/O memory + * @vaddr: The buffer's address if in system memory + * @is_iomem: True if the buffer is located in I/O memory, or false + * otherwise. + */ +struct iosys_map { + union { + void __iomem *vaddr_iomem; + void *vaddr; + }; + bool is_iomem; +}; + +/** + * IOSYS_MAP_INIT_VADDR - Initializes struct iosys_map to an address in system memory + * @vaddr_: A system-memory address + */ +#define IOSYS_MAP_INIT_VADDR(vaddr_) \ + { \ + .vaddr = (vaddr_), \ + .is_iomem = false, \ + } + +/** + * iosys_map_set_vaddr - Sets a iosys mapping structure to an address in system memory + * @map: The iosys_map structure + * @vaddr: A system-memory address + * + * Sets the address and clears the I/O-memory flag. + */ +static inline void iosys_map_set_vaddr(struct iosys_map *map, void *vaddr) +{ + map->vaddr = vaddr; + map->is_iomem = false; +} + +/** + * iosys_map_set_vaddr_iomem - Sets a iosys mapping structure to an address in I/O memory + * @map: The iosys_map structure + * @vaddr_iomem: An I/O-memory address + * + * Sets the address and the I/O-memory flag. + */ +static inline void iosys_map_set_vaddr_iomem(struct iosys_map *map, + void __iomem *vaddr_iomem) +{ + map->vaddr_iomem = vaddr_iomem; + map->is_iomem = true; +} + +/** + * iosys_map_is_equal - Compares two iosys mapping structures for equality + * @lhs: The iosys_map structure + * @rhs: A iosys_map structure to compare with + * + * Two iosys mapping structures are equal if they both refer to the same type of memory + * and to the same address within that memory. + * + * Returns: + * True is both structures are equal, or false otherwise. + */ +static inline bool iosys_map_is_equal(const struct iosys_map *lhs, + const struct iosys_map *rhs) +{ + if (lhs->is_iomem != rhs->is_iomem) + return false; + else if (lhs->is_iomem) + return lhs->vaddr_iomem == rhs->vaddr_iomem; + else + return lhs->vaddr == rhs->vaddr; +} + +/** + * iosys_map_is_null - Tests for a iosys mapping to be NULL + * @map: The iosys_map structure + * + * Depending on the state of struct iosys_map.is_iomem, tests if the + * mapping is NULL. + * + * Returns: + * True if the mapping is NULL, or false otherwise. + */ +static inline bool iosys_map_is_null(const struct iosys_map *map) +{ + if (map->is_iomem) + return !map->vaddr_iomem; + return !map->vaddr; +} + +/** + * iosys_map_is_set - Tests if the iosys mapping has been set + * @map: The iosys_map structure + * + * Depending on the state of struct iosys_map.is_iomem, tests if the + * mapping has been set. + * + * Returns: + * True if the mapping is been set, or false otherwise. + */ +static inline bool iosys_map_is_set(const struct iosys_map *map) +{ + return !iosys_map_is_null(map); +} + +/** + * iosys_map_clear - Clears a iosys mapping structure + * @map: The iosys_map structure + * + * Clears all fields to zero, including struct iosys_map.is_iomem, so + * mapping structures that were set to point to I/O memory are reset for + * system memory. Pointers are cleared to NULL. This is the default. + */ +static inline void iosys_map_clear(struct iosys_map *map) +{ + if (map->is_iomem) { + map->vaddr_iomem = NULL; + map->is_iomem = false; + } else { + map->vaddr = NULL; + } +} + +/** + * iosys_map_memcpy_to - Memcpy into iosys mapping + * @dst: The iosys_map structure + * @src: The source buffer + * @len: The number of byte in src + * + * Copies data into a iosys mapping. The source buffer is in system + * memory. Depending on the buffer's location, the helper picks the correct + * method of accessing the memory. + */ +static inline void iosys_map_memcpy_to(struct iosys_map *dst, const void *src, + size_t len) +{ + if (dst->is_iomem) + memcpy_toio(dst->vaddr_iomem, src, len); + else + memcpy(dst->vaddr, src, len); +} + +/** + * iosys_map_incr - Increments the address stored in a iosys mapping + * @map: The iosys_map structure + * @incr: The number of bytes to increment + * + * Increments the address stored in a iosys mapping. Depending on the + * buffer's location, the correct value will be updated. + */ +static inline void iosys_map_incr(struct iosys_map *map, size_t incr) +{ + if (map->is_iomem) + map->vaddr_iomem += incr; + else + map->vaddr += incr; +} + +#endif /* __IOSYS_MAP_H__ */ -- cgit v1.2.3 From 1d38fe6ee6a874675ca3bba6b48e69a0e6176ffc Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 24 Feb 2022 16:47:43 -0600 Subject: PCI/VGA: Move vgaarb to drivers/pci The VGA arbiter is really PCI-specific and doesn't depend on any GPU things. Move it to the PCI subsystem. Note that misc_init() must be called before vga_arb_device_init(). These are both subsys_initcalls, so this ordering depends on the link order, which is determined by drivers/Makefile: obj-y += pci/ obj-y += char/ <-- misc_init() obj-y += gpu/ <-- vga_arb_device_init() (before this commit) The drivers/pci/ subsys_initcalls are called *before* misc_init(), so convert vga_arb_device_init() to subsys_initcall_sync(), which is called after *all* subsys_initcalls. Link: https://lore.kernel.org/r/20220224224753.297579-2-helgaas@kernel.org Signed-off-by: Bjorn Helgaas --- Documentation/gpu/vgaarbiter.rst | 2 +- drivers/gpu/vga/Kconfig | 19 - drivers/gpu/vga/Makefile | 1 - drivers/gpu/vga/vgaarb.c | 1567 -------------------------------------- drivers/pci/Kconfig | 19 + drivers/pci/Makefile | 1 + drivers/pci/vgaarb.c | 1567 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 1588 insertions(+), 1588 deletions(-) delete mode 100644 drivers/gpu/vga/vgaarb.c create mode 100644 drivers/pci/vgaarb.c (limited to 'Documentation/gpu') diff --git a/Documentation/gpu/vgaarbiter.rst b/Documentation/gpu/vgaarbiter.rst index 339ed5fecd2e..bde3c0afb059 100644 --- a/Documentation/gpu/vgaarbiter.rst +++ b/Documentation/gpu/vgaarbiter.rst @@ -100,7 +100,7 @@ In-kernel interface .. kernel-doc:: include/linux/vgaarb.h :internal: -.. kernel-doc:: drivers/gpu/vga/vgaarb.c +.. kernel-doc:: drivers/pci/vgaarb.c :export: libpciaccess diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig index 1ad4c4ef0b5e..eb8b14ab22c3 100644 --- a/drivers/gpu/vga/Kconfig +++ b/drivers/gpu/vga/Kconfig @@ -1,23 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -config VGA_ARB - bool "VGA Arbitration" if EXPERT - default y - depends on (PCI && !S390) - help - Some "legacy" VGA devices implemented on PCI typically have the same - hard-decoded addresses as they did on ISA. When multiple PCI devices - are accessed at same time they need some kind of coordination. Please - see Documentation/gpu/vgaarbiter.rst for more details. Select this to - enable VGA arbiter. - -config VGA_ARB_MAX_GPUS - int "Maximum number of GPUs" - default 16 - depends on VGA_ARB - help - Reserves space in the kernel to maintain resource locking for - multiple GPUS. The overhead for each GPU is very small. - config VGA_SWITCHEROO bool "Laptop Hybrid Graphics - GPU switching support" depends on X86 diff --git a/drivers/gpu/vga/Makefile b/drivers/gpu/vga/Makefile index e92064442d60..9800620deda3 100644 --- a/drivers/gpu/vga/Makefile +++ b/drivers/gpu/vga/Makefile @@ -1,3 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VGA_ARB) += vgaarb.o obj-$(CONFIG_VGA_SWITCHEROO) += vga_switcheroo.o diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c deleted file mode 100644 index 569930552957..000000000000 --- a/drivers/gpu/vga/vgaarb.c +++ /dev/null @@ -1,1567 +0,0 @@ -/* - * vgaarb.c: Implements the VGA arbitration. For details refer to - * Documentation/gpu/vgaarbiter.rst - * - * - * (C) Copyright 2005 Benjamin Herrenschmidt - * (C) Copyright 2007 Paulo R. Zanoni - * (C) Copyright 2007, 2009 Tiago Vignatti - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS - * IN THE SOFTWARE. - * - */ - -#define pr_fmt(fmt) "vgaarb: " fmt - -#define vgaarb_dbg(dev, fmt, arg...) dev_dbg(dev, "vgaarb: " fmt, ##arg) -#define vgaarb_info(dev, fmt, arg...) dev_info(dev, "vgaarb: " fmt, ##arg) -#define vgaarb_err(dev, fmt, arg...) dev_err(dev, "vgaarb: " fmt, ##arg) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -static void vga_arbiter_notify_clients(void); -/* - * We keep a list of all vga devices in the system to speed - * up the various operations of the arbiter - */ -struct vga_device { - struct list_head list; - struct pci_dev *pdev; - unsigned int decodes; /* what does it decodes */ - unsigned int owns; /* what does it owns */ - unsigned int locks; /* what does it locks */ - unsigned int io_lock_cnt; /* legacy IO lock count */ - unsigned int mem_lock_cnt; /* legacy MEM lock count */ - unsigned int io_norm_cnt; /* normal IO count */ - unsigned int mem_norm_cnt; /* normal MEM count */ - bool bridge_has_one_vga; - unsigned int (*set_decode)(struct pci_dev *pdev, bool decode); -}; - -static LIST_HEAD(vga_list); -static int vga_count, vga_decode_count; -static bool vga_arbiter_used; -static DEFINE_SPINLOCK(vga_lock); -static DECLARE_WAIT_QUEUE_HEAD(vga_wait_queue); - - -static const char *vga_iostate_to_str(unsigned int iostate) -{ - /* Ignore VGA_RSRC_IO and VGA_RSRC_MEM */ - iostate &= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; - switch (iostate) { - case VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM: - return "io+mem"; - case VGA_RSRC_LEGACY_IO: - return "io"; - case VGA_RSRC_LEGACY_MEM: - return "mem"; - } - return "none"; -} - -static int vga_str_to_iostate(char *buf, int str_size, int *io_state) -{ - /* we could in theory hand out locks on IO and mem - * separately to userspace but it can cause deadlocks */ - if (strncmp(buf, "none", 4) == 0) { - *io_state = VGA_RSRC_NONE; - return 1; - } - - /* XXX We're not chekcing the str_size! */ - if (strncmp(buf, "io+mem", 6) == 0) - goto both; - else if (strncmp(buf, "io", 2) == 0) - goto both; - else if (strncmp(buf, "mem", 3) == 0) - goto both; - return 0; -both: - *io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; - return 1; -} - -/* this is only used a cookie - it should not be dereferenced */ -static struct pci_dev *vga_default; - -static void vga_arb_device_card_gone(struct pci_dev *pdev); - -/* Find somebody in our list */ -static struct vga_device *vgadev_find(struct pci_dev *pdev) -{ - struct vga_device *vgadev; - - list_for_each_entry(vgadev, &vga_list, list) - if (pdev == vgadev->pdev) - return vgadev; - return NULL; -} - -/** - * vga_default_device - return the default VGA device, for vgacon - * - * This can be defined by the platform. The default implementation - * is rather dumb and will probably only work properly on single - * vga card setups and/or x86 platforms. - * - * If your VGA default device is not PCI, you'll have to return - * NULL here. In this case, I assume it will not conflict with - * any PCI card. If this is not true, I'll have to define two archs - * hooks for enabling/disabling the VGA default device if that is - * possible. This may be a problem with real _ISA_ VGA cards, in - * addition to a PCI one. I don't know at this point how to deal - * with that card. Can theirs IOs be disabled at all ? If not, then - * I suppose it's a matter of having the proper arch hook telling - * us about it, so we basically never allow anybody to succeed a - * vga_get()... - */ -struct pci_dev *vga_default_device(void) -{ - return vga_default; -} -EXPORT_SYMBOL_GPL(vga_default_device); - -void vga_set_default_device(struct pci_dev *pdev) -{ - if (vga_default == pdev) - return; - - pci_dev_put(vga_default); - vga_default = pci_dev_get(pdev); -} - -/** - * vga_remove_vgacon - deactivete vga console - * - * Unbind and unregister vgacon in case pdev is the default vga - * device. Can be called by gpu drivers on initialization to make - * sure vga register access done by vgacon will not disturb the - * device. - * - * @pdev: pci device. - */ -#if !defined(CONFIG_VGA_CONSOLE) -int vga_remove_vgacon(struct pci_dev *pdev) -{ - return 0; -} -#elif !defined(CONFIG_DUMMY_CONSOLE) -int vga_remove_vgacon(struct pci_dev *pdev) -{ - return -ENODEV; -} -#else -int vga_remove_vgacon(struct pci_dev *pdev) -{ - int ret = 0; - - if (pdev != vga_default) - return 0; - vgaarb_info(&pdev->dev, "deactivate vga console\n"); - - console_lock(); - if (con_is_bound(&vga_con)) - ret = do_take_over_console(&dummy_con, 0, - MAX_NR_CONSOLES - 1, 1); - if (ret == 0) { - ret = do_unregister_con_driver(&vga_con); - - /* Ignore "already unregistered". */ - if (ret == -ENODEV) - ret = 0; - } - console_unlock(); - - return ret; -} -#endif -EXPORT_SYMBOL(vga_remove_vgacon); - -/* If we don't ever use VGA arb we should avoid - turning off anything anywhere due to old X servers getting - confused about the boot device not being VGA */ -static void vga_check_first_use(void) -{ - /* we should inform all GPUs in the system that - * VGA arb has occurred and to try and disable resources - * if they can */ - if (!vga_arbiter_used) { - vga_arbiter_used = true; - vga_arbiter_notify_clients(); - } -} - -static struct vga_device *__vga_tryget(struct vga_device *vgadev, - unsigned int rsrc) -{ - struct device *dev = &vgadev->pdev->dev; - unsigned int wants, legacy_wants, match; - struct vga_device *conflict; - unsigned int pci_bits; - u32 flags = 0; - - /* Account for "normal" resources to lock. If we decode the legacy, - * counterpart, we need to request it as well - */ - if ((rsrc & VGA_RSRC_NORMAL_IO) && - (vgadev->decodes & VGA_RSRC_LEGACY_IO)) - rsrc |= VGA_RSRC_LEGACY_IO; - if ((rsrc & VGA_RSRC_NORMAL_MEM) && - (vgadev->decodes & VGA_RSRC_LEGACY_MEM)) - rsrc |= VGA_RSRC_LEGACY_MEM; - - vgaarb_dbg(dev, "%s: %d\n", __func__, rsrc); - vgaarb_dbg(dev, "%s: owns: %d\n", __func__, vgadev->owns); - - /* Check what resources we need to acquire */ - wants = rsrc & ~vgadev->owns; - - /* We already own everything, just mark locked & bye bye */ - if (wants == 0) - goto lock_them; - - /* We don't need to request a legacy resource, we just enable - * appropriate decoding and go - */ - legacy_wants = wants & VGA_RSRC_LEGACY_MASK; - if (legacy_wants == 0) - goto enable_them; - - /* Ok, we don't, let's find out how we need to kick off */ - list_for_each_entry(conflict, &vga_list, list) { - unsigned int lwants = legacy_wants; - unsigned int change_bridge = 0; - - /* Don't conflict with myself */ - if (vgadev == conflict) - continue; - - /* We have a possible conflict. before we go further, we must - * check if we sit on the same bus as the conflicting device. - * if we don't, then we must tie both IO and MEM resources - * together since there is only a single bit controlling - * VGA forwarding on P2P bridges - */ - if (vgadev->pdev->bus != conflict->pdev->bus) { - change_bridge = 1; - lwants = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; - } - - /* Check if the guy has a lock on the resource. If he does, - * return the conflicting entry - */ - if (conflict->locks & lwants) - return conflict; - - /* Ok, now check if it owns the resource we want. We can - * lock resources that are not decoded, therefore a device - * can own resources it doesn't decode. - */ - match = lwants & conflict->owns; - if (!match) - continue; - - /* looks like he doesn't have a lock, we can steal - * them from him - */ - - flags = 0; - pci_bits = 0; - - /* If we can't control legacy resources via the bridge, we - * also need to disable normal decoding. - */ - if (!conflict->bridge_has_one_vga) { - if ((match & conflict->decodes) & VGA_RSRC_LEGACY_MEM) - pci_bits |= PCI_COMMAND_MEMORY; - if ((match & conflict->decodes) & VGA_RSRC_LEGACY_IO) - pci_bits |= PCI_COMMAND_IO; - - if (pci_bits) - flags |= PCI_VGA_STATE_CHANGE_DECODES; - } - - if (change_bridge) - flags |= PCI_VGA_STATE_CHANGE_BRIDGE; - - pci_set_vga_state(conflict->pdev, false, pci_bits, flags); - conflict->owns &= ~match; - - /* If we disabled normal decoding, reflect it in owns */ - if (pci_bits & PCI_COMMAND_MEMORY) - conflict->owns &= ~VGA_RSRC_NORMAL_MEM; - if (pci_bits & PCI_COMMAND_IO) - conflict->owns &= ~VGA_RSRC_NORMAL_IO; - } - -enable_them: - /* ok dude, we got it, everybody conflicting has been disabled, let's - * enable us. Mark any bits in "owns" regardless of whether we - * decoded them. We can lock resources we don't decode, therefore - * we must track them via "owns". - */ - flags = 0; - pci_bits = 0; - - if (!vgadev->bridge_has_one_vga) { - flags |= PCI_VGA_STATE_CHANGE_DECODES; - if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM)) - pci_bits |= PCI_COMMAND_MEMORY; - if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO)) - pci_bits |= PCI_COMMAND_IO; - } - if (wants & VGA_RSRC_LEGACY_MASK) - flags |= PCI_VGA_STATE_CHANGE_BRIDGE; - - pci_set_vga_state(vgadev->pdev, true, pci_bits, flags); - - vgadev->owns |= wants; -lock_them: - vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK); - if (rsrc & VGA_RSRC_LEGACY_IO) - vgadev->io_lock_cnt++; - if (rsrc & VGA_RSRC_LEGACY_MEM) - vgadev->mem_lock_cnt++; - if (rsrc & VGA_RSRC_NORMAL_IO) - vgadev->io_norm_cnt++; - if (rsrc & VGA_RSRC_NORMAL_MEM) - vgadev->mem_norm_cnt++; - - return NULL; -} - -static void __vga_put(struct vga_device *vgadev, unsigned int rsrc) -{ - struct device *dev = &vgadev->pdev->dev; - unsigned int old_locks = vgadev->locks; - - vgaarb_dbg(dev, "%s\n", __func__); - - /* Update our counters, and account for equivalent legacy resources - * if we decode them - */ - if ((rsrc & VGA_RSRC_NORMAL_IO) && vgadev->io_norm_cnt > 0) { - vgadev->io_norm_cnt--; - if (vgadev->decodes & VGA_RSRC_LEGACY_IO) - rsrc |= VGA_RSRC_LEGACY_IO; - } - if ((rsrc & VGA_RSRC_NORMAL_MEM) && vgadev->mem_norm_cnt > 0) { - vgadev->mem_norm_cnt--; - if (vgadev->decodes & VGA_RSRC_LEGACY_MEM) - rsrc |= VGA_RSRC_LEGACY_MEM; - } - if ((rsrc & VGA_RSRC_LEGACY_IO) && vgadev->io_lock_cnt > 0) - vgadev->io_lock_cnt--; - if ((rsrc & VGA_RSRC_LEGACY_MEM) && vgadev->mem_lock_cnt > 0) - vgadev->mem_lock_cnt--; - - /* Just clear lock bits, we do lazy operations so we don't really - * have to bother about anything else at this point - */ - if (vgadev->io_lock_cnt == 0) - vgadev->locks &= ~VGA_RSRC_LEGACY_IO; - if (vgadev->mem_lock_cnt == 0) - vgadev->locks &= ~VGA_RSRC_LEGACY_MEM; - - /* Kick the wait queue in case somebody was waiting if we actually - * released something - */ - if (old_locks != vgadev->locks) - wake_up_all(&vga_wait_queue); -} - -/** - * vga_get - acquire & locks VGA resources - * @pdev: pci device of the VGA card or NULL for the system default - * @rsrc: bit mask of resources to acquire and lock - * @interruptible: blocking should be interruptible by signals ? - * - * This function acquires VGA resources for the given card and mark those - * resources locked. If the resource requested are "normal" (and not legacy) - * resources, the arbiter will first check whether the card is doing legacy - * decoding for that type of resource. If yes, the lock is "converted" into a - * legacy resource lock. - * - * The arbiter will first look for all VGA cards that might conflict and disable - * their IOs and/or Memory access, including VGA forwarding on P2P bridges if - * necessary, so that the requested resources can be used. Then, the card is - * marked as locking these resources and the IO and/or Memory accesses are - * enabled on the card (including VGA forwarding on parent P2P bridges if any). - * - * This function will block if some conflicting card is already locking one of - * the required resources (or any resource on a different bus segment, since P2P - * bridges don't differentiate VGA memory and IO afaik). You can indicate - * whether this blocking should be interruptible by a signal (for userland - * interface) or not. - * - * Must not be called at interrupt time or in atomic context. If the card - * already owns the resources, the function succeeds. Nested calls are - * supported (a per-resource counter is maintained) - * - * On success, release the VGA resource again with vga_put(). - * - * Returns: - * - * 0 on success, negative error code on failure. - */ -int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) -{ - struct vga_device *vgadev, *conflict; - unsigned long flags; - wait_queue_entry_t wait; - int rc = 0; - - vga_check_first_use(); - /* The one who calls us should check for this, but lets be sure... */ - if (pdev == NULL) - pdev = vga_default_device(); - if (pdev == NULL) - return 0; - - for (;;) { - spin_lock_irqsave(&vga_lock, flags); - vgadev = vgadev_find(pdev); - if (vgadev == NULL) { - spin_unlock_irqrestore(&vga_lock, flags); - rc = -ENODEV; - break; - } - conflict = __vga_tryget(vgadev, rsrc); - spin_unlock_irqrestore(&vga_lock, flags); - if (conflict == NULL) - break; - - - /* We have a conflict, we wait until somebody kicks the - * work queue. Currently we have one work queue that we - * kick each time some resources are released, but it would - * be fairly easy to have a per device one so that we only - * need to attach to the conflicting device - */ - init_waitqueue_entry(&wait, current); - add_wait_queue(&vga_wait_queue, &wait); - set_current_state(interruptible ? - TASK_INTERRUPTIBLE : - TASK_UNINTERRUPTIBLE); - if (interruptible && signal_pending(current)) { - __set_current_state(TASK_RUNNING); - remove_wait_queue(&vga_wait_queue, &wait); - rc = -ERESTARTSYS; - break; - } - schedule(); - remove_wait_queue(&vga_wait_queue, &wait); - } - return rc; -} -EXPORT_SYMBOL(vga_get); - -/** - * vga_tryget - try to acquire & lock legacy VGA resources - * @pdev: pci devivce of VGA card or NULL for system default - * @rsrc: bit mask of resources to acquire and lock - * - * This function performs the same operation as vga_get(), but will return an - * error (-EBUSY) instead of blocking if the resources are already locked by - * another card. It can be called in any context - * - * On success, release the VGA resource again with vga_put(). - * - * Returns: - * - * 0 on success, negative error code on failure. - */ -static int vga_tryget(struct pci_dev *pdev, unsigned int rsrc) -{ - struct vga_device *vgadev; - unsigned long flags; - int rc = 0; - - vga_check_first_use(); - - /* The one who calls us should check for this, but lets be sure... */ - if (pdev == NULL) - pdev = vga_default_device(); - if (pdev == NULL) - return 0; - spin_lock_irqsave(&vga_lock, flags); - vgadev = vgadev_find(pdev); - if (vgadev == NULL) { - rc = -ENODEV; - goto bail; - } - if (__vga_tryget(vgadev, rsrc)) - rc = -EBUSY; -bail: - spin_unlock_irqrestore(&vga_lock, flags); - return rc; -} - -/** - * vga_put - release lock on legacy VGA resources - * @pdev: pci device of VGA card or NULL for system default - * @rsrc: but mask of resource to release - * - * This fuction releases resources previously locked by vga_get() or - * vga_tryget(). The resources aren't disabled right away, so that a subsequence - * vga_get() on the same card will succeed immediately. Resources have a - * counter, so locks are only released if the counter reaches 0. - */ -void vga_put(struct pci_dev *pdev, unsigned int rsrc) -{ - struct vga_device *vgadev; - unsigned long flags; - - /* The one who calls us should check for this, but lets be sure... */ - if (pdev == NULL) - pdev = vga_default_device(); - if (pdev == NULL) - return; - spin_lock_irqsave(&vga_lock, flags); - vgadev = vgadev_find(pdev); - if (vgadev == NULL) - goto bail; - __vga_put(vgadev, rsrc); -bail: - spin_unlock_irqrestore(&vga_lock, flags); -} -EXPORT_SYMBOL(vga_put); - -/* - * Rules for using a bridge to control a VGA descendant decoding: if a bridge - * has only one VGA descendant then it can be used to control the VGA routing - * for that device. It should always use the bridge closest to the device to - * control it. If a bridge has a direct VGA descendant, but also have a sub- - * bridge VGA descendant then we cannot use that bridge to control the direct - * VGA descendant. So for every device we register, we need to iterate all - * its parent bridges so we can invalidate any devices using them properly. - */ -static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev) -{ - struct vga_device *same_bridge_vgadev; - struct pci_bus *new_bus, *bus; - struct pci_dev *new_bridge, *bridge; - - vgadev->bridge_has_one_vga = true; - - if (list_empty(&vga_list)) - return; - - /* okay iterate the new devices bridge hierarachy */ - new_bus = vgadev->pdev->bus; - while (new_bus) { - new_bridge = new_bus->self; - - /* go through list of devices already registered */ - list_for_each_entry(same_bridge_vgadev, &vga_list, list) { - bus = same_bridge_vgadev->pdev->bus; - bridge = bus->self; - - /* see if the share a bridge with this device */ - if (new_bridge == bridge) { - /* - * If their direct parent bridge is the same - * as any bridge of this device then it can't - * be used for that device. - */ - same_bridge_vgadev->bridge_has_one_vga = false; - } - - /* - * Now iterate the previous devices bridge hierarchy. - * If the new devices parent bridge is in the other - * devices hierarchy then we can't use it to control - * this device - */ - while (bus) { - bridge = bus->self; - - if (bridge && bridge == vgadev->pdev->bus->self) - vgadev->bridge_has_one_vga = false; - - bus = bus->parent; - } - } - new_bus = new_bus->parent; - } -} - -/* - * Currently, we assume that the "initial" setup of the system is - * not sane, that is we come up with conflicting devices and let - * the arbiter's client decides if devices decodes or not legacy - * things. - */ -static bool vga_arbiter_add_pci_device(struct pci_dev *pdev) -{ - struct vga_device *vgadev; - unsigned long flags; - struct pci_bus *bus; - struct pci_dev *bridge; - u16 cmd; - - /* Only deal with VGA class devices */ - if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) - return false; - - /* Allocate structure */ - vgadev = kzalloc(sizeof(struct vga_device), GFP_KERNEL); - if (vgadev == NULL) { - vgaarb_err(&pdev->dev, "failed to allocate VGA arbiter data\n"); - /* - * What to do on allocation failure ? For now, let's just do - * nothing, I'm not sure there is anything saner to be done. - */ - return false; - } - - /* Take lock & check for duplicates */ - spin_lock_irqsave(&vga_lock, flags); - if (vgadev_find(pdev) != NULL) { - BUG_ON(1); - goto fail; - } - vgadev->pdev = pdev; - - /* By default, assume we decode everything */ - vgadev->decodes = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | - VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; - - /* by default mark it as decoding */ - vga_decode_count++; - /* Mark that we "own" resources based on our enables, we will - * clear that below if the bridge isn't forwarding - */ - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - if (cmd & PCI_COMMAND_IO) - vgadev->owns |= VGA_RSRC_LEGACY_IO; - if (cmd & PCI_COMMAND_MEMORY) - vgadev->owns |= VGA_RSRC_LEGACY_MEM; - - /* Check if VGA cycles can get down to us */ - bus = pdev->bus; - while (bus) { - bridge = bus->self; - if (bridge) { - u16 l; - - pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &l); - if (!(l & PCI_BRIDGE_CTL_VGA)) { - vgadev->owns = 0; - break; - } - } - bus = bus->parent; - } - - /* Deal with VGA default device. Use first enabled one - * by default if arch doesn't have it's own hook - */ - if (vga_default == NULL && - ((vgadev->owns & VGA_RSRC_LEGACY_MASK) == VGA_RSRC_LEGACY_MASK)) { - vgaarb_info(&pdev->dev, "setting as boot VGA device\n"); - vga_set_default_device(pdev); - } - - vga_arbiter_check_bridge_sharing(vgadev); - - /* Add to the list */ - list_add_tail(&vgadev->list, &vga_list); - vga_count++; - vgaarb_info(&pdev->dev, "VGA device added: decodes=%s,owns=%s,locks=%s\n", - vga_iostate_to_str(vgadev->decodes), - vga_iostate_to_str(vgadev->owns), - vga_iostate_to_str(vgadev->locks)); - - spin_unlock_irqrestore(&vga_lock, flags); - return true; -fail: - spin_unlock_irqrestore(&vga_lock, flags); - kfree(vgadev); - return false; -} - -static bool vga_arbiter_del_pci_device(struct pci_dev *pdev) -{ - struct vga_device *vgadev; - unsigned long flags; - bool ret = true; - - spin_lock_irqsave(&vga_lock, flags); - vgadev = vgadev_find(pdev); - if (vgadev == NULL) { - ret = false; - goto bail; - } - - if (vga_default == pdev) - vga_set_default_device(NULL); - - if (vgadev->decodes & (VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM)) - vga_decode_count--; - - /* Remove entry from list */ - list_del(&vgadev->list); - vga_count--; - /* Notify userland driver that the device is gone so it discards - * it's copies of the pci_dev pointer - */ - vga_arb_device_card_gone(pdev); - - /* Wake up all possible waiters */ - wake_up_all(&vga_wait_queue); -bail: - spin_unlock_irqrestore(&vga_lock, flags); - kfree(vgadev); - return ret; -} - -/* this is called with the lock */ -static inline void vga_update_device_decodes(struct vga_device *vgadev, - int new_decodes) -{ - struct device *dev = &vgadev->pdev->dev; - int old_decodes, decodes_removed, decodes_unlocked; - - old_decodes = vgadev->decodes; - decodes_removed = ~new_decodes & old_decodes; - decodes_unlocked = vgadev->locks & decodes_removed; - vgadev->decodes = new_decodes; - - vgaarb_info(dev, "changed VGA decodes: olddecodes=%s,decodes=%s:owns=%s\n", - vga_iostate_to_str(old_decodes), - vga_iostate_to_str(vgadev->decodes), - vga_iostate_to_str(vgadev->owns)); - - /* if we removed locked decodes, lock count goes to zero, and release */ - if (decodes_unlocked) { - if (decodes_unlocked & VGA_RSRC_LEGACY_IO) - vgadev->io_lock_cnt = 0; - if (decodes_unlocked & VGA_RSRC_LEGACY_MEM) - vgadev->mem_lock_cnt = 0; - __vga_put(vgadev, decodes_unlocked); - } - - /* change decodes counter */ - if (old_decodes & VGA_RSRC_LEGACY_MASK && - !(new_decodes & VGA_RSRC_LEGACY_MASK)) - vga_decode_count--; - if (!(old_decodes & VGA_RSRC_LEGACY_MASK) && - new_decodes & VGA_RSRC_LEGACY_MASK) - vga_decode_count++; - vgaarb_dbg(dev, "decoding count now is: %d\n", vga_decode_count); -} - -static void __vga_set_legacy_decoding(struct pci_dev *pdev, - unsigned int decodes, - bool userspace) -{ - struct vga_device *vgadev; - unsigned long flags; - - decodes &= VGA_RSRC_LEGACY_MASK; - - spin_lock_irqsave(&vga_lock, flags); - vgadev = vgadev_find(pdev); - if (vgadev == NULL) - goto bail; - - /* don't let userspace futz with kernel driver decodes */ - if (userspace && vgadev->set_decode) - goto bail; - - /* update the device decodes + counter */ - vga_update_device_decodes(vgadev, decodes); - - /* XXX if somebody is going from "doesn't decode" to "decodes" state - * here, additional care must be taken as we may have pending owner - * ship of non-legacy region ... - */ -bail: - spin_unlock_irqrestore(&vga_lock, flags); -} - -/** - * vga_set_legacy_decoding - * @pdev: pci device of the VGA card - * @decodes: bit mask of what legacy regions the card decodes - * - * Indicates to the arbiter if the card decodes legacy VGA IOs, legacy VGA - * Memory, both, or none. All cards default to both, the card driver (fbdev for - * example) should tell the arbiter if it has disabled legacy decoding, so the - * card can be left out of the arbitration process (and can be safe to take - * interrupts at any time. - */ -void vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes) -{ - __vga_set_legacy_decoding(pdev, decodes, false); -} -EXPORT_SYMBOL(vga_set_legacy_decoding); - -/** - * vga_client_register - register or unregister a VGA arbitration client - * @pdev: pci device of the VGA client - * @set_decode: vga decode change callback - * - * Clients have two callback mechanisms they can use. - * - * @set_decode callback: If a client can disable its GPU VGA resource, it - * will get a callback from this to set the encode/decode state. - * - * Rationale: we cannot disable VGA decode resources unconditionally some single - * GPU laptops seem to require ACPI or BIOS access to the VGA registers to - * control things like backlights etc. Hopefully newer multi-GPU laptops do - * something saner, and desktops won't have any special ACPI for this. The - * driver will get a callback when VGA arbitration is first used by userspace - * since some older X servers have issues. - * - * This function does not check whether a client for @pdev has been registered - * already. - * - * To unregister just call vga_client_unregister(). - * - * Returns: 0 on success, -1 on failure - */ -int vga_client_register(struct pci_dev *pdev, - unsigned int (*set_decode)(struct pci_dev *pdev, bool decode)) -{ - int ret = -ENODEV; - struct vga_device *vgadev; - unsigned long flags; - - spin_lock_irqsave(&vga_lock, flags); - vgadev = vgadev_find(pdev); - if (!vgadev) - goto bail; - - vgadev->set_decode = set_decode; - ret = 0; - -bail: - spin_unlock_irqrestore(&vga_lock, flags); - return ret; - -} -EXPORT_SYMBOL(vga_client_register); - -/* - * Char driver implementation - * - * Semantics is: - * - * open : open user instance of the arbitrer. by default, it's - * attached to the default VGA device of the system. - * - * close : close user instance, release locks - * - * read : return a string indicating the status of the target. - * an IO state string is of the form {io,mem,io+mem,none}, - * mc and ic are respectively mem and io lock counts (for - * debugging/diagnostic only). "decodes" indicate what the - * card currently decodes, "owns" indicates what is currently - * enabled on it, and "locks" indicates what is locked by this - * card. If the card is unplugged, we get "invalid" then for - * card_ID and an -ENODEV error is returned for any command - * until a new card is targeted - * - * ",decodes=,owns=,locks= (ic,mc)" - * - * write : write a command to the arbiter. List of commands is: - * - * target : switch target to card (see below) - * lock : acquires locks on target ("none" is invalid io_state) - * trylock : non-blocking acquire locks on target - * unlock : release locks on target - * unlock all : release all locks on target held by this user - * decodes : set the legacy decoding attributes for the card - * - * poll : event if something change on any card (not just the target) - * - * card_ID is of the form "PCI:domain:bus:dev.fn". It can be set to "default" - * to go back to the system default card (TODO: not implemented yet). - * Currently, only PCI is supported as a prefix, but the userland API may - * support other bus types in the future, even if the current kernel - * implementation doesn't. - * - * Note about locks: - * - * The driver keeps track of which user has what locks on which card. It - * supports stacking, like the kernel one. This complexifies the implementation - * a bit, but makes the arbiter more tolerant to userspace problems and able - * to properly cleanup in all cases when a process dies. - * Currently, a max of 16 cards simultaneously can have locks issued from - * userspace for a given user (file descriptor instance) of the arbiter. - * - * If the device is hot-unplugged, there is a hook inside the module to notify - * they being added/removed in the system and automatically added/removed in - * the arbiter. - */ - -#define MAX_USER_CARDS CONFIG_VGA_ARB_MAX_GPUS -#define PCI_INVALID_CARD ((struct pci_dev *)-1UL) - -/* - * Each user has an array of these, tracking which cards have locks - */ -struct vga_arb_user_card { - struct pci_dev *pdev; - unsigned int mem_cnt; - unsigned int io_cnt; -}; - -struct vga_arb_private { - struct list_head list; - struct pci_dev *target; - struct vga_arb_user_card cards[MAX_USER_CARDS]; - spinlock_t lock; -}; - -static LIST_HEAD(vga_user_list); -static DEFINE_SPINLOCK(vga_user_lock); - - -/* - * This function gets a string in the format: "PCI:domain:bus:dev.fn" and - * returns the respective values. If the string is not in this format, - * it returns 0. - */ -static int vga_pci_str_to_vars(char *buf, int count, unsigned int *domain, - unsigned int *bus, unsigned int *devfn) -{ - int n; - unsigned int slot, func; - - - n = sscanf(buf, "PCI:%x:%x:%x.%x", domain, bus, &slot, &func); - if (n != 4) - return 0; - - *devfn = PCI_DEVFN(slot, func); - - return 1; -} - -static ssize_t vga_arb_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct vga_arb_private *priv = file->private_data; - struct vga_device *vgadev; - struct pci_dev *pdev; - unsigned long flags; - size_t len; - int rc; - char *lbuf; - - lbuf = kmalloc(1024, GFP_KERNEL); - if (lbuf == NULL) - return -ENOMEM; - - /* Shields against vga_arb_device_card_gone (pci_dev going - * away), and allows access to vga list - */ - spin_lock_irqsave(&vga_lock, flags); - - /* If we are targeting the default, use it */ - pdev = priv->target; - if (pdev == NULL || pdev == PCI_INVALID_CARD) { - spin_unlock_irqrestore(&vga_lock, flags); - len = sprintf(lbuf, "invalid"); - goto done; - } - - /* Find card vgadev structure */ - vgadev = vgadev_find(pdev); - if (vgadev == NULL) { - /* Wow, it's not in the list, that shouldn't happen, - * let's fix us up and return invalid card - */ - if (pdev == priv->target) - vga_arb_device_card_gone(pdev); - spin_unlock_irqrestore(&vga_lock, flags); - len = sprintf(lbuf, "invalid"); - goto done; - } - - /* Fill the buffer with infos */ - len = snprintf(lbuf, 1024, - "count:%d,PCI:%s,decodes=%s,owns=%s,locks=%s(%d:%d)\n", - vga_decode_count, pci_name(pdev), - vga_iostate_to_str(vgadev->decodes), - vga_iostate_to_str(vgadev->owns), - vga_iostate_to_str(vgadev->locks), - vgadev->io_lock_cnt, vgadev->mem_lock_cnt); - - spin_unlock_irqrestore(&vga_lock, flags); -done: - - /* Copy that to user */ - if (len > count) - len = count; - rc = copy_to_user(buf, lbuf, len); - kfree(lbuf); - if (rc) - return -EFAULT; - return len; -} - -/* - * TODO: To avoid parsing inside kernel and to improve the speed we may - * consider use ioctl here - */ -static ssize_t vga_arb_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct vga_arb_private *priv = file->private_data; - struct vga_arb_user_card *uc = NULL; - struct pci_dev *pdev; - - unsigned int io_state; - - char kbuf[64], *curr_pos; - size_t remaining = count; - - int ret_val; - int i; - - if (count >= sizeof(kbuf)) - return -EINVAL; - if (copy_from_user(kbuf, buf, count)) - return -EFAULT; - curr_pos = kbuf; - kbuf[count] = '\0'; /* Just to make sure... */ - - if (strncmp(curr_pos, "lock ", 5) == 0) { - curr_pos += 5; - remaining -= 5; - - pr_debug("client 0x%p called 'lock'\n", priv); - - if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { - ret_val = -EPROTO; - goto done; - } - if (io_state == VGA_RSRC_NONE) { - ret_val = -EPROTO; - goto done; - } - - pdev = priv->target; - if (priv->target == NULL) { - ret_val = -ENODEV; - goto done; - } - - vga_get_uninterruptible(pdev, io_state); - - /* Update the client's locks lists... */ - for (i = 0; i < MAX_USER_CARDS; i++) { - if (priv->cards[i].pdev == pdev) { - if (io_state & VGA_RSRC_LEGACY_IO) - priv->cards[i].io_cnt++; - if (io_state & VGA_RSRC_LEGACY_MEM) - priv->cards[i].mem_cnt++; - break; - } - } - - ret_val = count; - goto done; - } else if (strncmp(curr_pos, "unlock ", 7) == 0) { - curr_pos += 7; - remaining -= 7; - - pr_debug("client 0x%p called 'unlock'\n", priv); - - if (strncmp(curr_pos, "all", 3) == 0) - io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; - else { - if (!vga_str_to_iostate - (curr_pos, remaining, &io_state)) { - ret_val = -EPROTO; - goto done; - } - /* TODO: Add this? - if (io_state == VGA_RSRC_NONE) { - ret_val = -EPROTO; - goto done; - } - */ - } - - pdev = priv->target; - if (priv->target == NULL) { - ret_val = -ENODEV; - goto done; - } - for (i = 0; i < MAX_USER_CARDS; i++) { - if (priv->cards[i].pdev == pdev) - uc = &priv->cards[i]; - } - - if (!uc) { - ret_val = -EINVAL; - goto done; - } - - if (io_state & VGA_RSRC_LEGACY_IO && uc->io_cnt == 0) { - ret_val = -EINVAL; - goto done; - } - - if (io_state & VGA_RSRC_LEGACY_MEM && uc->mem_cnt == 0) { - ret_val = -EINVAL; - goto done; - } - - vga_put(pdev, io_state); - - if (io_state & VGA_RSRC_LEGACY_IO) - uc->io_cnt--; - if (io_state & VGA_RSRC_LEGACY_MEM) - uc->mem_cnt--; - - ret_val = count; - goto done; - } else if (strncmp(curr_pos, "trylock ", 8) == 0) { - curr_pos += 8; - remaining -= 8; - - pr_debug("client 0x%p called 'trylock'\n", priv); - - if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { - ret_val = -EPROTO; - goto done; - } - /* TODO: Add this? - if (io_state == VGA_RSRC_NONE) { - ret_val = -EPROTO; - goto done; - } - */ - - pdev = priv->target; - if (priv->target == NULL) { - ret_val = -ENODEV; - goto done; - } - - if (vga_tryget(pdev, io_state)) { - /* Update the client's locks lists... */ - for (i = 0; i < MAX_USER_CARDS; i++) { - if (priv->cards[i].pdev == pdev) { - if (io_state & VGA_RSRC_LEGACY_IO) - priv->cards[i].io_cnt++; - if (io_state & VGA_RSRC_LEGACY_MEM) - priv->cards[i].mem_cnt++; - break; - } - } - ret_val = count; - goto done; - } else { - ret_val = -EBUSY; - goto done; - } - - } else if (strncmp(curr_pos, "target ", 7) == 0) { - unsigned int domain, bus, devfn; - struct vga_device *vgadev; - - curr_pos += 7; - remaining -= 7; - pr_debug("client 0x%p called 'target'\n", priv); - /* if target is default */ - if (!strncmp(curr_pos, "default", 7)) - pdev = pci_dev_get(vga_default_device()); - else { - if (!vga_pci_str_to_vars(curr_pos, remaining, - &domain, &bus, &devfn)) { - ret_val = -EPROTO; - goto done; - } - pdev = pci_get_domain_bus_and_slot(domain, bus, devfn); - if (!pdev) { - pr_debug("invalid PCI address %04x:%02x:%02x.%x\n", - domain, bus, PCI_SLOT(devfn), - PCI_FUNC(devfn)); - ret_val = -ENODEV; - goto done; - } - - pr_debug("%s ==> %04x:%02x:%02x.%x pdev %p\n", curr_pos, - domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), - pdev); - } - - vgadev = vgadev_find(pdev); - pr_debug("vgadev %p\n", vgadev); - if (vgadev == NULL) { - if (pdev) { - vgaarb_dbg(&pdev->dev, "not a VGA device\n"); - pci_dev_put(pdev); - } - - ret_val = -ENODEV; - goto done; - } - - priv->target = pdev; - for (i = 0; i < MAX_USER_CARDS; i++) { - if (priv->cards[i].pdev == pdev) - break; - if (priv->cards[i].pdev == NULL) { - priv->cards[i].pdev = pdev; - priv->cards[i].io_cnt = 0; - priv->cards[i].mem_cnt = 0; - break; - } - } - if (i == MAX_USER_CARDS) { - vgaarb_dbg(&pdev->dev, "maximum user cards (%d) number reached, ignoring this one!\n", - MAX_USER_CARDS); - pci_dev_put(pdev); - /* XXX: which value to return? */ - ret_val = -ENOMEM; - goto done; - } - - ret_val = count; - pci_dev_put(pdev); - goto done; - - - } else if (strncmp(curr_pos, "decodes ", 8) == 0) { - curr_pos += 8; - remaining -= 8; - pr_debug("client 0x%p called 'decodes'\n", priv); - - if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { - ret_val = -EPROTO; - goto done; - } - pdev = priv->target; - if (priv->target == NULL) { - ret_val = -ENODEV; - goto done; - } - - __vga_set_legacy_decoding(pdev, io_state, true); - ret_val = count; - goto done; - } - /* If we got here, the message written is not part of the protocol! */ - return -EPROTO; - -done: - return ret_val; -} - -static __poll_t vga_arb_fpoll(struct file *file, poll_table *wait) -{ - pr_debug("%s\n", __func__); - - poll_wait(file, &vga_wait_queue, wait); - return EPOLLIN; -} - -static int vga_arb_open(struct inode *inode, struct file *file) -{ - struct vga_arb_private *priv; - unsigned long flags; - - pr_debug("%s\n", __func__); - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - spin_lock_init(&priv->lock); - file->private_data = priv; - - spin_lock_irqsave(&vga_user_lock, flags); - list_add(&priv->list, &vga_user_list); - spin_unlock_irqrestore(&vga_user_lock, flags); - - /* Set the client' lists of locks */ - priv->target = vga_default_device(); /* Maybe this is still null! */ - priv->cards[0].pdev = priv->target; - priv->cards[0].io_cnt = 0; - priv->cards[0].mem_cnt = 0; - - - return 0; -} - -static int vga_arb_release(struct inode *inode, struct file *file) -{ - struct vga_arb_private *priv = file->private_data; - struct vga_arb_user_card *uc; - unsigned long flags; - int i; - - pr_debug("%s\n", __func__); - - spin_lock_irqsave(&vga_user_lock, flags); - list_del(&priv->list); - for (i = 0; i < MAX_USER_CARDS; i++) { - uc = &priv->cards[i]; - if (uc->pdev == NULL) - continue; - vgaarb_dbg(&uc->pdev->dev, "uc->io_cnt == %d, uc->mem_cnt == %d\n", - uc->io_cnt, uc->mem_cnt); - while (uc->io_cnt--) - vga_put(uc->pdev, VGA_RSRC_LEGACY_IO); - while (uc->mem_cnt--) - vga_put(uc->pdev, VGA_RSRC_LEGACY_MEM); - } - spin_unlock_irqrestore(&vga_user_lock, flags); - - kfree(priv); - - return 0; -} - -static void vga_arb_device_card_gone(struct pci_dev *pdev) -{ -} - -/* - * callback any registered clients to let them know we have a - * change in VGA cards - */ -static void vga_arbiter_notify_clients(void) -{ - struct vga_device *vgadev; - unsigned long flags; - uint32_t new_decodes; - bool new_state; - - if (!vga_arbiter_used) - return; - - spin_lock_irqsave(&vga_lock, flags); - list_for_each_entry(vgadev, &vga_list, list) { - if (vga_count > 1) - new_state = false; - else - new_state = true; - if (vgadev->set_decode) { - new_decodes = vgadev->set_decode(vgadev->pdev, - new_state); - vga_update_device_decodes(vgadev, new_decodes); - } - } - spin_unlock_irqrestore(&vga_lock, flags); -} - -static int pci_notify(struct notifier_block *nb, unsigned long action, - void *data) -{ - struct device *dev = data; - struct pci_dev *pdev = to_pci_dev(dev); - bool notify = false; - - vgaarb_dbg(dev, "%s\n", __func__); - - /* For now we're only intereted in devices added and removed. I didn't - * test this thing here, so someone needs to double check for the - * cases of hotplugable vga cards. */ - if (action == BUS_NOTIFY_ADD_DEVICE) - notify = vga_arbiter_add_pci_device(pdev); - else if (action == BUS_NOTIFY_DEL_DEVICE) - notify = vga_arbiter_del_pci_device(pdev); - - if (notify) - vga_arbiter_notify_clients(); - return 0; -} - -static struct notifier_block pci_notifier = { - .notifier_call = pci_notify, -}; - -static const struct file_operations vga_arb_device_fops = { - .read = vga_arb_read, - .write = vga_arb_write, - .poll = vga_arb_fpoll, - .open = vga_arb_open, - .release = vga_arb_release, - .llseek = noop_llseek, -}; - -static struct miscdevice vga_arb_device = { - MISC_DYNAMIC_MINOR, "vga_arbiter", &vga_arb_device_fops -}; - -#if defined(CONFIG_ACPI) -static bool vga_arb_integrated_gpu(struct device *dev) -{ - struct acpi_device *adev = ACPI_COMPANION(dev); - - return adev && !strcmp(acpi_device_hid(adev), ACPI_VIDEO_HID); -} -#else -static bool vga_arb_integrated_gpu(struct device *dev) -{ - return false; -} -#endif - -static void __init vga_arb_select_default_device(void) -{ - struct pci_dev *pdev, *found = NULL; - struct vga_device *vgadev; - -#if defined(CONFIG_X86) || defined(CONFIG_IA64) - u64 base = screen_info.lfb_base; - u64 size = screen_info.lfb_size; - u64 limit; - resource_size_t start, end; - unsigned long flags; - int i; - - if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) - base |= (u64)screen_info.ext_lfb_base << 32; - - limit = base + size; - - list_for_each_entry(vgadev, &vga_list, list) { - struct device *dev = &vgadev->pdev->dev; - /* - * Override vga_arbiter_add_pci_device()'s I/O based detection - * as it may take the wrong device (e.g. on Apple system under - * EFI). - * - * Select the device owning the boot framebuffer if there is - * one. - */ - - /* Does firmware framebuffer belong to us? */ - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - flags = pci_resource_flags(vgadev->pdev, i); - - if ((flags & IORESOURCE_MEM) == 0) - continue; - - start = pci_resource_start(vgadev->pdev, i); - end = pci_resource_end(vgadev->pdev, i); - - if (!start || !end) - continue; - - if (base < start || limit >= end) - continue; - - if (!vga_default_device()) - vgaarb_info(dev, "setting as boot device\n"); - else if (vgadev->pdev != vga_default_device()) - vgaarb_info(dev, "overriding boot device\n"); - vga_set_default_device(vgadev->pdev); - } - } -#endif - - if (!vga_default_device()) { - list_for_each_entry_reverse(vgadev, &vga_list, list) { - struct device *dev = &vgadev->pdev->dev; - u16 cmd; - - pdev = vgadev->pdev; - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - if (cmd & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { - found = pdev; - if (vga_arb_integrated_gpu(dev)) - break; - } - } - } - - if (found) { - vgaarb_info(&found->dev, "setting as boot device (VGA legacy resources not available)\n"); - vga_set_default_device(found); - return; - } - - if (!vga_default_device()) { - vgadev = list_first_entry_or_null(&vga_list, - struct vga_device, list); - if (vgadev) { - struct device *dev = &vgadev->pdev->dev; - vgaarb_info(dev, "setting as boot device (VGA legacy resources not available)\n"); - vga_set_default_device(vgadev->pdev); - } - } -} - -static int __init vga_arb_device_init(void) -{ - int rc; - struct pci_dev *pdev; - struct vga_device *vgadev; - - rc = misc_register(&vga_arb_device); - if (rc < 0) - pr_err("error %d registering device\n", rc); - - bus_register_notifier(&pci_bus_type, &pci_notifier); - - /* We add all PCI devices satisfying VGA class in the arbiter by - * default */ - pdev = NULL; - while ((pdev = - pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, - PCI_ANY_ID, pdev)) != NULL) - vga_arbiter_add_pci_device(pdev); - - list_for_each_entry(vgadev, &vga_list, list) { - struct device *dev = &vgadev->pdev->dev; - - if (vgadev->bridge_has_one_vga) - vgaarb_info(dev, "bridge control possible\n"); - else - vgaarb_info(dev, "no bridge control possible\n"); - } - - vga_arb_select_default_device(); - - pr_info("loaded\n"); - return rc; -} -subsys_initcall(vga_arb_device_init); diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index d98fafdd0f99..133c73207782 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -252,6 +252,25 @@ config PCIE_BUS_PEER2PEER endchoice +config VGA_ARB + bool "VGA Arbitration" if EXPERT + default y + depends on (PCI && !S390) + help + Some "legacy" VGA devices implemented on PCI typically have the same + hard-decoded addresses as they did on ISA. When multiple PCI devices + are accessed at same time they need some kind of coordination. Please + see Documentation/gpu/vgaarbiter.rst for more details. Select this to + enable VGA arbiter. + +config VGA_ARB_MAX_GPUS + int "Maximum number of GPUs" + default 16 + depends on VGA_ARB + help + Reserves space in the kernel to maintain resource locking for + multiple GPUS. The overhead for each GPU is very small. + source "drivers/pci/hotplug/Kconfig" source "drivers/pci/controller/Kconfig" source "drivers/pci/endpoint/Kconfig" diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 37be95adf169..0da6b1ebc694 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_PCI_PF_STUB) += pci-pf-stub.o obj-$(CONFIG_PCI_ECAM) += ecam.o obj-$(CONFIG_PCI_P2PDMA) += p2pdma.o obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o +obj-$(CONFIG_VGA_ARB) += vgaarb.o # Endpoint library must be initialized before its users obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c new file mode 100644 index 000000000000..8320385a487b --- /dev/null +++ b/drivers/pci/vgaarb.c @@ -0,0 +1,1567 @@ +/* + * vgaarb.c: Implements the VGA arbitration. For details refer to + * Documentation/gpu/vgaarbiter.rst + * + * + * (C) Copyright 2005 Benjamin Herrenschmidt + * (C) Copyright 2007 Paulo R. Zanoni + * (C) Copyright 2007, 2009 Tiago Vignatti + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS + * IN THE SOFTWARE. + * + */ + +#define pr_fmt(fmt) "vgaarb: " fmt + +#define vgaarb_dbg(dev, fmt, arg...) dev_dbg(dev, "vgaarb: " fmt, ##arg) +#define vgaarb_info(dev, fmt, arg...) dev_info(dev, "vgaarb: " fmt, ##arg) +#define vgaarb_err(dev, fmt, arg...) dev_err(dev, "vgaarb: " fmt, ##arg) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +static void vga_arbiter_notify_clients(void); +/* + * We keep a list of all vga devices in the system to speed + * up the various operations of the arbiter + */ +struct vga_device { + struct list_head list; + struct pci_dev *pdev; + unsigned int decodes; /* what does it decodes */ + unsigned int owns; /* what does it owns */ + unsigned int locks; /* what does it locks */ + unsigned int io_lock_cnt; /* legacy IO lock count */ + unsigned int mem_lock_cnt; /* legacy MEM lock count */ + unsigned int io_norm_cnt; /* normal IO count */ + unsigned int mem_norm_cnt; /* normal MEM count */ + bool bridge_has_one_vga; + unsigned int (*set_decode)(struct pci_dev *pdev, bool decode); +}; + +static LIST_HEAD(vga_list); +static int vga_count, vga_decode_count; +static bool vga_arbiter_used; +static DEFINE_SPINLOCK(vga_lock); +static DECLARE_WAIT_QUEUE_HEAD(vga_wait_queue); + + +static const char *vga_iostate_to_str(unsigned int iostate) +{ + /* Ignore VGA_RSRC_IO and VGA_RSRC_MEM */ + iostate &= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; + switch (iostate) { + case VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM: + return "io+mem"; + case VGA_RSRC_LEGACY_IO: + return "io"; + case VGA_RSRC_LEGACY_MEM: + return "mem"; + } + return "none"; +} + +static int vga_str_to_iostate(char *buf, int str_size, int *io_state) +{ + /* we could in theory hand out locks on IO and mem + * separately to userspace but it can cause deadlocks */ + if (strncmp(buf, "none", 4) == 0) { + *io_state = VGA_RSRC_NONE; + return 1; + } + + /* XXX We're not chekcing the str_size! */ + if (strncmp(buf, "io+mem", 6) == 0) + goto both; + else if (strncmp(buf, "io", 2) == 0) + goto both; + else if (strncmp(buf, "mem", 3) == 0) + goto both; + return 0; +both: + *io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; + return 1; +} + +/* this is only used a cookie - it should not be dereferenced */ +static struct pci_dev *vga_default; + +static void vga_arb_device_card_gone(struct pci_dev *pdev); + +/* Find somebody in our list */ +static struct vga_device *vgadev_find(struct pci_dev *pdev) +{ + struct vga_device *vgadev; + + list_for_each_entry(vgadev, &vga_list, list) + if (pdev == vgadev->pdev) + return vgadev; + return NULL; +} + +/** + * vga_default_device - return the default VGA device, for vgacon + * + * This can be defined by the platform. The default implementation + * is rather dumb and will probably only work properly on single + * vga card setups and/or x86 platforms. + * + * If your VGA default device is not PCI, you'll have to return + * NULL here. In this case, I assume it will not conflict with + * any PCI card. If this is not true, I'll have to define two archs + * hooks for enabling/disabling the VGA default device if that is + * possible. This may be a problem with real _ISA_ VGA cards, in + * addition to a PCI one. I don't know at this point how to deal + * with that card. Can theirs IOs be disabled at all ? If not, then + * I suppose it's a matter of having the proper arch hook telling + * us about it, so we basically never allow anybody to succeed a + * vga_get()... + */ +struct pci_dev *vga_default_device(void) +{ + return vga_default; +} +EXPORT_SYMBOL_GPL(vga_default_device); + +void vga_set_default_device(struct pci_dev *pdev) +{ + if (vga_default == pdev) + return; + + pci_dev_put(vga_default); + vga_default = pci_dev_get(pdev); +} + +/** + * vga_remove_vgacon - deactivete vga console + * + * Unbind and unregister vgacon in case pdev is the default vga + * device. Can be called by gpu drivers on initialization to make + * sure vga register access done by vgacon will not disturb the + * device. + * + * @pdev: pci device. + */ +#if !defined(CONFIG_VGA_CONSOLE) +int vga_remove_vgacon(struct pci_dev *pdev) +{ + return 0; +} +#elif !defined(CONFIG_DUMMY_CONSOLE) +int vga_remove_vgacon(struct pci_dev *pdev) +{ + return -ENODEV; +} +#else +int vga_remove_vgacon(struct pci_dev *pdev) +{ + int ret = 0; + + if (pdev != vga_default) + return 0; + vgaarb_info(&pdev->dev, "deactivate vga console\n"); + + console_lock(); + if (con_is_bound(&vga_con)) + ret = do_take_over_console(&dummy_con, 0, + MAX_NR_CONSOLES - 1, 1); + if (ret == 0) { + ret = do_unregister_con_driver(&vga_con); + + /* Ignore "already unregistered". */ + if (ret == -ENODEV) + ret = 0; + } + console_unlock(); + + return ret; +} +#endif +EXPORT_SYMBOL(vga_remove_vgacon); + +/* If we don't ever use VGA arb we should avoid + turning off anything anywhere due to old X servers getting + confused about the boot device not being VGA */ +static void vga_check_first_use(void) +{ + /* we should inform all GPUs in the system that + * VGA arb has occurred and to try and disable resources + * if they can */ + if (!vga_arbiter_used) { + vga_arbiter_used = true; + vga_arbiter_notify_clients(); + } +} + +static struct vga_device *__vga_tryget(struct vga_device *vgadev, + unsigned int rsrc) +{ + struct device *dev = &vgadev->pdev->dev; + unsigned int wants, legacy_wants, match; + struct vga_device *conflict; + unsigned int pci_bits; + u32 flags = 0; + + /* Account for "normal" resources to lock. If we decode the legacy, + * counterpart, we need to request it as well + */ + if ((rsrc & VGA_RSRC_NORMAL_IO) && + (vgadev->decodes & VGA_RSRC_LEGACY_IO)) + rsrc |= VGA_RSRC_LEGACY_IO; + if ((rsrc & VGA_RSRC_NORMAL_MEM) && + (vgadev->decodes & VGA_RSRC_LEGACY_MEM)) + rsrc |= VGA_RSRC_LEGACY_MEM; + + vgaarb_dbg(dev, "%s: %d\n", __func__, rsrc); + vgaarb_dbg(dev, "%s: owns: %d\n", __func__, vgadev->owns); + + /* Check what resources we need to acquire */ + wants = rsrc & ~vgadev->owns; + + /* We already own everything, just mark locked & bye bye */ + if (wants == 0) + goto lock_them; + + /* We don't need to request a legacy resource, we just enable + * appropriate decoding and go + */ + legacy_wants = wants & VGA_RSRC_LEGACY_MASK; + if (legacy_wants == 0) + goto enable_them; + + /* Ok, we don't, let's find out how we need to kick off */ + list_for_each_entry(conflict, &vga_list, list) { + unsigned int lwants = legacy_wants; + unsigned int change_bridge = 0; + + /* Don't conflict with myself */ + if (vgadev == conflict) + continue; + + /* We have a possible conflict. before we go further, we must + * check if we sit on the same bus as the conflicting device. + * if we don't, then we must tie both IO and MEM resources + * together since there is only a single bit controlling + * VGA forwarding on P2P bridges + */ + if (vgadev->pdev->bus != conflict->pdev->bus) { + change_bridge = 1; + lwants = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; + } + + /* Check if the guy has a lock on the resource. If he does, + * return the conflicting entry + */ + if (conflict->locks & lwants) + return conflict; + + /* Ok, now check if it owns the resource we want. We can + * lock resources that are not decoded, therefore a device + * can own resources it doesn't decode. + */ + match = lwants & conflict->owns; + if (!match) + continue; + + /* looks like he doesn't have a lock, we can steal + * them from him + */ + + flags = 0; + pci_bits = 0; + + /* If we can't control legacy resources via the bridge, we + * also need to disable normal decoding. + */ + if (!conflict->bridge_has_one_vga) { + if ((match & conflict->decodes) & VGA_RSRC_LEGACY_MEM) + pci_bits |= PCI_COMMAND_MEMORY; + if ((match & conflict->decodes) & VGA_RSRC_LEGACY_IO) + pci_bits |= PCI_COMMAND_IO; + + if (pci_bits) + flags |= PCI_VGA_STATE_CHANGE_DECODES; + } + + if (change_bridge) + flags |= PCI_VGA_STATE_CHANGE_BRIDGE; + + pci_set_vga_state(conflict->pdev, false, pci_bits, flags); + conflict->owns &= ~match; + + /* If we disabled normal decoding, reflect it in owns */ + if (pci_bits & PCI_COMMAND_MEMORY) + conflict->owns &= ~VGA_RSRC_NORMAL_MEM; + if (pci_bits & PCI_COMMAND_IO) + conflict->owns &= ~VGA_RSRC_NORMAL_IO; + } + +enable_them: + /* ok dude, we got it, everybody conflicting has been disabled, let's + * enable us. Mark any bits in "owns" regardless of whether we + * decoded them. We can lock resources we don't decode, therefore + * we must track them via "owns". + */ + flags = 0; + pci_bits = 0; + + if (!vgadev->bridge_has_one_vga) { + flags |= PCI_VGA_STATE_CHANGE_DECODES; + if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM)) + pci_bits |= PCI_COMMAND_MEMORY; + if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO)) + pci_bits |= PCI_COMMAND_IO; + } + if (wants & VGA_RSRC_LEGACY_MASK) + flags |= PCI_VGA_STATE_CHANGE_BRIDGE; + + pci_set_vga_state(vgadev->pdev, true, pci_bits, flags); + + vgadev->owns |= wants; +lock_them: + vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK); + if (rsrc & VGA_RSRC_LEGACY_IO) + vgadev->io_lock_cnt++; + if (rsrc & VGA_RSRC_LEGACY_MEM) + vgadev->mem_lock_cnt++; + if (rsrc & VGA_RSRC_NORMAL_IO) + vgadev->io_norm_cnt++; + if (rsrc & VGA_RSRC_NORMAL_MEM) + vgadev->mem_norm_cnt++; + + return NULL; +} + +static void __vga_put(struct vga_device *vgadev, unsigned int rsrc) +{ + struct device *dev = &vgadev->pdev->dev; + unsigned int old_locks = vgadev->locks; + + vgaarb_dbg(dev, "%s\n", __func__); + + /* Update our counters, and account for equivalent legacy resources + * if we decode them + */ + if ((rsrc & VGA_RSRC_NORMAL_IO) && vgadev->io_norm_cnt > 0) { + vgadev->io_norm_cnt--; + if (vgadev->decodes & VGA_RSRC_LEGACY_IO) + rsrc |= VGA_RSRC_LEGACY_IO; + } + if ((rsrc & VGA_RSRC_NORMAL_MEM) && vgadev->mem_norm_cnt > 0) { + vgadev->mem_norm_cnt--; + if (vgadev->decodes & VGA_RSRC_LEGACY_MEM) + rsrc |= VGA_RSRC_LEGACY_MEM; + } + if ((rsrc & VGA_RSRC_LEGACY_IO) && vgadev->io_lock_cnt > 0) + vgadev->io_lock_cnt--; + if ((rsrc & VGA_RSRC_LEGACY_MEM) && vgadev->mem_lock_cnt > 0) + vgadev->mem_lock_cnt--; + + /* Just clear lock bits, we do lazy operations so we don't really + * have to bother about anything else at this point + */ + if (vgadev->io_lock_cnt == 0) + vgadev->locks &= ~VGA_RSRC_LEGACY_IO; + if (vgadev->mem_lock_cnt == 0) + vgadev->locks &= ~VGA_RSRC_LEGACY_MEM; + + /* Kick the wait queue in case somebody was waiting if we actually + * released something + */ + if (old_locks != vgadev->locks) + wake_up_all(&vga_wait_queue); +} + +/** + * vga_get - acquire & locks VGA resources + * @pdev: pci device of the VGA card or NULL for the system default + * @rsrc: bit mask of resources to acquire and lock + * @interruptible: blocking should be interruptible by signals ? + * + * This function acquires VGA resources for the given card and mark those + * resources locked. If the resource requested are "normal" (and not legacy) + * resources, the arbiter will first check whether the card is doing legacy + * decoding for that type of resource. If yes, the lock is "converted" into a + * legacy resource lock. + * + * The arbiter will first look for all VGA cards that might conflict and disable + * their IOs and/or Memory access, including VGA forwarding on P2P bridges if + * necessary, so that the requested resources can be used. Then, the card is + * marked as locking these resources and the IO and/or Memory accesses are + * enabled on the card (including VGA forwarding on parent P2P bridges if any). + * + * This function will block if some conflicting card is already locking one of + * the required resources (or any resource on a different bus segment, since P2P + * bridges don't differentiate VGA memory and IO afaik). You can indicate + * whether this blocking should be interruptible by a signal (for userland + * interface) or not. + * + * Must not be called at interrupt time or in atomic context. If the card + * already owns the resources, the function succeeds. Nested calls are + * supported (a per-resource counter is maintained) + * + * On success, release the VGA resource again with vga_put(). + * + * Returns: + * + * 0 on success, negative error code on failure. + */ +int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) +{ + struct vga_device *vgadev, *conflict; + unsigned long flags; + wait_queue_entry_t wait; + int rc = 0; + + vga_check_first_use(); + /* The one who calls us should check for this, but lets be sure... */ + if (pdev == NULL) + pdev = vga_default_device(); + if (pdev == NULL) + return 0; + + for (;;) { + spin_lock_irqsave(&vga_lock, flags); + vgadev = vgadev_find(pdev); + if (vgadev == NULL) { + spin_unlock_irqrestore(&vga_lock, flags); + rc = -ENODEV; + break; + } + conflict = __vga_tryget(vgadev, rsrc); + spin_unlock_irqrestore(&vga_lock, flags); + if (conflict == NULL) + break; + + + /* We have a conflict, we wait until somebody kicks the + * work queue. Currently we have one work queue that we + * kick each time some resources are released, but it would + * be fairly easy to have a per device one so that we only + * need to attach to the conflicting device + */ + init_waitqueue_entry(&wait, current); + add_wait_queue(&vga_wait_queue, &wait); + set_current_state(interruptible ? + TASK_INTERRUPTIBLE : + TASK_UNINTERRUPTIBLE); + if (interruptible && signal_pending(current)) { + __set_current_state(TASK_RUNNING); + remove_wait_queue(&vga_wait_queue, &wait); + rc = -ERESTARTSYS; + break; + } + schedule(); + remove_wait_queue(&vga_wait_queue, &wait); + } + return rc; +} +EXPORT_SYMBOL(vga_get); + +/** + * vga_tryget - try to acquire & lock legacy VGA resources + * @pdev: pci devivce of VGA card or NULL for system default + * @rsrc: bit mask of resources to acquire and lock + * + * This function performs the same operation as vga_get(), but will return an + * error (-EBUSY) instead of blocking if the resources are already locked by + * another card. It can be called in any context + * + * On success, release the VGA resource again with vga_put(). + * + * Returns: + * + * 0 on success, negative error code on failure. + */ +static int vga_tryget(struct pci_dev *pdev, unsigned int rsrc) +{ + struct vga_device *vgadev; + unsigned long flags; + int rc = 0; + + vga_check_first_use(); + + /* The one who calls us should check for this, but lets be sure... */ + if (pdev == NULL) + pdev = vga_default_device(); + if (pdev == NULL) + return 0; + spin_lock_irqsave(&vga_lock, flags); + vgadev = vgadev_find(pdev); + if (vgadev == NULL) { + rc = -ENODEV; + goto bail; + } + if (__vga_tryget(vgadev, rsrc)) + rc = -EBUSY; +bail: + spin_unlock_irqrestore(&vga_lock, flags); + return rc; +} + +/** + * vga_put - release lock on legacy VGA resources + * @pdev: pci device of VGA card or NULL for system default + * @rsrc: but mask of resource to release + * + * This fuction releases resources previously locked by vga_get() or + * vga_tryget(). The resources aren't disabled right away, so that a subsequence + * vga_get() on the same card will succeed immediately. Resources have a + * counter, so locks are only released if the counter reaches 0. + */ +void vga_put(struct pci_dev *pdev, unsigned int rsrc) +{ + struct vga_device *vgadev; + unsigned long flags; + + /* The one who calls us should check for this, but lets be sure... */ + if (pdev == NULL) + pdev = vga_default_device(); + if (pdev == NULL) + return; + spin_lock_irqsave(&vga_lock, flags); + vgadev = vgadev_find(pdev); + if (vgadev == NULL) + goto bail; + __vga_put(vgadev, rsrc); +bail: + spin_unlock_irqrestore(&vga_lock, flags); +} +EXPORT_SYMBOL(vga_put); + +/* + * Rules for using a bridge to control a VGA descendant decoding: if a bridge + * has only one VGA descendant then it can be used to control the VGA routing + * for that device. It should always use the bridge closest to the device to + * control it. If a bridge has a direct VGA descendant, but also have a sub- + * bridge VGA descendant then we cannot use that bridge to control the direct + * VGA descendant. So for every device we register, we need to iterate all + * its parent bridges so we can invalidate any devices using them properly. + */ +static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev) +{ + struct vga_device *same_bridge_vgadev; + struct pci_bus *new_bus, *bus; + struct pci_dev *new_bridge, *bridge; + + vgadev->bridge_has_one_vga = true; + + if (list_empty(&vga_list)) + return; + + /* okay iterate the new devices bridge hierarachy */ + new_bus = vgadev->pdev->bus; + while (new_bus) { + new_bridge = new_bus->self; + + /* go through list of devices already registered */ + list_for_each_entry(same_bridge_vgadev, &vga_list, list) { + bus = same_bridge_vgadev->pdev->bus; + bridge = bus->self; + + /* see if the share a bridge with this device */ + if (new_bridge == bridge) { + /* + * If their direct parent bridge is the same + * as any bridge of this device then it can't + * be used for that device. + */ + same_bridge_vgadev->bridge_has_one_vga = false; + } + + /* + * Now iterate the previous devices bridge hierarchy. + * If the new devices parent bridge is in the other + * devices hierarchy then we can't use it to control + * this device + */ + while (bus) { + bridge = bus->self; + + if (bridge && bridge == vgadev->pdev->bus->self) + vgadev->bridge_has_one_vga = false; + + bus = bus->parent; + } + } + new_bus = new_bus->parent; + } +} + +/* + * Currently, we assume that the "initial" setup of the system is + * not sane, that is we come up with conflicting devices and let + * the arbiter's client decides if devices decodes or not legacy + * things. + */ +static bool vga_arbiter_add_pci_device(struct pci_dev *pdev) +{ + struct vga_device *vgadev; + unsigned long flags; + struct pci_bus *bus; + struct pci_dev *bridge; + u16 cmd; + + /* Only deal with VGA class devices */ + if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) + return false; + + /* Allocate structure */ + vgadev = kzalloc(sizeof(struct vga_device), GFP_KERNEL); + if (vgadev == NULL) { + vgaarb_err(&pdev->dev, "failed to allocate VGA arbiter data\n"); + /* + * What to do on allocation failure ? For now, let's just do + * nothing, I'm not sure there is anything saner to be done. + */ + return false; + } + + /* Take lock & check for duplicates */ + spin_lock_irqsave(&vga_lock, flags); + if (vgadev_find(pdev) != NULL) { + BUG_ON(1); + goto fail; + } + vgadev->pdev = pdev; + + /* By default, assume we decode everything */ + vgadev->decodes = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | + VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; + + /* by default mark it as decoding */ + vga_decode_count++; + /* Mark that we "own" resources based on our enables, we will + * clear that below if the bridge isn't forwarding + */ + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if (cmd & PCI_COMMAND_IO) + vgadev->owns |= VGA_RSRC_LEGACY_IO; + if (cmd & PCI_COMMAND_MEMORY) + vgadev->owns |= VGA_RSRC_LEGACY_MEM; + + /* Check if VGA cycles can get down to us */ + bus = pdev->bus; + while (bus) { + bridge = bus->self; + if (bridge) { + u16 l; + + pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &l); + if (!(l & PCI_BRIDGE_CTL_VGA)) { + vgadev->owns = 0; + break; + } + } + bus = bus->parent; + } + + /* Deal with VGA default device. Use first enabled one + * by default if arch doesn't have it's own hook + */ + if (vga_default == NULL && + ((vgadev->owns & VGA_RSRC_LEGACY_MASK) == VGA_RSRC_LEGACY_MASK)) { + vgaarb_info(&pdev->dev, "setting as boot VGA device\n"); + vga_set_default_device(pdev); + } + + vga_arbiter_check_bridge_sharing(vgadev); + + /* Add to the list */ + list_add_tail(&vgadev->list, &vga_list); + vga_count++; + vgaarb_info(&pdev->dev, "VGA device added: decodes=%s,owns=%s,locks=%s\n", + vga_iostate_to_str(vgadev->decodes), + vga_iostate_to_str(vgadev->owns), + vga_iostate_to_str(vgadev->locks)); + + spin_unlock_irqrestore(&vga_lock, flags); + return true; +fail: + spin_unlock_irqrestore(&vga_lock, flags); + kfree(vgadev); + return false; +} + +static bool vga_arbiter_del_pci_device(struct pci_dev *pdev) +{ + struct vga_device *vgadev; + unsigned long flags; + bool ret = true; + + spin_lock_irqsave(&vga_lock, flags); + vgadev = vgadev_find(pdev); + if (vgadev == NULL) { + ret = false; + goto bail; + } + + if (vga_default == pdev) + vga_set_default_device(NULL); + + if (vgadev->decodes & (VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM)) + vga_decode_count--; + + /* Remove entry from list */ + list_del(&vgadev->list); + vga_count--; + /* Notify userland driver that the device is gone so it discards + * it's copies of the pci_dev pointer + */ + vga_arb_device_card_gone(pdev); + + /* Wake up all possible waiters */ + wake_up_all(&vga_wait_queue); +bail: + spin_unlock_irqrestore(&vga_lock, flags); + kfree(vgadev); + return ret; +} + +/* this is called with the lock */ +static inline void vga_update_device_decodes(struct vga_device *vgadev, + int new_decodes) +{ + struct device *dev = &vgadev->pdev->dev; + int old_decodes, decodes_removed, decodes_unlocked; + + old_decodes = vgadev->decodes; + decodes_removed = ~new_decodes & old_decodes; + decodes_unlocked = vgadev->locks & decodes_removed; + vgadev->decodes = new_decodes; + + vgaarb_info(dev, "changed VGA decodes: olddecodes=%s,decodes=%s:owns=%s\n", + vga_iostate_to_str(old_decodes), + vga_iostate_to_str(vgadev->decodes), + vga_iostate_to_str(vgadev->owns)); + + /* if we removed locked decodes, lock count goes to zero, and release */ + if (decodes_unlocked) { + if (decodes_unlocked & VGA_RSRC_LEGACY_IO) + vgadev->io_lock_cnt = 0; + if (decodes_unlocked & VGA_RSRC_LEGACY_MEM) + vgadev->mem_lock_cnt = 0; + __vga_put(vgadev, decodes_unlocked); + } + + /* change decodes counter */ + if (old_decodes & VGA_RSRC_LEGACY_MASK && + !(new_decodes & VGA_RSRC_LEGACY_MASK)) + vga_decode_count--; + if (!(old_decodes & VGA_RSRC_LEGACY_MASK) && + new_decodes & VGA_RSRC_LEGACY_MASK) + vga_decode_count++; + vgaarb_dbg(dev, "decoding count now is: %d\n", vga_decode_count); +} + +static void __vga_set_legacy_decoding(struct pci_dev *pdev, + unsigned int decodes, + bool userspace) +{ + struct vga_device *vgadev; + unsigned long flags; + + decodes &= VGA_RSRC_LEGACY_MASK; + + spin_lock_irqsave(&vga_lock, flags); + vgadev = vgadev_find(pdev); + if (vgadev == NULL) + goto bail; + + /* don't let userspace futz with kernel driver decodes */ + if (userspace && vgadev->set_decode) + goto bail; + + /* update the device decodes + counter */ + vga_update_device_decodes(vgadev, decodes); + + /* XXX if somebody is going from "doesn't decode" to "decodes" state + * here, additional care must be taken as we may have pending owner + * ship of non-legacy region ... + */ +bail: + spin_unlock_irqrestore(&vga_lock, flags); +} + +/** + * vga_set_legacy_decoding + * @pdev: pci device of the VGA card + * @decodes: bit mask of what legacy regions the card decodes + * + * Indicates to the arbiter if the card decodes legacy VGA IOs, legacy VGA + * Memory, both, or none. All cards default to both, the card driver (fbdev for + * example) should tell the arbiter if it has disabled legacy decoding, so the + * card can be left out of the arbitration process (and can be safe to take + * interrupts at any time. + */ +void vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes) +{ + __vga_set_legacy_decoding(pdev, decodes, false); +} +EXPORT_SYMBOL(vga_set_legacy_decoding); + +/** + * vga_client_register - register or unregister a VGA arbitration client + * @pdev: pci device of the VGA client + * @set_decode: vga decode change callback + * + * Clients have two callback mechanisms they can use. + * + * @set_decode callback: If a client can disable its GPU VGA resource, it + * will get a callback from this to set the encode/decode state. + * + * Rationale: we cannot disable VGA decode resources unconditionally some single + * GPU laptops seem to require ACPI or BIOS access to the VGA registers to + * control things like backlights etc. Hopefully newer multi-GPU laptops do + * something saner, and desktops won't have any special ACPI for this. The + * driver will get a callback when VGA arbitration is first used by userspace + * since some older X servers have issues. + * + * This function does not check whether a client for @pdev has been registered + * already. + * + * To unregister just call vga_client_unregister(). + * + * Returns: 0 on success, -1 on failure + */ +int vga_client_register(struct pci_dev *pdev, + unsigned int (*set_decode)(struct pci_dev *pdev, bool decode)) +{ + int ret = -ENODEV; + struct vga_device *vgadev; + unsigned long flags; + + spin_lock_irqsave(&vga_lock, flags); + vgadev = vgadev_find(pdev); + if (!vgadev) + goto bail; + + vgadev->set_decode = set_decode; + ret = 0; + +bail: + spin_unlock_irqrestore(&vga_lock, flags); + return ret; + +} +EXPORT_SYMBOL(vga_client_register); + +/* + * Char driver implementation + * + * Semantics is: + * + * open : open user instance of the arbitrer. by default, it's + * attached to the default VGA device of the system. + * + * close : close user instance, release locks + * + * read : return a string indicating the status of the target. + * an IO state string is of the form {io,mem,io+mem,none}, + * mc and ic are respectively mem and io lock counts (for + * debugging/diagnostic only). "decodes" indicate what the + * card currently decodes, "owns" indicates what is currently + * enabled on it, and "locks" indicates what is locked by this + * card. If the card is unplugged, we get "invalid" then for + * card_ID and an -ENODEV error is returned for any command + * until a new card is targeted + * + * ",decodes=,owns=,locks= (ic,mc)" + * + * write : write a command to the arbiter. List of commands is: + * + * target : switch target to card (see below) + * lock : acquires locks on target ("none" is invalid io_state) + * trylock : non-blocking acquire locks on target + * unlock : release locks on target + * unlock all : release all locks on target held by this user + * decodes : set the legacy decoding attributes for the card + * + * poll : event if something change on any card (not just the target) + * + * card_ID is of the form "PCI:domain:bus:dev.fn". It can be set to "default" + * to go back to the system default card (TODO: not implemented yet). + * Currently, only PCI is supported as a prefix, but the userland API may + * support other bus types in the future, even if the current kernel + * implementation doesn't. + * + * Note about locks: + * + * The driver keeps track of which user has what locks on which card. It + * supports stacking, like the kernel one. This complexifies the implementation + * a bit, but makes the arbiter more tolerant to userspace problems and able + * to properly cleanup in all cases when a process dies. + * Currently, a max of 16 cards simultaneously can have locks issued from + * userspace for a given user (file descriptor instance) of the arbiter. + * + * If the device is hot-unplugged, there is a hook inside the module to notify + * they being added/removed in the system and automatically added/removed in + * the arbiter. + */ + +#define MAX_USER_CARDS CONFIG_VGA_ARB_MAX_GPUS +#define PCI_INVALID_CARD ((struct pci_dev *)-1UL) + +/* + * Each user has an array of these, tracking which cards have locks + */ +struct vga_arb_user_card { + struct pci_dev *pdev; + unsigned int mem_cnt; + unsigned int io_cnt; +}; + +struct vga_arb_private { + struct list_head list; + struct pci_dev *target; + struct vga_arb_user_card cards[MAX_USER_CARDS]; + spinlock_t lock; +}; + +static LIST_HEAD(vga_user_list); +static DEFINE_SPINLOCK(vga_user_lock); + + +/* + * This function gets a string in the format: "PCI:domain:bus:dev.fn" and + * returns the respective values. If the string is not in this format, + * it returns 0. + */ +static int vga_pci_str_to_vars(char *buf, int count, unsigned int *domain, + unsigned int *bus, unsigned int *devfn) +{ + int n; + unsigned int slot, func; + + + n = sscanf(buf, "PCI:%x:%x:%x.%x", domain, bus, &slot, &func); + if (n != 4) + return 0; + + *devfn = PCI_DEVFN(slot, func); + + return 1; +} + +static ssize_t vga_arb_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct vga_arb_private *priv = file->private_data; + struct vga_device *vgadev; + struct pci_dev *pdev; + unsigned long flags; + size_t len; + int rc; + char *lbuf; + + lbuf = kmalloc(1024, GFP_KERNEL); + if (lbuf == NULL) + return -ENOMEM; + + /* Shields against vga_arb_device_card_gone (pci_dev going + * away), and allows access to vga list + */ + spin_lock_irqsave(&vga_lock, flags); + + /* If we are targeting the default, use it */ + pdev = priv->target; + if (pdev == NULL || pdev == PCI_INVALID_CARD) { + spin_unlock_irqrestore(&vga_lock, flags); + len = sprintf(lbuf, "invalid"); + goto done; + } + + /* Find card vgadev structure */ + vgadev = vgadev_find(pdev); + if (vgadev == NULL) { + /* Wow, it's not in the list, that shouldn't happen, + * let's fix us up and return invalid card + */ + if (pdev == priv->target) + vga_arb_device_card_gone(pdev); + spin_unlock_irqrestore(&vga_lock, flags); + len = sprintf(lbuf, "invalid"); + goto done; + } + + /* Fill the buffer with infos */ + len = snprintf(lbuf, 1024, + "count:%d,PCI:%s,decodes=%s,owns=%s,locks=%s(%d:%d)\n", + vga_decode_count, pci_name(pdev), + vga_iostate_to_str(vgadev->decodes), + vga_iostate_to_str(vgadev->owns), + vga_iostate_to_str(vgadev->locks), + vgadev->io_lock_cnt, vgadev->mem_lock_cnt); + + spin_unlock_irqrestore(&vga_lock, flags); +done: + + /* Copy that to user */ + if (len > count) + len = count; + rc = copy_to_user(buf, lbuf, len); + kfree(lbuf); + if (rc) + return -EFAULT; + return len; +} + +/* + * TODO: To avoid parsing inside kernel and to improve the speed we may + * consider use ioctl here + */ +static ssize_t vga_arb_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct vga_arb_private *priv = file->private_data; + struct vga_arb_user_card *uc = NULL; + struct pci_dev *pdev; + + unsigned int io_state; + + char kbuf[64], *curr_pos; + size_t remaining = count; + + int ret_val; + int i; + + if (count >= sizeof(kbuf)) + return -EINVAL; + if (copy_from_user(kbuf, buf, count)) + return -EFAULT; + curr_pos = kbuf; + kbuf[count] = '\0'; /* Just to make sure... */ + + if (strncmp(curr_pos, "lock ", 5) == 0) { + curr_pos += 5; + remaining -= 5; + + pr_debug("client 0x%p called 'lock'\n", priv); + + if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { + ret_val = -EPROTO; + goto done; + } + if (io_state == VGA_RSRC_NONE) { + ret_val = -EPROTO; + goto done; + } + + pdev = priv->target; + if (priv->target == NULL) { + ret_val = -ENODEV; + goto done; + } + + vga_get_uninterruptible(pdev, io_state); + + /* Update the client's locks lists... */ + for (i = 0; i < MAX_USER_CARDS; i++) { + if (priv->cards[i].pdev == pdev) { + if (io_state & VGA_RSRC_LEGACY_IO) + priv->cards[i].io_cnt++; + if (io_state & VGA_RSRC_LEGACY_MEM) + priv->cards[i].mem_cnt++; + break; + } + } + + ret_val = count; + goto done; + } else if (strncmp(curr_pos, "unlock ", 7) == 0) { + curr_pos += 7; + remaining -= 7; + + pr_debug("client 0x%p called 'unlock'\n", priv); + + if (strncmp(curr_pos, "all", 3) == 0) + io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; + else { + if (!vga_str_to_iostate + (curr_pos, remaining, &io_state)) { + ret_val = -EPROTO; + goto done; + } + /* TODO: Add this? + if (io_state == VGA_RSRC_NONE) { + ret_val = -EPROTO; + goto done; + } + */ + } + + pdev = priv->target; + if (priv->target == NULL) { + ret_val = -ENODEV; + goto done; + } + for (i = 0; i < MAX_USER_CARDS; i++) { + if (priv->cards[i].pdev == pdev) + uc = &priv->cards[i]; + } + + if (!uc) { + ret_val = -EINVAL; + goto done; + } + + if (io_state & VGA_RSRC_LEGACY_IO && uc->io_cnt == 0) { + ret_val = -EINVAL; + goto done; + } + + if (io_state & VGA_RSRC_LEGACY_MEM && uc->mem_cnt == 0) { + ret_val = -EINVAL; + goto done; + } + + vga_put(pdev, io_state); + + if (io_state & VGA_RSRC_LEGACY_IO) + uc->io_cnt--; + if (io_state & VGA_RSRC_LEGACY_MEM) + uc->mem_cnt--; + + ret_val = count; + goto done; + } else if (strncmp(curr_pos, "trylock ", 8) == 0) { + curr_pos += 8; + remaining -= 8; + + pr_debug("client 0x%p called 'trylock'\n", priv); + + if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { + ret_val = -EPROTO; + goto done; + } + /* TODO: Add this? + if (io_state == VGA_RSRC_NONE) { + ret_val = -EPROTO; + goto done; + } + */ + + pdev = priv->target; + if (priv->target == NULL) { + ret_val = -ENODEV; + goto done; + } + + if (vga_tryget(pdev, io_state)) { + /* Update the client's locks lists... */ + for (i = 0; i < MAX_USER_CARDS; i++) { + if (priv->cards[i].pdev == pdev) { + if (io_state & VGA_RSRC_LEGACY_IO) + priv->cards[i].io_cnt++; + if (io_state & VGA_RSRC_LEGACY_MEM) + priv->cards[i].mem_cnt++; + break; + } + } + ret_val = count; + goto done; + } else { + ret_val = -EBUSY; + goto done; + } + + } else if (strncmp(curr_pos, "target ", 7) == 0) { + unsigned int domain, bus, devfn; + struct vga_device *vgadev; + + curr_pos += 7; + remaining -= 7; + pr_debug("client 0x%p called 'target'\n", priv); + /* if target is default */ + if (!strncmp(curr_pos, "default", 7)) + pdev = pci_dev_get(vga_default_device()); + else { + if (!vga_pci_str_to_vars(curr_pos, remaining, + &domain, &bus, &devfn)) { + ret_val = -EPROTO; + goto done; + } + pdev = pci_get_domain_bus_and_slot(domain, bus, devfn); + if (!pdev) { + pr_debug("invalid PCI address %04x:%02x:%02x.%x\n", + domain, bus, PCI_SLOT(devfn), + PCI_FUNC(devfn)); + ret_val = -ENODEV; + goto done; + } + + pr_debug("%s ==> %04x:%02x:%02x.%x pdev %p\n", curr_pos, + domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), + pdev); + } + + vgadev = vgadev_find(pdev); + pr_debug("vgadev %p\n", vgadev); + if (vgadev == NULL) { + if (pdev) { + vgaarb_dbg(&pdev->dev, "not a VGA device\n"); + pci_dev_put(pdev); + } + + ret_val = -ENODEV; + goto done; + } + + priv->target = pdev; + for (i = 0; i < MAX_USER_CARDS; i++) { + if (priv->cards[i].pdev == pdev) + break; + if (priv->cards[i].pdev == NULL) { + priv->cards[i].pdev = pdev; + priv->cards[i].io_cnt = 0; + priv->cards[i].mem_cnt = 0; + break; + } + } + if (i == MAX_USER_CARDS) { + vgaarb_dbg(&pdev->dev, "maximum user cards (%d) number reached, ignoring this one!\n", + MAX_USER_CARDS); + pci_dev_put(pdev); + /* XXX: which value to return? */ + ret_val = -ENOMEM; + goto done; + } + + ret_val = count; + pci_dev_put(pdev); + goto done; + + + } else if (strncmp(curr_pos, "decodes ", 8) == 0) { + curr_pos += 8; + remaining -= 8; + pr_debug("client 0x%p called 'decodes'\n", priv); + + if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { + ret_val = -EPROTO; + goto done; + } + pdev = priv->target; + if (priv->target == NULL) { + ret_val = -ENODEV; + goto done; + } + + __vga_set_legacy_decoding(pdev, io_state, true); + ret_val = count; + goto done; + } + /* If we got here, the message written is not part of the protocol! */ + return -EPROTO; + +done: + return ret_val; +} + +static __poll_t vga_arb_fpoll(struct file *file, poll_table *wait) +{ + pr_debug("%s\n", __func__); + + poll_wait(file, &vga_wait_queue, wait); + return EPOLLIN; +} + +static int vga_arb_open(struct inode *inode, struct file *file) +{ + struct vga_arb_private *priv; + unsigned long flags; + + pr_debug("%s\n", __func__); + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + spin_lock_init(&priv->lock); + file->private_data = priv; + + spin_lock_irqsave(&vga_user_lock, flags); + list_add(&priv->list, &vga_user_list); + spin_unlock_irqrestore(&vga_user_lock, flags); + + /* Set the client' lists of locks */ + priv->target = vga_default_device(); /* Maybe this is still null! */ + priv->cards[0].pdev = priv->target; + priv->cards[0].io_cnt = 0; + priv->cards[0].mem_cnt = 0; + + + return 0; +} + +static int vga_arb_release(struct inode *inode, struct file *file) +{ + struct vga_arb_private *priv = file->private_data; + struct vga_arb_user_card *uc; + unsigned long flags; + int i; + + pr_debug("%s\n", __func__); + + spin_lock_irqsave(&vga_user_lock, flags); + list_del(&priv->list); + for (i = 0; i < MAX_USER_CARDS; i++) { + uc = &priv->cards[i]; + if (uc->pdev == NULL) + continue; + vgaarb_dbg(&uc->pdev->dev, "uc->io_cnt == %d, uc->mem_cnt == %d\n", + uc->io_cnt, uc->mem_cnt); + while (uc->io_cnt--) + vga_put(uc->pdev, VGA_RSRC_LEGACY_IO); + while (uc->mem_cnt--) + vga_put(uc->pdev, VGA_RSRC_LEGACY_MEM); + } + spin_unlock_irqrestore(&vga_user_lock, flags); + + kfree(priv); + + return 0; +} + +static void vga_arb_device_card_gone(struct pci_dev *pdev) +{ +} + +/* + * callback any registered clients to let them know we have a + * change in VGA cards + */ +static void vga_arbiter_notify_clients(void) +{ + struct vga_device *vgadev; + unsigned long flags; + uint32_t new_decodes; + bool new_state; + + if (!vga_arbiter_used) + return; + + spin_lock_irqsave(&vga_lock, flags); + list_for_each_entry(vgadev, &vga_list, list) { + if (vga_count > 1) + new_state = false; + else + new_state = true; + if (vgadev->set_decode) { + new_decodes = vgadev->set_decode(vgadev->pdev, + new_state); + vga_update_device_decodes(vgadev, new_decodes); + } + } + spin_unlock_irqrestore(&vga_lock, flags); +} + +static int pci_notify(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct device *dev = data; + struct pci_dev *pdev = to_pci_dev(dev); + bool notify = false; + + vgaarb_dbg(dev, "%s\n", __func__); + + /* For now we're only intereted in devices added and removed. I didn't + * test this thing here, so someone needs to double check for the + * cases of hotplugable vga cards. */ + if (action == BUS_NOTIFY_ADD_DEVICE) + notify = vga_arbiter_add_pci_device(pdev); + else if (action == BUS_NOTIFY_DEL_DEVICE) + notify = vga_arbiter_del_pci_device(pdev); + + if (notify) + vga_arbiter_notify_clients(); + return 0; +} + +static struct notifier_block pci_notifier = { + .notifier_call = pci_notify, +}; + +static const struct file_operations vga_arb_device_fops = { + .read = vga_arb_read, + .write = vga_arb_write, + .poll = vga_arb_fpoll, + .open = vga_arb_open, + .release = vga_arb_release, + .llseek = noop_llseek, +}; + +static struct miscdevice vga_arb_device = { + MISC_DYNAMIC_MINOR, "vga_arbiter", &vga_arb_device_fops +}; + +#if defined(CONFIG_ACPI) +static bool vga_arb_integrated_gpu(struct device *dev) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + + return adev && !strcmp(acpi_device_hid(adev), ACPI_VIDEO_HID); +} +#else +static bool vga_arb_integrated_gpu(struct device *dev) +{ + return false; +} +#endif + +static void __init vga_arb_select_default_device(void) +{ + struct pci_dev *pdev, *found = NULL; + struct vga_device *vgadev; + +#if defined(CONFIG_X86) || defined(CONFIG_IA64) + u64 base = screen_info.lfb_base; + u64 size = screen_info.lfb_size; + u64 limit; + resource_size_t start, end; + unsigned long flags; + int i; + + if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) + base |= (u64)screen_info.ext_lfb_base << 32; + + limit = base + size; + + list_for_each_entry(vgadev, &vga_list, list) { + struct device *dev = &vgadev->pdev->dev; + /* + * Override vga_arbiter_add_pci_device()'s I/O based detection + * as it may take the wrong device (e.g. on Apple system under + * EFI). + * + * Select the device owning the boot framebuffer if there is + * one. + */ + + /* Does firmware framebuffer belong to us? */ + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + flags = pci_resource_flags(vgadev->pdev, i); + + if ((flags & IORESOURCE_MEM) == 0) + continue; + + start = pci_resource_start(vgadev->pdev, i); + end = pci_resource_end(vgadev->pdev, i); + + if (!start || !end) + continue; + + if (base < start || limit >= end) + continue; + + if (!vga_default_device()) + vgaarb_info(dev, "setting as boot device\n"); + else if (vgadev->pdev != vga_default_device()) + vgaarb_info(dev, "overriding boot device\n"); + vga_set_default_device(vgadev->pdev); + } + } +#endif + + if (!vga_default_device()) { + list_for_each_entry_reverse(vgadev, &vga_list, list) { + struct device *dev = &vgadev->pdev->dev; + u16 cmd; + + pdev = vgadev->pdev; + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if (cmd & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { + found = pdev; + if (vga_arb_integrated_gpu(dev)) + break; + } + } + } + + if (found) { + vgaarb_info(&found->dev, "setting as boot device (VGA legacy resources not available)\n"); + vga_set_default_device(found); + return; + } + + if (!vga_default_device()) { + vgadev = list_first_entry_or_null(&vga_list, + struct vga_device, list); + if (vgadev) { + struct device *dev = &vgadev->pdev->dev; + vgaarb_info(dev, "setting as boot device (VGA legacy resources not available)\n"); + vga_set_default_device(vgadev->pdev); + } + } +} + +static int __init vga_arb_device_init(void) +{ + int rc; + struct pci_dev *pdev; + struct vga_device *vgadev; + + rc = misc_register(&vga_arb_device); + if (rc < 0) + pr_err("error %d registering device\n", rc); + + bus_register_notifier(&pci_bus_type, &pci_notifier); + + /* We add all PCI devices satisfying VGA class in the arbiter by + * default */ + pdev = NULL; + while ((pdev = + pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_ANY_ID, pdev)) != NULL) + vga_arbiter_add_pci_device(pdev); + + list_for_each_entry(vgadev, &vga_list, list) { + struct device *dev = &vgadev->pdev->dev; + + if (vgadev->bridge_has_one_vga) + vgaarb_info(dev, "bridge control possible\n"); + else + vgaarb_info(dev, "no bridge control possible\n"); + } + + vga_arb_select_default_device(); + + pr_info("loaded\n"); + return rc; +} +subsys_initcall_sync(vga_arb_device_init); -- cgit v1.2.3