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-2024-08-02' of https://gitlab.freedesktop.org/drm/kernel

Pull drm fixes from Dave Airlie:
"Regular weekly fixes. This is a bit larger than usual but doesn't seem
too crazy.

Most of it is vmwgfx changes that fix a bunch of issues with wayland
userspaces with dma-buf/external buffers and modesetting fixes.

Otherwise it's kinda spread out, v3d fixes some new ioctls, nouveau
has regression revert and fixes, amdgpu, i915 and ast have some small
fixes, and some core fixes spread about.

client:
- fix error code

atomic:
- allow damage clips with async flips
- allow explicit sync with async flips

kselftests:
- fix dmabuf-heaps test

panic:
- fix schedule_work in panic paths

panel:
- fix OrangePi Neo orientation

gpuvm:
- fix missing dependency

amdgpu:
- SMU 14.x update
- Fix contiguous VRAM handling for IB parsing
- GFX 12 fix
- Regression fix for old APUs

i915:
- Static analysis fix for int overflow
- Fix for HDCP2_STREAM_STATUS macro and removal of PWR_CLK_STATE for gen12

nouveau:
- revert busy wait change that caused a resume regression
- fix buffer placement fault on dynamic pm s/r
- fix refcount underflow

ast:
- fix black screen on resume
- wake during connector status detect

v3d:
- fix issues with perf/timestamp ioctls

vmwgfx:
- fix deadlock in dma-buf fence polling
- fix screen surface refcounting
- fix dumb buffer handling
- fix support for external buffers
- fix overlay with screen targets
- trigger modeset on screen moves"

* tag 'drm-fixes-2024-08-02' of https://gitlab.freedesktop.org/drm/kernel: (31 commits)
Revert "nouveau: rip out busy fence waits"
nouveau: set placement to original placement on uvmm validate.
drm/atomic: Allow userspace to use damage clips with async flips
drm/atomic: Allow userspace to use explicit sync with atomic async flips
drm/i915: Fix possible int overflow in skl_ddi_calculate_wrpll()
drm/i915/hdcp: Fix HDCP2_STREAM_STATUS macro
drm/ast: astdp: Wake up during connector status detection
i915/perf: Remove code to update PWR_CLK_STATE for gen12
kselftests: dmabuf-heaps: Ensure the driver name is null-terminated
drm/client: Fix error code in drm_client_buffer_vmap_local()
drm/amdgpu: Fix APU handling in amdgpu_pm_load_smu_firmware()
drm/amdgpu: increase mes log buffer size for gfx12
drm/amdgpu: fix contiguous handling for IB parsing v2
drm/amdgpu/pm: support gpu_metrics sysfs interface for smu v14.0.2/3
drm/vmwgfx: Trigger a modeset when the screen moves
drm/vmwgfx: Fix overlay when using Screen Targets
drm/vmwgfx: Add basic support for external buffers
drm/vmwgfx: Fix handling of dumb buffers
drm/vmwgfx: Make sure the screen surface is ref counted
drm/vmwgfx: Fix a deadlock in dma buf fence polling
...

