drm fixes for 6.11-rc2

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
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmasZYEACgkQDHTzWXnE
 hr66WxAAicYCOHArmH+0eqTDKbx9+OJ2DsyNRPRVs81ta94rmBhxt4Gr40wANLGi
 mocemvjNlCZO4cIQ7xbsSVG/9hQpJiodnOVTNSbzW0lGoE9qfI2IbhPOXBf73HRo
 jjdbNXUQ1n5uavXnQb2vGxWSg9/yylo8e5MD6sN0NjRHaZ2BR9/uwzBNl93KEAIq
 4SecyrWWsf1ghMPpK5d6g418UXYB1ORzAaP5GUJMYS6RYYoGOupHSGjqmokXMq5G
 bV0HrgmGgAL8SNVMKAAwbHUa4LrUdepUPqEROAqv0wKw2xQhn4rX/WviPsrwRhWm
 kqUy1XdKQEX9nP9atCyN0cdK+igV9Q61Ea/oxfVxvRQswznZUDD0G/XdZBHyPavH
 It8CKXySOIq4fR0h60TRTCywcuL9WYdym/5/2WWC72kIx8hGo/AqA2VemBPQG2j0
 i79NVqUJXc9jMpU1xEkMg8mFACg7+8SL9jlD1CP5FBJ4/WWidri5rHBZi/3fElL/
 GWTVOVevK5IrCPnDy05PNjCsu2RySHy5rgYc9qx+6SZ85DXoyisYSgHIYqCbWCPO
 ZbV/pZvrc/7ExKGIFnIyj+o8qTBN5qfA3Iwjj9XILrIksEYF+2HsfAXGzkkrEPdO
 09LUDKaElSdIxMSG4Se0mMXIY1RfmgWwmJMGK/sZpCCkgNeGKP4=
 =mHpM
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2024-08-02 08:59:09 -07:00
commit 29b4a6996c
50 changed files with 1203 additions and 651 deletions

View File

@ -268,6 +268,7 @@ config DRM_EXEC
config DRM_GPUVM
tristate
depends on DRM
select DRM_EXEC
help
GPU-VM representation providing helpers to manage a GPUs virtual
address space

View File

@ -1778,7 +1778,7 @@ int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
struct ttm_operation_ctx ctx = { false, false };
struct amdgpu_vm *vm = &fpriv->vm;
struct amdgpu_bo_va_mapping *mapping;
int r;
int i, r;
addr /= AMDGPU_GPU_PAGE_SIZE;
@ -1793,13 +1793,13 @@ int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
if (dma_resv_locking_ctx((*bo)->tbo.base.resv) != &parser->exec.ticket)
return -EINVAL;
if (!((*bo)->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)) {
(*bo)->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
amdgpu_bo_placement_from_domain(*bo, (*bo)->allowed_domains);
r = ttm_bo_validate(&(*bo)->tbo, &(*bo)->placement, &ctx);
if (r)
return r;
}
(*bo)->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
amdgpu_bo_placement_from_domain(*bo, (*bo)->allowed_domains);
for (i = 0; i < (*bo)->placement.num_placement; i++)
(*bo)->placements[i].flags |= TTM_PL_FLAG_CONTIGUOUS;
r = ttm_bo_validate(&(*bo)->tbo, &(*bo)->placement, &ctx);
if (r)
return r;
return amdgpu_ttm_alloc_gart(&(*bo)->tbo);
}

View File

@ -103,7 +103,7 @@ static int amdgpu_mes_event_log_init(struct amdgpu_device *adev)
if (!amdgpu_mes_log_enable)
return 0;
r = amdgpu_bo_create_kernel(adev, AMDGPU_MES_LOG_BUFFER_SIZE, PAGE_SIZE,
r = amdgpu_bo_create_kernel(adev, adev->mes.event_log_size, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_GTT,
&adev->mes.event_log_gpu_obj,
&adev->mes.event_log_gpu_addr,
@ -113,7 +113,7 @@ static int amdgpu_mes_event_log_init(struct amdgpu_device *adev)
return r;
}
memset(adev->mes.event_log_cpu_addr, 0, PAGE_SIZE);
memset(adev->mes.event_log_cpu_addr, 0, adev->mes.event_log_size);
return 0;
@ -1573,7 +1573,7 @@ static int amdgpu_debugfs_mes_event_log_show(struct seq_file *m, void *unused)
uint32_t *mem = (uint32_t *)(adev->mes.event_log_cpu_addr);
seq_hex_dump(m, "", DUMP_PREFIX_OFFSET, 32, 4,
mem, AMDGPU_MES_LOG_BUFFER_SIZE, false);
mem, adev->mes.event_log_size, false);
return 0;
}

View File

