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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'drm-fixes-2022-02-04' of git://anongit.freedesktop.org/drm/drm

Pull drm fixes from Dave Airlie:
"Regular fixes for the week. Daniel has agreed to bring back the fbcon
hw acceleration under a CONFIG option for the non-drm fbdev users, we
don't advise turning this on unless you are in the niche that is old
fbdev drivers, Since it's essentially a revert and shouldn't be high
impact seemed like a good time to do it now.

Otherwise, i915 and amdgpu fixes are most of it, along with some minor
fixes elsewhere.

fbdev:
- readd fbcon acceleration

i915:
- fix DP monitor via type-c dock
- fix for engine busyness and read timeout with GuC
- use ALLOW_FAIL for error capture buffer allocs
- don't use interruptible lock on error paths
- smatch fix to reject zero sized overlays.

amdgpu:
- mGPU fan boost fix for beige goby
- S0ix fixes
- Cyan skillfish hang fix
- DCN fixes for DCN 3.1
- DCN fixes for DCN 3.01
- Apple retina panel fix
- ttm logic inversion fix

dma-buf:
- heaps: fix potential spectre v1 gadget

kmb:
- fix potential oob access

mxsfb:
- fix NULL ptr deref

nouveau:
- fix potential oob access during BIOS decode"

* tag 'drm-fixes-2022-02-04' of git://anongit.freedesktop.org/drm/drm: (24 commits)
drm: mxsfb: Fix NULL pointer dereference
drm/amdgpu: fix logic inversion in check
drm/amd: avoid suspend on dGPUs w/ s2idle support when runtime PM enabled
drm/amd/display: Force link_rate as LINK_RATE_RBR2 for 2018 15" Apple Retina panels
drm/amd/display: revert "Reset fifo after enable otg"
drm/amd/display: watermark latencies is not enough on DCN31
drm/amd/display: Update watermark values for DCN301
drm/amdgpu: fix a potential GPU hang on cyan skillfish
drm/amd: Only run s3 or s0ix if system is configured properly
drm/amd: add support to check whether the system is set to s3
fbcon: Add option to enable legacy hardware acceleration
Revert "fbcon: Disable accelerated scrolling"
Revert "fbdev: Garbage collect fbdev scrolling acceleration, part 1 (from TODO list)"
drm/i915/pmu: Fix KMD and GuC race on accessing busyness
dma-buf: heaps: Fix potential spectre v1 gadget
drm/amd: Warn users about potential s0ix problems
drm/amd/pm: correct the MGpuFanBoost support for Beige Goby
drm/nouveau: fix off by one in BIOS boundary checking
drm/i915/adlp: Fix TypeC PHY-ready status readout
drm/i915/pmu: Use PM timestamp instead of RING TIMESTAMP for reference
...

