drm fixes for 6.16-rc5

dma-buf:
 - fix timeout handling
 
 gem:
 - fix framebuffer object references
 
 sched:
 - fix spsc queue job count race
 
 bridge:
 - fix aux hpd bridge of node
 - panel: move missing flag handling
 - samsung-dsim: fix %pK usage to %p
 
 panel:
 - fix problem with simple panel lookup
 
 ttm:
 - fix error path handling
 
 amdgpu:
 - SDMA 5.x reset fix
 - Add missing firmware declaration
 - Fix leak in amdgpu_ctx_mgr_entity_fini()
 - Freesync fix
 - OLED backlight fix
 
 amdkfd:
 - mtype fix for ext coherent system memory
 - MMU notifier fix
 - gfx7/8 fix
 
 xe:
 - Fix chunking the PTE updates and overflowing the maximum number of
   dwords with with MI_STORE_DATA_IMM
 - Move WA BB to the LRC BO to mitigate hangs on context switch
 - Fix frequency/flush WAs for BMG
 - Fix kconfig prompt title and description
 - Do not require kunit
 - Extend 14018094691 WA to BMG
 - Fix wedging the device on signal
 
 i915:
 - Make mei interrupt top half irq disabled to fix RT builds
 - Fix timeline left held on VMA alloc error
 - Fix NULL pointer deref in vlv_dphy_param_init()
 - Fix selftest mock_request() to avoid NULL deref
 
 exynos:
 - switch to using %p instead of %pK
 - fix vblank NULL ptr race
 - fix lockup on samsung peach-pit/pi chromebooks
 
 vesadrm:
 - NULL ptr fix
 
 vmwgfx:
 - fix encrypted memory allocation bug
 
 v3d:
 - fix irq enabled during reset
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmhnJqYACgkQDHTzWXnE
 hr7yaA//dSpVeTqjY5k2uZNM87l+fihddR/NMXOMhFMA69AaBB66Rw30/BCZPI0l
 fKE0zU9Dt8ioVdBNz2Bf45Ia2OU0KVf35YO1yZ6ol1PzPxOplJaPTj83cZLLouOa
 X6F0QqpULMBdGWQv8XZFsiOpqli3Wjh4df4KNNkpHw2PykCmIhTGQnXzJpOF3p8m
 hjfPFJ2gJqnu76yUP0oHwdbPuCvZ6fndv6Vv1qQHSsBrFz8bsgQQtTsELWl/1H8Y
 6ORH3aMO8x6Fj2Lcz+r2O2IkK/HQ9HlR2hTH77TbjZMqj17brRoozRV4mMLe1W0S
 HftGQQGlpTjcdeuU1K3ILCyY49QzW28pOgZazQwy5c57c5LXJDakTUv6swVTG4yE
 1Xha9YED+TJ+dyg7eRD5+Pet0rmE7OVoVMLwZd5VFv3f08HSBt2ZTqW4NvqdE2iw
 /sChun2oM5w+QnKO7ziHXl59SqN1aR41s6ud34RE1tjvc5Op3UEIlO0kHRZXhqVN
 dhBGVsUjSBgfao7YpaDiYggr2oC9mHEd53+okEQ7o4UsoXdH/9xmia1yBbKBvoU8
 0w/XnaJJlcFGH6AtNOkRa0E5xZEYNAYsSVho2ME3lPqdDjijKXFVk2ERlj+OkUUY
 m5q/sfgOf+b4BChYOulUY59f+AqyxD1UB83K2ZZEpDqDftCKDOo=
 =mTVZ
 -----END PGP SIGNATURE-----

Merge tag 'drm-fixes-2025-07-04' of https://gitlab.freedesktop.org/drm/kernel

Pull drm fixes from Dave Airlie:
 "Weekly drm fixes, bit of a bumper crop, the usual amdgpu/xe/i915
  suspects, then there is a large scattering of fixes across core and
  drivers. I think the simple panel lookup fix is probably the largest,
  the sched race fix is also fun, but I don't see anything standing out
  too badly.

  dma-buf:
   - fix timeout handling

  gem:
   - fix framebuffer object references

  sched:
   - fix spsc queue job count race

  bridge:
   - fix aux hpd bridge of node
   - panel: move missing flag handling
   - samsung-dsim: fix %pK usage to %p

  panel:
   - fix problem with simple panel lookup

  ttm:
   - fix error path handling

  amdgpu:
   - SDMA 5.x reset fix
   - Add missing firmware declaration
   - Fix leak in amdgpu_ctx_mgr_entity_fini()
   - Freesync fix
   - OLED backlight fix

  amdkfd:
   - mtype fix for ext coherent system memory
   - MMU notifier fix
   - gfx7/8 fix

  xe:
   - Fix chunking the PTE updates and overflowing the maximum number of
     dwords with with MI_STORE_DATA_IMM
   - Move WA BB to the LRC BO to mitigate hangs on context switch
   - Fix frequency/flush WAs for BMG
   - Fix kconfig prompt title and description
   - Do not require kunit
   - Extend 14018094691 WA to BMG
   - Fix wedging the device on signal

  i915:
   - Make mei interrupt top half irq disabled to fix RT builds
   - Fix timeline left held on VMA alloc error
   - Fix NULL pointer deref in vlv_dphy_param_init()
   - Fix selftest mock_request() to avoid NULL deref

  exynos:
   - switch to using %p instead of %pK
   - fix vblank NULL ptr race
   - fix lockup on samsung peach-pit/pi chromebooks

  vesadrm:
   - NULL ptr fix

  vmwgfx:
   - fix encrypted memory allocation bug

  v3d:
   - fix irq enabled during reset"

* tag 'drm-fixes-2025-07-04' of https://gitlab.freedesktop.org/drm/kernel: (41 commits)
  drm/xe: Do not wedge device on killed exec queues
  drm/xe: Extend WA 14018094691 to BMG
  drm/v3d: Disable interrupts before resetting the GPU
  drm/gem: Acquire references on GEM handles for framebuffers
  drm/sched: Increment job count before swapping tail spsc queue
  drm/xe: Allow dropping kunit dependency as built-in
  drm/xe: Fix kconfig prompt
  drm/xe/bmg: Update Wa_22019338487
  drm/xe/bmg: Update Wa_14022085890
  drm/xe: Split xe_device_td_flush()
  drm/xe/xe_guc_pc: Lock once to update stashed frequencies
  drm/xe/guc_pc: Add _locked variant for min/max freq
  drm/xe: Make WA BB part of LRC BO
  drm/xe: Fix out-of-bounds field write in MI_STORE_DATA_IMM
  drm/i915/gsc: mei interrupt top half should be in irq disabled context
  drm/i915/gt: Fix timeline left held on VMA alloc error
  drm/vmwgfx: Fix guests running with TDX/SEV
  drm/amd/display: Don't allow OLED to go down to fully off
  drm/amd/display: Added case for when RR equals panel's max RR using freesync
  drm/amdkfd: add hqd_sdma_get_doorbell callbacks for gfx7/8
  ...
This commit is contained in:
Linus Torvalds 2025-07-04 09:48:36 -07:00
commit 42bb9b630c
47 changed files with 634 additions and 295 deletions

View File

@ -685,11 +685,13 @@ long dma_resv_wait_timeout(struct dma_resv *obj, enum dma_resv_usage usage,
dma_resv_iter_begin(&cursor, obj, usage);
dma_resv_for_each_fence_unlocked(&cursor, fence) {
ret = dma_fence_wait_timeout(fence, intr, ret);
if (ret <= 0) {
dma_resv_iter_end(&cursor);
return ret;
}
ret = dma_fence_wait_timeout(fence, intr, timeout);
if (ret <= 0)
break;
/* Even for zero timeout the return value is 1 */
if (timeout)
timeout = ret;
}
dma_resv_iter_end(&cursor);

View File

@ -561,6 +561,13 @@ static uint32_t read_vmid_from_vmfault_reg(struct amdgpu_device *adev)
return REG_GET_FIELD(status, VM_CONTEXT1_PROTECTION_FAULT_STATUS, VMID);
}
static uint32_t kgd_hqd_sdma_get_doorbell(struct amdgpu_device *adev,
int engine, int queue)
{
return 0;
}
const struct kfd2kgd_calls gfx_v7_kfd2kgd = {
.program_sh_mem_settings = kgd_program_sh_mem_settings,
.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
@ -578,4 +585,5 @@ const struct kfd2kgd_calls gfx_v7_kfd2kgd = {
.set_scratch_backing_va = set_scratch_backing_va,
.set_vm_context_page_table_base = set_vm_context_page_table_base,
.read_vmid_from_vmfault_reg = read_vmid_from_vmfault_reg,
.hqd_sdma_get_doorbell = kgd_hqd_sdma_get_doorbell,
};

View File

@ -582,6 +582,13 @@ static void set_vm_context_page_table_base(struct amdgpu_device *adev,
lower_32_bits(page_table_base));
}
static uint32_t kgd_hqd_sdma_get_doorbell(struct amdgpu_device *adev,
int engine, int queue)
{
return 0;
}
const struct kfd2kgd_calls gfx_v8_kfd2kgd = {
.program_sh_mem_settings = kgd_program_sh_mem_settings,
.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
@ -599,4 +606,5 @@ const struct kfd2kgd_calls gfx_v8_kfd2kgd = {
get_atc_vmid_pasid_mapping_info,
.set_scratch_backing_va = set_scratch_backing_va,
.set_vm_context_page_table_base = set_vm_context_page_table_base,
.hqd_sdma_get_doorbell = kgd_hqd_sdma_get_doorbell,
};

View File

@ -944,6 +944,7 @@ static void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr)
drm_sched_entity_fini(entity);
}
}
kref_put(&ctx->refcount, amdgpu_ctx_fini);
}
}

View File