@ -52,7 +52,6 @@ enum amdgpu_mes_priority_level {
#define AMDGPU_MES_PROC_CTX_SIZE 0x1000 /* one page area */
#define AMDGPU_MES_GANG_CTX_SIZE 0x1000 /* one page area */
#define AMDGPU_MES_LOG_BUFFER_SIZE 0x4000 /* Maximu log buffer size for MES */
struct amdgpu_mes_funcs;
@ -135,8 +134,9 @@ struct amdgpu_mes {
unsigned long *doorbell_bitmap;
/* MES event log buffer */
struct amdgpu_bo *event_log_gpu_obj;
uint64_t event_log_gpu_addr;
uint32_t event_log_size;
struct amdgpu_bo *event_log_gpu_obj;
uint64_t event_log_gpu_addr;
void *event_log_cpu_addr;
/* ip specific functions */

View File

@ -1163,6 +1163,8 @@ static int mes_v11_0_sw_init(void *handle)
adev->mes.kiq_hw_init = &mes_v11_0_kiq_hw_init;
adev->mes.kiq_hw_fini = &mes_v11_0_kiq_hw_fini;
adev->mes.event_log_size = AMDGPU_MES_LOG_BUFFER_SIZE;
r = amdgpu_mes_init(adev);
if (r)
return r;

View File

@ -551,8 +551,10 @@ static int mes_v12_0_set_hw_resources(struct amdgpu_mes *mes)
mes_set_hw_res_pkt.oversubscription_timer = 50;
mes_set_hw_res_pkt.unmapped_doorbell_handling = 1;
mes_set_hw_res_pkt.enable_mes_event_int_logging = 0;
mes_set_hw_res_pkt.event_intr_history_gpu_mc_ptr = mes->event_log_gpu_addr;
if (amdgpu_mes_log_enable) {
mes_set_hw_res_pkt.enable_mes_event_int_logging = 1;
mes_set_hw_res_pkt.event_intr_history_gpu_mc_ptr = mes->event_log_gpu_addr;
}
return mes_v12_0_submit_pkt_and_poll_completion(mes,
&mes_set_hw_res_pkt, sizeof(mes_set_hw_res_pkt),
@ -1237,6 +1239,8 @@ static int mes_v12_0_sw_init(void *handle)
adev->mes.kiq_hw_init = &mes_v12_0_kiq_hw_init;
adev->mes.kiq_hw_fini = &mes_v12_0_kiq_hw_fini;
adev->mes.event_log_size = AMDGPU_MES_LOG_BUFFER_SIZE;
r = amdgpu_mes_init(adev);
if (r)
return r;

View File

@ -28,6 +28,9 @@
#define MES_API_VERSION 1
/* Maximum log buffer size for MES. Needs to be updated if MES expands MES_EVT_INTR_HIST_LOG */
#define AMDGPU_MES_LOG_BUFFER_SIZE 0x4000
/* Driver submits one API(cmd) as a single Frame and this command size is same
* for all API to ease the debugging and parsing of ring buffer.
*/

View File

@ -28,6 +28,9 @@
#define MES_API_VERSION 0x14
/* Maximum log buffer size for MES. Needs to be updated if MES expands MES_EVT_INTR_HIST_LOG_12 */
#define AMDGPU_MES_LOG_BUFFER_SIZE 0xC000
/* Driver submits one API(cmd) as a single Frame and this command size is same for all API
* to ease the debugging and parsing of ring buffer.
*/

View File

@ -618,7 +618,8 @@ int amdgpu_pm_load_smu_firmware(struct amdgpu_device *adev, uint32_t *smu_versio
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
int r = 0;
if (!pp_funcs || !pp_funcs->load_firmware || adev->flags & AMD_IS_APU)
if (!pp_funcs || !pp_funcs->load_firmware ||
(is_support_sw_smu(adev) && (adev->flags & AMD_IS_APU)))
return 0;
mutex_lock(&adev->pm.mutex);

View File

@ -66,6 +66,7 @@
#define MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE 0x4000
#define DEBUGSMC_MSG_Mode1Reset 2
#define LINK_SPEED_MAX 3
static struct cmn2asic_msg_mapping smu_v14_0_2_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1),
@ -221,7 +222,6 @@ static struct cmn2asic_mapping smu_v14_0_2_workload_map[PP_SMC_POWER_PROFILE_COU
WORKLOAD_MAP(PP_SMC_POWER_PROFILE_WINDOW3D, WORKLOAD_PPLIB_WINDOW_3D_BIT),
};
#if 0
static const uint8_t smu_v14_0_2_throttler_map[] = {
[THROTTLER_PPT0_BIT] = (SMU_THROTTLER_PPT0_BIT),
[THROTTLER_PPT1_BIT] = (SMU_THROTTLER_PPT1_BIT),
@ -241,7 +241,6 @@ static const uint8_t smu_v14_0_2_throttler_map[] = {
[THROTTLER_GFX_APCC_PLUS_BIT] = (SMU_THROTTLER_APCC_BIT),
[THROTTLER_FIT_BIT] = (SMU_THROTTLER_FIT_BIT),
};
#endif
static int
smu_v14_0_2_get_allowed_feature_mask(struct smu_context *smu,
@ -1869,6 +1868,88 @@ static ssize_t smu_v14_0_2_get_ecc_info(struct smu_context *smu,
return ret;
}
static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
void **table)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v1_3 *gpu_metrics =
(struct gpu_metrics_v1_3 *)smu_table->gpu_metrics_table;
SmuMetricsExternal_t metrics_ext;
SmuMetrics_t *metrics = &metrics_ext.SmuMetrics;
int ret = 0;
ret = smu_cmn_get_metrics_table(smu,
&metrics_ext,
true);
if (ret)
return ret;
smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3);
gpu_metrics->temperature_edge = metrics->AvgTemperature[TEMP_EDGE];
gpu_metrics->temperature_hotspot = metrics->AvgTemperature[TEMP_HOTSPOT];
gpu_metrics->temperature_mem = metrics->AvgTemperature[TEMP_MEM];
gpu_metrics->temperature_vrgfx = metrics->AvgTemperature[TEMP_VR_GFX];
gpu_metrics->temperature_vrsoc = metrics->AvgTemperature[TEMP_VR_SOC];
gpu_metrics->temperature_vrmem = max(metrics->AvgTemperature[TEMP_VR_MEM0],
metrics->AvgTemperature[TEMP_VR_MEM1]);
gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity;
gpu_metrics->average_umc_activity = metrics->AverageUclkActivity;
gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage,
metrics->Vcn1ActivityPercentage);
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
if (metrics->AverageGfxActivity <= SMU_14_0_2_BUSY_THRESHOLD)
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
else
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs;
if (metrics->AverageUclkActivity <= SMU_14_0_2_BUSY_THRESHOLD)
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPostDs;
else
gpu_metrics->average_uclk_frequency = metrics->AverageMemclkFrequencyPreDs;
gpu_metrics->average_vclk0_frequency = metrics->AverageVclk0Frequency;
gpu_metrics->average_dclk0_frequency = metrics->AverageDclk0Frequency;
gpu_metrics->average_vclk1_frequency = metrics->AverageVclk1Frequency;
gpu_metrics->average_dclk1_frequency = metrics->AverageDclk1Frequency;
gpu_metrics->current_gfxclk = gpu_metrics->average_gfxclk_frequency;
gpu_metrics->current_socclk = metrics->CurrClock[PPCLK_SOCCLK];
gpu_metrics->current_uclk = metrics->CurrClock[PPCLK_UCLK];
gpu_metrics->current_vclk0 = metrics->CurrClock[PPCLK_VCLK_0];
gpu_metrics->current_dclk0 = metrics->CurrClock[PPCLK_DCLK_0];
gpu_metrics->current_vclk1 = metrics->CurrClock[PPCLK_VCLK_0];
gpu_metrics->current_dclk1 = metrics->CurrClock[PPCLK_DCLK_0];
gpu_metrics->throttle_status =
smu_v14_0_2_get_throttler_status(metrics);
gpu_metrics->indep_throttle_status =
smu_cmn_get_indep_throttler_status(gpu_metrics->throttle_status,
smu_v14_0_2_throttler_map);
gpu_metrics->current_fan_speed = metrics->AvgFanRpm;
gpu_metrics->pcie_link_width = metrics->PcieWidth;
if ((metrics->PcieRate - 1) > LINK_SPEED_MAX)
gpu_metrics->pcie_link_speed = pcie_gen_to_speed(1);
else
gpu_metrics->pcie_link_speed = pcie_gen_to_speed(metrics->PcieRate);
gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
gpu_metrics->voltage_gfx = metrics->AvgVoltage[SVI_PLANE_VDD_GFX];
gpu_metrics->voltage_soc = metrics->AvgVoltage[SVI_PLANE_VDD_SOC];
gpu_metrics->voltage_mem = metrics->AvgVoltage[SVI_PLANE_VDDIO_MEM];
*table = (void *)gpu_metrics;
return sizeof(struct gpu_metrics_v1_3);
}
static const struct pptable_funcs smu_v14_0_2_ppt_funcs = {
.get_allowed_feature_mask = smu_v14_0_2_get_allowed_feature_mask,
.set_default_dpm_table = smu_v14_0_2_set_default_dpm_table,
@ -1905,6 +1986,7 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = {
.enable_thermal_alert = smu_v14_0_enable_thermal_alert,
.disable_thermal_alert = smu_v14_0_disable_thermal_alert,
.notify_memory_pool_location = smu_v14_0_notify_memory_pool_location,
.get_gpu_metrics = smu_v14_0_2_get_gpu_metrics,
.set_soft_freq_limited_range = smu_v14_0_set_soft_freq_limited_range,
.init_pptable_microcode = smu_v14_0_init_pptable_microcode,
.populate_umd_state_clk = smu_v14_0_2_populate_umd_state_clk,

View File

@ -158,7 +158,14 @@ void ast_dp_launch(struct drm_device *dev)
ASTDP_HOST_EDID_READ_DONE);
}
bool ast_dp_power_is_on(struct ast_device *ast)
{
u8 vgacre3;
vgacre3 = ast_get_index_reg(ast, AST_IO_VGACRI, 0xe3);
return !(vgacre3 & AST_DP_PHY_SLEEP);
}
void ast_dp_power_on_off(struct drm_device *dev, bool on)
{

View File

@ -391,6 +391,11 @@ static int ast_drm_freeze(struct drm_device *dev)
static int ast_drm_thaw(struct drm_device *dev)
{
struct ast_device *ast = to_ast_device(dev);
ast_enable_vga(ast->ioregs);
ast_open_key(ast->ioregs);
ast_enable_mmio(dev->dev, ast->ioregs);
ast_post_gpu(dev);
return drm_mode_config_helper_resume(dev);

View File

@ -472,6 +472,7 @@ void ast_init_3rdtx(struct drm_device *dev);
bool ast_astdp_is_connected(struct ast_device *ast);
int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata);
void ast_dp_launch(struct drm_device *dev);
bool ast_dp_power_is_on(struct ast_device *ast);
void ast_dp_power_on_off(struct drm_device *dev, bool no);
void ast_dp_set_on_off(struct drm_device *dev, bool no);
void ast_dp_set_mode(struct drm_crtc *crtc, struct ast_vbios_mode_info *vbios_mode);

View File

@ -28,6 +28,7 @@
* Authors: Dave Airlie <airlied@redhat.com>
*/
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/pci.h>
@ -1687,11 +1688,35 @@ static int ast_astdp_connector_helper_detect_ctx(struct drm_connector *connector
struct drm_modeset_acquire_ctx *ctx,
bool force)
{
struct drm_device *dev = connector->dev;
struct ast_device *ast = to_ast_device(connector->dev);
enum drm_connector_status status = connector_status_disconnected;
struct drm_connector_state *connector_state = connector->state;
bool is_active = false;
mutex_lock(&ast->modeset_lock);
if (connector_state && connector_state->crtc) {
struct drm_crtc_state *crtc_state = connector_state->crtc->state;
if (crtc_state && crtc_state->active)
is_active = true;
}
if (!is_active && !ast_dp_power_is_on(ast)) {
ast_dp_power_on_off(dev, true);
msleep(50);
}
if (ast_astdp_is_connected(ast))
return connector_status_connected;
return connector_status_disconnected;
status = connector_status_connected;
if (!is_active && status == connector_status_disconnected)
ast_dp_power_on_off(dev, false);
mutex_unlock(&ast->modeset_lock);
return status;
}
static const struct drm_connector_helper_funcs ast_astdp_connector_helper_funcs = {

View File

@ -1070,7 +1070,10 @@ int drm_atomic_set_property(struct drm_atomic_state *state,
break;
}
if (async_flip && prop != config->prop_fb_id) {
if (async_flip &&
prop != config->prop_fb_id &&
prop != config->prop_in_fence_fd &&
prop != config->prop_fb_damage_clips) {
ret = drm_atomic_plane_get_property(plane, plane_state,
prop, &old_val);
ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop);

View File

@ -355,7 +355,7 @@ int drm_client_buffer_vmap_local(struct drm_client_buffer *buffer,
err_drm_gem_vmap_unlocked:
drm_gem_unlock(gem);
return 0;
return ret;
}
EXPORT_SYMBOL(drm_client_buffer_vmap_local);

View File

@ -624,6 +624,17 @@ static void drm_fb_helper_add_damage_clip(struct drm_fb_helper *helper, u32 x, u
static void drm_fb_helper_damage(struct drm_fb_helper *helper, u32 x, u32 y,
u32 width, u32 height)
{
/*
* This function may be invoked by panic() to flush the frame
* buffer, where all CPUs except the panic CPU are stopped.
* During the following schedule_work(), the panic CPU needs
* the worker_pool lock, which might be held by a stopped CPU,
* causing schedule_work() and panic() to block. Return early on
* oops_in_progress to prevent this blocking.
*/
if (oops_in_progress)
return;
drm_fb_helper_add_damage_clip(helper, x, y, width, height);
schedule_work(&helper->damage_work);

View File

@ -414,6 +414,12 @@ static const struct dmi_system_id orientation_data[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ONE XPLAYER"),
},
.driver_data = (void *)&lcd1600x2560_leftside_up,
}, { /* OrangePi Neo */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "OrangePi"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "NEO-01"),
},
.driver_data = (void *)&lcd1200x1920_rightside_up,
}, { /* Samsung GalaxyBook 10.6 */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),

View File

@ -1658,7 +1658,7 @@ static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
}
static int
skl_ddi_calculate_wrpll(int clock /* in Hz */,
skl_ddi_calculate_wrpll(int clock,
int ref_clock,
struct skl_wrpll_params *wrpll_params)
{
@ -1683,7 +1683,7 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */,
};
unsigned int dco, d, i;
unsigned int p0, p1, p2;
u64 afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
u64 afe_clock = (u64)clock * 1000 * 5; /* AFE Clock is 5x Pixel clock, in Hz */
for (d = 0; d < ARRAY_SIZE(dividers); d++) {
for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
@ -1808,7 +1808,7 @@ static int skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state)
struct skl_wrpll_params wrpll_params = {};
int ret;
ret = skl_ddi_calculate_wrpll(crtc_state->port_clock * 1000,
ret = skl_ddi_calculate_wrpll(crtc_state->port_clock,
i915->display.dpll.ref_clks.nssc, &wrpll_params);
if (ret)
return ret;

View File

@ -251,7 +251,7 @@
#define HDCP2_STREAM_STATUS(dev_priv, trans, port) \
(TRANS_HDCP(dev_priv) ? \
TRANS_HDCP2_STREAM_STATUS(trans) : \
PIPE_HDCP2_STREAM_STATUS(pipe))
PIPE_HDCP2_STREAM_STATUS(port))
#define _PORTA_HDCP2_AUTH_STREAM 0x66F00
#define _PORTB_HDCP2_AUTH_STREAM 0x66F04

View File

@ -2748,26 +2748,6 @@ oa_configure_all_contexts(struct i915_perf_stream *stream,
return 0;
}
static int
gen12_configure_all_contexts(struct i915_perf_stream *stream,
const struct i915_oa_config *oa_config,
struct i915_active *active)
{
struct flex regs[] = {
{
GEN8_R_PWR_CLK_STATE(RENDER_RING_BASE),
CTX_R_PWR_CLK_STATE,
},
};
if (stream->engine->class != RENDER_CLASS)
return 0;
return oa_configure_all_contexts(stream,
regs, ARRAY_SIZE(regs),
active);
}
static int
lrc_configure_all_contexts(struct i915_perf_stream *stream,
const struct i915_oa_config *oa_config,
@ -2874,7 +2854,6 @@ gen12_enable_metric_set(struct i915_perf_stream *stream,
{
struct drm_i915_private *i915 = stream->perf->i915;
struct intel_uncore *uncore = stream->uncore;
struct i915_oa_config *oa_config = stream->oa_config;
bool periodic = stream->periodic;
u32 period_exponent = stream->period_exponent;
u32 sqcnt1;
@ -2918,15 +2897,6 @@ gen12_enable_metric_set(struct i915_perf_stream *stream,
intel_uncore_rmw(uncore, GEN12_SQCNT1, 0, sqcnt1);
/*
* Update all contexts prior writing the mux configurations as we need
* to make sure all slices/subslices are ON before writing to NOA
* registers.
*/
ret = gen12_configure_all_contexts(stream, oa_config, active);
if (ret)
return ret;
/*
* For Gen12, performance counters are context
* saved/restored. Only enable it for the context that
@ -2980,9 +2950,6 @@ static void gen12_disable_metric_set(struct i915_perf_stream *stream)
_MASKED_BIT_DISABLE(GEN12_DISABLE_DOP_GATING));
}
/* Reset all contexts' slices/subslices configurations. */
gen12_configure_all_contexts(stream, NULL, NULL);
/* disable the context save/restore or OAR counters */
if (stream->ctx)
gen12_configure_oar_context(stream, NULL);

View File

@ -898,7 +898,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict,
* Without this the operation can timeout and we'll fallback to a
* software copy, which might take several minutes to finish.
*/
nouveau_fence_wait(fence, false);
nouveau_fence_wait(fence, false, false);
ret = ttm_bo_move_accel_cleanup(bo, &fence->base, evict, false,
new_reg);
nouveau_fence_unref(&fence);

View File

@ -72,7 +72,7 @@ nouveau_channel_idle(struct nouveau_channel *chan)
ret = nouveau_fence_new(&fence, chan);
if (!ret) {
ret = nouveau_fence_wait(fence, false);
ret = nouveau_fence_wait(fence, false, false);
nouveau_fence_unref(&fence);
}

View File

@ -128,7 +128,7 @@ static void nouveau_dmem_page_free(struct page *page)
static void nouveau_dmem_fence_done(struct nouveau_fence **fence)
{
if (fence) {
nouveau_fence_wait(*fence, false);
nouveau_fence_wait(*fence, true, false);
nouveau_fence_unref(fence);
} else {
/*

View File

@ -311,11 +311,39 @@ nouveau_fence_wait_legacy(struct dma_fence *f, bool intr, long wait)
return timeout - t;
}
static int
nouveau_fence_wait_busy(struct nouveau_fence *fence, bool intr)
{
int ret = 0;
while (!nouveau_fence_done(fence)) {
if (time_after_eq(jiffies, fence->timeout)) {
ret = -EBUSY;
break;
}
__set_current_state(intr ?
TASK_INTERRUPTIBLE :
TASK_UNINTERRUPTIBLE);
if (intr && signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
}
__set_current_state(TASK_RUNNING);
return ret;
}
int
nouveau_fence_wait(struct nouveau_fence *fence, bool intr)
nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr)
{
long ret;
if (!lazy)
return nouveau_fence_wait_busy(fence, intr);
ret = dma_fence_wait_timeout(&fence->base, intr, 15 * HZ);
if (ret < 0)
return ret;

View File

@ -23,7 +23,7 @@ void nouveau_fence_unref(struct nouveau_fence **);
int nouveau_fence_emit(struct nouveau_fence *);
bool nouveau_fence_done(struct nouveau_fence *);
int nouveau_fence_wait(struct nouveau_fence *, bool intr);
int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr);
int nouveau_fence_sync(struct nouveau_bo *, struct nouveau_channel *, bool exclusive, bool intr);
struct nouveau_fence_chan {

View File

@ -928,7 +928,7 @@ revalidate:
}
if (sync) {
if (!(ret = nouveau_fence_wait(fence, false))) {
if (!(ret = nouveau_fence_wait(fence, false, false))) {
if ((ret = dma_fence_get_status(&fence->base)) == 1)
ret = 0;
}

View File

@ -64,7 +64,8 @@ struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev,
* to the caller, instead of a normal nouveau_bo ttm reference. */
ret = drm_gem_object_init(dev, &nvbo->bo.base, size);
if (ret) {
nouveau_bo_ref(NULL, &nvbo);
drm_gem_object_release(&nvbo->bo.base);
kfree(nvbo);
obj = ERR_PTR(-ENOMEM);
goto unlock;
}

View File

@ -1803,6 +1803,7 @@ nouveau_uvmm_bo_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec)
{
struct nouveau_bo *nvbo = nouveau_gem_object(vm_bo->obj);
nouveau_bo_placement_set(nvbo, nvbo->valid_domains, 0);
return nouveau_bo_validate(nvbo, true, false);
}

View File

@ -565,6 +565,10 @@ void v3d_mmu_insert_ptes(struct v3d_bo *bo);
void v3d_mmu_remove_ptes(struct v3d_bo *bo);
/* v3d_sched.c */
void v3d_timestamp_query_info_free(struct v3d_timestamp_query_info *query_info,
unsigned int count);
void v3d_performance_query_info_free(struct v3d_performance_query_info *query_info,
unsigned int count);
void v3d_job_update_stats(struct v3d_job *job, enum v3d_queue queue);
int v3d_sched_init(struct v3d_dev *v3d);
void v3d_sched_fini(struct v3d_dev *v3d);

View File

@ -73,24 +73,44 @@ v3d_sched_job_free(struct drm_sched_job *sched_job)
v3d_job_cleanup(job);
}
void
v3d_timestamp_query_info_free(struct v3d_timestamp_query_info *query_info,
unsigned int count)
{
if (query_info->queries) {
unsigned int i;
for (i = 0; i < count; i++)
drm_syncobj_put(query_info->queries[i].syncobj);
kvfree(query_info->queries);
}
}
void
v3d_performance_query_info_free(struct v3d_performance_query_info *query_info,
unsigned int count)
{
if (query_info->queries) {
unsigned int i;
for (i = 0; i < count; i++)
drm_syncobj_put(query_info->queries[i].syncobj);
kvfree(query_info->queries);
}
}
static void
v3d_cpu_job_free(struct drm_sched_job *sched_job)
{
struct v3d_cpu_job *job = to_cpu_job(sched_job);
struct v3d_timestamp_query_info *timestamp_query = &job->timestamp_query;
struct v3d_performance_query_info *performance_query = &job->performance_query;
if (timestamp_query->queries) {
for (int i = 0; i < timestamp_query->count; i++)
drm_syncobj_put(timestamp_query->queries[i].syncobj);
kvfree(timestamp_query->queries);
}
v3d_timestamp_query_info_free(&job->timestamp_query,
job->timestamp_query.count);
if (performance_query->queries) {
for (int i = 0; i < performance_query->count; i++)
drm_syncobj_put(performance_query->queries[i].syncobj);
kvfree(performance_query->queries);
}
v3d_performance_query_info_free(&job->performance_query,
job->performance_query.count);
v3d_job_cleanup(&job->base);
}

View File

@ -452,6 +452,8 @@ v3d_get_cpu_timestamp_query_params(struct drm_file *file_priv,
{
u32 __user *offsets, *syncs;
struct drm_v3d_timestamp_query timestamp;
unsigned int i;
int err;
if (!job) {
DRM_DEBUG("CPU job extension was attached to a GPU job.\n");
@ -480,26 +482,34 @@ v3d_get_cpu_timestamp_query_params(struct drm_file *file_priv,
offsets = u64_to_user_ptr(timestamp.offsets);
syncs = u64_to_user_ptr(timestamp.syncs);
for (int i = 0; i < timestamp.count; i++) {
for (i = 0; i < timestamp.count; i++) {
u32 offset, sync;
if (copy_from_user(&offset, offsets++, sizeof(offset))) {
kvfree(job->timestamp_query.queries);
return -EFAULT;
err = -EFAULT;
goto error;
}
job->timestamp_query.queries[i].offset = offset;
if (copy_from_user(&sync, syncs++, sizeof(sync))) {
kvfree(job->timestamp_query.queries);
return -EFAULT;
err = -EFAULT;
goto error;
}
job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync);
if (!job->timestamp_query.queries[i].syncobj) {
err = -ENOENT;
goto error;
}
}
job->timestamp_query.count = timestamp.count;
return 0;
error:
v3d_timestamp_query_info_free(&job->timestamp_query, i);
return err;
}
static int
@ -509,6 +519,8 @@ v3d_get_cpu_reset_timestamp_params(struct drm_file *file_priv,
{
u32 __user *syncs;
struct drm_v3d_reset_timestamp_query reset;
unsigned int i;
int err;
if (!job) {
DRM_DEBUG("CPU job extension was attached to a GPU job.\n");
@ -533,21 +545,29 @@ v3d_get_cpu_reset_timestamp_params(struct drm_file *file_priv,
syncs = u64_to_user_ptr(reset.syncs);
for (int i = 0; i < reset.count; i++) {
for (i = 0; i < reset.count; i++) {
u32 sync;
job->timestamp_query.queries[i].offset = reset.offset + 8 * i;
if (copy_from_user(&sync, syncs++, sizeof(sync))) {
kvfree(job->timestamp_query.queries);
return -EFAULT;
err = -EFAULT;
goto error;
}
job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync);
if (!job->timestamp_query.queries[i].syncobj) {
err = -ENOENT;
goto error;
}
}
job->timestamp_query.count = reset.count;
return 0;
error:
v3d_timestamp_query_info_free(&job->timestamp_query, i);
return err;
}
/* Get data for the copy timestamp query results job submission. */
@ -558,7 +578,8 @@ v3d_get_cpu_copy_query_results_params(struct drm_file *file_priv,
{
u32 __user *offsets, *syncs;
struct drm_v3d_copy_timestamp_query copy;
int i;
unsigned int i;
int err;
if (!job) {
DRM_DEBUG("CPU job extension was attached to a GPU job.\n");
@ -591,18 +612,22 @@ v3d_get_cpu_copy_query_results_params(struct drm_file *file_priv,
u32 offset, sync;
if (copy_from_user(&offset, offsets++, sizeof(offset))) {
kvfree(job->timestamp_query.queries);
return -EFAULT;
err = -EFAULT;
goto error;
}
job->timestamp_query.queries[i].offset = offset;
if (copy_from_user(&sync, syncs++, sizeof(sync))) {
kvfree(job->timestamp_query.queries);
return -EFAULT;
err = -EFAULT;
goto error;
}
job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync);
if (!job->timestamp_query.queries[i].syncobj) {
err = -ENOENT;
goto error;
}
}
job->timestamp_query.count = copy.count;
@ -613,6 +638,10 @@ v3d_get_cpu_copy_query_results_params(struct drm_file *file_priv,
job->copy.stride = copy.stride;
return 0;
error:
v3d_timestamp_query_info_free(&job->timestamp_query, i);
return err;
}
static int
@ -623,6 +652,8 @@ v3d_get_cpu_reset_performance_params(struct drm_file *file_priv,
u32 __user *syncs;
u64 __user *kperfmon_ids;
struct drm_v3d_reset_performance_query reset;
unsigned int i, j;
int err;
if (!job) {
DRM_DEBUG("CPU job extension was attached to a GPU job.\n");
@ -637,6 +668,9 @@ v3d_get_cpu_reset_performance_params(struct drm_file *file_priv,
if (copy_from_user(&reset, ext, sizeof(reset)))
return -EFAULT;
if (reset.nperfmons > V3D_MAX_PERFMONS)
return -EINVAL;
job->job_type = V3D_CPU_JOB_TYPE_RESET_PERFORMANCE_QUERY;
job->performance_query.queries = kvmalloc_array(reset.count,
@ -648,39 +682,47 @@ v3d_get_cpu_reset_performance_params(struct drm_file *file_priv,
syncs = u64_to_user_ptr(reset.syncs);
kperfmon_ids = u64_to_user_ptr(reset.kperfmon_ids);
for (int i = 0; i < reset.count; i++) {
for (i = 0; i < reset.count; i++) {
u32 sync;
u64 ids;
u32 __user *ids_pointer;
u32 id;
if (copy_from_user(&sync, syncs++, sizeof(sync))) {
kvfree(job->performance_query.queries);
return -EFAULT;
err = -EFAULT;
goto error;
}
job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync);
if (copy_from_user(&ids, kperfmon_ids++, sizeof(ids))) {
kvfree(job->performance_query.queries);
return -EFAULT;
err = -EFAULT;
goto error;
}
ids_pointer = u64_to_user_ptr(ids);
for (int j = 0; j < reset.nperfmons; j++) {
for (j = 0; j < reset.nperfmons; j++) {
if (copy_from_user(&id, ids_pointer++, sizeof(id))) {
kvfree(job->performance_query.queries);
return -EFAULT;
err = -EFAULT;
goto error;
}
job->performance_query.queries[i].kperfmon_ids[j] = id;
}
job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync);
if (!job->performance_query.queries[i].syncobj) {
err = -ENOENT;
goto error;
}
}
job->performance_query.count = reset.count;
job->performance_query.nperfmons = reset.nperfmons;
return 0;
error:
v3d_performance_query_info_free(&job->performance_query, i);
return err;
}
static int
@ -691,6 +733,8 @@ v3d_get_cpu_copy_performance_query_params(struct drm_file *file_priv,
u32 __user *syncs;
u64 __user *kperfmon_ids;
struct drm_v3d_copy_performance_query copy;
unsigned int i, j;
int err;
if (!job) {
DRM_DEBUG("CPU job extension was attached to a GPU job.\n");
@ -708,6 +752,9 @@ v3d_get_cpu_copy_performance_query_params(struct drm_file *file_priv,
if (copy.pad)
return -EINVAL;
if (copy.nperfmons > V3D_MAX_PERFMONS)
return -EINVAL;
job->job_type = V3D_CPU_JOB_TYPE_COPY_PERFORMANCE_QUERY;
job->performance_query.queries = kvmalloc_array(copy.count,
@ -719,34 +766,38 @@ v3d_get_cpu_copy_performance_query_params(struct drm_file *file_priv,
syncs = u64_to_user_ptr(copy.syncs);
kperfmon_ids = u64_to_user_ptr(copy.kperfmon_ids);
for (int i = 0; i < copy.count; i++) {
for (i = 0; i < copy.count; i++) {
u32 sync;
u64 ids;
u32 __user *ids_pointer;
u32 id;
if (copy_from_user(&sync, syncs++, sizeof(sync))) {
kvfree(job->performance_query.queries);
return -EFAULT;
err = -EFAULT;
goto error;
}
job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync);
if (copy_from_user(&ids, kperfmon_ids++, sizeof(ids))) {
kvfree(job->performance_query.queries);
return -EFAULT;
err = -EFAULT;
goto error;
}
ids_pointer = u64_to_user_ptr(ids);
for (int j = 0; j < copy.nperfmons; j++) {
for (j = 0; j < copy.nperfmons; j++) {
if (copy_from_user(&id, ids_pointer++, sizeof(id))) {
kvfree(job->performance_query.queries);
return -EFAULT;
err = -EFAULT;
goto error;
}
job->performance_query.queries[i].kperfmon_ids[j] = id;
}
job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync);
if (!job->performance_query.queries[i].syncobj) {
err = -ENOENT;
goto error;
}
}
job->performance_query.count = copy.count;
job->performance_query.nperfmons = copy.nperfmons;
@ -759,6 +810,10 @@ v3d_get_cpu_copy_performance_query_params(struct drm_file *file_priv,
job->copy.stride = copy.stride;
return 0;
error:
v3d_performance_query_info_free(&job->performance_query, i);
return err;
}
/* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data

View File

@ -48,7 +48,7 @@ struct virtio_gpu_submit {
static int virtio_gpu_do_fence_wait(struct virtio_gpu_submit *submit,
struct dma_fence *in_fence)
{
u32 context = submit->fence_ctx + submit->ring_idx;
u64 context = submit->fence_ctx + submit->ring_idx;
if (dma_fence_match_context(in_fence, context))
return 0;

View File

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**********************************************************
* Copyright 2021 VMware, Inc.
* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Copyright (c) 2021-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@ -31,6 +33,10 @@
#include <drm/vmwgfx_drm.h>
#define SVGA3D_FLAGS_UPPER_32(svga3d_flags) ((svga3d_flags) >> 32)
#define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \
((svga3d_flags) & ((uint64_t)U32_MAX))
static inline u32 clamped_umul32(u32 a, u32 b)
{
uint64_t tmp = (uint64_t) a*b;

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
* Copyright © 2011-2023 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved.
* Copyright (c) 2011-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@ -28,15 +28,39 @@
#include "vmwgfx_bo.h"
#include "vmwgfx_drv.h"
#include "vmwgfx_resource_priv.h"
#include <drm/ttm/ttm_placement.h>
static void vmw_bo_release(struct vmw_bo *vbo)
{
struct vmw_resource *res;
WARN_ON(vbo->tbo.base.funcs &&
kref_read(&vbo->tbo.base.refcount) != 0);
vmw_bo_unmap(vbo);
xa_destroy(&vbo->detached_resources);
WARN_ON(vbo->is_dumb && !vbo->dumb_surface);
if (vbo->is_dumb && vbo->dumb_surface) {
res = &vbo->dumb_surface->res;
WARN_ON(vbo != res->guest_memory_bo);
WARN_ON(!res->guest_memory_bo);
if (res->guest_memory_bo) {
/* Reserve and switch the backing mob. */
mutex_lock(&res->dev_priv->cmdbuf_mutex);
(void)vmw_resource_reserve(res, false, true);
vmw_resource_mob_detach(res);
if (res->coherent)
vmw_bo_dirty_release(res->guest_memory_bo);
res->guest_memory_bo = NULL;
res->guest_memory_offset = 0;
vmw_resource_unreserve(res, false, false, false, NULL,
0);
mutex_unlock(&res->dev_priv->cmdbuf_mutex);
}
vmw_surface_unreference(&vbo->dumb_surface);
}
drm_gem_object_release(&vbo->tbo.base);
}
@ -325,6 +349,11 @@ void vmw_bo_pin_reserved(struct vmw_bo *vbo, bool pin)
*
*/
void *vmw_bo_map_and_cache(struct vmw_bo *vbo)
{
return vmw_bo_map_and_cache_size(vbo, vbo->tbo.base.size);
}
void *vmw_bo_map_and_cache_size(struct vmw_bo *vbo, size_t size)
{
struct ttm_buffer_object *bo = &vbo->tbo;
bool not_used;
@ -335,9 +364,10 @@ void *vmw_bo_map_and_cache(struct vmw_bo *vbo)
if (virtual)
return virtual;
ret = ttm_bo_kmap(bo, 0, PFN_UP(bo->base.size), &vbo->map);
ret = ttm_bo_kmap(bo, 0, PFN_UP(size), &vbo->map);
if (ret)
DRM_ERROR("Buffer object map failed: %d.\n", ret);
DRM_ERROR("Buffer object map failed: %d (size: bo = %zu, map = %zu).\n",
ret, bo->base.size, size);
return ttm_kmap_obj_virtual(&vbo->map, &not_used);
}
@ -390,6 +420,7 @@ static int vmw_bo_init(struct vmw_private *dev_priv,
BUILD_BUG_ON(TTM_MAX_BO_PRIORITY <= 3);
vmw_bo->tbo.priority = 3;
vmw_bo->res_tree = RB_ROOT;
xa_init(&vmw_bo->detached_resources);
params->size = ALIGN(params->size, PAGE_SIZE);
drm_gem_private_object_init(vdev, &vmw_bo->tbo.base, params->size);
@ -654,52 +685,6 @@ void vmw_bo_fence_single(struct ttm_buffer_object *bo,
dma_fence_put(&fence->base);
}
/**
* vmw_dumb_create - Create a dumb kms buffer
*
* @file_priv: Pointer to a struct drm_file identifying the caller.
* @dev: Pointer to the drm device.
* @args: Pointer to a struct drm_mode_create_dumb structure
* Return: Zero on success, negative error code on failure.
*
* This is a driver callback for the core drm create_dumb functionality.
* Note that this is very similar to the vmw_bo_alloc ioctl, except
* that the arguments have a different format.
*/
int vmw_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
struct vmw_private *dev_priv = vmw_priv(dev);
struct vmw_bo *vbo;
int cpp = DIV_ROUND_UP(args->bpp, 8);
int ret;
switch (cpp) {
case 1: /* DRM_FORMAT_C8 */
case 2: /* DRM_FORMAT_RGB565 */
case 4: /* DRM_FORMAT_XRGB8888 */
break;
default:
/*
* Dumb buffers don't allow anything else.
* This is tested via IGT's dumb_buffers
*/
return -EINVAL;
}
args->pitch = args->width * cpp;
args->size = ALIGN(args->pitch * args->height, PAGE_SIZE);
ret = vmw_gem_object_create_with_handle(dev_priv, file_priv,
args->size, &args->handle,
&vbo);
/* drop reference from allocate - handle holds it now */
drm_gem_object_put(&vbo->tbo.base);
return ret;
}
/**
* vmw_bo_swap_notify - swapout notify callback.
*
@ -853,3 +838,43 @@ void vmw_bo_placement_set_default_accelerated(struct vmw_bo *bo)
vmw_bo_placement_set(bo, domain, domain);
}
void vmw_bo_add_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res)
{
xa_store(&vbo->detached_resources, (unsigned long)res, res, GFP_KERNEL);
}
void vmw_bo_del_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res)
{
xa_erase(&vbo->detached_resources, (unsigned long)res);
}
struct vmw_surface *vmw_bo_surface(struct vmw_bo *vbo)
{
unsigned long index;
struct vmw_resource *res = NULL;
struct vmw_surface *surf = NULL;
struct rb_node *rb_itr = vbo->res_tree.rb_node;
if (vbo->is_dumb && vbo->dumb_surface) {
res = &vbo->dumb_surface->res;
goto out;
}
xa_for_each(&vbo->detached_resources, index, res) {
if (res->func->res_type == vmw_res_surface)
goto out;
}
for (rb_itr = rb_first(&vbo->res_tree); rb_itr;
rb_itr = rb_next(rb_itr)) {
res = rb_entry(rb_itr, struct vmw_resource, mob_node);
if (res->func->res_type == vmw_res_surface)
goto out;
}
out:
if (res)
surf = vmw_res_to_srf(res);
return surf;
}

View File

@ -1,7 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
*
* Copyright 2023 VMware, Inc., Palo Alto, CA., USA
* Copyright (c) 2023-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@ -35,11 +36,13 @@
#include <linux/rbtree_types.h>
#include <linux/types.h>
#include <linux/xarray.h>
struct vmw_bo_dirty;
struct vmw_fence_obj;
struct vmw_private;
struct vmw_resource;
struct vmw_surface;
enum vmw_bo_domain {
VMW_BO_DOMAIN_SYS = BIT(0),
@ -85,11 +88,15 @@ struct vmw_bo {
struct rb_root res_tree;
u32 res_prios[TTM_MAX_BO_PRIORITY];
struct xarray detached_resources;
atomic_t cpu_writers;
/* Not ref-counted. Protected by binding_mutex */
struct vmw_resource *dx_query_ctx;
struct vmw_bo_dirty *dirty;
bool is_dumb;
struct vmw_surface *dumb_surface;
};
void vmw_bo_placement_set(struct vmw_bo *bo, u32 domain, u32 busy_domain);
@ -124,15 +131,21 @@ void vmw_bo_fence_single(struct ttm_buffer_object *bo,
struct vmw_fence_obj *fence);
void *vmw_bo_map_and_cache(struct vmw_bo *vbo);
void *vmw_bo_map_and_cache_size(struct vmw_bo *vbo, size_t size);
void vmw_bo_unmap(struct vmw_bo *vbo);
void vmw_bo_move_notify(struct ttm_buffer_object *bo,
struct ttm_resource *mem);
void vmw_bo_swap_notify(struct ttm_buffer_object *bo);
void vmw_bo_add_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res);
void vmw_bo_del_detached_resource(struct vmw_bo *vbo, struct vmw_resource *res);
struct vmw_surface *vmw_bo_surface(struct vmw_bo *vbo);
int vmw_user_bo_lookup(struct drm_file *filp,
u32 handle,
struct vmw_bo **out);
/**
* vmw_bo_adjust_prio - Adjust the buffer object eviction priority
* according to attached resources

View File

@ -1,7 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
*
* Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA
* Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@ -762,6 +763,26 @@ extern int vmw_gmr_bind(struct vmw_private *dev_priv,
int gmr_id);
extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id);
/**
* User handles
*/
struct vmw_user_object {
struct vmw_surface *surface;
struct vmw_bo *buffer;
};
int vmw_user_object_lookup(struct vmw_private *dev_priv, struct drm_file *filp,
u32 handle, struct vmw_user_object *uo);
struct vmw_user_object *vmw_user_object_ref(struct vmw_user_object *uo);
void vmw_user_object_unref(struct vmw_user_object *uo);
bool vmw_user_object_is_null(struct vmw_user_object *uo);
struct vmw_surface *vmw_user_object_surface(struct vmw_user_object *uo);
struct vmw_bo *vmw_user_object_buffer(struct vmw_user_object *uo);
void *vmw_user_object_map(struct vmw_user_object *uo);
void *vmw_user_object_map_size(struct vmw_user_object *uo, size_t size);
void vmw_user_object_unmap(struct vmw_user_object *uo);
bool vmw_user_object_is_mapped(struct vmw_user_object *uo);
/**
* Resource utilities - vmwgfx_resource.c
*/
@ -776,11 +797,6 @@ extern int vmw_resource_validate(struct vmw_resource *res, bool intr,
extern int vmw_resource_reserve(struct vmw_resource *res, bool interruptible,
bool no_backup);
extern bool vmw_resource_needs_backup(const struct vmw_resource *res);
extern int vmw_user_lookup_handle(struct vmw_private *dev_priv,
struct drm_file *filp,
uint32_t handle,
struct vmw_surface **out_surf,
struct vmw_bo **out_buf);
extern int vmw_user_resource_lookup_handle(
struct vmw_private *dev_priv,
struct ttm_object_file *tfile,
@ -1057,9 +1073,6 @@ int vmw_kms_suspend(struct drm_device *dev);
int vmw_kms_resume(struct drm_device *dev);
void vmw_kms_lost_device(struct drm_device *dev);
int vmw_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args);
extern int vmw_resource_pin(struct vmw_resource *res, bool interruptible);
extern void vmw_resource_unpin(struct vmw_resource *res);
extern enum vmw_res_type vmw_res_type(const struct vmw_resource *res);
@ -1176,6 +1189,15 @@ extern int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev,
int vmw_gb_surface_define(struct vmw_private *dev_priv,
const struct vmw_surface_metadata *req,
struct vmw_surface **srf_out);
struct vmw_surface *vmw_lookup_surface_for_buffer(struct vmw_private *vmw,
struct vmw_bo *bo,
u32 handle);
u32 vmw_lookup_surface_handle_for_buffer(struct vmw_private *vmw,
struct vmw_bo *bo,
u32 handle);
int vmw_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args);
/*
* Shader management - vmwgfx_shader.c

View File

@ -32,7 +32,6 @@
#define VMW_FENCE_WRAP (1 << 31)
struct vmw_fence_manager {
int num_fence_objects;
struct vmw_private *dev_priv;
spinlock_t lock;
struct list_head fence_list;
@ -124,13 +123,13 @@ static void vmw_fence_obj_destroy(struct dma_fence *f)
{
struct vmw_fence_obj *fence =
container_of(f, struct vmw_fence_obj, base);
struct vmw_fence_manager *fman = fman_from_fence(fence);
spin_lock(&fman->lock);
list_del_init(&fence->head);
--fman->num_fence_objects;
spin_unlock(&fman->lock);
if (!list_empty(&fence->head)) {
spin_lock(&fman->lock);
list_del_init(&fence->head);
spin_unlock(&fman->lock);
}
fence->destroy(fence);
}
@ -257,7 +256,6 @@ static const struct dma_fence_ops vmw_fence_ops = {
.release = vmw_fence_obj_destroy,
};
/*
* Execute signal actions on fences recently signaled.
* This is done from a workqueue so we don't have to execute
@ -355,7 +353,6 @@ static int vmw_fence_obj_init(struct vmw_fence_manager *fman,
goto out_unlock;
}
list_add_tail(&fence->head, &fman->fence_list);
++fman->num_fence_objects;
out_unlock:
spin_unlock(&fman->lock);
@ -403,7 +400,7 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
u32 passed_seqno)
{
u32 goal_seqno;
struct vmw_fence_obj *fence;
struct vmw_fence_obj *fence, *next_fence;
if (likely(!fman->seqno_valid))
return false;
@ -413,7 +410,7 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman,
return false;
fman->seqno_valid = false;
list_for_each_entry(fence, &fman->fence_list, head) {
list_for_each_entry_safe(fence, next_fence, &fman->fence_list, head) {
if (!list_empty(&fence->seq_passed_actions)) {
fman->seqno_valid = true;
vmw_fence_goal_write(fman->dev_priv,

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright 2021-2023 VMware, Inc.
* Copyright (c) 2021-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@ -78,6 +79,59 @@ static struct sg_table *vmw_gem_object_get_sg_table(struct drm_gem_object *obj)
return drm_prime_pages_to_sg(obj->dev, vmw_tt->dma_ttm.pages, vmw_tt->dma_ttm.num_pages);
}
static int vmw_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)
{
struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(obj);
int ret;
if (obj->import_attach) {
ret = dma_buf_vmap(obj->import_attach->dmabuf, map);
if (!ret) {
if (drm_WARN_ON(obj->dev, map->is_iomem)) {
dma_buf_vunmap(obj->import_attach->dmabuf, map);
return -EIO;
}
}
} else {
ret = ttm_bo_vmap(bo, map);
}
return ret;
}
static void vmw_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
{
if (obj->import_attach)
dma_buf_vunmap(obj->import_attach->dmabuf, map);
else
drm_gem_ttm_vunmap(obj, map);
}
static int vmw_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
{
int ret;
if (obj->import_attach) {
/*
* Reset both vm_ops and vm_private_data, so we don't end up with
* vm_ops pointing to our implementation if the dma-buf backend
* doesn't set those fields.
*/
vma->vm_private_data = NULL;
vma->vm_ops = NULL;
ret = dma_buf_mmap(obj->dma_buf, vma, 0);
/* Drop the reference drm_gem_mmap_obj() acquired.*/
if (!ret)
drm_gem_object_put(obj);
return ret;
}
return drm_gem_ttm_mmap(obj, vma);
}
static const struct vm_operations_struct vmw_vm_ops = {
.pfn_mkwrite = vmw_bo_vm_mkwrite,
.page_mkwrite = vmw_bo_vm_mkwrite,
@ -94,9 +148,9 @@ static const struct drm_gem_object_funcs vmw_gem_object_funcs = {
.pin = vmw_gem_object_pin,
.unpin = vmw_gem_object_unpin,
.get_sg_table = vmw_gem_object_get_sg_table,
.vmap = drm_gem_ttm_vmap,
.vunmap = drm_gem_ttm_vunmap,
.mmap = drm_gem_ttm_mmap,
.vmap = vmw_gem_vmap,
.vunmap = vmw_gem_vunmap,
.mmap = vmw_gem_mmap,
.vm_ops = &vmw_vm_ops,
};

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
* Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA
* Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@ -193,13 +194,16 @@ static u32 vmw_du_cursor_mob_size(u32 w, u32 h)
*/
static u32 *vmw_du_cursor_plane_acquire_image(struct vmw_plane_state *vps)
{
if (vps->surf) {
if (vps->surf_mapped)
return vmw_bo_map_and_cache(vps->surf->res.guest_memory_bo);
return vps->surf->snooper.image;
} else if (vps->bo)
return vmw_bo_map_and_cache(vps->bo);
return NULL;
struct vmw_surface *surf;
if (vmw_user_object_is_null(&vps->uo))
return NULL;
surf = vmw_user_object_surface(&vps->uo);
if (surf && !vmw_user_object_is_mapped(&vps->uo))
return surf->snooper.image;
return vmw_user_object_map(&vps->uo);
}
static bool vmw_du_cursor_plane_has_changed(struct vmw_plane_state *old_vps,
@ -536,21 +540,15 @@ void vmw_du_primary_plane_destroy(struct drm_plane *plane)
* vmw_du_plane_unpin_surf - unpins resource associated with a framebuffer surface
*
* @vps: plane state associated with the display surface
* @unreference: true if we also want to unreference the display.
*/
void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps,
bool unreference)
void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps)
{
if (vps->surf) {
if (vps->pinned) {
vmw_resource_unpin(&vps->surf->res);
vps->pinned--;
}
struct vmw_surface *surf = vmw_user_object_surface(&vps->uo);
if (unreference) {
if (vps->pinned)
DRM_ERROR("Surface still pinned\n");
vmw_surface_unreference(&vps->surf);
if (surf) {
if (vps->pinned) {
vmw_resource_unpin(&surf->res);
vps->pinned--;
}
}
}
@ -572,7 +570,7 @@ vmw_du_plane_cleanup_fb(struct drm_plane *plane,
{
struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
vmw_du_plane_unpin_surf(vps, false);
vmw_du_plane_unpin_surf(vps);
}
@ -661,25 +659,14 @@ vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane,
struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
if (vps->surf_mapped) {
vmw_bo_unmap(vps->surf->res.guest_memory_bo);
vps->surf_mapped = false;
}
if (!vmw_user_object_is_null(&vps->uo))
vmw_user_object_unmap(&vps->uo);
vmw_du_cursor_plane_unmap_cm(vps);
vmw_du_put_cursor_mob(vcp, vps);
vmw_du_plane_unpin_surf(vps, false);
if (vps->surf) {
vmw_surface_unreference(&vps->surf);
vps->surf = NULL;
}
if (vps->bo) {
vmw_bo_unreference(&vps->bo);
vps->bo = NULL;
}
vmw_du_plane_unpin_surf(vps);
vmw_user_object_unref(&vps->uo);
}
@ -698,64 +685,48 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
struct drm_framebuffer *fb = new_state->fb;
struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
struct vmw_bo *bo = NULL;
int ret = 0;
if (vps->surf) {
if (vps->surf_mapped) {
vmw_bo_unmap(vps->surf->res.guest_memory_bo);
vps->surf_mapped = false;
}
vmw_surface_unreference(&vps->surf);
vps->surf = NULL;
}
if (vps->bo) {
vmw_bo_unreference(&vps->bo);
vps->bo = NULL;
if (!vmw_user_object_is_null(&vps->uo)) {
vmw_user_object_unmap(&vps->uo);
vmw_user_object_unref(&vps->uo);
}
if (fb) {
if (vmw_framebuffer_to_vfb(fb)->bo) {
vps->bo = vmw_framebuffer_to_vfbd(fb)->buffer;
vmw_bo_reference(vps->bo);
vps->uo.buffer = vmw_framebuffer_to_vfbd(fb)->buffer;
vps->uo.surface = NULL;
} else {
vps->surf = vmw_framebuffer_to_vfbs(fb)->surface;
vmw_surface_reference(vps->surf);
memcpy(&vps->uo, &vmw_framebuffer_to_vfbs(fb)->uo, sizeof(vps->uo));
}
vmw_user_object_ref(&vps->uo);
}
if (!vps->surf && vps->bo) {
const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32);
bo = vmw_user_object_buffer(&vps->uo);
if (bo) {
struct ttm_operation_ctx ctx = {false, false};
/*
* Not using vmw_bo_map_and_cache() helper here as we need to
* reserve the ttm_buffer_object first which
* vmw_bo_map_and_cache() omits.
*/
ret = ttm_bo_reserve(&vps->bo->tbo, true, false, NULL);
if (unlikely(ret != 0))
ret = ttm_bo_reserve(&bo->tbo, true, false, NULL);
if (ret != 0)
return -ENOMEM;
ret = ttm_bo_kmap(&vps->bo->tbo, 0, PFN_UP(size), &vps->bo->map);
ttm_bo_unreserve(&vps->bo->tbo);
if (unlikely(ret != 0))
ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
if (ret != 0)
return -ENOMEM;
} else if (vps->surf && !vps->bo && vps->surf->res.guest_memory_bo) {
WARN_ON(vps->surf->snooper.image);
ret = ttm_bo_reserve(&vps->surf->res.guest_memory_bo->tbo, true, false,
NULL);
if (unlikely(ret != 0))
return -ENOMEM;
vmw_bo_map_and_cache(vps->surf->res.guest_memory_bo);
ttm_bo_unreserve(&vps->surf->res.guest_memory_bo->tbo);
vps->surf_mapped = true;
vmw_bo_pin_reserved(bo, true);
if (vmw_framebuffer_to_vfb(fb)->bo) {
const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32);
(void)vmw_bo_map_and_cache_size(bo, size);
} else {
vmw_bo_map_and_cache(bo);
}
ttm_bo_unreserve(&bo->tbo);
}
if (vps->surf || vps->bo) {
if (!vmw_user_object_is_null(&vps->uo)) {
vmw_du_get_cursor_mob(vcp, vps);
vmw_du_cursor_plane_map_cm(vps);
}
@ -777,14 +748,17 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
struct vmw_plane_state *old_vps = vmw_plane_state_to_vps(old_state);
struct vmw_bo *old_bo = NULL;
struct vmw_bo *new_bo = NULL;
s32 hotspot_x, hotspot_y;
int ret;
hotspot_x = du->hotspot_x + new_state->hotspot_x;
hotspot_y = du->hotspot_y + new_state->hotspot_y;
du->cursor_surface = vps->surf;
du->cursor_surface = vmw_user_object_surface(&vps->uo);
if (!vps->surf && !vps->bo) {
if (vmw_user_object_is_null(&vps->uo)) {
vmw_cursor_update_position(dev_priv, false, 0, 0);
return;
}
@ -792,10 +766,26 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
vps->cursor.hotspot_x = hotspot_x;
vps->cursor.hotspot_y = hotspot_y;
if (vps->surf) {
if (du->cursor_surface)
du->cursor_age = du->cursor_surface->snooper.age;
if (!vmw_user_object_is_null(&old_vps->uo)) {
old_bo = vmw_user_object_buffer(&old_vps->uo);
ret = ttm_bo_reserve(&old_bo->tbo, false, false, NULL);
if (ret != 0)
return;
}
if (!vmw_user_object_is_null(&vps->uo)) {
new_bo = vmw_user_object_buffer(&vps->uo);
if (old_bo != new_bo) {
ret = ttm_bo_reserve(&new_bo->tbo, false, false, NULL);
if (ret != 0)
return;
} else {
new_bo = NULL;
}
}
if (!vmw_du_cursor_plane_has_changed(old_vps, vps)) {
/*
* If it hasn't changed, avoid making the device do extra
@ -813,6 +803,11 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
hotspot_x, hotspot_y);
}
if (old_bo)
ttm_bo_unreserve(&old_bo->tbo);
if (new_bo)
ttm_bo_unreserve(&new_bo->tbo);
du->cursor_x = new_state->crtc_x + du->set_gui_x;
du->cursor_y = new_state->crtc_y + du->set_gui_y;
@ -913,7 +908,7 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
}
if (!vmw_framebuffer_to_vfb(fb)->bo) {
surface = vmw_framebuffer_to_vfbs(fb)->surface;
surface = vmw_user_object_surface(&vmw_framebuffer_to_vfbs(fb)->uo);
WARN_ON(!surface);
@ -1074,12 +1069,7 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane)
memset(&vps->cursor, 0, sizeof(vps->cursor));
/* Each ref counted resource needs to be acquired again */
if (vps->surf)
(void) vmw_surface_reference(vps->surf);
if (vps->bo)
(void) vmw_bo_reference(vps->bo);
vmw_user_object_ref(&vps->uo);
state = &vps->base;
__drm_atomic_helper_plane_duplicate_state(plane, state);
@ -1128,11 +1118,7 @@ vmw_du_plane_destroy_state(struct drm_plane *plane,
struct vmw_plane_state *vps = vmw_plane_state_to_vps(state);
/* Should have been freed by cleanup_fb */
if (vps->surf)
vmw_surface_unreference(&vps->surf);
if (vps->bo)
vmw_bo_unreference(&vps->bo);
vmw_user_object_unref(&vps->uo);
drm_atomic_helper_plane_destroy_state(plane, state);
}
@ -1227,7 +1213,7 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
vmw_framebuffer_to_vfbs(framebuffer);
drm_framebuffer_cleanup(framebuffer);
vmw_surface_unreference(&vfbs->surface);
vmw_user_object_unref(&vfbs->uo);
kfree(vfbs);
}
@ -1272,29 +1258,41 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
return -ENOSYS;
}
static int vmw_framebuffer_surface_create_handle(struct drm_framebuffer *fb,
struct drm_file *file_priv,
unsigned int *handle)
{
struct vmw_framebuffer_surface *vfbs = vmw_framebuffer_to_vfbs(fb);
struct vmw_bo *bo = vmw_user_object_buffer(&vfbs->uo);
return drm_gem_handle_create(file_priv, &bo->tbo.base, handle);
}
static const struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
.create_handle = vmw_framebuffer_surface_create_handle,
.destroy = vmw_framebuffer_surface_destroy,
.dirty = drm_atomic_helper_dirtyfb,
};
static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
struct vmw_surface *surface,
struct vmw_user_object *uo,
struct vmw_framebuffer **out,
const struct drm_mode_fb_cmd2
*mode_cmd,
bool is_bo_proxy)
*mode_cmd)
{
struct drm_device *dev = &dev_priv->drm;
struct vmw_framebuffer_surface *vfbs;
enum SVGA3dSurfaceFormat format;
struct vmw_surface *surface;
int ret;
/* 3D is only supported on HWv8 and newer hosts */
if (dev_priv->active_display_unit == vmw_du_legacy)
return -ENOSYS;
surface = vmw_user_object_surface(uo);
/*
* Sanity checks.
*/
@ -1357,8 +1355,8 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
}
drm_helper_mode_fill_fb_struct(dev, &vfbs->base.base, mode_cmd);
vfbs->surface = vmw_surface_reference(surface);
vfbs->is_bo_proxy = is_bo_proxy;
memcpy(&vfbs->uo, uo, sizeof(vfbs->uo));
vmw_user_object_ref(&vfbs->uo);
*out = &vfbs->base;
@ -1370,7 +1368,7 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
return 0;
out_err2:
vmw_surface_unreference(&surface);
vmw_user_object_unref(&vfbs->uo);
kfree(vfbs);
out_err1:
return ret;
@ -1386,7 +1384,6 @@ static int vmw_framebuffer_bo_create_handle(struct drm_framebuffer *fb,
{
struct vmw_framebuffer_bo *vfbd =
vmw_framebuffer_to_vfbd(fb);
return drm_gem_handle_create(file_priv, &vfbd->buffer->tbo.base, handle);
}
@ -1407,86 +1404,6 @@ static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = {
.dirty = drm_atomic_helper_dirtyfb,
};
/**
* vmw_create_bo_proxy - create a proxy surface for the buffer object
*
* @dev: DRM device
* @mode_cmd: parameters for the new surface
* @bo_mob: MOB backing the buffer object
* @srf_out: newly created surface
*
* When the content FB is a buffer object, we create a surface as a proxy to the
* same buffer. This way we can do a surface copy rather than a surface DMA.
* This is a more efficient approach
*
* RETURNS:
* 0 on success, error code otherwise
*/
static int vmw_create_bo_proxy(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *mode_cmd,
struct vmw_bo *bo_mob,
struct vmw_surface **srf_out)
{
struct vmw_surface_metadata metadata = {0};
uint32_t format;
struct vmw_resource *res;
unsigned int bytes_pp;
int ret;
switch (mode_cmd->pixel_format) {
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_XRGB8888:
format = SVGA3D_X8R8G8B8;
bytes_pp = 4;
break;
case DRM_FORMAT_RGB565:
case DRM_FORMAT_XRGB1555:
format = SVGA3D_R5G6B5;
bytes_pp = 2;
break;
case 8:
format = SVGA3D_P8;
bytes_pp = 1;
break;
default:
DRM_ERROR("Invalid framebuffer format %p4cc\n",
&mode_cmd->pixel_format);
return -EINVAL;
}
metadata.format = format;
metadata.mip_levels[0] = 1;
metadata.num_sizes = 1;
metadata.base_size.width = mode_cmd->pitches[0] / bytes_pp;
metadata.base_size.height = mode_cmd->height;
metadata.base_size.depth = 1;
metadata.scanout = true;
ret = vmw_gb_surface_define(vmw_priv(dev), &metadata, srf_out);
if (ret) {
DRM_ERROR("Failed to allocate proxy content buffer\n");
return ret;
}
res = &(*srf_out)->res;
/* Reserve and switch the backing mob. */
mutex_lock(&res->dev_priv->cmdbuf_mutex);
(void) vmw_resource_reserve(res, false, true);
vmw_user_bo_unref(&res->guest_memory_bo);
res->guest_memory_bo = vmw_user_bo_ref(bo_mob);
res->guest_memory_offset = 0;
vmw_resource_unreserve(res, false, false, false, NULL, 0);
mutex_unlock(&res->dev_priv->cmdbuf_mutex);
return 0;
}
static int vmw_kms_new_framebuffer_bo(struct vmw_private *dev_priv,
struct vmw_bo *bo,
struct vmw_framebuffer **out,
@ -1565,55 +1482,24 @@ vmw_kms_srf_ok(struct vmw_private *dev_priv, uint32_t width, uint32_t height)
* vmw_kms_new_framebuffer - Create a new framebuffer.
*
* @dev_priv: Pointer to device private struct.
* @bo: Pointer to buffer object to wrap the kms framebuffer around.
* Either @bo or @surface must be NULL.
* @surface: Pointer to a surface to wrap the kms framebuffer around.
* Either @bo or @surface must be NULL.
* @only_2d: No presents will occur to this buffer object based framebuffer.
* This helps the code to do some important optimizations.
* @uo: Pointer to user object to wrap the kms framebuffer around.
* Either the buffer or surface inside the user object must be NULL.
* @mode_cmd: Frame-buffer metadata.
*/
struct vmw_framebuffer *
vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
struct vmw_bo *bo,
struct vmw_surface *surface,
bool only_2d,
struct vmw_user_object *uo,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct vmw_framebuffer *vfb = NULL;
bool is_bo_proxy = false;
int ret;
/*
* We cannot use the SurfaceDMA command in an non-accelerated VM,
* therefore, wrap the buffer object in a surface so we can use the
* SurfaceCopy command.
*/
if (vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height) &&
bo && only_2d &&
mode_cmd->width > 64 && /* Don't create a proxy for cursor */
dev_priv->active_display_unit == vmw_du_screen_target) {
ret = vmw_create_bo_proxy(&dev_priv->drm, mode_cmd,
bo, &surface);
if (ret)
return ERR_PTR(ret);
is_bo_proxy = true;
}
/* Create the new framebuffer depending one what we have */
if (surface) {
ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
mode_cmd,
is_bo_proxy);
/*
* vmw_create_bo_proxy() adds a reference that is no longer
* needed
*/
if (is_bo_proxy)
vmw_surface_unreference(&surface);
} else if (bo) {
ret = vmw_kms_new_framebuffer_bo(dev_priv, bo, &vfb,
if (vmw_user_object_surface(uo)) {
ret = vmw_kms_new_framebuffer_surface(dev_priv, uo, &vfb,
mode_cmd);
} else if (uo->buffer) {
ret = vmw_kms_new_framebuffer_bo(dev_priv, uo->buffer, &vfb,
mode_cmd);
} else {
BUG();
@ -1635,14 +1521,12 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
{
struct vmw_private *dev_priv = vmw_priv(dev);
struct vmw_framebuffer *vfb = NULL;
struct vmw_surface *surface = NULL;
struct vmw_bo *bo = NULL;
struct vmw_user_object uo = {0};
int ret;
/* returns either a bo or surface */
ret = vmw_user_lookup_handle(dev_priv, file_priv,
mode_cmd->handles[0],
&surface, &bo);
ret = vmw_user_object_lookup(dev_priv, file_priv, mode_cmd->handles[0],
&uo);
if (ret) {
DRM_ERROR("Invalid buffer object handle %u (0x%x).\n",
mode_cmd->handles[0], mode_cmd->handles[0]);
@ -1650,7 +1534,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
}
if (!bo &&
if (vmw_user_object_surface(&uo) &&
!vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height)) {
DRM_ERROR("Surface size cannot exceed %dx%d\n",
dev_priv->texture_max_width,
@ -1659,20 +1543,15 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
}
vfb = vmw_kms_new_framebuffer(dev_priv, bo, surface,
!(dev_priv->capabilities & SVGA_CAP_3D),
mode_cmd);
vfb = vmw_kms_new_framebuffer(dev_priv, &uo, mode_cmd);
if (IS_ERR(vfb)) {
ret = PTR_ERR(vfb);
goto err_out;
}
err_out:
/* vmw_user_lookup_handle takes one ref so does new_fb */
if (bo)
vmw_user_bo_unref(&bo);
if (surface)
vmw_surface_unreference(&surface);
/* vmw_user_object_lookup takes one ref so does new_fb */
vmw_user_object_unref(&uo);
if (ret) {
DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret);
@ -2584,72 +2463,6 @@ void vmw_kms_helper_validation_finish(struct vmw_private *dev_priv,
vmw_fence_obj_unreference(&fence);
}
/**
* vmw_kms_update_proxy - Helper function to update a proxy surface from
* its backing MOB.
*
* @res: Pointer to the surface resource
* @clips: Clip rects in framebuffer (surface) space.
* @num_clips: Number of clips in @clips.
* @increment: Integer with which to increment the clip counter when looping.
* Used to skip a predetermined number of clip rects.
*
* This function makes sure the proxy surface is updated from its backing MOB
* using the region given by @clips. The surface resource @res and its backing
* MOB needs to be reserved and validated on call.
*/
int vmw_kms_update_proxy(struct vmw_resource *res,
const struct drm_clip_rect *clips,
unsigned num_clips,
int increment)
{
struct vmw_private *dev_priv = res->dev_priv;
struct drm_vmw_size *size = &vmw_res_to_srf(res)->metadata.base_size;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdUpdateGBImage body;
} *cmd;
SVGA3dBox *box;
size_t copy_size = 0;
int i;
if (!clips)
return 0;
cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd) * num_clips);
if (!cmd)
return -ENOMEM;
for (i = 0; i < num_clips; ++i, clips += increment, ++cmd) {
box = &cmd->body.box;
cmd->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE;
cmd->header.size = sizeof(cmd->body);
cmd->body.image.sid = res->id;
cmd->body.image.face = 0;
cmd->body.image.mipmap = 0;
if (clips->x1 > size->width || clips->x2 > size->width ||
clips->y1 > size->height || clips->y2 > size->height) {
DRM_ERROR("Invalid clips outsize of framebuffer.\n");
return -EINVAL;
}
box->x = clips->x1;
box->y = clips->y1;
box->z = 0;
box->w = clips->x2 - clips->x1;
box->h = clips->y2 - clips->y1;
box->d = 1;
copy_size += sizeof(*cmd);
}
vmw_cmd_commit(dev_priv, copy_size);
return 0;
}
/**
* vmw_kms_create_implicit_placement_property - Set up the implicit placement
* property.
@ -2784,8 +2597,9 @@ int vmw_du_helper_plane_update(struct vmw_du_update_plane *update)
} else {
struct vmw_framebuffer_surface *vfbs =
container_of(update->vfb, typeof(*vfbs), base);
struct vmw_surface *surf = vmw_user_object_surface(&vfbs->uo);
ret = vmw_validation_add_resource(&val_ctx, &vfbs->surface->res,
ret = vmw_validation_add_resource(&val_ctx, &surf->res,
0, VMW_RES_DIRTY_NONE, NULL,
NULL);
}
@ -2941,3 +2755,93 @@ int vmw_connector_get_modes(struct drm_connector *connector)
return num_modes;
}
struct vmw_user_object *vmw_user_object_ref(struct vmw_user_object *uo)
{
if (uo->buffer)
vmw_user_bo_ref(uo->buffer);
else if (uo->surface)
vmw_surface_reference(uo->surface);
return uo;
}
void vmw_user_object_unref(struct vmw_user_object *uo)
{
if (uo->buffer)
vmw_user_bo_unref(&uo->buffer);
else if (uo->surface)
vmw_surface_unreference(&uo->surface);
}
struct vmw_bo *
vmw_user_object_buffer(struct vmw_user_object *uo)
{
if (uo->buffer)
return uo->buffer;
else if (uo->surface)
return uo->surface->res.guest_memory_bo;
return NULL;
}
struct vmw_surface *
vmw_user_object_surface(struct vmw_user_object *uo)
{
if (uo->buffer)
return uo->buffer->dumb_surface;
return uo->surface;
}
void *vmw_user_object_map(struct vmw_user_object *uo)
{
struct vmw_bo *bo = vmw_user_object_buffer(uo);
WARN_ON(!bo);
return vmw_bo_map_and_cache(bo);
}
void *vmw_user_object_map_size(struct vmw_user_object *uo, size_t size)
{
struct vmw_bo *bo = vmw_user_object_buffer(uo);
WARN_ON(!bo);
return vmw_bo_map_and_cache_size(bo, size);
}
void vmw_user_object_unmap(struct vmw_user_object *uo)
{
struct vmw_bo *bo = vmw_user_object_buffer(uo);
int ret;
WARN_ON(!bo);
/* Fence the mob creation so we are guarateed to have the mob */
ret = ttm_bo_reserve(&bo->tbo, false, false, NULL);
if (ret != 0)
return;
vmw_bo_unmap(bo);
vmw_bo_pin_reserved(bo, false);
ttm_bo_unreserve(&bo->tbo);
}
bool vmw_user_object_is_mapped(struct vmw_user_object *uo)
{
struct vmw_bo *bo;
if (!uo || vmw_user_object_is_null(uo))
return false;
bo = vmw_user_object_buffer(uo);
if (WARN_ON(!bo))
return false;
WARN_ON(bo->map.bo && !bo->map.virtual);
return bo->map.virtual;
}
bool vmw_user_object_is_null(struct vmw_user_object *uo)
{
return !uo->buffer && !uo->surface;
}

View File

@ -1,7 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
*
* Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA
* Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@ -221,11 +222,9 @@ struct vmw_framebuffer {
struct vmw_framebuffer_surface {
struct vmw_framebuffer base;
struct vmw_surface *surface;
bool is_bo_proxy; /* true if this is proxy surface for DMA buf */
struct vmw_user_object uo;
};
struct vmw_framebuffer_bo {
struct vmw_framebuffer base;
struct vmw_bo *buffer;
@ -277,8 +276,7 @@ struct vmw_cursor_plane_state {
*/
struct vmw_plane_state {
struct drm_plane_state base;
struct vmw_surface *surf;
struct vmw_bo *bo;
struct vmw_user_object uo;
int content_fb_type;
unsigned long bo_size;
@ -457,9 +455,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
uint32_t num_clips);
struct vmw_framebuffer *
vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
struct vmw_bo *bo,
struct vmw_surface *surface,
bool only_2d,
struct vmw_user_object *uo,
const struct drm_mode_fb_cmd2 *mode_cmd);
void vmw_guess_mode_timing(struct drm_display_mode *mode);
void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv);
@ -486,8 +482,7 @@ void vmw_du_plane_reset(struct drm_plane *plane);
struct drm_plane_state *vmw_du_plane_duplicate_state(struct drm_plane *plane);
void vmw_du_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state);
void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps,
bool unreference);
void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps);
int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_atomic_state *state);

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
* Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA
* Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@ -147,8 +148,9 @@ static int vmw_ldu_fb_pin(struct vmw_framebuffer *vfb)
struct vmw_bo *buf;
int ret;
buf = vfb->bo ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer :
vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.guest_memory_bo;
buf = vfb->bo ?
vmw_framebuffer_to_vfbd(&vfb->base)->buffer :
vmw_user_object_buffer(&vmw_framebuffer_to_vfbs(&vfb->base)->uo);
if (!buf)
return 0;
@ -169,8 +171,10 @@ static int vmw_ldu_fb_unpin(struct vmw_framebuffer *vfb)
struct vmw_private *dev_priv = vmw_priv(vfb->base.dev);
struct vmw_bo *buf;
buf = vfb->bo ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer :
vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.guest_memory_bo;
buf = vfb->bo ?
vmw_framebuffer_to_vfbd(&vfb->base)->buffer :
vmw_user_object_buffer(&vmw_framebuffer_to_vfbs(&vfb->base)->uo);
if (WARN_ON(!buf))
return 0;

View File

@ -92,7 +92,7 @@ static int vmw_overlay_send_put(struct vmw_private *dev_priv,
{
struct vmw_escape_video_flush *flush;
size_t fifo_size;
bool have_so = (dev_priv->active_display_unit == vmw_du_screen_object);
bool have_so = (dev_priv->active_display_unit != vmw_du_legacy);
int i, num_items;
SVGAGuestPtr ptr;

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
* Copyright 2013 VMware, Inc., Palo Alto, CA., USA
* Copyright (c) 2013-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@ -31,6 +32,7 @@
*/
#include "vmwgfx_drv.h"
#include "vmwgfx_bo.h"
#include "ttm_object.h"
#include <linux/dma-buf.h>
@ -88,13 +90,35 @@ int vmw_prime_handle_to_fd(struct drm_device *dev,
uint32_t handle, uint32_t flags,
int *prime_fd)
{
struct vmw_private *vmw = vmw_priv(dev);
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
struct vmw_bo *vbo;
int ret;
int surf_handle;
if (handle > VMWGFX_NUM_MOB)
if (handle > VMWGFX_NUM_MOB) {
ret = ttm_prime_handle_to_fd(tfile, handle, flags, prime_fd);
else
ret = drm_gem_prime_handle_to_fd(dev, file_priv, handle, flags, prime_fd);
} else {
ret = vmw_user_bo_lookup(file_priv, handle, &vbo);
if (ret)
return ret;
if (vbo && vbo->is_dumb) {
ret = drm_gem_prime_handle_to_fd(dev, file_priv, handle,
flags, prime_fd);
} else {
surf_handle = vmw_lookup_surface_handle_for_buffer(vmw,
vbo,
handle);
if (surf_handle > 0)
ret = ttm_prime_handle_to_fd(tfile, surf_handle,
flags, prime_fd);
else
ret = drm_gem_prime_handle_to_fd(dev, file_priv,
handle, flags,
prime_fd);
}
vmw_user_bo_unref(&vbo);
}
return ret;
}

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
* Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA
* Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@ -58,6 +59,7 @@ void vmw_resource_mob_attach(struct vmw_resource *res)
rb_link_node(&res->mob_node, parent, new);
rb_insert_color(&res->mob_node, &gbo->res_tree);
vmw_bo_del_detached_resource(gbo, res);
vmw_bo_prio_add(gbo, res->used_prio);
}
@ -287,28 +289,35 @@ out_bad_resource:
*
* The pointer this pointed at by out_surf and out_buf needs to be null.
*/
int vmw_user_lookup_handle(struct vmw_private *dev_priv,
int vmw_user_object_lookup(struct vmw_private *dev_priv,
struct drm_file *filp,
uint32_t handle,
struct vmw_surface **out_surf,
struct vmw_bo **out_buf)
u32 handle,
struct vmw_user_object *uo)
{
struct ttm_object_file *tfile = vmw_fpriv(filp)->tfile;
struct vmw_resource *res;
int ret;
BUG_ON(*out_surf || *out_buf);
WARN_ON(uo->surface || uo->buffer);
ret = vmw_user_resource_lookup_handle(dev_priv, tfile, handle,
user_surface_converter,
&res);
if (!ret) {
*out_surf = vmw_res_to_srf(res);
uo->surface = vmw_res_to_srf(res);
return 0;
}
*out_surf = NULL;
ret = vmw_user_bo_lookup(filp, handle, out_buf);
uo->surface = NULL;
ret = vmw_user_bo_lookup(filp, handle, &uo->buffer);
if (!ret && !uo->buffer->is_dumb) {
uo->surface = vmw_lookup_surface_for_buffer(dev_priv,
uo->buffer,
handle);
if (uo->surface)
vmw_user_bo_unref(&uo->buffer);
}
return ret;
}

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
* Copyright 2011-2023 VMware, Inc., Palo Alto, CA., USA
* Copyright (c) 2011-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@ -240,7 +241,7 @@ static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc)
struct vmw_connector_state *vmw_conn_state;
int x, y;
sou->buffer = vps->bo;
sou->buffer = vmw_user_object_buffer(&vps->uo);
conn_state = sou->base.connector.state;
vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
@ -376,10 +377,11 @@ vmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane,
struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
struct drm_crtc *crtc = plane->state->crtc ?
plane->state->crtc : old_state->crtc;
struct vmw_bo *bo = vmw_user_object_buffer(&vps->uo);
if (vps->bo)
vmw_bo_unpin(vmw_priv(crtc->dev), vps->bo, false);
vmw_bo_unreference(&vps->bo);
if (bo)
vmw_bo_unpin(vmw_priv(crtc->dev), bo, false);
vmw_user_object_unref(&vps->uo);
vps->bo_size = 0;
vmw_du_plane_cleanup_fb(plane, old_state);
@ -411,9 +413,10 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
.bo_type = ttm_bo_type_device,
.pin = true
};
struct vmw_bo *bo = NULL;
if (!new_fb) {
vmw_bo_unreference(&vps->bo);
vmw_user_object_unref(&vps->uo);
vps->bo_size = 0;
return 0;
@ -422,17 +425,17 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
bo_params.size = new_state->crtc_w * new_state->crtc_h * 4;
dev_priv = vmw_priv(crtc->dev);
if (vps->bo) {
bo = vmw_user_object_buffer(&vps->uo);
if (bo) {
if (vps->bo_size == bo_params.size) {
/*
* Note that this might temporarily up the pin-count
* to 2, until cleanup_fb() is called.
*/
return vmw_bo_pin_in_vram(dev_priv, vps->bo,
true);
return vmw_bo_pin_in_vram(dev_priv, bo, true);
}
vmw_bo_unreference(&vps->bo);
vmw_user_object_unref(&vps->uo);
vps->bo_size = 0;
}
@ -442,7 +445,7 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
* resume the overlays, this is preferred to failing to alloc.
*/
vmw_overlay_pause_all(dev_priv);
ret = vmw_bo_create(dev_priv, &bo_params, &vps->bo);
ret = vmw_gem_object_create(dev_priv, &bo_params, &vps->uo.buffer);
vmw_overlay_resume_all(dev_priv);
if (ret)
return ret;
@ -453,7 +456,7 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
* TTM already thinks the buffer is pinned, but make sure the
* pin_count is upped.
*/
return vmw_bo_pin_in_vram(dev_priv, vps->bo, true);
return vmw_bo_pin_in_vram(dev_priv, vps->uo.buffer, true);
}
static uint32_t vmw_sou_bo_fifo_size(struct vmw_du_update_plane *update,
@ -580,6 +583,7 @@ static uint32_t vmw_sou_surface_pre_clip(struct vmw_du_update_plane *update,
{
struct vmw_kms_sou_dirty_cmd *blit = cmd;
struct vmw_framebuffer_surface *vfbs;
struct vmw_surface *surf = NULL;
vfbs = container_of(update->vfb, typeof(*vfbs), base);
@ -587,7 +591,8 @@ static uint32_t vmw_sou_surface_pre_clip(struct vmw_du_update_plane *update,
blit->header.size = sizeof(blit->body) + sizeof(SVGASignedRect) *
num_hits;
blit->body.srcImage.sid = vfbs->surface->res.id;
surf = vmw_user_object_surface(&vfbs->uo);
blit->body.srcImage.sid = surf->res.id;
blit->body.destScreenId = update->du->unit;
/* Update the source and destination bounding box later in post_clip */
@ -1104,7 +1109,7 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
int ret;
if (!srf)
srf = &vfbs->surface->res;
srf = &vmw_user_object_surface(&vfbs->uo)->res;
ret = vmw_validation_add_resource(&val_ctx, srf, 0, VMW_RES_DIRTY_NONE,
NULL, NULL);

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/******************************************************************************
*
* COPYRIGHT (C) 2014-2023 VMware, Inc., Palo Alto, CA., USA
* Copyright (c) 2014-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@ -29,6 +30,7 @@
#include "vmwgfx_kms.h"
#include "vmwgfx_vkms.h"
#include "vmw_surface_cache.h"
#include <linux/fsnotify.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@ -735,7 +737,7 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv,
int ret;
if (!srf)
srf = &vfbs->surface->res;
srf = &vmw_user_object_surface(&vfbs->uo)->res;
ret = vmw_validation_add_resource(&val_ctx, srf, 0, VMW_RES_DIRTY_NONE,
NULL, NULL);
@ -746,12 +748,6 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv,
if (ret)
goto out_unref;
if (vfbs->is_bo_proxy) {
ret = vmw_kms_update_proxy(srf, clips, num_clips, inc);
if (ret)
goto out_finish;
}
sdirty.base.fifo_commit = vmw_kms_stdu_surface_fifo_commit;
sdirty.base.clip = vmw_kms_stdu_surface_clip;
sdirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_surface_copy) +
@ -765,7 +761,7 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv,
ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips,
dest_x, dest_y, num_clips, inc,
&sdirty.base);
out_finish:
vmw_kms_helper_validation_finish(dev_priv, NULL, &val_ctx, out_fence,
NULL);
@ -877,6 +873,32 @@ vmw_stdu_connector_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
/*
* Trigger a modeset if the X,Y position of the Screen Target changes.
* This is needed when multi-mon is cycled. The original Screen Target will have
* the same mode but its relative X,Y position in the topology will change.
*/
static int vmw_stdu_connector_atomic_check(struct drm_connector *conn,
struct drm_atomic_state *state)
{
struct drm_connector_state *conn_state;
struct vmw_screen_target_display_unit *du;
struct drm_crtc_state *new_crtc_state;
conn_state = drm_atomic_get_connector_state(state, conn);
du = vmw_connector_to_stdu(conn);
if (!conn_state->crtc)
return 0;
new_crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
if (du->base.gui_x != du->base.set_gui_x ||
du->base.gui_y != du->base.set_gui_y)
new_crtc_state->mode_changed = true;
return 0;
}
static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
.dpms = vmw_du_connector_dpms,
.detect = vmw_du_connector_detect,
@ -891,7 +913,8 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
static const struct
drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = {
.get_modes = vmw_connector_get_modes,
.mode_valid = vmw_stdu_connector_mode_valid
.mode_valid = vmw_stdu_connector_mode_valid,
.atomic_check = vmw_stdu_connector_atomic_check,
};
@ -918,9 +941,8 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane,
{
struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
if (vps->surf)
if (vmw_user_object_surface(&vps->uo))
WARN_ON(!vps->pinned);
vmw_du_plane_cleanup_fb(plane, old_state);
vps->content_fb_type = SAME_AS_DISPLAY;
@ -928,7 +950,6 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane,
}
/**
* vmw_stdu_primary_plane_prepare_fb - Readies the display surface
*
@ -952,13 +973,15 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
enum stdu_content_type new_content_type;
struct vmw_framebuffer_surface *new_vfbs;
uint32_t hdisplay = new_state->crtc_w, vdisplay = new_state->crtc_h;
struct drm_plane_state *old_state = plane->state;
struct drm_rect rect;
int ret;
/* No FB to prepare */
if (!new_fb) {
if (vps->surf) {
if (vmw_user_object_surface(&vps->uo)) {
WARN_ON(vps->pinned != 0);
vmw_surface_unreference(&vps->surf);
vmw_user_object_unref(&vps->uo);
}
return 0;
@ -968,8 +991,8 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
new_vfbs = (vfb->bo) ? NULL : vmw_framebuffer_to_vfbs(new_fb);
if (new_vfbs &&
new_vfbs->surface->metadata.base_size.width == hdisplay &&
new_vfbs->surface->metadata.base_size.height == vdisplay)
vmw_user_object_surface(&new_vfbs->uo)->metadata.base_size.width == hdisplay &&
vmw_user_object_surface(&new_vfbs->uo)->metadata.base_size.height == vdisplay)
new_content_type = SAME_AS_DISPLAY;
else if (vfb->bo)
new_content_type = SEPARATE_BO;
@ -1007,29 +1030,29 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
metadata.num_sizes = 1;
metadata.scanout = true;
} else {
metadata = new_vfbs->surface->metadata;
metadata = vmw_user_object_surface(&new_vfbs->uo)->metadata;
}
metadata.base_size.width = hdisplay;
metadata.base_size.height = vdisplay;
metadata.base_size.depth = 1;
if (vps->surf) {
if (vmw_user_object_surface(&vps->uo)) {
struct drm_vmw_size cur_base_size =
vps->surf->metadata.base_size;
vmw_user_object_surface(&vps->uo)->metadata.base_size;
if (cur_base_size.width != metadata.base_size.width ||
cur_base_size.height != metadata.base_size.height ||
vps->surf->metadata.format != metadata.format) {
vmw_user_object_surface(&vps->uo)->metadata.format != metadata.format) {
WARN_ON(vps->pinned != 0);
vmw_surface_unreference(&vps->surf);
vmw_user_object_unref(&vps->uo);
}
}
if (!vps->surf) {
if (!vmw_user_object_surface(&vps->uo)) {
ret = vmw_gb_surface_define(dev_priv, &metadata,
&vps->surf);
&vps->uo.surface);
if (ret != 0) {
DRM_ERROR("Couldn't allocate STDU surface.\n");
return ret;
@ -1042,18 +1065,19 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
* The only time we add a reference in prepare_fb is if the
* state object doesn't have a reference to begin with
*/
if (vps->surf) {
if (vmw_user_object_surface(&vps->uo)) {
WARN_ON(vps->pinned != 0);
vmw_surface_unreference(&vps->surf);
vmw_user_object_unref(&vps->uo);
}
vps->surf = vmw_surface_reference(new_vfbs->surface);
memcpy(&vps->uo, &new_vfbs->uo, sizeof(vps->uo));
vmw_user_object_ref(&vps->uo);
}
if (vps->surf) {
if (vmw_user_object_surface(&vps->uo)) {
/* Pin new surface before flipping */
ret = vmw_resource_pin(&vps->surf->res, false);
ret = vmw_resource_pin(&vmw_user_object_surface(&vps->uo)->res, false);
if (ret)
goto out_srf_unref;
@ -1062,6 +1086,34 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
vps->content_fb_type = new_content_type;
/*
* The drm fb code will do blit's via the vmap interface, which doesn't
* trigger vmw_bo page dirty tracking due to being kernel side (and thus
* doesn't require mmap'ing) so we have to update the surface's dirty
* regions by hand but we want to be careful to not overwrite the
* resource if it has been written to by the gpu (res_dirty).
*/
if (vps->uo.buffer && vps->uo.buffer->is_dumb) {
struct vmw_surface *surf = vmw_user_object_surface(&vps->uo);
struct vmw_resource *res = &surf->res;
if (!res->res_dirty && drm_atomic_helper_damage_merged(old_state,
new_state,
&rect)) {
/*
* At some point it might be useful to actually translate
* (rect.x1, rect.y1) => start, and (rect.x2, rect.y2) => end,
* but currently the fb code will just report the entire fb
* dirty so in practice it doesn't matter.
*/
pgoff_t start = res->guest_memory_offset >> PAGE_SHIFT;
pgoff_t end = __KERNEL_DIV_ROUND_UP(res->guest_memory_offset +
res->guest_memory_size,
PAGE_SIZE);
vmw_resource_dirty_update(res, start, end);
}
}
/*
* This should only happen if the buffer object is too large to create a
* proxy surface for.
@ -1072,7 +1124,7 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
return 0;
out_srf_unref:
vmw_surface_unreference(&vps->surf);
vmw_user_object_unref(&vps->uo);
return ret;
}
@ -1214,14 +1266,8 @@ static uint32_t
vmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update,
uint32_t num_hits)
{
struct vmw_framebuffer_surface *vfbs;
uint32_t size = 0;
vfbs = container_of(update->vfb, typeof(*vfbs), base);
if (vfbs->is_bo_proxy)
size += sizeof(struct vmw_stdu_update_gb_image) * num_hits;
size += sizeof(struct vmw_stdu_update);
return size;
@ -1230,61 +1276,14 @@ vmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update,
static uint32_t vmw_stdu_surface_fifo_size(struct vmw_du_update_plane *update,
uint32_t num_hits)
{
struct vmw_framebuffer_surface *vfbs;
uint32_t size = 0;
vfbs = container_of(update->vfb, typeof(*vfbs), base);
if (vfbs->is_bo_proxy)
size += sizeof(struct vmw_stdu_update_gb_image) * num_hits;
size += sizeof(struct vmw_stdu_surface_copy) + sizeof(SVGA3dCopyBox) *
num_hits + sizeof(struct vmw_stdu_update);
return size;
}
static uint32_t
vmw_stdu_surface_update_proxy(struct vmw_du_update_plane *update, void *cmd)
{
struct vmw_framebuffer_surface *vfbs;
struct drm_plane_state *state = update->plane->state;
struct drm_plane_state *old_state = update->old_state;
struct vmw_stdu_update_gb_image *cmd_update = cmd;
struct drm_atomic_helper_damage_iter iter;
struct drm_rect clip;
uint32_t copy_size = 0;
vfbs = container_of(update->vfb, typeof(*vfbs), base);
/*
* proxy surface is special where a buffer object type fb is wrapped
* in a surface and need an update gb image command to sync with device.
*/
drm_atomic_helper_damage_iter_init(&iter, old_state, state);
drm_atomic_for_each_plane_damage(&iter, &clip) {
SVGA3dBox *box = &cmd_update->body.box;
cmd_update->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE;
cmd_update->header.size = sizeof(cmd_update->body);
cmd_update->body.image.sid = vfbs->surface->res.id;
cmd_update->body.image.face = 0;
cmd_update->body.image.mipmap = 0;
box->x = clip.x1;
box->y = clip.y1;
box->z = 0;
box->w = drm_rect_width(&clip);
box->h = drm_rect_height(&clip);
box->d = 1;
copy_size += sizeof(*cmd_update);
cmd_update++;
}
return copy_size;
}
static uint32_t
vmw_stdu_surface_populate_copy(struct vmw_du_update_plane *update, void *cmd,
uint32_t num_hits)
@ -1299,7 +1298,7 @@ vmw_stdu_surface_populate_copy(struct vmw_du_update_plane *update, void *cmd,
cmd_copy->header.id = SVGA_3D_CMD_SURFACE_COPY;
cmd_copy->header.size = sizeof(cmd_copy->body) + sizeof(SVGA3dCopyBox) *
num_hits;
cmd_copy->body.src.sid = vfbs->surface->res.id;
cmd_copy->body.src.sid = vmw_user_object_surface(&vfbs->uo)->res.id;
cmd_copy->body.dest.sid = stdu->display_srf->res.id;
return sizeof(*cmd_copy);
@ -1370,10 +1369,7 @@ static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv,
srf_update.mutex = &dev_priv->cmdbuf_mutex;
srf_update.intr = true;
if (vfbs->is_bo_proxy)
srf_update.post_prepare = vmw_stdu_surface_update_proxy;
if (vfbs->surface->res.id != stdu->display_srf->res.id) {
if (vmw_user_object_surface(&vfbs->uo)->res.id != stdu->display_srf->res.id) {
srf_update.calc_fifo_size = vmw_stdu_surface_fifo_size;
srf_update.pre_clip = vmw_stdu_surface_populate_copy;
srf_update.clip = vmw_stdu_surface_populate_clip;
@ -1417,7 +1413,7 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
stdu = vmw_crtc_to_stdu(crtc);
dev_priv = vmw_priv(crtc->dev);
stdu->display_srf = vps->surf;
stdu->display_srf = vmw_user_object_surface(&vps->uo);
stdu->content_fb_type = vps->content_fb_type;
stdu->cpp = vps->cpp;

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/**************************************************************************
*
* Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA
* Copyright (c) 2009-2024 Broadcom. All Rights Reserved. The term
* Broadcom refers to Broadcom Inc. and/or its subsidiaries.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@ -36,9 +37,6 @@
#include <drm/ttm/ttm_placement.h>
#define SVGA3D_FLAGS_64(upper32, lower32) (((uint64_t)upper32 << 32) | lower32)
#define SVGA3D_FLAGS_UPPER_32(svga3d_flags) (svga3d_flags >> 32)
#define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \
(svga3d_flags & ((uint64_t)U32_MAX))
/**
* struct vmw_user_surface - User-space visible surface resource
@ -686,6 +684,14 @@ static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
struct vmw_resource *res = &user_srf->srf.res;
*p_base = NULL;
/*
* Dumb buffers own the resource and they'll unref the
* resource themselves
*/
if (res && res->guest_memory_bo && res->guest_memory_bo->is_dumb)
return;
vmw_resource_unreference(&res);
}
@ -812,7 +818,8 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
}
}
res->guest_memory_size = cur_bo_offset;
if (metadata->scanout &&
if (!file_priv->atomic &&
metadata->scanout &&
metadata->num_sizes == 1 &&
metadata->sizes[0].width == VMW_CURSOR_SNOOP_WIDTH &&
metadata->sizes[0].height == VMW_CURSOR_SNOOP_HEIGHT &&
@ -864,6 +871,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
vmw_resource_unreference(&res);
goto out_unlock;
}
vmw_bo_add_detached_resource(res->guest_memory_bo, res);
}
tmp = vmw_resource_reference(&srf->res);
@ -892,6 +900,113 @@ out_unlock:
return ret;
}
static struct vmw_user_surface *
vmw_lookup_user_surface_for_buffer(struct vmw_private *vmw, struct vmw_bo *bo,
u32 handle)
{
struct vmw_user_surface *user_srf = NULL;
struct vmw_surface *surf;
struct ttm_base_object *base;
surf = vmw_bo_surface(bo);
if (surf) {
rcu_read_lock();
user_srf = container_of(surf, struct vmw_user_surface, srf);
base = &user_srf->prime.base;
if (base && !kref_get_unless_zero(&base->refcount)) {
drm_dbg_driver(&vmw->drm,
"%s: referencing a stale surface handle %d\n",
__func__, handle);
base = NULL;
user_srf = NULL;
}
rcu_read_unlock();
}
return user_srf;
}
struct vmw_surface *vmw_lookup_surface_for_buffer(struct vmw_private *vmw,
struct vmw_bo *bo,
u32 handle)
{
struct vmw_user_surface *user_srf =
vmw_lookup_user_surface_for_buffer(vmw, bo, handle);
struct vmw_surface *surf = NULL;
struct ttm_base_object *base;
if (user_srf) {
surf = vmw_surface_reference(&user_srf->srf);
base = &user_srf->prime.base;
ttm_base_object_unref(&base);
}
return surf;
}
u32 vmw_lookup_surface_handle_for_buffer(struct vmw_private *vmw,
struct vmw_bo *bo,
u32 handle)
{
struct vmw_user_surface *user_srf =
vmw_lookup_user_surface_for_buffer(vmw, bo, handle);
int surf_handle = 0;
struct ttm_base_object *base;
if (user_srf) {
base = &user_srf->prime.base;
surf_handle = (u32)base->handle;
ttm_base_object_unref(&base);
}
return surf_handle;
}
static int vmw_buffer_prime_to_surface_base(struct vmw_private *dev_priv,
struct drm_file *file_priv,
u32 fd, u32 *handle,
struct ttm_base_object **base_p)
{
struct ttm_base_object *base;
struct vmw_bo *bo;
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
struct vmw_user_surface *user_srf;
int ret;
ret = drm_gem_prime_fd_to_handle(&dev_priv->drm, file_priv, fd, handle);
if (ret) {
drm_warn(&dev_priv->drm,
"Wasn't able to find user buffer for fd = %u.\n", fd);
return ret;
}
ret = vmw_user_bo_lookup(file_priv, *handle, &bo);
if (ret) {
drm_warn(&dev_priv->drm,
"Wasn't able to lookup user buffer for handle = %u.\n", *handle);
return ret;
}
user_srf = vmw_lookup_user_surface_for_buffer(dev_priv, bo, *handle);
if (WARN_ON(!user_srf)) {
drm_warn(&dev_priv->drm,
"User surface fd %d (handle %d) is null.\n", fd, *handle);
ret = -EINVAL;
goto out;
}
base = &user_srf->prime.base;
ret = ttm_ref_object_add(tfile, base, NULL, false);
if (ret) {
drm_warn(&dev_priv->drm,
"Couldn't add an object ref for the buffer (%d).\n", *handle);
goto out;
}
*base_p = base;
out:
vmw_user_bo_unref(&bo);
return ret;
}
static int
vmw_surface_handle_reference(struct vmw_private *dev_priv,
@ -901,15 +1016,19 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv,
struct ttm_base_object **base_p)
{
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
struct vmw_user_surface *user_srf;
struct vmw_user_surface *user_srf = NULL;
uint32_t handle;
struct ttm_base_object *base;
int ret;
if (handle_type == DRM_VMW_HANDLE_PRIME) {
ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle);
if (unlikely(ret != 0))
return ret;
if (ret)
return vmw_buffer_prime_to_surface_base(dev_priv,
file_priv,
u_handle,
&handle,
base_p);
} else {
handle = u_handle;
}
@ -1503,7 +1622,12 @@ vmw_gb_surface_define_internal(struct drm_device *dev,
ret = vmw_user_bo_lookup(file_priv, req->base.buffer_handle,
&res->guest_memory_bo);
if (ret == 0) {
if (res->guest_memory_bo->tbo.base.size < res->guest_memory_size) {
if (res->guest_memory_bo->is_dumb) {
VMW_DEBUG_USER("Can't backup surface with a dumb buffer.\n");
vmw_user_bo_unref(&res->guest_memory_bo);
ret = -EINVAL;
goto out_unlock;
} else if (res->guest_memory_bo->tbo.base.size < res->guest_memory_size) {
VMW_DEBUG_USER("Surface backup buffer too small.\n");
vmw_user_bo_unref(&res->guest_memory_bo);
ret = -EINVAL;
@ -1560,6 +1684,7 @@ vmw_gb_surface_define_internal(struct drm_device *dev,
rep->handle = user_srf->prime.base.handle;
rep->backup_size = res->guest_memory_size;
if (res->guest_memory_bo) {
vmw_bo_add_detached_resource(res->guest_memory_bo, res);
rep->buffer_map_handle =
drm_vma_node_offset_addr(&res->guest_memory_bo->tbo.base.vma_node);
rep->buffer_size = res->guest_memory_bo->tbo.base.size;
@ -2100,3 +2225,140 @@ int vmw_gb_surface_define(struct vmw_private *dev_priv,
out_unlock:
return ret;
}
static SVGA3dSurfaceFormat vmw_format_bpp_to_svga(struct vmw_private *vmw,
int bpp)
{
switch (bpp) {
case 8: /* DRM_FORMAT_C8 */
return SVGA3D_P8;
case 16: /* DRM_FORMAT_RGB565 */
return SVGA3D_R5G6B5;
case 32: /* DRM_FORMAT_XRGB8888 */
if (has_sm4_context(vmw))
return SVGA3D_B8G8R8X8_UNORM;
return SVGA3D_X8R8G8B8;
default:
drm_warn(&vmw->drm, "Unsupported format bpp: %d\n", bpp);
return SVGA3D_X8R8G8B8;
}
}
/**
* vmw_dumb_create - Create a dumb kms buffer
*
* @file_priv: Pointer to a struct drm_file identifying the caller.
* @dev: Pointer to the drm device.
* @args: Pointer to a struct drm_mode_create_dumb structure
* Return: Zero on success, negative error code on failure.
*
* This is a driver callback for the core drm create_dumb functionality.
* Note that this is very similar to the vmw_bo_alloc ioctl, except
* that the arguments have a different format.
*/
int vmw_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
struct vmw_private *dev_priv = vmw_priv(dev);
struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
struct vmw_bo *vbo = NULL;
struct vmw_resource *res = NULL;
union drm_vmw_gb_surface_create_ext_arg arg = { 0 };
struct drm_vmw_gb_surface_create_ext_req *req = &arg.req;
int ret;
struct drm_vmw_size drm_size = {
.width = args->width,
.height = args->height,
.depth = 1,
};
SVGA3dSurfaceFormat format = vmw_format_bpp_to_svga(dev_priv, args->bpp);
const struct SVGA3dSurfaceDesc *desc = vmw_surface_get_desc(format);
SVGA3dSurfaceAllFlags flags = SVGA3D_SURFACE_HINT_TEXTURE |
SVGA3D_SURFACE_HINT_RENDERTARGET |
SVGA3D_SURFACE_SCREENTARGET |
SVGA3D_SURFACE_BIND_SHADER_RESOURCE |
SVGA3D_SURFACE_BIND_RENDER_TARGET;
/*
* Without mob support we're just going to use raw memory buffer
* because we wouldn't be able to support full surface coherency
* without mobs
*/
if (!dev_priv->has_mob) {
int cpp = DIV_ROUND_UP(args->bpp, 8);
switch (cpp) {
case 1: /* DRM_FORMAT_C8 */
case 2: /* DRM_FORMAT_RGB565 */
case 4: /* DRM_FORMAT_XRGB8888 */
break;
default:
/*
* Dumb buffers don't allow anything else.
* This is tested via IGT's dumb_buffers
*/
return -EINVAL;
}
args->pitch = args->width * cpp;
args->size = ALIGN(args->pitch * args->height, PAGE_SIZE);
ret = vmw_gem_object_create_with_handle(dev_priv, file_priv,
args->size, &args->handle,
&vbo);
/* drop reference from allocate - handle holds it now */
drm_gem_object_put(&vbo->tbo.base);
return ret;
}
req->version = drm_vmw_gb_surface_v1;
req->multisample_pattern = SVGA3D_MS_PATTERN_NONE;
req->quality_level = SVGA3D_MS_QUALITY_NONE;
req->buffer_byte_stride = 0;
req->must_be_zero = 0;
req->base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(flags);
req->svga3d_flags_upper_32_bits = SVGA3D_FLAGS_UPPER_32(flags);
req->base.format = (uint32_t)format;
req->base.drm_surface_flags = drm_vmw_surface_flag_scanout;
req->base.drm_surface_flags |= drm_vmw_surface_flag_shareable;
req->base.drm_surface_flags |= drm_vmw_surface_flag_create_buffer;
req->base.drm_surface_flags |= drm_vmw_surface_flag_coherent;
req->base.base_size.width = args->width;
req->base.base_size.height = args->height;
req->base.base_size.depth = 1;
req->base.array_size = 0;
req->base.mip_levels = 1;
req->base.multisample_count = 0;
req->base.buffer_handle = SVGA3D_INVALID_ID;
req->base.autogen_filter = SVGA3D_TEX_FILTER_NONE;
ret = vmw_gb_surface_define_ext_ioctl(dev, &arg, file_priv);
if (ret) {
drm_warn(dev, "Unable to create a dumb buffer\n");
return ret;
}
args->handle = arg.rep.buffer_handle;
args->size = arg.rep.buffer_size;
args->pitch = vmw_surface_calculate_pitch(desc, &drm_size);
ret = vmw_user_resource_lookup_handle(dev_priv, tfile, arg.rep.handle,
user_surface_converter,
&res);
if (ret) {
drm_err(dev, "Created resource handle doesn't exist!\n");
goto err;
}
vbo = res->guest_memory_bo;
vbo->is_dumb = true;
vbo->dumb_surface = vmw_res_to_srf(res);
err:
if (res)
vmw_resource_unreference(&res);
if (ret)
ttm_ref_object_base_unref(tfile, arg.rep.handle);
return ret;
}

View File

@ -75,7 +75,7 @@ done:
return ret;
}
static int
static void
compute_crc(struct drm_crtc *crtc,
struct vmw_surface *surf,
u32 *crc)
@ -101,8 +101,6 @@ compute_crc(struct drm_crtc *crtc,
}
vmw_bo_unmap(bo);
return 0;
}
static void
@ -116,7 +114,6 @@ crc_generate_worker(struct work_struct *work)
u64 frame_start, frame_end;
u32 crc32 = 0;
struct vmw_surface *surf = 0;
int ret;
spin_lock_irq(&du->vkms.crc_state_lock);
crc_pending = du->vkms.crc_pending;
@ -130,22 +127,24 @@ crc_generate_worker(struct work_struct *work)
return;
spin_lock_irq(&du->vkms.crc_state_lock);
surf = du->vkms.surface;
surf = vmw_surface_reference(du->vkms.surface);
spin_unlock_irq(&du->vkms.crc_state_lock);
if (vmw_surface_sync(vmw, surf)) {
drm_warn(crtc->dev, "CRC worker wasn't able to sync the crc surface!\n");
return;
}
if (surf) {
if (vmw_surface_sync(vmw, surf)) {
drm_warn(
crtc->dev,
"CRC worker wasn't able to sync the crc surface!\n");
return;
}
ret = compute_crc(crtc, surf, &crc32);
if (ret)
return;
compute_crc(crtc, surf, &crc32);
vmw_surface_unreference(&surf);
}
spin_lock_irq(&du->vkms.crc_state_lock);
frame_start = du->vkms.frame_start;
frame_end = du->vkms.frame_end;
crc_pending = du->vkms.crc_pending;
du->vkms.frame_start = 0;
du->vkms.frame_end = 0;
du->vkms.crc_pending = false;
@ -164,7 +163,7 @@ vmw_vkms_vblank_simulate(struct hrtimer *timer)
struct vmw_display_unit *du = container_of(timer, struct vmw_display_unit, vkms.timer);
struct drm_crtc *crtc = &du->crtc;
struct vmw_private *vmw = vmw_priv(crtc->dev);
struct vmw_surface *surf = NULL;
bool has_surface = false;
u64 ret_overrun;
bool locked, ret;
@ -179,10 +178,10 @@ vmw_vkms_vblank_simulate(struct hrtimer *timer)
WARN_ON(!ret);
if (!locked)
return HRTIMER_RESTART;
surf = du->vkms.surface;
has_surface = du->vkms.surface != NULL;
vmw_vkms_unlock(crtc);
if (du->vkms.crc_enabled && surf) {
if (du->vkms.crc_enabled && has_surface) {
u64 frame = drm_crtc_accurate_vblank_count(crtc);
spin_lock(&du->vkms.crc_state_lock);
@ -336,6 +335,8 @@ vmw_vkms_crtc_cleanup(struct drm_crtc *crtc)
{
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
if (du->vkms.surface)
vmw_surface_unreference(&du->vkms.surface);
WARN_ON(work_pending(&du->vkms.crc_generator_work));
hrtimer_cancel(&du->vkms.timer);
}
@ -497,9 +498,12 @@ vmw_vkms_set_crc_surface(struct drm_crtc *crtc,
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
struct vmw_private *vmw = vmw_priv(crtc->dev);
if (vmw->vkms_enabled) {
if (vmw->vkms_enabled && du->vkms.surface != surf) {
WARN_ON(atomic_read(&du->vkms.atomic_lock) != VMW_VKMS_LOCK_MODESET);
du->vkms.surface = surf;
if (du->vkms.surface)
vmw_surface_unreference(&du->vkms.surface);
if (surf)
du->vkms.surface = vmw_surface_reference(surf);
}
}

View File

@ -29,9 +29,11 @@ static int check_vgem(int fd)
version.name = name;
ret = ioctl(fd, DRM_IOCTL_VERSION, &version);
if (ret)
if (ret || version.name_len != 4)
return 0;
name[4] = '\0';
return !strcmp(name, "vgem");
}