+972 -160
-24
Documentation/gpu/todo.rst
··· 300 300 301 301 Level: Advanced 302 302 303 - Garbage collect fbdev scrolling acceleration 304 - -------------------------------------------- 305 - 306 - Scroll acceleration has been disabled in fbcon. Now it works as the old 307 - SCROLL_REDRAW mode. A ton of code was removed in fbcon.c and the hook bmove was 308 - removed from fbcon_ops. 309 - Remaining tasks: 310 - 311 - - a bunch of the hooks in fbcon_ops could be removed or simplified by calling 312 - directly instead of the function table (with a switch on p->rotate) 313 - 314 - - fb_copyarea is unused after this, and can be deleted from all drivers 315 - 316 - - after that, fb_copyarea can be deleted from fb_ops in include/linux/fb.h as 317 - well as cfb_copyarea 318 - 319 - Note that not all acceleration code can be deleted, since clearing and cursor 320 - support is still accelerated, which might be good candidates for further 321 - deletion projects. 322 - 323 - Contact: Daniel Vetter 324 - 325 - Level: Intermediate 326 - 327 303 idr_init_base() 328 304 --------------- 329 305
+2
drivers/dma-buf/dma-heap.c
··· 14 14 #include <linux/xarray.h> 15 15 #include <linux/list.h> 16 16 #include <linux/slab.h> 17 + #include <linux/nospec.h> 17 18 #include <linux/uaccess.h> 18 19 #include <linux/syscalls.h> 19 20 #include <linux/dma-heap.h> ··· 136 135 if (nr >= ARRAY_SIZE(dma_heap_ioctl_cmds)) 137 136 return -EINVAL; 138 137 138 + nr = array_index_nospec(nr, ARRAY_SIZE(dma_heap_ioctl_cmds)); 139 139 /* Get the kernel ioctl cmd that matches */ 140 140 kcmd = dma_heap_ioctl_cmds[nr]; 141 141
+8 -2
drivers/gpu/drm/amd/amdgpu/amdgpu.h
··· 1408 1408 int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev); 1409 1409 1410 1410 void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps); 1411 - bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev); 1412 1411 void amdgpu_acpi_detect(void); 1413 1412 #else 1414 1413 static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; } 1415 1414 static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { } 1416 - static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; } 1417 1415 static inline void amdgpu_acpi_detect(void) { } 1418 1416 static inline bool amdgpu_acpi_is_power_shift_control_supported(void) { return false; } 1419 1417 static inline int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev, 1420 1418 u8 dev_state, bool drv_state) { return 0; } 1421 1419 static inline int amdgpu_acpi_smart_shift_update(struct drm_device *dev, 1422 1420 enum amdgpu_ss ss_state) { return 0; } 1421 + #endif 1422 + 1423 + #if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND) 1424 + bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev); 1425 + bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev); 1426 + #else 1427 + static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; } 1428 + static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { return false; } 1423 1429 #endif 1424 1430 1425 1431 int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
+32 -5
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
··· 1031 1031 } 1032 1032 } 1033 1033 1034 + #if IS_ENABLED(CONFIG_SUSPEND) 1035 + /** 1036 + * amdgpu_acpi_is_s3_active 1037 + * 1038 + * @adev: amdgpu_device_pointer 1039 + * 1040 + * returns true if supported, false if not. 1041 + */ 1042 + bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) 1043 + { 1044 + return !(adev->flags & AMD_IS_APU) || 1045 + (pm_suspend_target_state == PM_SUSPEND_MEM); 1046 + } 1047 + 1034 1048 /** 1035 1049 * amdgpu_acpi_is_s0ix_active 1036 1050 * ··· 1054 1040 */ 1055 1041 bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) 1056 1042 { 1057 - #if IS_ENABLED(CONFIG_AMD_PMC) && IS_ENABLED(CONFIG_SUSPEND) 1058 - if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) { 1059 - if (adev->flags & AMD_IS_APU) 1060 - return pm_suspend_target_state == PM_SUSPEND_TO_IDLE; 1043 + if (!(adev->flags & AMD_IS_APU) || 1044 + (pm_suspend_target_state != PM_SUSPEND_TO_IDLE)) 1045 + return false; 1046 + 1047 + if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) { 1048 + dev_warn_once(adev->dev, 1049 + "Power consumption will be higher as BIOS has not been configured for suspend-to-idle.\n" 1050 + "To use suspend-to-idle change the sleep mode in BIOS setup.\n"); 1051 + return false; 1061 1052 } 1062 - #endif 1053 + 1054 + #if !IS_ENABLED(CONFIG_AMD_PMC) 1055 + dev_warn_once(adev->dev, 1056 + "Power consumption will be higher as the kernel has not been compiled with CONFIG_AMD_PMC.\n"); 1063 1057 return false; 1058 + #else 1059 + return true; 1060 + #endif /* CONFIG_AMD_PMC */ 1064 1061 } 1062 + 1063 + #endif /* CONFIG_SUSPEND */
+9 -2
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
··· 2246 2246 static int amdgpu_pmops_prepare(struct device *dev) 2247 2247 { 2248 2248 struct drm_device *drm_dev = dev_get_drvdata(dev); 2249 + struct amdgpu_device *adev = drm_to_adev(drm_dev); 2249 2250 2250 2251 /* Return a positive number here so 2251 2252 * DPM_FLAG_SMART_SUSPEND works properly 2252 2253 */ 2253 2254 if (amdgpu_device_supports_boco(drm_dev)) 2254 - return pm_runtime_suspended(dev) && 2255 - pm_suspend_via_firmware(); 2255 + return pm_runtime_suspended(dev); 2256 + 2257 + /* if we will not support s3 or s2i for the device 2258 + * then skip suspend 2259 + */ 2260 + if (!amdgpu_acpi_is_s0ix_active(adev) && 2261 + !amdgpu_acpi_is_s3_active(adev)) 2262 + return 1; 2256 2263 2257 2264 return 0; 2258 2265 }
+1 -1
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
··· 1904 1904 unsigned i; 1905 1905 int r; 1906 1906 1907 - if (direct_submit && !ring->sched.ready) { 1907 + if (!direct_submit && !ring->sched.ready) { 1908 1908 DRM_ERROR("Trying to move memory with ring turned off.\n"); 1909 1909 return -EINVAL; 1910 1910 }
+3
drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
··· 1140 1140 { 1141 1141 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 1142 1142 1143 + if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 1, 3)) 1144 + return; 1145 + 1143 1146 adev->mmhub.funcs->get_clockgating(adev, flags); 1144 1147 1145 1148 if (adev->ip_versions[ATHUB_HWIP][0] >= IP_VERSION(2, 1, 0))
+8 -8
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c
··· 570 570 .wm_inst = WM_A, 571 571 .wm_type = WM_TYPE_PSTATE_CHG, 572 572 .pstate_latency_us = 11.65333, 573 - .sr_exit_time_us = 7.95, 574 - .sr_enter_plus_exit_time_us = 9, 573 + .sr_exit_time_us = 13.5, 574 + .sr_enter_plus_exit_time_us = 16.5, 575 575 .valid = true, 576 576 }, 577 577 { 578 578 .wm_inst = WM_B, 579 579 .wm_type = WM_TYPE_PSTATE_CHG, 580 580 .pstate_latency_us = 11.65333, 581 - .sr_exit_time_us = 9.82, 582 - .sr_enter_plus_exit_time_us = 11.196, 581 + .sr_exit_time_us = 13.5, 582 + .sr_enter_plus_exit_time_us = 16.5, 583 583 .valid = true, 584 584 }, 585 585 { 586 586 .wm_inst = WM_C, 587 587 .wm_type = WM_TYPE_PSTATE_CHG, 588 588 .pstate_latency_us = 11.65333, 589 - .sr_exit_time_us = 9.89, 590 - .sr_enter_plus_exit_time_us = 11.24, 589 + .sr_exit_time_us = 13.5, 590 + .sr_enter_plus_exit_time_us = 16.5, 591 591 .valid = true, 592 592 }, 593 593 { 594 594 .wm_inst = WM_D, 595 595 .wm_type = WM_TYPE_PSTATE_CHG, 596 596 .pstate_latency_us = 11.65333, 597 - .sr_exit_time_us = 9.748, 598 - .sr_enter_plus_exit_time_us = 11.102, 597 + .sr_exit_time_us = 13.5, 598 + .sr_enter_plus_exit_time_us = 16.5, 599 599 .valid = true, 600 600 }, 601 601 }
+10 -10
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
··· 329 329 330 330 }; 331 331 332 - static struct wm_table ddr4_wm_table = { 332 + static struct wm_table ddr5_wm_table = { 333 333 .entries = { 334 334 { 335 335 .wm_inst = WM_A, 336 336 .wm_type = WM_TYPE_PSTATE_CHG, 337 337 .pstate_latency_us = 11.72, 338 - .sr_exit_time_us = 6.09, 339 - .sr_enter_plus_exit_time_us = 7.14, 338 + .sr_exit_time_us = 9, 339 + .sr_enter_plus_exit_time_us = 11, 340 340 .valid = true, 341 341 }, 342 342 { 343 343 .wm_inst = WM_B, 344 344 .wm_type = WM_TYPE_PSTATE_CHG, 345 345 .pstate_latency_us = 11.72, 346 - .sr_exit_time_us = 10.12, 347 - .sr_enter_plus_exit_time_us = 11.48, 346 + .sr_exit_time_us = 9, 347 + .sr_enter_plus_exit_time_us = 11, 348 348 .valid = true, 349 349 }, 350 350 { 351 351 .wm_inst = WM_C, 352 352 .wm_type = WM_TYPE_PSTATE_CHG, 353 353 .pstate_latency_us = 11.72, 354 - .sr_exit_time_us = 10.12, 355 - .sr_enter_plus_exit_time_us = 11.48, 354 + .sr_exit_time_us = 9, 355 + .sr_enter_plus_exit_time_us = 11, 356 356 .valid = true, 357 357 }, 358 358 { 359 359 .wm_inst = WM_D, 360 360 .wm_type = WM_TYPE_PSTATE_CHG, 361 361 .pstate_latency_us = 11.72, 362 - .sr_exit_time_us = 10.12, 363 - .sr_enter_plus_exit_time_us = 11.48, 362 + .sr_exit_time_us = 9, 363 + .sr_enter_plus_exit_time_us = 11, 364 364 .valid = true, 365 365 }, 366 366 } ··· 687 687 if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) { 688 688 dcn31_bw_params.wm_table = lpddr5_wm_table; 689 689 } else { 690 - dcn31_bw_params.wm_table = ddr4_wm_table; 690 + dcn31_bw_params.wm_table = ddr5_wm_table; 691 691 } 692 692 /* Saved clocks configured at boot for debug purposes */ 693 693 dcn31_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info);
-5
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
··· 1608 1608 pipe_ctx->stream_res.stream_enc, 1609 1609 pipe_ctx->stream_res.tg->inst); 1610 1610 1611 - if (dc_is_embedded_signal(pipe_ctx->stream->signal) && 1612 - pipe_ctx->stream_res.stream_enc->funcs->reset_fifo) 1613 - pipe_ctx->stream_res.stream_enc->funcs->reset_fifo( 1614 - pipe_ctx->stream_res.stream_enc); 1615 - 1616 1611 if (dc_is_dp_signal(pipe_ctx->stream->signal)) 1617 1612 dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG); 1618 1613
-15
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
··· 902 902 903 903 } 904 904 905 - void enc1_stream_encoder_reset_fifo( 906 - struct stream_encoder *enc) 907 - { 908 - struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); 909 - 910 - /* set DIG_START to 0x1 to reset FIFO */ 911 - REG_UPDATE(DIG_FE_CNTL, DIG_START, 1); 912 - udelay(100); 913 - 914 - /* write 0 to take the FIFO out of reset */ 915 - REG_UPDATE(DIG_FE_CNTL, DIG_START, 0); 916 - } 917 - 918 905 void enc1_stream_encoder_dp_blank( 919 906 struct dc_link *link, 920 907 struct stream_encoder *enc) ··· 1587 1600 enc1_stream_encoder_send_immediate_sdp_message, 1588 1601 .stop_dp_info_packets = 1589 1602 enc1_stream_encoder_stop_dp_info_packets, 1590 - .reset_fifo = 1591 - enc1_stream_encoder_reset_fifo, 1592 1603 .dp_blank = 1593 1604 enc1_stream_encoder_dp_blank, 1594 1605 .dp_unblank =
-3
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h
··· 626 626 void enc1_stream_encoder_stop_dp_info_packets( 627 627 struct stream_encoder *enc); 628 628 629 - void enc1_stream_encoder_reset_fifo( 630 - struct stream_encoder *enc); 631 - 632 629 void enc1_stream_encoder_dp_blank( 633 630 struct dc_link *link, 634 631 struct stream_encoder *enc);
-2
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
··· 593 593 enc1_stream_encoder_send_immediate_sdp_message, 594 594 .stop_dp_info_packets = 595 595 enc1_stream_encoder_stop_dp_info_packets, 596 - .reset_fifo = 597 - enc1_stream_encoder_reset_fifo, 598 596 .dp_blank = 599 597 enc1_stream_encoder_dp_blank, 600 598 .dp_unblank =
-2
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c
··· 789 789 enc3_stream_encoder_update_dp_info_packets, 790 790 .stop_dp_info_packets = 791 791 enc1_stream_encoder_stop_dp_info_packets, 792 - .reset_fifo = 793 - enc1_stream_encoder_reset_fifo, 794 792 .dp_blank = 795 793 enc1_stream_encoder_dp_blank, 796 794 .dp_unblank =
-4
drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
··· 164 164 void (*stop_dp_info_packets)( 165 165 struct stream_encoder *enc); 166 166 167 - void (*reset_fifo)( 168 - struct stream_encoder *enc 169 - ); 170 - 171 167 void (*dp_blank)( 172 168 struct dc_link *link, 173 169 struct stream_encoder *enc);
+3 -3
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
··· 3696 3696 3697 3697 static int sienna_cichlid_enable_mgpu_fan_boost(struct smu_context *smu) 3698 3698 { 3699 - struct smu_table_context *table_context = &smu->smu_table; 3700 - PPTable_t *smc_pptable = table_context->driver_pptable; 3699 + uint16_t *mgpu_fan_boost_limit_rpm; 3701 3700 3701 + GET_PPTABLE_MEMBER(MGpuFanBoostLimitRpm, &mgpu_fan_boost_limit_rpm); 3702 3702 /* 3703 3703 * Skip the MGpuFanBoost setting for those ASICs 3704 3704 * which do not support it 3705 3705 */ 3706 - if (!smc_pptable->MGpuFanBoostLimitRpm) 3706 + if (*mgpu_fan_boost_limit_rpm == 0) 3707 3707 return 0; 3708 3708 3709 3709 return smu_cmn_send_smc_msg_with_param(smu,
+3
drivers/gpu/drm/i915/display/intel_overlay.c
··· 959 959 const struct intel_crtc_state *pipe_config = 960 960 overlay->crtc->config; 961 961 962 + if (rec->dst_height == 0 || rec->dst_width == 0) 963 + return -EINVAL; 964 + 962 965 if (rec->dst_x < pipe_config->pipe_src_w && 963 966 rec->dst_x + rec->dst_width <= pipe_config->pipe_src_w && 964 967 rec->dst_y < pipe_config->pipe_src_h &&
+2 -1
drivers/gpu/drm/i915/display/intel_tc.c
··· 345 345 static bool adl_tc_phy_status_complete(struct intel_digital_port *dig_port) 346 346 { 347 347 struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); 348 + enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port); 348 349 struct intel_uncore *uncore = &i915->uncore; 349 350 u32 val; 350 351 351 - val = intel_uncore_read(uncore, TCSS_DDI_STATUS(dig_port->tc_phy_fia_idx)); 352 + val = intel_uncore_read(uncore, TCSS_DDI_STATUS(tc_port)); 352 353 if (val == 0xffffffff) { 353 354 drm_dbg_kms(&i915->drm, 354 355 "Port %s: PHY in TCCOLD, assuming not complete\n",
+7 -2
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
··· 2505 2505 timeout) < 0) { 2506 2506 i915_request_put(rq); 2507 2507 2508 - tl = intel_context_timeline_lock(ce); 2508 + /* 2509 + * Error path, cannot use intel_context_timeline_lock as 2510 + * that is user interruptable and this clean up step 2511 + * must be done. 2512 + */ 2513 + mutex_lock(&ce->timeline->mutex); 2509 2514 intel_context_exit(ce); 2510 - intel_context_timeline_unlock(tl); 2515 + mutex_unlock(&ce->timeline->mutex); 2511 2516 2512 2517 if (nonblock) 2513 2518 return -EWOULDBLOCK;
+5
drivers/gpu/drm/i915/gt/uc/intel_guc.h
··· 206 206 * context usage for overflows. 207 207 */ 208 208 struct delayed_work work; 209 + 210 + /** 211 + * @shift: Right shift value for the gpm timestamp 212 + */ 213 + u32 shift; 209 214 } timestamp; 210 215 211 216 #ifdef CONFIG_DRM_I915_SELFTEST
+97 -17
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
··· 1113 1113 if (new_start == lower_32_bits(*prev_start)) 1114 1114 return; 1115 1115 1116 + /* 1117 + * When gt is unparked, we update the gt timestamp and start the ping 1118 + * worker that updates the gt_stamp every POLL_TIME_CLKS. As long as gt 1119 + * is unparked, all switched in contexts will have a start time that is 1120 + * within +/- POLL_TIME_CLKS of the most recent gt_stamp. 1121 + * 1122 + * If neither gt_stamp nor new_start has rolled over, then the 1123 + * gt_stamp_hi does not need to be adjusted, however if one of them has 1124 + * rolled over, we need to adjust gt_stamp_hi accordingly. 1125 + * 1126 + * The below conditions address the cases of new_start rollover and 1127 + * gt_stamp_last rollover respectively. 1128 + */ 1116 1129 if (new_start < gt_stamp_last && 1117 1130 (new_start - gt_stamp_last) <= POLL_TIME_CLKS) 1118 1131 gt_stamp_hi++; ··· 1137 1124 *prev_start = ((u64)gt_stamp_hi << 32) | new_start; 1138 1125 } 1139 1126 1140 - static void guc_update_engine_gt_clks(struct intel_engine_cs *engine) 1127 + /* 1128 + * GuC updates shared memory and KMD reads it. Since this is not synchronized, 1129 + * we run into a race where the value read is inconsistent. Sometimes the 1130 + * inconsistency is in reading the upper MSB bytes of the last_in value when 1131 + * this race occurs. 2 types of cases are seen - upper 8 bits are zero and upper 1132 + * 24 bits are zero. Since these are non-zero values, it is non-trivial to 1133 + * determine validity of these values. Instead we read the values multiple times 1134 + * until they are consistent. In test runs, 3 attempts results in consistent 1135 + * values. The upper bound is set to 6 attempts and may need to be tuned as per 1136 + * any new occurences. 1137 + */ 1138 + static void __get_engine_usage_record(struct intel_engine_cs *engine, 1139 + u32 *last_in, u32 *id, u32 *total) 1141 1140 { 1142 1141 struct guc_engine_usage_record *rec = intel_guc_engine_usage(engine); 1142 + int i = 0; 1143 + 1144 + do { 1145 + *last_in = READ_ONCE(rec->last_switch_in_stamp); 1146 + *id = READ_ONCE(rec->current_context_index); 1147 + *total = READ_ONCE(rec->total_runtime); 1148 + 1149 + if (READ_ONCE(rec->last_switch_in_stamp) == *last_in && 1150 + READ_ONCE(rec->current_context_index) == *id && 1151 + READ_ONCE(rec->total_runtime) == *total) 1152 + break; 1153 + } while (++i < 6); 1154 + } 1155 + 1156 + static void guc_update_engine_gt_clks(struct intel_engine_cs *engine) 1157 + { 1143 1158 struct intel_engine_guc_stats *stats = &engine->stats.guc; 1144 1159 struct intel_guc *guc = &engine->gt->uc.guc; 1145 - u32 last_switch = rec->last_switch_in_stamp; 1146 - u32 ctx_id = rec->current_context_index; 1147 - u32 total = rec->total_runtime; 1160 + u32 last_switch, ctx_id, total; 1148 1161 1149 1162 lockdep_assert_held(&guc->timestamp.lock); 1163 + 1164 + __get_engine_usage_record(engine, &last_switch, &ctx_id, &total); 1150 1165 1151 1166 stats->running = ctx_id != ~0U && last_switch; 1152 1167 if (stats->running) ··· 1190 1149 } 1191 1150 } 1192 1151 1193 - static void guc_update_pm_timestamp(struct intel_guc *guc, 1194 - struct intel_engine_cs *engine, 1195 - ktime_t *now) 1152 + static u32 gpm_timestamp_shift(struct intel_gt *gt) 1196 1153 { 1197 - u32 gt_stamp_now, gt_stamp_hi; 1154 + intel_wakeref_t wakeref; 1155 + u32 reg, shift; 1156 + 1157 + with_intel_runtime_pm(gt->uncore->rpm, wakeref) 1158 + reg = intel_uncore_read(gt->uncore, RPM_CONFIG0); 1159 + 1160 + shift = (reg & GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK) >> 1161 + GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_SHIFT; 1162 + 1163 + return 3 - shift; 1164 + } 1165 + 1166 + static u64 gpm_timestamp(struct intel_gt *gt) 1167 + { 1168 + u32 lo, hi, old_hi, loop = 0; 1169 + 1170 + hi = intel_uncore_read(gt->uncore, MISC_STATUS1); 1171 + do { 1172 + lo = intel_uncore_read(gt->uncore, MISC_STATUS0); 1173 + old_hi = hi; 1174 + hi = intel_uncore_read(gt->uncore, MISC_STATUS1); 1175 + } while (old_hi != hi && loop++ < 2); 1176 + 1177 + return ((u64)hi << 32) | lo; 1178 + } 1179 + 1180 + static void guc_update_pm_timestamp(struct intel_guc *guc, ktime_t *now) 1181 + { 1182 + struct intel_gt *gt = guc_to_gt(guc); 1183 + u32 gt_stamp_lo, gt_stamp_hi; 1184 + u64 gpm_ts; 1198 1185 1199 1186 lockdep_assert_held(&guc->timestamp.lock); 1200 1187 1201 1188 gt_stamp_hi = upper_32_bits(guc->timestamp.gt_stamp); 1202 - gt_stamp_now = intel_uncore_read(engine->uncore, 1203 - RING_TIMESTAMP(engine->mmio_base)); 1189 + gpm_ts = gpm_timestamp(gt) >> guc->timestamp.shift; 1190 + gt_stamp_lo = lower_32_bits(gpm_ts); 1204 1191 *now = ktime_get(); 1205 1192 1206 - if (gt_stamp_now < lower_32_bits(guc->timestamp.gt_stamp)) 1193 + if (gt_stamp_lo < lower_32_bits(guc->timestamp.gt_stamp)) 1207 1194 gt_stamp_hi++; 1208 1195 1209 - guc->timestamp.gt_stamp = ((u64)gt_stamp_hi << 32) | gt_stamp_now; 1196 + guc->timestamp.gt_stamp = ((u64)gt_stamp_hi << 32) | gt_stamp_lo; 1210 1197 } 1211 1198 1212 1199 /* ··· 1277 1208 if (!in_reset && intel_gt_pm_get_if_awake(gt)) { 1278 1209 stats_saved = *stats; 1279 1210 gt_stamp_saved = guc->timestamp.gt_stamp; 1211 + /* 1212 + * Update gt_clks, then gt timestamp to simplify the 'gt_stamp - 1213 + * start_gt_clk' calculation below for active engines. 1214 + */ 1280 1215 guc_update_engine_gt_clks(engine); 1281 - guc_update_pm_timestamp(guc, engine, now); 1216 + guc_update_pm_timestamp(guc, now); 1282 1217 intel_gt_pm_put_async(gt); 1283 1218 if (i915_reset_count(gpu_error) != reset_count) { 1284 1219 *stats = stats_saved; ··· 1314 1241 1315 1242 spin_lock_irqsave(&guc->timestamp.lock, flags); 1316 1243 1244 + guc_update_pm_timestamp(guc, &unused); 1317 1245 for_each_engine(engine, gt, id) { 1318 - guc_update_pm_timestamp(guc, engine, &unused); 1319 1246 guc_update_engine_gt_clks(engine); 1320 1247 engine->stats.guc.prev_total = 0; 1321 1248 } ··· 1332 1259 ktime_t unused; 1333 1260 1334 1261 spin_lock_irqsave(&guc->timestamp.lock, flags); 1335 - for_each_engine(engine, gt, id) { 1336 - guc_update_pm_timestamp(guc, engine, &unused); 1262 + 1263 + guc_update_pm_timestamp(guc, &unused); 1264 + for_each_engine(engine, gt, id) 1337 1265 guc_update_engine_gt_clks(engine); 1338 - } 1266 + 1339 1267 spin_unlock_irqrestore(&guc->timestamp.lock, flags); 1340 1268 } 1341 1269 ··· 1409 1335 void intel_guc_busyness_unpark(struct intel_gt *gt) 1410 1336 { 1411 1337 struct intel_guc *guc = &gt->uc.guc; 1338 + unsigned long flags; 1339 + ktime_t unused; 1412 1340 1413 1341 if (!guc_submission_initialized(guc)) 1414 1342 return; 1415 1343 1344 + spin_lock_irqsave(&guc->timestamp.lock, flags); 1345 + guc_update_pm_timestamp(guc, &unused); 1346 + spin_unlock_irqrestore(&guc->timestamp.lock, flags); 1416 1347 mod_delayed_work(system_highpri_wq, &guc->timestamp.work, 1417 1348 guc->timestamp.ping_delay); 1418 1349 } ··· 1862 1783 spin_lock_init(&guc->timestamp.lock); 1863 1784 INIT_DELAYED_WORK(&guc->timestamp.work, guc_timestamp_ping); 1864 1785 guc->timestamp.ping_delay = (POLL_TIME_CLKS / gt->clock_frequency + 1) * HZ; 1786 + guc->timestamp.shift = gpm_timestamp_shift(gt); 1865 1787 1866 1788 return 0; 1867 1789 }
+1 -1
drivers/gpu/drm/i915/i915_gpu_error.c
··· 1522 1522 struct i915_request *rq = NULL; 1523 1523 unsigned long flags; 1524 1524 1525 - ee = intel_engine_coredump_alloc(engine, GFP_KERNEL); 1525 + ee = intel_engine_coredump_alloc(engine, ALLOW_FAIL); 1526 1526 if (!ee) 1527 1527 return NULL; 1528 1528
+2 -1
drivers/gpu/drm/i915/i915_reg.h
··· 2684 2684 #define RING_WAIT (1 << 11) /* gen3+, PRBx_CTL */ 2685 2685 #define RING_WAIT_SEMAPHORE (1 << 10) /* gen6+ */ 2686 2686 2687 - #define GUCPMTIMESTAMP _MMIO(0xC3E8) 2687 + #define MISC_STATUS0 _MMIO(0xA500) 2688 + #define MISC_STATUS1 _MMIO(0xA504) 2688 2689 2689 2690 /* There are 16 64-bit CS General Purpose Registers per-engine on Gen8+ */ 2690 2691 #define GEN8_RING_CS_GPR(base, n) _MMIO((base) + 0x600 + (n) * 8)
-6
drivers/gpu/drm/kmb/kmb_plane.c
··· 158 158 case LAYER_1: 159 159 kmb->plane_status[plane_id].ctrl = LCD_CTRL_VL2_ENABLE; 160 160 break; 161 - case LAYER_2: 162 - kmb->plane_status[plane_id].ctrl = LCD_CTRL_GL1_ENABLE; 163 - break; 164 - case LAYER_3: 165 - kmb->plane_status[plane_id].ctrl = LCD_CTRL_GL2_ENABLE; 166 - break; 167 161 } 168 162 169 163 kmb->plane_status[plane_id].disable = true;
+5 -1
drivers/gpu/drm/mxsfb/mxsfb_kms.c
··· 361 361 bridge_state = 362 362 drm_atomic_get_new_bridge_state(state, 363 363 mxsfb->bridge); 364 - bus_format = bridge_state->input_bus_cfg.format; 364 + if (!bridge_state) 365 + bus_format = MEDIA_BUS_FMT_FIXED; 366 + else 367 + bus_format = bridge_state->input_bus_cfg.format; 368 + 365 369 if (bus_format == MEDIA_BUS_FMT_FIXED) { 366 370 dev_warn_once(drm->dev, 367 371 "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n"
+1 -1
drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c
··· 38 38 *addr += bios->imaged_addr; 39 39 } 40 40 41 - if (unlikely(*addr + size >= bios->size)) { 41 + if (unlikely(*addr + size > bios->size)) { 42 42 nvkm_error(&bios->subdev, "OOB %d %08x %08x\n", size, p, *addr); 43 43 return false; 44 44 }
+20
drivers/video/console/Kconfig
··· 78 78 help 79 79 Low-level framebuffer-based console driver. 80 80 81 + config FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION 82 + bool "Enable legacy fbcon hardware acceleration code" 83 + depends on FRAMEBUFFER_CONSOLE 84 + default y if PARISC 85 + default n 86 + help 87 + This option enables the fbcon (framebuffer text-based) hardware 88 + acceleration for graphics drivers which were written for the fbdev 89 + graphics interface. 90 + 91 + On modern machines, on mainstream machines (like x86-64) or when 92 + using a modern Linux distribution those fbdev drivers usually aren't used. 93 + So enabling this option wouldn't have any effect, which is why you want 94 + to disable this option on such newer machines. 95 + 96 + If you compile this kernel for older machines which still require the 97 + fbdev drivers, you may want to say Y. 98 + 99 + If unsure, select n. 100 + 81 101 config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY 82 102 bool "Map the console to the primary display device" 83 103 depends on FRAMEBUFFER_CONSOLE
+16
drivers/video/fbdev/core/bitblit.c
··· 43 43 } 44 44 } 45 45 46 + static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy, 47 + int sx, int dy, int dx, int height, int width) 48 + { 49 + struct fb_copyarea area; 50 + 51 + area.sx = sx * vc->vc_font.width; 52 + area.sy = sy * vc->vc_font.height; 53 + area.dx = dx * vc->vc_font.width; 54 + area.dy = dy * vc->vc_font.height; 55 + area.height = height * vc->vc_font.height; 56 + area.width = width * vc->vc_font.width; 57 + 58 + info->fbops->fb_copyarea(info, &area); 59 + } 60 + 46 61 static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy, 47 62 int sx, int height, int width) 48 63 { ··· 393 378 394 379 void fbcon_set_bitops(struct fbcon_ops *ops) 395 380 { 381 + ops->bmove = bit_bmove; 396 382 ops->clear = bit_clear; 397 383 ops->putcs = bit_putcs; 398 384 ops->clear_margins = bit_clear_margins;
+536 -21
drivers/video/fbdev/core/fbcon.c
··· 173 173 int count, int ypos, int xpos); 174 174 static void fbcon_clear_margins(struct vc_data *vc, int bottom_only); 175 175 static void fbcon_cursor(struct vc_data *vc, int mode); 176 + static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, 177 + int height, int width); 176 178 static int fbcon_switch(struct vc_data *vc); 177 179 static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); 178 180 static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table); ··· 182 180 /* 183 181 * Internal routines 184 182 */ 183 + static __inline__ void ywrap_up(struct vc_data *vc, int count); 184 + static __inline__ void ywrap_down(struct vc_data *vc, int count); 185 + static __inline__ void ypan_up(struct vc_data *vc, int count); 186 + static __inline__ void ypan_down(struct vc_data *vc, int count); 187 + static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx, 188 + int dy, int dx, int height, int width, u_int y_break); 185 189 static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, 186 190 int unit); 191 + static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, 192 + int line, int count, int dy); 187 193 static void fbcon_modechanged(struct fb_info *info); 188 194 static void fbcon_set_all_vcs(struct fb_info *info); 189 195 static void fbcon_start(void); ··· 1025 1015 struct vc_data *svc = *default_mode; 1026 1016 struct fbcon_display *t, *p = &fb_display[vc->vc_num]; 1027 1017 int logo = 1, new_rows, new_cols, rows, cols; 1028 - int ret; 1018 + int cap, ret; 1029 1019 1030 1020 if (WARN_ON(info_idx == -1)) 1031 1021 return; ··· 1034 1024 con2fb_map[vc->vc_num] = info_idx; 1035 1025 1036 1026 info = registered_fb[con2fb_map[vc->vc_num]]; 1027 + cap = info->flags; 1037 1028 1038 1029 if (logo_shown < 0 && console_loglevel <= CONSOLE_LOGLEVEL_QUIET) 1039 1030 logo_shown = FBCON_LOGO_DONTSHOW; ··· 1136 1125 1137 1126 ops->graphics = 0; 1138 1127 1128 + #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION 1129 + if ((cap & FBINFO_HWACCEL_COPYAREA) && 1130 + !(cap & FBINFO_HWACCEL_DISABLED)) 1131 + p->scrollmode = SCROLL_MOVE; 1132 + else /* default to something safe */ 1133 + p->scrollmode = SCROLL_REDRAW; 1134 + #endif 1135 + 1139 1136 /* 1140 1137 * ++guenther: console.c:vc_allocate() relies on initializing 1141 1138 * vc_{cols,rows}, but we must not set those if we are only ··· 1230 1211 * This system is now divided into two levels because of complications 1231 1212 * caused by hardware scrolling. Top level functions: 1232 1213 * 1233 - * fbcon_clear(), fbcon_putc(), fbcon_clear_margins() 1214 + * fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins() 1234 1215 * 1235 1216 * handles y values in range [0, scr_height-1] that correspond to real 1236 1217 * screen positions. y_wrap shift means that first line of bitmap may be 1237 1218 * anywhere on this display. These functions convert lineoffsets to 1238 1219 * bitmap offsets and deal with the wrap-around case by splitting blits. 1239 1220 * 1221 + * fbcon_bmove_physical_8() -- These functions fast implementations 1240 1222 * fbcon_clear_physical_8() -- of original fbcon_XXX fns. 1241 1223 * fbcon_putc_physical_8() -- (font width != 8) may be added later 1242 1224 * ··· 1410 1390 } 1411 1391 } 1412 1392 1393 + static __inline__ void ywrap_up(struct vc_data *vc, int count) 1394 + { 1395 + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1396 + struct fbcon_ops *ops = info->fbcon_par; 1397 + struct fbcon_display *p = &fb_display[vc->vc_num]; 1398 + 1399 + p->yscroll += count; 1400 + if (p->yscroll >= p->vrows) /* Deal with wrap */ 1401 + p->yscroll -= p->vrows; 1402 + ops->var.xoffset = 0; 1403 + ops->var.yoffset = p->yscroll * vc->vc_font.height; 1404 + ops->var.vmode |= FB_VMODE_YWRAP; 1405 + ops->update_start(info); 1406 + scrollback_max += count; 1407 + if (scrollback_max > scrollback_phys_max) 1408 + scrollback_max = scrollback_phys_max; 1409 + scrollback_current = 0; 1410 + } 1411 + 1412 + static __inline__ void ywrap_down(struct vc_data *vc, int count) 1413 + { 1414 + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1415 + struct fbcon_ops *ops = info->fbcon_par; 1416 + struct fbcon_display *p = &fb_display[vc->vc_num]; 1417 + 1418 + p->yscroll -= count; 1419 + if (p->yscroll < 0) /* Deal with wrap */ 1420 + p->yscroll += p->vrows; 1421 + ops->var.xoffset = 0; 1422 + ops->var.yoffset = p->yscroll * vc->vc_font.height; 1423 + ops->var.vmode |= FB_VMODE_YWRAP; 1424 + ops->update_start(info); 1425 + scrollback_max -= count; 1426 + if (scrollback_max < 0) 1427 + scrollback_max = 0; 1428 + scrollback_current = 0; 1429 + } 1430 + 1431 + static __inline__ void ypan_up(struct vc_data *vc, int count) 1432 + { 1433 + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1434 + struct fbcon_display *p = &fb_display[vc->vc_num]; 1435 + struct fbcon_ops *ops = info->fbcon_par; 1436 + 1437 + p->yscroll += count; 1438 + if (p->yscroll > p->vrows - vc->vc_rows) { 1439 + ops->bmove(vc, info, p->vrows - vc->vc_rows, 1440 + 0, 0, 0, vc->vc_rows, vc->vc_cols); 1441 + p->yscroll -= p->vrows - vc->vc_rows; 1442 + } 1443 + 1444 + ops->var.xoffset = 0; 1445 + ops->var.yoffset = p->yscroll * vc->vc_font.height; 1446 + ops->var.vmode &= ~FB_VMODE_YWRAP; 1447 + ops->update_start(info); 1448 + fbcon_clear_margins(vc, 1); 1449 + scrollback_max += count; 1450 + if (scrollback_max > scrollback_phys_max) 1451 + scrollback_max = scrollback_phys_max; 1452 + scrollback_current = 0; 1453 + } 1454 + 1455 + static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) 1456 + { 1457 + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1458 + struct fbcon_ops *ops = info->fbcon_par; 1459 + struct fbcon_display *p = &fb_display[vc->vc_num]; 1460 + 1461 + p->yscroll += count; 1462 + 1463 + if (p->yscroll > p->vrows - vc->vc_rows) { 1464 + p->yscroll -= p->vrows - vc->vc_rows; 1465 + fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); 1466 + } 1467 + 1468 + ops->var.xoffset = 0; 1469 + ops->var.yoffset = p->yscroll * vc->vc_font.height; 1470 + ops->var.vmode &= ~FB_VMODE_YWRAP; 1471 + ops->update_start(info); 1472 + fbcon_clear_margins(vc, 1); 1473 + scrollback_max += count; 1474 + if (scrollback_max > scrollback_phys_max) 1475 + scrollback_max = scrollback_phys_max; 1476 + scrollback_current = 0; 1477 + } 1478 + 1479 + static __inline__ void ypan_down(struct vc_data *vc, int count) 1480 + { 1481 + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1482 + struct fbcon_display *p = &fb_display[vc->vc_num]; 1483 + struct fbcon_ops *ops = info->fbcon_par; 1484 + 1485 + p->yscroll -= count; 1486 + if (p->yscroll < 0) { 1487 + ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, 1488 + 0, vc->vc_rows, vc->vc_cols); 1489 + p->yscroll += p->vrows - vc->vc_rows; 1490 + } 1491 + 1492 + ops->var.xoffset = 0; 1493 + ops->var.yoffset = p->yscroll * vc->vc_font.height; 1494 + ops->var.vmode &= ~FB_VMODE_YWRAP; 1495 + ops->update_start(info); 1496 + fbcon_clear_margins(vc, 1); 1497 + scrollback_max -= count; 1498 + if (scrollback_max < 0) 1499 + scrollback_max = 0; 1500 + scrollback_current = 0; 1501 + } 1502 + 1503 + static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) 1504 + { 1505 + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1506 + struct fbcon_ops *ops = info->fbcon_par; 1507 + struct fbcon_display *p = &fb_display[vc->vc_num]; 1508 + 1509 + p->yscroll -= count; 1510 + 1511 + if (p->yscroll < 0) { 1512 + p->yscroll += p->vrows - vc->vc_rows; 1513 + fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); 1514 + } 1515 + 1516 + ops->var.xoffset = 0; 1517 + ops->var.yoffset = p->yscroll * vc->vc_font.height; 1518 + ops->var.vmode &= ~FB_VMODE_YWRAP; 1519 + ops->update_start(info); 1520 + fbcon_clear_margins(vc, 1); 1521 + scrollback_max -= count; 1522 + if (scrollback_max < 0) 1523 + scrollback_max = 0; 1524 + scrollback_current = 0; 1525 + } 1526 + 1527 + static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, 1528 + int line, int count, int dy) 1529 + { 1530 + unsigned short *s = (unsigned short *) 1531 + (vc->vc_origin + vc->vc_size_row * line); 1532 + 1533 + while (count--) { 1534 + unsigned short *start = s; 1535 + unsigned short *le = advance_row(s, 1); 1536 + unsigned short c; 1537 + int x = 0; 1538 + unsigned short attr = 1; 1539 + 1540 + do { 1541 + c = scr_readw(s); 1542 + if (attr != (c & 0xff00)) { 1543 + attr = c & 0xff00; 1544 + if (s > start) { 1545 + fbcon_putcs(vc, start, s - start, 1546 + dy, x); 1547 + x += s - start; 1548 + start = s; 1549 + } 1550 + } 1551 + console_conditional_schedule(); 1552 + s++; 1553 + } while (s < le); 1554 + if (s > start) 1555 + fbcon_putcs(vc, start, s - start, dy, x); 1556 + console_conditional_schedule(); 1557 + dy++; 1558 + } 1559 + } 1560 + 1561 + static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, 1562 + struct fbcon_display *p, int line, int count, int ycount) 1563 + { 1564 + int offset = ycount * vc->vc_cols; 1565 + unsigned short *d = (unsigned short *) 1566 + (vc->vc_origin + vc->vc_size_row * line); 1567 + unsigned short *s = d + offset; 1568 + struct fbcon_ops *ops = info->fbcon_par; 1569 + 1570 + while (count--) { 1571 + unsigned short *start = s; 1572 + unsigned short *le = advance_row(s, 1); 1573 + unsigned short c; 1574 + int x = 0; 1575 + 1576 + do { 1577 + c = scr_readw(s); 1578 + 1579 + if (c == scr_readw(d)) { 1580 + if (s > start) { 1581 + ops->bmove(vc, info, line + ycount, x, 1582 + line, x, 1, s-start); 1583 + x += s - start + 1; 1584 + start = s + 1; 1585 + } else { 1586 + x++; 1587 + start++; 1588 + } 1589 + } 1590 + 1591 + scr_writew(c, d); 1592 + console_conditional_schedule(); 1593 + s++; 1594 + d++; 1595 + } while (s < le); 1596 + if (s > start) 1597 + ops->bmove(vc, info, line + ycount, x, line, x, 1, 1598 + s-start); 1599 + console_conditional_schedule(); 1600 + if (ycount > 0) 1601 + line++; 1602 + else { 1603 + line--; 1604 + /* NOTE: We subtract two lines from these pointers */ 1605 + s -= vc->vc_size_row; 1606 + d -= vc->vc_size_row; 1607 + } 1608 + } 1609 + } 1610 + 1413 1611 static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p, 1414 1612 int line, int count, int offset) 1415 1613 { ··· 1688 1450 { 1689 1451 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1690 1452 struct fbcon_display *p = &fb_display[vc->vc_num]; 1453 + int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; 1691 1454 1692 1455 if (fbcon_is_inactive(vc, info)) 1693 1456 return true; ··· 1705 1466 case SM_UP: 1706 1467 if (count > vc->vc_rows) /* Maximum realistic size */ 1707 1468 count = vc->vc_rows; 1708 - fbcon_redraw(vc, p, t, b - t - count, 1709 - count * vc->vc_cols); 1710 - fbcon_clear(vc, b - count, 0, count, vc->vc_cols); 1711 - scr_memsetw((unsigned short *) (vc->vc_origin + 1712 - vc->vc_size_row * 1713 - (b - count)), 1714 - vc->vc_video_erase_char, 1715 - vc->vc_size_row * count); 1716 - return true; 1469 + if (logo_shown >= 0) 1470 + goto redraw_up; 1471 + switch (fb_scrollmode(p)) { 1472 + case SCROLL_MOVE: 1473 + fbcon_redraw_blit(vc, info, p, t, b - t - count, 1474 + count); 1475 + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); 1476 + scr_memsetw((unsigned short *) (vc->vc_origin + 1477 + vc->vc_size_row * 1478 + (b - count)), 1479 + vc->vc_video_erase_char, 1480 + vc->vc_size_row * count); 1481 + return true; 1482 + 1483 + case SCROLL_WRAP_MOVE: 1484 + if (b - t - count > 3 * vc->vc_rows >> 2) { 1485 + if (t > 0) 1486 + fbcon_bmove(vc, 0, 0, count, 0, t, 1487 + vc->vc_cols); 1488 + ywrap_up(vc, count); 1489 + if (vc->vc_rows - b > 0) 1490 + fbcon_bmove(vc, b - count, 0, b, 0, 1491 + vc->vc_rows - b, 1492 + vc->vc_cols); 1493 + } else if (info->flags & FBINFO_READS_FAST) 1494 + fbcon_bmove(vc, t + count, 0, t, 0, 1495 + b - t - count, vc->vc_cols); 1496 + else 1497 + goto redraw_up; 1498 + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); 1499 + break; 1500 + 1501 + case SCROLL_PAN_REDRAW: 1502 + if ((p->yscroll + count <= 1503 + 2 * (p->vrows - vc->vc_rows)) 1504 + && ((!scroll_partial && (b - t == vc->vc_rows)) 1505 + || (scroll_partial 1506 + && (b - t - count > 1507 + 3 * vc->vc_rows >> 2)))) { 1508 + if (t > 0) 1509 + fbcon_redraw_move(vc, p, 0, t, count); 1510 + ypan_up_redraw(vc, t, count); 1511 + if (vc->vc_rows - b > 0) 1512 + fbcon_redraw_move(vc, p, b, 1513 + vc->vc_rows - b, b); 1514 + } else 1515 + fbcon_redraw_move(vc, p, t + count, b - t - count, t); 1516 + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); 1517 + break; 1518 + 1519 + case SCROLL_PAN_MOVE: 1520 + if ((p->yscroll + count <= 1521 + 2 * (p->vrows - vc->vc_rows)) 1522 + && ((!scroll_partial && (b - t == vc->vc_rows)) 1523 + || (scroll_partial 1524 + && (b - t - count > 1525 + 3 * vc->vc_rows >> 2)))) { 1526 + if (t > 0) 1527 + fbcon_bmove(vc, 0, 0, count, 0, t, 1528 + vc->vc_cols); 1529 + ypan_up(vc, count); 1530 + if (vc->vc_rows - b > 0) 1531 + fbcon_bmove(vc, b - count, 0, b, 0, 1532 + vc->vc_rows - b, 1533 + vc->vc_cols); 1534 + } else if (info->flags & FBINFO_READS_FAST) 1535 + fbcon_bmove(vc, t + count, 0, t, 0, 1536 + b - t - count, vc->vc_cols); 1537 + else 1538 + goto redraw_up; 1539 + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); 1540 + break; 1541 + 1542 + case SCROLL_REDRAW: 1543 + redraw_up: 1544 + fbcon_redraw(vc, p, t, b - t - count, 1545 + count * vc->vc_cols); 1546 + fbcon_clear(vc, b - count, 0, count, vc->vc_cols); 1547 + scr_memsetw((unsigned short *) (vc->vc_origin + 1548 + vc->vc_size_row * 1549 + (b - count)), 1550 + vc->vc_video_erase_char, 1551 + vc->vc_size_row * count); 1552 + return true; 1553 + } 1554 + break; 1717 1555 1718 1556 case SM_DOWN: 1719 1557 if (count > vc->vc_rows) /* Maximum realistic size */ 1720 1558 count = vc->vc_rows; 1721 - fbcon_redraw(vc, p, b - 1, b - t - count, 1722 - -count * vc->vc_cols); 1723 - fbcon_clear(vc, t, 0, count, vc->vc_cols); 1724 - scr_memsetw((unsigned short *) (vc->vc_origin + 1725 - vc->vc_size_row * 1726 - t), 1727 - vc->vc_video_erase_char, 1728 - vc->vc_size_row * count); 1729 - return true; 1559 + if (logo_shown >= 0) 1560 + goto redraw_down; 1561 + switch (fb_scrollmode(p)) { 1562 + case SCROLL_MOVE: 1563 + fbcon_redraw_blit(vc, info, p, b - 1, b - t - count, 1564 + -count); 1565 + fbcon_clear(vc, t, 0, count, vc->vc_cols); 1566 + scr_memsetw((unsigned short *) (vc->vc_origin + 1567 + vc->vc_size_row * 1568 + t), 1569 + vc->vc_video_erase_char, 1570 + vc->vc_size_row * count); 1571 + return true; 1572 + 1573 + case SCROLL_WRAP_MOVE: 1574 + if (b - t - count > 3 * vc->vc_rows >> 2) { 1575 + if (vc->vc_rows - b > 0) 1576 + fbcon_bmove(vc, b, 0, b - count, 0, 1577 + vc->vc_rows - b, 1578 + vc->vc_cols); 1579 + ywrap_down(vc, count); 1580 + if (t > 0) 1581 + fbcon_bmove(vc, count, 0, 0, 0, t, 1582 + vc->vc_cols); 1583 + } else if (info->flags & FBINFO_READS_FAST) 1584 + fbcon_bmove(vc, t, 0, t + count, 0, 1585 + b - t - count, vc->vc_cols); 1586 + else 1587 + goto redraw_down; 1588 + fbcon_clear(vc, t, 0, count, vc->vc_cols); 1589 + break; 1590 + 1591 + case SCROLL_PAN_MOVE: 1592 + if ((count - p->yscroll <= p->vrows - vc->vc_rows) 1593 + && ((!scroll_partial && (b - t == vc->vc_rows)) 1594 + || (scroll_partial 1595 + && (b - t - count > 1596 + 3 * vc->vc_rows >> 2)))) { 1597 + if (vc->vc_rows - b > 0) 1598 + fbcon_bmove(vc, b, 0, b - count, 0, 1599 + vc->vc_rows - b, 1600 + vc->vc_cols); 1601 + ypan_down(vc, count); 1602 + if (t > 0) 1603 + fbcon_bmove(vc, count, 0, 0, 0, t, 1604 + vc->vc_cols); 1605 + } else if (info->flags & FBINFO_READS_FAST) 1606 + fbcon_bmove(vc, t, 0, t + count, 0, 1607 + b - t - count, vc->vc_cols); 1608 + else 1609 + goto redraw_down; 1610 + fbcon_clear(vc, t, 0, count, vc->vc_cols); 1611 + break; 1612 + 1613 + case SCROLL_PAN_REDRAW: 1614 + if ((count - p->yscroll <= p->vrows - vc->vc_rows) 1615 + && ((!scroll_partial && (b - t == vc->vc_rows)) 1616 + || (scroll_partial 1617 + && (b - t - count > 1618 + 3 * vc->vc_rows >> 2)))) { 1619 + if (vc->vc_rows - b > 0) 1620 + fbcon_redraw_move(vc, p, b, vc->vc_rows - b, 1621 + b - count); 1622 + ypan_down_redraw(vc, t, count); 1623 + if (t > 0) 1624 + fbcon_redraw_move(vc, p, count, t, 0); 1625 + } else 1626 + fbcon_redraw_move(vc, p, t, b - t - count, t + count); 1627 + fbcon_clear(vc, t, 0, count, vc->vc_cols); 1628 + break; 1629 + 1630 + case SCROLL_REDRAW: 1631 + redraw_down: 1632 + fbcon_redraw(vc, p, b - 1, b - t - count, 1633 + -count * vc->vc_cols); 1634 + fbcon_clear(vc, t, 0, count, vc->vc_cols); 1635 + scr_memsetw((unsigned short *) (vc->vc_origin + 1636 + vc->vc_size_row * 1637 + t), 1638 + vc->vc_video_erase_char, 1639 + vc->vc_size_row * count); 1640 + return true; 1641 + } 1730 1642 } 1731 1643 return false; 1644 + } 1645 + 1646 + 1647 + static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, 1648 + int height, int width) 1649 + { 1650 + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1651 + struct fbcon_display *p = &fb_display[vc->vc_num]; 1652 + 1653 + if (fbcon_is_inactive(vc, info)) 1654 + return; 1655 + 1656 + if (!width || !height) 1657 + return; 1658 + 1659 + /* Split blits that cross physical y_wrap case. 1660 + * Pathological case involves 4 blits, better to use recursive 1661 + * code rather than unrolled case 1662 + * 1663 + * Recursive invocations don't need to erase the cursor over and 1664 + * over again, so we use fbcon_bmove_rec() 1665 + */ 1666 + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width, 1667 + p->vrows - p->yscroll); 1668 + } 1669 + 1670 + static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx, 1671 + int dy, int dx, int height, int width, u_int y_break) 1672 + { 1673 + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 1674 + struct fbcon_ops *ops = info->fbcon_par; 1675 + u_int b; 1676 + 1677 + if (sy < y_break && sy + height > y_break) { 1678 + b = y_break - sy; 1679 + if (dy < sy) { /* Avoid trashing self */ 1680 + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, 1681 + y_break); 1682 + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, 1683 + height - b, width, y_break); 1684 + } else { 1685 + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, 1686 + height - b, width, y_break); 1687 + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, 1688 + y_break); 1689 + } 1690 + return; 1691 + } 1692 + 1693 + if (dy < y_break && dy + height > y_break) { 1694 + b = y_break - dy; 1695 + if (dy < sy) { /* Avoid trashing self */ 1696 + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, 1697 + y_break); 1698 + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, 1699 + height - b, width, y_break); 1700 + } else { 1701 + fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, 1702 + height - b, width, y_break); 1703 + fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, 1704 + y_break); 1705 + } 1706 + return; 1707 + } 1708 + ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, 1709 + height, width); 1710 + } 1711 + 1712 + static void updatescrollmode_accel(struct fbcon_display *p, 1713 + struct fb_info *info, 1714 + struct vc_data *vc) 1715 + { 1716 + #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION 1717 + struct fbcon_ops *ops = info->fbcon_par; 1718 + int cap = info->flags; 1719 + u16 t = 0; 1720 + int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep, 1721 + info->fix.xpanstep); 1722 + int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t); 1723 + int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); 1724 + int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual, 1725 + info->var.xres_virtual); 1726 + int good_pan = (cap & FBINFO_HWACCEL_YPAN) && 1727 + divides(ypan, vc->vc_font.height) && vyres > yres; 1728 + int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) && 1729 + divides(ywrap, vc->vc_font.height) && 1730 + divides(vc->vc_font.height, vyres) && 1731 + divides(vc->vc_font.height, yres); 1732 + int reading_fast = cap & FBINFO_READS_FAST; 1733 + int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && 1734 + !(cap & FBINFO_HWACCEL_DISABLED); 1735 + int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && 1736 + !(cap & FBINFO_HWACCEL_DISABLED); 1737 + 1738 + if (good_wrap || good_pan) { 1739 + if (reading_fast || fast_copyarea) 1740 + p->scrollmode = good_wrap ? 1741 + SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE; 1742 + else 1743 + p->scrollmode = good_wrap ? SCROLL_REDRAW : 1744 + SCROLL_PAN_REDRAW; 1745 + } else { 1746 + if (reading_fast || (fast_copyarea && !fast_imageblit)) 1747 + p->scrollmode = SCROLL_MOVE; 1748 + else 1749 + p->scrollmode = SCROLL_REDRAW; 1750 + } 1751 + #endif 1732 1752 } 1733 1753 1734 1754 static void updatescrollmode(struct fbcon_display *p, ··· 2005 1507 p->vrows -= (yres - (fh * vc->vc_rows)) / fh; 2006 1508 if ((yres % fh) && (vyres % fh < yres % fh)) 2007 1509 p->vrows--; 1510 + 1511 + /* update scrollmode in case hardware acceleration is used */ 1512 + updatescrollmode_accel(p, info, vc); 2008 1513 } 2009 1514 2010 1515 #define PITCH(w) (((w) + 7) >> 3) ··· 2165 1664 2166 1665 updatescrollmode(p, info, vc); 2167 1666 2168 - scrollback_phys_max = 0; 1667 + switch (fb_scrollmode(p)) { 1668 + case SCROLL_WRAP_MOVE: 1669 + scrollback_phys_max = p->vrows - vc->vc_rows; 1670 + break; 1671 + case SCROLL_PAN_MOVE: 1672 + case SCROLL_PAN_REDRAW: 1673 + scrollback_phys_max = p->vrows - 2 * vc->vc_rows; 1674 + if (scrollback_phys_max < 0) 1675 + scrollback_phys_max = 0; 1676 + break; 1677 + default: 1678 + scrollback_phys_max = 0; 1679 + break; 1680 + } 1681 + 2169 1682 scrollback_max = 0; 2170 1683 scrollback_current = 0; 2171 1684
+72
drivers/video/fbdev/core/fbcon.h
··· 29 29 /* Filled in by the low-level console driver */ 30 30 const u_char *fontdata; 31 31 int userfont; /* != 0 if fontdata kmalloc()ed */ 32 + #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION 33 + u_short scrollmode; /* Scroll Method, use fb_scrollmode() */ 34 + #endif 32 35 u_short inverse; /* != 0 text black on white as default */ 33 36 short yscroll; /* Hardware scrolling */ 34 37 int vrows; /* number of virtual rows */ ··· 54 51 }; 55 52 56 53 struct fbcon_ops { 54 + void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, 55 + int sx, int dy, int dx, int height, int width); 57 56 void (*clear)(struct vc_data *vc, struct fb_info *info, int sy, 58 57 int sx, int height, int width); 59 58 void (*putcs)(struct vc_data *vc, struct fb_info *info, ··· 153 148 154 149 #define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0) 155 150 #define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1) 151 + 152 + /* 153 + * Scroll Method 154 + */ 155 + 156 + /* There are several methods fbcon can use to move text around the screen: 157 + * 158 + * Operation Pan Wrap 159 + *--------------------------------------------- 160 + * SCROLL_MOVE copyarea No No 161 + * SCROLL_PAN_MOVE copyarea Yes No 162 + * SCROLL_WRAP_MOVE copyarea No Yes 163 + * SCROLL_REDRAW imageblit No No 164 + * SCROLL_PAN_REDRAW imageblit Yes No 165 + * SCROLL_WRAP_REDRAW imageblit No Yes 166 + * 167 + * (SCROLL_WRAP_REDRAW is not implemented yet) 168 + * 169 + * In general, fbcon will choose the best scrolling 170 + * method based on the rule below: 171 + * 172 + * Pan/Wrap > accel imageblit > accel copyarea > 173 + * soft imageblit > (soft copyarea) 174 + * 175 + * Exception to the rule: Pan + accel copyarea is 176 + * preferred over Pan + accel imageblit. 177 + * 178 + * The above is typical for PCI/AGP cards. Unless 179 + * overridden, fbcon will never use soft copyarea. 180 + * 181 + * If you need to override the above rule, set the 182 + * appropriate flags in fb_info->flags. For example, 183 + * to prefer copyarea over imageblit, set 184 + * FBINFO_READS_FAST. 185 + * 186 + * Other notes: 187 + * + use the hardware engine to move the text 188 + * (hw-accelerated copyarea() and fillrect()) 189 + * + use hardware-supported panning on a large virtual screen 190 + * + amifb can not only pan, but also wrap the display by N lines 191 + * (i.e. visible line i = physical line (i+N) % yres). 192 + * + read what's already rendered on the screen and 193 + * write it in a different place (this is cfb_copyarea()) 194 + * + re-render the text to the screen 195 + * 196 + * Whether to use wrapping or panning can only be figured out at 197 + * runtime (when we know whether our font height is a multiple 198 + * of the pan/wrap step) 199 + * 200 + */ 201 + 202 + #define SCROLL_MOVE 0x001 203 + #define SCROLL_PAN_MOVE 0x002 204 + #define SCROLL_WRAP_MOVE 0x003 205 + #define SCROLL_REDRAW 0x004 206 + #define SCROLL_PAN_REDRAW 0x005 207 + 208 + static inline u_short fb_scrollmode(struct fbcon_display *fb) 209 + { 210 + #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION 211 + return fb->scrollmode; 212 + #else 213 + /* hardcoded to SCROLL_REDRAW if acceleration was disabled. */ 214 + return SCROLL_REDRAW; 215 + #endif 216 + } 217 + 156 218 157 219 #ifdef CONFIG_FB_TILEBLITTING 158 220 extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
+24 -4
drivers/video/fbdev/core/fbcon_ccw.c
··· 59 59 } 60 60 } 61 61 62 + 63 + static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy, 64 + int sx, int dy, int dx, int height, int width) 65 + { 66 + struct fbcon_ops *ops = info->fbcon_par; 67 + struct fb_copyarea area; 68 + u32 vyres = GETVYRES(ops->p, info); 69 + 70 + area.sx = sy * vc->vc_font.height; 71 + area.sy = vyres - ((sx + width) * vc->vc_font.width); 72 + area.dx = dy * vc->vc_font.height; 73 + area.dy = vyres - ((dx + width) * vc->vc_font.width); 74 + area.width = height * vc->vc_font.height; 75 + area.height = width * vc->vc_font.width; 76 + 77 + info->fbops->fb_copyarea(info, &area); 78 + } 79 + 62 80 static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy, 63 81 int sx, int height, int width) 64 82 { 83 + struct fbcon_ops *ops = info->fbcon_par; 65 84 struct fb_fillrect region; 66 85 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; 67 - u32 vyres = info->var.yres; 86 + u32 vyres = GETVYRES(ops->p, info); 68 87 69 88 region.color = attr_bgcol_ec(bgshift,vc,info); 70 89 region.dx = sy * vc->vc_font.height; ··· 140 121 u32 cnt, pitch, size; 141 122 u32 attribute = get_attribute(info, scr_readw(s)); 142 123 u8 *dst, *buf = NULL; 143 - u32 vyres = info->var.yres; 124 + u32 vyres = GETVYRES(ops->p, info); 144 125 145 126 if (!ops->fontbuffer) 146 127 return; ··· 229 210 int attribute, use_sw = vc->vc_cursor_type & CUR_SW; 230 211 int err = 1, dx, dy; 231 212 char *src; 232 - u32 vyres = info->var.yres; 213 + u32 vyres = GETVYRES(ops->p, info); 233 214 234 215 if (!ops->fontbuffer) 235 216 return; ··· 387 368 { 388 369 struct fbcon_ops *ops = info->fbcon_par; 389 370 u32 yoffset; 390 - u32 vyres = info->var.yres; 371 + u32 vyres = GETVYRES(ops->p, info); 391 372 int err; 392 373 393 374 yoffset = (vyres - info->var.yres) - ops->var.xoffset; ··· 402 383 403 384 void fbcon_rotate_ccw(struct fbcon_ops *ops) 404 385 { 386 + ops->bmove = ccw_bmove; 405 387 ops->clear = ccw_clear; 406 388 ops->putcs = ccw_putcs; 407 389 ops->clear_margins = ccw_clear_margins;
+24 -4
drivers/video/fbdev/core/fbcon_cw.c
··· 44 44 } 45 45 } 46 46 47 + 48 + static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy, 49 + int sx, int dy, int dx, int height, int width) 50 + { 51 + struct fbcon_ops *ops = info->fbcon_par; 52 + struct fb_copyarea area; 53 + u32 vxres = GETVXRES(ops->p, info); 54 + 55 + area.sx = vxres - ((sy + height) * vc->vc_font.height); 56 + area.sy = sx * vc->vc_font.width; 57 + area.dx = vxres - ((dy + height) * vc->vc_font.height); 58 + area.dy = dx * vc->vc_font.width; 59 + area.width = height * vc->vc_font.height; 60 + area.height = width * vc->vc_font.width; 61 + 62 + info->fbops->fb_copyarea(info, &area); 63 + } 64 + 47 65 static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy, 48 66 int sx, int height, int width) 49 67 { 68 + struct fbcon_ops *ops = info->fbcon_par; 50 69 struct fb_fillrect region; 51 70 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; 52 - u32 vxres = info->var.xres; 71 + u32 vxres = GETVXRES(ops->p, info); 53 72 54 73 region.color = attr_bgcol_ec(bgshift,vc,info); 55 74 region.dx = vxres - ((sy + height) * vc->vc_font.height); ··· 125 106 u32 cnt, pitch, size; 126 107 u32 attribute = get_attribute(info, scr_readw(s)); 127 108 u8 *dst, *buf = NULL; 128 - u32 vxres = info->var.xres; 109 + u32 vxres = GETVXRES(ops->p, info); 129 110 130 111 if (!ops->fontbuffer) 131 112 return; ··· 212 193 int attribute, use_sw = vc->vc_cursor_type & CUR_SW; 213 194 int err = 1, dx, dy; 214 195 char *src; 215 - u32 vxres = info->var.xres; 196 + u32 vxres = GETVXRES(ops->p, info); 216 197 217 198 if (!ops->fontbuffer) 218 199 return; ··· 369 350 static int cw_update_start(struct fb_info *info) 370 351 { 371 352 struct fbcon_ops *ops = info->fbcon_par; 372 - u32 vxres = info->var.xres; 353 + u32 vxres = GETVXRES(ops->p, info); 373 354 u32 xoffset; 374 355 int err; 375 356 ··· 385 366 386 367 void fbcon_rotate_cw(struct fbcon_ops *ops) 387 368 { 369 + ops->bmove = cw_bmove; 388 370 ops->clear = cw_clear; 389 371 ops->putcs = cw_putcs; 390 372 ops->clear_margins = cw_clear_margins;
+9
drivers/video/fbdev/core/fbcon_rotate.h
··· 11 11 #ifndef _FBCON_ROTATE_H 12 12 #define _FBCON_ROTATE_H 13 13 14 + #define GETVYRES(s,i) ({ \ 15 + (fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE) ? \ 16 + (i)->var.yres : (i)->var.yres_virtual; }) 17 + 18 + #define GETVXRES(s,i) ({ \ 19 + (fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE || !(i)->fix.xpanstep) ? \ 20 + (i)->var.xres : (i)->var.xres_virtual; }) 21 + 22 + 14 23 static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat) 15 24 { 16 25 u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
+29 -8
drivers/video/fbdev/core/fbcon_ud.c
··· 44 44 } 45 45 } 46 46 47 + 48 + static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy, 49 + int sx, int dy, int dx, int height, int width) 50 + { 51 + struct fbcon_ops *ops = info->fbcon_par; 52 + struct fb_copyarea area; 53 + u32 vyres = GETVYRES(ops->p, info); 54 + u32 vxres = GETVXRES(ops->p, info); 55 + 56 + area.sy = vyres - ((sy + height) * vc->vc_font.height); 57 + area.sx = vxres - ((sx + width) * vc->vc_font.width); 58 + area.dy = vyres - ((dy + height) * vc->vc_font.height); 59 + area.dx = vxres - ((dx + width) * vc->vc_font.width); 60 + area.height = height * vc->vc_font.height; 61 + area.width = width * vc->vc_font.width; 62 + 63 + info->fbops->fb_copyarea(info, &area); 64 + } 65 + 47 66 static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy, 48 67 int sx, int height, int width) 49 68 { 69 + struct fbcon_ops *ops = info->fbcon_par; 50 70 struct fb_fillrect region; 51 71 int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; 52 - u32 vyres = info->var.yres; 53 - u32 vxres = info->var.xres; 72 + u32 vyres = GETVYRES(ops->p, info); 73 + u32 vxres = GETVXRES(ops->p, info); 54 74 55 75 region.color = attr_bgcol_ec(bgshift,vc,info); 56 76 region.dy = vyres - ((sy + height) * vc->vc_font.height); ··· 162 142 u32 mod = vc->vc_font.width % 8, cnt, pitch, size; 163 143 u32 attribute = get_attribute(info, scr_readw(s)); 164 144 u8 *dst, *buf = NULL; 165 - u32 vyres = info->var.yres; 166 - u32 vxres = info->var.xres; 145 + u32 vyres = GETVYRES(ops->p, info); 146 + u32 vxres = GETVXRES(ops->p, info); 167 147 168 148 if (!ops->fontbuffer) 169 149 return; ··· 259 239 int attribute, use_sw = vc->vc_cursor_type & CUR_SW; 260 240 int err = 1, dx, dy; 261 241 char *src; 262 - u32 vyres = info->var.yres; 263 - u32 vxres = info->var.xres; 242 + u32 vyres = GETVYRES(ops->p, info); 243 + u32 vxres = GETVXRES(ops->p, info); 264 244 265 245 if (!ops->fontbuffer) 266 246 return; ··· 410 390 { 411 391 struct fbcon_ops *ops = info->fbcon_par; 412 392 int xoffset, yoffset; 413 - u32 vyres = info->var.yres; 414 - u32 vxres = info->var.xres; 393 + u32 vyres = GETVYRES(ops->p, info); 394 + u32 vxres = GETVXRES(ops->p, info); 415 395 int err; 416 396 417 397 xoffset = vxres - info->var.xres - ops->var.xoffset; ··· 429 409 430 410 void fbcon_rotate_ud(struct fbcon_ops *ops) 431 411 { 412 + ops->bmove = ud_bmove; 432 413 ops->clear = ud_clear; 433 414 ops->putcs = ud_putcs; 434 415 ops->clear_margins = ud_clear_margins;
+16
drivers/video/fbdev/core/tileblit.c
··· 16 16 #include <asm/types.h> 17 17 #include "fbcon.h" 18 18 19 + static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy, 20 + int sx, int dy, int dx, int height, int width) 21 + { 22 + struct fb_tilearea area; 23 + 24 + area.sx = sx; 25 + area.sy = sy; 26 + area.dx = dx; 27 + area.dy = dy; 28 + area.height = height; 29 + area.width = width; 30 + 31 + info->tileops->fb_tilecopy(info, &area); 32 + } 33 + 19 34 static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy, 20 35 int sx, int height, int width) 21 36 { ··· 133 118 struct fb_tilemap map; 134 119 struct fbcon_ops *ops = info->fbcon_par; 135 120 121 + ops->bmove = tile_bmove; 136 122 ops->clear = tile_clear; 137 123 ops->putcs = tile_putcs; 138 124 ops->clear_margins = tile_clear_margins;
+6 -6
drivers/video/fbdev/skeletonfb.c
··· 505 505 } 506 506 507 507 /** 508 - * xxxfb_copyarea - OBSOLETE function. 508 + * xxxfb_copyarea - REQUIRED function. Can use generic routines if 509 + * non acclerated hardware and packed pixel based. 509 510 * Copies one area of the screen to another area. 510 - * Will be deleted in a future version 511 511 * 512 512 * @info: frame buffer structure that represents a single frame buffer 513 513 * @area: Structure providing the data to copy the framebuffer contents 514 514 * from one region to another. 515 515 * 516 - * This drawing operation copied a rectangular area from one area of the 516 + * This drawing operation copies a rectangular area from one area of the 517 517 * screen to another area. 518 518 */ 519 519 void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) ··· 645 645 .fb_setcolreg = xxxfb_setcolreg, 646 646 .fb_blank = xxxfb_blank, 647 647 .fb_pan_display = xxxfb_pan_display, 648 - .fb_fillrect = xxxfb_fillrect, /* Needed !!! */ 649 - .fb_copyarea = xxxfb_copyarea, /* Obsolete */ 650 - .fb_imageblit = xxxfb_imageblit, /* Needed !!! */ 648 + .fb_fillrect = xxxfb_fillrect, /* Needed !!! */ 649 + .fb_copyarea = xxxfb_copyarea, /* Needed !!! */ 650 + .fb_imageblit = xxxfb_imageblit, /* Needed !!! */ 651 651 .fb_cursor = xxxfb_cursor, /* Optional !!! */ 652 652 .fb_sync = xxxfb_sync, 653 653 .fb_ioctl = xxxfb_ioctl,
+1 -1
include/linux/fb.h
··· 262 262 263 263 /* Draws a rectangle */ 264 264 void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect); 265 - /* Copy data from area to another. Obsolete. */ 265 + /* Copy data from area to another */ 266 266 void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region); 267 267 /* Draws a image to the display */ 268 268 void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);