mirror of
https://github.com/torvalds/linux.git
synced 2026-06-05 21:15:53 +02:00
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:
commit
42bb9b630c
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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[] = {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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(>->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(>->global_invl_lock);
|
||||
xe_mmio_write32(>->mmio, XE2_GLOBAL_INVAL, 0x1);
|
||||
|
||||
xe_mmio_write32(>->mmio, XE2_GLOBAL_INVAL, 0x1);
|
||||
if (xe_mmio_wait32(>->mmio, XE2_GLOBAL_INVAL, 0x1, 0x0, 500, NULL, true))
|
||||
xe_gt_err_once(gt, "Global invalidation timeout\n");
|
||||
|
||||
spin_unlock(>->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) ?
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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(>->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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user