@ -45,6 +45,7 @@
#include "amdgpu_ras.h"
MODULE_FIRMWARE("amdgpu/sdma_4_4_2.bin");
MODULE_FIRMWARE("amdgpu/sdma_4_4_4.bin");
MODULE_FIRMWARE("amdgpu/sdma_4_4_5.bin");
static const struct amdgpu_hwip_reg_entry sdma_reg_list_4_4_2[] = {

View File

@ -1543,8 +1543,13 @@ static int sdma_v5_0_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
{
struct amdgpu_device *adev = ring->adev;
u32 inst_id = ring->me;
int r;
return amdgpu_sdma_reset_engine(adev, inst_id);
amdgpu_amdkfd_suspend(adev, true);
r = amdgpu_sdma_reset_engine(adev, inst_id);
amdgpu_amdkfd_resume(adev, true);
return r;
}
static int sdma_v5_0_stop_queue(struct amdgpu_ring *ring)

View File

@ -1456,8 +1456,13 @@ static int sdma_v5_2_reset_queue(struct amdgpu_ring *ring, unsigned int vmid)
{
struct amdgpu_device *adev = ring->adev;
u32 inst_id = ring->me;
int r;
return amdgpu_sdma_reset_engine(adev, inst_id);
amdgpu_amdkfd_suspend(adev, true);
r = amdgpu_sdma_reset_engine(adev, inst_id);
amdgpu_amdkfd_resume(adev, true);
return r;
}
static int sdma_v5_2_stop_queue(struct amdgpu_ring *ring)

View File

@ -1171,13 +1171,12 @@ svm_range_split_head(struct svm_range *prange, uint64_t new_start,
}
static void
svm_range_add_child(struct svm_range *prange, struct mm_struct *mm,
struct svm_range *pchild, enum svm_work_list_ops op)
svm_range_add_child(struct svm_range *prange, struct svm_range *pchild, enum svm_work_list_ops op)
{
pr_debug("add child 0x%p [0x%lx 0x%lx] to prange 0x%p child list %d\n",
pchild, pchild->start, pchild->last, prange, op);
pchild->work_item.mm = mm;
pchild->work_item.mm = NULL;
pchild->work_item.op = op;
list_add_tail(&pchild->child_list, &prange->child_list);
}
@ -1278,7 +1277,7 @@ svm_range_get_pte_flags(struct kfd_node *node,
mapping_flags |= ext_coherent ? AMDGPU_VM_MTYPE_UC : AMDGPU_VM_MTYPE_NC;
/* system memory accessed by the dGPU */
} else {
if (gc_ip_version < IP_VERSION(9, 5, 0))
if (gc_ip_version < IP_VERSION(9, 5, 0) || ext_coherent)
mapping_flags |= AMDGPU_VM_MTYPE_UC;
else
mapping_flags |= AMDGPU_VM_MTYPE_NC;
@ -2394,15 +2393,17 @@ svm_range_add_list_work(struct svm_range_list *svms, struct svm_range *prange,
prange->work_item.op != SVM_OP_UNMAP_RANGE)
prange->work_item.op = op;
} else {
prange->work_item.op = op;
/* Pairs with mmput in deferred_list_work */
mmget(mm);
prange->work_item.mm = mm;
list_add_tail(&prange->deferred_list,
&prange->svms->deferred_range_list);
pr_debug("add prange 0x%p [0x%lx 0x%lx] to work list op %d\n",
prange, prange->start, prange->last, op);
/* Pairs with mmput in deferred_list_work.
* If process is exiting and mm is gone, don't update mmu notifier.
*/
if (mmget_not_zero(mm)) {
prange->work_item.mm = mm;
prange->work_item.op = op;
list_add_tail(&prange->deferred_list,
&prange->svms->deferred_range_list);
pr_debug("add prange 0x%p [0x%lx 0x%lx] to work list op %d\n",
prange, prange->start, prange->last, op);
}
}
spin_unlock(&svms->deferred_list_lock);
}
@ -2416,8 +2417,7 @@ void schedule_deferred_list_work(struct svm_range_list *svms)
}
static void
svm_range_unmap_split(struct mm_struct *mm, struct svm_range *parent,
struct svm_range *prange, unsigned long start,
svm_range_unmap_split(struct svm_range *parent, struct svm_range *prange, unsigned long start,
unsigned long last)
{
struct svm_range *head;
@ -2438,12 +2438,12 @@ svm_range_unmap_split(struct mm_struct *mm, struct svm_range *parent,
svm_range_split(tail, last + 1, tail->last, &head);
if (head != prange && tail != prange) {
svm_range_add_child(parent, mm, head, SVM_OP_UNMAP_RANGE);
svm_range_add_child(parent, mm, tail, SVM_OP_ADD_RANGE);
svm_range_add_child(parent, head, SVM_OP_UNMAP_RANGE);
svm_range_add_child(parent, tail, SVM_OP_ADD_RANGE);
} else if (tail != prange) {
svm_range_add_child(parent, mm, tail, SVM_OP_UNMAP_RANGE);
svm_range_add_child(parent, tail, SVM_OP_UNMAP_RANGE);
} else if (head != prange) {
svm_range_add_child(parent, mm, head, SVM_OP_UNMAP_RANGE);
svm_range_add_child(parent, head, SVM_OP_UNMAP_RANGE);
} else if (parent != prange) {
prange->work_item.op = SVM_OP_UNMAP_RANGE;
}
@ -2520,14 +2520,14 @@ svm_range_unmap_from_cpu(struct mm_struct *mm, struct svm_range *prange,
l = min(last, pchild->last);
if (l >= s)
svm_range_unmap_from_gpus(pchild, s, l, trigger);
svm_range_unmap_split(mm, prange, pchild, start, last);
svm_range_unmap_split(prange, pchild, start, last);
mutex_unlock(&pchild->lock);
}
s = max(start, prange->start);
l = min(last, prange->last);
if (l >= s)
svm_range_unmap_from_gpus(prange, s, l, trigger);
svm_range_unmap_split(mm, prange, prange, start, last);
svm_range_unmap_split(prange, prange, start, last);
if (unmap_parent)
svm_range_add_list_work(svms, prange, mm, SVM_OP_UNMAP_RANGE);
@ -2570,8 +2570,6 @@ svm_range_cpu_invalidate_pagetables(struct mmu_interval_notifier *mni,
if (range->event == MMU_NOTIFY_RELEASE)
return true;
if (!mmget_not_zero(mni->mm))
return true;
start = mni->interval_tree.start;
last = mni->interval_tree.last;
@ -2598,7 +2596,6 @@ svm_range_cpu_invalidate_pagetables(struct mmu_interval_notifier *mni,
}
svm_range_unlock(prange);
mmput(mni->mm);
return true;
}

View File

@ -3610,13 +3610,15 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
luminance_range = &conn_base->display_info.luminance_range;
if (luminance_range->max_luminance) {
caps->aux_min_input_signal = luminance_range->min_luminance;
if (luminance_range->max_luminance)
caps->aux_max_input_signal = luminance_range->max_luminance;
} else {
caps->aux_min_input_signal = 0;
else
caps->aux_max_input_signal = 512;
}
if (luminance_range->min_luminance)
caps->aux_min_input_signal = luminance_range->min_luminance;
else
caps->aux_min_input_signal = 1;
min_input_signal_override = drm_get_panel_min_brightness_quirk(aconnector->drm_edid);
if (min_input_signal_override >= 0)

View File

@ -974,6 +974,7 @@ struct dc_crtc_timing {
uint32_t pix_clk_100hz;
uint32_t min_refresh_in_uhz;
uint32_t max_refresh_in_uhz;
uint32_t vic;
uint32_t hdmi_vic;

View File

@ -155,6 +155,14 @@ unsigned int mod_freesync_calc_v_total_from_refresh(
v_total = div64_u64(div64_u64(((unsigned long long)(
frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)),
stream->timing.h_total), 1000000);
} else if (refresh_in_uhz >= stream->timing.max_refresh_in_uhz) {
/* When the target refresh rate is the maximum panel refresh rate
* round up the vtotal value to prevent off-by-one error causing
* v_total_min to be below the panel's lower bound
*/
v_total = div64_u64(div64_u64(((unsigned long long)(
frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)),
stream->timing.h_total) + (1000000 - 1), 1000000);
} else {
v_total = div64_u64(div64_u64(((unsigned long long)(
frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)),

View File

@ -64,10 +64,11 @@ struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent, str
adev->id = ret;
adev->name = "dp_hpd_bridge";
adev->dev.parent = parent;
adev->dev.of_node = of_node_get(parent->of_node);
adev->dev.release = drm_aux_hpd_bridge_release;
adev->dev.platform_data = of_node_get(np);
device_set_of_node_from_dev(&adev->dev, parent);
ret = auxiliary_device_init(adev);
if (ret) {
of_node_put(adev->dev.platform_data);

View File

@ -299,6 +299,7 @@ struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
panel_bridge->bridge.of_node = panel->dev->of_node;
panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;
panel_bridge->bridge.type = connector_type;
panel_bridge->bridge.pre_enable_prev_first = panel->prepare_prev_first;
drm_bridge_add(&panel_bridge->bridge);
@ -413,8 +414,6 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
return bridge;
}
bridge->pre_enable_prev_first = panel->prepare_prev_first;
*ptr = bridge;
devres_add(dev, ptr);
@ -456,8 +455,6 @@ struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
if (ret)
return ERR_PTR(ret);
bridge->pre_enable_prev_first = panel->prepare_prev_first;
return bridge;
}
EXPORT_SYMBOL(drmm_panel_bridge_add);

View File

@ -1095,7 +1095,7 @@ static void samsung_dsim_send_to_fifo(struct samsung_dsim *dsi,
bool first = !xfer->tx_done;
u32 reg;
dev_dbg(dev, "< xfer %pK: tx len %u, done %u, rx len %u, done %u\n",
dev_dbg(dev, "< xfer %p: tx len %u, done %u, rx len %u, done %u\n",
xfer, length, xfer->tx_done, xfer->rx_len, xfer->rx_done);
if (length > DSI_TX_FIFO_SIZE)
@ -1293,7 +1293,7 @@ static bool samsung_dsim_transfer_finish(struct samsung_dsim *dsi)
spin_unlock_irqrestore(&dsi->transfer_lock, flags);
dev_dbg(dsi->dev,
"> xfer %pK, tx_len %zu, tx_done %u, rx_len %u, rx_done %u\n",
"> xfer %p, tx_len %zu, tx_done %u, rx_len %u, rx_done %u\n",
xfer, xfer->packet.payload_length, xfer->tx_done, xfer->rx_len,
xfer->rx_done);

View File

@ -212,6 +212,35 @@ void drm_gem_private_object_fini(struct drm_gem_object *obj)
}
EXPORT_SYMBOL(drm_gem_private_object_fini);
static void drm_gem_object_handle_get(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
drm_WARN_ON(dev, !mutex_is_locked(&dev->object_name_lock));
if (obj->handle_count++ == 0)
drm_gem_object_get(obj);
}
/**
* drm_gem_object_handle_get_unlocked - acquire reference on user-space handles
* @obj: GEM object
*
* Acquires a reference on the GEM buffer object's handle. Required
* to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked()
* to release the reference.
*/
void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
guard(mutex)(&dev->object_name_lock);
drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */
drm_gem_object_handle_get(obj);
}
EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked);
/**
* drm_gem_object_handle_free - release resources bound to userspace handles
* @obj: GEM object to clean up.
@ -242,8 +271,14 @@ static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj)
}
}
static void
drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
/**
* drm_gem_object_handle_put_unlocked - releases reference on user-space handles
* @obj: GEM object
*
* Releases a reference on the GEM buffer object's handle. Possibly releases
* the GEM buffer object and associated dma-buf objects.
*/
void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
bool final = false;
@ -268,6 +303,7 @@ drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj)
if (final)
drm_gem_object_put(obj);
}
EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked);
/*
* Called at device or object close to release the file's
@ -389,8 +425,8 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
int ret;
WARN_ON(!mutex_is_locked(&dev->object_name_lock));
if (obj->handle_count++ == 0)
drm_gem_object_get(obj);
drm_gem_object_handle_get(obj);
/*
* Get the user-visible handle using idr. Preload and perform

View File

@ -99,7 +99,7 @@ void drm_gem_fb_destroy(struct drm_framebuffer *fb)
unsigned int i;
for (i = 0; i < fb->format->num_planes; i++)
drm_gem_object_put(fb->obj[i]);
drm_gem_object_handle_put_unlocked(fb->obj[i]);
drm_framebuffer_cleanup(fb);
kfree(fb);
@ -182,8 +182,10 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
if (!objs[i]) {
drm_dbg_kms(dev, "Failed to lookup GEM object\n");
ret = -ENOENT;
goto err_gem_object_put;
goto err_gem_object_handle_put_unlocked;
}
drm_gem_object_handle_get_unlocked(objs[i]);
drm_gem_object_put(objs[i]);
min_size = (height - 1) * mode_cmd->pitches[i]
+ drm_format_info_min_pitch(info, i, width)
@ -193,22 +195,22 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
drm_dbg_kms(dev,
"GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
objs[i]->size, min_size, i);
drm_gem_object_put(objs[i]);
drm_gem_object_handle_put_unlocked(objs[i]);
ret = -EINVAL;
goto err_gem_object_put;
goto err_gem_object_handle_put_unlocked;
}
}
ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
if (ret)
goto err_gem_object_put;
goto err_gem_object_handle_put_unlocked;
return 0;
err_gem_object_put:
err_gem_object_handle_put_unlocked:
while (i > 0) {
--i;
drm_gem_object_put(objs[i]);
drm_gem_object_handle_put_unlocked(objs[i]);
}
return ret;
}

View File

@ -161,6 +161,8 @@ void drm_sysfs_lease_event(struct drm_device *dev);
/* drm_gem.c */
int drm_gem_init(struct drm_device *dev);
void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj);
void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
int drm_gem_handle_create_tail(struct drm_file *file_priv,
struct drm_gem_object *obj,
u32 *handlep);

View File

@ -91,12 +91,13 @@ static const struct dev_pm_ops mipi_dsi_device_pm_ops = {
.restore = pm_generic_restore,
};
static const struct bus_type mipi_dsi_bus_type = {
const struct bus_type mipi_dsi_bus_type = {
.name = "mipi-dsi",
.match = mipi_dsi_device_match,
.uevent = mipi_dsi_uevent,
.pm = &mipi_dsi_device_pm_ops,
};
EXPORT_SYMBOL_GPL(mipi_dsi_bus_type);
/**
* of_find_mipi_dsi_device_by_node() - find the MIPI DSI device matching a

View File

@ -636,6 +636,10 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
if (!ctx->drm_dev)
goto out;
/* check if crtc and vblank have been initialized properly */
if (!drm_dev_has_vblank(ctx->drm_dev))
goto out;
if (!ctx->i80_if) {
drm_crtc_handle_vblank(&ctx->crtc->base);

View File

@ -187,6 +187,7 @@ struct fimd_context {
u32 i80ifcon;
bool i80_if;
bool suspended;
bool dp_clk_enabled;
wait_queue_head_t wait_vsync_queue;
atomic_t wait_vsync_event;
atomic_t win_updated;
@ -1047,7 +1048,18 @@ static void fimd_dp_clock_enable(struct exynos_drm_clk *clk, bool enable)
struct fimd_context *ctx = container_of(clk, struct fimd_context,
dp_clk);
u32 val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;
if (enable == ctx->dp_clk_enabled)
return;
if (enable)
pm_runtime_resume_and_get(ctx->dev);
ctx->dp_clk_enabled = enable;
writel(val, ctx->regs + DP_MIE_CLKCON);
if (!enable)
pm_runtime_put(ctx->dev);
}
static const struct exynos_drm_crtc_ops fimd_crtc_ops = {

View File

@ -174,7 +174,7 @@ static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev,
return ERR_PTR(ret);
}
DRM_DEV_DEBUG_KMS(dev->dev, "created file object = %pK\n", obj->filp);
DRM_DEV_DEBUG_KMS(dev->dev, "created file object = %p\n", obj->filp);
return exynos_gem;
}

View File

@ -271,7 +271,7 @@ static inline struct exynos_drm_ipp_task *
task->src.rect.h = task->dst.rect.h = UINT_MAX;
task->transform.rotation = DRM_MODE_ROTATE_0;
DRM_DEV_DEBUG_DRIVER(task->dev, "Allocated task %pK\n", task);
DRM_DEV_DEBUG_DRIVER(task->dev, "Allocated task %p\n", task);
return task;
}
@ -339,7 +339,7 @@ static int exynos_drm_ipp_task_set(struct exynos_drm_ipp_task *task,
}
DRM_DEV_DEBUG_DRIVER(task->dev,
"Got task %pK configuration from userspace\n",
"Got task %p configuration from userspace\n",
task);
return 0;
}
@ -394,7 +394,7 @@ static void exynos_drm_ipp_task_release_buf(struct exynos_drm_ipp_buffer *buf)
static void exynos_drm_ipp_task_free(struct exynos_drm_ipp *ipp,
struct exynos_drm_ipp_task *task)
{
DRM_DEV_DEBUG_DRIVER(task->dev, "Freeing task %pK\n", task);
DRM_DEV_DEBUG_DRIVER(task->dev, "Freeing task %p\n", task);
exynos_drm_ipp_task_release_buf(&task->src);
exynos_drm_ipp_task_release_buf(&task->dst);
@ -559,7 +559,7 @@ static int exynos_drm_ipp_check_format(struct exynos_drm_ipp_task *task,
DRM_EXYNOS_IPP_FORMAT_DESTINATION);
if (!fmt) {
DRM_DEV_DEBUG_DRIVER(task->dev,
"Task %pK: %s format not supported\n",
"Task %p: %s format not supported\n",
task, buf == src ? "src" : "dst");
return -EINVAL;
}
@ -609,7 +609,7 @@ static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
bool rotate = (rotation != DRM_MODE_ROTATE_0);
bool scale = false;
DRM_DEV_DEBUG_DRIVER(task->dev, "Checking task %pK\n", task);
DRM_DEV_DEBUG_DRIVER(task->dev, "Checking task %p\n", task);
if (src->rect.w == UINT_MAX)
src->rect.w = src->buf.width;
@ -625,7 +625,7 @@ static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
dst->rect.x + dst->rect.w > (dst->buf.width) ||
dst->rect.y + dst->rect.h > (dst->buf.height)) {
DRM_DEV_DEBUG_DRIVER(task->dev,
"Task %pK: defined area is outside provided buffers\n",
"Task %p: defined area is outside provided buffers\n",
task);
return -EINVAL;
}
@ -642,7 +642,7 @@ static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
(!(ipp->capabilities & DRM_EXYNOS_IPP_CAP_SCALE) && scale) ||
(!(ipp->capabilities & DRM_EXYNOS_IPP_CAP_CONVERT) &&
src->buf.fourcc != dst->buf.fourcc)) {
DRM_DEV_DEBUG_DRIVER(task->dev, "Task %pK: hw capabilities exceeded\n",
DRM_DEV_DEBUG_DRIVER(task->dev, "Task %p: hw capabilities exceeded\n",
task);
return -EINVAL;
}
@ -655,7 +655,7 @@ static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
if (ret)
return ret;
DRM_DEV_DEBUG_DRIVER(ipp->dev, "Task %pK: all checks done.\n",
DRM_DEV_DEBUG_DRIVER(ipp->dev, "Task %p: all checks done.\n",
task);
return ret;
@ -667,25 +667,25 @@ static int exynos_drm_ipp_task_setup_buffers(struct exynos_drm_ipp_task *task,
struct exynos_drm_ipp_buffer *src = &task->src, *dst = &task->dst;
int ret = 0;
DRM_DEV_DEBUG_DRIVER(task->dev, "Setting buffer for task %pK\n",
DRM_DEV_DEBUG_DRIVER(task->dev, "Setting buffer for task %p\n",
task);
ret = exynos_drm_ipp_task_setup_buffer(src, filp);
if (ret) {
DRM_DEV_DEBUG_DRIVER(task->dev,
"Task %pK: src buffer setup failed\n",
"Task %p: src buffer setup failed\n",
task);
return ret;
}
ret = exynos_drm_ipp_task_setup_buffer(dst, filp);
if (ret) {
DRM_DEV_DEBUG_DRIVER(task->dev,
"Task %pK: dst buffer setup failed\n",
"Task %p: dst buffer setup failed\n",
task);
return ret;
}
DRM_DEV_DEBUG_DRIVER(task->dev, "Task %pK: buffers prepared.\n",
DRM_DEV_DEBUG_DRIVER(task->dev, "Task %p: buffers prepared.\n",
task);
return ret;
@ -764,7 +764,7 @@ void exynos_drm_ipp_task_done(struct exynos_drm_ipp_task *task, int ret)
struct exynos_drm_ipp *ipp = task->ipp;
unsigned long flags;
DRM_DEV_DEBUG_DRIVER(task->dev, "ipp: %d, task %pK done: %d\n",
DRM_DEV_DEBUG_DRIVER(task->dev, "ipp: %d, task %p done: %d\n",
ipp->id, task, ret);
spin_lock_irqsave(&ipp->lock, flags);
@ -807,7 +807,7 @@ static void exynos_drm_ipp_next_task(struct exynos_drm_ipp *ipp)
spin_unlock_irqrestore(&ipp->lock, flags);
DRM_DEV_DEBUG_DRIVER(ipp->dev,
"ipp: %d, selected task %pK to run\n", ipp->id,
"ipp: %d, selected task %p to run\n", ipp->id,
task);
ret = ipp->funcs->commit(ipp, task);
@ -917,14 +917,14 @@ int exynos_drm_ipp_commit_ioctl(struct drm_device *dev, void *data,
*/
if (arg->flags & DRM_EXYNOS_IPP_FLAG_NONBLOCK) {
DRM_DEV_DEBUG_DRIVER(ipp->dev,
"ipp: %d, nonblocking processing task %pK\n",
"ipp: %d, nonblocking processing task %p\n",
ipp->id, task);
task->flags |= DRM_EXYNOS_IPP_TASK_ASYNC;
exynos_drm_ipp_schedule_task(task->ipp, task);
ret = 0;
} else {
DRM_DEV_DEBUG_DRIVER(ipp->dev, "ipp: %d, processing task %pK\n",
DRM_DEV_DEBUG_DRIVER(ipp->dev, "ipp: %d, processing task %p\n",
ipp->id, task);
exynos_drm_ipp_schedule_task(ipp, task);
ret = wait_event_interruptible(ipp->done_wq,

View File

@ -1589,8 +1589,8 @@ static void vlv_dsi_add_properties(struct intel_connector *connector)
static void vlv_dphy_param_init(struct intel_dsi *intel_dsi)
{
struct intel_display *display = to_intel_display(&intel_dsi->base);
struct intel_connector *connector = intel_dsi->attached_connector;
struct intel_display *display = to_intel_display(connector);
struct mipi_config *mipi_config = connector->panel.vbt.dsi.config;
u32 tlpx_ns, extra_byte_count, tlpx_ui;
u32 ui_num, ui_den;

View File

@ -284,7 +284,7 @@ static void gsc_irq_handler(struct intel_gt *gt, unsigned int intf_id)
if (gt->gsc.intf[intf_id].irq < 0)
return;
ret = generic_handle_irq(gt->gsc.intf[intf_id].irq);
ret = generic_handle_irq_safe(gt->gsc.intf[intf_id].irq);
if (ret)
gt_err_ratelimited(gt, "error handling GSC irq: %d\n", ret);
}

View File

@ -610,7 +610,6 @@ static int ring_context_alloc(struct intel_context *ce)
/* One ringbuffer to rule them all */
GEM_BUG_ON(!engine->legacy.ring);
ce->ring = engine->legacy.ring;
ce->timeline = intel_timeline_get(engine->legacy.timeline);
GEM_BUG_ON(ce->state);
if (engine->context_size) {
@ -623,6 +622,8 @@ static int ring_context_alloc(struct intel_context *ce)
ce->state = vma;
}
ce->timeline = intel_timeline_get(engine->legacy.timeline);
return 0;
}

View File

@ -73,8 +73,8 @@ static int igt_add_request(void *arg)
/* Basic preliminary test to create a request and let it loose! */
request = mock_request(rcs0(i915)->kernel_context, HZ / 10);
if (!request)
return -ENOMEM;
if (IS_ERR(request))
return PTR_ERR(request);
i915_request_add(request);
@ -91,8 +91,8 @@ static int igt_wait_request(void *arg)
/* Submit a request, then wait upon it */
request = mock_request(rcs0(i915)->kernel_context, T);
if (!request)
return -ENOMEM;
if (IS_ERR(request))
return PTR_ERR(request);
i915_request_get(request);
@ -160,8 +160,8 @@ static int igt_fence_wait(void *arg)
/* Submit a request, treat it as a fence and wait upon it */
request = mock_request(rcs0(i915)->kernel_context, T);
if (!request)
return -ENOMEM;
if (IS_ERR(request))
return PTR_ERR(request);
if (dma_fence_wait_timeout(&request->fence, false, T) != -ETIME) {
pr_err("fence wait success before submit (expected timeout)!\n");
@ -219,8 +219,8 @@ static int igt_request_rewind(void *arg)
GEM_BUG_ON(IS_ERR(ce));
request = mock_request(ce, 2 * HZ);
intel_context_put(ce);
if (!request) {
err = -ENOMEM;
if (IS_ERR(request)) {
err = PTR_ERR(request);
goto err_context_0;
}
@ -237,8 +237,8 @@ static int igt_request_rewind(void *arg)
GEM_BUG_ON(IS_ERR(ce));
vip = mock_request(ce, 0);
intel_context_put(ce);
if (!vip) {
err = -ENOMEM;
if (IS_ERR(vip)) {
err = PTR_ERR(vip);
goto err_context_1;
}

View File

@ -35,7 +35,7 @@ mock_request(struct intel_context *ce, unsigned long delay)
/* NB the i915->requests slab cache is enlarged to fit mock_request */
request = intel_context_create_request(ce);
if (IS_ERR(request))
return NULL;
return request;
request->mock.delay = delay;
return request;

View File

@ -26,6 +26,7 @@
#include <linux/i2c.h>
#include <linux/media-bus-format.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@ -136,6 +137,14 @@ struct panel_desc {
int connector_type;
};
struct panel_desc_dsi {
struct panel_desc desc;
unsigned long flags;
enum mipi_dsi_pixel_format format;
unsigned int lanes;
};
struct panel_simple {
struct drm_panel base;
@ -430,10 +439,7 @@ static const struct drm_panel_funcs panel_simple_funcs = {
.get_timings = panel_simple_get_timings,
};
static struct panel_desc panel_dpi;
static int panel_dpi_probe(struct device *dev,
struct panel_simple *panel)
static struct panel_desc *panel_dpi_probe(struct device *dev)
{
struct display_timing *timing;
const struct device_node *np;
@ -445,17 +451,17 @@ static int panel_dpi_probe(struct device *dev,
np = dev->of_node;
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL);
if (!timing)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
ret = of_get_display_timing(np, "panel-timing", timing);
if (ret < 0) {
dev_err(dev, "%pOF: no panel-timing node found for \"panel-dpi\" binding\n",
np);
return ret;
return ERR_PTR(ret);
}
desc->timings = timing;
@ -473,9 +479,7 @@ static int panel_dpi_probe(struct device *dev,
/* We do not know the connector for the DT node, so guess it */
desc->connector_type = DRM_MODE_CONNECTOR_DPI;
panel->desc = desc;
return 0;
return desc;
}
#define PANEL_SIMPLE_BOUNDS_CHECK(to_check, bounds, field) \
@ -570,8 +574,44 @@ static int panel_simple_override_nondefault_lvds_datamapping(struct device *dev,
return 0;
}
static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
static const struct panel_desc *panel_simple_get_desc(struct device *dev)
{
if (IS_ENABLED(CONFIG_DRM_MIPI_DSI) &&
dev_is_mipi_dsi(dev)) {
const struct panel_desc_dsi *dsi_desc;
dsi_desc = of_device_get_match_data(dev);
if (!dsi_desc)
return ERR_PTR(-ENODEV);
return &dsi_desc->desc;
}
if (dev_is_platform(dev)) {
const struct panel_desc *desc;
desc = of_device_get_match_data(dev);
if (!desc) {
/*
* panel-dpi probes without a descriptor and
* panel_dpi_probe() will initialize one for us
* based on the device tree.
*/
if (of_device_is_compatible(dev->of_node, "panel-dpi"))
return panel_dpi_probe(dev);
else
return ERR_PTR(-ENODEV);
}
return desc;
}
return ERR_PTR(-ENODEV);
}
static struct panel_simple *panel_simple_probe(struct device *dev)
{
const struct panel_desc *desc;
struct panel_simple *panel;
struct display_timing dt;
struct device_node *ddc;
@ -579,27 +619,31 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
u32 bus_flags;
int err;
desc = panel_simple_get_desc(dev);
if (IS_ERR(desc))
return ERR_CAST(desc);
panel = devm_drm_panel_alloc(dev, struct panel_simple, base,
&panel_simple_funcs, desc->connector_type);
if (IS_ERR(panel))
return PTR_ERR(panel);
return ERR_CAST(panel);
panel->desc = desc;
panel->supply = devm_regulator_get(dev, "power");
if (IS_ERR(panel->supply))
return PTR_ERR(panel->supply);
return ERR_CAST(panel->supply);
panel->enable_gpio = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR(panel->enable_gpio))
return dev_err_probe(dev, PTR_ERR(panel->enable_gpio),
"failed to request GPIO\n");
return dev_err_cast_probe(dev, panel->enable_gpio,
"failed to request GPIO\n");
err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation);
if (err) {
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err);
return err;
return ERR_PTR(err);
}
ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
@ -608,19 +652,12 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
of_node_put(ddc);
if (!panel->ddc)
return -EPROBE_DEFER;
return ERR_PTR(-EPROBE_DEFER);
}
if (desc == &panel_dpi) {
/* Handle the generic panel-dpi binding */
err = panel_dpi_probe(dev, panel);
if (err)
goto free_ddc;
desc = panel->desc;
} else {
if (!of_get_display_timing(dev->of_node, "panel-timing", &dt))
panel_simple_parse_panel_timing_node(dev, panel, &dt);
}
if (!of_device_is_compatible(dev->of_node, "panel-dpi") &&
!of_get_display_timing(dev->of_node, "panel-timing", &dt))
panel_simple_parse_panel_timing_node(dev, panel, &dt);
if (desc->connector_type == DRM_MODE_CONNECTOR_LVDS) {
/* Optional data-mapping property for overriding bus format */
@ -703,7 +740,7 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
drm_panel_add(&panel->base);
return 0;
return panel;
disable_pm_runtime:
pm_runtime_dont_use_autosuspend(dev);
@ -712,7 +749,7 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
if (panel->ddc)
put_device(&panel->ddc->dev);
return err;
return ERR_PTR(err);
}
static void panel_simple_shutdown(struct device *dev)
@ -5367,7 +5404,12 @@ static const struct of_device_id platform_of_match[] = {
}, {
/* Must be the last entry */
.compatible = "panel-dpi",
.data = &panel_dpi,
/*
* Explicitly NULL, the panel_desc structure will be
* allocated by panel_dpi_probe().
*/
.data = NULL,
}, {
/* sentinel */
}
@ -5376,13 +5418,13 @@ MODULE_DEVICE_TABLE(of, platform_of_match);
static int panel_simple_platform_probe(struct platform_device *pdev)
{
const struct panel_desc *desc;
struct panel_simple *panel;
desc = of_device_get_match_data(&pdev->dev);
if (!desc)
return -ENODEV;
panel = panel_simple_probe(&pdev->dev);
if (IS_ERR(panel))
return PTR_ERR(panel);
return panel_simple_probe(&pdev->dev, desc);
return 0;
}
static void panel_simple_platform_remove(struct platform_device *pdev)
@ -5412,14 +5454,6 @@ static struct platform_driver panel_simple_platform_driver = {
.shutdown = panel_simple_platform_shutdown,
};
struct panel_desc_dsi {
struct panel_desc desc;
unsigned long flags;
enum mipi_dsi_pixel_format format;
unsigned int lanes;
};
static const struct drm_display_mode auo_b080uan01_mode = {
.clock = 154500,
.hdisplay = 1200,
@ -5653,16 +5687,14 @@ MODULE_DEVICE_TABLE(of, dsi_of_match);
static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
{
const struct panel_desc_dsi *desc;
struct panel_simple *panel;
int err;
desc = of_device_get_match_data(&dsi->dev);
if (!desc)
return -ENODEV;
err = panel_simple_probe(&dsi->dev, &desc->desc);
if (err < 0)
return err;
panel = panel_simple_probe(&dsi->dev);
if (IS_ERR(panel))
return PTR_ERR(panel);
desc = container_of(panel->desc, struct panel_desc_dsi, desc);
dsi->mode_flags = desc->flags;
dsi->format = desc->format;
dsi->lanes = desc->lanes;

View File

@ -362,14 +362,19 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
if (!__screen_info_vbe_mode_nonvga(si)) {
vesa->cmap_write = vesadrm_vga_cmap_write;
#if defined(CONFIG_X86_32)
} else {
#if defined(CONFIG_X86_32)
phys_addr_t pmi_base = __screen_info_vesapm_info_base(si);
const u16 *pmi_addr = phys_to_virt(pmi_base);
vesa->pmi.PrimaryPalette = (u8 *)pmi_addr + pmi_addr[2];
vesa->cmap_write = vesadrm_pmi_cmap_write;
if (pmi_base) {
const u16 *pmi_addr = phys_to_virt(pmi_base);
vesa->pmi.PrimaryPalette = (u8 *)pmi_addr + pmi_addr[2];
vesa->cmap_write = vesadrm_pmi_cmap_write;
} else
#endif
if (format->is_color_indexed)
drm_warn(dev, "hardware palette is unchangeable, colors may be incorrect\n");
}
#ifdef CONFIG_X86

View File

@ -254,6 +254,13 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
ret = dma_resv_trylock(&fbo->base.base._resv);
WARN_ON(!ret);
ret = dma_resv_reserve_fences(&fbo->base.base._resv, 1);
if (ret) {
dma_resv_unlock(&fbo->base.base._resv);
kfree(fbo);
return ret;
}
if (fbo->base.resource) {
ttm_resource_set_bo(fbo->base.resource, &fbo->base);
bo->resource = NULL;
@ -262,12 +269,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
fbo->base.bulk_move = NULL;
}
ret = dma_resv_reserve_fences(&fbo->base.base._resv, 1);
if (ret) {
kfree(fbo);
return ret;
}
ttm_bo_get(bo);
fbo->bo = bo;

View File

@ -101,6 +101,12 @@ enum v3d_gen {
V3D_GEN_71 = 71,
};
enum v3d_irq {
V3D_CORE_IRQ,
V3D_HUB_IRQ,
V3D_MAX_IRQS,
};
struct v3d_dev {
struct drm_device drm;
@ -112,6 +118,8 @@ struct v3d_dev {
bool single_irq_line;
int irq[V3D_MAX_IRQS];
struct v3d_perfmon_info perfmon_info;
void __iomem *hub_regs;

View File

@ -134,6 +134,8 @@ v3d_reset(struct v3d_dev *v3d)
if (false)
v3d_idle_axi(v3d, 0);
v3d_irq_disable(v3d);
v3d_idle_gca(v3d);
v3d_reset_sms(v3d);
v3d_reset_v3d(v3d);

View File

@ -260,7 +260,7 @@ v3d_hub_irq(int irq, void *arg)
int
v3d_irq_init(struct v3d_dev *v3d)
{
int irq1, ret, core;
int irq, ret, core;
INIT_WORK(&v3d->overflow_mem_work, v3d_overflow_mem_work);
@ -271,17 +271,24 @@ v3d_irq_init(struct v3d_dev *v3d)
V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS(v3d->ver));
V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS(v3d->ver));
irq1 = platform_get_irq_optional(v3d_to_pdev(v3d), 1);
if (irq1 == -EPROBE_DEFER)
return irq1;
if (irq1 > 0) {
ret = devm_request_irq(v3d->drm.dev, irq1,
irq = platform_get_irq_optional(v3d_to_pdev(v3d), 1);
if (irq == -EPROBE_DEFER)
return irq;
if (irq > 0) {
v3d->irq[V3D_CORE_IRQ] = irq;
ret = devm_request_irq(v3d->drm.dev, v3d->irq[V3D_CORE_IRQ],
v3d_irq, IRQF_SHARED,
"v3d_core0", v3d);
if (ret)
goto fail;
ret = devm_request_irq(v3d->drm.dev,
platform_get_irq(v3d_to_pdev(v3d), 0),
irq = platform_get_irq(v3d_to_pdev(v3d), 0);
if (irq < 0)
return irq;
v3d->irq[V3D_HUB_IRQ] = irq;
ret = devm_request_irq(v3d->drm.dev, v3d->irq[V3D_HUB_IRQ],
v3d_hub_irq, IRQF_SHARED,
"v3d_hub", v3d);
if (ret)
@ -289,8 +296,12 @@ v3d_irq_init(struct v3d_dev *v3d)
} else {
v3d->single_irq_line = true;
ret = devm_request_irq(v3d->drm.dev,
platform_get_irq(v3d_to_pdev(v3d), 0),
irq = platform_get_irq(v3d_to_pdev(v3d), 0);
if (irq < 0)
return irq;
v3d->irq[V3D_CORE_IRQ] = irq;
ret = devm_request_irq(v3d->drm.dev, v3d->irq[V3D_CORE_IRQ],
v3d_irq, IRQF_SHARED,
"v3d", v3d);
if (ret)
@ -331,6 +342,12 @@ v3d_irq_disable(struct v3d_dev *v3d)
V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_SET, ~0);
V3D_WRITE(V3D_HUB_INT_MSK_SET, ~0);
/* Finish any interrupt handler still in flight. */
for (int i = 0; i < V3D_MAX_IRQS; i++) {
if (v3d->irq[i])
synchronize_irq(v3d->irq[i]);
}
/* Clear any pending interrupts we might have left. */
for (core = 0; core < v3d->cores; core++)
V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS(v3d->ver));

View File

@ -749,7 +749,7 @@ static int vmw_setup_pci_resources(struct vmw_private *dev,
dev->fifo_mem = devm_memremap(dev->drm.dev,
fifo_start,
fifo_size,
MEMREMAP_WB);
MEMREMAP_WB | MEMREMAP_DEC);
if (IS_ERR(dev->fifo_mem)) {
drm_err(&dev->drm,

View File

@ -1,7 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
config DRM_XE
tristate "Intel Xe Graphics"
depends on DRM && PCI && (m || (y && KUNIT=y))
tristate "Intel Xe2 Graphics"
depends on DRM && PCI
depends on KUNIT || !KUNIT
depends on INTEL_VSEC || !INTEL_VSEC
depends on X86_PLATFORM_DEVICES || !(X86 && ACPI)
select INTERVAL_TREE
@ -46,7 +47,8 @@ config DRM_XE
select AUXILIARY_BUS
select HMM_MIRROR
help
Experimental driver for Intel Xe series GPUs
Driver for Intel Xe2 series GPUs and later. Experimental support
for Xe series is also available.
If "M" is selected, the module will be called xe.

View File

@ -40,6 +40,7 @@
#include "xe_gt_printk.h"
#include "xe_gt_sriov_vf.h"
#include "xe_guc.h"
#include "xe_guc_pc.h"
#include "xe_hw_engine_group.h"
#include "xe_hwmon.h"
#include "xe_irq.h"
@ -986,38 +987,15 @@ void xe_device_wmb(struct xe_device *xe)
xe_mmio_write32(xe_root_tile_mmio(xe), VF_CAP_REG, 0);
}
/**
* xe_device_td_flush() - Flush transient L3 cache entries
* @xe: The device
*
* Display engine has direct access to memory and is never coherent with L3/L4
* caches (or CPU caches), however KMD is responsible for specifically flushing
* transient L3 GPU cache entries prior to the flip sequence to ensure scanout
* can happen from such a surface without seeing corruption.
*
* Display surfaces can be tagged as transient by mapping it using one of the
* various L3:XD PAT index modes on Xe2.
*
* Note: On non-discrete xe2 platforms, like LNL, the entire L3 cache is flushed
* at the end of each submission via PIPE_CONTROL for compute/render, since SA
* Media is not coherent with L3 and we want to support render-vs-media
* usescases. For other engines like copy/blt the HW internally forces uncached
* behaviour, hence why we can skip the TDF on such platforms.
/*
* Issue a TRANSIENT_FLUSH_REQUEST and wait for completion on each gt.
*/
void xe_device_td_flush(struct xe_device *xe)
static void tdf_request_sync(struct xe_device *xe)
{
struct xe_gt *gt;
unsigned int fw_ref;
struct xe_gt *gt;
u8 id;
if (!IS_DGFX(xe) || GRAPHICS_VER(xe) < 20)
return;
if (XE_WA(xe_root_mmio_gt(xe), 16023588340)) {
xe_device_l2_flush(xe);
return;
}
for_each_gt(gt, xe, id) {
if (xe_gt_is_media_type(gt))
continue;
@ -1027,6 +1005,7 @@ void xe_device_td_flush(struct xe_device *xe)
return;
xe_mmio_write32(&gt->mmio, XE2_TDF_CTRL, TRANSIENT_FLUSH_REQUEST);
/*
* FIXME: We can likely do better here with our choice of
* timeout. Currently we just assume the worst case, i.e. 150us,
@ -1057,15 +1036,52 @@ void xe_device_l2_flush(struct xe_device *xe)
return;
spin_lock(&gt->global_invl_lock);
xe_mmio_write32(&gt->mmio, XE2_GLOBAL_INVAL, 0x1);
xe_mmio_write32(&gt->mmio, XE2_GLOBAL_INVAL, 0x1);
if (xe_mmio_wait32(&gt->mmio, XE2_GLOBAL_INVAL, 0x1, 0x0, 500, NULL, true))
xe_gt_err_once(gt, "Global invalidation timeout\n");
spin_unlock(&gt->global_invl_lock);
xe_force_wake_put(gt_to_fw(gt), fw_ref);
}
/**
* xe_device_td_flush() - Flush transient L3 cache entries
* @xe: The device
*
* Display engine has direct access to memory and is never coherent with L3/L4
* caches (or CPU caches), however KMD is responsible for specifically flushing
* transient L3 GPU cache entries prior to the flip sequence to ensure scanout
* can happen from such a surface without seeing corruption.
*
* Display surfaces can be tagged as transient by mapping it using one of the
* various L3:XD PAT index modes on Xe2.
*
* Note: On non-discrete xe2 platforms, like LNL, the entire L3 cache is flushed
* at the end of each submission via PIPE_CONTROL for compute/render, since SA
* Media is not coherent with L3 and we want to support render-vs-media
* usescases. For other engines like copy/blt the HW internally forces uncached
* behaviour, hence why we can skip the TDF on such platforms.
*/
void xe_device_td_flush(struct xe_device *xe)
{
struct xe_gt *root_gt;
if (!IS_DGFX(xe) || GRAPHICS_VER(xe) < 20)
return;
root_gt = xe_root_mmio_gt(xe);
if (XE_WA(root_gt, 16023588340)) {
/* A transient flush is not sufficient: flush the L2 */
xe_device_l2_flush(xe);
} else {
xe_guc_pc_apply_flush_freq_limit(&root_gt->uc.guc.pc);
tdf_request_sync(xe);
xe_guc_pc_remove_flush_freq_limit(&root_gt->uc.guc.pc);
}
}
u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size)
{
return xe_device_has_flat_ccs(xe) ?

View File

@ -9,7 +9,7 @@
#include <drm/drm_drv.h>
#define DRIVER_NAME "xe"
#define DRIVER_DESC "Intel Xe Graphics"
#define DRIVER_DESC "Intel Xe2 Graphics"
/* Interface history:
*

View File

@ -5,8 +5,11 @@
#include "xe_guc_pc.h"
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/ktime.h>
#include <linux/wait_bit.h>
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
@ -51,9 +54,12 @@
#define LNL_MERT_FREQ_CAP 800
#define BMG_MERT_FREQ_CAP 2133
#define BMG_MIN_FREQ 1200
#define BMG_MERT_FLUSH_FREQ_CAP 2600
#define SLPC_RESET_TIMEOUT_MS 5 /* roughly 5ms, but no need for precision */
#define SLPC_RESET_EXTENDED_TIMEOUT_MS 1000 /* To be used only at pc_start */
#define SLPC_ACT_FREQ_TIMEOUT_MS 100
/**
* DOC: GuC Power Conservation (PC)
@ -141,6 +147,36 @@ static int wait_for_pc_state(struct xe_guc_pc *pc,
return -ETIMEDOUT;
}
static int wait_for_flush_complete(struct xe_guc_pc *pc)
{
const unsigned long timeout = msecs_to_jiffies(30);
if (!wait_var_event_timeout(&pc->flush_freq_limit,
!atomic_read(&pc->flush_freq_limit),
timeout))
return -ETIMEDOUT;
return 0;
}
static int wait_for_act_freq_limit(struct xe_guc_pc *pc, u32 freq)
{
int timeout_us = SLPC_ACT_FREQ_TIMEOUT_MS * USEC_PER_MSEC;
int slept, wait = 10;
for (slept = 0; slept < timeout_us;) {
if (xe_guc_pc_get_act_freq(pc) <= freq)
return 0;
usleep_range(wait, wait << 1);
slept += wait;
wait <<= 1;
if (slept + wait > timeout_us)
wait = timeout_us - slept;
}
return -ETIMEDOUT;
}
static int pc_action_reset(struct xe_guc_pc *pc)
{
struct xe_guc_ct *ct = pc_to_ct(pc);
@ -553,6 +589,25 @@ u32 xe_guc_pc_get_rpn_freq(struct xe_guc_pc *pc)
return pc->rpn_freq;
}
static int xe_guc_pc_get_min_freq_locked(struct xe_guc_pc *pc, u32 *freq)
{
int ret;
lockdep_assert_held(&pc->freq_lock);
/* Might be in the middle of a gt reset */
if (!pc->freq_ready)
return -EAGAIN;
ret = pc_action_query_task_state(pc);
if (ret)
return ret;
*freq = pc_get_min_freq(pc);
return 0;
}
/**
* xe_guc_pc_get_min_freq - Get the min operational frequency
* @pc: The GuC PC
@ -562,27 +617,29 @@ u32 xe_guc_pc_get_rpn_freq(struct xe_guc_pc *pc)
* -EAGAIN if GuC PC not ready (likely in middle of a reset).
*/
int xe_guc_pc_get_min_freq(struct xe_guc_pc *pc, u32 *freq)
{
guard(mutex)(&pc->freq_lock);
return xe_guc_pc_get_min_freq_locked(pc, freq);
}
static int xe_guc_pc_set_min_freq_locked(struct xe_guc_pc *pc, u32 freq)
{
int ret;
xe_device_assert_mem_access(pc_to_xe(pc));
lockdep_assert_held(&pc->freq_lock);
mutex_lock(&pc->freq_lock);
if (!pc->freq_ready) {
/* Might be in the middle of a gt reset */
ret = -EAGAIN;
goto out;
}
/* Might be in the middle of a gt reset */
if (!pc->freq_ready)
return -EAGAIN;
ret = pc_action_query_task_state(pc);
ret = pc_set_min_freq(pc, freq);
if (ret)
goto out;
return ret;
*freq = pc_get_min_freq(pc);
pc->user_requested_min = freq;
out:
mutex_unlock(&pc->freq_lock);
return ret;
return 0;
}
/**
@ -595,25 +652,29 @@ int xe_guc_pc_get_min_freq(struct xe_guc_pc *pc, u32 *freq)
* -EINVAL if value out of bounds.
*/
int xe_guc_pc_set_min_freq(struct xe_guc_pc *pc, u32 freq)
{
guard(mutex)(&pc->freq_lock);
return xe_guc_pc_set_min_freq_locked(pc, freq);
}
static int xe_guc_pc_get_max_freq_locked(struct xe_guc_pc *pc, u32 *freq)
{
int ret;
mutex_lock(&pc->freq_lock);
if (!pc->freq_ready) {
/* Might be in the middle of a gt reset */
ret = -EAGAIN;
goto out;
}
lockdep_assert_held(&pc->freq_lock);
ret = pc_set_min_freq(pc, freq);
/* Might be in the middle of a gt reset */
if (!pc->freq_ready)
return -EAGAIN;
ret = pc_action_query_task_state(pc);
if (ret)
goto out;
return ret;
pc->user_requested_min = freq;
*freq = pc_get_max_freq(pc);
out:
mutex_unlock(&pc->freq_lock);
return ret;
return 0;
}
/**
@ -625,25 +686,29 @@ int xe_guc_pc_set_min_freq(struct xe_guc_pc *pc, u32 freq)
* -EAGAIN if GuC PC not ready (likely in middle of a reset).
*/
int xe_guc_pc_get_max_freq(struct xe_guc_pc *pc, u32 *freq)
{
guard(mutex)(&pc->freq_lock);
return xe_guc_pc_get_max_freq_locked(pc, freq);
}
static int xe_guc_pc_set_max_freq_locked(struct xe_guc_pc *pc, u32 freq)
{
int ret;
mutex_lock(&pc->freq_lock);
if (!pc->freq_ready) {
/* Might be in the middle of a gt reset */
ret = -EAGAIN;
goto out;
}
lockdep_assert_held(&pc->freq_lock);
ret = pc_action_query_task_state(pc);
/* Might be in the middle of a gt reset */
if (!pc->freq_ready)
return -EAGAIN;
ret = pc_set_max_freq(pc, freq);
if (ret)
goto out;
return ret;
*freq = pc_get_max_freq(pc);
pc->user_requested_max = freq;
out:
mutex_unlock(&pc->freq_lock);
return ret;
return 0;
}
/**
@ -657,24 +722,14 @@ int xe_guc_pc_get_max_freq(struct xe_guc_pc *pc, u32 *freq)
*/
int xe_guc_pc_set_max_freq(struct xe_guc_pc *pc, u32 freq)
{
int ret;
mutex_lock(&pc->freq_lock);
if (!pc->freq_ready) {
/* Might be in the middle of a gt reset */
ret = -EAGAIN;
goto out;
if (XE_WA(pc_to_gt(pc), 22019338487)) {
if (wait_for_flush_complete(pc) != 0)
return -EAGAIN;
}
ret = pc_set_max_freq(pc, freq);
if (ret)
goto out;
guard(mutex)(&pc->freq_lock);
pc->user_requested_max = freq;
out:
mutex_unlock(&pc->freq_lock);
return ret;
return xe_guc_pc_set_max_freq_locked(pc, freq);
}
/**
@ -817,6 +872,7 @@ void xe_guc_pc_init_early(struct xe_guc_pc *pc)
static int pc_adjust_freq_bounds(struct xe_guc_pc *pc)
{
struct xe_tile *tile = gt_to_tile(pc_to_gt(pc));
int ret;
lockdep_assert_held(&pc->freq_lock);
@ -843,6 +899,9 @@ static int pc_adjust_freq_bounds(struct xe_guc_pc *pc)
if (pc_get_min_freq(pc) > pc->rp0_freq)
ret = pc_set_min_freq(pc, pc->rp0_freq);
if (XE_WA(tile->primary_gt, 14022085890))
ret = pc_set_min_freq(pc, max(BMG_MIN_FREQ, pc_get_min_freq(pc)));
out:
return ret;
}
@ -868,29 +927,116 @@ static int pc_adjust_requested_freq(struct xe_guc_pc *pc)
return ret;
}
static int pc_set_mert_freq_cap(struct xe_guc_pc *pc)
static bool needs_flush_freq_limit(struct xe_guc_pc *pc)
{
struct xe_gt *gt = pc_to_gt(pc);
return XE_WA(gt, 22019338487) &&
pc->rp0_freq > BMG_MERT_FLUSH_FREQ_CAP;
}
/**
* xe_guc_pc_apply_flush_freq_limit() - Limit max GT freq during L2 flush
* @pc: the xe_guc_pc object
*
* As per the WA, reduce max GT frequency during L2 cache flush
*/
void xe_guc_pc_apply_flush_freq_limit(struct xe_guc_pc *pc)
{
struct xe_gt *gt = pc_to_gt(pc);
u32 max_freq;
int ret;
if (!needs_flush_freq_limit(pc))
return;
guard(mutex)(&pc->freq_lock);
ret = xe_guc_pc_get_max_freq_locked(pc, &max_freq);
if (!ret && max_freq > BMG_MERT_FLUSH_FREQ_CAP) {
ret = pc_set_max_freq(pc, BMG_MERT_FLUSH_FREQ_CAP);
if (ret) {
xe_gt_err_once(gt, "Failed to cap max freq on flush to %u, %pe\n",
BMG_MERT_FLUSH_FREQ_CAP, ERR_PTR(ret));
return;
}
atomic_set(&pc->flush_freq_limit, 1);
/*
* If user has previously changed max freq, stash that value to
* restore later, otherwise use the current max. New user
* requests wait on flush.
*/
if (pc->user_requested_max != 0)
pc->stashed_max_freq = pc->user_requested_max;
else
pc->stashed_max_freq = max_freq;
}
/*
* Wait for actual freq to go below the flush cap: even if the previous
* max was below cap, the current one might still be above it
*/
ret = wait_for_act_freq_limit(pc, BMG_MERT_FLUSH_FREQ_CAP);
if (ret)
xe_gt_err_once(gt, "Actual freq did not reduce to %u, %pe\n",
BMG_MERT_FLUSH_FREQ_CAP, ERR_PTR(ret));
}
/**
* xe_guc_pc_remove_flush_freq_limit() - Remove max GT freq limit after L2 flush completes.
* @pc: the xe_guc_pc object
*
* Retrieve the previous GT max frequency value.
*/
void xe_guc_pc_remove_flush_freq_limit(struct xe_guc_pc *pc)
{
struct xe_gt *gt = pc_to_gt(pc);
int ret = 0;
if (XE_WA(pc_to_gt(pc), 22019338487)) {
/*
* Get updated min/max and stash them.
*/
ret = xe_guc_pc_get_min_freq(pc, &pc->stashed_min_freq);
if (!ret)
ret = xe_guc_pc_get_max_freq(pc, &pc->stashed_max_freq);
if (ret)
return ret;
if (!needs_flush_freq_limit(pc))
return;
/*
* Ensure min and max are bound by MERT_FREQ_CAP until driver loads.
*/
mutex_lock(&pc->freq_lock);
ret = pc_set_min_freq(pc, min(pc->rpe_freq, pc_max_freq_cap(pc)));
if (!ret)
ret = pc_set_max_freq(pc, min(pc->rp0_freq, pc_max_freq_cap(pc)));
mutex_unlock(&pc->freq_lock);
}
if (!atomic_read(&pc->flush_freq_limit))
return;
mutex_lock(&pc->freq_lock);
ret = pc_set_max_freq(&gt->uc.guc.pc, pc->stashed_max_freq);
if (ret)
xe_gt_err_once(gt, "Failed to restore max freq %u:%d",
pc->stashed_max_freq, ret);
atomic_set(&pc->flush_freq_limit, 0);
mutex_unlock(&pc->freq_lock);
wake_up_var(&pc->flush_freq_limit);
}
static int pc_set_mert_freq_cap(struct xe_guc_pc *pc)
{
int ret;
if (!XE_WA(pc_to_gt(pc), 22019338487))
return 0;
guard(mutex)(&pc->freq_lock);
/*
* Get updated min/max and stash them.
*/
ret = xe_guc_pc_get_min_freq_locked(pc, &pc->stashed_min_freq);
if (!ret)
ret = xe_guc_pc_get_max_freq_locked(pc, &pc->stashed_max_freq);
if (ret)
return ret;
/*
* Ensure min and max are bound by MERT_FREQ_CAP until driver loads.
*/
ret = pc_set_min_freq(pc, min(pc->rpe_freq, pc_max_freq_cap(pc)));
if (!ret)
ret = pc_set_max_freq(pc, min(pc->rp0_freq, pc_max_freq_cap(pc)));
return ret;
}

View File

@ -38,5 +38,7 @@ u64 xe_guc_pc_mc6_residency(struct xe_guc_pc *pc);
void xe_guc_pc_init_early(struct xe_guc_pc *pc);
int xe_guc_pc_restore_stashed_freq(struct xe_guc_pc *pc);
void xe_guc_pc_raise_unslice(struct xe_guc_pc *pc);
void xe_guc_pc_apply_flush_freq_limit(struct xe_guc_pc *pc);
void xe_guc_pc_remove_flush_freq_limit(struct xe_guc_pc *pc);
#endif /* _XE_GUC_PC_H_ */

View File

@ -15,6 +15,8 @@
struct xe_guc_pc {
/** @bo: GGTT buffer object that is shared with GuC PC */
struct xe_bo *bo;
/** @flush_freq_limit: 1 when max freq changes are limited by driver */
atomic_t flush_freq_limit;
/** @rp0_freq: HW RP0 frequency - The Maximum one */
u32 rp0_freq;
/** @rpa_freq: HW RPa frequency - The Achievable one */

View File

@ -891,12 +891,13 @@ static void xe_guc_exec_queue_lr_cleanup(struct work_struct *w)
struct xe_exec_queue *q = ge->q;
struct xe_guc *guc = exec_queue_to_guc(q);
struct xe_gpu_scheduler *sched = &ge->sched;
bool wedged;
bool wedged = false;
xe_gt_assert(guc_to_gt(guc), xe_exec_queue_is_lr(q));
trace_xe_exec_queue_lr_cleanup(q);
wedged = guc_submit_hint_wedged(exec_queue_to_guc(q));
if (!exec_queue_killed(q))
wedged = guc_submit_hint_wedged(exec_queue_to_guc(q));
/* Kill the run_job / process_msg entry points */
xe_sched_submission_stop(sched);
@ -1070,7 +1071,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
int err = -ETIME;
pid_t pid = -1;
int i = 0;
bool wedged, skip_timeout_check;
bool wedged = false, skip_timeout_check;
/*
* TDR has fired before free job worker. Common if exec queue
@ -1116,7 +1117,8 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
* doesn't work for SRIOV. For now assuming timeouts in wedged mode are
* genuine timeouts.
*/
wedged = guc_submit_hint_wedged(exec_queue_to_guc(q));
if (!exec_queue_killed(q))
wedged = guc_submit_hint_wedged(exec_queue_to_guc(q));
/* Engine state now stable, disable scheduling to check timestamp */
if (!wedged && exec_queue_registered(q)) {

View File

@ -40,6 +40,7 @@
#define LRC_PPHWSP_SIZE SZ_4K
#define LRC_INDIRECT_RING_STATE_SIZE SZ_4K
#define LRC_WA_BB_SIZE SZ_4K
static struct xe_device *
lrc_to_xe(struct xe_lrc *lrc)
@ -910,7 +911,11 @@ static void xe_lrc_finish(struct xe_lrc *lrc)
{
xe_hw_fence_ctx_finish(&lrc->fence_ctx);
xe_bo_unpin_map_no_vm(lrc->bo);
xe_bo_unpin_map_no_vm(lrc->bb_per_ctx_bo);
}
static size_t wa_bb_offset(struct xe_lrc *lrc)
{
return lrc->bo->size - LRC_WA_BB_SIZE;
}
/*
@ -943,15 +948,16 @@ static void xe_lrc_finish(struct xe_lrc *lrc)
#define CONTEXT_ACTIVE 1ULL
static int xe_lrc_setup_utilization(struct xe_lrc *lrc)
{
const size_t max_size = LRC_WA_BB_SIZE;
u32 *cmd, *buf = NULL;
if (lrc->bb_per_ctx_bo->vmap.is_iomem) {
buf = kmalloc(lrc->bb_per_ctx_bo->size, GFP_KERNEL);
if (lrc->bo->vmap.is_iomem) {
buf = kmalloc(max_size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
cmd = buf;
} else {
cmd = lrc->bb_per_ctx_bo->vmap.vaddr;
cmd = lrc->bo->vmap.vaddr + wa_bb_offset(lrc);
}
*cmd++ = MI_STORE_REGISTER_MEM | MI_SRM_USE_GGTT | MI_SRM_ADD_CS_OFFSET;
@ -974,13 +980,14 @@ static int xe_lrc_setup_utilization(struct xe_lrc *lrc)
*cmd++ = MI_BATCH_BUFFER_END;
if (buf) {
xe_map_memcpy_to(gt_to_xe(lrc->gt), &lrc->bb_per_ctx_bo->vmap, 0,
buf, (cmd - buf) * sizeof(*cmd));
xe_map_memcpy_to(gt_to_xe(lrc->gt), &lrc->bo->vmap,
wa_bb_offset(lrc), buf,
(cmd - buf) * sizeof(*cmd));
kfree(buf);
}
xe_lrc_write_ctx_reg(lrc, CTX_BB_PER_CTX_PTR,
xe_bo_ggtt_addr(lrc->bb_per_ctx_bo) | 1);
xe_lrc_write_ctx_reg(lrc, CTX_BB_PER_CTX_PTR, xe_bo_ggtt_addr(lrc->bo) +
wa_bb_offset(lrc) + 1);
return 0;
}
@ -1018,20 +1025,13 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
* FIXME: Perma-pinning LRC as we don't yet support moving GGTT address
* via VM bind calls.
*/
lrc->bo = xe_bo_create_pin_map(xe, tile, NULL, lrc_size,
lrc->bo = xe_bo_create_pin_map(xe, tile, NULL,
lrc_size + LRC_WA_BB_SIZE,
ttm_bo_type_kernel,
bo_flags);
if (IS_ERR(lrc->bo))
return PTR_ERR(lrc->bo);
lrc->bb_per_ctx_bo = xe_bo_create_pin_map(xe, tile, NULL, SZ_4K,
ttm_bo_type_kernel,
bo_flags);
if (IS_ERR(lrc->bb_per_ctx_bo)) {
err = PTR_ERR(lrc->bb_per_ctx_bo);
goto err_lrc_finish;
}
lrc->size = lrc_size;
lrc->ring.size = ring_size;
lrc->ring.tail = 0;
@ -1819,7 +1819,8 @@ struct xe_lrc_snapshot *xe_lrc_snapshot_capture(struct xe_lrc *lrc)
snapshot->seqno = xe_lrc_seqno(lrc);
snapshot->lrc_bo = xe_bo_get(lrc->bo);
snapshot->lrc_offset = xe_lrc_pphwsp_offset(lrc);
snapshot->lrc_size = lrc->bo->size - snapshot->lrc_offset;
snapshot->lrc_size = lrc->bo->size - snapshot->lrc_offset -
LRC_WA_BB_SIZE;
snapshot->lrc_snapshot = NULL;
snapshot->ctx_timestamp = lower_32_bits(xe_lrc_ctx_timestamp(lrc));
snapshot->ctx_job_timestamp = xe_lrc_ctx_job_timestamp(lrc);

View File

@ -53,9 +53,6 @@ struct xe_lrc {
/** @ctx_timestamp: readout value of CTX_TIMESTAMP on last update */
u64 ctx_timestamp;
/** @bb_per_ctx_bo: buffer object for per context batch wa buffer */
struct xe_bo *bb_per_ctx_bo;
};
struct xe_lrc_snapshot;

View File

@ -82,7 +82,7 @@ struct xe_migrate {
* of the instruction. Subtracting the instruction header (1 dword) and
* address (2 dwords), that leaves 0x3FD dwords (0x1FE qwords) for PTE values.
*/
#define MAX_PTE_PER_SDI 0x1FE
#define MAX_PTE_PER_SDI 0x1FEU
/**
* xe_tile_migrate_exec_queue() - Get this tile's migrate exec queue.
@ -1553,15 +1553,17 @@ static u32 pte_update_cmd_size(u64 size)
u64 entries = DIV_U64_ROUND_UP(size, XE_PAGE_SIZE);
XE_WARN_ON(size > MAX_PREEMPTDISABLE_TRANSFER);
/*
* MI_STORE_DATA_IMM command is used to update page table. Each
* instruction can update maximumly 0x1ff pte entries. To update
* n (n <= 0x1ff) pte entries, we need:
* 1 dword for the MI_STORE_DATA_IMM command header (opcode etc)
* 2 dword for the page table's physical location
* 2*n dword for value of pte to fill (each pte entry is 2 dwords)
* instruction can update maximumly MAX_PTE_PER_SDI pte entries. To
* update n (n <= MAX_PTE_PER_SDI) pte entries, we need:
*
* - 1 dword for the MI_STORE_DATA_IMM command header (opcode etc)
* - 2 dword for the page table's physical location
* - 2*n dword for value of pte to fill (each pte entry is 2 dwords)
*/
num_dword = (1 + 2) * DIV_U64_ROUND_UP(entries, 0x1ff);
num_dword = (1 + 2) * DIV_U64_ROUND_UP(entries, MAX_PTE_PER_SDI);
num_dword += entries * 2;
return num_dword;
@ -1577,7 +1579,7 @@ static void build_pt_update_batch_sram(struct xe_migrate *m,
ptes = DIV_ROUND_UP(size, XE_PAGE_SIZE);
while (ptes) {
u32 chunk = min(0x1ffU, ptes);
u32 chunk = min(MAX_PTE_PER_SDI, ptes);
bb->cs[bb->len++] = MI_STORE_DATA_IMM | MI_SDI_NUM_QW(chunk);
bb->cs[bb->len++] = pt_offset;

View File

@ -21,7 +21,8 @@
GRAPHICS_VERSION_RANGE(1270, 1274)
MEDIA_VERSION(1300)
PLATFORM(DG2)
14018094691 GRAPHICS_VERSION(2004)
14018094691 GRAPHICS_VERSION_RANGE(2001, 2002)
GRAPHICS_VERSION(2004)
14019882105 GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0)
18024947630 GRAPHICS_VERSION(2001)
GRAPHICS_VERSION(2004)
@ -59,3 +60,7 @@ no_media_l3 MEDIA_VERSION(3000)
MEDIA_VERSION_RANGE(1301, 3000)
16026508708 GRAPHICS_VERSION_RANGE(1200, 3001)
MEDIA_VERSION_RANGE(1300, 3000)
# SoC workaround - currently applies to all platforms with the following
# primary GT GMDID
14022085890 GRAPHICS_VERSION(2001)

View File

@ -223,6 +223,9 @@ struct mipi_dsi_multi_context {
#define to_mipi_dsi_device(__dev) container_of_const(__dev, struct mipi_dsi_device, dev)
extern const struct bus_type mipi_dsi_bus_type;
#define dev_is_mipi_dsi(dev) ((dev)->bus == &mipi_dsi_bus_type)
/**
* mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any
* given pixel format defined by the MIPI DSI

View File

@ -70,9 +70,11 @@ static inline bool spsc_queue_push(struct spsc_queue *queue, struct spsc_node *n
preempt_disable();
atomic_inc(&queue->job_count);
smp_mb__after_atomic();
tail = (struct spsc_node **)atomic_long_xchg(&queue->tail, (long)&node->next);
WRITE_ONCE(*tail, node);
atomic_inc(&queue->job_count);
/*
* In case of first element verify new node will be visible to the consumer