+1203 -651
+1
drivers/gpu/drm/Kconfig
··· 268 268 config DRM_GPUVM 269 269 tristate 270 270 depends on DRM 271 + select DRM_EXEC 271 272 help 272 273 GPU-VM representation providing helpers to manage a GPUs virtual 273 274 address space
+8 -8
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
··· 1778 1778 struct ttm_operation_ctx ctx = { false, false }; 1779 1779 struct amdgpu_vm *vm = &fpriv->vm; 1780 1780 struct amdgpu_bo_va_mapping *mapping; 1781 - int r; 1781 + int i, r; 1782 1782 1783 1783 addr /= AMDGPU_GPU_PAGE_SIZE; 1784 1784 ··· 1793 1793 if (dma_resv_locking_ctx((*bo)->tbo.base.resv) != &parser->exec.ticket) 1794 1794 return -EINVAL; 1795 1795 1796 - if (!((*bo)->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)) { 1797 - (*bo)->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; 1798 - amdgpu_bo_placement_from_domain(*bo, (*bo)->allowed_domains); 1799 - r = ttm_bo_validate(&(*bo)->tbo, &(*bo)->placement, &ctx); 1800 - if (r) 1801 - return r; 1802 - } 1796 + (*bo)->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; 1797 + amdgpu_bo_placement_from_domain(*bo, (*bo)->allowed_domains); 1798 + for (i = 0; i < (*bo)->placement.num_placement; i++) 1799 + (*bo)->placements[i].flags |= TTM_PL_FLAG_CONTIGUOUS; 1800 + r = ttm_bo_validate(&(*bo)->tbo, &(*bo)->placement, &ctx); 1801 + if (r) 1802 + return r; 1803 1803 1804 1804 return amdgpu_ttm_alloc_gart(&(*bo)->tbo); 1805 1805 }
+3 -3
drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
··· 103 103 if (!amdgpu_mes_log_enable) 104 104 return 0; 105 105 106 - r = amdgpu_bo_create_kernel(adev, AMDGPU_MES_LOG_BUFFER_SIZE, PAGE_SIZE, 106 + r = amdgpu_bo_create_kernel(adev, adev->mes.event_log_size, PAGE_SIZE, 107 107 AMDGPU_GEM_DOMAIN_GTT, 108 108 &adev->mes.event_log_gpu_obj, 109 109 &adev->mes.event_log_gpu_addr, ··· 113 113 return r; 114 114 } 115 115 116 - memset(adev->mes.event_log_cpu_addr, 0, PAGE_SIZE); 116 + memset(adev->mes.event_log_cpu_addr, 0, adev->mes.event_log_size); 117 117 118 118 return 0; 119 119 ··· 1573 1573 uint32_t *mem = (uint32_t *)(adev->mes.event_log_cpu_addr); 1574 1574 1575 1575 seq_hex_dump(m, "", DUMP_PREFIX_OFFSET, 32, 4, 1576 - mem, AMDGPU_MES_LOG_BUFFER_SIZE, false); 1576 + mem, adev->mes.event_log_size, false); 1577 1577 1578 1578 return 0; 1579 1579 }
+3 -3
drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
··· 52 52 53 53 #define AMDGPU_MES_PROC_CTX_SIZE 0x1000 /* one page area */ 54 54 #define AMDGPU_MES_GANG_CTX_SIZE 0x1000 /* one page area */ 55 - #define AMDGPU_MES_LOG_BUFFER_SIZE 0x4000 /* Maximu log buffer size for MES */ 56 55 57 56 struct amdgpu_mes_funcs; 58 57 ··· 134 135 unsigned long *doorbell_bitmap; 135 136 136 137 /* MES event log buffer */ 137 - struct amdgpu_bo *event_log_gpu_obj; 138 - uint64_t event_log_gpu_addr; 138 + uint32_t event_log_size; 139 + struct amdgpu_bo *event_log_gpu_obj; 140 + uint64_t event_log_gpu_addr; 139 141 void *event_log_cpu_addr; 140 142 141 143 /* ip specific functions */
+2
drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
··· 1163 1163 adev->mes.kiq_hw_init = &mes_v11_0_kiq_hw_init; 1164 1164 adev->mes.kiq_hw_fini = &mes_v11_0_kiq_hw_fini; 1165 1165 1166 + adev->mes.event_log_size = AMDGPU_MES_LOG_BUFFER_SIZE; 1167 + 1166 1168 r = amdgpu_mes_init(adev); 1167 1169 if (r) 1168 1170 return r;
+6 -2
drivers/gpu/drm/amd/amdgpu/mes_v12_0.c
··· 551 551 mes_set_hw_res_pkt.oversubscription_timer = 50; 552 552 mes_set_hw_res_pkt.unmapped_doorbell_handling = 1; 553 553 554 - mes_set_hw_res_pkt.enable_mes_event_int_logging = 0; 555 - mes_set_hw_res_pkt.event_intr_history_gpu_mc_ptr = mes->event_log_gpu_addr; 554 + if (amdgpu_mes_log_enable) { 555 + mes_set_hw_res_pkt.enable_mes_event_int_logging = 1; 556 + mes_set_hw_res_pkt.event_intr_history_gpu_mc_ptr = mes->event_log_gpu_addr; 557 + } 556 558 557 559 return mes_v12_0_submit_pkt_and_poll_completion(mes, 558 560 &mes_set_hw_res_pkt, sizeof(mes_set_hw_res_pkt), ··· 1238 1236 adev->mes.funcs = &mes_v12_0_funcs; 1239 1237 adev->mes.kiq_hw_init = &mes_v12_0_kiq_hw_init; 1240 1238 adev->mes.kiq_hw_fini = &mes_v12_0_kiq_hw_fini; 1239 + 1240 + adev->mes.event_log_size = AMDGPU_MES_LOG_BUFFER_SIZE; 1241 1241 1242 1242 r = amdgpu_mes_init(adev); 1243 1243 if (r)
+3
drivers/gpu/drm/amd/include/mes_v11_api_def.h
··· 28 28 29 29 #define MES_API_VERSION 1 30 30 31 + /* Maximum log buffer size for MES. Needs to be updated if MES expands MES_EVT_INTR_HIST_LOG */ 32 + #define AMDGPU_MES_LOG_BUFFER_SIZE 0x4000 33 + 31 34 /* Driver submits one API(cmd) as a single Frame and this command size is same 32 35 * for all API to ease the debugging and parsing of ring buffer. 33 36 */
+3
drivers/gpu/drm/amd/include/mes_v12_api_def.h
··· 28 28 29 29 #define MES_API_VERSION 0x14 30 30 31 + /* Maximum log buffer size for MES. Needs to be updated if MES expands MES_EVT_INTR_HIST_LOG_12 */ 32 + #define AMDGPU_MES_LOG_BUFFER_SIZE 0xC000 33 + 31 34 /* Driver submits one API(cmd) as a single Frame and this command size is same for all API 32 35 * to ease the debugging and parsing of ring buffer. 33 36 */
+2 -1
drivers/gpu/drm/amd/pm/amdgpu_dpm.c
··· 618 618 const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; 619 619 int r = 0; 620 620 621 - if (!pp_funcs || !pp_funcs->load_firmware || adev->flags & AMD_IS_APU) 621 + if (!pp_funcs || !pp_funcs->load_firmware || 622 + (is_support_sw_smu(adev) && (adev->flags & AMD_IS_APU))) 622 623 return 0; 623 624 624 625 mutex_lock(&adev->pm.mutex);
+84 -2
drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
··· 66 66 67 67 #define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000 68 68 #define DEBUGSMC_MSG_Mode1Reset 2 69 + #define LINK_SPEED_MAX 3 69 70 70 71 static struct cmn2asic_msg_mapping smu_v14_0_2_message_map[SMU_MSG_MAX_COUNT] = { 71 72 MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), ··· 222 221 WORKLOAD_MAP(PP_SMC_POWER_PROFILE_WINDOW3D, WORKLOAD_PPLIB_WINDOW_3D_BIT), 223 222 }; 224 223 225 - #if 0 226 224 static const uint8_t smu_v14_0_2_throttler_map[] = { 227 225 [THROTTLER_PPT0_BIT] = (SMU_THROTTLER_PPT0_BIT), 228 226 [THROTTLER_PPT1_BIT] = (SMU_THROTTLER_PPT1_BIT), ··· 241 241 [THROTTLER_GFX_APCC_PLUS_BIT] = (SMU_THROTTLER_APCC_BIT), 242 242 [THROTTLER_FIT_BIT] = (SMU_THROTTLER_FIT_BIT), 243 243 }; 244 - #endif 245 244 246 245 static int 247 246 smu_v14_0_2_get_allowed_feature_mask(struct smu_context *smu, ··· 1868 1869 return ret; 1869 1870 } 1870 1871 1872 + static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu, 1873 + void **table) 1874 + { 1875 + struct smu_table_context *smu_table = &smu->smu_table; 1876 + struct gpu_metrics_v1_3 *gpu_metrics = 1877 + (struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table; 1878 + SmuMetricsExternal_t metrics_ext; 1879 + SmuMetrics_t *metrics = &metrics_ext.SmuMetrics; 1880 + int ret = 0; 1881 + 1882 + ret = smu_cmn_get_metrics_table(smu, 1883 + &metrics_ext, 1884 + true); 1885 + if (ret) 1886 + return ret; 1887 + 1888 + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3); 1889 + 1890 + gpu_metrics->temperature_edge = metrics->AvgTemperature[TEMP_EDGE]; 1891 + gpu_metrics->temperature_hotspot = metrics->AvgTemperature[TEMP_HOTSPOT]; 1892 + gpu_metrics->temperature_mem = metrics->AvgTemperature[TEMP_MEM]; 1893 + gpu_metrics->temperature_vrgfx = metrics->AvgTemperature[TEMP_VR_GFX]; 1894 + gpu_metrics->temperature_vrsoc = metrics->AvgTemperature[TEMP_VR_SOC]; 1895 + gpu_metrics->temperature_vrmem = max(metrics->AvgTemperature[TEMP_VR_MEM0], 1896 + metrics->AvgTemperature[TEMP_VR_MEM1]); 1897 + 1898 + gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity; 1899 + gpu_metrics->average_umc_activity = metrics->AverageUclkActivity; 1900 + gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage, 1901 + metrics->Vcn1ActivityPercentage); 1902 + 1903 + gpu_metrics->average_socket_power = metrics->AverageSocketPower; 1904 + gpu_metrics->energy_accumulator = metrics->EnergyAccumulator; 1905 + 1906 + if (metrics->AverageGfxActivity <= SMU_14_0_2_BUSY_THRESHOLD) 1907 + gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs; 1908 + else 1909 + gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs; 1910 + 1911 + if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD) 1912 + gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs; 1913 + else 1914 + gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs; 1915 + 1916 + gpu_metrics->average_vclk0_frequency = metrics->AverageVclk0Frequency; 1917 + gpu_metrics->average_dclk0_frequency = metrics->AverageDclk0Frequency; 1918 + gpu_metrics->average_vclk1_frequency = metrics->AverageVclk1Frequency; 1919 + gpu_metrics->average_dclk1_frequency = metrics->AverageDclk1Frequency; 1920 + 1921 + gpu_metrics->current_gfxclk = gpu_metrics->average_gfxclk_frequency; 1922 + gpu_metrics->current_socclk = metrics->CurrClock[PPCLK_SOCCLK]; 1923 + gpu_metrics->current_uclk = metrics->CurrClock[PPCLK_UCLK]; 1924 + gpu_metrics->current_vclk0 = metrics->CurrClock[PPCLK_VCLK_0]; 1925 + gpu_metrics->current_dclk0 = metrics->CurrClock[PPCLK_DCLK_0]; 1926 + gpu_metrics->current_vclk1 = metrics->CurrClock[PPCLK_VCLK_0]; 1927 + gpu_metrics->current_dclk1 = metrics->CurrClock[PPCLK_DCLK_0]; 1928 + 1929 + gpu_metrics->throttle_status = 1930 + smu_v14_0_2_get_throttler_status(metrics); 1931 + gpu_metrics->indep_throttle_status = 1932 + smu_cmn_get_indep_throttler_status(gpu_metrics->throttle_status, 1933 + smu_v14_0_2_throttler_map); 1934 + 1935 + gpu_metrics->current_fan_speed = metrics->AvgFanRpm; 1936 + 1937 + gpu_metrics->pcie_link_width = metrics->PcieWidth; 1938 + if ((metrics->PcieRate - 1) > LINK_SPEED_MAX) 1939 + gpu_metrics->pcie_link_speed = pcie_gen_to_speed(1); 1940 + else 1941 + gpu_metrics->pcie_link_speed = pcie_gen_to_speed(metrics->PcieRate); 1942 + 1943 + gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); 1944 + 1945 + gpu_metrics->voltage_gfx = metrics->AvgVoltage[SVI_PLANE_VDD_GFX]; 1946 + gpu_metrics->voltage_soc = metrics->AvgVoltage[SVI_PLANE_VDD_SOC]; 1947 + gpu_metrics->voltage_mem = metrics->AvgVoltage[SVI_PLANE_VDDIO_MEM]; 1948 + 1949 + *table = (void *)gpu_metrics; 1950 + 1951 + return sizeof(struct gpu_metrics_v1_3); 1952 + } 1953 + 1871 1954 static const struct pptable_funcs smu_v14_0_2_ppt_funcs = { 1872 1955 .get_allowed_feature_mask = smu_v14_0_2_get_allowed_feature_mask, 1873 1956 .set_default_dpm_table = smu_v14_0_2_set_default_dpm_table, ··· 1986 1905 .enable_thermal_alert = smu_v14_0_enable_thermal_alert, 1987 1906 .disable_thermal_alert = smu_v14_0_disable_thermal_alert, 1988 1907 .notify_memory_pool_location = smu_v14_0_notify_memory_pool_location, 1908 + .get_gpu_metrics = smu_v14_0_2_get_gpu_metrics, 1989 1909 .set_soft_freq_limited_range = smu_v14_0_set_soft_freq_limited_range, 1990 1910 .init_pptable_microcode = smu_v14_0_init_pptable_microcode, 1991 1911 .populate_umd_state_clk = smu_v14_0_2_populate_umd_state_clk,
+7
drivers/gpu/drm/ast/ast_dp.c
··· 158 158 ASTDP_HOST_EDID_READ_DONE); 159 159 } 160 160 161 + bool ast_dp_power_is_on(struct ast_device *ast) 162 + { 163 + u8 vgacre3; 161 164 165 + vgacre3 = ast_get_index_reg(ast, AST_IO_VGACRI, 0xe3); 166 + 167 + return !(vgacre3 & AST_DP_PHY_SLEEP); 168 + } 162 169 163 170 void ast_dp_power_on_off(struct drm_device *dev, bool on) 164 171 {
+5
drivers/gpu/drm/ast/ast_drv.c
··· 391 391 392 392 static int ast_drm_thaw(struct drm_device *dev) 393 393 { 394 + struct ast_device *ast = to_ast_device(dev); 395 + 396 + ast_enable_vga(ast->ioregs); 397 + ast_open_key(ast->ioregs); 398 + ast_enable_mmio(dev->dev, ast->ioregs); 394 399 ast_post_gpu(dev); 395 400 396 401 return drm_mode_config_helper_resume(dev);
+1
drivers/gpu/drm/ast/ast_drv.h
··· 472 472 bool ast_astdp_is_connected(struct ast_device *ast); 473 473 int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata); 474 474 void ast_dp_launch(struct drm_device *dev); 475 + bool ast_dp_power_is_on(struct ast_device *ast); 475 476 void ast_dp_power_on_off(struct drm_device *dev, bool no); 476 477 void ast_dp_set_on_off(struct drm_device *dev, bool no); 477 478 void ast_dp_set_mode(struct drm_crtc *crtc, struct ast_vbios_mode_info *vbios_mode);
+27 -2
drivers/gpu/drm/ast/ast_mode.c
··· 28 28 * Authors: Dave Airlie <airlied@redhat.com> 29 29 */ 30 30 31 + #include <linux/delay.h> 31 32 #include <linux/export.h> 32 33 #include <linux/pci.h> 33 34 ··· 1688 1687 struct drm_modeset_acquire_ctx *ctx, 1689 1688 bool force) 1690 1689 { 1690 + struct drm_device *dev = connector->dev; 1691 1691 struct ast_device *ast = to_ast_device(connector->dev); 1692 + enum drm_connector_status status = connector_status_disconnected; 1693 + struct drm_connector_state *connector_state = connector->state; 1694 + bool is_active = false; 1695 + 1696 + mutex_lock(&ast->modeset_lock); 1697 + 1698 + if (connector_state && connector_state->crtc) { 1699 + struct drm_crtc_state *crtc_state = connector_state->crtc->state; 1700 + 1701 + if (crtc_state && crtc_state->active) 1702 + is_active = true; 1703 + } 1704 + 1705 + if (!is_active && !ast_dp_power_is_on(ast)) { 1706 + ast_dp_power_on_off(dev, true); 1707 + msleep(50); 1708 + } 1692 1709 1693 1710 if (ast_astdp_is_connected(ast)) 1694 - return connector_status_connected; 1695 - return connector_status_disconnected; 1711 + status = connector_status_connected; 1712 + 1713 + if (!is_active && status == connector_status_disconnected) 1714 + ast_dp_power_on_off(dev, false); 1715 + 1716 + mutex_unlock(&ast->modeset_lock); 1717 + 1718 + return status; 1696 1719 } 1697 1720 1698 1721 static const struct drm_connector_helper_funcs ast_astdp_connector_helper_funcs = {
+4 -1
drivers/gpu/drm/drm_atomic_uapi.c
··· 1070 1070 break; 1071 1071 } 1072 1072 1073 - if (async_flip && prop != config->prop_fb_id) { 1073 + if (async_flip && 1074 + prop != config->prop_fb_id && 1075 + prop != config->prop_in_fence_fd && 1076 + prop != config->prop_fb_damage_clips) { 1074 1077 ret = drm_atomic_plane_get_property(plane, plane_state, 1075 1078 prop, &old_val); 1076 1079 ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop);
+1 -1
drivers/gpu/drm/drm_client.c
··· 355 355 356 356 err_drm_gem_vmap_unlocked: 357 357 drm_gem_unlock(gem); 358 - return 0; 358 + return ret; 359 359 } 360 360 EXPORT_SYMBOL(drm_client_buffer_vmap_local); 361 361
+11
drivers/gpu/drm/drm_fb_helper.c
··· 624 624 static void drm_fb_helper_damage(struct drm_fb_helper *helper, u32 x, u32 y, 625 625 u32 width, u32 height) 626 626 { 627 + /* 628 + * This function may be invoked by panic() to flush the frame 629 + * buffer, where all CPUs except the panic CPU are stopped. 630 + * During the following schedule_work(), the panic CPU needs 631 + * the worker_pool lock, which might be held by a stopped CPU, 632 + * causing schedule_work() and panic() to block. Return early on 633 + * oops_in_progress to prevent this blocking. 634 + */ 635 + if (oops_in_progress) 636 + return; 637 + 627 638 drm_fb_helper_add_damage_clip(helper, x, y, width, height); 628 639 629 640 schedule_work(&helper->damage_work);
+6
drivers/gpu/drm/drm_panel_orientation_quirks.c
··· 414 414 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ONE XPLAYER"), 415 415 }, 416 416 .driver_data = (void *)&lcd1600x2560_leftside_up, 417 + }, { /* OrangePi Neo */ 418 + .matches = { 419 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "OrangePi"), 420 + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "NEO-01"), 421 + }, 422 + .driver_data = (void *)&lcd1200x1920_rightside_up, 417 423 }, { /* Samsung GalaxyBook 10.6 */ 418 424 .matches = { 419 425 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+3 -3
drivers/gpu/drm/i915/display/intel_dpll_mgr.c
··· 1658 1658 } 1659 1659 1660 1660 static int 1661 - skl_ddi_calculate_wrpll(int clock /* in Hz */, 1661 + skl_ddi_calculate_wrpll(int clock, 1662 1662 int ref_clock, 1663 1663 struct skl_wrpll_params *wrpll_params) 1664 1664 { ··· 1683 1683 }; 1684 1684 unsigned int dco, d, i; 1685 1685 unsigned int p0, p1, p2; 1686 - u64 afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */ 1686 + u64 afe_clock = (u64)clock * 1000 * 5; /* AFE Clock is 5x Pixel clock, in Hz */ 1687 1687 1688 1688 for (d = 0; d < ARRAY_SIZE(dividers); d++) { 1689 1689 for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) { ··· 1808 1808 struct skl_wrpll_params wrpll_params = {}; 1809 1809 int ret; 1810 1810 1811 - ret = skl_ddi_calculate_wrpll(crtc_state->port_clock * 1000, 1811 + ret = skl_ddi_calculate_wrpll(crtc_state->port_clock, 1812 1812 i915->display.dpll.ref_clks.nssc, &wrpll_params); 1813 1813 if (ret) 1814 1814 return ret;
+1 -1
drivers/gpu/drm/i915/display/intel_hdcp_regs.h
··· 251 251 #define HDCP2_STREAM_STATUS(dev_priv, trans, port) \ 252 252 (TRANS_HDCP(dev_priv) ? \ 253 253 TRANS_HDCP2_STREAM_STATUS(trans) : \ 254 - PIPE_HDCP2_STREAM_STATUS(pipe)) 254 + PIPE_HDCP2_STREAM_STATUS(port)) 255 255 256 256 #define _PORTA_HDCP2_AUTH_STREAM 0x66F00 257 257 #define _PORTB_HDCP2_AUTH_STREAM 0x66F04
-33
drivers/gpu/drm/i915/i915_perf.c
··· 2749 2749 } 2750 2750 2751 2751 static int 2752 - gen12_configure_all_contexts(struct i915_perf_stream *stream, 2753 - const struct i915_oa_config *oa_config, 2754 - struct i915_active *active) 2755 - { 2756 - struct flex regs[] = { 2757 - { 2758 - GEN8_R_PWR_CLK_STATE(RENDER_RING_BASE), 2759 - CTX_R_PWR_CLK_STATE, 2760 - }, 2761 - }; 2762 - 2763 - if (stream->engine->class != RENDER_CLASS) 2764 - return 0; 2765 - 2766 - return oa_configure_all_contexts(stream, 2767 - regs, ARRAY_SIZE(regs), 2768 - active); 2769 - } 2770 - 2771 - static int 2772 2752 lrc_configure_all_contexts(struct i915_perf_stream *stream, 2773 2753 const struct i915_oa_config *oa_config, 2774 2754 struct i915_active *active) ··· 2854 2874 { 2855 2875 struct drm_i915_private *i915 = stream->perf->i915; 2856 2876 struct intel_uncore *uncore = stream->uncore; 2857 - struct i915_oa_config *oa_config = stream->oa_config; 2858 2877 bool periodic = stream->periodic; 2859 2878 u32 period_exponent = stream->period_exponent; 2860 2879 u32 sqcnt1; ··· 2896 2917 (HAS_OA_BPC_REPORTING(i915) ? GEN12_SQCNT1_OABPC : 0); 2897 2918 2898 2919 intel_uncore_rmw(uncore, GEN12_SQCNT1, 0, sqcnt1); 2899 - 2900 - /* 2901 - * Update all contexts prior writing the mux configurations as we need 2902 - * to make sure all slices/subslices are ON before writing to NOA 2903 - * registers. 2904 - */ 2905 - ret = gen12_configure_all_contexts(stream, oa_config, active); 2906 - if (ret) 2907 - return ret; 2908 2920 2909 2921 /* 2910 2922 * For Gen12, performance counters are context ··· 2949 2979 intel_uncore_write(uncore, GEN7_ROW_CHICKEN2, 2950 2980 _MASKED_BIT_DISABLE(GEN12_DISABLE_DOP_GATING)); 2951 2981 } 2952 - 2953 - /* Reset all contexts' slices/subslices configurations. */ 2954 - gen12_configure_all_contexts(stream, NULL, NULL); 2955 2982 2956 2983 /* disable the context save/restore or OAR counters */ 2957 2984 if (stream->ctx)
+1 -1
drivers/gpu/drm/nouveau/nouveau_bo.c
··· 898 898 * Without this the operation can timeout and we'll fallback to a 899 899 * software copy, which might take several minutes to finish. 900 900 */ 901 - nouveau_fence_wait(fence, false); 901 + nouveau_fence_wait(fence, false, false); 902 902 ret = ttm_bo_move_accel_cleanup(bo, &fence->base, evict, false, 903 903 new_reg); 904 904 nouveau_fence_unref(&fence);
+1 -1
drivers/gpu/drm/nouveau/nouveau_chan.c
··· 72 72 73 73 ret = nouveau_fence_new(&fence, chan); 74 74 if (!ret) { 75 - ret = nouveau_fence_wait(fence, false); 75 + ret = nouveau_fence_wait(fence, false, false); 76 76 nouveau_fence_unref(&fence); 77 77 } 78 78
+1 -1
drivers/gpu/drm/nouveau/nouveau_dmem.c
··· 128 128 static void nouveau_dmem_fence_done(struct nouveau_fence **fence) 129 129 { 130 130 if (fence) { 131 - nouveau_fence_wait(*fence, false); 131 + nouveau_fence_wait(*fence, true, false); 132 132 nouveau_fence_unref(fence); 133 133 } else { 134 134 /*
+29 -1
drivers/gpu/drm/nouveau/nouveau_fence.c
··· 311 311 return timeout - t; 312 312 } 313 313 314 + static int 315 + nouveau_fence_wait_busy(struct nouveau_fence *fence, bool intr) 316 + { 317 + int ret = 0; 318 + 319 + while (!nouveau_fence_done(fence)) { 320 + if (time_after_eq(jiffies, fence->timeout)) { 321 + ret = -EBUSY; 322 + break; 323 + } 324 + 325 + __set_current_state(intr ? 326 + TASK_INTERRUPTIBLE : 327 + TASK_UNINTERRUPTIBLE); 328 + 329 + if (intr && signal_pending(current)) { 330 + ret = -ERESTARTSYS; 331 + break; 332 + } 333 + } 334 + 335 + __set_current_state(TASK_RUNNING); 336 + return ret; 337 + } 338 + 314 339 int 315 - nouveau_fence_wait(struct nouveau_fence *fence, bool intr) 340 + nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) 316 341 { 317 342 long ret; 343 + 344 + if (!lazy) 345 + return nouveau_fence_wait_busy(fence, intr); 318 346 319 347 ret = dma_fence_wait_timeout(&fence->base, intr, 15 * HZ); 320 348 if (ret < 0)
+1 -1
drivers/gpu/drm/nouveau/nouveau_fence.h
··· 23 23 24 24 int nouveau_fence_emit(struct nouveau_fence *); 25 25 bool nouveau_fence_done(struct nouveau_fence *); 26 - int nouveau_fence_wait(struct nouveau_fence *, bool intr); 26 + int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr); 27 27 int nouveau_fence_sync(struct nouveau_bo *, struct nouveau_channel *, bool exclusive, bool intr); 28 28 29 29 struct nouveau_fence_chan {
+1 -1
drivers/gpu/drm/nouveau/nouveau_gem.c
··· 928 928 } 929 929 930 930 if (sync) { 931 - if (!(ret = nouveau_fence_wait(fence, false))) { 931 + if (!(ret = nouveau_fence_wait(fence, false, false))) { 932 932 if ((ret = dma_fence_get_status(&fence->base)) == 1) 933 933 ret = 0; 934 934 }
+2 -1
drivers/gpu/drm/nouveau/nouveau_prime.c
··· 64 64 * to the caller, instead of a normal nouveau_bo ttm reference. */ 65 65 ret = drm_gem_object_init(dev, &nvbo->bo.base, size); 66 66 if (ret) { 67 - nouveau_bo_ref(NULL, &nvbo); 67 + drm_gem_object_release(&nvbo->bo.base); 68 + kfree(nvbo); 68 69 obj = ERR_PTR(-ENOMEM); 69 70 goto unlock; 70 71 }
+1
drivers/gpu/drm/nouveau/nouveau_uvmm.c
··· 1803 1803 { 1804 1804 struct nouveau_bo *nvbo = nouveau_gem_object(vm_bo->obj); 1805 1805 1806 + nouveau_bo_placement_set(nvbo, nvbo->valid_domains, 0); 1806 1807 return nouveau_bo_validate(nvbo, true, false); 1807 1808 } 1808 1809
+4
drivers/gpu/drm/v3d/v3d_drv.h
··· 565 565 void v3d_mmu_remove_ptes(struct v3d_bo *bo); 566 566 567 567 /* v3d_sched.c */ 568 + void v3d_timestamp_query_info_free(struct v3d_timestamp_query_info *query_info, 569 + unsigned int count); 570 + void v3d_performance_query_info_free(struct v3d_performance_query_info *query_info, 571 + unsigned int count); 568 572 void v3d_job_update_stats(struct v3d_job *job, enum v3d_queue queue); 569 573 int v3d_sched_init(struct v3d_dev *v3d); 570 574 void v3d_sched_fini(struct v3d_dev *v3d);
+32 -12
drivers/gpu/drm/v3d/v3d_sched.c
··· 73 73 v3d_job_cleanup(job); 74 74 } 75 75 76 + void 77 + v3d_timestamp_query_info_free(struct v3d_timestamp_query_info *query_info, 78 + unsigned int count) 79 + { 80 + if (query_info->queries) { 81 + unsigned int i; 82 + 83 + for (i = 0; i < count; i++) 84 + drm_syncobj_put(query_info->queries[i].syncobj); 85 + 86 + kvfree(query_info->queries); 87 + } 88 + } 89 + 90 + void 91 + v3d_performance_query_info_free(struct v3d_performance_query_info *query_info, 92 + unsigned int count) 93 + { 94 + if (query_info->queries) { 95 + unsigned int i; 96 + 97 + for (i = 0; i < count; i++) 98 + drm_syncobj_put(query_info->queries[i].syncobj); 99 + 100 + kvfree(query_info->queries); 101 + } 102 + } 103 + 76 104 static void 77 105 v3d_cpu_job_free(struct drm_sched_job *sched_job) 78 106 { 79 107 struct v3d_cpu_job *job = to_cpu_job(sched_job); 80 - struct v3d_timestamp_query_info *timestamp_query = &job->timestamp_query; 81 - struct v3d_performance_query_info *performance_query = &job->performance_query; 82 108 83 - if (timestamp_query->queries) { 84 - for (int i = 0; i < timestamp_query->count; i++) 85 - drm_syncobj_put(timestamp_query->queries[i].syncobj); 86 - kvfree(timestamp_query->queries); 87 - } 109 + v3d_timestamp_query_info_free(&job->timestamp_query, 110 + job->timestamp_query.count); 88 111 89 - if (performance_query->queries) { 90 - for (int i = 0; i < performance_query->count; i++) 91 - drm_syncobj_put(performance_query->queries[i].syncobj); 92 - kvfree(performance_query->queries); 93 - } 112 + v3d_performance_query_info_free(&job->performance_query, 113 + job->performance_query.count); 94 114 95 115 v3d_job_cleanup(&job->base); 96 116 }
+88 -33
drivers/gpu/drm/v3d/v3d_submit.c
··· 452 452 { 453 453 u32 __user *offsets, *syncs; 454 454 struct drm_v3d_timestamp_query timestamp; 455 + unsigned int i; 456 + int err; 455 457 456 458 if (!job) { 457 459 DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); ··· 482 480 offsets = u64_to_user_ptr(timestamp.offsets); 483 481 syncs = u64_to_user_ptr(timestamp.syncs); 484 482 485 - for (int i = 0; i < timestamp.count; i++) { 483 + for (i = 0; i < timestamp.count; i++) { 486 484 u32 offset, sync; 487 485 488 486 if (copy_from_user(&offset, offsets++, sizeof(offset))) { 489 - kvfree(job->timestamp_query.queries); 490 - return -EFAULT; 487 + err = -EFAULT; 488 + goto error; 491 489 } 492 490 493 491 job->timestamp_query.queries[i].offset = offset; 494 492 495 493 if (copy_from_user(&sync, syncs++, sizeof(sync))) { 496 - kvfree(job->timestamp_query.queries); 497 - return -EFAULT; 494 + err = -EFAULT; 495 + goto error; 498 496 } 499 497 500 498 job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); 499 + if (!job->timestamp_query.queries[i].syncobj) { 500 + err = -ENOENT; 501 + goto error; 502 + } 501 503 } 502 504 job->timestamp_query.count = timestamp.count; 503 505 504 506 return 0; 507 + 508 + error: 509 + v3d_timestamp_query_info_free(&job->timestamp_query, i); 510 + return err; 505 511 } 506 512 507 513 static int ··· 519 509 { 520 510 u32 __user *syncs; 521 511 struct drm_v3d_reset_timestamp_query reset; 512 + unsigned int i; 513 + int err; 522 514 523 515 if (!job) { 524 516 DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); ··· 545 533 546 534 syncs = u64_to_user_ptr(reset.syncs); 547 535 548 - for (int i = 0; i < reset.count; i++) { 536 + for (i = 0; i < reset.count; i++) { 549 537 u32 sync; 550 538 551 539 job->timestamp_query.queries[i].offset = reset.offset + 8 * i; 552 540 553 541 if (copy_from_user(&sync, syncs++, sizeof(sync))) { 554 - kvfree(job->timestamp_query.queries); 555 - return -EFAULT; 542 + err = -EFAULT; 543 + goto error; 556 544 } 557 545 558 546 job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); 547 + if (!job->timestamp_query.queries[i].syncobj) { 548 + err = -ENOENT; 549 + goto error; 550 + } 559 551 } 560 552 job->timestamp_query.count = reset.count; 561 553 562 554 return 0; 555 + 556 + error: 557 + v3d_timestamp_query_info_free(&job->timestamp_query, i); 558 + return err; 563 559 } 564 560 565 561 /* Get data for the copy timestamp query results job submission. */ ··· 578 558 { 579 559 u32 __user *offsets, *syncs; 580 560 struct drm_v3d_copy_timestamp_query copy; 581 - int i; 561 + unsigned int i; 562 + int err; 582 563 583 564 if (!job) { 584 565 DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); ··· 612 591 u32 offset, sync; 613 592 614 593 if (copy_from_user(&offset, offsets++, sizeof(offset))) { 615 - kvfree(job->timestamp_query.queries); 616 - return -EFAULT; 594 + err = -EFAULT; 595 + goto error; 617 596 } 618 597 619 598 job->timestamp_query.queries[i].offset = offset; 620 599 621 600 if (copy_from_user(&sync, syncs++, sizeof(sync))) { 622 - kvfree(job->timestamp_query.queries); 623 - return -EFAULT; 601 + err = -EFAULT; 602 + goto error; 624 603 } 625 604 626 605 job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); 606 + if (!job->timestamp_query.queries[i].syncobj) { 607 + err = -ENOENT; 608 + goto error; 609 + } 627 610 } 628 611 job->timestamp_query.count = copy.count; 629 612 ··· 638 613 job->copy.stride = copy.stride; 639 614 640 615 return 0; 616 + 617 + error: 618 + v3d_timestamp_query_info_free(&job->timestamp_query, i); 619 + return err; 641 620 } 642 621 643 622 static int ··· 652 623 u32 __user *syncs; 653 624 u64 __user *kperfmon_ids; 654 625 struct drm_v3d_reset_performance_query reset; 626 + unsigned int i, j; 627 + int err; 655 628 656 629 if (!job) { 657 630 DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); ··· 668 637 if (copy_from_user(&reset, ext, sizeof(reset))) 669 638 return -EFAULT; 670 639 640 + if (reset.nperfmons > V3D_MAX_PERFMONS) 641 + return -EINVAL; 642 + 671 643 job->job_type = V3D_CPU_JOB_TYPE_RESET_PERFORMANCE_QUERY; 672 644 673 645 job->performance_query.queries = kvmalloc_array(reset.count, ··· 682 648 syncs = u64_to_user_ptr(reset.syncs); 683 649 kperfmon_ids = u64_to_user_ptr(reset.kperfmon_ids); 684 650 685 - for (int i = 0; i < reset.count; i++) { 651 + for (i = 0; i < reset.count; i++) { 686 652 u32 sync; 687 653 u64 ids; 688 654 u32 __user *ids_pointer; 689 655 u32 id; 690 656 691 657 if (copy_from_user(&sync, syncs++, sizeof(sync))) { 692 - kvfree(job->performance_query.queries); 693 - return -EFAULT; 658 + err = -EFAULT; 659 + goto error; 694 660 } 695 661 696 - job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); 697 - 698 662 if (copy_from_user(&ids, kperfmon_ids++, sizeof(ids))) { 699 - kvfree(job->performance_query.queries); 700 - return -EFAULT; 663 + err = -EFAULT; 664 + goto error; 701 665 } 702 666 703 667 ids_pointer = u64_to_user_ptr(ids); 704 668 705 - for (int j = 0; j < reset.nperfmons; j++) { 669 + for (j = 0; j < reset.nperfmons; j++) { 706 670 if (copy_from_user(&id, ids_pointer++, sizeof(id))) { 707 - kvfree(job->performance_query.queries); 708 - return -EFAULT; 671 + err = -EFAULT; 672 + goto error; 709 673 } 710 674 711 675 job->performance_query.queries[i].kperfmon_ids[j] = id; 676 + } 677 + 678 + job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); 679 + if (!job->performance_query.queries[i].syncobj) { 680 + err = -ENOENT; 681 + goto error; 712 682 } 713 683 } 714 684 job->performance_query.count = reset.count; 715 685 job->performance_query.nperfmons = reset.nperfmons; 716 686 717 687 return 0; 688 + 689 + error: 690 + v3d_performance_query_info_free(&job->performance_query, i); 691 + return err; 718 692 } 719 693 720 694 static int ··· 733 691 u32 __user *syncs; 734 692 u64 __user *kperfmon_ids; 735 693 struct drm_v3d_copy_performance_query copy; 694 + unsigned int i, j; 695 + int err; 736 696 737 697 if (!job) { 738 698 DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); ··· 752 708 if (copy.pad) 753 709 return -EINVAL; 754 710 711 + if (copy.nperfmons > V3D_MAX_PERFMONS) 712 + return -EINVAL; 713 + 755 714 job->job_type = V3D_CPU_JOB_TYPE_COPY_PERFORMANCE_QUERY; 756 715 757 716 job->performance_query.queries = kvmalloc_array(copy.count, ··· 766 719 syncs = u64_to_user_ptr(copy.syncs); 767 720 kperfmon_ids = u64_to_user_ptr(copy.kperfmon_ids); 768 721 769 - for (int i = 0; i < copy.count; i++) { 722 + for (i = 0; i < copy.count; i++) { 770 723 u32 sync; 771 724 u64 ids; 772 725 u32 __user *ids_pointer; 773 726 u32 id; 774 727 775 728 if (copy_from_user(&sync, syncs++, sizeof(sync))) { 776 - kvfree(job->performance_query.queries); 777 - return -EFAULT; 729 + err = -EFAULT; 730 + goto error; 778 731 } 779 732 780 - job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); 781 - 782 733 if (copy_from_user(&ids, kperfmon_ids++, sizeof(ids))) { 783 - kvfree(job->performance_query.queries); 784 - return -EFAULT; 734 + err = -EFAULT; 735 + goto error; 785 736 } 786 737 787 738 ids_pointer = u64_to_user_ptr(ids); 788 739 789 - for (int j = 0; j < copy.nperfmons; j++) { 740 + for (j = 0; j < copy.nperfmons; j++) { 790 741 if (copy_from_user(&id, ids_pointer++, sizeof(id))) { 791 - kvfree(job->performance_query.queries); 792 - return -EFAULT; 742 + err = -EFAULT; 743 + goto error; 793 744 } 794 745 795 746 job->performance_query.queries[i].kperfmon_ids[j] = id; 747 + } 748 + 749 + job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); 750 + if (!job->performance_query.queries[i].syncobj) { 751 + err = -ENOENT; 752 + goto error; 796 753 } 797 754 } 798 755 job->performance_query.count = copy.count; ··· 810 759 job->copy.stride = copy.stride; 811 760 812 761 return 0; 762 + 763 + error: 764 + v3d_performance_query_info_free(&job->performance_query, i); 765 + return err; 813 766 } 814 767 815 768 /* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data
+1 -1
drivers/gpu/drm/virtio/virtgpu_submit.c
··· 48 48 static int virtio_gpu_do_fence_wait(struct virtio_gpu_submit *submit, 49 49 struct dma_fence *in_fence) 50 50 { 51 - u32 context = submit->fence_ctx + submit->ring_idx; 51 + u64 context = submit->fence_ctx + submit->ring_idx; 52 52 53 53 if (dma_fence_match_context(in_fence, context)) 54 54 return 0;
+8 -2
drivers/gpu/drm/vmwgfx/vmw_surface_cache.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 1 2 /********************************************************** 2 - * Copyright 2021 VMware, Inc. 3 - * SPDX-License-Identifier: GPL-2.0 OR MIT 3 + * 4 + * Copyright (c) 2021-2024 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 4 6 * 5 7 * Permission is hereby granted, free of charge, to any person 6 8 * obtaining a copy of this software and associated documentation ··· 32 30 #include "device_include/svga3d_surfacedefs.h" 33 31 34 32 #include <drm/vmwgfx_drm.h> 33 + 34 + #define SVGA3D_FLAGS_UPPER_32(svga3d_flags) ((svga3d_flags) >> 32) 35 + #define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \ 36 + ((svga3d_flags) & ((uint64_t)U32_MAX)) 35 37 36 38 static inline u32 clamped_umul32(u32 a, u32 b) 37 39 {
+76 -51
drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright © 2011-2023 VMware, Inc., Palo Alto, CA., USA 5 - * All Rights Reserved. 4 + * Copyright (c) 2011-2024 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 6 6 * 7 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 8 * copy of this software and associated documentation files (the ··· 28 28 29 29 #include "vmwgfx_bo.h" 30 30 #include "vmwgfx_drv.h" 31 - 31 + #include "vmwgfx_resource_priv.h" 32 32 33 33 #include <drm/ttm/ttm_placement.h> 34 34 35 35 static void vmw_bo_release(struct vmw_bo *vbo) 36 36 { 37 + struct vmw_resource *res; 38 + 37 39 WARN_ON(vbo->tbo.base.funcs && 38 40 kref_read(&vbo->tbo.base.refcount) != 0); 39 41 vmw_bo_unmap(vbo); 42 + 43 + xa_destroy(&vbo->detached_resources); 44 + WARN_ON(vbo->is_dumb && !vbo->dumb_surface); 45 + if (vbo->is_dumb && vbo->dumb_surface) { 46 + res = &vbo->dumb_surface->res; 47 + WARN_ON(vbo != res->guest_memory_bo); 48 + WARN_ON(!res->guest_memory_bo); 49 + if (res->guest_memory_bo) { 50 + /* Reserve and switch the backing mob. */ 51 + mutex_lock(&res->dev_priv->cmdbuf_mutex); 52 + (void)vmw_resource_reserve(res, false, true); 53 + vmw_resource_mob_detach(res); 54 + if (res->coherent) 55 + vmw_bo_dirty_release(res->guest_memory_bo); 56 + res->guest_memory_bo = NULL; 57 + res->guest_memory_offset = 0; 58 + vmw_resource_unreserve(res, false, false, false, NULL, 59 + 0); 60 + mutex_unlock(&res->dev_priv->cmdbuf_mutex); 61 + } 62 + vmw_surface_unreference(&vbo->dumb_surface); 63 + } 40 64 drm_gem_object_release(&vbo->tbo.base); 41 65 } 42 66 ··· 350 326 */ 351 327 void *vmw_bo_map_and_cache(struct vmw_bo *vbo) 352 328 { 329 + return vmw_bo_map_and_cache_size(vbo, vbo->tbo.base.size); 330 + } 331 + 332 + void *vmw_bo_map_and_cache_size(struct vmw_bo *vbo, size_t size) 333 + { 353 334 struct ttm_buffer_object *bo = &vbo->tbo; 354 335 bool not_used; 355 336 void *virtual; ··· 364 335 if (virtual) 365 336 return virtual; 366 337 367 - ret = ttm_bo_kmap(bo, 0, PFN_UP(bo->base.size), &vbo->map); 338 + ret = ttm_bo_kmap(bo, 0, PFN_UP(size), &vbo->map); 368 339 if (ret) 369 - DRM_ERROR("Buffer object map failed: %d.\n", ret); 340 + DRM_ERROR("Buffer object map failed: %d (size: bo = %zu, map = %zu).\n", 341 + ret, bo->base.size, size); 370 342 371 343 return ttm_kmap_obj_virtual(&vbo->map, &not_used); 372 344 } ··· 420 390 BUILD_BUG_ON(TTM_MAX_BO_PRIORITY <= 3); 421 391 vmw_bo->tbo.priority = 3; 422 392 vmw_bo->res_tree = RB_ROOT; 393 + xa_init(&vmw_bo->detached_resources); 423 394 424 395 params->size = ALIGN(params->size, PAGE_SIZE); 425 396 drm_gem_private_object_init(vdev, &vmw_bo->tbo.base, params->size); ··· 685 654 dma_fence_put(&fence->base); 686 655 } 687 656 688 - 689 - /** 690 - * vmw_dumb_create - Create a dumb kms buffer 691 - * 692 - * @file_priv: Pointer to a struct drm_file identifying the caller. 693 - * @dev: Pointer to the drm device. 694 - * @args: Pointer to a struct drm_mode_create_dumb structure 695 - * Return: Zero on success, negative error code on failure. 696 - * 697 - * This is a driver callback for the core drm create_dumb functionality. 698 - * Note that this is very similar to the vmw_bo_alloc ioctl, except 699 - * that the arguments have a different format. 700 - */ 701 - int vmw_dumb_create(struct drm_file *file_priv, 702 - struct drm_device *dev, 703 - struct drm_mode_create_dumb *args) 704 - { 705 - struct vmw_private *dev_priv = vmw_priv(dev); 706 - struct vmw_bo *vbo; 707 - int cpp = DIV_ROUND_UP(args->bpp, 8); 708 - int ret; 709 - 710 - switch (cpp) { 711 - case 1: /* DRM_FORMAT_C8 */ 712 - case 2: /* DRM_FORMAT_RGB565 */ 713 - case 4: /* DRM_FORMAT_XRGB8888 */ 714 - break; 715 - default: 716 - /* 717 - * Dumb buffers don't allow anything else. 718 - * This is tested via IGT's dumb_buffers 719 - */ 720 - return -EINVAL; 721 - } 722 - 723 - args->pitch = args->width * cpp; 724 - args->size = ALIGN(args->pitch * args->height, PAGE_SIZE); 725 - 726 - ret = vmw_gem_object_create_with_handle(dev_priv, file_priv, 727 - args->size, &args->handle, 728 - &vbo); 729 - /* drop reference from allocate - handle holds it now */ 730 - drm_gem_object_put(&vbo->tbo.base); 731 - return ret; 732 - } 733 - 734 657 /** 735 658 * vmw_bo_swap_notify - swapout notify callback. 736 659 * ··· 837 852 domain = VMW_BO_DOMAIN_MOB; 838 853 839 854 vmw_bo_placement_set(bo, domain, domain); 855 + } 856 + 857 + void vmw_bo_add_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res) 858 + { 859 + xa_store(&vbo->detached_resources, (unsigned long)res, res, GFP_KERNEL); 860 + } 861 + 862 + void vmw_bo_del_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res) 863 + { 864 + xa_erase(&vbo->detached_resources, (unsigned long)res); 865 + } 866 + 867 + struct vmw_surface *vmw_bo_surface(struct vmw_bo *vbo) 868 + { 869 + unsigned long index; 870 + struct vmw_resource *res = NULL; 871 + struct vmw_surface *surf = NULL; 872 + struct rb_node *rb_itr = vbo->res_tree.rb_node; 873 + 874 + if (vbo->is_dumb && vbo->dumb_surface) { 875 + res = &vbo->dumb_surface->res; 876 + goto out; 877 + } 878 + 879 + xa_for_each(&vbo->detached_resources, index, res) { 880 + if (res->func->res_type == vmw_res_surface) 881 + goto out; 882 + } 883 + 884 + for (rb_itr = rb_first(&vbo->res_tree); rb_itr; 885 + rb_itr = rb_next(rb_itr)) { 886 + res = rb_entry(rb_itr, struct vmw_resource, mob_node); 887 + if (res->func->res_type == vmw_res_surface) 888 + goto out; 889 + } 890 + 891 + out: 892 + if (res) 893 + surf = vmw_res_to_srf(res); 894 + return surf; 840 895 }
+14 -1
drivers/gpu/drm/vmwgfx/vmwgfx_bo.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2023 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright (c) 2023-2024 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5 6 * 6 7 * Permission is hereby granted, free of charge, to any person obtaining a 7 8 * copy of this software and associated documentation files (the ··· 36 35 37 36 #include <linux/rbtree_types.h> 38 37 #include <linux/types.h> 38 + #include <linux/xarray.h> 39 39 40 40 struct vmw_bo_dirty; 41 41 struct vmw_fence_obj; 42 42 struct vmw_private; 43 43 struct vmw_resource; 44 + struct vmw_surface; 44 45 45 46 enum vmw_bo_domain { 46 47 VMW_BO_DOMAIN_SYS = BIT(0), ··· 88 85 89 86 struct rb_root res_tree; 90 87 u32 res_prios[TTM_MAX_BO_PRIORITY]; 88 + struct xarray detached_resources; 91 89 92 90 atomic_t cpu_writers; 93 91 /* Not ref-counted. Protected by binding_mutex */ 94 92 struct vmw_resource *dx_query_ctx; 95 93 struct vmw_bo_dirty *dirty; 94 + 95 + bool is_dumb; 96 + struct vmw_surface *dumb_surface; 96 97 }; 97 98 98 99 void vmw_bo_placement_set(struct vmw_bo *bo, u32 domain, u32 busy_domain); ··· 131 124 struct vmw_fence_obj *fence); 132 125 133 126 void *vmw_bo_map_and_cache(struct vmw_bo *vbo); 127 + void *vmw_bo_map_and_cache_size(struct vmw_bo *vbo, size_t size); 134 128 void vmw_bo_unmap(struct vmw_bo *vbo); 135 129 136 130 void vmw_bo_move_notify(struct ttm_buffer_object *bo, 137 131 struct ttm_resource *mem); 138 132 void vmw_bo_swap_notify(struct ttm_buffer_object *bo); 139 133 134 + void vmw_bo_add_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res); 135 + void vmw_bo_del_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res); 136 + struct vmw_surface *vmw_bo_surface(struct vmw_bo *vbo); 137 + 140 138 int vmw_user_bo_lookup(struct drm_file *filp, 141 139 u32 handle, 142 140 struct vmw_bo **out); 141 + 143 142 /** 144 143 * vmw_bo_adjust_prio - Adjust the buffer object eviction priority 145 144 * according to attached resources
+31 -9
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5 6 * 6 7 * Permission is hereby granted, free of charge, to any person obtaining a 7 8 * copy of this software and associated documentation files (the ··· 764 763 extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id); 765 764 766 765 /** 766 + * User handles 767 + */ 768 + struct vmw_user_object { 769 + struct vmw_surface *surface; 770 + struct vmw_bo *buffer; 771 + }; 772 + 773 + int vmw_user_object_lookup(struct vmw_private *dev_priv, struct drm_file *filp, 774 + u32 handle, struct vmw_user_object *uo); 775 + struct vmw_user_object *vmw_user_object_ref(struct vmw_user_object *uo); 776 + void vmw_user_object_unref(struct vmw_user_object *uo); 777 + bool vmw_user_object_is_null(struct vmw_user_object *uo); 778 + struct vmw_surface *vmw_user_object_surface(struct vmw_user_object *uo); 779 + struct vmw_bo *vmw_user_object_buffer(struct vmw_user_object *uo); 780 + void *vmw_user_object_map(struct vmw_user_object *uo); 781 + void *vmw_user_object_map_size(struct vmw_user_object *uo, size_t size); 782 + void vmw_user_object_unmap(struct vmw_user_object *uo); 783 + bool vmw_user_object_is_mapped(struct vmw_user_object *uo); 784 + 785 + /** 767 786 * Resource utilities - vmwgfx_resource.c 768 787 */ 769 788 struct vmw_user_resource_conv; ··· 797 776 extern int vmw_resource_reserve(struct vmw_resource *res, bool interruptible, 798 777 bool no_backup); 799 778 extern bool vmw_resource_needs_backup(const struct vmw_resource *res); 800 - extern int vmw_user_lookup_handle(struct vmw_private *dev_priv, 801 - struct drm_file *filp, 802 - uint32_t handle, 803 - struct vmw_surface **out_surf, 804 - struct vmw_bo **out_buf); 805 779 extern int vmw_user_resource_lookup_handle( 806 780 struct vmw_private *dev_priv, 807 781 struct ttm_object_file *tfile, ··· 1073 1057 int vmw_kms_resume(struct drm_device *dev); 1074 1058 void vmw_kms_lost_device(struct drm_device *dev); 1075 1059 1076 - int vmw_dumb_create(struct drm_file *file_priv, 1077 - struct drm_device *dev, 1078 - struct drm_mode_create_dumb *args); 1079 1060 extern int vmw_resource_pin(struct vmw_resource *res, bool interruptible); 1080 1061 extern void vmw_resource_unpin(struct vmw_resource *res); 1081 1062 extern enum vmw_res_type vmw_res_type(const struct vmw_resource *res); ··· 1189 1176 int vmw_gb_surface_define(struct vmw_private *dev_priv, 1190 1177 const struct vmw_surface_metadata *req, 1191 1178 struct vmw_surface **srf_out); 1179 + struct vmw_surface *vmw_lookup_surface_for_buffer(struct vmw_private *vmw, 1180 + struct vmw_bo *bo, 1181 + u32 handle); 1182 + u32 vmw_lookup_surface_handle_for_buffer(struct vmw_private *vmw, 1183 + struct vmw_bo *bo, 1184 + u32 handle); 1185 + int vmw_dumb_create(struct drm_file *file_priv, 1186 + struct drm_device *dev, 1187 + struct drm_mode_create_dumb *args); 1192 1188 1193 1189 /* 1194 1190 * Shader management - vmwgfx_shader.c
+7 -10
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
··· 32 32 #define VMW_FENCE_WRAP (1 << 31) 33 33 34 34 struct vmw_fence_manager { 35 - int num_fence_objects; 36 35 struct vmw_private *dev_priv; 37 36 spinlock_t lock; 38 37 struct list_head fence_list; ··· 123 124 { 124 125 struct vmw_fence_obj *fence = 125 126 container_of(f, struct vmw_fence_obj, base); 126 - 127 127 struct vmw_fence_manager *fman = fman_from_fence(fence); 128 128 129 - spin_lock(&fman->lock); 130 - list_del_init(&fence->head); 131 - --fman->num_fence_objects; 132 - spin_unlock(&fman->lock); 129 + if (!list_empty(&fence->head)) { 130 + spin_lock(&fman->lock); 131 + list_del_init(&fence->head); 132 + spin_unlock(&fman->lock); 133 + } 133 134 fence->destroy(fence); 134 135 } 135 136 ··· 256 257 .release = vmw_fence_obj_destroy, 257 258 }; 258 259 259 - 260 260 /* 261 261 * Execute signal actions on fences recently signaled. 262 262 * This is done from a workqueue so we don't have to execute ··· 353 355 goto out_unlock; 354 356 } 355 357 list_add_tail(&fence->head, &fman->fence_list); 356 - ++fman->num_fence_objects; 357 358 358 359 out_unlock: 359 360 spin_unlock(&fman->lock); ··· 400 403 u32 passed_seqno) 401 404 { 402 405 u32 goal_seqno; 403 - struct vmw_fence_obj *fence; 406 + struct vmw_fence_obj *fence, *next_fence; 404 407 405 408 if (likely(!fman->seqno_valid)) 406 409 return false; ··· 410 413 return false; 411 414 412 415 fman->seqno_valid = false; 413 - list_for_each_entry(fence, &fman->fence_list, head) { 416 + list_for_each_entry_safe(fence, next_fence, &fman->fence_list, head) { 414 417 if (!list_empty(&fence->seq_passed_actions)) { 415 418 fman->seqno_valid = true; 416 419 vmw_fence_goal_write(fman->dev_priv,
+58 -4
drivers/gpu/drm/vmwgfx/vmwgfx_gem.c
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 2 /* 3 - * Copyright 2021-2023 VMware, Inc. 3 + * Copyright (c) 2021-2024 Broadcom. All Rights Reserved. The term 4 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 4 5 * 5 6 * Permission is hereby granted, free of charge, to any person 6 7 * obtaining a copy of this software and associated documentation ··· 79 78 return drm_prime_pages_to_sg(obj->dev, vmw_tt->dma_ttm.pages, vmw_tt->dma_ttm.num_pages); 80 79 } 81 80 81 + static int vmw_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map) 82 + { 83 + struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(obj); 84 + int ret; 85 + 86 + if (obj->import_attach) { 87 + ret = dma_buf_vmap(obj->import_attach->dmabuf, map); 88 + if (!ret) { 89 + if (drm_WARN_ON(obj->dev, map->is_iomem)) { 90 + dma_buf_vunmap(obj->import_attach->dmabuf, map); 91 + return -EIO; 92 + } 93 + } 94 + } else { 95 + ret = ttm_bo_vmap(bo, map); 96 + } 97 + 98 + return ret; 99 + } 100 + 101 + static void vmw_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map) 102 + { 103 + if (obj->import_attach) 104 + dma_buf_vunmap(obj->import_attach->dmabuf, map); 105 + else 106 + drm_gem_ttm_vunmap(obj, map); 107 + } 108 + 109 + static int vmw_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) 110 + { 111 + int ret; 112 + 113 + if (obj->import_attach) { 114 + /* 115 + * Reset both vm_ops and vm_private_data, so we don't end up with 116 + * vm_ops pointing to our implementation if the dma-buf backend 117 + * doesn't set those fields. 118 + */ 119 + vma->vm_private_data = NULL; 120 + vma->vm_ops = NULL; 121 + 122 + ret = dma_buf_mmap(obj->dma_buf, vma, 0); 123 + 124 + /* Drop the reference drm_gem_mmap_obj() acquired.*/ 125 + if (!ret) 126 + drm_gem_object_put(obj); 127 + 128 + return ret; 129 + } 130 + 131 + return drm_gem_ttm_mmap(obj, vma); 132 + } 133 + 82 134 static const struct vm_operations_struct vmw_vm_ops = { 83 135 .pfn_mkwrite = vmw_bo_vm_mkwrite, 84 136 .page_mkwrite = vmw_bo_vm_mkwrite, ··· 148 94 .pin = vmw_gem_object_pin, 149 95 .unpin = vmw_gem_object_unpin, 150 96 .get_sg_table = vmw_gem_object_get_sg_table, 151 - .vmap = drm_gem_ttm_vmap, 152 - .vunmap = drm_gem_ttm_vunmap, 153 - .mmap = drm_gem_ttm_mmap, 97 + .vmap = vmw_gem_vmap, 98 + .vunmap = vmw_gem_vunmap, 99 + .mmap = vmw_gem_mmap, 154 100 .vm_ops = &vmw_vm_ops, 155 101 }; 156 102
+204 -300
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5 6 * 6 7 * Permission is hereby granted, free of charge, to any person obtaining a 7 8 * copy of this software and associated documentation files (the ··· 194 193 */ 195 194 static u32 *vmw_du_cursor_plane_acquire_image(struct vmw_plane_state *vps) 196 195 { 197 - if (vps->surf) { 198 - if (vps->surf_mapped) 199 - return vmw_bo_map_and_cache(vps->surf->res.guest_memory_bo); 200 - return vps->surf->snooper.image; 201 - } else if (vps->bo) 202 - return vmw_bo_map_and_cache(vps->bo); 203 - return NULL; 196 + struct vmw_surface *surf; 197 + 198 + if (vmw_user_object_is_null(&vps->uo)) 199 + return NULL; 200 + 201 + surf = vmw_user_object_surface(&vps->uo); 202 + if (surf && !vmw_user_object_is_mapped(&vps->uo)) 203 + return surf->snooper.image; 204 + 205 + return vmw_user_object_map(&vps->uo); 204 206 } 205 207 206 208 static bool vmw_du_cursor_plane_has_changed(struct vmw_plane_state *old_vps, ··· 540 536 * vmw_du_plane_unpin_surf - unpins resource associated with a framebuffer surface 541 537 * 542 538 * @vps: plane state associated with the display surface 543 - * @unreference: true if we also want to unreference the display. 544 539 */ 545 - void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps, 546 - bool unreference) 540 + void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps) 547 541 { 548 - if (vps->surf) { 549 - if (vps->pinned) { 550 - vmw_resource_unpin(&vps->surf->res); 551 - vps->pinned--; 552 - } 542 + struct vmw_surface *surf = vmw_user_object_surface(&vps->uo); 553 543 554 - if (unreference) { 555 - if (vps->pinned) 556 - DRM_ERROR("Surface still pinned\n"); 557 - vmw_surface_unreference(&vps->surf); 544 + if (surf) { 545 + if (vps->pinned) { 546 + vmw_resource_unpin(&surf->res); 547 + vps->pinned--; 558 548 } 559 549 } 560 550 } ··· 570 572 { 571 573 struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 572 574 573 - vmw_du_plane_unpin_surf(vps, false); 575 + vmw_du_plane_unpin_surf(vps); 574 576 } 575 577 576 578 ··· 659 661 struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 660 662 struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 661 663 662 - if (vps->surf_mapped) { 663 - vmw_bo_unmap(vps->surf->res.guest_memory_bo); 664 - vps->surf_mapped = false; 665 - } 664 + if (!vmw_user_object_is_null(&vps->uo)) 665 + vmw_user_object_unmap(&vps->uo); 666 666 667 667 vmw_du_cursor_plane_unmap_cm(vps); 668 668 vmw_du_put_cursor_mob(vcp, vps); 669 669 670 - vmw_du_plane_unpin_surf(vps, false); 671 - 672 - if (vps->surf) { 673 - vmw_surface_unreference(&vps->surf); 674 - vps->surf = NULL; 675 - } 676 - 677 - if (vps->bo) { 678 - vmw_bo_unreference(&vps->bo); 679 - vps->bo = NULL; 680 - } 670 + vmw_du_plane_unpin_surf(vps); 671 + vmw_user_object_unref(&vps->uo); 681 672 } 682 673 683 674 ··· 685 698 struct drm_framebuffer *fb = new_state->fb; 686 699 struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 687 700 struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 701 + struct vmw_bo *bo = NULL; 688 702 int ret = 0; 689 703 690 - if (vps->surf) { 691 - if (vps->surf_mapped) { 692 - vmw_bo_unmap(vps->surf->res.guest_memory_bo); 693 - vps->surf_mapped = false; 694 - } 695 - vmw_surface_unreference(&vps->surf); 696 - vps->surf = NULL; 697 - } 698 - 699 - if (vps->bo) { 700 - vmw_bo_unreference(&vps->bo); 701 - vps->bo = NULL; 704 + if (!vmw_user_object_is_null(&vps->uo)) { 705 + vmw_user_object_unmap(&vps->uo); 706 + vmw_user_object_unref(&vps->uo); 702 707 } 703 708 704 709 if (fb) { 705 710 if (vmw_framebuffer_to_vfb(fb)->bo) { 706 - vps->bo = vmw_framebuffer_to_vfbd(fb)->buffer; 707 - vmw_bo_reference(vps->bo); 711 + vps->uo.buffer = vmw_framebuffer_to_vfbd(fb)->buffer; 712 + vps->uo.surface = NULL; 708 713 } else { 709 - vps->surf = vmw_framebuffer_to_vfbs(fb)->surface; 710 - vmw_surface_reference(vps->surf); 714 + memcpy(&vps->uo, &vmw_framebuffer_to_vfbs(fb)->uo, sizeof(vps->uo)); 711 715 } 716 + vmw_user_object_ref(&vps->uo); 712 717 } 713 718 714 - if (!vps->surf && vps->bo) { 715 - const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32); 719 + bo = vmw_user_object_buffer(&vps->uo); 720 + if (bo) { 721 + struct ttm_operation_ctx ctx = {false, false}; 716 722 717 - /* 718 - * Not using vmw_bo_map_and_cache() helper here as we need to 719 - * reserve the ttm_buffer_object first which 720 - * vmw_bo_map_and_cache() omits. 721 - */ 722 - ret = ttm_bo_reserve(&vps->bo->tbo, true, false, NULL); 723 - 724 - if (unlikely(ret != 0)) 723 + ret = ttm_bo_reserve(&bo->tbo, true, false, NULL); 724 + if (ret != 0) 725 725 return -ENOMEM; 726 726 727 - ret = ttm_bo_kmap(&vps->bo->tbo, 0, PFN_UP(size), &vps->bo->map); 728 - 729 - ttm_bo_unreserve(&vps->bo->tbo); 730 - 731 - if (unlikely(ret != 0)) 727 + ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); 728 + if (ret != 0) 732 729 return -ENOMEM; 733 - } else if (vps->surf && !vps->bo && vps->surf->res.guest_memory_bo) { 734 730 735 - WARN_ON(vps->surf->snooper.image); 736 - ret = ttm_bo_reserve(&vps->surf->res.guest_memory_bo->tbo, true, false, 737 - NULL); 738 - if (unlikely(ret != 0)) 739 - return -ENOMEM; 740 - vmw_bo_map_and_cache(vps->surf->res.guest_memory_bo); 741 - ttm_bo_unreserve(&vps->surf->res.guest_memory_bo->tbo); 742 - vps->surf_mapped = true; 731 + vmw_bo_pin_reserved(bo, true); 732 + if (vmw_framebuffer_to_vfb(fb)->bo) { 733 + const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32); 734 + 735 + (void)vmw_bo_map_and_cache_size(bo, size); 736 + } else { 737 + vmw_bo_map_and_cache(bo); 738 + } 739 + ttm_bo_unreserve(&bo->tbo); 743 740 } 744 741 745 - if (vps->surf || vps->bo) { 742 + if (!vmw_user_object_is_null(&vps->uo)) { 746 743 vmw_du_get_cursor_mob(vcp, vps); 747 744 vmw_du_cursor_plane_map_cm(vps); 748 745 } ··· 748 777 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 749 778 struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 750 779 struct vmw_plane_state *old_vps = vmw_plane_state_to_vps(old_state); 780 + struct vmw_bo *old_bo = NULL; 781 + struct vmw_bo *new_bo = NULL; 751 782 s32 hotspot_x, hotspot_y; 783 + int ret; 752 784 753 785 hotspot_x = du->hotspot_x + new_state->hotspot_x; 754 786 hotspot_y = du->hotspot_y + new_state->hotspot_y; 755 787 756 - du->cursor_surface = vps->surf; 788 + du->cursor_surface = vmw_user_object_surface(&vps->uo); 757 789 758 - if (!vps->surf && !vps->bo) { 790 + if (vmw_user_object_is_null(&vps->uo)) { 759 791 vmw_cursor_update_position(dev_priv, false, 0, 0); 760 792 return; 761 793 } ··· 766 792 vps->cursor.hotspot_x = hotspot_x; 767 793 vps->cursor.hotspot_y = hotspot_y; 768 794 769 - if (vps->surf) { 795 + if (du->cursor_surface) 770 796 du->cursor_age = du->cursor_surface->snooper.age; 797 + 798 + if (!vmw_user_object_is_null(&old_vps->uo)) { 799 + old_bo = vmw_user_object_buffer(&old_vps->uo); 800 + ret = ttm_bo_reserve(&old_bo->tbo, false, false, NULL); 801 + if (ret != 0) 802 + return; 771 803 } 772 804 805 + if (!vmw_user_object_is_null(&vps->uo)) { 806 + new_bo = vmw_user_object_buffer(&vps->uo); 807 + if (old_bo != new_bo) { 808 + ret = ttm_bo_reserve(&new_bo->tbo, false, false, NULL); 809 + if (ret != 0) 810 + return; 811 + } else { 812 + new_bo = NULL; 813 + } 814 + } 773 815 if (!vmw_du_cursor_plane_has_changed(old_vps, vps)) { 774 816 /* 775 817 * If it hasn't changed, avoid making the device do extra ··· 802 812 new_state->crtc_h, 803 813 hotspot_x, hotspot_y); 804 814 } 815 + 816 + if (old_bo) 817 + ttm_bo_unreserve(&old_bo->tbo); 818 + if (new_bo) 819 + ttm_bo_unreserve(&new_bo->tbo); 805 820 806 821 du->cursor_x = new_state->crtc_x + du->set_gui_x; 807 822 du->cursor_y = new_state->crtc_y + du->set_gui_y; ··· 908 913 } 909 914 910 915 if (!vmw_framebuffer_to_vfb(fb)->bo) { 911 - surface = vmw_framebuffer_to_vfbs(fb)->surface; 916 + surface = vmw_user_object_surface(&vmw_framebuffer_to_vfbs(fb)->uo); 912 917 913 918 WARN_ON(!surface); 914 919 ··· 1069 1074 memset(&vps->cursor, 0, sizeof(vps->cursor)); 1070 1075 1071 1076 /* Each ref counted resource needs to be acquired again */ 1072 - if (vps->surf) 1073 - (void) vmw_surface_reference(vps->surf); 1074 - 1075 - if (vps->bo) 1076 - (void) vmw_bo_reference(vps->bo); 1077 - 1077 + vmw_user_object_ref(&vps->uo); 1078 1078 state = &vps->base; 1079 1079 1080 1080 __drm_atomic_helper_plane_duplicate_state(plane, state); ··· 1118 1128 struct vmw_plane_state *vps = vmw_plane_state_to_vps(state); 1119 1129 1120 1130 /* Should have been freed by cleanup_fb */ 1121 - if (vps->surf) 1122 - vmw_surface_unreference(&vps->surf); 1123 - 1124 - if (vps->bo) 1125 - vmw_bo_unreference(&vps->bo); 1131 + vmw_user_object_unref(&vps->uo); 1126 1132 1127 1133 drm_atomic_helper_plane_destroy_state(plane, state); 1128 1134 } ··· 1213 1227 vmw_framebuffer_to_vfbs(framebuffer); 1214 1228 1215 1229 drm_framebuffer_cleanup(framebuffer); 1216 - vmw_surface_unreference(&vfbs->surface); 1230 + vmw_user_object_unref(&vfbs->uo); 1217 1231 1218 1232 kfree(vfbs); 1219 1233 } ··· 1258 1272 return -ENOSYS; 1259 1273 } 1260 1274 1275 + static int vmw_framebuffer_surface_create_handle(struct drm_framebuffer *fb, 1276 + struct drm_file *file_priv, 1277 + unsigned int *handle) 1278 + { 1279 + struct vmw_framebuffer_surface *vfbs = vmw_framebuffer_to_vfbs(fb); 1280 + struct vmw_bo *bo = vmw_user_object_buffer(&vfbs->uo); 1281 + 1282 + return drm_gem_handle_create(file_priv, &bo->tbo.base, handle); 1283 + } 1261 1284 1262 1285 static const struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { 1286 + .create_handle = vmw_framebuffer_surface_create_handle, 1263 1287 .destroy = vmw_framebuffer_surface_destroy, 1264 1288 .dirty = drm_atomic_helper_dirtyfb, 1265 1289 }; 1266 1290 1267 1291 static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, 1268 - struct vmw_surface *surface, 1292 + struct vmw_user_object *uo, 1269 1293 struct vmw_framebuffer **out, 1270 1294 const struct drm_mode_fb_cmd2 1271 - *mode_cmd, 1272 - bool is_bo_proxy) 1295 + *mode_cmd) 1273 1296 1274 1297 { 1275 1298 struct drm_device *dev = &dev_priv->drm; 1276 1299 struct vmw_framebuffer_surface *vfbs; 1277 1300 enum SVGA3dSurfaceFormat format; 1301 + struct vmw_surface *surface; 1278 1302 int ret; 1279 1303 1280 1304 /* 3D is only supported on HWv8 and newer hosts */ 1281 1305 if (dev_priv->active_display_unit == vmw_du_legacy) 1282 1306 return -ENOSYS; 1307 + 1308 + surface = vmw_user_object_surface(uo); 1283 1309 1284 1310 /* 1285 1311 * Sanity checks. ··· 1355 1357 } 1356 1358 1357 1359 drm_helper_mode_fill_fb_struct(dev, &vfbs->base.base, mode_cmd); 1358 - vfbs->surface = vmw_surface_reference(surface); 1359 - vfbs->is_bo_proxy = is_bo_proxy; 1360 + memcpy(&vfbs->uo, uo, sizeof(vfbs->uo)); 1361 + vmw_user_object_ref(&vfbs->uo); 1360 1362 1361 1363 *out = &vfbs->base; 1362 1364 ··· 1368 1370 return 0; 1369 1371 1370 1372 out_err2: 1371 - vmw_surface_unreference(&surface); 1373 + vmw_user_object_unref(&vfbs->uo); 1372 1374 kfree(vfbs); 1373 1375 out_err1: 1374 1376 return ret; ··· 1384 1386 { 1385 1387 struct vmw_framebuffer_bo *vfbd = 1386 1388 vmw_framebuffer_to_vfbd(fb); 1387 - 1388 1389 return drm_gem_handle_create(file_priv, &vfbd->buffer->tbo.base, handle); 1389 1390 } 1390 1391 ··· 1403 1406 .destroy = vmw_framebuffer_bo_destroy, 1404 1407 .dirty = drm_atomic_helper_dirtyfb, 1405 1408 }; 1406 - 1407 - /** 1408 - * vmw_create_bo_proxy - create a proxy surface for the buffer object 1409 - * 1410 - * @dev: DRM device 1411 - * @mode_cmd: parameters for the new surface 1412 - * @bo_mob: MOB backing the buffer object 1413 - * @srf_out: newly created surface 1414 - * 1415 - * When the content FB is a buffer object, we create a surface as a proxy to the 1416 - * same buffer. This way we can do a surface copy rather than a surface DMA. 1417 - * This is a more efficient approach 1418 - * 1419 - * RETURNS: 1420 - * 0 on success, error code otherwise 1421 - */ 1422 - static int vmw_create_bo_proxy(struct drm_device *dev, 1423 - const struct drm_mode_fb_cmd2 *mode_cmd, 1424 - struct vmw_bo *bo_mob, 1425 - struct vmw_surface **srf_out) 1426 - { 1427 - struct vmw_surface_metadata metadata = {0}; 1428 - uint32_t format; 1429 - struct vmw_resource *res; 1430 - unsigned int bytes_pp; 1431 - int ret; 1432 - 1433 - switch (mode_cmd->pixel_format) { 1434 - case DRM_FORMAT_ARGB8888: 1435 - case DRM_FORMAT_XRGB8888: 1436 - format = SVGA3D_X8R8G8B8; 1437 - bytes_pp = 4; 1438 - break; 1439 - 1440 - case DRM_FORMAT_RGB565: 1441 - case DRM_FORMAT_XRGB1555: 1442 - format = SVGA3D_R5G6B5; 1443 - bytes_pp = 2; 1444 - break; 1445 - 1446 - case 8: 1447 - format = SVGA3D_P8; 1448 - bytes_pp = 1; 1449 - break; 1450 - 1451 - default: 1452 - DRM_ERROR("Invalid framebuffer format %p4cc\n", 1453 - &mode_cmd->pixel_format); 1454 - return -EINVAL; 1455 - } 1456 - 1457 - metadata.format = format; 1458 - metadata.mip_levels[0] = 1; 1459 - metadata.num_sizes = 1; 1460 - metadata.base_size.width = mode_cmd->pitches[0] / bytes_pp; 1461 - metadata.base_size.height = mode_cmd->height; 1462 - metadata.base_size.depth = 1; 1463 - metadata.scanout = true; 1464 - 1465 - ret = vmw_gb_surface_define(vmw_priv(dev), &metadata, srf_out); 1466 - if (ret) { 1467 - DRM_ERROR("Failed to allocate proxy content buffer\n"); 1468 - return ret; 1469 - } 1470 - 1471 - res = &(*srf_out)->res; 1472 - 1473 - /* Reserve and switch the backing mob. */ 1474 - mutex_lock(&res->dev_priv->cmdbuf_mutex); 1475 - (void) vmw_resource_reserve(res, false, true); 1476 - vmw_user_bo_unref(&res->guest_memory_bo); 1477 - res->guest_memory_bo = vmw_user_bo_ref(bo_mob); 1478 - res->guest_memory_offset = 0; 1479 - vmw_resource_unreserve(res, false, false, false, NULL, 0); 1480 - mutex_unlock(&res->dev_priv->cmdbuf_mutex); 1481 - 1482 - return 0; 1483 - } 1484 - 1485 - 1486 1409 1487 1410 static int vmw_kms_new_framebuffer_bo(struct vmw_private *dev_priv, 1488 1411 struct vmw_bo *bo, ··· 1482 1565 * vmw_kms_new_framebuffer - Create a new framebuffer. 1483 1566 * 1484 1567 * @dev_priv: Pointer to device private struct. 1485 - * @bo: Pointer to buffer object to wrap the kms framebuffer around. 1486 - * Either @bo or @surface must be NULL. 1487 - * @surface: Pointer to a surface to wrap the kms framebuffer around. 1488 - * Either @bo or @surface must be NULL. 1489 - * @only_2d: No presents will occur to this buffer object based framebuffer. 1490 - * This helps the code to do some important optimizations. 1568 + * @uo: Pointer to user object to wrap the kms framebuffer around. 1569 + * Either the buffer or surface inside the user object must be NULL. 1491 1570 * @mode_cmd: Frame-buffer metadata. 1492 1571 */ 1493 1572 struct vmw_framebuffer * 1494 1573 vmw_kms_new_framebuffer(struct vmw_private *dev_priv, 1495 - struct vmw_bo *bo, 1496 - struct vmw_surface *surface, 1497 - bool only_2d, 1574 + struct vmw_user_object *uo, 1498 1575 const struct drm_mode_fb_cmd2 *mode_cmd) 1499 1576 { 1500 1577 struct vmw_framebuffer *vfb = NULL; 1501 - bool is_bo_proxy = false; 1502 1578 int ret; 1503 1579 1504 - /* 1505 - * We cannot use the SurfaceDMA command in an non-accelerated VM, 1506 - * therefore, wrap the buffer object in a surface so we can use the 1507 - * SurfaceCopy command. 1508 - */ 1509 - if (vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height) && 1510 - bo && only_2d && 1511 - mode_cmd->width > 64 && /* Don't create a proxy for cursor */ 1512 - dev_priv->active_display_unit == vmw_du_screen_target) { 1513 - ret = vmw_create_bo_proxy(&dev_priv->drm, mode_cmd, 1514 - bo, &surface); 1515 - if (ret) 1516 - return ERR_PTR(ret); 1517 - 1518 - is_bo_proxy = true; 1519 - } 1520 - 1521 1580 /* Create the new framebuffer depending one what we have */ 1522 - if (surface) { 1523 - ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb, 1524 - mode_cmd, 1525 - is_bo_proxy); 1526 - /* 1527 - * vmw_create_bo_proxy() adds a reference that is no longer 1528 - * needed 1529 - */ 1530 - if (is_bo_proxy) 1531 - vmw_surface_unreference(&surface); 1532 - } else if (bo) { 1533 - ret = vmw_kms_new_framebuffer_bo(dev_priv, bo, &vfb, 1581 + if (vmw_user_object_surface(uo)) { 1582 + ret = vmw_kms_new_framebuffer_surface(dev_priv, uo, &vfb, 1583 + mode_cmd); 1584 + } else if (uo->buffer) { 1585 + ret = vmw_kms_new_framebuffer_bo(dev_priv, uo->buffer, &vfb, 1534 1586 mode_cmd); 1535 1587 } else { 1536 1588 BUG(); ··· 1521 1635 { 1522 1636 struct vmw_private *dev_priv = vmw_priv(dev); 1523 1637 struct vmw_framebuffer *vfb = NULL; 1524 - struct vmw_surface *surface = NULL; 1525 - struct vmw_bo *bo = NULL; 1638 + struct vmw_user_object uo = {0}; 1526 1639 int ret; 1527 1640 1528 1641 /* returns either a bo or surface */ 1529 - ret = vmw_user_lookup_handle(dev_priv, file_priv, 1530 - mode_cmd->handles[0], 1531 - &surface, &bo); 1642 + ret = vmw_user_object_lookup(dev_priv, file_priv, mode_cmd->handles[0], 1643 + &uo); 1532 1644 if (ret) { 1533 1645 DRM_ERROR("Invalid buffer object handle %u (0x%x).\n", 1534 1646 mode_cmd->handles[0], mode_cmd->handles[0]); ··· 1534 1650 } 1535 1651 1536 1652 1537 - if (!bo && 1653 + if (vmw_user_object_surface(&uo) && 1538 1654 !vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height)) { 1539 1655 DRM_ERROR("Surface size cannot exceed %dx%d\n", 1540 1656 dev_priv->texture_max_width, ··· 1543 1659 } 1544 1660 1545 1661 1546 - vfb = vmw_kms_new_framebuffer(dev_priv, bo, surface, 1547 - !(dev_priv->capabilities & SVGA_CAP_3D), 1548 - mode_cmd); 1662 + vfb = vmw_kms_new_framebuffer(dev_priv, &uo, mode_cmd); 1549 1663 if (IS_ERR(vfb)) { 1550 1664 ret = PTR_ERR(vfb); 1551 1665 goto err_out; 1552 1666 } 1553 1667 1554 1668 err_out: 1555 - /* vmw_user_lookup_handle takes one ref so does new_fb */ 1556 - if (bo) 1557 - vmw_user_bo_unref(&bo); 1558 - if (surface) 1559 - vmw_surface_unreference(&surface); 1669 + /* vmw_user_object_lookup takes one ref so does new_fb */ 1670 + vmw_user_object_unref(&uo); 1560 1671 1561 1672 if (ret) { 1562 1673 DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); ··· 2464 2585 } 2465 2586 2466 2587 /** 2467 - * vmw_kms_update_proxy - Helper function to update a proxy surface from 2468 - * its backing MOB. 2469 - * 2470 - * @res: Pointer to the surface resource 2471 - * @clips: Clip rects in framebuffer (surface) space. 2472 - * @num_clips: Number of clips in @clips. 2473 - * @increment: Integer with which to increment the clip counter when looping. 2474 - * Used to skip a predetermined number of clip rects. 2475 - * 2476 - * This function makes sure the proxy surface is updated from its backing MOB 2477 - * using the region given by @clips. The surface resource @res and its backing 2478 - * MOB needs to be reserved and validated on call. 2479 - */ 2480 - int vmw_kms_update_proxy(struct vmw_resource *res, 2481 - const struct drm_clip_rect *clips, 2482 - unsigned num_clips, 2483 - int increment) 2484 - { 2485 - struct vmw_private *dev_priv = res->dev_priv; 2486 - struct drm_vmw_size *size = &vmw_res_to_srf(res)->metadata.base_size; 2487 - struct { 2488 - SVGA3dCmdHeader header; 2489 - SVGA3dCmdUpdateGBImage body; 2490 - } *cmd; 2491 - SVGA3dBox *box; 2492 - size_t copy_size = 0; 2493 - int i; 2494 - 2495 - if (!clips) 2496 - return 0; 2497 - 2498 - cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd) * num_clips); 2499 - if (!cmd) 2500 - return -ENOMEM; 2501 - 2502 - for (i = 0; i < num_clips; ++i, clips += increment, ++cmd) { 2503 - box = &cmd->body.box; 2504 - 2505 - cmd->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; 2506 - cmd->header.size = sizeof(cmd->body); 2507 - cmd->body.image.sid = res->id; 2508 - cmd->body.image.face = 0; 2509 - cmd->body.image.mipmap = 0; 2510 - 2511 - if (clips->x1 > size->width || clips->x2 > size->width || 2512 - clips->y1 > size->height || clips->y2 > size->height) { 2513 - DRM_ERROR("Invalid clips outsize of framebuffer.\n"); 2514 - return -EINVAL; 2515 - } 2516 - 2517 - box->x = clips->x1; 2518 - box->y = clips->y1; 2519 - box->z = 0; 2520 - box->w = clips->x2 - clips->x1; 2521 - box->h = clips->y2 - clips->y1; 2522 - box->d = 1; 2523 - 2524 - copy_size += sizeof(*cmd); 2525 - } 2526 - 2527 - vmw_cmd_commit(dev_priv, copy_size); 2528 - 2529 - return 0; 2530 - } 2531 - 2532 - /** 2533 2588 * vmw_kms_create_implicit_placement_property - Set up the implicit placement 2534 2589 * property. 2535 2590 * ··· 2597 2784 } else { 2598 2785 struct vmw_framebuffer_surface *vfbs = 2599 2786 container_of(update->vfb, typeof(*vfbs), base); 2787 + struct vmw_surface *surf = vmw_user_object_surface(&vfbs->uo); 2600 2788 2601 - ret = vmw_validation_add_resource(&val_ctx, &vfbs->surface->res, 2789 + ret = vmw_validation_add_resource(&val_ctx, &surf->res, 2602 2790 0, VMW_RES_DIRTY_NONE, NULL, 2603 2791 NULL); 2604 2792 } ··· 2754 2940 num_modes = 1 + drm_add_modes_noedid(connector, max_width, max_height); 2755 2941 2756 2942 return num_modes; 2943 + } 2944 + 2945 + struct vmw_user_object *vmw_user_object_ref(struct vmw_user_object *uo) 2946 + { 2947 + if (uo->buffer) 2948 + vmw_user_bo_ref(uo->buffer); 2949 + else if (uo->surface) 2950 + vmw_surface_reference(uo->surface); 2951 + return uo; 2952 + } 2953 + 2954 + void vmw_user_object_unref(struct vmw_user_object *uo) 2955 + { 2956 + if (uo->buffer) 2957 + vmw_user_bo_unref(&uo->buffer); 2958 + else if (uo->surface) 2959 + vmw_surface_unreference(&uo->surface); 2960 + } 2961 + 2962 + struct vmw_bo * 2963 + vmw_user_object_buffer(struct vmw_user_object *uo) 2964 + { 2965 + if (uo->buffer) 2966 + return uo->buffer; 2967 + else if (uo->surface) 2968 + return uo->surface->res.guest_memory_bo; 2969 + return NULL; 2970 + } 2971 + 2972 + struct vmw_surface * 2973 + vmw_user_object_surface(struct vmw_user_object *uo) 2974 + { 2975 + if (uo->buffer) 2976 + return uo->buffer->dumb_surface; 2977 + return uo->surface; 2978 + } 2979 + 2980 + void *vmw_user_object_map(struct vmw_user_object *uo) 2981 + { 2982 + struct vmw_bo *bo = vmw_user_object_buffer(uo); 2983 + 2984 + WARN_ON(!bo); 2985 + return vmw_bo_map_and_cache(bo); 2986 + } 2987 + 2988 + void *vmw_user_object_map_size(struct vmw_user_object *uo, size_t size) 2989 + { 2990 + struct vmw_bo *bo = vmw_user_object_buffer(uo); 2991 + 2992 + WARN_ON(!bo); 2993 + return vmw_bo_map_and_cache_size(bo, size); 2994 + } 2995 + 2996 + void vmw_user_object_unmap(struct vmw_user_object *uo) 2997 + { 2998 + struct vmw_bo *bo = vmw_user_object_buffer(uo); 2999 + int ret; 3000 + 3001 + WARN_ON(!bo); 3002 + 3003 + /* Fence the mob creation so we are guarateed to have the mob */ 3004 + ret = ttm_bo_reserve(&bo->tbo, false, false, NULL); 3005 + if (ret != 0) 3006 + return; 3007 + 3008 + vmw_bo_unmap(bo); 3009 + vmw_bo_pin_reserved(bo, false); 3010 + 3011 + ttm_bo_unreserve(&bo->tbo); 3012 + } 3013 + 3014 + bool vmw_user_object_is_mapped(struct vmw_user_object *uo) 3015 + { 3016 + struct vmw_bo *bo; 3017 + 3018 + if (!uo || vmw_user_object_is_null(uo)) 3019 + return false; 3020 + 3021 + bo = vmw_user_object_buffer(uo); 3022 + 3023 + if (WARN_ON(!bo)) 3024 + return false; 3025 + 3026 + WARN_ON(bo->map.bo && !bo->map.virtual); 3027 + return bo->map.virtual; 3028 + } 3029 + 3030 + bool vmw_user_object_is_null(struct vmw_user_object *uo) 3031 + { 3032 + return !uo->buffer && !uo->surface; 2757 3033 }
+6 -11
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5 6 * 6 7 * Permission is hereby granted, free of charge, to any person obtaining a 7 8 * copy of this software and associated documentation files (the ··· 222 221 223 222 struct vmw_framebuffer_surface { 224 223 struct vmw_framebuffer base; 225 - struct vmw_surface *surface; 226 - bool is_bo_proxy; /* true if this is proxy surface for DMA buf */ 224 + struct vmw_user_object uo; 227 225 }; 228 - 229 226 230 227 struct vmw_framebuffer_bo { 231 228 struct vmw_framebuffer base; ··· 276 277 */ 277 278 struct vmw_plane_state { 278 279 struct drm_plane_state base; 279 - struct vmw_surface *surf; 280 - struct vmw_bo *bo; 280 + struct vmw_user_object uo; 281 281 282 282 int content_fb_type; 283 283 unsigned long bo_size; ··· 455 457 uint32_t num_clips); 456 458 struct vmw_framebuffer * 457 459 vmw_kms_new_framebuffer(struct vmw_private *dev_priv, 458 - struct vmw_bo *bo, 459 - struct vmw_surface *surface, 460 - bool only_2d, 460 + struct vmw_user_object *uo, 461 461 const struct drm_mode_fb_cmd2 *mode_cmd); 462 462 void vmw_guess_mode_timing(struct drm_display_mode *mode); 463 463 void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv); ··· 482 486 struct drm_plane_state *vmw_du_plane_duplicate_state(struct drm_plane *plane); 483 487 void vmw_du_plane_destroy_state(struct drm_plane *plane, 484 488 struct drm_plane_state *state); 485 - void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps, 486 - bool unreference); 489 + void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps); 487 490 488 491 int vmw_du_crtc_atomic_check(struct drm_crtc *crtc, 489 492 struct drm_atomic_state *state);
+9 -5
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5 6 * 6 7 * Permission is hereby granted, free of charge, to any person obtaining a 7 8 * copy of this software and associated documentation files (the ··· 148 147 struct vmw_bo *buf; 149 148 int ret; 150 149 151 - buf = vfb->bo ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : 152 - vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.guest_memory_bo; 150 + buf = vfb->bo ? 151 + vmw_framebuffer_to_vfbd(&vfb->base)->buffer : 152 + vmw_user_object_buffer(&vmw_framebuffer_to_vfbs(&vfb->base)->uo); 153 153 154 154 if (!buf) 155 155 return 0; ··· 171 169 struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); 172 170 struct vmw_bo *buf; 173 171 174 - buf = vfb->bo ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : 175 - vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.guest_memory_bo; 172 + buf = vfb->bo ? 173 + vmw_framebuffer_to_vfbd(&vfb->base)->buffer : 174 + vmw_user_object_buffer(&vmw_framebuffer_to_vfbs(&vfb->base)->uo); 175 + 176 176 177 177 if (WARN_ON(!buf)) 178 178 return 0;
+1 -1
drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
··· 92 92 { 93 93 struct vmw_escape_video_flush *flush; 94 94 size_t fifo_size; 95 - bool have_so = (dev_priv->active_display_unit == vmw_du_screen_object); 95 + bool have_so = (dev_priv->active_display_unit != vmw_du_legacy); 96 96 int i, num_items; 97 97 SVGAGuestPtr ptr; 98 98
+28 -4
drivers/gpu/drm/vmwgfx/vmwgfx_prime.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2013 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright (c) 2013-2024 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5 6 * 6 7 * Permission is hereby granted, free of charge, to any person obtaining a 7 8 * copy of this software and associated documentation files (the ··· 32 31 */ 33 32 34 33 #include "vmwgfx_drv.h" 34 + #include "vmwgfx_bo.h" 35 35 #include "ttm_object.h" 36 36 #include <linux/dma-buf.h> 37 37 ··· 90 88 uint32_t handle, uint32_t flags, 91 89 int *prime_fd) 92 90 { 91 + struct vmw_private *vmw = vmw_priv(dev); 93 92 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 93 + struct vmw_bo *vbo; 94 94 int ret; 95 + int surf_handle; 95 96 96 - if (handle > VMWGFX_NUM_MOB) 97 + if (handle > VMWGFX_NUM_MOB) { 97 98 ret = ttm_prime_handle_to_fd(tfile, handle, flags, prime_fd); 98 - else 99 - ret = drm_gem_prime_handle_to_fd(dev, file_priv, handle, flags, prime_fd); 99 + } else { 100 + ret = vmw_user_bo_lookup(file_priv, handle, &vbo); 101 + if (ret) 102 + return ret; 103 + if (vbo && vbo->is_dumb) { 104 + ret = drm_gem_prime_handle_to_fd(dev, file_priv, handle, 105 + flags, prime_fd); 106 + } else { 107 + surf_handle = vmw_lookup_surface_handle_for_buffer(vmw, 108 + vbo, 109 + handle); 110 + if (surf_handle > 0) 111 + ret = ttm_prime_handle_to_fd(tfile, surf_handle, 112 + flags, prime_fd); 113 + else 114 + ret = drm_gem_prime_handle_to_fd(dev, file_priv, 115 + handle, flags, 116 + prime_fd); 117 + } 118 + vmw_user_bo_unref(&vbo); 119 + } 100 120 101 121 return ret; 102 122 }
+18 -9
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5 6 * 6 7 * Permission is hereby granted, free of charge, to any person obtaining a 7 8 * copy of this software and associated documentation files (the ··· 59 58 60 59 rb_link_node(&res->mob_node, parent, new); 61 60 rb_insert_color(&res->mob_node, &gbo->res_tree); 61 + vmw_bo_del_detached_resource(gbo, res); 62 62 63 63 vmw_bo_prio_add(gbo, res->used_prio); 64 64 } ··· 289 287 * 290 288 * The pointer this pointed at by out_surf and out_buf needs to be null. 291 289 */ 292 - int vmw_user_lookup_handle(struct vmw_private *dev_priv, 290 + int vmw_user_object_lookup(struct vmw_private *dev_priv, 293 291 struct drm_file *filp, 294 - uint32_t handle, 295 - struct vmw_surface **out_surf, 296 - struct vmw_bo **out_buf) 292 + u32 handle, 293 + struct vmw_user_object *uo) 297 294 { 298 295 struct ttm_object_file *tfile = vmw_fpriv(filp)->tfile; 299 296 struct vmw_resource *res; 300 297 int ret; 301 298 302 - BUG_ON(*out_surf || *out_buf); 299 + WARN_ON(uo->surface || uo->buffer); 303 300 304 301 ret = vmw_user_resource_lookup_handle(dev_priv, tfile, handle, 305 302 user_surface_converter, 306 303 &res); 307 304 if (!ret) { 308 - *out_surf = vmw_res_to_srf(res); 305 + uo->surface = vmw_res_to_srf(res); 309 306 return 0; 310 307 } 311 308 312 - *out_surf = NULL; 313 - ret = vmw_user_bo_lookup(filp, handle, out_buf); 309 + uo->surface = NULL; 310 + ret = vmw_user_bo_lookup(filp, handle, &uo->buffer); 311 + if (!ret && !uo->buffer->is_dumb) { 312 + uo->surface = vmw_lookup_surface_for_buffer(dev_priv, 313 + uo->buffer, 314 + handle); 315 + if (uo->surface) 316 + vmw_user_bo_unref(&uo->buffer); 317 + } 318 + 314 319 return ret; 315 320 } 316 321
+19 -14
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2011-2023 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright (c) 2011-2024 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5 6 * 6 7 * Permission is hereby granted, free of charge, to any person obtaining a 7 8 * copy of this software and associated documentation files (the ··· 241 240 struct vmw_connector_state *vmw_conn_state; 242 241 int x, y; 243 242 244 - sou->buffer = vps->bo; 243 + sou->buffer = vmw_user_object_buffer(&vps->uo); 245 244 246 245 conn_state = sou->base.connector.state; 247 246 vmw_conn_state = vmw_connector_state_to_vcs(conn_state); ··· 377 376 struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 378 377 struct drm_crtc *crtc = plane->state->crtc ? 379 378 plane->state->crtc : old_state->crtc; 379 + struct vmw_bo *bo = vmw_user_object_buffer(&vps->uo); 380 380 381 - if (vps->bo) 382 - vmw_bo_unpin(vmw_priv(crtc->dev), vps->bo, false); 383 - vmw_bo_unreference(&vps->bo); 381 + if (bo) 382 + vmw_bo_unpin(vmw_priv(crtc->dev), bo, false); 383 + vmw_user_object_unref(&vps->uo); 384 384 vps->bo_size = 0; 385 385 386 386 vmw_du_plane_cleanup_fb(plane, old_state); ··· 413 411 .bo_type = ttm_bo_type_device, 414 412 .pin = true 415 413 }; 414 + struct vmw_bo *bo = NULL; 416 415 417 416 if (!new_fb) { 418 - vmw_bo_unreference(&vps->bo); 417 + vmw_user_object_unref(&vps->uo); 419 418 vps->bo_size = 0; 420 419 421 420 return 0; ··· 425 422 bo_params.size = new_state->crtc_w * new_state->crtc_h * 4; 426 423 dev_priv = vmw_priv(crtc->dev); 427 424 428 - if (vps->bo) { 425 + bo = vmw_user_object_buffer(&vps->uo); 426 + if (bo) { 429 427 if (vps->bo_size == bo_params.size) { 430 428 /* 431 429 * Note that this might temporarily up the pin-count 432 430 * to 2, until cleanup_fb() is called. 433 431 */ 434 - return vmw_bo_pin_in_vram(dev_priv, vps->bo, 435 - true); 432 + return vmw_bo_pin_in_vram(dev_priv, bo, true); 436 433 } 437 434 438 - vmw_bo_unreference(&vps->bo); 435 + vmw_user_object_unref(&vps->uo); 439 436 vps->bo_size = 0; 440 437 } 441 438 ··· 445 442 * resume the overlays, this is preferred to failing to alloc. 446 443 */ 447 444 vmw_overlay_pause_all(dev_priv); 448 - ret = vmw_bo_create(dev_priv, &bo_params, &vps->bo); 445 + ret = vmw_gem_object_create(dev_priv, &bo_params, &vps->uo.buffer); 449 446 vmw_overlay_resume_all(dev_priv); 450 447 if (ret) 451 448 return ret; ··· 456 453 * TTM already thinks the buffer is pinned, but make sure the 457 454 * pin_count is upped. 458 455 */ 459 - return vmw_bo_pin_in_vram(dev_priv, vps->bo, true); 456 + return vmw_bo_pin_in_vram(dev_priv, vps->uo.buffer, true); 460 457 } 461 458 462 459 static uint32_t vmw_sou_bo_fifo_size(struct vmw_du_update_plane *update, ··· 583 580 { 584 581 struct vmw_kms_sou_dirty_cmd *blit = cmd; 585 582 struct vmw_framebuffer_surface *vfbs; 583 + struct vmw_surface *surf = NULL; 586 584 587 585 vfbs = container_of(update->vfb, typeof(*vfbs), base); 588 586 ··· 591 587 blit->header.size = sizeof(blit->body) + sizeof(SVGASignedRect) * 592 588 num_hits; 593 589 594 - blit->body.srcImage.sid = vfbs->surface->res.id; 590 + surf = vmw_user_object_surface(&vfbs->uo); 591 + blit->body.srcImage.sid = surf->res.id; 595 592 blit->body.destScreenId = update->du->unit; 596 593 597 594 /* Update the source and destination bounding box later in post_clip */ ··· 1109 1104 int ret; 1110 1105 1111 1106 if (!srf) 1112 - srf = &vfbs->surface->res; 1107 + srf = &vmw_user_object_surface(&vfbs->uo)->res; 1113 1108 1114 1109 ret = vmw_validation_add_resource(&val_ctx, srf, 0, VMW_RES_DIRTY_NONE, 1115 1110 NULL, NULL);
+85 -89
drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /****************************************************************************** 3 3 * 4 - * COPYRIGHT (C) 2014-2023 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright (c) 2014-2024 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5 6 * 6 7 * Permission is hereby granted, free of charge, to any person obtaining a 7 8 * copy of this software and associated documentation files (the ··· 30 29 #include "vmwgfx_kms.h" 31 30 #include "vmwgfx_vkms.h" 32 31 #include "vmw_surface_cache.h" 32 + #include <linux/fsnotify.h> 33 33 34 34 #include <drm/drm_atomic.h> 35 35 #include <drm/drm_atomic_helper.h> ··· 737 735 int ret; 738 736 739 737 if (!srf) 740 - srf = &vfbs->surface->res; 738 + srf = &vmw_user_object_surface(&vfbs->uo)->res; 741 739 742 740 ret = vmw_validation_add_resource(&val_ctx, srf, 0, VMW_RES_DIRTY_NONE, 743 741 NULL, NULL); ··· 747 745 ret = vmw_validation_prepare(&val_ctx, &dev_priv->cmdbuf_mutex, true); 748 746 if (ret) 749 747 goto out_unref; 750 - 751 - if (vfbs->is_bo_proxy) { 752 - ret = vmw_kms_update_proxy(srf, clips, num_clips, inc); 753 - if (ret) 754 - goto out_finish; 755 - } 756 748 757 749 sdirty.base.fifo_commit = vmw_kms_stdu_surface_fifo_commit; 758 750 sdirty.base.clip = vmw_kms_stdu_surface_clip; ··· 761 765 ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, 762 766 dest_x, dest_y, num_clips, inc, 763 767 &sdirty.base); 764 - out_finish: 768 + 765 769 vmw_kms_helper_validation_finish(dev_priv, NULL, &val_ctx, out_fence, 766 770 NULL); 767 771 ··· 873 877 return MODE_OK; 874 878 } 875 879 880 + /* 881 + * Trigger a modeset if the X,Y position of the Screen Target changes. 882 + * This is needed when multi-mon is cycled. The original Screen Target will have 883 + * the same mode but its relative X,Y position in the topology will change. 884 + */ 885 + static int vmw_stdu_connector_atomic_check(struct drm_connector *conn, 886 + struct drm_atomic_state *state) 887 + { 888 + struct drm_connector_state *conn_state; 889 + struct vmw_screen_target_display_unit *du; 890 + struct drm_crtc_state *new_crtc_state; 891 + 892 + conn_state = drm_atomic_get_connector_state(state, conn); 893 + du = vmw_connector_to_stdu(conn); 894 + 895 + if (!conn_state->crtc) 896 + return 0; 897 + 898 + new_crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); 899 + if (du->base.gui_x != du->base.set_gui_x || 900 + du->base.gui_y != du->base.set_gui_y) 901 + new_crtc_state->mode_changed = true; 902 + 903 + return 0; 904 + } 905 + 876 906 static const struct drm_connector_funcs vmw_stdu_connector_funcs = { 877 907 .dpms = vmw_du_connector_dpms, 878 908 .detect = vmw_du_connector_detect, ··· 913 891 static const struct 914 892 drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = { 915 893 .get_modes = vmw_connector_get_modes, 916 - .mode_valid = vmw_stdu_connector_mode_valid 894 + .mode_valid = vmw_stdu_connector_mode_valid, 895 + .atomic_check = vmw_stdu_connector_atomic_check, 917 896 }; 918 897 919 898 ··· 941 918 { 942 919 struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 943 920 944 - if (vps->surf) 921 + if (vmw_user_object_surface(&vps->uo)) 945 922 WARN_ON(!vps->pinned); 946 - 947 923 vmw_du_plane_cleanup_fb(plane, old_state); 948 924 949 925 vps->content_fb_type = SAME_AS_DISPLAY; 950 926 vps->cpp = 0; 951 927 } 952 - 953 928 954 929 955 930 /** ··· 973 952 enum stdu_content_type new_content_type; 974 953 struct vmw_framebuffer_surface *new_vfbs; 975 954 uint32_t hdisplay = new_state->crtc_w, vdisplay = new_state->crtc_h; 955 + struct drm_plane_state *old_state = plane->state; 956 + struct drm_rect rect; 976 957 int ret; 977 958 978 959 /* No FB to prepare */ 979 960 if (!new_fb) { 980 - if (vps->surf) { 961 + if (vmw_user_object_surface(&vps->uo)) { 981 962 WARN_ON(vps->pinned != 0); 982 - vmw_surface_unreference(&vps->surf); 963 + vmw_user_object_unref(&vps->uo); 983 964 } 984 965 985 966 return 0; ··· 991 968 new_vfbs = (vfb->bo) ? NULL : vmw_framebuffer_to_vfbs(new_fb); 992 969 993 970 if (new_vfbs && 994 - new_vfbs->surface->metadata.base_size.width == hdisplay && 995 - new_vfbs->surface->metadata.base_size.height == vdisplay) 971 + vmw_user_object_surface(&new_vfbs->uo)->metadata.base_size.width == hdisplay && 972 + vmw_user_object_surface(&new_vfbs->uo)->metadata.base_size.height == vdisplay) 996 973 new_content_type = SAME_AS_DISPLAY; 997 974 else if (vfb->bo) 998 975 new_content_type = SEPARATE_BO; ··· 1030 1007 metadata.num_sizes = 1; 1031 1008 metadata.scanout = true; 1032 1009 } else { 1033 - metadata = new_vfbs->surface->metadata; 1010 + metadata = vmw_user_object_surface(&new_vfbs->uo)->metadata; 1034 1011 } 1035 1012 1036 1013 metadata.base_size.width = hdisplay; 1037 1014 metadata.base_size.height = vdisplay; 1038 1015 metadata.base_size.depth = 1; 1039 1016 1040 - if (vps->surf) { 1017 + if (vmw_user_object_surface(&vps->uo)) { 1041 1018 struct drm_vmw_size cur_base_size = 1042 - vps->surf->metadata.base_size; 1019 + vmw_user_object_surface(&vps->uo)->metadata.base_size; 1043 1020 1044 1021 if (cur_base_size.width != metadata.base_size.width || 1045 1022 cur_base_size.height != metadata.base_size.height || 1046 - vps->surf->metadata.format != metadata.format) { 1023 + vmw_user_object_surface(&vps->uo)->metadata.format != metadata.format) { 1047 1024 WARN_ON(vps->pinned != 0); 1048 - vmw_surface_unreference(&vps->surf); 1025 + vmw_user_object_unref(&vps->uo); 1049 1026 } 1050 1027 1051 1028 } 1052 1029 1053 - if (!vps->surf) { 1030 + if (!vmw_user_object_surface(&vps->uo)) { 1054 1031 ret = vmw_gb_surface_define(dev_priv, &metadata, 1055 - &vps->surf); 1032 + &vps->uo.surface); 1056 1033 if (ret != 0) { 1057 1034 DRM_ERROR("Couldn't allocate STDU surface.\n"); 1058 1035 return ret; ··· 1065 1042 * The only time we add a reference in prepare_fb is if the 1066 1043 * state object doesn't have a reference to begin with 1067 1044 */ 1068 - if (vps->surf) { 1045 + if (vmw_user_object_surface(&vps->uo)) { 1069 1046 WARN_ON(vps->pinned != 0); 1070 - vmw_surface_unreference(&vps->surf); 1047 + vmw_user_object_unref(&vps->uo); 1071 1048 } 1072 1049 1073 - vps->surf = vmw_surface_reference(new_vfbs->surface); 1050 + memcpy(&vps->uo, &new_vfbs->uo, sizeof(vps->uo)); 1051 + vmw_user_object_ref(&vps->uo); 1074 1052 } 1075 1053 1076 - if (vps->surf) { 1054 + if (vmw_user_object_surface(&vps->uo)) { 1077 1055 1078 1056 /* Pin new surface before flipping */ 1079 - ret = vmw_resource_pin(&vps->surf->res, false); 1057 + ret = vmw_resource_pin(&vmw_user_object_surface(&vps->uo)->res, false); 1080 1058 if (ret) 1081 1059 goto out_srf_unref; 1082 1060 ··· 1085 1061 } 1086 1062 1087 1063 vps->content_fb_type = new_content_type; 1064 + 1065 + /* 1066 + * The drm fb code will do blit's via the vmap interface, which doesn't 1067 + * trigger vmw_bo page dirty tracking due to being kernel side (and thus 1068 + * doesn't require mmap'ing) so we have to update the surface's dirty 1069 + * regions by hand but we want to be careful to not overwrite the 1070 + * resource if it has been written to by the gpu (res_dirty). 1071 + */ 1072 + if (vps->uo.buffer && vps->uo.buffer->is_dumb) { 1073 + struct vmw_surface *surf = vmw_user_object_surface(&vps->uo); 1074 + struct vmw_resource *res = &surf->res; 1075 + 1076 + if (!res->res_dirty && drm_atomic_helper_damage_merged(old_state, 1077 + new_state, 1078 + &rect)) { 1079 + /* 1080 + * At some point it might be useful to actually translate 1081 + * (rect.x1, rect.y1) => start, and (rect.x2, rect.y2) => end, 1082 + * but currently the fb code will just report the entire fb 1083 + * dirty so in practice it doesn't matter. 1084 + */ 1085 + pgoff_t start = res->guest_memory_offset >> PAGE_SHIFT; 1086 + pgoff_t end = __KERNEL_DIV_ROUND_UP(res->guest_memory_offset + 1087 + res->guest_memory_size, 1088 + PAGE_SIZE); 1089 + vmw_resource_dirty_update(res, start, end); 1090 + } 1091 + } 1088 1092 1089 1093 /* 1090 1094 * This should only happen if the buffer object is too large to create a ··· 1124 1072 return 0; 1125 1073 1126 1074 out_srf_unref: 1127 - vmw_surface_unreference(&vps->surf); 1075 + vmw_user_object_unref(&vps->uo); 1128 1076 return ret; 1129 1077 } 1130 1078 ··· 1266 1214 vmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update, 1267 1215 uint32_t num_hits) 1268 1216 { 1269 - struct vmw_framebuffer_surface *vfbs; 1270 1217 uint32_t size = 0; 1271 - 1272 - vfbs = container_of(update->vfb, typeof(*vfbs), base); 1273 - 1274 - if (vfbs->is_bo_proxy) 1275 - size += sizeof(struct vmw_stdu_update_gb_image) * num_hits; 1276 1218 1277 1219 size += sizeof(struct vmw_stdu_update); 1278 1220 ··· 1276 1230 static uint32_t vmw_stdu_surface_fifo_size(struct vmw_du_update_plane *update, 1277 1231 uint32_t num_hits) 1278 1232 { 1279 - struct vmw_framebuffer_surface *vfbs; 1280 1233 uint32_t size = 0; 1281 - 1282 - vfbs = container_of(update->vfb, typeof(*vfbs), base); 1283 - 1284 - if (vfbs->is_bo_proxy) 1285 - size += sizeof(struct vmw_stdu_update_gb_image) * num_hits; 1286 1234 1287 1235 size += sizeof(struct vmw_stdu_surface_copy) + sizeof(SVGA3dCopyBox) * 1288 1236 num_hits + sizeof(struct vmw_stdu_update); 1289 1237 1290 1238 return size; 1291 - } 1292 - 1293 - static uint32_t 1294 - vmw_stdu_surface_update_proxy(struct vmw_du_update_plane *update, void *cmd) 1295 - { 1296 - struct vmw_framebuffer_surface *vfbs; 1297 - struct drm_plane_state *state = update->plane->state; 1298 - struct drm_plane_state *old_state = update->old_state; 1299 - struct vmw_stdu_update_gb_image *cmd_update = cmd; 1300 - struct drm_atomic_helper_damage_iter iter; 1301 - struct drm_rect clip; 1302 - uint32_t copy_size = 0; 1303 - 1304 - vfbs = container_of(update->vfb, typeof(*vfbs), base); 1305 - 1306 - /* 1307 - * proxy surface is special where a buffer object type fb is wrapped 1308 - * in a surface and need an update gb image command to sync with device. 1309 - */ 1310 - drm_atomic_helper_damage_iter_init(&iter, old_state, state); 1311 - drm_atomic_for_each_plane_damage(&iter, &clip) { 1312 - SVGA3dBox *box = &cmd_update->body.box; 1313 - 1314 - cmd_update->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; 1315 - cmd_update->header.size = sizeof(cmd_update->body); 1316 - cmd_update->body.image.sid = vfbs->surface->res.id; 1317 - cmd_update->body.image.face = 0; 1318 - cmd_update->body.image.mipmap = 0; 1319 - 1320 - box->x = clip.x1; 1321 - box->y = clip.y1; 1322 - box->z = 0; 1323 - box->w = drm_rect_width(&clip); 1324 - box->h = drm_rect_height(&clip); 1325 - box->d = 1; 1326 - 1327 - copy_size += sizeof(*cmd_update); 1328 - cmd_update++; 1329 - } 1330 - 1331 - return copy_size; 1332 1239 } 1333 1240 1334 1241 static uint32_t ··· 1298 1299 cmd_copy->header.id = SVGA_3D_CMD_SURFACE_COPY; 1299 1300 cmd_copy->header.size = sizeof(cmd_copy->body) + sizeof(SVGA3dCopyBox) * 1300 1301 num_hits; 1301 - cmd_copy->body.src.sid = vfbs->surface->res.id; 1302 + cmd_copy->body.src.sid = vmw_user_object_surface(&vfbs->uo)->res.id; 1302 1303 cmd_copy->body.dest.sid = stdu->display_srf->res.id; 1303 1304 1304 1305 return sizeof(*cmd_copy); ··· 1369 1370 srf_update.mutex = &dev_priv->cmdbuf_mutex; 1370 1371 srf_update.intr = true; 1371 1372 1372 - if (vfbs->is_bo_proxy) 1373 - srf_update.post_prepare = vmw_stdu_surface_update_proxy; 1374 - 1375 - if (vfbs->surface->res.id != stdu->display_srf->res.id) { 1373 + if (vmw_user_object_surface(&vfbs->uo)->res.id != stdu->display_srf->res.id) { 1376 1374 srf_update.calc_fifo_size = vmw_stdu_surface_fifo_size; 1377 1375 srf_update.pre_clip = vmw_stdu_surface_populate_copy; 1378 1376 srf_update.clip = vmw_stdu_surface_populate_clip; ··· 1413 1417 stdu = vmw_crtc_to_stdu(crtc); 1414 1418 dev_priv = vmw_priv(crtc->dev); 1415 1419 1416 - stdu->display_srf = vps->surf; 1420 + stdu->display_srf = vmw_user_object_surface(&vps->uo); 1417 1421 stdu->content_fb_type = vps->content_fb_type; 1418 1422 stdu->cpp = vps->cpp; 1419 1423
+271 -9
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term 5 + * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5 6 * 6 7 * Permission is hereby granted, free of charge, to any person obtaining a 7 8 * copy of this software and associated documentation files (the ··· 37 36 #include <drm/ttm/ttm_placement.h> 38 37 39 38 #define SVGA3D_FLAGS_64(upper32, lower32) (((uint64_t)upper32 << 32) | lower32) 40 - #define SVGA3D_FLAGS_UPPER_32(svga3d_flags) (svga3d_flags >> 32) 41 - #define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \ 42 - (svga3d_flags & ((uint64_t)U32_MAX)) 43 39 44 40 /** 45 41 * struct vmw_user_surface - User-space visible surface resource ··· 684 686 struct vmw_resource *res = &user_srf->srf.res; 685 687 686 688 *p_base = NULL; 689 + 690 + /* 691 + * Dumb buffers own the resource and they'll unref the 692 + * resource themselves 693 + */ 694 + if (res && res->guest_memory_bo && res->guest_memory_bo->is_dumb) 695 + return; 696 + 687 697 vmw_resource_unreference(&res); 688 698 } 689 699 ··· 818 812 } 819 813 } 820 814 res->guest_memory_size = cur_bo_offset; 821 - if (metadata->scanout && 815 + if (!file_priv->atomic && 816 + metadata->scanout && 822 817 metadata->num_sizes == 1 && 823 818 metadata->sizes[0].width == VMW_CURSOR_SNOOP_WIDTH && 824 819 metadata->sizes[0].height == VMW_CURSOR_SNOOP_HEIGHT && ··· 871 864 vmw_resource_unreference(&res); 872 865 goto out_unlock; 873 866 } 867 + vmw_bo_add_detached_resource(res->guest_memory_bo, res); 874 868 } 875 869 876 870 tmp = vmw_resource_reference(&srf->res); ··· 900 892 return ret; 901 893 } 902 894 895 + static struct vmw_user_surface * 896 + vmw_lookup_user_surface_for_buffer(struct vmw_private *vmw, struct vmw_bo *bo, 897 + u32 handle) 898 + { 899 + struct vmw_user_surface *user_srf = NULL; 900 + struct vmw_surface *surf; 901 + struct ttm_base_object *base; 902 + 903 + surf = vmw_bo_surface(bo); 904 + if (surf) { 905 + rcu_read_lock(); 906 + user_srf = container_of(surf, struct vmw_user_surface, srf); 907 + base = &user_srf->prime.base; 908 + if (base && !kref_get_unless_zero(&base->refcount)) { 909 + drm_dbg_driver(&vmw->drm, 910 + "%s: referencing a stale surface handle %d\n", 911 + __func__, handle); 912 + base = NULL; 913 + user_srf = NULL; 914 + } 915 + rcu_read_unlock(); 916 + } 917 + 918 + return user_srf; 919 + } 920 + 921 + struct vmw_surface *vmw_lookup_surface_for_buffer(struct vmw_private *vmw, 922 + struct vmw_bo *bo, 923 + u32 handle) 924 + { 925 + struct vmw_user_surface *user_srf = 926 + vmw_lookup_user_surface_for_buffer(vmw, bo, handle); 927 + struct vmw_surface *surf = NULL; 928 + struct ttm_base_object *base; 929 + 930 + if (user_srf) { 931 + surf = vmw_surface_reference(&user_srf->srf); 932 + base = &user_srf->prime.base; 933 + ttm_base_object_unref(&base); 934 + } 935 + return surf; 936 + } 937 + 938 + u32 vmw_lookup_surface_handle_for_buffer(struct vmw_private *vmw, 939 + struct vmw_bo *bo, 940 + u32 handle) 941 + { 942 + struct vmw_user_surface *user_srf = 943 + vmw_lookup_user_surface_for_buffer(vmw, bo, handle); 944 + int surf_handle = 0; 945 + struct ttm_base_object *base; 946 + 947 + if (user_srf) { 948 + base = &user_srf->prime.base; 949 + surf_handle = (u32)base->handle; 950 + ttm_base_object_unref(&base); 951 + } 952 + return surf_handle; 953 + } 954 + 955 + static int vmw_buffer_prime_to_surface_base(struct vmw_private *dev_priv, 956 + struct drm_file *file_priv, 957 + u32 fd, u32 *handle, 958 + struct ttm_base_object **base_p) 959 + { 960 + struct ttm_base_object *base; 961 + struct vmw_bo *bo; 962 + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 963 + struct vmw_user_surface *user_srf; 964 + int ret; 965 + 966 + ret = drm_gem_prime_fd_to_handle(&dev_priv->drm, file_priv, fd, handle); 967 + if (ret) { 968 + drm_warn(&dev_priv->drm, 969 + "Wasn't able to find user buffer for fd = %u.\n", fd); 970 + return ret; 971 + } 972 + 973 + ret = vmw_user_bo_lookup(file_priv, *handle, &bo); 974 + if (ret) { 975 + drm_warn(&dev_priv->drm, 976 + "Wasn't able to lookup user buffer for handle = %u.\n", *handle); 977 + return ret; 978 + } 979 + 980 + user_srf = vmw_lookup_user_surface_for_buffer(dev_priv, bo, *handle); 981 + if (WARN_ON(!user_srf)) { 982 + drm_warn(&dev_priv->drm, 983 + "User surface fd %d (handle %d) is null.\n", fd, *handle); 984 + ret = -EINVAL; 985 + goto out; 986 + } 987 + 988 + base = &user_srf->prime.base; 989 + ret = ttm_ref_object_add(tfile, base, NULL, false); 990 + if (ret) { 991 + drm_warn(&dev_priv->drm, 992 + "Couldn't add an object ref for the buffer (%d).\n", *handle); 993 + goto out; 994 + } 995 + 996 + *base_p = base; 997 + out: 998 + vmw_user_bo_unref(&bo); 999 + 1000 + return ret; 1001 + } 903 1002 904 1003 static int 905 1004 vmw_surface_handle_reference(struct vmw_private *dev_priv, ··· 1016 901 struct ttm_base_object **base_p) 1017 902 { 1018 903 struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 1019 - struct vmw_user_surface *user_srf; 904 + struct vmw_user_surface *user_srf = NULL; 1020 905 uint32_t handle; 1021 906 struct ttm_base_object *base; 1022 907 int ret; 1023 908 1024 909 if (handle_type == DRM_VMW_HANDLE_PRIME) { 1025 910 ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle); 1026 - if (unlikely(ret != 0)) 1027 - return ret; 911 + if (ret) 912 + return vmw_buffer_prime_to_surface_base(dev_priv, 913 + file_priv, 914 + u_handle, 915 + &handle, 916 + base_p); 1028 917 } else { 1029 918 handle = u_handle; 1030 919 } ··· 1622 1503 ret = vmw_user_bo_lookup(file_priv, req->base.buffer_handle, 1623 1504 &res->guest_memory_bo); 1624 1505 if (ret == 0) { 1625 - if (res->guest_memory_bo->tbo.base.size < res->guest_memory_size) { 1506 + if (res->guest_memory_bo->is_dumb) { 1507 + VMW_DEBUG_USER("Can't backup surface with a dumb buffer.\n"); 1508 + vmw_user_bo_unref(&res->guest_memory_bo); 1509 + ret = -EINVAL; 1510 + goto out_unlock; 1511 + } else if (res->guest_memory_bo->tbo.base.size < res->guest_memory_size) { 1626 1512 VMW_DEBUG_USER("Surface backup buffer too small.\n"); 1627 1513 vmw_user_bo_unref(&res->guest_memory_bo); 1628 1514 ret = -EINVAL; ··· 1684 1560 rep->handle = user_srf->prime.base.handle; 1685 1561 rep->backup_size = res->guest_memory_size; 1686 1562 if (res->guest_memory_bo) { 1563 + vmw_bo_add_detached_resource(res->guest_memory_bo, res); 1687 1564 rep->buffer_map_handle = 1688 1565 drm_vma_node_offset_addr(&res->guest_memory_bo->tbo.base.vma_node); 1689 1566 rep->buffer_size = res->guest_memory_bo->tbo.base.size; ··· 2223 2098 return ret; 2224 2099 2225 2100 out_unlock: 2101 + return ret; 2102 + } 2103 + 2104 + static SVGA3dSurfaceFormat vmw_format_bpp_to_svga(struct vmw_private *vmw, 2105 + int bpp) 2106 + { 2107 + switch (bpp) { 2108 + case 8: /* DRM_FORMAT_C8 */ 2109 + return SVGA3D_P8; 2110 + case 16: /* DRM_FORMAT_RGB565 */ 2111 + return SVGA3D_R5G6B5; 2112 + case 32: /* DRM_FORMAT_XRGB8888 */ 2113 + if (has_sm4_context(vmw)) 2114 + return SVGA3D_B8G8R8X8_UNORM; 2115 + return SVGA3D_X8R8G8B8; 2116 + default: 2117 + drm_warn(&vmw->drm, "Unsupported format bpp: %d\n", bpp); 2118 + return SVGA3D_X8R8G8B8; 2119 + } 2120 + } 2121 + 2122 + /** 2123 + * vmw_dumb_create - Create a dumb kms buffer 2124 + * 2125 + * @file_priv: Pointer to a struct drm_file identifying the caller. 2126 + * @dev: Pointer to the drm device. 2127 + * @args: Pointer to a struct drm_mode_create_dumb structure 2128 + * Return: Zero on success, negative error code on failure. 2129 + * 2130 + * This is a driver callback for the core drm create_dumb functionality. 2131 + * Note that this is very similar to the vmw_bo_alloc ioctl, except 2132 + * that the arguments have a different format. 2133 + */ 2134 + int vmw_dumb_create(struct drm_file *file_priv, 2135 + struct drm_device *dev, 2136 + struct drm_mode_create_dumb *args) 2137 + { 2138 + struct vmw_private *dev_priv = vmw_priv(dev); 2139 + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; 2140 + struct vmw_bo *vbo = NULL; 2141 + struct vmw_resource *res = NULL; 2142 + union drm_vmw_gb_surface_create_ext_arg arg = { 0 }; 2143 + struct drm_vmw_gb_surface_create_ext_req *req = &arg.req; 2144 + int ret; 2145 + struct drm_vmw_size drm_size = { 2146 + .width = args->width, 2147 + .height = args->height, 2148 + .depth = 1, 2149 + }; 2150 + SVGA3dSurfaceFormat format = vmw_format_bpp_to_svga(dev_priv, args->bpp); 2151 + const struct SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format); 2152 + SVGA3dSurfaceAllFlags flags = SVGA3D_SURFACE_HINT_TEXTURE | 2153 + SVGA3D_SURFACE_HINT_RENDERTARGET | 2154 + SVGA3D_SURFACE_SCREENTARGET | 2155 + SVGA3D_SURFACE_BIND_SHADER_RESOURCE | 2156 + SVGA3D_SURFACE_BIND_RENDER_TARGET; 2157 + 2158 + /* 2159 + * Without mob support we're just going to use raw memory buffer 2160 + * because we wouldn't be able to support full surface coherency 2161 + * without mobs 2162 + */ 2163 + if (!dev_priv->has_mob) { 2164 + int cpp = DIV_ROUND_UP(args->bpp, 8); 2165 + 2166 + switch (cpp) { 2167 + case 1: /* DRM_FORMAT_C8 */ 2168 + case 2: /* DRM_FORMAT_RGB565 */ 2169 + case 4: /* DRM_FORMAT_XRGB8888 */ 2170 + break; 2171 + default: 2172 + /* 2173 + * Dumb buffers don't allow anything else. 2174 + * This is tested via IGT's dumb_buffers 2175 + */ 2176 + return -EINVAL; 2177 + } 2178 + 2179 + args->pitch = args->width * cpp; 2180 + args->size = ALIGN(args->pitch * args->height, PAGE_SIZE); 2181 + 2182 + ret = vmw_gem_object_create_with_handle(dev_priv, file_priv, 2183 + args->size, &args->handle, 2184 + &vbo); 2185 + /* drop reference from allocate - handle holds it now */ 2186 + drm_gem_object_put(&vbo->tbo.base); 2187 + return ret; 2188 + } 2189 + 2190 + req->version = drm_vmw_gb_surface_v1; 2191 + req->multisample_pattern = SVGA3D_MS_PATTERN_NONE; 2192 + req->quality_level = SVGA3D_MS_QUALITY_NONE; 2193 + req->buffer_byte_stride = 0; 2194 + req->must_be_zero = 0; 2195 + req->base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(flags); 2196 + req->svga3d_flags_upper_32_bits = SVGA3D_FLAGS_UPPER_32(flags); 2197 + req->base.format = (uint32_t)format; 2198 + req->base.drm_surface_flags = drm_vmw_surface_flag_scanout; 2199 + req->base.drm_surface_flags |= drm_vmw_surface_flag_shareable; 2200 + req->base.drm_surface_flags |= drm_vmw_surface_flag_create_buffer; 2201 + req->base.drm_surface_flags |= drm_vmw_surface_flag_coherent; 2202 + req->base.base_size.width = args->width; 2203 + req->base.base_size.height = args->height; 2204 + req->base.base_size.depth = 1; 2205 + req->base.array_size = 0; 2206 + req->base.mip_levels = 1; 2207 + req->base.multisample_count = 0; 2208 + req->base.buffer_handle = SVGA3D_INVALID_ID; 2209 + req->base.autogen_filter = SVGA3D_TEX_FILTER_NONE; 2210 + ret = vmw_gb_surface_define_ext_ioctl(dev, &arg, file_priv); 2211 + if (ret) { 2212 + drm_warn(dev, "Unable to create a dumb buffer\n"); 2213 + return ret; 2214 + } 2215 + 2216 + args->handle = arg.rep.buffer_handle; 2217 + args->size = arg.rep.buffer_size; 2218 + args->pitch = vmw_surface_calculate_pitch(desc, &drm_size); 2219 + 2220 + ret = vmw_user_resource_lookup_handle(dev_priv, tfile, arg.rep.handle, 2221 + user_surface_converter, 2222 + &res); 2223 + if (ret) { 2224 + drm_err(dev, "Created resource handle doesn't exist!\n"); 2225 + goto err; 2226 + } 2227 + 2228 + vbo = res->guest_memory_bo; 2229 + vbo->is_dumb = true; 2230 + vbo->dumb_surface = vmw_res_to_srf(res); 2231 + 2232 + err: 2233 + if (res) 2234 + vmw_resource_unreference(&res); 2235 + if (ret) 2236 + ttm_ref_object_base_unref(tfile, arg.rep.handle); 2237 + 2226 2238 return ret; 2227 2239 }
+22 -18
drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
··· 75 75 return ret; 76 76 } 77 77 78 - static int 78 + static void 79 79 compute_crc(struct drm_crtc *crtc, 80 80 struct vmw_surface *surf, 81 81 u32 *crc) ··· 101 101 } 102 102 103 103 vmw_bo_unmap(bo); 104 - 105 - return 0; 106 104 } 107 105 108 106 static void ··· 114 116 u64 frame_start, frame_end; 115 117 u32 crc32 = 0; 116 118 struct vmw_surface *surf = 0; 117 - int ret; 118 119 119 120 spin_lock_irq(&du->vkms.crc_state_lock); 120 121 crc_pending = du->vkms.crc_pending; ··· 127 130 return; 128 131 129 132 spin_lock_irq(&du->vkms.crc_state_lock); 130 - surf = du->vkms.surface; 133 + surf = vmw_surface_reference(du->vkms.surface); 131 134 spin_unlock_irq(&du->vkms.crc_state_lock); 132 135 133 - if (vmw_surface_sync(vmw, surf)) { 134 - drm_warn(crtc->dev, "CRC worker wasn't able to sync the crc surface!\n"); 135 - return; 136 - } 136 + if (surf) { 137 + if (vmw_surface_sync(vmw, surf)) { 138 + drm_warn( 139 + crtc->dev, 140 + "CRC worker wasn't able to sync the crc surface!\n"); 141 + return; 142 + } 137 143 138 - ret = compute_crc(crtc, surf, &crc32); 139 - if (ret) 140 - return; 144 + compute_crc(crtc, surf, &crc32); 145 + vmw_surface_unreference(&surf); 146 + } 141 147 142 148 spin_lock_irq(&du->vkms.crc_state_lock); 143 149 frame_start = du->vkms.frame_start; 144 150 frame_end = du->vkms.frame_end; 145 - crc_pending = du->vkms.crc_pending; 146 151 du->vkms.frame_start = 0; 147 152 du->vkms.frame_end = 0; 148 153 du->vkms.crc_pending = false; ··· 163 164 struct vmw_display_unit *du = container_of(timer, struct vmw_display_unit, vkms.timer); 164 165 struct drm_crtc *crtc = &du->crtc; 165 166 struct vmw_private *vmw = vmw_priv(crtc->dev); 166 - struct vmw_surface *surf = NULL; 167 + bool has_surface = false; 167 168 u64 ret_overrun; 168 169 bool locked, ret; 169 170 ··· 178 179 WARN_ON(!ret); 179 180 if (!locked) 180 181 return HRTIMER_RESTART; 181 - surf = du->vkms.surface; 182 + has_surface = du->vkms.surface != NULL; 182 183 vmw_vkms_unlock(crtc); 183 184 184 - if (du->vkms.crc_enabled && surf) { 185 + if (du->vkms.crc_enabled && has_surface) { 185 186 u64 frame = drm_crtc_accurate_vblank_count(crtc); 186 187 187 188 spin_lock(&du->vkms.crc_state_lock); ··· 335 336 { 336 337 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 337 338 339 + if (du->vkms.surface) 340 + vmw_surface_unreference(&du->vkms.surface); 338 341 WARN_ON(work_pending(&du->vkms.crc_generator_work)); 339 342 hrtimer_cancel(&du->vkms.timer); 340 343 } ··· 498 497 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 499 498 struct vmw_private *vmw = vmw_priv(crtc->dev); 500 499 501 - if (vmw->vkms_enabled) { 500 + if (vmw->vkms_enabled && du->vkms.surface != surf) { 502 501 WARN_ON(atomic_read(&du->vkms.atomic_lock) != VMW_VKMS_LOCK_MODESET); 503 - du->vkms.surface = surf; 502 + if (du->vkms.surface) 503 + vmw_surface_unreference(&du->vkms.surface); 504 + if (surf) 505 + du->vkms.surface = vmw_surface_reference(surf); 504 506 } 505 507 } 506 508
+3 -1
tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c
··· 29 29 version.name = name; 30 30 31 31 ret = ioctl(fd, DRM_IOCTL_VERSION, &version); 32 - if (ret) 32 + if (ret || version.name_len != 4) 33 33 return 0; 34 + 35 + name[4] = '\0'; 34 36 35 37 return !strcmp(name, "vgem"); 36 38 }