Re: [PATCH] drm/panthor: fix building without CONFIG_DEBUG_FS
On Thu, 24 Apr 2025 13:25:47 +0200 Arnd Bergmann wrote: > From: Arnd Bergmann > > When debugfs is disabled, including panthor_gem.h causes warnings > about a non-static global function defined in a header: > > In file included from drivers/gpu/drm/panthor/panthor_drv.c:30: > drivers/gpu/drm/panthor/panthor_gem.h:222:6: error: no previous prototype for > 'panthor_gem_debugfs_set_usage_flags' [-Werror=missing-prototypes] > 222 | void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object > *bo, u32 usage_flags) {}; > > This could be changed to a static inline function, but as the normal > one is also static inline, just move the #ifdef check in there. > The #ifdef is still needed to avoid accessing a struct member that > does not exist without debugfs. > > Fixes: a3707f53eb3f ("drm/panthor: show device-wide list of DRM GEM objects > over DebugFS") > Signed-off-by: Arnd Bergmann > --- > drivers/gpu/drm/panthor/panthor_gem.h | 7 ++- > 1 file changed, 2 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpu/drm/panthor/panthor_gem.h > b/drivers/gpu/drm/panthor/panthor_gem.h > index 4641994ddd7f..693842e10dee 100644 > --- a/drivers/gpu/drm/panthor/panthor_gem.h > +++ b/drivers/gpu/drm/panthor/panthor_gem.h > @@ -209,17 +209,14 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, > struct panthor_vm *vm, > > void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo); > > -#ifdef CONFIG_DEBUG_FS > void panthor_gem_debugfs_print_bos(struct panthor_device *pfdev, > struct seq_file *m); > static inline void > panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 > usage_flags) > { > +#ifdef CONFIG_DEBUG_FS > bo->debugfs.flags = usage_flags | > PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED; > -} > - > -#else > -void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 > usage_flags) {}; > #endif > +} > Oops. I actually don't see a good reason to expose this function, so could we go for something like that instead? diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 2dcf308094b2..962c2dc075db 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -42,11 +42,20 @@ static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) mutex_unlock(&ptdev->gems.lock); } +static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, + u32 usage_flags) +{ + bo->debugfs.flags = usage_flags | PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED; +} #else static void panthor_gem_debugfs_bo_add(struct panthor_device *ptdev, struct panthor_gem_object *bo) {} static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) {} +static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, + u32 usage_flags) +{ +} #endif static void panthor_gem_free_object(struct drm_gem_object *obj) diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h index 4641994ddd7f..4dd732dcd59f 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -212,14 +212,6 @@ void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo); #ifdef CONFIG_DEBUG_FS void panthor_gem_debugfs_print_bos(struct panthor_device *pfdev, struct seq_file *m); -static inline void -panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) -{ - bo->debugfs.flags = usage_flags | PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED; -} - -#else -void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) {}; #endif #endif /* __PANTHOR_GEM_H__ */
[PATCH v3 4/7] drm/gpusvm: refactor core API to use pages struct
Refactor the core API of get/unmap/free pages to all operate on drm_gpusvm_pages. In the next patch we want to export a simplified core API without needing fully blown svm range etc. Suggested-by: Matthew Brost Signed-off-by: Matthew Auld Cc: Thomas Hellström --- drivers/gpu/drm/drm_gpusvm.c | 161 --- 1 file changed, 110 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index ef38017d2159..fbe0d70ef163 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -1128,19 +1128,19 @@ drm_gpusvm_range_find_or_insert(struct drm_gpusvm *gpusvm, EXPORT_SYMBOL_GPL(drm_gpusvm_range_find_or_insert); /** - * __drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range (internal) + * __drm_gpusvm_unmap_pages() - Unmap pages associated with GPU SVM pages + * (internal) * @gpusvm: Pointer to the GPU SVM structure - * @range: Pointer to the GPU SVM range structure + * @pages: Pointer to the GPU SVM pages structure * @npages: Number of pages to unmap * - * This function unmap pages associated with a GPU SVM range. Assumes and + * This function unmap pages associated with a GPU SVM pages struct. Assumes and * asserts correct locking is in place when called. */ -static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range, - unsigned long npages) +static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm, +struct drm_gpusvm_pages *svm_pages, +unsigned long npages) { - struct drm_gpusvm_pages *svm_pages = &range->pages; struct drm_pagemap *dpagemap = svm_pages->dpagemap; struct device *dev = gpusvm->drm->dev; unsigned long i, j; @@ -1168,17 +1168,15 @@ static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm, } /** - * drm_gpusvm_range_free_pages() - Free pages associated with a GPU SVM range + * __drm_gpusvm_free_pages() - Free dma array associated with GPU SVM pages * @gpusvm: Pointer to the GPU SVM structure - * @range: Pointer to the GPU SVM range structure + * @svm_pages: Pointer to the GPU SVM pages structure * * This function frees the dma address array associated with a GPU SVM range. */ -static void drm_gpusvm_range_free_pages(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range) +static void __drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm, + struct drm_gpusvm_pages *svm_pages) { - struct drm_gpusvm_pages *svm_pages = &range->pages; - lockdep_assert_held(&gpusvm->notifier_lock); if (svm_pages->dma_addr) { @@ -1211,8 +1209,8 @@ void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm, return; drm_gpusvm_notifier_lock(gpusvm); - __drm_gpusvm_range_unmap_pages(gpusvm, range, npages); - drm_gpusvm_range_free_pages(gpusvm, range); + __drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages); + __drm_gpusvm_free_pages(gpusvm, &range->pages); __drm_gpusvm_range_remove(notifier, range); drm_gpusvm_notifier_unlock(gpusvm); @@ -1277,6 +1275,28 @@ void drm_gpusvm_range_put(struct drm_gpusvm_range *range) } EXPORT_SYMBOL_GPL(drm_gpusvm_range_put); +/** + * drm_gpusvm_pages_valid() - GPU SVM range pages valid + * @gpusvm: Pointer to the GPU SVM structure + * @svm_pages: Pointer to the GPU SVM pages structure + * + * This function determines if a GPU SVM range pages are valid. Expected be + * called holding gpusvm->notifier_lock and as the last step before committing a + * GPU binding. This is akin to a notifier seqno check in the HMM documentation + * but due to wider notifiers (i.e., notifiers which span multiple ranges) this + * function is required for finer grained checking (i.e., per range) if pages + * are valid. + * + * Return: True if GPU SVM range has valid pages, False otherwise + */ +static bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm, + struct drm_gpusvm_pages *svm_pages) +{ + lockdep_assert_held(&gpusvm->notifier_lock); + + return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping; +} + /** * drm_gpusvm_range_pages_valid() - GPU SVM range pages valid * @gpusvm: Pointer to the GPU SVM structure @@ -1294,11 +1314,7 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_put); bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm, struct drm_gpusvm_range *range) { - struct drm_gpusvm_pages *svm_pages = &range->pages; - - lockdep_assert_held(&gpusvm->notifier_lock); - - return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping; + return drm_gpusvm_pages_valid(gpusvm, &range->pages); } EXPORT_SYMBOL_GPL(dr
[PATCH 0/4] drm/nouveau: Simplify nouveau_fence.c
Just some minor attempts at improving the readability of nouveau_fence.c This series is based on this partially merged series: [1] Feel free to drop single patches if they are not deemed worth the effort. P. [1] https://lore.kernel.org/dri-devel/20250415121900.55719-3-pha...@kernel.org/ Philipp Stanner (4): drm/nouveau: nouveau_fence: Standardize list iterations drm/nouveau: Simplify calls to nvif_event_block() drm/nouveau: Simplify nouveau_fence_done() drm/nouveau: Check dma_fence in canonical way drivers/gpu/drm/nouveau/nouveau_fence.c | 72 +++-- 1 file changed, 30 insertions(+), 42 deletions(-) -- 2.48.1
[PATCH 4/4] drm/nouveau: Check dma_fence in canonical way
In nouveau_fence_done(), a fence is checked for being signaled by manually evaluating the base fence's bits. This can be done in a canonical manner through dma_fence_is_signaled(). Replace the bit-check with dma_fence_is_signaled(). Signed-off-by: Philipp Stanner --- drivers/gpu/drm/nouveau/nouveau_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index fb9811938c82..d5654e26d5bc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -253,7 +253,7 @@ nouveau_fence_done(struct nouveau_fence *fence) struct nouveau_channel *chan; unsigned long flags; - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) + if (dma_fence_is_signaled(&fence->base)) return true; spin_lock_irqsave(&fctx->lock, flags); -- 2.48.1
Re: [5/6] gpu: nova-core: Clarify fields in FalconAppifHdrV1
On 4/24/2025 3:45 AM, Alexandre Courbot wrote: > On Thu Apr 24, 2025 at 12:06 PM JST, Joel Fernandes wrote: >> On April 24, 2025, 1:18 a.m. UTC >> Alexandre Courbot wrote: >>> Since this just renames fields, would you be ok if I squashed this one >>> into the relevant patch of my series, alongside a >>> >>> [joelagn...@nvidia.com: give better names to FalconAppifHdrV1's fields] >>> >>> ? >> >> Yes, sounds good to me. Thanks! > > Ah, but since the documentation for FalconAppifHdrV1 references > fwsec.rst, which won't exist in my branch, I will only squash the new > fields names - please make sure to carry the FalconAppifHdrV1's > doccomment into another patch! Sure, that works for me. Thanks, - Joel
Re: [PATCH v4 2/5] drm/xe: Strict migration policy for atomic SVM faults
On Tue, 2025-04-22 at 10:04 -0700, Matthew Brost wrote: > Mixing GPU and CPU atomics does not work unless a strict migration > policy of GPU atomics must be device memory. Enforce a policy of must > be > in VRAM with a retry loop of 2 attempts, if retry loop fails abort > fault. > > v2: > - Only retry migration on atomics > - Drop alway migrate modparam > v3: > - Only set vram_only on DGFX (Himal) > - Bail on get_pages failure if vram_only and retry count exceeded > (Himal) > - s/vram_only/devmem_only > - Update xe_svm_range_is_valid to accept devmem_only argument > v4: > - Fix logic bug get_pages failure > > Signed-off-by: Himal Prasad Ghimiray > > Signed-off-by: Matthew Brost > --- > drivers/gpu/drm/xe/xe_module.c | 3 -- > drivers/gpu/drm/xe/xe_module.h | 1 - > drivers/gpu/drm/xe/xe_svm.c | 89 +--- > -- > drivers/gpu/drm/xe/xe_svm.h | 5 -- > 4 files changed, 65 insertions(+), 33 deletions(-) > > diff --git a/drivers/gpu/drm/xe/xe_module.c > b/drivers/gpu/drm/xe/xe_module.c > index 05c7d0ae6d83..1c4dfafbcd0b 100644 > --- a/drivers/gpu/drm/xe/xe_module.c > +++ b/drivers/gpu/drm/xe/xe_module.c > @@ -33,9 +33,6 @@ struct xe_modparam xe_modparam = { > module_param_named(svm_notifier_size, xe_modparam.svm_notifier_size, > uint, 0600); > MODULE_PARM_DESC(svm_notifier_size, "Set the svm notifier size(in > MiB), must be power of 2"); > > -module_param_named(always_migrate_to_vram, > xe_modparam.always_migrate_to_vram, bool, 0444); > -MODULE_PARM_DESC(always_migrate_to_vram, "Always migrate to VRAM on > GPU fault"); > - module_param_named_unsafe(force_execlist, > xe_modparam.force_execlist, bool, 0444); > MODULE_PARM_DESC(force_execlist, "Force Execlist submission"); > > diff --git a/drivers/gpu/drm/xe/xe_module.h > b/drivers/gpu/drm/xe/xe_module.h > index 84339e509c80..5a3bfea8b7b4 100644 > --- a/drivers/gpu/drm/xe/xe_module.h > +++ b/drivers/gpu/drm/xe/xe_module.h > @@ -12,7 +12,6 @@ > struct xe_modparam { > bool force_execlist; > bool probe_display; > - bool always_migrate_to_vram; > u32 force_vram_bar_size; > int guc_log_level; > char *guc_firmware_path; > diff --git a/drivers/gpu/drm/xe/xe_svm.c > b/drivers/gpu/drm/xe/xe_svm.c > index 890f6b2f40e9..f749ae367a8f 100644 > --- a/drivers/gpu/drm/xe/xe_svm.c > +++ b/drivers/gpu/drm/xe/xe_svm.c > @@ -650,9 +650,11 @@ void xe_svm_fini(struct xe_vm *vm) > } > > static bool xe_svm_range_is_valid(struct xe_svm_range *range, > - struct xe_tile *tile) > + struct xe_tile *tile, > + bool devmem_only) > { > - return (range->tile_present & ~range->tile_invalidated) & > BIT(tile->id); > + return ((range->tile_present & ~range->tile_invalidated) & > BIT(tile->id)) > + && (!devmem_only || range- > >base.flags.migrate_devmem); > } So let's say devmem_only is true here, and range- >base.flags.migrate_devmem is false. Wouldn't that mean the range is unusable and needs to be freed and re-allocated? Also another thing going back to older code, it seems like range- >tile_invalidated is protected by the notifier lock, so shouldn't we assert that to be held in the function? It seems not to be held further below: > > #if IS_ENABLED(CONFIG_DRM_XE_DEVMEM_MIRROR) > @@ -726,6 +728,35 @@ static int xe_svm_alloc_vram(struct xe_vm *vm, > struct xe_tile *tile, > } > #endif > > +static bool supports_4K_migration(struct xe_device *xe) > +{ > + if (xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K) > + return false; > + > + return true; > +} Do we have any hardware that supports pagefaults but not 4K VRAM pages? > + > +static bool xe_svm_range_needs_migrate_to_vram(struct xe_svm_range > *range, > + struct xe_vma *vma) > +{ > + struct xe_vm *vm = range_to_vm(&range->base); > + u64 range_size = xe_svm_range_size(range); > + > + if (!range->base.flags.migrate_devmem) > + return false; > + > + if (xe_svm_range_in_vram(range)) { > + drm_dbg(&vm->xe->drm, "Range is already in VRAM\n"); > + return false; > + } > + > + if (range_size <= SZ_64K && !supports_4K_migration(vm->xe)) > { > + drm_dbg(&vm->xe->drm, "Platform doesn't support > SZ_4K range migration\n"); > + return false; > + } > + > + return true; > +} > > /** > * xe_svm_handle_pagefault() - SVM handle page fault > @@ -750,12 +781,15 @@ int xe_svm_handle_pagefault(struct xe_vm *vm, > struct xe_vma *vma, > IS_ENABLED(CONFIG_DRM_XE_DEVMEM_MIRROR), > .check_pages_threshold = IS_DGFX(vm->xe) && > IS_ENABLED(CONFIG_DRM_XE_DEVMEM_MIRROR) ? > SZ_64K : 0, > + .devmem_only = atomic && IS_DGFX(vm->xe) && > + IS_ENABLED(CONFIG_DRM_XE_DEVMEM_MIRROR), > }; > struct xe_svm_range *range; >
Re: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
Hi Matthew, kernel test robot noticed the following build errors: [auto build test ERROR on drm-xe/drm-xe-next] [also build test ERROR on next-20250424] [cannot apply to drm-exynos/exynos-drm-next linus/master drm/drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-misc/drm-misc-next drm-tip/drm-tip v6.15-rc3] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Matthew-Auld/drm-gpusvm-fix-hmm_pfn_to_map_order-usage/20250424-202128 base: https://gitlab.freedesktop.org/drm/xe/kernel.git drm-xe-next patch link: https://lore.kernel.org/r/20250424121827.862729-15-matthew.auld%40intel.com patch subject: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm config: loongarch-randconfig-002-20250424 (https://download.01.org/0day-ci/archive/20250424/202504242203.mfhcd5la-...@intel.com/config) compiler: loongarch64-linux-gcc (GCC) 12.4.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250424/202504242203.mfhcd5la-...@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot | Closes: https://lore.kernel.org/oe-kbuild-all/202504242203.mfhcd5la-...@intel.com/ All errors (new ones prefixed by >>): In file included from include/linux/irqflags.h:19, from include/linux/spinlock.h:59, from include/linux/sched.h:2213, from include/linux/ratelimit.h:6, from include/linux/dev_printk.h:16, from include/linux/device.h:15, from include/drm/drm_print.h:31, from drivers/gpu/drm/xe/xe_assert.h:11, from drivers/gpu/drm/xe/xe_vm.h:9, from drivers/gpu/drm/xe/xe_vm.c:6: arch/loongarch/include/asm/percpu.h:20:4: error: #error compiler support for the model attribute is necessary when a recent assembler is used 20 | # error compiler support for the model attribute is necessary when a recent assembler is used |^ drivers/gpu/drm/xe/xe_vm.c: In function 'xe_vma_userptr_force_invalidate': >> drivers/gpu/drm/xe/xe_vm.c:699:52: error: 'struct xe_userptr' has no member >> named 'notifier_seq'; did you mean 'notifier'? 699 | uvma->userptr.notifier_seq)) |^~~~ |notifier drivers/gpu/drm/xe/xe_vm.c:700:31: error: 'struct xe_userptr' has no member named 'notifier_seq'; did you mean 'notifier'? 700 | uvma->userptr.notifier_seq -= 2; | ^~~~ | notifier Kconfig warnings: (for reference only) WARNING: unmet direct dependencies detected for DRM_GPUSVM Depends on [n]: HAS_IOMEM [=y] && DRM [=y] && DEVICE_PRIVATE [=n] Selected by [m]: - DRM_XE [=m] && HAS_IOMEM [=y] && DRM [=y] && PCI [=y] && MMU [=y] && (m [=m] && MODULES [=y] || KUNIT [=n]=y [=y]) vim +699 drivers/gpu/drm/xe/xe_vm.c dd08ebf6c3525a Matthew Brost2023-03-30 676 100a5b8dadfca5 Thomas Hellström 2025-02-28 677 #if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT) 100a5b8dadfca5 Thomas Hellström 2025-02-28 678 /** 100a5b8dadfca5 Thomas Hellström 2025-02-28 679 * xe_vma_userptr_force_invalidate() - force invalidate a userptr 100a5b8dadfca5 Thomas Hellström 2025-02-28 680 * @uvma: The userptr vma to invalidate 100a5b8dadfca5 Thomas Hellström 2025-02-28 681 * 100a5b8dadfca5 Thomas Hellström 2025-02-28 682 * Perform a forced userptr invalidation for testing purposes. 100a5b8dadfca5 Thomas Hellström 2025-02-28 683 */ 100a5b8dadfca5 Thomas Hellström 2025-02-28 684 void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma) 100a5b8dadfca5 Thomas Hellström 2025-02-28 685 { 100a5b8dadfca5 Thomas Hellström 2025-02-28 686 struct xe_vm *vm = xe_vma_vm(&uvma->vma); 100a5b8dadfca5 Thomas Hellström 2025-02-28 687 100a5b8dadfca5 Thomas Hellström 2025-02-28 688 /* Protect against concurrent userptr pinning */ 100a5b8dadfca5 Thomas Hellström 2025-02-28 689 lockdep_assert_held(&vm->lock); 100a5b8dadfca5 Thomas Hellström 2025-02-28 690 /* Protect against concurrent notifiers */ a2cfe1a4a9e967 Matthew Auld 2025-04-24 691 lockdep_assert_held(&vm->svm.gpusvm.notifier_lock); 100a5b8dadfca5 Thomas Hellström 2025-02-28 692 /*
[PATCH v22 2/5] drm/xe/xe_gt_pagefault: Move pagefault struct to header
Move the pagefault struct from xe_gt_pagefault.c to the xe_gt_pagefault_types.h header file, and move the associated enum values into the regs folder under xe_pagefault_desc.h Since xe_pagefault_desc.h is being initialized here, also move the xe_guc_pagefault_desc hardware formats to the new file. v2: - Normalize names for common header (Matt Brost) v3: - s/Migrate/Move (Michal W) - s/xe_pagefault/xe_gt_pagefault (Michal W) - Create new header file, xe_gt_pagefault_types.h (Michal W) - Add kernel docs (Michal W) v4: - Fix includes usage (Michal W) - Reference Bspec (Michal W) v5: - Convert enums to defines in regs folder (Michal W) - Move xe_guc_pagefault_desc to regs folder (Michal W) Bspec: 77412 Signed-off-by: Jonathan Cavitt Reviewed-by: Shuicheng Lin Cc: Michal Wajdeczko --- drivers/gpu/drm/xe/regs/xe_pagefault_desc.h | 49 + drivers/gpu/drm/xe/xe_gt_pagefault.c| 43 -- drivers/gpu/drm/xe/xe_gt_pagefault_types.h | 42 ++ drivers/gpu/drm/xe/xe_guc_fwif.h| 28 4 files changed, 100 insertions(+), 62 deletions(-) create mode 100644 drivers/gpu/drm/xe/regs/xe_pagefault_desc.h create mode 100644 drivers/gpu/drm/xe/xe_gt_pagefault_types.h diff --git a/drivers/gpu/drm/xe/regs/xe_pagefault_desc.h b/drivers/gpu/drm/xe/regs/xe_pagefault_desc.h new file mode 100644 index ..a169ac274e14 --- /dev/null +++ b/drivers/gpu/drm/xe/regs/xe_pagefault_desc.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2025 Intel Corporation + */ + +#ifndef _XE_PAGEFAULT_DESC_H_ +#define _XE_PAGEFAULT_DESC_H_ + +#include +#include + +struct xe_guc_pagefault_desc { + u32 dw0; +#define PFD_FAULT_LEVELGENMASK(2, 0) +#define PFD_SRC_ID GENMASK(10, 3) +#define PFD_RSVD_0 GENMASK(17, 11) +#define XE2_PFD_TRVA_FAULT BIT(18) +#define PFD_ENG_INSTANCE GENMASK(24, 19) +#define PFD_ENG_CLASS GENMASK(27, 25) +#define PFD_PDATA_LO GENMASK(31, 28) + + u32 dw1; +#define PFD_PDATA_HI GENMASK(11, 0) +#define PFD_PDATA_HI_SHIFT 4 +#define PFD_ASID GENMASK(31, 12) + + u32 dw2; +#define PFD_ACCESS_TYPEGENMASK(1, 0) +#define PFD_FAULT_TYPE GENMASK(3, 2) +#define PFD_VFID GENMASK(9, 4) +#define PFD_RSVD_1 GENMASK(11, 10) +#define PFD_VIRTUAL_ADDR_LOGENMASK(31, 12) +#define PFD_VIRTUAL_ADDR_LO_SHIFT 12 + + u32 dw3; +#define PFD_VIRTUAL_ADDR_HIGENMASK(31, 0) +#define PFD_VIRTUAL_ADDR_HI_SHIFT 32 +} __packed; + +#define FLT_ACCESS_TYPE_READ 0u +#define FLT_ACCESS_TYPE_WRITE 1u +#define FLT_ACCESS_TYPE_ATOMIC 2u +#define FLT_ACCESS_TYPE_RESERVED 3u + +#define FLT_TYPE_NOT_PRESENT_FAULT 0u +#define FLT_TYPE_WRITE_ACCESS_VIOLATION1u +#define FLT_TYPE_ATOMIC_ACCESS_VIOLATION 2u + +#endif diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c index d4e3b7eb165a..93afa54c8780 100644 --- a/drivers/gpu/drm/xe/xe_gt_pagefault.c +++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c @@ -12,8 +12,10 @@ #include #include "abi/guc_actions_abi.h" +#include "regs/xe_pagefault_desc.h" #include "xe_bo.h" #include "xe_gt.h" +#include "xe_gt_pagefault_types.h" #include "xe_gt_stats.h" #include "xe_gt_tlb_invalidation.h" #include "xe_guc.h" @@ -23,33 +25,6 @@ #include "xe_trace_bo.h" #include "xe_vm.h" -struct pagefault { - u64 page_addr; - u32 asid; - u16 pdata; - u8 vfid; - u8 access_type; - u8 fault_type; - u8 fault_level; - u8 engine_class; - u8 engine_instance; - u8 fault_unsuccessful; - bool trva_fault; -}; - -enum access_type { - ACCESS_TYPE_READ = 0, - ACCESS_TYPE_WRITE = 1, - ACCESS_TYPE_ATOMIC = 2, - ACCESS_TYPE_RESERVED = 3, -}; - -enum fault_type { - NOT_PRESENT = 0, - WRITE_ACCESS_VIOLATION = 1, - ATOMIC_ACCESS_VIOLATION = 2, -}; - struct acc { u64 va_range_base; u32 asid; @@ -61,9 +36,9 @@ struct acc { u8 engine_instance; }; -static bool access_is_atomic(enum access_type access_type) +static bool access_is_atomic(u32 access_type) { - return access_type == ACCESS_TYPE_ATOMIC; + return access_type == FLT_ACCESS_TYPE_ATOMIC; } static bool vma_is_valid(struct xe_tile *tile, struct xe_vma *vma) @@ -205,7 +180,7 @@ static struct xe_vm *asid_to_vm(struct xe_device *xe, u32 asid) return vm; } -static int handle_pagefault(struct xe_gt *gt, struct pagefault *pf) +static int handle_pagefault(struct xe_gt *gt, struct xe_gt_pagefault *pf) { struct xe_device *xe = gt_to_xe(gt); struct xe_vm *vm; @@ -237,7 +212,7 @@ static int handle_pagefault(struct xe_gt *gt, struct pagefault *pf) goto unlock_vm; } - if (xe_vma_read_only(vma) && pf->access_type != ACCESS_
[PATCH v22 0/5] drm/xe/xe_vm: Implement xe_vm_get_property_ioctl
Add additional information to each VM so they can report up to the first 50 seen faults. Only pagefaults are saved this way currently, though in the future, all faults should be tracked by the VM for future reporting. Additionally, of the pagefaults reported, only failed pagefaults are saved this way, as successful pagefaults should recover silently and not need to be reported to userspace. To allow userspace to access these faults, a new ioctl - xe_vm_get_property_ioct - was created. v2: (Matt Brost) - Break full ban list request into a separate property. - Reformat drm_xe_vm_get_property struct. - Remove need for drm_xe_faults helper struct. - Separate data pointer and scalar return value in ioctl. - Get address type on pagefault report and save it to the pagefault. - Correctly reject writes to read-only VMAs. - Miscellaneous formatting fixes. v3: (Matt Brost) - Only allow querying of failed pagefaults v4: - Remove unnecessary size parameter from helper function, as it is a property of the arguments. (jcavitt) - Remove unnecessary copy_from_user (Jainxun) - Set address_precision to 1 (Jainxun) - Report max size instead of dynamic size for memory allocation purposes. Total memory usage is reported separately. v5: - Return int from xe_vm_get_property_size (Shuicheng) - Fix memory leak (Shuicheng) - Remove unnecessary size variable (jcavitt) v6: - Free vm after use (Shuicheng) - Compress pf copy logic (Shuicheng) - Update fault_unsuccessful before storing (Shuicheng) - Fix old struct name in comments (Shuicheng) - Keep first 50 pagefaults instead of last 50 (Jianxun) - Rename ioctl to xe_vm_get_faults_ioctl (jcavitt) v7: - Avoid unnecessary execution by checking MAX_PFS earlier (jcavitt) - Fix double-locking error (jcavitt) - Assert kmemdump is successful (Shuicheng) - Repair and move fill_faults break condition (Dan Carpenter) - Free vm after use (jcavitt) - Combine assertions (jcavitt) - Expand size check in xe_vm_get_faults_ioctl (jcavitt) - Remove return mask from fill_faults, as return is already -EFAULT or 0 (jcavitt) v8: - Revert back to using drm_xe_vm_get_property_ioctl - s/Migrate/Move (Michal) - s/xe_pagefault/xe_gt_pagefault (Michal) - Create new header file, xe_gt_pagefault_types.h (Michal) - Add and fix kernel docs (Michal) - Rename xe_vm.pfs to xe_vm.faults (jcavitt) - Store fault data and not pagefault in xe_vm faults list (jcavitt) - Store address, address type, and address precision per fault (jcavitt) - Store engine class and instance data per fault (Jianxun) - Properly handle kzalloc error (Michal W) - s/MAX_PFS/MAX_FAULTS_SAVED_PER_VM (Michal W) - Store fault level per fault (Micahl M) - Apply better copy_to_user logic (jcavitt) v9: - More kernel doc fixes (Michal W, Jianxun) - Better error handling (jcavitt) v10: - Convert enums to defines in regs folder (Michal W) - Move xe_guc_pagefault_desc to regs folder (Michal W) - Future-proof size logic for zero-size properties (jcavitt) - Replace address type extern with access type (Jianxun) - Add fault type to xe_drm_fault (Jianxun) v11: - Remove unnecessary switch case logic (Raag) - Compress size get, size validation, and property fill functions into a single helper function (jcavitt) - Assert valid size (jcavitt) - Store pagefaults in non-fault-mode VMs as well (Jianxun) v12: - Remove unnecessary else condition - Correct backwards helper function size logic (jcavitt) - Fix kernel docs and comments (Michal W) v13: - Move xe and user engine class mapping arrays to header (John H) v14: - Fix double locking issue (Jianxun) - Use size_t instead of int (Raag) - Remove unnecessary includes (jcavitt) v15: - Do not report faults from reserved engines (Jianxun) v16: - Remove engine class and instance (Ivan) v17: - Map access type, fault type, and fault level to user macros (Matt Brost, Ivan) v18: - Add uAPI merge request to this cover letter v19: - Perform kzalloc outside of lock (Auld) v20: - Fix inconsistent use of whitespace in defines v21: - Remove unnecessary size assertion (jcavitt) v22: - Fix xe_vm_fault_entry kernel docs (Shuicheng) uAPI: https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32987 Signed-off-by: Jonathan Cavitt Suggested-by: Joonas Lahtinen Suggested-by: Matthew Brost Cc: Zhang Jianxun Cc: Shuicheng Lin Cc: Michal Wajdeczko Cc: Michal Mrozek Cc: Raag Jadav Cc: John Harrison Cc: Ivan Briano Cc: Matthew Auld Jonathan Cavitt (5): drm/xe/xe_gt_pagefault: Disallow writes to read-only VMAs drm/xe/xe_gt_pagefault: Move pagefault struct to header drm/xe/uapi: Define drm_xe_vm_get_property drm/xe/xe_vm: Add per VM fault info drm/xe/xe_vm: Implement xe_vm_get_property_ioctl drivers/gpu/drm/xe/regs/xe_pagefault_desc.h | 49 + drivers/gpu/drm/xe/xe_device.c | 3 + drivers/gpu/drm/xe/xe_gt_pagefault.c| 72 drivers/gpu/drm/xe/xe_gt_pagefault_types.h | 42 + drivers/gpu/drm/xe/xe_guc_fwif.h| 28 --- drivers/gpu/drm/xe/x
[PATCH v22 1/5] drm/xe/xe_gt_pagefault: Disallow writes to read-only VMAs
The page fault handler should reject write/atomic access to read only VMAs. Add code to handle this in handle_pagefault after the VMA lookup. Fixes: 3d420e9fa848 ("drm/xe: Rework GPU page fault handling") Signed-off-by: Jonathan Cavitt Suggested-by: Matthew Brost Reviewed-by: Shuicheng Lin --- drivers/gpu/drm/xe/xe_gt_pagefault.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c index 10622ca471a2..d4e3b7eb165a 100644 --- a/drivers/gpu/drm/xe/xe_gt_pagefault.c +++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c @@ -237,6 +237,11 @@ static int handle_pagefault(struct xe_gt *gt, struct pagefault *pf) goto unlock_vm; } + if (xe_vma_read_only(vma) && pf->access_type != ACCESS_TYPE_READ) { + err = -EPERM; + goto unlock_vm; + } + atomic = access_is_atomic(pf->access_type); if (xe_vma_is_cpu_addr_mirror(vma)) -- 2.43.0
Re: [PATCH 06/11] drm/vc4: Test for imported buffers with drm_gem_is_imported()
On Mon, 14 Apr 2025 at 14:51, Thomas Zimmermann wrote: > > Instead of testing import_attach for imported GEM buffers, invoke > drm_gem_is_imported() to do the test. The helper tests the dma_buf > itself while import_attach is just an artifact of the import. Prepares > to make import_attach optional. > > Signed-off-by: Thomas Zimmermann > Cc: Maxime Ripard > Cc: Dave Stevenson > Cc: "Maíra Canal" > Cc: Raspberry Pi Kernel Maintenance Acked-by: Dave Stevenson > --- > drivers/gpu/drm/vc4/vc4_bo.c | 2 +- > drivers/gpu/drm/vc4/vc4_gem.c | 2 +- > 2 files changed, 2 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c > index 7125773889f1..b503fd0488b0 100644 > --- a/drivers/gpu/drm/vc4/vc4_bo.c > +++ b/drivers/gpu/drm/vc4/vc4_bo.c > @@ -556,7 +556,7 @@ static void vc4_free_object(struct drm_gem_object *gem_bo) > mutex_lock(&vc4->bo_lock); > /* If the object references someone else's memory, we can't cache it. > */ > - if (gem_bo->import_attach) { > + if (drm_gem_is_imported(gem_bo)) { > vc4_bo_destroy(bo); > goto out; > } > diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c > index 8125f87edc60..3e79ad69250a 100644 > --- a/drivers/gpu/drm/vc4/vc4_gem.c > +++ b/drivers/gpu/drm/vc4/vc4_gem.c > @@ -1249,7 +1249,7 @@ int vc4_gem_madvise_ioctl(struct drm_device *dev, void > *data, > /* Not sure it's safe to purge imported BOs. Let's just assume it's > * not until proven otherwise. > */ > - if (gem_obj->import_attach) { > + if (drm_gem_is_imported(gem_obj)) { > DRM_DEBUG("madvise not supported on imported BOs\n"); > ret = -EINVAL; > goto out_put_gem; > -- > 2.49.0 >
Re: [PATCH v3 7/7] drm/xe/pt: unify xe_pt_svm_pre_commit with userptr
Hi Matthew, kernel test robot noticed the following build warnings: [auto build test WARNING on drm-xe/drm-xe-next] [also build test WARNING on next-20250424] [cannot apply to drm-exynos/exynos-drm-next linus/master drm/drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-misc/drm-misc-next drm-tip/drm-tip v6.15-rc3] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Matthew-Auld/drm-gpusvm-fix-hmm_pfn_to_map_order-usage/20250424-202128 base: https://gitlab.freedesktop.org/drm/xe/kernel.git drm-xe-next patch link: https://lore.kernel.org/r/20250424121827.862729-16-matthew.auld%40intel.com patch subject: [PATCH v3 7/7] drm/xe/pt: unify xe_pt_svm_pre_commit with userptr config: csky-randconfig-001-20250424 (https://download.01.org/0day-ci/archive/20250424/202504242339.wqvu1ovp-...@intel.com/config) compiler: csky-linux-gcc (GCC) 12.4.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250424/202504242339.wqvu1ovp-...@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot | Closes: https://lore.kernel.org/oe-kbuild-all/202504242339.wqvu1ovp-...@intel.com/ All warnings (new ones prefixed by >>): In file included from drivers/gpu/drm/xe/xe_res_cursor.h:38, from drivers/gpu/drm/xe/xe_vm.c:38: >> drivers/gpu/drm/xe/xe_svm.h:182: warning: "xe_svm_assert_in_notifier" >> redefined 182 | #define xe_svm_assert_in_notifier(vm__) \ | drivers/gpu/drm/xe/xe_svm.h:170: note: this is the location of the previous definition 170 | #define xe_svm_assert_in_notifier(...) do {} while (0) | -- In file included from drivers/gpu/drm/xe/xe_tile.c:16: drivers/gpu/drm/xe/xe_svm.h: In function 'xe_svm_init': drivers/gpu/drm/xe/xe_svm.h:128:16: error: implicit declaration of function 'drm_gpusvm_init'; did you mean 'drm_mm_init'? [-Werror=implicit-function-declaration] 128 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm, |^~~ |drm_mm_init drivers/gpu/drm/xe/xe_svm.h:128:35: error: invalid use of undefined type 'struct xe_vm' 128 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm, | ^~ drivers/gpu/drm/xe/xe_svm.h:128:71: error: invalid use of undefined type 'struct xe_vm' 128 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm, | ^~ In file included from drivers/gpu/drm/xe/xe_sriov.h:9, from drivers/gpu/drm/xe/xe_device.h:13, from drivers/gpu/drm/xe/xe_tile.c:10: drivers/gpu/drm/xe/xe_svm.h: In function 'xe_svm_fini': drivers/gpu/drm/xe/xe_svm.h:135:21: error: invalid use of undefined type 'struct xe_vm' 135 | xe_assert(vm->xe, xe_vm_is_closed(vm)); | ^~ drivers/gpu/drm/xe/xe_assert.h:110:41: note: in definition of macro 'xe_assert_msg' 110 | const struct xe_device *__xe = (xe); \ | ^~ drivers/gpu/drm/xe/xe_svm.h:135:9: note: in expansion of macro 'xe_assert' 135 | xe_assert(vm->xe, xe_vm_is_closed(vm)); | ^ In file included from include/linux/bits.h:22, from include/linux/gfp_types.h:5, from include/linux/gfp.h:5, from include/drm/drm_managed.h:6, from drivers/gpu/drm/xe/xe_tile.c:8: drivers/gpu/drm/xe/xe_svm.h:135:27: error: implicit declaration of function 'xe_vm_is_closed' [-Werror=implicit-function-declaration] 135 | xe_assert(vm->xe, xe_vm_is_closed(vm)); | ^~~ include/linux/build_bug.h:30:63: note: in definition of macro 'BUILD_BUG_ON_INVALID' 30 | #define BUILD_BUG_ON_INVALID(e) ((void)(sizeof((__force long)(e | ^ drivers/gpu/drm/xe/xe_assert.h:111:9: note: in expansion of macro '__xe_assert_msg' 111 | __xe_assert_msg(__xe, condition, \ | ^~~ dri
RE: [PATCH] drm/i915/gsc: mei interrupt top half should be in irq disabled context
On Thu, 24 Apr 2025, Jani Nikula wrote: >On Thu, 24 Apr 2025, Sebastian Andrzej Siewior >wrote: >> On 2025-04-24 14:56:08 [+0800], Junxiao Chang wrote: >>> MEI GSC interrupt comes from i915. It has top half and bottom half. >>> Top half is called from i915 interrupt handler. It should be in irq >>> disabled context. >>> >>> With RT kernel, by default i915 IRQ handler is in threaded IRQ. MEI >>> GSC top half might be in threaded IRQ context. In this case, local >>> IRQ should be disabled for MEI GSC interrupt top half. >>> >>> This change fixes A380/A770 GPU boot hang issue with RT kernel. >> >> This should have a Fixes when generic_handle_irq() was introduced. If PREEMPT_RT is disabled, original driver works fine. I prefer to not add "Fixes:"? >> >>> Signed-off-by: Junxiao Chang >>> --- >>> drivers/gpu/drm/i915/gt/intel_gsc.c | 14 ++ >>> 1 file changed, 14 insertions(+) >>> >>> diff --git a/drivers/gpu/drm/i915/gt/intel_gsc.c >>> b/drivers/gpu/drm/i915/gt/intel_gsc.c >>> index 1e925c75fb080..9c72117263f78 100644 >>> --- a/drivers/gpu/drm/i915/gt/intel_gsc.c >>> +++ b/drivers/gpu/drm/i915/gt/intel_gsc.c >>> @@ -270,6 +270,9 @@ static void gsc_init_one(struct drm_i915_private >>> *i915, struct intel_gsc *gsc, static void gsc_irq_handler(struct >>> intel_gt *gt, unsigned int intf_id) { >>> int ret; >>> +#ifdef CONFIG_PREEMPT_RT >>> + int irq_disabled_flag; >>> +#endif >>> >>> if (intf_id >= INTEL_GSC_NUM_INTERFACES) { >>> gt_warn_once(gt, "GSC irq: intf_id %d is out of range", >>> intf_id); >>> @@ -284,7 +287,18 @@ static void gsc_irq_handler(struct intel_gt *gt, >unsigned int intf_id) >>> if (gt->gsc.intf[intf_id].irq < 0) >>> return; >>> >>> +#ifdef CONFIG_PREEMPT_RT >>> + /* mei interrupt top half should run in irq disabled context */ >>> + irq_disabled_flag = irqs_disabled(); >>> + if (!irq_disabled_flag) >>> + local_irq_disable(); >>> +#endif >>> ret = generic_handle_irq(gt->gsc.intf[intf_id].irq); >> >> What about generic_handle_irq_safe() instead the whole ifdef show? > >Anything without the ifdefs would be welcome. Sebastain's suggestion looks very good. I just tried it, it works well with both RT and non RT, it doesn't need ifdefs. I will do more testing. >BR, >Jani. > >> >>> +#ifdef CONFIG_PREEMPT_RT >>> + if (!irq_disabled_flag) >>> + local_irq_enable(); >>> +#endif >>> + >>> if (ret) >>> gt_err_ratelimited(gt, "error handling GSC irq: %d\n", ret); } >> >> Sebastian > >-- >Jani Nikula, Intel Thanks! Junxiao
[PATCH v9 01/12] mtd: core: always create master device
Create master device without partition when CONFIG_MTD_PARTITIONED_MASTER flag is unset. This streamlines device tree and allows to anchor runtime power management on master device in all cases. Signed-off-by: Alexander Usyskin --- drivers/mtd/mtdchar.c | 2 +- drivers/mtd/mtdcore.c | 152 - drivers/mtd/mtdcore.h | 2 +- drivers/mtd/mtdpart.c | 16 ++-- include/linux/mtd/partitions.h | 2 +- 5 files changed, 123 insertions(+), 51 deletions(-) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 8dc4f5c493fc..391d81ad960c 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -559,7 +559,7 @@ static int mtdchar_blkpg_ioctl(struct mtd_info *mtd, /* Sanitize user input */ p.devname[BLKPG_DEVNAMELTH - 1] = '\0'; - return mtd_add_partition(mtd, p.devname, p.start, p.length); + return mtd_add_partition(mtd, p.devname, p.start, p.length, NULL); case BLKPG_DEL_PARTITION: diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 5ba9a741f5ac..429d8c16baf0 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -68,7 +68,13 @@ static struct class mtd_class = { .pm = MTD_CLS_PM_OPS, }; +static struct class mtd_master_class = { + .name = "mtd_master", + .pm = MTD_CLS_PM_OPS, +}; + static DEFINE_IDR(mtd_idr); +static DEFINE_IDR(mtd_master_idr); /* These are exported solely for the purpose of mtd_blkdevs.c. You should not use them for _anything_ else */ @@ -83,8 +89,9 @@ EXPORT_SYMBOL_GPL(__mtd_next_device); static LIST_HEAD(mtd_notifiers); - +#define MTD_MASTER_DEVS 255 #define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2) +static dev_t mtd_master_devt; /* REVISIT once MTD uses the driver model better, whoever allocates * the mtd_info will probably want to use the release() hook... @@ -104,6 +111,17 @@ static void mtd_release(struct device *dev) device_destroy(&mtd_class, index + 1); } +static void mtd_master_release(struct device *dev) +{ + struct mtd_info *mtd = dev_get_drvdata(dev); + + idr_remove(&mtd_master_idr, mtd->index); + of_node_put(mtd_get_of_node(mtd)); + + if (mtd_is_partition(mtd)) + release_mtd_partition(mtd); +} + static void mtd_device_release(struct kref *kref) { struct mtd_info *mtd = container_of(kref, struct mtd_info, refcnt); @@ -367,6 +385,11 @@ static const struct device_type mtd_devtype = { .release= mtd_release, }; +static const struct device_type mtd_master_devtype = { + .name = "mtd_master", + .release= mtd_master_release, +}; + static bool mtd_expert_analysis_mode; #ifdef CONFIG_DEBUG_FS @@ -634,13 +657,13 @@ static void mtd_check_of_node(struct mtd_info *mtd) /** * add_mtd_device - register an MTD device * @mtd: pointer to new MTD device info structure + * @partitioned: create partitioned device * * Add a device to the list of MTD devices present in the system, and * notify each currently active MTD 'user' of its arrival. Returns * zero on success or non-zero on failure. */ - -int add_mtd_device(struct mtd_info *mtd) +int add_mtd_device(struct mtd_info *mtd, bool partitioned) { struct device_node *np = mtd_get_of_node(mtd); struct mtd_info *master = mtd_get_master(mtd); @@ -687,10 +710,17 @@ int add_mtd_device(struct mtd_info *mtd) ofidx = -1; if (np) ofidx = of_alias_get_id(np, "mtd"); - if (ofidx >= 0) - i = idr_alloc(&mtd_idr, mtd, ofidx, ofidx + 1, GFP_KERNEL); - else - i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL); + if (partitioned) { + if (ofidx >= 0) + i = idr_alloc(&mtd_idr, mtd, ofidx, ofidx + 1, GFP_KERNEL); + else + i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL); + } else { + if (ofidx >= 0) + i = idr_alloc(&mtd_master_idr, mtd, ofidx, ofidx + 1, GFP_KERNEL); + else + i = idr_alloc(&mtd_master_idr, mtd, 0, 0, GFP_KERNEL); + } if (i < 0) { error = i; goto fail_locked; @@ -738,10 +768,18 @@ int add_mtd_device(struct mtd_info *mtd) /* Caller should have set dev.parent to match the * physical device, if appropriate. */ - mtd->dev.type = &mtd_devtype; - mtd->dev.class = &mtd_class; - mtd->dev.devt = MTD_DEVT(i); - error = dev_set_name(&mtd->dev, "mtd%d", i); + if (partitioned) { + mtd->dev.type = &mtd_devtype; + mtd->dev.class = &mtd_class; + mtd->dev.devt = MTD_DEVT(i); + dev_set_name(&mtd->dev, "mtd%d", i); + error = dev_set_name(&mtd->dev, "mtd%d", i); + } else { +
[PATCH v9 02/12] mtd: add driver for intel graphics non-volatile memory device
Add auxiliary driver for intel discrete graphics non-volatile memory device. CC: Lucas De Marchi Reviewed-by: Rodrigo Vivi Acked-by: Miquel Raynal Co-developed-by: Tomas Winkler Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin --- MAINTAINERS| 7 ++ drivers/mtd/devices/Kconfig| 11 +++ drivers/mtd/devices/Makefile | 1 + drivers/mtd/devices/mtd_intel_dg.c | 138 + include/linux/intel_dg_nvm_aux.h | 27 ++ 5 files changed, 184 insertions(+) create mode 100644 drivers/mtd/devices/mtd_intel_dg.c create mode 100644 include/linux/intel_dg_nvm_aux.h diff --git a/MAINTAINERS b/MAINTAINERS index dc7ea662bcea..7548561c78c0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11842,6 +11842,13 @@ L: linux-ker...@vger.kernel.org S: Supported F: arch/x86/include/asm/intel-family.h +INTEL DISCRETE GRAPHICS NVM MTD DRIVER +M: Alexander Usyskin +L: linux-...@lists.infradead.org +S: Supported +F: drivers/mtd/devices/mtd_intel_dg.c +F: include/linux/intel_dg_nvm_aux.h + INTEL DRM DISPLAY FOR XE AND I915 DRIVERS M: Jani Nikula M: Rodrigo Vivi diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index ff2f9e55ef28..59be6d3f0d32 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -183,6 +183,17 @@ config MTD_POWERNV_FLASH platforms from Linux. This device abstracts away the firmware interface for flash access. +config MTD_INTEL_DG + tristate "Intel Discrete Graphics non-volatile memory driver" + depends on AUXILIARY_BUS + depends on MTD + help + This provides an MTD device to access Intel Discrete Graphics + non-volatile memory. + + To compile this driver as a module, choose M here: the module + will be called mtd-intel-dg. + comment "Disk-On-Chip Device Drivers" config MTD_DOCG3 diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index d11eb2b8b6f8..9fe4ce9cffde 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_MTD_SST25L) += sst25l.o obj-$(CONFIG_MTD_BCM47XXSFLASH)+= bcm47xxsflash.o obj-$(CONFIG_MTD_ST_SPI_FSM)+= st_spi_fsm.o obj-$(CONFIG_MTD_POWERNV_FLASH)+= powernv_flash.o +obj-$(CONFIG_MTD_INTEL_DG) += mtd_intel_dg.o CFLAGS_docg3.o += -I$(src) diff --git a/drivers/mtd/devices/mtd_intel_dg.c b/drivers/mtd/devices/mtd_intel_dg.c new file mode 100644 index ..963a88cacc6c --- /dev/null +++ b/drivers/mtd/devices/mtd_intel_dg.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(c) 2019-2025, Intel Corporation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct intel_dg_nvm { + struct kref refcnt; + void __iomem *base; + size_t size; + unsigned int nregions; + struct { + const char *name; + u8 id; + u64 offset; + u64 size; + } regions[] __counted_by(nregions); +}; + +static void intel_dg_nvm_release(struct kref *kref) +{ + struct intel_dg_nvm *nvm = container_of(kref, struct intel_dg_nvm, refcnt); + int i; + + pr_debug("freeing intel_dg nvm\n"); + for (i = 0; i < nvm->nregions; i++) + kfree(nvm->regions[i].name); + kfree(nvm); +} + +static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev, + const struct auxiliary_device_id *aux_dev_id) +{ + struct intel_dg_nvm_dev *invm = auxiliary_dev_to_intel_dg_nvm_dev(aux_dev); + struct device *device; + struct intel_dg_nvm *nvm; + unsigned int nregions; + unsigned int i, n; + char *name; + int ret; + + device = &aux_dev->dev; + + /* count available regions */ + for (nregions = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) { + if (invm->regions[i].name) + nregions++; + } + + if (!nregions) { + dev_err(device, "no regions defined\n"); + return -ENODEV; + } + + nvm = kzalloc(struct_size(nvm, regions, nregions), GFP_KERNEL); + if (!nvm) + return -ENOMEM; + + kref_init(&nvm->refcnt); + + nvm->nregions = nregions; + for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) { + if (!invm->regions[i].name) + continue; + + name = kasprintf(GFP_KERNEL, "%s.%s", +dev_name(&aux_dev->dev), invm->regions[i].name); + if (!name) + continue; + nvm->regions[n].name = name; + nvm->regions[n].id = i; + n++; + } + nvm->nregions = n; /* in case where kasprintf fail */ + + nvm->base = devm_ior
[PATCH v9 10/12] drm/xe/nvm: add on-die non-volatile memory device
Enable access to internal non-volatile memory on DGFX with GSC/CSC devices via a child device. The nvm child device is exposed via auxiliary bus. Reviewed-by: Rodrigo Vivi Acked-by: Rodrigo Vivi Signed-off-by: Alexander Usyskin --- drivers/gpu/drm/xe/Makefile | 1 + drivers/gpu/drm/xe/xe_device.c | 5 ++ drivers/gpu/drm/xe/xe_device_types.h | 6 ++ drivers/gpu/drm/xe/xe_nvm.c | 101 +++ drivers/gpu/drm/xe/xe_nvm.h | 15 drivers/gpu/drm/xe/xe_pci.c | 6 ++ 6 files changed, 134 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_nvm.c create mode 100644 drivers/gpu/drm/xe/xe_nvm.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 3ecac0a38b82..1f026bf280ea 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -80,6 +80,7 @@ xe-y += xe_bb.o \ xe_mmio.o \ xe_mocs.o \ xe_module.o \ + xe_nvm.o \ xe_oa.o \ xe_observation.o \ xe_pat.o \ diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 75e753e0a682..c7755903d5e4 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -45,6 +45,7 @@ #include "xe_memirq.h" #include "xe_mmio.h" #include "xe_module.h" +#include "xe_nvm.h" #include "xe_oa.h" #include "xe_observation.h" #include "xe_pat.h" @@ -885,6 +886,8 @@ int xe_device_probe(struct xe_device *xe) return err; } + xe_nvm_init(xe); + err = xe_heci_gsc_init(xe); if (err) return err; @@ -938,6 +941,8 @@ void xe_device_remove(struct xe_device *xe) { xe_display_unregister(xe); + xe_nvm_fini(xe); + drm_dev_unplug(&xe->drm); xe_bo_pci_dev_remove_all(xe); diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 06c65dace026..c9265b7c3351 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -35,6 +35,7 @@ #include "intel_display_device.h" #endif +struct intel_dg_nvm_dev; struct xe_ggtt; struct xe_pat_ops; struct xe_pxp; @@ -319,6 +320,8 @@ struct xe_device { u8 has_fan_control:1; /** @info.has_flat_ccs: Whether flat CCS metadata is used */ u8 has_flat_ccs:1; + /** @info.has_gsc_nvm: Device has gsc non-volatile memory */ + u8 has_gsc_nvm:1; /** @info.has_heci_cscfi: device has heci cscfi */ u8 has_heci_cscfi:1; /** @info.has_heci_gscfi: device has heci gscfi */ @@ -542,6 +545,9 @@ struct xe_device { /** @heci_gsc: graphics security controller */ struct xe_heci_gsc heci_gsc; + /** @nvm: discrete graphics non-volatile memory */ + struct intel_dg_nvm_dev *nvm; + /** @oa: oa observation subsystem */ struct xe_oa oa; diff --git a/drivers/gpu/drm/xe/xe_nvm.c b/drivers/gpu/drm/xe/xe_nvm.c new file mode 100644 index ..26de7d4472c8 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_nvm.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright(c) 2019-2025, Intel Corporation. All rights reserved. + */ + +#include +#include + +#include "xe_device_types.h" +#include "xe_nvm.h" +#include "xe_sriov.h" + +#define GEN12_GUNIT_NVM_BASE 0x00102040 +#define GEN12_GUNIT_NVM_SIZE 0x80 +#define HECI_FW_STATUS_2_NVM_ACCESS_MODE BIT(3) + +static const struct intel_dg_nvm_region regions[INTEL_DG_NVM_REGIONS] = { + [0] = { .name = "DESCRIPTOR", }, + [2] = { .name = "GSC", }, + [11] = { .name = "OptionROM", }, + [12] = { .name = "DAM", }, +}; + +static void xe_nvm_release_dev(struct device *dev) +{ +} + +void xe_nvm_init(struct xe_device *xe) +{ + struct pci_dev *pdev = to_pci_dev(xe->drm.dev); + struct intel_dg_nvm_dev *nvm; + struct auxiliary_device *aux_dev; + int ret; + + if (!xe->info.has_gsc_nvm) + return; + + /* No access to internal NVM from VFs */ + if (IS_SRIOV_VF(xe)) + return; + + /* Nvm pointer should be NULL here */ + if (WARN_ON(xe->nvm)) + return; + + xe->nvm = kzalloc(sizeof(*nvm), GFP_KERNEL); + if (!xe->nvm) + return; + + nvm = xe->nvm; + + nvm->writeable_override = false; + nvm->bar.parent = &pdev->resource[0]; + nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start; + nvm->bar.end = nvm->bar.start + GEN12_GUNIT_NVM_SIZE - 1; + nvm->bar.flags = IORESOURCE_MEM; + nvm->bar.desc = IORES_DESC_NONE; + nvm->regions = regions; + + aux_dev = &nvm->aux_dev; + + aux_dev->name = "nvm"; + aux_dev->id = (pci_domain_nr(pdev->bus) << 16) | + PCI_DEVID(pdev->bus->number, pdev->devfn); + aux_dev->dev.parent = &pdev->dev; + aux_dev->dev.release = xe_nvm_release_dev;
[PATCH v9 06/12] mtd: intel-dg: align 64bit read and write
GSC NVM controller HW errors on quad access overlapping 1K border. Align 64bit read and write to avoid readq/writeq over 1K border. Acked-by: Miquel Raynal Signed-off-by: Alexander Usyskin --- drivers/mtd/devices/mtd_intel_dg.c | 35 ++ 1 file changed, 35 insertions(+) diff --git a/drivers/mtd/devices/mtd_intel_dg.c b/drivers/mtd/devices/mtd_intel_dg.c index 4023f2ebc344..3535f7b64429 100644 --- a/drivers/mtd/devices/mtd_intel_dg.c +++ b/drivers/mtd/devices/mtd_intel_dg.c @@ -238,6 +238,24 @@ static ssize_t idg_write(struct intel_dg_nvm *nvm, u8 region, len_s -= to_shift; } + if (!IS_ALIGNED(to, sizeof(u64)) && + ((to ^ (to + len_s)) & GENMASK(31, 10))) { + /* +* Workaround reads/writes across 1k-aligned addresses +* (start u32 before 1k, end u32 after) +* as this fails on hardware. +*/ + u32 data; + + memcpy(&data, &buf[0], sizeof(u32)); + idg_nvm_write32(nvm, to, data); + if (idg_nvm_error(nvm)) + return -EIO; + buf += sizeof(u32); + to += sizeof(u32); + len_s -= sizeof(u32); + } + len8 = ALIGN_DOWN(len_s, sizeof(u64)); for (i = 0; i < len8; i += sizeof(u64)) { u64 data; @@ -295,6 +313,23 @@ static ssize_t idg_read(struct intel_dg_nvm *nvm, u8 region, from += from_shift; } + if (!IS_ALIGNED(from, sizeof(u64)) && + ((from ^ (from + len_s)) & GENMASK(31, 10))) { + /* +* Workaround reads/writes across 1k-aligned addresses +* (start u32 before 1k, end u32 after) +* as this fails on hardware. +*/ + u32 data = idg_nvm_read32(nvm, from); + + if (idg_nvm_error(nvm)) + return -EIO; + memcpy(&buf[0], &data, sizeof(data)); + len_s -= sizeof(u32); + buf += sizeof(u32); + from += sizeof(u32); + } + len8 = ALIGN_DOWN(len_s, sizeof(u64)); for (i = 0; i < len8; i += sizeof(u64)) { u64 data = idg_nvm_read64(nvm, from + i); -- 2.43.0
[PATCH v9 05/12] mtd: intel-dg: register with mtd
Register the on-die nvm device with the mtd subsystem. Refcount nvm object on _get and _put mtd callbacks. For erase operation address and size should be 4K aligned. For write operation address and size has to be 4bytes aligned. CC: Rodrigo Vivi CC: Lucas De Marchi Acked-by: Miquel Raynal Co-developed-by: Tomas Winkler Signed-off-by: Tomas Winkler Co-developed-by: Vitaly Lubart Signed-off-by: Vitaly Lubart Signed-off-by: Alexander Usyskin --- drivers/mtd/devices/mtd_intel_dg.c | 230 - 1 file changed, 226 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/devices/mtd_intel_dg.c b/drivers/mtd/devices/mtd_intel_dg.c index 6f67cf966d05..4023f2ebc344 100644 --- a/drivers/mtd/devices/mtd_intel_dg.c +++ b/drivers/mtd/devices/mtd_intel_dg.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -12,6 +13,8 @@ #include #include #include +#include +#include #include #include #include @@ -19,6 +22,8 @@ struct intel_dg_nvm { struct kref refcnt; + struct mtd_info mtd; + struct mutex lock; /* region access lock */ void __iomem *base; size_t size; unsigned int nregions; @@ -177,7 +182,6 @@ static int idg_nvm_is_valid(struct intel_dg_nvm *nvm) return 0; } -__maybe_unused static unsigned int idg_nvm_get_region(const struct intel_dg_nvm *nvm, loff_t from) { unsigned int i; @@ -209,7 +213,6 @@ static ssize_t idg_nvm_rewrite_partial(struct intel_dg_nvm *nvm, loff_t to, return len; } -__maybe_unused static ssize_t idg_write(struct intel_dg_nvm *nvm, u8 region, loff_t to, size_t len, const unsigned char *buf) { @@ -266,7 +269,6 @@ static ssize_t idg_write(struct intel_dg_nvm *nvm, u8 region, return len; } -__maybe_unused static ssize_t idg_read(struct intel_dg_nvm *nvm, u8 region, loff_t from, size_t len, unsigned char *buf) { @@ -325,7 +327,6 @@ static ssize_t idg_read(struct intel_dg_nvm *nvm, u8 region, return len; } -__maybe_unused static ssize_t idg_erase(struct intel_dg_nvm *nvm, u8 region, loff_t from, u64 len, u64 *fail_addr) { @@ -414,6 +415,147 @@ static int intel_dg_nvm_init(struct intel_dg_nvm *nvm, struct device *device) return n; } +static int intel_dg_mtd_erase(struct mtd_info *mtd, struct erase_info *info) +{ + struct intel_dg_nvm *nvm = mtd->priv; + unsigned int idx; + u8 region; + u64 addr; + ssize_t bytes; + loff_t from; + size_t len; + size_t total_len; + + if (WARN_ON(!nvm)) + return -EINVAL; + + if (!IS_ALIGNED(info->addr, SZ_4K) || !IS_ALIGNED(info->len, SZ_4K)) { + dev_err(&mtd->dev, "unaligned erase %llx %llx\n", + info->addr, info->len); + info->fail_addr = MTD_FAIL_ADDR_UNKNOWN; + return -EINVAL; + } + + total_len = info->len; + addr = info->addr; + + guard(mutex)(&nvm->lock); + + while (total_len > 0) { + if (!IS_ALIGNED(addr, SZ_4K) || !IS_ALIGNED(total_len, SZ_4K)) { + dev_err(&mtd->dev, "unaligned erase %llx %zx\n", addr, total_len); + info->fail_addr = addr; + return -ERANGE; + } + + idx = idg_nvm_get_region(nvm, addr); + if (idx >= nvm->nregions) { + dev_err(&mtd->dev, "out of range"); + info->fail_addr = MTD_FAIL_ADDR_UNKNOWN; + return -ERANGE; + } + + from = addr - nvm->regions[idx].offset; + region = nvm->regions[idx].id; + len = total_len; + if (len > nvm->regions[idx].size - from) + len = nvm->regions[idx].size - from; + + dev_dbg(&mtd->dev, "erasing region[%d] %s from %llx len %zx\n", + region, nvm->regions[idx].name, from, len); + + bytes = idg_erase(nvm, region, from, len, &info->fail_addr); + if (bytes < 0) { + dev_dbg(&mtd->dev, "erase failed with %zd\n", bytes); + info->fail_addr += nvm->regions[idx].offset; + return bytes; + } + + addr += len; + total_len -= len; + } + + return 0; +} + +static int intel_dg_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, +size_t *retlen, u_char *buf) +{ + struct intel_dg_nvm *nvm = mtd->priv; + ssize_t ret; + unsigned int idx; + u8 region; + + if (WARN_ON(!nvm)) + return -EINVAL; + + idx = idg_nvm_get_region(nvm, from); + + dev_dbg(&mtd->dev, "reading region[%d] %s from %lld len %zd\n", + nvm->regions[idx].id, nvm->regions[idx].name, from, len); + + if (idx >= n
[PATCH v9 07/12] mtd: intel-dg: wake card on operations
Enable runtime PM in mtd driver to notify graphics driver that whole card should be kept awake while nvm operations are performed through this driver. CC: Lucas De Marchi Acked-by: Karthik Poosa Acked-by: Miquel Raynal Signed-off-by: Alexander Usyskin --- drivers/mtd/devices/mtd_intel_dg.c | 79 +- 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/devices/mtd_intel_dg.c b/drivers/mtd/devices/mtd_intel_dg.c index 3535f7b64429..9f4bb15a03b8 100644 --- a/drivers/mtd/devices/mtd_intel_dg.c +++ b/drivers/mtd/devices/mtd_intel_dg.c @@ -15,11 +15,14 @@ #include #include #include +#include #include #include #include #include +#define INTEL_DG_NVM_RPM_TIMEOUT 500 + struct intel_dg_nvm { struct kref refcnt; struct mtd_info mtd; @@ -460,6 +463,7 @@ static int intel_dg_mtd_erase(struct mtd_info *mtd, struct erase_info *info) loff_t from; size_t len; size_t total_len; + int ret = 0; if (WARN_ON(!nvm)) return -EINVAL; @@ -474,20 +478,28 @@ static int intel_dg_mtd_erase(struct mtd_info *mtd, struct erase_info *info) total_len = info->len; addr = info->addr; + ret = pm_runtime_resume_and_get(&mtd->dev); + if (ret < 0) { + dev_err(&mtd->dev, "rpm: get failed %d\n", ret); + return ret; + } + guard(mutex)(&nvm->lock); while (total_len > 0) { if (!IS_ALIGNED(addr, SZ_4K) || !IS_ALIGNED(total_len, SZ_4K)) { dev_err(&mtd->dev, "unaligned erase %llx %zx\n", addr, total_len); info->fail_addr = addr; - return -ERANGE; + ret = -ERANGE; + goto out; } idx = idg_nvm_get_region(nvm, addr); if (idx >= nvm->nregions) { dev_err(&mtd->dev, "out of range"); info->fail_addr = MTD_FAIL_ADDR_UNKNOWN; - return -ERANGE; + ret = -ERANGE; + goto out; } from = addr - nvm->regions[idx].offset; @@ -503,14 +515,18 @@ static int intel_dg_mtd_erase(struct mtd_info *mtd, struct erase_info *info) if (bytes < 0) { dev_dbg(&mtd->dev, "erase failed with %zd\n", bytes); info->fail_addr += nvm->regions[idx].offset; - return bytes; + ret = bytes; + goto out; } addr += len; total_len -= len; } - return 0; +out: + pm_runtime_mark_last_busy(&mtd->dev); + pm_runtime_put_autosuspend(&mtd->dev); + return ret; } static int intel_dg_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, @@ -539,17 +555,25 @@ static int intel_dg_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, if (len > nvm->regions[idx].size - from) len = nvm->regions[idx].size - from; + ret = pm_runtime_resume_and_get(&mtd->dev); + if (ret < 0) { + dev_err(&mtd->dev, "rpm: get failed %zd\n", ret); + return ret; + } + guard(mutex)(&nvm->lock); ret = idg_read(nvm, region, from, len, buf); if (ret < 0) { dev_dbg(&mtd->dev, "read failed with %zd\n", ret); - return ret; + } else { + *retlen = ret; + ret = 0; } - *retlen = ret; - - return 0; + pm_runtime_mark_last_busy(&mtd->dev); + pm_runtime_put_autosuspend(&mtd->dev); + return ret; } static int intel_dg_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, @@ -578,17 +602,25 @@ static int intel_dg_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, if (len > nvm->regions[idx].size - to) len = nvm->regions[idx].size - to; + ret = pm_runtime_resume_and_get(&mtd->dev); + if (ret < 0) { + dev_err(&mtd->dev, "rpm: get failed %zd\n", ret); + return ret; + } + guard(mutex)(&nvm->lock); ret = idg_write(nvm, region, to, len, buf); if (ret < 0) { dev_dbg(&mtd->dev, "write failed with %zd\n", ret); - return ret; + } else { + *retlen = ret; + ret = 0; } - *retlen = ret; - - return 0; + pm_runtime_mark_last_busy(&mtd->dev); + pm_runtime_put_autosuspend(&mtd->dev); + return ret; } static void intel_dg_nvm_release(struct kref *kref) @@ -670,6 +702,15 @@ static int intel_dg_nvm_init_mtd(struct intel_dg_nvm *nvm, struct device *device kfree(parts); + if (ret) + goto out; + + devm_pm_runtime_enable(&nvm->mtd.dev); + + pm_runtime_set_autosuspe
[PATCH v9 04/12] mtd: intel-dg: implement access functions
Implement read(), erase() and write() functions. CC: Lucas De Marchi CC: Rodrigo Vivi Acked-by: Miquel Raynal Co-developed-by: Tomas Winkler Signed-off-by: Tomas Winkler Co-developed-by: Vitaly Lubart Signed-off-by: Vitaly Lubart Signed-off-by: Alexander Usyskin --- drivers/mtd/devices/mtd_intel_dg.c | 197 + 1 file changed, 197 insertions(+) diff --git a/drivers/mtd/devices/mtd_intel_dg.c b/drivers/mtd/devices/mtd_intel_dg.c index ba1c720e717b..6f67cf966d05 100644 --- a/drivers/mtd/devices/mtd_intel_dg.c +++ b/drivers/mtd/devices/mtd_intel_dg.c @@ -5,13 +5,16 @@ #include #include +#include #include #include #include +#include #include #include #include #include +#include #include struct intel_dg_nvm { @@ -91,6 +94,33 @@ static inline u32 idg_nvm_read32(struct intel_dg_nvm *nvm, u32 address) return ioread32(base + NVM_TRIGGER_REG); } +static inline u64 idg_nvm_read64(struct intel_dg_nvm *nvm, u32 address) +{ + void __iomem *base = nvm->base; + + iowrite32(address, base + NVM_ADDRESS_REG); + + return readq(base + NVM_TRIGGER_REG); +} + +static void idg_nvm_write32(struct intel_dg_nvm *nvm, u32 address, u32 data) +{ + void __iomem *base = nvm->base; + + iowrite32(address, base + NVM_ADDRESS_REG); + + iowrite32(data, base + NVM_TRIGGER_REG); +} + +static void idg_nvm_write64(struct intel_dg_nvm *nvm, u32 address, u64 data) +{ + void __iomem *base = nvm->base; + + iowrite32(address, base + NVM_ADDRESS_REG); + + writeq(data, base + NVM_TRIGGER_REG); +} + static int idg_nvm_get_access_map(struct intel_dg_nvm *nvm, u32 *access_map) { u32 flmap1; @@ -147,6 +177,173 @@ static int idg_nvm_is_valid(struct intel_dg_nvm *nvm) return 0; } +__maybe_unused +static unsigned int idg_nvm_get_region(const struct intel_dg_nvm *nvm, loff_t from) +{ + unsigned int i; + + for (i = 0; i < nvm->nregions; i++) { + if ((nvm->regions[i].offset + nvm->regions[i].size - 1) > from && + nvm->regions[i].offset <= from && + nvm->regions[i].size != 0) + break; + } + + return i; +} + +static ssize_t idg_nvm_rewrite_partial(struct intel_dg_nvm *nvm, loff_t to, + loff_t offset, size_t len, const u32 *newdata) +{ + u32 data = idg_nvm_read32(nvm, to); + + if (idg_nvm_error(nvm)) + return -EIO; + + memcpy((u8 *)&data + offset, newdata, len); + + idg_nvm_write32(nvm, to, data); + if (idg_nvm_error(nvm)) + return -EIO; + + return len; +} + +__maybe_unused +static ssize_t idg_write(struct intel_dg_nvm *nvm, u8 region, +loff_t to, size_t len, const unsigned char *buf) +{ + size_t i; + size_t len8; + size_t len4; + size_t to4; + size_t to_shift; + size_t len_s = len; + ssize_t ret; + + idg_nvm_set_region_id(nvm, region); + + to4 = ALIGN_DOWN(to, sizeof(u32)); + to_shift = min(sizeof(u32) - ((size_t)to - to4), len); + if (to - to4) { + ret = idg_nvm_rewrite_partial(nvm, to4, to - to4, to_shift, (uint32_t *)&buf[0]); + if (ret < 0) + return ret; + + buf += to_shift; + to += to_shift; + len_s -= to_shift; + } + + len8 = ALIGN_DOWN(len_s, sizeof(u64)); + for (i = 0; i < len8; i += sizeof(u64)) { + u64 data; + + memcpy(&data, &buf[i], sizeof(u64)); + idg_nvm_write64(nvm, to + i, data); + if (idg_nvm_error(nvm)) + return -EIO; + } + + len4 = len_s - len8; + if (len4 >= sizeof(u32)) { + u32 data; + + memcpy(&data, &buf[i], sizeof(u32)); + idg_nvm_write32(nvm, to + i, data); + if (idg_nvm_error(nvm)) + return -EIO; + i += sizeof(u32); + len4 -= sizeof(u32); + } + + if (len4 > 0) { + ret = idg_nvm_rewrite_partial(nvm, to + i, 0, len4, (uint32_t *)&buf[i]); + if (ret < 0) + return ret; + } + + return len; +} + +__maybe_unused +static ssize_t idg_read(struct intel_dg_nvm *nvm, u8 region, + loff_t from, size_t len, unsigned char *buf) +{ + size_t i; + size_t len8; + size_t len4; + size_t from4; + size_t from_shift; + size_t len_s = len; + + idg_nvm_set_region_id(nvm, region); + + from4 = ALIGN_DOWN(from, sizeof(u32)); + from_shift = min(sizeof(u32) - ((size_t)from - from4), len); + + if (from - from4) { + u32 data = idg_nvm_read32(nvm, from4); + + if (idg_nvm_error(nvm)) + return -EIO; + memcpy(&buf[0],
[PATCH v9 08/12] drm/i915/nvm: add nvm device for discrete graphics
Enable access to internal non-volatile memory on DGFX devices via a child device. The nvm child device is exposed via auxiliary bus. CC: Lucas De Marchi Reviewed-by: Rodrigo Vivi Acked-by: Rodrigo Vivi Co-developed-by: Tomas Winkler Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin --- drivers/gpu/drm/i915/Makefile | 4 ++ drivers/gpu/drm/i915/i915_driver.c | 6 ++ drivers/gpu/drm/i915/i915_drv.h| 3 + drivers/gpu/drm/i915/i915_reg.h| 1 + drivers/gpu/drm/i915/intel_nvm.c | 92 ++ drivers/gpu/drm/i915/intel_nvm.h | 15 + 6 files changed, 121 insertions(+) create mode 100644 drivers/gpu/drm/i915/intel_nvm.c create mode 100644 drivers/gpu/drm/i915/intel_nvm.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 13d4a16f7d33..d9bb89cce0c9 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -212,6 +212,10 @@ i915-y += \ i915-y += \ gt/intel_gsc.o +# graphics nvm device (DGFX) support +i915-y += \ + intel_nvm.o + # graphics hardware monitoring (HWMON) support i915-$(CONFIG_HWMON) += \ i915_hwmon.o diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 97ff9855b5de..263ca12b96ae 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -83,6 +83,8 @@ #include "soc/intel_dram.h" #include "soc/intel_gmch.h" +#include "intel_nvm.h" + #include "i915_debugfs.h" #include "i915_driver.h" #include "i915_drm_client.h" @@ -648,6 +650,8 @@ static int i915_driver_register(struct drm_i915_private *dev_priv) /* Depends on sysfs having been initialized */ i915_perf_register(dev_priv); + intel_nvm_init(dev_priv); + for_each_gt(gt, dev_priv, i) intel_gt_driver_register(gt); @@ -690,6 +694,8 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) i915_hwmon_unregister(dev_priv); + intel_nvm_fini(dev_priv); + i915_perf_unregister(dev_priv); i915_pmu_unregister(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c0eec8fe5cad..bb879dc9764b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -65,6 +65,7 @@ struct drm_i915_clock_gating_funcs; struct vlv_s0ix_state; struct intel_pxp; +struct intel_dg_nvm_dev; #define GEM_QUIRK_PIN_SWIZZLED_PAGES BIT(0) @@ -311,6 +312,8 @@ struct drm_i915_private { struct i915_perf perf; + struct intel_dg_nvm_dev *nvm; + struct i915_hwmon *hwmon; struct intel_gt *gt[I915_MAX_GT]; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 88c46a7c948f..68ded276c844 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -321,6 +321,7 @@ #define DG2_GSC_HECI2_BASE 0x00374000 #define MTL_GSC_HECI1_BASE 0x00116000 #define MTL_GSC_HECI2_BASE 0x00117000 +#define GEN12_GUNIT_NVM_BASE 0x00102040 #define HECI_H_CSR(base) _MMIO((base) + 0x4) #define HECI_H_CSR_IEREG_BIT(0) diff --git a/drivers/gpu/drm/i915/intel_nvm.c b/drivers/gpu/drm/i915/intel_nvm.c new file mode 100644 index ..75d3ebe669ff --- /dev/null +++ b/drivers/gpu/drm/i915/intel_nvm.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright(c) 2019-2024, Intel Corporation. All rights reserved. + */ + +#include +#include +#include "i915_reg.h" +#include "i915_drv.h" +#include "intel_nvm.h" + +#define GEN12_GUNIT_NVM_SIZE 0x80 + +static const struct intel_dg_nvm_region regions[INTEL_DG_NVM_REGIONS] = { + [0] = { .name = "DESCRIPTOR", }, + [2] = { .name = "GSC", }, + [11] = { .name = "OptionROM", }, + [12] = { .name = "DAM", }, +}; + +static void i915_nvm_release_dev(struct device *dev) +{ +} + +void intel_nvm_init(struct drm_i915_private *i915) +{ + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); + struct intel_dg_nvm_dev *nvm; + struct auxiliary_device *aux_dev; + int ret; + + /* Only the DGFX devices have internal NVM */ + if (!IS_DGFX(i915)) + return; + + /* Nvm pointer should be NULL here */ + if (WARN_ON(i915->nvm)) + return; + + i915->nvm = kzalloc(sizeof(*nvm), GFP_KERNEL); + if (!i915->nvm) + return; + + nvm = i915->nvm; + + nvm->writeable_override = true; + nvm->bar.parent = &pdev->resource[0]; + nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start; + nvm->bar.end = nvm->bar.start + GEN12_GUNIT_NVM_SIZE - 1; + nvm->bar.flags = IORESOURCE_MEM; + nvm->bar.desc = IORES_DESC_NONE; + nvm->regions = regions; + + aux_dev = &nvm->aux_dev; + + aux_dev->name = "nvm"; + aux_dev->id = (pci_domain_nr(pdev->bus) << 16) | + PCI_DEVID(pdev->bus->number, pde
[PATCH v9 09/12] drm/i915/nvm: add support for access mode
Check NVM access mode from GSC FW status registers and overwrite access status read from SPI descriptor, if needed. Reviewed-by: Rodrigo Vivi Acked-by: Rodrigo Vivi Signed-off-by: Alexander Usyskin --- drivers/gpu/drm/i915/intel_nvm.c | 25 - 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_nvm.c b/drivers/gpu/drm/i915/intel_nvm.c index 75d3ebe669ff..dd3999c934a7 100644 --- a/drivers/gpu/drm/i915/intel_nvm.c +++ b/drivers/gpu/drm/i915/intel_nvm.c @@ -10,6 +10,7 @@ #include "intel_nvm.h" #define GEN12_GUNIT_NVM_SIZE 0x80 +#define HECI_FW_STATUS_2_NVM_ACCESS_MODE BIT(3) static const struct intel_dg_nvm_region regions[INTEL_DG_NVM_REGIONS] = { [0] = { .name = "DESCRIPTOR", }, @@ -22,6 +23,28 @@ static void i915_nvm_release_dev(struct device *dev) { } +static bool i915_nvm_writable_override(struct drm_i915_private *i915) +{ + resource_size_t base; + bool writable_override; + + if (IS_DG1(i915)) { + base = DG1_GSC_HECI2_BASE; + } else if (IS_DG2(i915)) { + base = DG2_GSC_HECI2_BASE; + } else { + drm_err(&i915->drm, "Unknown platform\n"); + return true; + } + + writable_override = + !(intel_uncore_read(&i915->uncore, HECI_FWSTS(base, 2)) & + HECI_FW_STATUS_2_NVM_ACCESS_MODE); + if (writable_override) + drm_info(&i915->drm, "NVM access overridden by jumper\n"); + return writable_override; +} + void intel_nvm_init(struct drm_i915_private *i915) { struct pci_dev *pdev = to_pci_dev(i915->drm.dev); @@ -43,7 +66,7 @@ void intel_nvm_init(struct drm_i915_private *i915) nvm = i915->nvm; - nvm->writeable_override = true; + nvm->writable_override = i915_nvm_writable_override(i915); nvm->bar.parent = &pdev->resource[0]; nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start; nvm->bar.end = nvm->bar.start + GEN12_GUNIT_NVM_SIZE - 1; -- 2.43.0
Re: [PATCH v2] drm/amdgpu: check a user-provided number of BOs in list
On Wed, Apr 23, 2025 at 10:29 AM Christian König wrote: > > On 4/22/25 18:26, Deucher, Alexander wrote: > > [Public] > > > >> -Original Message- > >> From: Alex Deucher > >> Sent: Tuesday, April 22, 2025 9:46 AM > >> To: Koenig, Christian > >> Cc: Denis Arefev ; Deucher, Alexander > >> ; David Airlie ; Simona > >> Vetter > >> ; Andrey Grodzovsky ; > >> Chunming Zhou ; amd-...@lists.freedesktop.org; dri- > >> de...@lists.freedesktop.org; linux-ker...@vger.kernel.org; lvc- > >> proj...@linuxtesting.org; sta...@vger.kernel.org > >> Subject: Re: [PATCH v2] drm/amdgpu: check a user-provided number of BOs in > >> list > >> > >> Applied. Thanks! > > > > This change beaks the following IGT tests: > > > > igt@amdgpu/amd_vcn@vcn-decoder-create-decode-destroy@vcn-decoder-create > > igt@amdgpu/amd_vcn@vcn-decoder-create-decode-destroy@vcn-decoder-decode > > igt@amdgpu/amd_vcn@vcn-decoder-create-decode-destroy@vcn-decoder-destroy > > igt@amdgpu/amd_jpeg_dec@amdgpu_cs_jpeg_decode > > igt@amdgpu/amd_cs_nop@cs-nops-with-nop-compute0@cs-nop-with-nop-compute0 > > igt@amdgpu/amd_cs_nop@cs-nops-with-sync-compute0@cs-nop-with-sync-compute0 > > igt@amdgpu/amd_cs_nop@cs-nops-with-fork-compute0@cs-nop-with-fork-compute0 > > igt@amdgpu/amd_cs_nop@cs-nops-with-sync-fork-compute0@cs-nop-with-sync-fork-compute0 > > igt@amdgpu/amd_basic@userptr-with-ip-dma@userptr > > igt@amdgpu/amd_basic@cs-compute-with-ip-compute@cs-compute > > igt@amdgpu/amd_basic@cs-sdma-with-ip-dma@cs-sdma > > igt@amdgpu/amd_basic@eviction-test-with-ip-dma@eviction_test > > igt@amdgpu/amd_cp_dma_misc@gtt_to_vram-amdgpu_hw_ip_compute0 > > igt@amdgpu/amd_cp_dma_misc@vram_to_gtt-amdgpu_hw_ip_compute0 > > igt@amdgpu/amd_cp_dma_misc@vram_to_vram-amdgpu_hw_ip_compute0 > > > Could it be that we used BO list with zero entries for those? Yes. Dropping the 0 check fixed them. E.g., + if (in->bo_number > USHRT_MAX) + return -EINVAL; Alex > > Christian. > > > > > Alex > > > >> > >> On Tue, Apr 22, 2025 at 5:13 AM Koenig, Christian > >> > >> wrote: > >>> > >>> [AMD Official Use Only - AMD Internal Distribution Only] > >>> > >>> Reviewed-by: Christian König > >>> > >>> > >>> Von: Denis Arefev > >>> Gesendet: Freitag, 18. April 2025 10:31 > >>> An: Deucher, Alexander > >>> Cc: Koenig, Christian; David Airlie; Simona Vetter; Andrey Grodzovsky; > >>> Chunming Zhou; amd-...@lists.freedesktop.org; > >>> dri-devel@lists.freedesktop.org; linux-ker...@vger.kernel.org; > >>> lvc-proj...@linuxtesting.org; sta...@vger.kernel.org > >>> Betreff: [PATCH v2] drm/amdgpu: check a user-provided number of BOs in > >>> list > >>> > >>> The user can set any value to the variable ‘bo_number’, via the ioctl > >>> command DRM_IOCTL_AMDGPU_BO_LIST. This will affect the arithmetic > >>> expression ‘in->bo_number * in->bo_info_size’, which is prone to > >>> overflow. Add a valid value check. > >>> > >>> Found by Linux Verification Center (linuxtesting.org) with SVACE. > >>> > >>> Fixes: 964d0fbf6301 ("drm/amdgpu: Allow to create BO lists in CS ioctl > >>> v3") > >>> Cc: sta...@vger.kernel.org > >>> Signed-off-by: Denis Arefev > >>> --- > >>> V1 -> V2: > >>> Set a reasonable limit 'USHRT_MAX' for 'bo_number' it as Christian > >>> König suggested > >>> > >>> drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 3 +++ > >>> 1 file changed, 3 insertions(+) > >>> > >>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c > >>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c > >>> index 702f6610d024..85f7ee1e085d 100644 > >>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c > >>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c > >>> @@ -189,6 +189,9 @@ int amdgpu_bo_create_list_entry_array(struct > >> drm_amdgpu_bo_list_in *in, > >>> struct drm_amdgpu_bo_list_entry *info; > >>> int r; > >>> > >>> + if (!in->bo_number || in->bo_number > USHRT_MAX) > >>> + return -EINVAL; > >>> + > >>> info = kvmalloc_array(in->bo_number, info_size, GFP_KERNEL); > >>> if (!info) > >>> return -ENOMEM; > >>> -- > >>> 2.43.0 > >>> >
[PATCH v9 12/12] drm/xe/nvm: add support for non-posted erase
From: Reuven Abliyev Erase command is slow on discrete graphics storage and may overshot PCI completion timeout. BMG introduces the ability to have non-posted erase. Add driver support for non-posted erase with polling for erase completion. Reviewed-by: Rodrigo Vivi Acked-by: Rodrigo Vivi Signed-off-by: Reuven Abliyev Signed-off-by: Alexander Usyskin --- drivers/gpu/drm/xe/xe_nvm.c| 25 + drivers/mtd/devices/mtd_intel_dg.c | 43 -- include/linux/intel_dg_nvm_aux.h | 2 ++ 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_nvm.c b/drivers/gpu/drm/xe/xe_nvm.c index 8aec20bc629a..dd91f2e37661 100644 --- a/drivers/gpu/drm/xe/xe_nvm.c +++ b/drivers/gpu/drm/xe/xe_nvm.c @@ -14,7 +14,15 @@ #include "xe_sriov.h" #define GEN12_GUNIT_NVM_BASE 0x00102040 +#define GEN12_DEBUG_NVM_BASE 0x00101018 + +#define GEN12_CNTL_PROTECTED_NVM_REG 0x0010100C + #define GEN12_GUNIT_NVM_SIZE 0x80 +#define GEN12_DEBUG_NVM_SIZE 0x4 + +#define NVM_NON_POSTED_ERASE_CHICKEN_BIT BIT(13) + #define HECI_FW_STATUS_2_NVM_ACCESS_MODE BIT(3) static const struct intel_dg_nvm_region regions[INTEL_DG_NVM_REGIONS] = { @@ -28,6 +36,16 @@ static void xe_nvm_release_dev(struct device *dev) { } +static bool xe_nvm_non_posted_erase(struct xe_device *xe) +{ + struct xe_gt *gt = xe_root_mmio_gt(xe); + + if (xe->info.platform != XE_BATTLEMAGE) + return false; + return !(xe_mmio_read32(>->mmio, XE_REG(GEN12_CNTL_PROTECTED_NVM_REG)) & +NVM_NON_POSTED_ERASE_CHICKEN_BIT); +} + static bool xe_nvm_writable_override(struct xe_device *xe) { struct xe_gt *gt = xe_root_mmio_gt(xe); @@ -85,6 +103,7 @@ void xe_nvm_init(struct xe_device *xe) nvm = xe->nvm; nvm->writable_override = xe_nvm_writable_override(xe); + nvm->non_posted_erase = xe_nvm_non_posted_erase(xe); nvm->bar.parent = &pdev->resource[0]; nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start; nvm->bar.end = nvm->bar.start + GEN12_GUNIT_NVM_SIZE - 1; @@ -92,6 +111,12 @@ void xe_nvm_init(struct xe_device *xe) nvm->bar.desc = IORES_DESC_NONE; nvm->regions = regions; + nvm->bar2.parent = &pdev->resource[0]; + nvm->bar2.start = GEN12_DEBUG_NVM_BASE + pdev->resource[0].start; + nvm->bar2.end = nvm->bar2.start + GEN12_DEBUG_NVM_SIZE - 1; + nvm->bar2.flags = IORESOURCE_MEM; + nvm->bar2.desc = IORES_DESC_NONE; + aux_dev = &nvm->aux_dev; aux_dev->name = "nvm"; diff --git a/drivers/mtd/devices/mtd_intel_dg.c b/drivers/mtd/devices/mtd_intel_dg.c index 9f4bb15a03b8..3016e9cab00e 100644 --- a/drivers/mtd/devices/mtd_intel_dg.c +++ b/drivers/mtd/devices/mtd_intel_dg.c @@ -28,6 +28,9 @@ struct intel_dg_nvm { struct mtd_info mtd; struct mutex lock; /* region access lock */ void __iomem *base; + void __iomem *base2; + bool non_posted_erase; + size_t size; unsigned int nregions; struct { @@ -44,6 +47,7 @@ struct intel_dg_nvm { #define NVM_VALSIG_REG0x0010 #define NVM_ADDRESS_REG 0x0040 #define NVM_REGION_ID_REG 0x0044 +#define NVM_DEBUG_REG 0x /* * [15:0]-Erase size = 0x0010 4K 0x0080 32K 0x0100 64K * [23:16]-Reserved @@ -75,6 +79,9 @@ struct intel_dg_nvm { #define NVM_FREG_ADDR_SHIFT 12 #define NVM_FREG_MIN_REGION_SIZE 0xFFF +#define NVM_NON_POSTED_ERASE_DONE BIT(23) +#define NVM_NON_POSTED_ERASE_DONE_ITER 3000 + static inline void idg_nvm_set_region_id(struct intel_dg_nvm *nvm, u8 region) { iowrite32((u32)region, nvm->base + NVM_REGION_ID_REG); @@ -370,11 +377,30 @@ idg_erase(struct intel_dg_nvm *nvm, u8 region, loff_t from, u64 len, u64 *fail_a { u64 i; const u32 block = 0x10; + u32 reg; + u32 iter = 0; void __iomem *base = nvm->base; + void __iomem *base2 = nvm->base2; for (i = 0; i < len; i += SZ_4K) { iowrite32(from + i, base + NVM_ADDRESS_REG); iowrite32(region << 24 | block, base + NVM_ERASE_REG); + if (nvm->non_posted_erase) { + /* Wait for Erase Done */ + reg = ioread32(base2 + NVM_DEBUG_REG); + while (!(reg & NVM_NON_POSTED_ERASE_DONE) && + ++iter < NVM_NON_POSTED_ERASE_DONE_ITER) { + msleep(10); + reg = ioread32(base2 + NVM_DEBUG_REG); + } + if (reg & NVM_NON_POSTED_ERASE_DONE) { + /* Clear Erase Done */ + iowrite32(reg, base2 + NVM_DEBUG_REG); + } else { + *fail_addr = from + i; + return -ETIME; + } + } /* Since the
[PATCH RFC v2 3/5] drm/panel: ilitek-ili9881c: Add support for two-lane configuration
Enable support for two-lane configuration which is done by setting the LANSEL_SW_EN and LANSEL_SW bits in the Pad Control register. Use the data-lanes device tree parameter to configure the number of lanes. The default configuration remains set to four lanes. Signed-off-by: Kory Maincent --- Change in v2: - Read the data-lanes parameter from the port endpoint and use drm_of_get_data_lanes_count instead of of_property_read_u32. --- drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 33 +-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 28cd7560e5db1d5734b10babdb4e4e553c6e07d0..2e38dea28336f445cb6a074dbbec006f0659287a 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -1263,6 +1264,21 @@ static int ili9881c_send_cmd_data(struct ili9881c *ctx, u8 cmd, u8 data) return 0; } +static int ili9881c_set_lanes_cfg(struct ili9881c *ctx) +{ + int ret; + + if (ctx->dsi->lanes != 2) + /* Nothing to do */ + return 0; + + ret = ili9881c_switch_page(ctx, 1); + if (ret) + return ret; + + return ili9881c_send_cmd_data(ctx, 0xB7, 0x3); +} + static int ili9881c_prepare(struct drm_panel *panel) { struct ili9881c *ctx = panel_to_ili9881c(panel); @@ -1295,6 +1311,10 @@ static int ili9881c_prepare(struct drm_panel *panel) return ret; } + ret = ili9881c_set_lanes_cfg(ctx); + if (ret) + return ret; + ret = ili9881c_switch_page(ctx, 0); if (ret) return ret; @@ -1503,8 +1523,9 @@ static const struct drm_panel_funcs ili9881c_funcs = { static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) { + struct device_node *endpoint; struct ili9881c *ctx; - int ret; + int ret, lanes; ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -1545,11 +1566,19 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) if (ret) return ret; + endpoint = of_graph_get_endpoint_by_regs(dsi->dev.of_node, -1, -1); + lanes = drm_of_get_data_lanes_count(endpoint, 2, 4); + of_node_put(endpoint); + if (lanes == -EINVAL) + lanes = 4; + else if (lanes < 0) + return lanes; + drm_panel_add(&ctx->panel); dsi->mode_flags = ctx->desc->mode_flags; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->lanes = 4; + dsi->lanes = lanes; return mipi_dsi_attach(dsi); } -- 2.34.1
[PATCH RFC v2 4/5] dt-bindings: ili9881c: Add Saef SFTO340XC support
Document the compatible value for Saef SFTO340XC panels. Signed-off-by: Kory Maincent --- Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml index 3a897e464178dfc8a7c70e0fafb51184c50a520b..1e6845454e23bb37f1f7adffd99cd17a5effe68e 100644 --- a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml @@ -19,6 +19,7 @@ properties: - ampire,am8001280g - bananapi,lhr050h41 - feixin,k101-im2byl02 + - saef,sfto340xc - startek,kd050hdfia020 - tdo,tl050hdv35 - wanchanglong,w552946aba -- 2.34.1
Re: [PATCH 34/34] drm/bridge: panel: convert to devm_drm_bridge_alloc() API
Hi Maxime, On Tue, 8 Apr 2025 17:51:08 +0200 Maxime Ripard wrote: > Hi, > > On Mon, Apr 07, 2025 at 05:27:39PM +0200, Luca Ceresoli wrote: > > This is the new API for allocating DRM bridges. > > > > The devm lifetime management of this driver is peculiar. The underlying > > device for the panel_bridge is the panel, and the devm lifetime is tied the > > panel device (panel->dev). However the panel_bridge allocation is not > > performed by the panel driver, but rather by a separate entity (typically > > the previous bridge in the encoder chain). > > > > Thus when that separate entoty is destroyed, the panel_bridge is not > > removed automatically by devm, so it is rather done explicitly by calling > > drm_panel_bridge_remove(). This is the function that does devm_kfree() the > > panel_bridge in current code, so update it as well to put the bridge > > reference instead. > > > > Signed-off-by: Luca Ceresoli [...] > > --- a/drivers/gpu/drm/bridge/panel.c > > +++ b/drivers/gpu/drm/bridge/panel.c > > @@ -287,15 +287,14 @@ struct drm_bridge *drm_panel_bridge_add_typed(struct > > drm_panel *panel, > > if (!panel) > > return ERR_PTR(-EINVAL); > > > > - panel_bridge = devm_kzalloc(panel->dev, sizeof(*panel_bridge), > > - GFP_KERNEL); > > - if (!panel_bridge) > > - return ERR_PTR(-ENOMEM); > > + panel_bridge = devm_drm_bridge_alloc(panel->dev, struct panel_bridge, > > bridge, > > +&panel_bridge_bridge_funcs); > > + if (IS_ERR(panel_bridge)) > > + return (void *)panel_bridge; > > > > panel_bridge->connector_type = connector_type; > > panel_bridge->panel = panel; > > > > - panel_bridge->bridge.funcs = &panel_bridge_bridge_funcs; > > panel_bridge->bridge.of_node = panel->dev->of_node; > > panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES; > > panel_bridge->bridge.type = connector_type; > > @@ -327,7 +326,7 @@ void drm_panel_bridge_remove(struct drm_bridge *bridge) > > panel_bridge = drm_bridge_to_panel_bridge(bridge); > > > > drm_bridge_remove(bridge); > > - devm_kfree(panel_bridge->panel->dev, bridge); > > + devm_drm_put_bridge(panel_bridge->panel->dev, bridge); > > } > > EXPORT_SYMBOL(drm_panel_bridge_remove); > > I'm fine with it on principle, but as a temporary measure. > > Now that we have the panel allocation function in place, we can just > allocate a bridge for each panel and don't need drm_panel_bridge_add_* > at all. > > As I was saying before, it doesn't need to happen right now, or before > the rest of your work for hotplug goes in. But this needs to be tackled > at some point. I totally agree this needs to be handled eventually, and also to get there in steps. The current status of this driver is not ideal, so I paid attention to not make it unnecessarily worse when writing this patch. Do you think the current patch is OK for the next step? I'm going to send v2 in a few hours, so don't hesitate to mention any improvements you deem necessary. Luca -- Luca Ceresoli, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
[RFC PATCH] drm/bridge: ti-sn65dsi86: Enable HPD functionality
For TI SoC J784S4, the display pipeline looks like: TIDSS -> CDNS-DSI -> SN65DSI86 -> DisplayConnector -> DisplaySink This requires HPD to detect connection form the connector. By default, the HPD is disabled for eDP. So enable it conditionally based on a new flag 'keep-hpd' as mentioned in the comments in the driver. Signed-off-by: Jayesh Choudhary --- Hello All, Sending this RFC patch to get some thoughts on hpd for sn65dsi86. Now that we have a usecase for hpd in sn65dsi86, I wanted to get some comments on this approach to "NOT DISABLE" hpd in the bridge. As the driver considers the eDP case, it disables hpd by default. So I have added another property in the binding for keeping hpd functionality (the name used is still debatable) and used it in the driver. Is this approach okay? Also should this have a "Fixes" tag? .../bindings/display/bridge/ti,sn65dsi86.yaml | 6 ++ drivers/gpu/drm/bridge/ti-sn65dsi86.c | 14 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml index c93878b6d718..5948be612849 100644 --- a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml +++ b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml @@ -34,6 +34,12 @@ properties: Set if the HPD line on the bridge isn't hooked up to anything or is otherwise unusable. + keep-hpd: +type: boolean +description: + HPD is disabled in the bridge by default. Set it if HPD line makes + sense and is used. + vccio-supply: description: A 1.8V supply that powers the digital IOs. diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index f72675766e01..4081cc957c6c 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -191,6 +191,7 @@ struct ti_sn65dsi86 { u8 ln_polrs; boolcomms_enabled; struct mutexcomms_mutex; + boolkeep_hpd; #if defined(CONFIG_OF_GPIO) struct gpio_chipgchip; @@ -348,12 +349,15 @@ static void ti_sn65dsi86_enable_comms(struct ti_sn65dsi86 *pdata, * 200 ms. We'll assume that the panel driver will have the hardcoded * delay in its prepare and always disable HPD. * -* If HPD somehow makes sense on some future panel we'll have to -* change this to be conditional on someone specifying that HPD should -* be used. +* If needed, use 'keep-hpd' property in the hardware description in +* board file as a conditional specifying that HPD should be used. */ - regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG, HPD_DISABLE, - HPD_DISABLE); + + pdata->keep_hpd = of_property_read_bool(pdata->dev->of_node, "keep-hpd"); + + if (!pdata->keep_hpd) + regmap_update_bits(pdata->regmap, SN_HPD_DISABLE_REG, HPD_DISABLE, + HPD_DISABLE); pdata->comms_enabled = true; -- 2.34.1
Re: [PATCH] fbdev: via: use new GPIO line value setter callbacks
On 4/24/25 10:52, Linus Walleij wrote: On Tue, Apr 8, 2025 at 9:43 AM Bartosz Golaszewski wrote: From: Bartosz Golaszewski struct gpio_chip now has callbacks for setting line values that return an integer, allowing to indicate failures. Convert the driver to using them. Signed-off-by: Bartosz Golaszewski Reviewed-by: Linus Walleij added to fbdev for-next tree. Thanks! Helge
Re: RE: [PATCH] drm/i915/gsc: mei interrupt top half should be in irq disabled context
On 2025-04-24 10:53:31 [+], Chang, Junxiao wrote: > >> This should have a Fixes when generic_handle_irq() was introduced. > > If PREEMPT_RT is disabled, original driver works fine. I prefer to not > add "Fixes:"? PREEMPT_RT is mainline. It deserves the same fixes as other parts of the kernel. Sebastian
Re: [PATCH v6 1/2] drm/display/dp: Export fn to calculate link symbol cycles
On Thu, Apr 24, 2025 at 12:40:14PM +0300, Govindapillai, Vinod wrote: > Hi, > > > On Thu, 2025-04-24 at 13:52 +0530, Arun R Murthy wrote: > > Unify the function to calculate the link symbol cycles for both dsc and > > non-dsc case and export the function so that it can be used in the > > respective platform display drivers for other calculations. > > > > v2: unify the fn for both dsc and non-dsc case (Imre) > > v3: rename drm_dp_link_symbol_cycles to drm_dp_link_data_symbol_cycles > > retain slice_eoc_cycles as is (Imre) > > v4: Expose only drm_dp_link_symbol_cycles() (Imre) > > > > Reviewed-by: Imre Deak > > Signed-off-by: Arun R Murthy > > --- > > drivers/gpu/drm/display/drm_dp_helper.c | 53 > > + > > include/drm/display/drm_dp_helper.h | 2 ++ > > 2 files changed, 36 insertions(+), 19 deletions(-) > > > > diff --git a/drivers/gpu/drm/display/drm_dp_helper.c > > b/drivers/gpu/drm/display/drm_dp_helper.c > > index > > 57828f2b7b5a0582ca4a6f2a9be2d5909fe8ad24..6b451c9053a77e3e3889ae4cef64caaf942247c8 > > 100644 > > --- a/drivers/gpu/drm/display/drm_dp_helper.c > > +++ b/drivers/gpu/drm/display/drm_dp_helper.c > > @@ -4393,8 +4393,9 @@ EXPORT_SYMBOL(drm_panel_dp_aux_backlight); > > #endif > > > > /* See DP Standard v2.1 2.6.4.4.1.1, 2.8.4.4, 2.8.7 */ > > -static int drm_dp_link_symbol_cycles(int lane_count, int pixels, int > > bpp_x16, > > - int symbol_size, bool is_mst) > > +static int drm_dp_link_data_symbol_cycles(int lane_count, int pixels, > > + int bpp_x16, int symbol_size, > > + bool is_mst) > > { > > int cycles = DIV_ROUND_UP(pixels * bpp_x16, 16 * symbol_size * > > lane_count); > > int align = is_mst ? 4 / lane_count : 1; > > @@ -4402,22 +4403,41 @@ static int drm_dp_link_symbol_cycles(int > > lane_count, int pixels, int > > bpp_x16, > > return ALIGN(cycles, align); > > } > > > > -static int drm_dp_link_dsc_symbol_cycles(int lane_count, int pixels, int > > slice_count, > > -int bpp_x16, int symbol_size, bool > > is_mst) > > +/** > > + * drm_dp_link_symbol_cycles - calculate the link symbol count > > with/without dsc > > + * @lane_count: DP link lane count > > + * @pixels: number of pixels in a scanline > > + * @dsc_slice_count: number of slices for DSC or '0' for non-DSC > > + * @bpp_x16: bits per pixel in .4 binary fixed format > > + * @symbol_size: DP symbol size > > + * @is_mst: %true for MST and %false for SST > > + * > > + * Calculate the link symbol cycles for both DSC (@dsc_slice_count !=0) and > > + * non-DSC case (@dsc_slice_count == 0) and return the count. > > + */ > > +int drm_dp_link_symbol_cycles(int lane_count, int pixels, int > > dsc_slice_count, > > + int bpp_x16, int symbol_size, bool is_mst) > > { > > - int slice_pixels = DIV_ROUND_UP(pixels, slice_count); > > - int slice_data_cycles = drm_dp_link_symbol_cycles(lane_count, > > slice_pixels, > > - bpp_x16, symbol_size, > > is_mst); > > - int slice_eoc_cycles = is_mst ? 4 / lane_count : 1; > > + int slice_count = dsc_slice_count ? : 1; > > + int slice_data_cycles = drm_dp_link_data_symbol_cycles(lane_count, > > + pixels, > > + bpp_x16, > > + symbol_size, > > + is_mst); > > Btw, now we pass "pixels" in drm_dp_link_data_symbol_cycles instead of > "pixels / slice_count" in case of dsc as well! Arg, yes, that's a good catch, not sure why that got changed. So int slice_pixels = DIV_ROUND_UP(pixels, slice_count); should be kept, and passed to drm_dp_link_data_symbol_cycles(). > Now I see the some of the modesets for example 6k @60 are failing! > > BR > Vinod > > > + int slice_eoc_cycles = 0; > > + > > + if (dsc_slice_count) > > + slice_eoc_cycles = is_mst ? 4 / lane_count : 1; > > > > return slice_count * (slice_data_cycles + slice_eoc_cycles); > > } > > +EXPORT_SYMBOL(drm_dp_link_symbol_cycles); > > > > /** > > * drm_dp_bw_overhead - Calculate the BW overhead of a DP link stream > > * @lane_count: DP link lane count > > * @hactive: pixel count of the active period in one scanline of the stream > > - * @dsc_slice_count: DSC slice count if @flags/DRM_DP_LINK_BW_OVERHEAD_DSC > > is set > > + * @dsc_slice_count: number of slices for DSC or '0' for non-DSC > > * @bpp_x16: bits per pixel in .4 binary fixed point > > * @flags: DRM_DP_OVERHEAD_x flags > > * > > @@ -4431,7 +4451,7 @@ static int drm_dp_link_dsc_symbol_cycles(int > > lane_count, int pixels, int > > slice_c > > * as well as the stream's > > * - @hactive timing > > * - @bpp_x16 color depth > > - *
[PATCH v1 1/1] atyfb: Remove unused PCI vendor ID
The custom definition of PCI vendor ID in video/mach64.h is unused. Remove it. Note, that the proper one is available in pci_ids.h. Signed-off-by: Andy Shevchenko --- include/video/mach64.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/video/mach64.h b/include/video/mach64.h index d96e3c189634..f1709f7c8421 100644 --- a/include/video/mach64.h +++ b/include/video/mach64.h @@ -934,9 +934,6 @@ #define MEM_BNDRY_EN 0x0004 #define ONE_MB 0x10 -/* ATI PCI constants */ -#define PCI_ATI_VENDOR_ID 0x1002 - /* CNFG_CHIP_ID register constants */ #define CFG_CHIP_TYPE 0x -- 2.47.2
Re: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
Hi Matthew, kernel test robot noticed the following build errors: [auto build test ERROR on drm-xe/drm-xe-next] [also build test ERROR on next-20250424] [cannot apply to drm-exynos/exynos-drm-next linus/master drm/drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-misc/drm-misc-next drm-tip/drm-tip v6.15-rc3] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Matthew-Auld/drm-gpusvm-fix-hmm_pfn_to_map_order-usage/20250424-202128 base: https://gitlab.freedesktop.org/drm/xe/kernel.git drm-xe-next patch link: https://lore.kernel.org/r/20250424121827.862729-15-matthew.auld%40intel.com patch subject: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm config: csky-randconfig-001-20250424 (https://download.01.org/0day-ci/archive/20250424/202504242229.drmsyxrh-...@intel.com/config) compiler: csky-linux-gcc (GCC) 12.4.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250424/202504242229.drmsyxrh-...@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot | Closes: https://lore.kernel.org/oe-kbuild-all/202504242229.drmsyxrh-...@intel.com/ All errors (new ones prefixed by >>): drivers/gpu/drm/drm_gpusvm.c: In function 'drm_gpusvm_get_devmem_page': >> drivers/gpu/drm/drm_gpusvm.c:1709:9: error: implicit declaration of function >> 'zone_device_page_init' [-Werror=implicit-function-declaration] 1709 | zone_device_page_init(page); | ^ cc1: some warnings being treated as errors -- In file included from drivers/gpu/drm/xe/xe_tile.c:16: drivers/gpu/drm/xe/xe_svm.h: In function 'xe_svm_init': >> drivers/gpu/drm/xe/xe_svm.h:137:16: error: implicit declaration of function >> 'drm_gpusvm_init'; did you mean 'drm_mm_init'? >> [-Werror=implicit-function-declaration] 137 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm, |^~~ |drm_mm_init >> drivers/gpu/drm/xe/xe_svm.h:137:35: error: invalid use of undefined type >> 'struct xe_vm' 137 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm, | ^~ drivers/gpu/drm/xe/xe_svm.h:137:71: error: invalid use of undefined type 'struct xe_vm' 137 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm, | ^~ In file included from drivers/gpu/drm/xe/xe_sriov.h:9, from drivers/gpu/drm/xe/xe_device.h:13, from drivers/gpu/drm/xe/xe_tile.c:10: drivers/gpu/drm/xe/xe_svm.h: In function 'xe_svm_fini': drivers/gpu/drm/xe/xe_svm.h:144:21: error: invalid use of undefined type 'struct xe_vm' 144 | xe_assert(vm->xe, xe_vm_is_closed(vm)); | ^~ drivers/gpu/drm/xe/xe_assert.h:110:41: note: in definition of macro 'xe_assert_msg' 110 | const struct xe_device *__xe = (xe); \ | ^~ drivers/gpu/drm/xe/xe_svm.h:144:9: note: in expansion of macro 'xe_assert' 144 | xe_assert(vm->xe, xe_vm_is_closed(vm)); | ^ In file included from include/linux/bits.h:22, from include/linux/gfp_types.h:5, from include/linux/gfp.h:5, from include/drm/drm_managed.h:6, from drivers/gpu/drm/xe/xe_tile.c:8: >> drivers/gpu/drm/xe/xe_svm.h:144:27: error: implicit declaration of function >> 'xe_vm_is_closed' [-Werror=implicit-function-declaration] 144 | xe_assert(vm->xe, xe_vm_is_closed(vm)); | ^~~ include/linux/build_bug.h:30:63: note: in definition of macro 'BUILD_BUG_ON_INVALID' 30 | #define BUILD_BUG_ON_INVALID(e) ((void)(sizeof((__force long)(e | ^ drivers/gpu/drm/xe/xe_assert.h:111:9: note: in expansion of macro '__xe_assert_msg' 111 | __xe_assert_msg(__xe, condition, \ | ^~~ drivers/gpu/drm/xe/xe_assert.h:108
Re: [PATCH v2 2/2] drm/panthor: Fix the user MMIO offset logic for emulators
On 17.04.2025 16:49, Boris Brezillon wrote: > Currently, we pick the MMIO offset based on the size of the pgoff_t > type seen by the process that manipulates the FD, such that a 32-bit > process can always map the user MMIO ranges. But this approach doesn't > work well for emulators like FEX, where the emulator is a 64-bit binary > which might be executing 32-bit code. In that case, the kernel thinks > it's the 64-bit process and assumes DRM_PANTHOR_USER_MMIO_OFFSET_64BIT > is in use, but the UMD library expects DRM_PANTHOR_USER_MMIO_OFFSET_32BIT, > because it can't mmap() anything above the pgoff_t size. > > In order to solve that, we need a way to explicitly set the user MMIO > offset from the UMD, such that the kernel doesn't have to guess it > from the TIF_32BIT flag set on user thread. We keep the old behavior > if DRM_PANTHOR_SET_USER_MMIO_OFFSET is never called. > > Changes: > - Drop the lock/immutable fields and allow SET_USER_MMIO_OFFSET > requests to race with mmap() requests > - Don't do the is_user_mmio_offset test twice in panthor_mmap() > - Improve the uAPI docs > > Signed-off-by: Boris Brezillon Reviewed-by: Adrián Larumbe > --- > drivers/gpu/drm/panthor/panthor_device.h | 18 > drivers/gpu/drm/panthor/panthor_drv.c| 56 +--- > include/uapi/drm/panthor_drm.h | 38 > 3 files changed, 96 insertions(+), 16 deletions(-) > > diff --git a/drivers/gpu/drm/panthor/panthor_device.h > b/drivers/gpu/drm/panthor/panthor_device.h > index 4c27b6d85f46..6d8c2d5042f2 100644 > --- a/drivers/gpu/drm/panthor/panthor_device.h > +++ b/drivers/gpu/drm/panthor/panthor_device.h > @@ -219,6 +219,24 @@ struct panthor_file { > /** @ptdev: Device attached to this file. */ > struct panthor_device *ptdev; > > + /** @user_mmio: User MMIO related fields. */ > + struct { > + /** > + * @offset: Offset used for user MMIO mappings. > + * > + * This offset should not be used to check the type of mapping > + * except in panthor_mmap(). After that point, MMIO mapping > + * offsets have been adjusted to match > + * DRM_PANTHOR_USER_MMIO_OFFSET and this macro should be used > + * instead. > + * Make sure this rule is followed at all times, because > + * userspace is in control of the offset, and can change the > + * value behind out back, potentially leading to erronous > + * branching happening in kernel space. > + */ > + u64 offset; > + } user_mmio; > + > /** @vms: VM pool attached to this file. */ > struct panthor_vm_pool *vms; > > diff --git a/drivers/gpu/drm/panthor/panthor_drv.c > b/drivers/gpu/drm/panthor/panthor_drv.c > index 4d4a52a033f6..aedef2bfa7ac 100644 > --- a/drivers/gpu/drm/panthor/panthor_drv.c > +++ b/drivers/gpu/drm/panthor/panthor_drv.c > @@ -1338,6 +1338,20 @@ static int panthor_ioctl_vm_get_state(struct > drm_device *ddev, void *data, > return 0; > } > > +static int panthor_ioctl_set_user_mmio_offset(struct drm_device *ddev, > + void *data, struct drm_file *file) > +{ > + struct drm_panthor_set_user_mmio_offset *args = data; > + struct panthor_file *pfile = file->driver_priv; > + > + if (args->offset != DRM_PANTHOR_USER_MMIO_OFFSET_32BIT && > + args->offset != DRM_PANTHOR_USER_MMIO_OFFSET_64BIT) > + return -EINVAL; > + > + WRITE_ONCE(pfile->user_mmio.offset, args->offset); > + return 0; > +} > + > static int > panthor_open(struct drm_device *ddev, struct drm_file *file) > { > @@ -1355,6 +1369,18 @@ panthor_open(struct drm_device *ddev, struct drm_file > *file) > } > > pfile->ptdev = ptdev; > + pfile->user_mmio.offset = DRM_PANTHOR_USER_MMIO_OFFSET; > + > +#ifdef CONFIG_ARM64 > + /* > + * With 32-bit systems being limited by the 32-bit representation of > + * mmap2's pgoffset field, we need to make the MMIO offset arch > + * specific. > + */ > + if (test_tsk_thread_flag(current, TIF_32BIT)) > + pfile->user_mmio.offset = DRM_PANTHOR_USER_MMIO_OFFSET_32BIT; > +#endif > + > > ret = panthor_vm_pool_create(pfile); > if (ret) > @@ -1407,6 +1433,7 @@ static const struct drm_ioctl_desc > panthor_drm_driver_ioctls[] = { > PANTHOR_IOCTL(TILER_HEAP_CREATE, tiler_heap_create, DRM_RENDER_ALLOW), > PANTHOR_IOCTL(TILER_HEAP_DESTROY, tiler_heap_destroy, DRM_RENDER_ALLOW), > PANTHOR_IOCTL(GROUP_SUBMIT, group_submit, DRM_RENDER_ALLOW), > + PANTHOR_IOCTL(SET_USER_MMIO_OFFSET, set_user_mmio_offset, > DRM_RENDER_ALLOW), > }; > > static int panthor_mmap(struct file *filp, struct vm_area_struct *vma) > @@ -1415,30 +1442,26 @@ static int panthor_mmap(struct file *filp, struct > vm_area_struct *vma) > struct panthor_file *pfile = file->driver_priv; > struct
Re: [PATCH v2 1/2] drm/panthor: Add missing explicit padding in drm_panthor_gpu_info
On 17.04.2025 16:49, Boris Brezillon wrote: > drm_panthor_gpu_info::shader_present is currently automatically offset > by 4 byte to meet Arm's 32-bit/64-bit field alignment rules, but those > constraints don't stand on 32-bit x86 and cause a mismatch when running > an x86 binary in a user emulated environment like FEX. It's also > generally agreed that uAPIs should explicitly pad their struct fields, > which we originally intended to do, but a mistake slipped through during > the submission process, leading drm_panthor_gpu_info::shader_present to > be misaligned. > > This uAPI change doesn't break any of the existing users of panthor > which are either arm32 or arm64 where the 64-bit alignment of > u64 fields is already enforced a the compiler level. > > Changes in v2: > - Rename the garbage field into pad0 and adjust the comment accordingly > - Add Liviu's R-b > > Fixes: 0f25e493a246 ("drm/panthor: Add uAPI") > Signed-off-by: Boris Brezillon > Acked-by: Liviu Dudau Reviewed-by: Adrián Larumbe > --- > include/uapi/drm/panthor_drm.h | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/include/uapi/drm/panthor_drm.h b/include/uapi/drm/panthor_drm.h > index 97e2c4510e69..dbb907eae443 100644 > --- a/include/uapi/drm/panthor_drm.h > +++ b/include/uapi/drm/panthor_drm.h > @@ -293,6 +293,9 @@ struct drm_panthor_gpu_info { > /** @as_present: Bitmask encoding the number of address-space exposed > by the MMU. */ > __u32 as_present; > > + /** @pad0: MBZ. */ > + __u32 pad0; > + > /** @shader_present: Bitmask encoding the shader cores exposed by the > GPU. */ > __u64 shader_present; > > -- > 2.49.0 Adrian Larumbe
Re:Re:Re: [PATCH v4] drm/rockchip: Disable AFBC for res >2560 on rk3399
Hi, Andy and Daniel! What is the status of this one? I've noticed it went to archived. Is it good to go or not? Any further recommendations? Thank you, Konstantin
Re: [PATCH] drm/panthor: fix building without CONFIG_DEBUG_FS
On Thu, Apr 24, 2025, at 13:41, Boris Brezillon wrote: > On Thu, 24 Apr 2025 13:25:47 +0200 >> +#ifdef CONFIG_DEBUG_FS >> bo->debugfs.flags = usage_flags | >> PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED; >> -} >> - >> -#else >> -void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 >> usage_flags) {}; >> #endif >> +} >> > > Oops. I actually don't see a good reason to expose this function, so > could we go for something like that instead? I think moving it into pantor_gem.c makes sense, and it certainly avoids the build warning. > #else > static void panthor_gem_debugfs_bo_add(struct panthor_device *ptdev, >struct panthor_gem_object *bo) > {} > static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) {} > +static void panthor_gem_debugfs_set_usage_flags(struct > panthor_gem_object *bo, > + u32 usage_flags) > +{ Side note: I think the panthor_gem_debugfs_bo_{add,rm} stubs could actually be replaced with an IS_ENABLED() check in the normal functions, but that wouldn't work for panthor_gem_debugfs_set_usage_flags or panthor_gem_debugfs_print_bos(). Arnd
Re: [PATCH 29/34] drm: zynqmp_dp: convert to devm_drm_bridge_alloc() API
Hello Tomi, On Wed, 16 Apr 2025 15:31:41 +0300 Tomi Valkeinen wrote: > Hi, > > On 07/04/2025 17:23, Luca Ceresoli wrote: > > This is the new API for allocating DRM bridges. > > > > This driver has a peculiar structure. zynqmp_dpsub.c is the actual driver, > > which delegates to a submodule (zynqmp_dp.c) the allocation of a > > sub-structure embedding the drm_bridge and its initialization, however it > > does not delegate the drm_bridge_add(). Hence, following carefully the code > > flow, it is correct to change the allocation function and .funcs assignment > > in the submodule, while the drm_bridge_add() is not in that submodule. > > > > Signed-off-by: Luca Ceresoli [...] > To add to my last mail, this clearly cannot be right, as it changes > kzalloc call to devm_* call, without removing the kfree()s... Thank you very much for having tested this patch and found the mistake! I have checked all other patches in the series and found no other instance of this specific flaw, but a couple flaws of a different nature. I'm now fixing all of them and will send v2 later today. Luca -- Luca Ceresoli, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
Re: amdgpu_dm_connector_mode_valid regression
On Thu, Apr 24, 2025 at 4:49 AM Marek Marczykowski-Górecki wrote: > > On Fri, Apr 11, 2025 at 12:01:28PM +0200, Marek Marczykowski-Górecki wrote: > > > > Hi, > > > > On Wed, Apr 02, 2025 at 04:35:05PM +0200, Gergo Koteles wrote: > > > Hi Dmitry, > > > > > > But the code would start to become quite untraceable. > > > duplicate mode in amdgpu_dm_connector_mode_valid() > > > call drm_mode_set_crtcinfo() in amdgpu_dm_connector_mode_valid() > > > duplicate mode in create_stream_for_sink() > > > overwrite ctrc in decide_crtc_timing_for_drm_display_mode() > > > if crtc_clock == 0 call drm_mode_set_crtcinfo() again in > > > create_stream_for_sink() > > > > FWIW I'm affected by the same issue (on HP ProBook 445 G7, with AMD > > Ryzen 5 4500U). And the patch quoted below fixes it for me too. > > I've re-tested it with 6.15-rc3 and the issue is still there. Is there > something I can do to help fixing it before final 6.15 is out? I believe this should be fixed in this patch which is already in this week's -fixes PR: https://gitlab.freedesktop.org/agd5f/linux/-/commit/b316727a27d0dac1e6b7ae51204df4d0f241fcc2 Alex > > -- > Best Regards, > Marek Marczykowski-Górecki > Invisible Things Lab
Re: [PATCH 4/4] drm/nouveau: Check dma_fence in canonical way
On 4/24/25 3:02 PM, Philipp Stanner wrote: In nouveau_fence_done(), a fence is checked for being signaled by manually evaluating the base fence's bits. This can be done in a canonical manner through dma_fence_is_signaled(). Replace the bit-check with dma_fence_is_signaled(). Signed-off-by: Philipp Stanner --- drivers/gpu/drm/nouveau/nouveau_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index fb9811938c82..d5654e26d5bc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -253,7 +253,7 @@ nouveau_fence_done(struct nouveau_fence *fence) struct nouveau_channel *chan; unsigned long flags; - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) + if (dma_fence_is_signaled(&fence->base)) This is only correct with commit bbe5679f30d7 ("drm/nouveau: Fix WARN_ON in nouveau_fence_context_kill()") from drm-misc-fixes, correct?
[PATCH 3/4] drm/nouveau: Simplify nouveau_fence_done()
nouveau_fence_done() contains an if branch that checks whether a nouveau_fence has either of the two existing nouveau_fence backend ops, which will always evaluate to true. Remove the surplus check. Signed-off-by: Philipp Stanner --- drivers/gpu/drm/nouveau/nouveau_fence.c | 24 +++- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 2b79bcb7da16..fb9811938c82 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -249,21 +249,19 @@ nouveau_fence_emit(struct nouveau_fence *fence) bool nouveau_fence_done(struct nouveau_fence *fence) { - if (fence->base.ops == &nouveau_fence_ops_legacy || - fence->base.ops == &nouveau_fence_ops_uevent) { - struct nouveau_fence_chan *fctx = nouveau_fctx(fence); - struct nouveau_channel *chan; - unsigned long flags; + struct nouveau_fence_chan *fctx = nouveau_fctx(fence); + struct nouveau_channel *chan; + unsigned long flags; - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) - return true; + if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) + return true; + + spin_lock_irqsave(&fctx->lock, flags); + chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); + if (chan) + nouveau_fence_update(chan, fctx); + spin_unlock_irqrestore(&fctx->lock, flags); - spin_lock_irqsave(&fctx->lock, flags); - chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); - if (chan) - nouveau_fence_update(chan, fctx); - spin_unlock_irqrestore(&fctx->lock, flags); - } return dma_fence_is_signaled(&fence->base); } -- 2.48.1
Re: [PATCH] drm: drm_fourcc: add 10/12bit software decoder YCbCr formats
On Thu, Apr 24, 2025 at 02:53:18PM +0200, Robert Mader wrote: > Chris, Javier, Laurent - sorry for the noise, but given you reviewed > changes in the respective files before, maybe you can help me moving > this forward? I'd be very happy for any feedback to get this landed, > thanks! :) I don't have spare bandwidth at the moment, sorry :-( One comment below though. Tomi, can you check if there's any overlap with the formats you're adding for the Xilinx FPGA drivers ? > On 07.04.25 21:13, Robert Mader wrote: > > This adds FOURCCs for 10/12bit YCbCr formats used by software decoders > > like ffmpeg, dav1d and libvpx. The intended use-case is buffer sharing > > between SW-decoders and GPUs by allocating buffers with udmabuf or > > dma-heaps, avoiding unnecessary copies or format conversions. > > > > Unlike formats typically used by hardware decoders these formats > > use a LSB alignment. In order to allow fast implementations in GL > > and Vulkan the padding must contain only zeros, so the float > > representation can calculated by simple multiplicating with 2^6=64 > > or 2^4=16. This needs to be documented somewhere. > > > > WIP MRs for Mesa, Vulkan and Gstreamer can be found at: > > - https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34303 > > - https://github.com/rmader/Vulkan-Docs/commits/ycbcr-16bit-lsb-formats/ > > - https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8540 > > > > The values where inspired by the corresponding VA_FOURCC_I010, however > > suggestions are very welcome. > > > > Signed-off-by: Robert Mader > > --- > > drivers/gpu/drm/drm_fourcc.c | 18 ++ > > include/uapi/drm/drm_fourcc.h | 20 > > 2 files changed, 38 insertions(+) > > > > diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c > > index 3a94ca211f9c..917f77703645 100644 > > --- a/drivers/gpu/drm/drm_fourcc.c > > +++ b/drivers/gpu/drm/drm_fourcc.c > > @@ -346,6 +346,24 @@ const struct drm_format_info *__drm_format_info(u32 > > format) > > { .format = DRM_FORMAT_P030,.depth = 0, > > .num_planes = 2, > > .char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, > > .block_h = { 1, 1, 0 }, > > .hsub = 2, .vsub = 2, .is_yuv = true}, > > + { .format = DRM_FORMAT_I010,.depth = 0, > > .num_planes = 3, > > + .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, > > .block_h = { 1, 1, 1 }, > > + .hsub = 2, .vsub = 2, .is_yuv = true}, > > + { .format = DRM_FORMAT_I210,.depth = 0, > > .num_planes = 3, > > + .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, > > .block_h = { 1, 1, 1 }, > > + .hsub = 2, .vsub = 1, .is_yuv = true}, > > + { .format = DRM_FORMAT_I410,.depth = 0, > > .num_planes = 3, > > + .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, > > .block_h = { 1, 1, 1 }, > > + .hsub = 1, .vsub = 1, .is_yuv = true}, > > + { .format = DRM_FORMAT_I012,.depth = 0, > > .num_planes = 3, > > + .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, > > .block_h = { 1, 1, 1 }, > > + .hsub = 2, .vsub = 2, .is_yuv = true}, > > + { .format = DRM_FORMAT_I212,.depth = 0, > > .num_planes = 3, > > + .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, > > .block_h = { 1, 1, 1 }, > > + .hsub = 2, .vsub = 1, .is_yuv = true}, > > + { .format = DRM_FORMAT_I412,.depth = 0, > > .num_planes = 3, > > + .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, > > .block_h = { 1, 1, 1 }, > > + .hsub = 1, .vsub = 1, .is_yuv = true}, > > }; > > > > unsigned int i; > > diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h > > index e41a3cec6a9e..f22c80031595 100644 > > --- a/include/uapi/drm/drm_fourcc.h > > +++ b/include/uapi/drm/drm_fourcc.h > > @@ -397,6 +397,26 @@ extern "C" { > > #define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* > > non-subsampled Cb (1) and Cr (2) planes */ > > #define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* > > non-subsampled Cr (1) and Cb (2) planes */ > > > > +/* > > + * 3 plane YCbCr LSB aligned > > + * index 0 = Y plane, [15:0] x:Y [6:10] little endian > > + * index 1 = Cr plane, [15:0] x:Cr [6:10] little endian > > + * index 2 = Cb plane, [15:0] x:Cb [6:10] little endian > > + */ > > +#define DRM_FORMAT_I010fourcc_code('I', '0', '1', '0') /* 2x2 > > subsampled Cb (1) and Cr (2) planes 10 bits per channel */ > > +#define DRM_FORMAT_I210fourcc_code('I', '2', '1', '0') /* 2x1 > > subsampled Cb (1) and Cr (2) planes 10 bits per channel */ > > +#define DRM_FORMAT_I410fourcc_code('I', '4', '1', '0') /* > > non-subsampled Cb (1) and Cr (2) planes 10 bits per channel */ > > + > > +/* > > + * 3 plane YCbCr LSB al
Re: [PATCH 4/4] drm/nouveau: Check dma_fence in canonical way
On Thu, 2025-04-24 at 15:24 +0200, Danilo Krummrich wrote: > On 4/24/25 3:02 PM, Philipp Stanner wrote: > > In nouveau_fence_done(), a fence is checked for being signaled by > > manually evaluating the base fence's bits. This can be done in a > > canonical manner through dma_fence_is_signaled(). > > > > Replace the bit-check with dma_fence_is_signaled(). > > > > Signed-off-by: Philipp Stanner > > --- > > drivers/gpu/drm/nouveau/nouveau_fence.c | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c > > b/drivers/gpu/drm/nouveau/nouveau_fence.c > > index fb9811938c82..d5654e26d5bc 100644 > > --- a/drivers/gpu/drm/nouveau/nouveau_fence.c > > +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c > > @@ -253,7 +253,7 @@ nouveau_fence_done(struct nouveau_fence *fence) > > struct nouveau_channel *chan; > > unsigned long flags; > > > > - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence- > > >base.flags)) > > + if (dma_fence_is_signaled(&fence->base)) > > This is only correct with commit bbe5679f30d7 ("drm/nouveau: Fix > WARN_ON in > nouveau_fence_context_kill()") from drm-misc-fixes, correct? Yup. Otherwise, this series can't be merged anyways, because patch 1 depends on it. The cover letter says so: "This series is based on this partially merged series: [1]" P.
Re: [PATCH 4/4] drm/nouveau: Check dma_fence in canonical way
(+ drm-misc maintainers) On Thu, Apr 24, 2025 at 03:25:55PM +0200, Philipp Stanner wrote: > On Thu, 2025-04-24 at 15:24 +0200, Danilo Krummrich wrote: > > On 4/24/25 3:02 PM, Philipp Stanner wrote: > > > In nouveau_fence_done(), a fence is checked for being signaled by > > > manually evaluating the base fence's bits. This can be done in a > > > canonical manner through dma_fence_is_signaled(). > > > > > > Replace the bit-check with dma_fence_is_signaled(). > > > > > > Signed-off-by: Philipp Stanner > > > --- > > > drivers/gpu/drm/nouveau/nouveau_fence.c | 2 +- > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > > > diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c > > > b/drivers/gpu/drm/nouveau/nouveau_fence.c > > > index fb9811938c82..d5654e26d5bc 100644 > > > --- a/drivers/gpu/drm/nouveau/nouveau_fence.c > > > +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c > > > @@ -253,7 +253,7 @@ nouveau_fence_done(struct nouveau_fence *fence) > > > struct nouveau_channel *chan; > > > unsigned long flags; > > > > > > - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence- > > > >base.flags)) > > > + if (dma_fence_is_signaled(&fence->base)) > > > > This is only correct with commit bbe5679f30d7 ("drm/nouveau: Fix > > WARN_ON in > > nouveau_fence_context_kill()") from drm-misc-fixes, correct? > > Yup. Otherwise, this series can't be merged anyways, because patch 1 > depends on it. > > The cover letter says so: "This series is based on this partially > merged series: [1]" Well, the series may be based on commit bbe5679f30d7, but all patches from the series can still be applied independently. Only patch 4 depends on this commit in terms of correctness. But that's fine, I think we can get drm-misc-fixes (or the next -rc) backmerged into drm-misc-next.
[PATCH v9 11/12] drm/xe/nvm: add support for access mode
Check NVM access mode from GSC FW status registers and overwrite access status read from SPI descriptor, if needed. Reviewed-by: Rodrigo Vivi Acked-by: Rodrigo Vivi Signed-off-by: Alexander Usyskin --- drivers/gpu/drm/xe/regs/xe_gsc_regs.h | 4 +++ drivers/gpu/drm/xe/xe_heci_gsc.c | 5 +--- drivers/gpu/drm/xe/xe_nvm.c | 37 ++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/regs/xe_gsc_regs.h b/drivers/gpu/drm/xe/regs/xe_gsc_regs.h index 7702364b65f1..9b66cc972a63 100644 --- a/drivers/gpu/drm/xe/regs/xe_gsc_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_gsc_regs.h @@ -16,6 +16,10 @@ #define MTL_GSC_HECI1_BASE 0x00116000 #define MTL_GSC_HECI2_BASE 0x00117000 +#define DG1_GSC_HECI2_BASE 0x00259000 +#define PVC_GSC_HECI2_BASE 0x00285000 +#define DG2_GSC_HECI2_BASE 0x00374000 + #define HECI_H_CSR(base) XE_REG((base) + 0x4) #define HECI_H_CSR_IEREG_BIT(0) #define HECI_H_CSR_ISREG_BIT(1) diff --git a/drivers/gpu/drm/xe/xe_heci_gsc.c b/drivers/gpu/drm/xe/xe_heci_gsc.c index 27d11e06a82b..6d7b62724126 100644 --- a/drivers/gpu/drm/xe/xe_heci_gsc.c +++ b/drivers/gpu/drm/xe/xe_heci_gsc.c @@ -11,15 +11,12 @@ #include "xe_device_types.h" #include "xe_drv.h" #include "xe_heci_gsc.h" +#include "regs/xe_gsc_regs.h" #include "xe_platform_types.h" #include "xe_survivability_mode.h" #define GSC_BAR_LENGTH 0x0FFC -#define DG1_GSC_HECI2_BASE 0x259000 -#define PVC_GSC_HECI2_BASE 0x285000 -#define DG2_GSC_HECI2_BASE 0x374000 - static void heci_gsc_irq_mask(struct irq_data *d) { /* generic irq handling */ diff --git a/drivers/gpu/drm/xe/xe_nvm.c b/drivers/gpu/drm/xe/xe_nvm.c index 26de7d4472c8..8aec20bc629a 100644 --- a/drivers/gpu/drm/xe/xe_nvm.c +++ b/drivers/gpu/drm/xe/xe_nvm.c @@ -6,8 +6,11 @@ #include #include +#include "xe_device.h" #include "xe_device_types.h" +#include "xe_mmio.h" #include "xe_nvm.h" +#include "regs/xe_gsc_regs.h" #include "xe_sriov.h" #define GEN12_GUNIT_NVM_BASE 0x00102040 @@ -25,6 +28,38 @@ static void xe_nvm_release_dev(struct device *dev) { } +static bool xe_nvm_writable_override(struct xe_device *xe) +{ + struct xe_gt *gt = xe_root_mmio_gt(xe); + resource_size_t base; + bool writable_override; + + switch (xe->info.platform) { + case XE_BATTLEMAGE: + base = DG2_GSC_HECI2_BASE; + break; + case XE_PVC: + base = PVC_GSC_HECI2_BASE; + break; + case XE_DG2: + base = DG2_GSC_HECI2_BASE; + break; + case XE_DG1: + base = DG1_GSC_HECI2_BASE; + break; + default: + drm_err(&xe->drm, "Unknown platform\n"); + return true; + } + + writable_override = + !(xe_mmio_read32(>->mmio, HECI_FWSTS2(base)) & + HECI_FW_STATUS_2_NVM_ACCESS_MODE); + if (writable_override) + drm_info(&xe->drm, "NVM access overridden by jumper\n"); + return writable_override; +} + void xe_nvm_init(struct xe_device *xe) { struct pci_dev *pdev = to_pci_dev(xe->drm.dev); @@ -49,7 +84,7 @@ void xe_nvm_init(struct xe_device *xe) nvm = xe->nvm; - nvm->writeable_override = false; + nvm->writable_override = xe_nvm_writable_override(xe); nvm->bar.parent = &pdev->resource[0]; nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start; nvm->bar.end = nvm->bar.start + GEN12_GUNIT_NVM_SIZE - 1; -- 2.43.0
[PATCH v9 00/12] mtd: add driver for Intel discrete graphics
Add driver for access to Intel discrete graphics card internal NVM device. Expose device on auxiliary bus by i915 and Xe drivers and provide mtd driver to register this device with MTD framework. This is a rewrite of "drm/i915/spi: spi access for discrete graphics" and "spi: add driver for Intel discrete graphics" series with connection to the Xe driver and splitting the spi driver part to separate module in mtd subsystem. This series intended to be pushed through drm-xe-next. V2: Replace dev_* prints with drm_* prints in drm (xe and i915) patches. Enable NVM device on Battlemage HW (xe driver patch) Fix overwrite register address (xe driver patch) Add Rodrigo's r-b V3: Use devm_pm_runtime_enable to simplify flow. Drop print in i915 unload that was accidentally set as error. Drop HAS_GSC_NVM macro in line with latest Xe changes. Add more Rodrigo's r-b and Miquel's ack. V4: Add patch that always creates mtd master device and adjust mtd-intel-dg power management to use this device. V5: Fix master device creation to accomodate for devices without partitions (create partitoned master in this case) Rebase over latest drm-xe-next Add ack's V6: Fix master device release (use rigth idr in release) Rebase over latest drm-xe-next Grammar and style fixes V7: Add patch with non-posted erase support (fix hang on BMG) Rebase over latest drm-xe-next V8: Create separate partition device under master device, if requested and configure parent of usual partitions to this partition. Rebase over drm-tip. V9: Fix checkpatch warning on non-posted erase patch. Add Rodrigo's review and ack. Alexander Usyskin (11): mtd: core: always create master device mtd: add driver for intel graphics non-volatile memory device mtd: intel-dg: implement region enumeration mtd: intel-dg: implement access functions mtd: intel-dg: register with mtd mtd: intel-dg: align 64bit read and write mtd: intel-dg: wake card on operations drm/i915/nvm: add nvm device for discrete graphics drm/i915/nvm: add support for access mode drm/xe/nvm: add on-die non-volatile memory device drm/xe/nvm: add support for access mode Reuven Abliyev (1): drm/xe/nvm: add support for non-posted erase MAINTAINERS | 7 + drivers/gpu/drm/i915/Makefile | 4 + drivers/gpu/drm/i915/i915_driver.c| 6 + drivers/gpu/drm/i915/i915_drv.h | 3 + drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_nvm.c | 115 drivers/gpu/drm/i915/intel_nvm.h | 15 + drivers/gpu/drm/xe/Makefile | 1 + drivers/gpu/drm/xe/regs/xe_gsc_regs.h | 4 + drivers/gpu/drm/xe/xe_device.c| 5 + drivers/gpu/drm/xe/xe_device_types.h | 6 + drivers/gpu/drm/xe/xe_heci_gsc.c | 5 +- drivers/gpu/drm/xe/xe_nvm.c | 161 + drivers/gpu/drm/xe/xe_nvm.h | 15 + drivers/gpu/drm/xe/xe_pci.c | 6 + drivers/mtd/devices/Kconfig | 11 + drivers/mtd/devices/Makefile | 1 + drivers/mtd/devices/mtd_intel_dg.c| 884 ++ drivers/mtd/mtdchar.c | 2 +- drivers/mtd/mtdcore.c | 152 +++-- drivers/mtd/mtdcore.h | 2 +- drivers/mtd/mtdpart.c | 16 +- include/linux/intel_dg_nvm_aux.h | 29 + include/linux/mtd/partitions.h| 2 +- 24 files changed, 1398 insertions(+), 55 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_nvm.c create mode 100644 drivers/gpu/drm/i915/intel_nvm.h create mode 100644 drivers/gpu/drm/xe/xe_nvm.c create mode 100644 drivers/gpu/drm/xe/xe_nvm.h create mode 100644 drivers/mtd/devices/mtd_intel_dg.c create mode 100644 include/linux/intel_dg_nvm_aux.h -- 2.43.0
[PATCH v9 03/12] mtd: intel-dg: implement region enumeration
In intel-dg, there is no access to the spi controller, the information is extracted from the descriptor region. CC: Lucas De Marchi Reviewed-by: Rodrigo Vivi Acked-by: Miquel Raynal Co-developed-by: Tomas Winkler Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin --- drivers/mtd/devices/mtd_intel_dg.c | 198 + 1 file changed, 198 insertions(+) diff --git a/drivers/mtd/devices/mtd_intel_dg.c b/drivers/mtd/devices/mtd_intel_dg.c index 963a88cacc6c..ba1c720e717b 100644 --- a/drivers/mtd/devices/mtd_intel_dg.c +++ b/drivers/mtd/devices/mtd_intel_dg.c @@ -3,6 +3,8 @@ * Copyright(c) 2019-2025, Intel Corporation. All rights reserved. */ +#include +#include #include #include #include @@ -22,9 +24,199 @@ struct intel_dg_nvm { u8 id; u64 offset; u64 size; + unsigned int is_readable:1; + unsigned int is_writable:1; } regions[] __counted_by(nregions); }; +#define NVM_TRIGGER_REG 0x +#define NVM_VALSIG_REG0x0010 +#define NVM_ADDRESS_REG 0x0040 +#define NVM_REGION_ID_REG 0x0044 +/* + * [15:0]-Erase size = 0x0010 4K 0x0080 32K 0x0100 64K + * [23:16]-Reserved + * [31:24]-Erase MEM RegionID + */ +#define NVM_ERASE_REG 0x0048 +#define NVM_ACCESS_ERROR_REG 0x0070 +#define NVM_ADDRESS_ERROR_REG 0x0074 + +/* Flash Valid Signature */ +#define NVM_FLVALSIG 0x0FF0A55A + +#define NVM_MAP_ADDR_MASK GENMASK(7, 0) +#define NVM_MAP_ADDR_SHIFT0x0004 + +#define NVM_REGION_ID_DESCRIPTOR 0 +/* Flash Region Base Address */ +#define NVM_FRBA 0x40 +/* Flash Region __n - Flash Descriptor Record */ +#define NVM_FLREG(__n) (NVM_FRBA + ((__n) * 4)) +/* Flash Map 1 Register */ +#define NVM_FLMAP1_REG 0x18 +#define NVM_FLMSTR4_OFFSET 0x00C + +#define NVM_ACCESS_ERROR_PCIE_MASK 0x7 + +#define NVM_FREG_BASE_MASK GENMASK(15, 0) +#define NVM_FREG_ADDR_MASK GENMASK(31, 16) +#define NVM_FREG_ADDR_SHIFT 12 +#define NVM_FREG_MIN_REGION_SIZE 0xFFF + +static inline void idg_nvm_set_region_id(struct intel_dg_nvm *nvm, u8 region) +{ + iowrite32((u32)region, nvm->base + NVM_REGION_ID_REG); +} + +static inline u32 idg_nvm_error(struct intel_dg_nvm *nvm) +{ + void __iomem *base = nvm->base; + + u32 reg = ioread32(base + NVM_ACCESS_ERROR_REG) & NVM_ACCESS_ERROR_PCIE_MASK; + + /* reset error bits */ + if (reg) + iowrite32(reg, base + NVM_ACCESS_ERROR_REG); + + return reg; +} + +static inline u32 idg_nvm_read32(struct intel_dg_nvm *nvm, u32 address) +{ + void __iomem *base = nvm->base; + + iowrite32(address, base + NVM_ADDRESS_REG); + + return ioread32(base + NVM_TRIGGER_REG); +} + +static int idg_nvm_get_access_map(struct intel_dg_nvm *nvm, u32 *access_map) +{ + u32 flmap1; + u32 fmba; + u32 fmstr4; + u32 fmstr4_addr; + + idg_nvm_set_region_id(nvm, NVM_REGION_ID_DESCRIPTOR); + + flmap1 = idg_nvm_read32(nvm, NVM_FLMAP1_REG); + if (idg_nvm_error(nvm)) + return -EIO; + /* Get Flash Master Baser Address (FMBA) */ + fmba = (FIELD_GET(NVM_MAP_ADDR_MASK, flmap1) << NVM_MAP_ADDR_SHIFT); + fmstr4_addr = fmba + NVM_FLMSTR4_OFFSET; + + fmstr4 = idg_nvm_read32(nvm, fmstr4_addr); + if (idg_nvm_error(nvm)) + return -EIO; + + *access_map = fmstr4; + return 0; +} + +static bool idg_nvm_region_readable(u32 access_map, u8 region) +{ + if (region < 12) + return access_map & BIT(region + 8); /* [19:8] */ + else + return access_map & BIT(region - 12); /* [3:0] */ +} + +static bool idg_nvm_region_writable(u32 access_map, u8 region) +{ + if (region < 12) + return access_map & BIT(region + 20); /* [31:20] */ + else + return access_map & BIT(region - 8); /* [7:4] */ +} + +static int idg_nvm_is_valid(struct intel_dg_nvm *nvm) +{ + u32 is_valid; + + idg_nvm_set_region_id(nvm, NVM_REGION_ID_DESCRIPTOR); + + is_valid = idg_nvm_read32(nvm, NVM_VALSIG_REG); + if (idg_nvm_error(nvm)) + return -EIO; + + if (is_valid != NVM_FLVALSIG) + return -ENODEV; + + return 0; +} + +static int intel_dg_nvm_init(struct intel_dg_nvm *nvm, struct device *device) +{ + int ret; + unsigned int i, n; + u32 access_map = 0; + + /* clean error register, previous errors are ignored */ + idg_nvm_error(nvm); + + ret = idg_nvm_is_valid(nvm); + if (ret) { + dev_err(device, "The MEM is not valid %d\n", ret); + return ret; + } + + if (idg_nvm_get_access_map(nvm, &access_map)) + return -EIO; + + for (i = 0, n = 0; i < nvm->nregions; i++) { + u32 address, base, limit, region; + u8 id = nvm->regions[i].id; + + address = NVM_FLREG
[PATCH v22 5/5] drm/xe/xe_vm: Implement xe_vm_get_property_ioctl
Add support for userspace to request a list of observed faults from a specified VM. v2: - Only allow querying of failed pagefaults (Matt Brost) v3: - Remove unnecessary size parameter from helper function, as it is a property of the arguments. (jcavitt) - Remove unnecessary copy_from_user (Jainxun) - Set address_precision to 1 (Jainxun) - Report max size instead of dynamic size for memory allocation purposes. Total memory usage is reported separately. v4: - Return int from xe_vm_get_property_size (Shuicheng) - Fix memory leak (Shuicheng) - Remove unnecessary size variable (jcavitt) v5: - Rename ioctl to xe_vm_get_faults_ioctl (jcavitt) - Update fill_property_pfs to eliminate need for kzalloc (Jianxun) v6: - Repair and move fill_faults break condition (Dan Carpenter) - Free vm after use (jcavitt) - Combine assertions (jcavitt) - Expand size check in xe_vm_get_faults_ioctl (jcavitt) - Remove return mask from fill_faults, as return is already -EFAULT or 0 (jcavitt) v7: - Revert back to using xe_vm_get_property_ioctl - Apply better copy_to_user logic (jcavitt) v8: - Fix and clean up error value handling in ioctl (jcavitt) - Reapply return mask for fill_faults (jcavitt) v9: - Future-proof size logic for zero-size properties (jcavitt) - Add access and fault types (Jianxun) - Remove address type (Jianxun) v10: - Remove unnecessary switch case logic (Raag) - Compress size get, size validation, and property fill functions into a single helper function (jcavitt) - Assert valid size (jcavitt) v11: - Remove unnecessary else condition - Correct backwards helper function size logic (jcavitt) v12: - Use size_t instead of int (Raag) v13: - Remove engine class and instance (Ivan) v14: - Map access type, fault type, and fault level to user macros (Matt Brost, Ivan) v15: - Remove unnecessary size assertion (jcavitt) Signed-off-by: Jonathan Cavitt Suggested-by: Matthew Brost Reviewed-by: Shuicheng Lin Cc: Jainxun Zhang Cc: Shuicheng Lin Cc: Raag Jadav Cc: Ivan Briano --- drivers/gpu/drm/xe/xe_device.c | 3 + drivers/gpu/drm/xe/xe_vm.c | 107 + drivers/gpu/drm/xe/xe_vm.h | 2 + 3 files changed, 112 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 75e753e0a682..6816dc3a428c 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -196,6 +196,9 @@ static const struct drm_ioctl_desc xe_ioctls[] = { DRM_IOCTL_DEF_DRV(XE_WAIT_USER_FENCE, xe_wait_user_fence_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(XE_OBSERVATION, xe_observation_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(XE_VM_GET_PROPERTY, xe_vm_get_property_ioctl, + DRM_RENDER_ALLOW), + }; static long xe_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 107e397b4987..c20ac51d8573 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -3600,6 +3600,113 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file) return err; } +/* + * Map access type, fault type, and fault level from current bspec + * specification to user spec abstraction. The current mapping is + * 1-to-1, but if there is ever a hardware change, we will need + * this abstraction layer to maintain API stability through the + * hardware change. + */ +static u8 xe_to_user_access_type(u8 access_type) +{ + return access_type; +} + +static u8 xe_to_user_fault_type(u8 fault_type) +{ + return fault_type; +} + +static u8 xe_to_user_fault_level(u8 fault_level) +{ + return fault_level; +} + +static int fill_faults(struct xe_vm *vm, + struct drm_xe_vm_get_property *args) +{ + struct xe_vm_fault __user *usr_ptr = u64_to_user_ptr(args->data); + struct xe_vm_fault store = { 0 }; + struct xe_vm_fault_entry *entry; + int ret = 0, i = 0, count, entry_size; + + entry_size = sizeof(struct xe_vm_fault); + count = args->size / entry_size; + + spin_lock(&vm->faults.lock); + list_for_each_entry(entry, &vm->faults.list, list) { + if (i++ == count) + break; + + memset(&store, 0, entry_size); + + store.address = entry->address; + store.address_precision = entry->address_precision; + + store.access_type = xe_to_user_access_type(entry->access_type); + store.fault_type = xe_to_user_fault_type(entry->fault_type); + store.fault_level = xe_to_user_fault_level(entry->fault_level); + + ret = copy_to_user(usr_ptr, &store, entry_size); + if (ret) + break; + + usr_ptr++; + } + spin_unlock(&vm->faults.lock); + + return ret ? -EFAULT : 0; +} + +static int xe_vm_get_property_helper(struct xe_vm
[PATCH RFC v2 5/5] drm: panel: Add Saef SFTO340XC LCD panel
Add support for Saef Technology Limited SFTO340XC LCD panel. Signed-off-by: Kory Maincent --- drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 232 ++ 1 file changed, 232 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 2e38dea28336f445cb6a074dbbec006f0659287a..574d2dad873474ffa02d554aff9d62c63e070d99 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -44,6 +44,7 @@ struct ili9881c_desc { const struct drm_display_mode *mode; const unsigned long mode_flags; u8 default_address_mode; + const unsigned int msleep_delay; }; struct ili9881c { @@ -458,6 +459,207 @@ static const struct ili9881c_instr k101_im2byl02_init[] = { ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */ }; +static const struct ili9881c_instr sfto340xc_init[] = { + ILI9881C_SWITCH_PAGE_INSTR(3), + ILI9881C_COMMAND_INSTR(0x01, 0x00), + ILI9881C_COMMAND_INSTR(0x02, 0x01), + ILI9881C_COMMAND_INSTR(0x03, 0x73), + ILI9881C_COMMAND_INSTR(0x04, 0x03), + ILI9881C_COMMAND_INSTR(0x05, 0x00), + ILI9881C_COMMAND_INSTR(0x06, 0x0A), + ILI9881C_COMMAND_INSTR(0x07, 0x05), + ILI9881C_COMMAND_INSTR(0x08, 0x00), + ILI9881C_COMMAND_INSTR(0x09, 0x40), + ILI9881C_COMMAND_INSTR(0x0a, 0x00), + ILI9881C_COMMAND_INSTR(0x0B, 0x00), + ILI9881C_COMMAND_INSTR(0x0C, 0x00), + ILI9881C_COMMAND_INSTR(0x0D, 0x40), + ILI9881C_COMMAND_INSTR(0x0E, 0x00), + ILI9881C_COMMAND_INSTR(0x0f, 0x3c), + ILI9881C_COMMAND_INSTR(0x10, 0x3c), + ILI9881C_COMMAND_INSTR(0x11, 0x00), + ILI9881C_COMMAND_INSTR(0x12, 0x00), + ILI9881C_COMMAND_INSTR(0x13, 0x00), + ILI9881C_COMMAND_INSTR(0x14, 0x00), + ILI9881C_COMMAND_INSTR(0x15, 0x00), + ILI9881C_COMMAND_INSTR(0x16, 0x00), + ILI9881C_COMMAND_INSTR(0x17, 0x00), + ILI9881C_COMMAND_INSTR(0x18, 0x00), + ILI9881C_COMMAND_INSTR(0x19, 0x00), + ILI9881C_COMMAND_INSTR(0x1A, 0x00), + ILI9881C_COMMAND_INSTR(0x1B, 0x00), + ILI9881C_COMMAND_INSTR(0x1C, 0x00), + ILI9881C_COMMAND_INSTR(0x1D, 0x00), + ILI9881C_COMMAND_INSTR(0x1E, 0xC0), + ILI9881C_COMMAND_INSTR(0x1F, 0x80), + ILI9881C_COMMAND_INSTR(0x20, 0x06), + ILI9881C_COMMAND_INSTR(0x21, 0x01), + ILI9881C_COMMAND_INSTR(0x22, 0x00), + ILI9881C_COMMAND_INSTR(0x23, 0x00), + ILI9881C_COMMAND_INSTR(0x24, 0x00), + ILI9881C_COMMAND_INSTR(0x25, 0x00), + ILI9881C_COMMAND_INSTR(0x26, 0x00), + ILI9881C_COMMAND_INSTR(0x27, 0x00), + ILI9881C_COMMAND_INSTR(0x28, 0xB3), + ILI9881C_COMMAND_INSTR(0x29, 0x03), + ILI9881C_COMMAND_INSTR(0x2A, 0x00), + ILI9881C_COMMAND_INSTR(0x2B, 0x00), + ILI9881C_COMMAND_INSTR(0x2C, 0x00), + ILI9881C_COMMAND_INSTR(0x2D, 0x00), + ILI9881C_COMMAND_INSTR(0x2E, 0x00), + ILI9881C_COMMAND_INSTR(0x2F, 0x00), + ILI9881C_COMMAND_INSTR(0x30, 0x00), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x32, 0x00), + ILI9881C_COMMAND_INSTR(0x33, 0x00), + ILI9881C_COMMAND_INSTR(0x34, 0x23), + ILI9881C_COMMAND_INSTR(0x35, 0x00), + ILI9881C_COMMAND_INSTR(0x36, 0x00), + ILI9881C_COMMAND_INSTR(0x37, 0x08), + ILI9881C_COMMAND_INSTR(0x38, 0x3C), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x3A, 0x00), + ILI9881C_COMMAND_INSTR(0x3B, 0x00), + ILI9881C_COMMAND_INSTR(0x3C, 0x00), + ILI9881C_COMMAND_INSTR(0x3D, 0x00), + ILI9881C_COMMAND_INSTR(0x3E, 0x00), + ILI9881C_COMMAND_INSTR(0x3F, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x00), + ILI9881C_COMMAND_INSTR(0x41, 0x00), + ILI9881C_COMMAND_INSTR(0x42, 0x00), + ILI9881C_COMMAND_INSTR(0x43, 0x00), + ILI9881C_COMMAND_INSTR(0x44, 0x00), + ILI9881C_COMMAND_INSTR(0x50, 0x01), + ILI9881C_COMMAND_INSTR(0x51, 0x23), + ILI9881C_COMMAND_INSTR(0x52, 0x44), + ILI9881C_COMMAND_INSTR(0x53, 0x67), + ILI9881C_COMMAND_INSTR(0x54, 0x89), + ILI9881C_COMMAND_INSTR(0x55, 0xAB), + ILI9881C_COMMAND_INSTR(0x56, 0x01), + ILI9881C_COMMAND_INSTR(0x57, 0x23), + ILI9881C_COMMAND_INSTR(0x58, 0x45), + ILI9881C_COMMAND_INSTR(0x59, 0x67), + ILI9881C_COMMAND_INSTR(0x5A, 0x89), + ILI9881C_COMMAND_INSTR(0x5B, 0xAB), + ILI9881C_COMMAND_INSTR(0x5C, 0xCD), + ILI9881C_COMMAND_INSTR(0x5D, 0xEF), + ILI9881C_COMMAND_INSTR(0x5E, 0x01), + ILI9881C_COMMAND_INSTR(0x5F, 0x00), + ILI9881C_COMMAND_INSTR(0x60, 0x00), + ILI9881C_COMMAND_INSTR(0x61, 0x01), + ILI9881C_COMMAND_INSTR(0x62, 0x01), + ILI9881C_COMMAND_INSTR(0x63, 0x08), + ILI9881C_COMMAND_INSTR(0x64, 0x0E), + ILI9881C_COMMAND_INSTR(0x65, 0x0E), + ILI9881C_COMMAND_INSTR(0x66, 0x0F), + I
[PATCH RFC v2 0/5] Add support for Saef SFTO340XC panel.
Add support for Saef Technology Limited SFTO340XC LCD panel. Add alongside the number of lanes configuration in the ili9881c driver as the board on my desc use the panel with only two lanes. Faced an issue with panel-common binding. Wrote a fix (first patch) but not sure it is the right one. If someone from dt tree could take a look, it would be nice. Signed-off-by: Kory Maincent --- Changes in v2: - Add new patch trying to fix panel-common binding. - Read the data-lanes parameter from the port endpoint and use drm_of_get_data_lanes_count instead of of_property_read_u32. - Link to v1: https://lore.kernel.org/r/20250408-feature_sfto340xc-v1-0-f303d1b9a...@bootlin.com --- Kory Maincent (5): dt-bindings: display: panel: Fix port binding dt-bindings: display: panel: ili9881c: Add data-lanes property drm/panel: ilitek-ili9881c: Add support for two-lane configuration dt-bindings: ili9881c: Add Saef SFTO340XC support drm: panel: Add Saef SFTO340XC LCD panel .../bindings/display/panel/ilitek,ili9881c.yaml| 21 ++ .../bindings/display/panel/panel-common.yaml | 2 +- drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 265 - 3 files changed, 285 insertions(+), 3 deletions(-) --- base-commit: bef4f1156b74721b7d14538659031119b6f2 change-id: 20250129-feature_sfto340xc-d2b25a5b5748 Best regards, -- Köry Maincent, Bootlin Embedded Linux and kernel engineering https://bootlin.com
[PATCH RFC v2 2/5] dt-bindings: display: panel: ili9881c: Add data-lanes property
Add the data-lanes property to specify the number of DSI lanes used by the panel. This allows configuring the panel for either two, three or four lanes. At the same time, extend the devicetree example with an endpoint node for better clarity. Signed-off-by: Kory Maincent --- Change in v2: - Use data-lanes property from video-interfaces.yaml - Add endpoint description example --- .../bindings/display/panel/ilitek,ili9881c.yaml | 20 1 file changed, 20 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml index baf5dfe5f5ebdd92f460a78d0e56e1b45e7dd323..3a897e464178dfc8a7c70e0fafb51184c50a520b 100644 --- a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml @@ -27,6 +27,20 @@ properties: reg: maxItems: 1 + port: +$ref: /schemas/graph.yaml#/$defs/port-base +unevaluatedProperties: false + +properties: + endpoint: +$ref: /schemas/media/video-interfaces.yaml# +unevaluatedProperties: false + +properties: + data-lanes: +minItems: 1 +maxItems: 4 + backlight: true power-supply: true reset-gpios: true @@ -53,6 +67,12 @@ examples: power-supply = <®_display>; reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL05 */ backlight = <&pwm_bl>; +port { +panel_in: endpoint { +remote-endpoint = <&dsi_out>; +data-lanes = <1 2>; +}; +}; }; }; -- 2.34.1
[PATCH] drm/panthor: fix building without CONFIG_DEBUG_FS
From: Arnd Bergmann When debugfs is disabled, including panthor_gem.h causes warnings about a non-static global function defined in a header: In file included from drivers/gpu/drm/panthor/panthor_drv.c:30: drivers/gpu/drm/panthor/panthor_gem.h:222:6: error: no previous prototype for 'panthor_gem_debugfs_set_usage_flags' [-Werror=missing-prototypes] 222 | void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) {}; This could be changed to a static inline function, but as the normal one is also static inline, just move the #ifdef check in there. The #ifdef is still needed to avoid accessing a struct member that does not exist without debugfs. Fixes: a3707f53eb3f ("drm/panthor: show device-wide list of DRM GEM objects over DebugFS") Signed-off-by: Arnd Bergmann --- drivers/gpu/drm/panthor/panthor_gem.h | 7 ++- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h index 4641994ddd7f..693842e10dee 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -209,17 +209,14 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo); -#ifdef CONFIG_DEBUG_FS void panthor_gem_debugfs_print_bos(struct panthor_device *pfdev, struct seq_file *m); static inline void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) { +#ifdef CONFIG_DEBUG_FS bo->debugfs.flags = usage_flags | PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED; -} - -#else -void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) {}; #endif +} #endif /* __PANTHOR_GEM_H__ */ -- 2.39.5
[PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
Goal here is cut over to gpusvm and remove xe_hmm, relying instead on common code. The core facilities we need are get_pages(), unmap_pages() and free_pages() for a given useptr range, plus a vm level notifier lock, which is now provided by gpusvm. v2: - Reuse the same SVM vm struct we use for full SVM, that way we can use the same lock (Matt B & Himal) v3: - Re-use svm_init/fini for userptr. Signed-off-by: Matthew Auld Cc: Himal Prasad Ghimiray Cc: Thomas Hellström Cc: Matthew Brost --- drivers/gpu/drm/xe/Kconfig | 3 +- drivers/gpu/drm/xe/Makefile | 1 - drivers/gpu/drm/xe/xe_exec.c | 4 +- drivers/gpu/drm/xe/xe_hmm.c | 325 --- drivers/gpu/drm/xe/xe_hmm.h | 18 -- drivers/gpu/drm/xe/xe_pt.c | 22 +-- drivers/gpu/drm/xe/xe_svm.c | 32 +-- drivers/gpu/drm/xe/xe_svm.h | 6 +- drivers/gpu/drm/xe/xe_vm.c | 86 drivers/gpu/drm/xe/xe_vm_types.h | 26 +-- 10 files changed, 92 insertions(+), 431 deletions(-) delete mode 100644 drivers/gpu/drm/xe/xe_hmm.c delete mode 100644 drivers/gpu/drm/xe/xe_hmm.h diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig index 9bce047901b2..1e63dde76c55 100644 --- a/drivers/gpu/drm/xe/Kconfig +++ b/drivers/gpu/drm/xe/Kconfig @@ -43,7 +43,7 @@ config DRM_XE select MMU_NOTIFIER select WANT_DEV_COREDUMP select AUXILIARY_BUS - select HMM_MIRROR + select DRM_GPUSVM help Experimental driver for Intel Xe series GPUs @@ -79,7 +79,6 @@ config DRM_XE_GPUSVM depends on !UML depends on DEVICE_PRIVATE default y - select DRM_GPUSVM help Enable this option if you want support for CPU to GPU address mirroring. diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 3ecac0a38b82..f1123be158f8 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -124,7 +124,6 @@ xe-y += xe_bb.o \ xe_wait_user_fence.o \ xe_wopcm.o -xe-$(CONFIG_HMM_MIRROR) += xe_hmm.o xe-$(CONFIG_DRM_XE_GPUSVM) += xe_svm.o # graphics hardware monitoring (HWMON) support diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c index b75adfc99fb7..c0ce681076d5 100644 --- a/drivers/gpu/drm/xe/xe_exec.c +++ b/drivers/gpu/drm/xe/xe_exec.c @@ -294,7 +294,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (err) goto err_put_job; - err = down_read_interruptible(&vm->userptr.notifier_lock); + err = down_read_interruptible(&vm->svm.gpusvm.notifier_lock); if (err) goto err_put_job; @@ -336,7 +336,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) err_repin: if (!xe_vm_in_lr_mode(vm)) - up_read(&vm->userptr.notifier_lock); + up_read(&vm->svm.gpusvm.notifier_lock); err_put_job: if (err) xe_sched_job_put(job); diff --git a/drivers/gpu/drm/xe/xe_hmm.c b/drivers/gpu/drm/xe/xe_hmm.c deleted file mode 100644 index 57b71956ddf4.. --- a/drivers/gpu/drm/xe/xe_hmm.c +++ /dev/null @@ -1,325 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright © 2024 Intel Corporation - */ - -#include -#include -#include -#include -#include -#include -#include -#include "xe_hmm.h" -#include "xe_vm.h" -#include "xe_bo.h" - -static u64 xe_npages_in_range(unsigned long start, unsigned long end) -{ - return (end - start) >> PAGE_SHIFT; -} - -static int xe_alloc_sg(struct xe_device *xe, struct sg_table *st, - struct hmm_range *range, struct rw_semaphore *notifier_sem) -{ - unsigned long i, npages, hmm_pfn; - unsigned long num_chunks = 0; - int ret; - - /* HMM docs says this is needed. */ - ret = down_read_interruptible(notifier_sem); - if (ret) - return ret; - - if (mmu_interval_read_retry(range->notifier, range->notifier_seq)) { - up_read(notifier_sem); - return -EAGAIN; - } - - npages = xe_npages_in_range(range->start, range->end); - for (i = 0; i < npages;) { - unsigned long len; - - hmm_pfn = range->hmm_pfns[i]; - xe_assert(xe, hmm_pfn & HMM_PFN_VALID); - - len = 1UL << hmm_pfn_to_map_order(hmm_pfn); - - /* If order > 0 the page may extend beyond range->start */ - len -= (hmm_pfn & ~HMM_PFN_FLAGS) & (len - 1); - i += len; - num_chunks++; - } - up_read(notifier_sem); - - return sg_alloc_table(st, num_chunks, GFP_KERNEL); -} - -/** - * xe_build_sg() - build a scatter gather table for all the physical pages/pfn - * in a hmm_range. dma-map pages if necessary. dma-address is save in sg table - * and will be used to program GPU page table la
[PATCH v3 5/7] drm/gpusvm: export drm_gpusvm_pages API
Export get/unmap/free pages API. We also need to tweak the SVM init to allow skipping much of the unneeded parts. Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Matthew Brost --- drivers/gpu/drm/drm_gpusvm.c | 66 include/drm/drm_gpusvm.h | 16 + 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index fbe0d70ef163..0e0a3c995b4b 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -539,6 +539,12 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = { * * This function initializes the GPU SVM. * + * Note: If only using the simple drm_gpusvm_pages API (get/unmap/free), + * then only @gpusvm, @name, and @drm are expected. However, the same base + * @gpusvm can also be used with both modes together in which case the full + * setup is needed, where the core drm_gpusvm_pages API will simply never use + * the other fields. + * * Return: 0 on success, a negative error code on failure. */ int drm_gpusvm_init(struct drm_gpusvm *gpusvm, @@ -549,8 +555,16 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm, const struct drm_gpusvm_ops *ops, const unsigned long *chunk_sizes, int num_chunks) { - if (!ops->invalidate || !num_chunks) - return -EINVAL; + if (mm) { + if (!ops->invalidate || !num_chunks) + return -EINVAL; + mmgrab(mm); + } else { + /* No full SVM mode, only core drm_gpusvm_pages API. */ + if (ops || num_chunks || mm_range || notifier_size || + device_private_page_owner) + return -EINVAL; + } gpusvm->name = name; gpusvm->drm = drm; @@ -563,7 +577,6 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm, gpusvm->chunk_sizes = chunk_sizes; gpusvm->num_chunks = num_chunks; - mmgrab(mm); gpusvm->root = RB_ROOT_CACHED; INIT_LIST_HEAD(&gpusvm->notifier_list); @@ -671,7 +684,8 @@ void drm_gpusvm_fini(struct drm_gpusvm *gpusvm) drm_gpusvm_range_remove(gpusvm, range); } - mmdrop(gpusvm->mm); + if (gpusvm->mm) + mmdrop(gpusvm->mm); WARN_ON(!RB_EMPTY_ROOT(&gpusvm->root.rb_root)); } EXPORT_SYMBOL_GPL(drm_gpusvm_fini); @@ -1185,6 +1199,27 @@ static void __drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm, } } +/** + * drm_gpusvm_free_pages() - Free dma-mapping associated with GPU SVM pages + * struct + * @gpusvm: Pointer to the GPU SVM structure + * @svm_pages: Pointer to the GPU SVM pages structure + * @npages: Number of mapped pages + * + * This function unmaps and frees the dma address array associated with a GPU + * SVM pages struct. + */ +void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm, + struct drm_gpusvm_pages *svm_pages, + unsigned long npages) +{ + drm_gpusvm_notifier_lock(gpusvm); + __drm_gpusvm_unmap_pages(gpusvm, svm_pages, npages); + __drm_gpusvm_free_pages(gpusvm, svm_pages); + drm_gpusvm_notifier_unlock(gpusvm); +} +EXPORT_SYMBOL_GPL(drm_gpusvm_free_pages); + /** * drm_gpusvm_range_remove() - Remove GPU SVM range * @gpusvm: Pointer to the GPU SVM structure @@ -1360,13 +1395,12 @@ static bool drm_gpusvm_pages_valid_unlocked(struct drm_gpusvm *gpusvm, * * Return: 0 on success, negative error code on failure. */ -static int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_pages *svm_pages, - struct mm_struct *mm, - struct mmu_interval_notifier *notifier, - unsigned long pages_start, - unsigned long pages_end, - const struct drm_gpusvm_ctx *ctx) +int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, +struct drm_gpusvm_pages *svm_pages, +struct mm_struct *mm, +struct mmu_interval_notifier *notifier, +unsigned long pages_start, unsigned long pages_end, +const struct drm_gpusvm_ctx *ctx) { struct hmm_range hmm_range = { .default_flags = HMM_PFN_REQ_FAULT | (ctx->read_only ? 0 : @@ -1548,6 +1582,7 @@ static int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, goto retry; return err; } +EXPORT_SYMBOL_GPL(drm_gpusvm_get_pages); /** * drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range @@ -1583,10 +1618,10 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_get_pages); * Must be called in the invalidate() callback of the corresponding notifier for * IOMMU security model. */ -static void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm, -
[PATCH v3 1/7] drm/gpusvm: fix hmm_pfn_to_map_order() usage
Handle the case where the hmm range partially covers a huge page (like 2M), otherwise we can potentially end up doing something nasty like mapping memory which is outside the range, and maybe not even mapped by the mm. Fix is based on the xe userptr code, which in a future patch will directly use gpusvm, so needs alignment here. v2: - Add kernel-doc (Matt B) - s/fls/ilog2/ (Thomas) Reported-by: Thomas Hellström Signed-off-by: Matthew Auld Cc: Matthew Brost Reviewed-by: Thomas Hellström --- drivers/gpu/drm/drm_gpusvm.c | 33 +++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index 38431e8360e7..a2842a112ba0 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -817,6 +817,35 @@ drm_gpusvm_range_alloc(struct drm_gpusvm *gpusvm, return range; } +/** + * drm_gpusvm_hmm_pfn_to_order() - Get the largest CPU mapping order. + * @hmm_pfn: The current hmm_pfn. + * @hmm_pfn_index: Index of the @hmm_pfn within the pfn array. + * @npages: Number of pages within the pfn array i.e the hmm range size. + * + * To allow skipping PFNs with the same flags (like when they belong to + * the same huge PTE) when looping over the pfn array, take a given a hmm_pfn, + * and return the largest order that will fit inside the CPU PTE, but also + * crucially accounting for the original hmm range boundaries. + * + * Return: The largest order that will safely fit within the size of the hmm_pfn + * CPU PTE. + */ +static unsigned int drm_gpusvm_hmm_pfn_to_order(unsigned long hmm_pfn, + unsigned long hmm_pfn_index, + unsigned long npages) +{ + unsigned long size; + + size = 1UL << hmm_pfn_to_map_order(hmm_pfn); + size -= (hmm_pfn & ~HMM_PFN_FLAGS) & (size - 1); + hmm_pfn_index += size; + if (hmm_pfn_index > npages) + size -= (hmm_pfn_index - npages); + + return ilog2(size); +} + /** * drm_gpusvm_check_pages() - Check pages * @gpusvm: Pointer to the GPU SVM structure @@ -875,7 +904,7 @@ static bool drm_gpusvm_check_pages(struct drm_gpusvm *gpusvm, err = -EFAULT; goto err_free; } - i += 0x1 << hmm_pfn_to_map_order(pfns[i]); + i += 0x1 << drm_gpusvm_hmm_pfn_to_order(pfns[i], i, npages); } err_free: @@ -1408,7 +1437,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, for (i = 0, j = 0; i < npages; ++j) { struct page *page = hmm_pfn_to_page(pfns[i]); - order = hmm_pfn_to_map_order(pfns[i]); + order = drm_gpusvm_hmm_pfn_to_order(pfns[i], i, npages); if (is_device_private_page(page) || is_device_coherent_page(page)) { if (zdd != page->zone_device_data && i > 0) { -- 2.49.0
[PATCH v3 0/7] Replace xe_hmm with gpusvm
As a first step to moving userptr handling over to drm, replace the hmm usage in xe over to gpusvm, which already offers similar functionality. As some prep steps we also align on some of the missing pieces that were already handled in xe_hmm. v2: - Rework the gpusvm API based on feedback. - Unify SVM and userptr vm struct so we use the same notifier lock. - Drop the mark pages as dirty patch. - Various other improvements. v3: - Further unify common handling of userptr and svm in xe. -- 2.49.0
[PATCH v3 2/7] drm/gpusvm: use more selective dma dir in get_pages()
If we are only reading the memory then from the device pov the direction can be DMA_TO_DEVICE. This aligns with the xe-userptr code. Using the most restrictive data direction to represent the access is normally a good idea. Signed-off-by: Matthew Auld Cc: Thomas Hellström Cc: Matthew Brost Reviewed-by: Thomas Hellström Reviewed-by: Matthew Brost --- drivers/gpu/drm/drm_gpusvm.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index a2842a112ba0..d40a01524387 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -1363,6 +1363,8 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, int err = 0; struct dev_pagemap *pagemap; struct drm_pagemap *dpagemap; + enum dma_data_direction dma_dir = ctx->read_only ? DMA_TO_DEVICE : + DMA_BIDIRECTIONAL; retry: hmm_range.notifier_seq = mmu_interval_read_begin(notifier); @@ -1467,7 +1469,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, dpagemap->ops->device_map(dpagemap, gpusvm->drm->dev, page, order, - DMA_BIDIRECTIONAL); + dma_dir); if (dma_mapping_error(gpusvm->drm->dev, range->dma_addr[j].addr)) { err = -EFAULT; @@ -1486,7 +1488,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, addr = dma_map_page(gpusvm->drm->dev, page, 0, PAGE_SIZE << order, - DMA_BIDIRECTIONAL); + dma_dir); if (dma_mapping_error(gpusvm->drm->dev, addr)) { err = -EFAULT; goto err_unmap; @@ -1494,7 +1496,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, range->dma_addr[j] = drm_pagemap_device_addr_encode (addr, DRM_INTERCONNECT_SYSTEM, order, -DMA_BIDIRECTIONAL); +dma_dir); } i += 1 << order; num_dma_mapped = i; -- 2.49.0
Re: [PATCH] drm/panthor: fix building without CONFIG_DEBUG_FS
On Thu, 24 Apr 2025 14:10:16 +0200 "Arnd Bergmann" wrote: > On Thu, Apr 24, 2025, at 13:41, Boris Brezillon wrote: > > On Thu, 24 Apr 2025 13:25:47 +0200 > >> +#ifdef CONFIG_DEBUG_FS > >>bo->debugfs.flags = usage_flags | > >> PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED; > >> -} > >> - > >> -#else > >> -void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, > >> u32 usage_flags) {}; > >> #endif > >> +} > >> > > > > Oops. I actually don't see a good reason to expose this function, so > > could we go for something like that instead? > > I think moving it into pantor_gem.c makes sense, and it certainly > avoids the build warning. > > > #else > > static void panthor_gem_debugfs_bo_add(struct panthor_device *ptdev, > >struct panthor_gem_object *bo) > > {} > > static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) {} > > +static void panthor_gem_debugfs_set_usage_flags(struct > > panthor_gem_object *bo, > > + u32 usage_flags) > > +{ > > Side note: I think the panthor_gem_debugfs_bo_{add,rm} stubs could > actually be replaced with an IS_ENABLED() check in the normal > functions, but that wouldn't work for > panthor_gem_debugfs_set_usage_flags or > panthor_gem_debugfs_print_bos(). Yeah, I think I prefer consistency over saving a few LoC ;-). Do you plan to send a v2 with the suggested changes, or should we take care of that?
Re: [PATCH] drm: drm_fourcc: add 10/12bit software decoder YCbCr formats
Chris, Javier, Laurent - sorry for the noise, but given you reviewed changes in the respective files before, maybe you can help me moving this forward? I'd be very happy for any feedback to get this landed, thanks! :) On 07.04.25 21:13, Robert Mader wrote: This adds FOURCCs for 10/12bit YCbCr formats used by software decoders like ffmpeg, dav1d and libvpx. The intended use-case is buffer sharing between SW-decoders and GPUs by allocating buffers with udmabuf or dma-heaps, avoiding unnecessary copies or format conversions. Unlike formats typically used by hardware decoders these formats use a LSB alignment. In order to allow fast implementations in GL and Vulkan the padding must contain only zeros, so the float representation can calculated by simple multiplicating with 2^6=64 or 2^4=16. WIP MRs for Mesa, Vulkan and Gstreamer can be found at: - https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34303 - https://github.com/rmader/Vulkan-Docs/commits/ycbcr-16bit-lsb-formats/ - https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8540 The values where inspired by the corresponding VA_FOURCC_I010, however suggestions are very welcome. Signed-off-by: Robert Mader --- drivers/gpu/drm/drm_fourcc.c | 18 ++ include/uapi/drm/drm_fourcc.h | 20 2 files changed, 38 insertions(+) diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 3a94ca211f9c..917f77703645 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -346,6 +346,24 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_P030,.depth = 0, .num_planes = 2, .char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true}, + { .format = DRM_FORMAT_I010,.depth = 0, .num_planes = 3, + .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, + .hsub = 2, .vsub = 2, .is_yuv = true}, + { .format = DRM_FORMAT_I210,.depth = 0, .num_planes = 3, + .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, + .hsub = 2, .vsub = 1, .is_yuv = true}, + { .format = DRM_FORMAT_I410,.depth = 0, .num_planes = 3, + .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, + .hsub = 1, .vsub = 1, .is_yuv = true}, + { .format = DRM_FORMAT_I012,.depth = 0, .num_planes = 3, + .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, + .hsub = 2, .vsub = 2, .is_yuv = true}, + { .format = DRM_FORMAT_I212,.depth = 0, .num_planes = 3, + .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, + .hsub = 2, .vsub = 1, .is_yuv = true}, + { .format = DRM_FORMAT_I412,.depth = 0, .num_planes = 3, + .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, + .hsub = 1, .vsub = 1, .is_yuv = true}, }; unsigned int i; diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index e41a3cec6a9e..f22c80031595 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -397,6 +397,26 @@ extern "C" { #define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ +/* + * 3 plane YCbCr LSB aligned + * index 0 = Y plane, [15:0] x:Y [6:10] little endian + * index 1 = Cr plane, [15:0] x:Cr [6:10] little endian + * index 2 = Cb plane, [15:0] x:Cb [6:10] little endian + */ +#define DRM_FORMAT_I010fourcc_code('I', '0', '1', '0') /* 2x2 subsampled Cb (1) and Cr (2) planes 10 bits per channel */ +#define DRM_FORMAT_I210fourcc_code('I', '2', '1', '0') /* 2x1 subsampled Cb (1) and Cr (2) planes 10 bits per channel */ +#define DRM_FORMAT_I410fourcc_code('I', '4', '1', '0') /* non-subsampled Cb (1) and Cr (2) planes 10 bits per channel */ + +/* + * 3 plane YCbCr LSB aligned + * index 0 = Y plane, [15:0] x:Y [4:12] little endian + * index 1 = Cr plane, [15:0] x:Cr [4:12] little endian + * index 2 = Cb plane, [15:0] x:Cb [4:12] little endian + */ +#define DRM_FORMAT_I012fourcc_code('I', '0', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes 12 bits per channel */ +#define DRM_FORMAT_I212fourcc_code('I', '2', '1', '2') /* 2x1 subsampled Cb (1) and Cr (2) planes 12 bits per channel */ +#define DRM_FORMAT_I412fourcc_code('I', '4', '1', '2') /* non-subsampled Cb (1) and Cr (2) planes 12 bits pe
Re: [PATCH v2 0/8] DRM Rust abstractions
On 4/11/25 1:55 AM, Danilo Krummrich wrote: This is the series for the initial DRM Rust abstractions, including DRM device / driver, IOCTL, File and GEM object abstractions. With the changes requested by Alyssa and Lyude, applied to nova-next, thanks!
RE: [PATCH v21 4/5] drm/xe/xe_vm: Add per VM fault info
-Original Message- From: Lin, Shuicheng Sent: Wednesday, April 23, 2025 8:49 PM To: Cavitt, Jonathan ; intel...@lists.freedesktop.org Cc: Gupta, saurabhg ; Zuo, Alex ; joonas.lahti...@linux.intel.com; Brost, Matthew ; Zhang, Jianxun ; dri-devel@lists.freedesktop.org; Wajdeczko, Michal ; Mrozek, Michal ; Jadav, Raag ; Harrison, John C ; Briano, Ivan ; Auld, Matthew Subject: RE: [PATCH v21 4/5] drm/xe/xe_vm: Add per VM fault info > > On Wed, April 23, 2025 1:19 PM Cavitt, Jonathan wrote: > > Add additional information to each VM so they can report up to the first > > 50 seen faults. Only pagefaults are saved this way currently, though in the > > future, all faults should be tracked by the VM for future reporting. > > > > Additionally, of the pagefaults reported, only failed pagefaults are saved > > this > > way, as successful pagefaults should recover silently and not need to be > > reported to userspace. > > > > v2: > > - Free vm after use (Shuicheng) > > - Compress pf copy logic (Shuicheng) > > - Update fault_unsuccessful before storing (Shuicheng) > > - Fix old struct name in comments (Shuicheng) > > - Keep first 50 pagefaults instead of last 50 (Jianxun) > > > > v3: > > - Avoid unnecessary execution by checking MAX_PFS earlier (jcavitt) > > - Fix double-locking error (jcavitt) > > - Assert kmemdump is successful (Shuicheng) > > > > v4: > > - Rename xe_vm.pfs to xe_vm.faults (jcavitt) > > - Store fault data and not pagefault in xe_vm faults list (jcavitt) > > - Store address, address type, and address precision per fault (jcavitt) > > - Store engine class and instance data per fault (Jianxun) > > - Add and fix kernel docs (Michal W) > > - Properly handle kzalloc error (Michal W) > > - s/MAX_PFS/MAX_FAULTS_SAVED_PER_VM (Michal W) > > - Store fault level per fault (Micahl M) > > > > v5: > > - Store fault and access type instead of address type (Jianxun) > > > > v6: > > - Store pagefaults in non-fault-mode VMs as well (Jianxun) > > > > v7: > > - Fix kernel docs and comments (Michal W) > > > > v8: > > - Fix double-locking issue (Jianxun) > > > > v9: > > - Do not report faults from reserved engines (Jianxun) > > > > v10: > > - Remove engine class and instance (Ivan) > > > > v11: > > - Perform kzalloc outside of lock (Auld) > > > > Signed-off-by: Jonathan Cavitt > > Suggested-by: Matthew Brost > > Cc: Shuicheng Lin > > Cc: Jianxun Zhang > > Cc: Michal Wajdeczko > > Cc: Michal Mzorek > > Cc: Ivan Briano > > Cc: Matthew Auld > > --- > > drivers/gpu/drm/xe/xe_gt_pagefault.c | 26 > > drivers/gpu/drm/xe/xe_vm.c | 88 > > drivers/gpu/drm/xe/xe_vm.h | 9 +++ > > drivers/gpu/drm/xe/xe_vm_types.h | 28 + > > 4 files changed, 151 insertions(+) > > > > diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c > > b/drivers/gpu/drm/xe/xe_gt_pagefault.c > > index 93afa54c8780..a84f6247f8a2 100644 > > --- a/drivers/gpu/drm/xe/xe_gt_pagefault.c > > +++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c > > @@ -345,6 +345,31 @@ int xe_guc_pagefault_handler(struct xe_guc *guc, > > u32 *msg, u32 len) > > return full ? -ENOSPC : 0; > > } > > > > +static void save_pagefault_to_vm(struct xe_device *xe, struct > > +xe_gt_pagefault *pf) { > > + struct xe_vm *vm; > > + > > + /* > > +* Pagefault may be associated to VM that is not in fault mode. > > +* Perform asid_to_vm behavior, except if vm is not in fault > > +* mode, return the VM anyways. > > +*/ > > + down_read(&xe->usm.lock); > > + vm = xa_load(&xe->usm.asid_to_vm, pf->asid); > > + if (vm) > > + xe_vm_get(vm); > > + else > > + vm = ERR_PTR(-EINVAL); > > + up_read(&xe->usm.lock); > > + > > + if (IS_ERR(vm)) > > + return; > > + > > + xe_vm_add_fault_entry_pf(vm, pf); > > + > > + xe_vm_put(vm); > > +} > > + > > #define USM_QUEUE_MAX_RUNTIME_MS 20 > > > > static void pf_queue_work_func(struct work_struct *w) @@ -364,6 +389,7 > > @@ static void pf_queue_work_func(struct work_struct *w) > > if (unlikely(ret)) { > > print_pagefault(xe, &pf); > > pf.fault_unsuccessful = 1; > > + save_pagefault_to_vm(xe, &pf); > > drm_dbg(&xe->drm, "Fault response: > > Unsuccessful %d\n", ret); > > } > > > > diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index > > 0c69ef6b5ec5..107e397b4987 100644 > > --- a/drivers/gpu/drm/xe/xe_vm.c > > +++ b/drivers/gpu/drm/xe/xe_vm.c > > @@ -27,7 +27,9 @@ > > #include "xe_device.h" > > #include "xe_drm_client.h" > > #include "xe_exec_queue.h" > > +#include "xe_gt.h" > > #include "xe_gt_pagefault.h" > > +#include "xe_gt_pagefault_types.h" > > #include "xe_gt_tlb_invalidation.h" > > #include "xe_migrate.h" > > #include "xe_pat.h" > > @@ -778,6 +780,87 @@ int xe_vm_userptr_check_repin(struct xe_vm *vm) > > list_empty_careful(&vm->userptr.invalidated)) ? 0 : - >
Re: [PATCH 13/16] gpu: nova-core: Add support for VBIOS ucode extraction for boot
On 4/23/2025 10:06 AM, Danilo Krummrich wrote: [...] >> + >> +/// Probe for VBIOS extraction >> +/// Once the VBIOS object is built, bar0 is not read for vbios purposes >> anymore. >> +pub(crate) fn probe(bar0: &Devres) -> Result { > > Let's not call it probe(), what about VBios::parse(), or simply VBios::new()? > Yes, new() is better. I changed it. >> +// VBIOS data vector: As BIOS images are scanned, they are added to >> this vector >> +// for reference or copying into other data structures. It is the >> entire >> +// scanned contents of the VBIOS which progressively extends. It is >> used >> +// so that we do not re-read any contents that are already read as >> we use >> +// the cumulative length read so far, and re-read any gaps as we >> extend >> +// the length >> +let mut data = KVec::new(); >> + >> +// Loop through all the BiosImage and extract relevant ones and >> relevant data from them >> +let mut cur_offset = 0; > > I suggest to create a new type that contains data and offset and implement > read_bios_image_at_offset() and friends as methods of this type. I think this > would turn out much cleaner. I moved it into struct Vbios {} itself instead of introducing a new type. Is that Ok? I agree it is cleaner. Please see below link for this particular refactor (moving data) and let me know if it looks Ok to you: http://bit.ly/4lHfDKZ Thanks! - Joel
[PATCH v2 01/34] drm: convert many bridge drivers from devm_kzalloc() to devm_drm_bridge_alloc() API
devm_drm_bridge_alloc() is the new API to be used for allocating (and partially initializing) a private driver struct embedding a struct drm_bridge. For many drivers having a simple code flow in the probe function, this commit does a mass conversion automatically with the following semantic patch. The changes have been reviewed manually for correctness as well as to find any false positives. @@ type T; identifier C; identifier BR; expression DEV; expression FUNCS; @@ -T *C; +T *C; ... ( -C = devm_kzalloc(DEV, ...); -if (!C) -return -ENOMEM; +C = devm_drm_bridge_alloc(DEV, T, BR, FUNCS); +if (IS_ERR(C)) + return PTR_ERR(C); | -C = devm_kzalloc(DEV, ...); -if (!C) -return ERR_PTR(-ENOMEM); +C = devm_drm_bridge_alloc(DEV, T, BR, FUNCS); +if (IS_ERR(C)) + return PTR_ERR(C); ) ... -C->BR.funcs = FUNCS; Signed-off-by: Luca Ceresoli --- Cc: Adam Ford Cc: Adrien Grassein Cc: Aleksandr Mishin Cc: Andy Yan Cc: AngeloGioacchino Del Regno Cc: Benson Leung Cc: Biju Das Cc: Christoph Fritz Cc: Cristian Ciocaltea Cc: Detlev Casanova Cc: Dharma Balasubiramani Cc: Guenter Roeck Cc: Heiko Stuebner Cc: Jani Nikula Cc: Janne Grunau Cc: Jerome Brunet Cc: Jesse Van Gavere Cc: Kevin Hilman Cc: Kieran Bingham Cc: Liu Ying Cc: Manikandan Muralidharan Cc: Martin Blumenstingl Cc: Matthias Brugger Cc: Philipp Zabel Cc: Phong LE Cc: Sasha Finkelstein Cc: Sugar Zhang Cc: Sui Jingfeng Cc: Tomi Valkeinen Cc: Vitalii Mordan Changed in v2: - added missing PTR_ERR() in the second spatch alternative --- drivers/gpu/drm/adp/adp-mipi.c | 8 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c| 9 - drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c | 9 - drivers/gpu/drm/bridge/aux-bridge.c | 9 - drivers/gpu/drm/bridge/aux-hpd-bridge.c | 9 + drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c | 8 drivers/gpu/drm/bridge/chipone-icn6211.c| 9 - drivers/gpu/drm/bridge/chrontel-ch7033.c| 8 drivers/gpu/drm/bridge/cros-ec-anx7688.c| 9 - drivers/gpu/drm/bridge/fsl-ldb.c| 7 +++ drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c | 9 - drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c| 10 -- drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 8 drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c| 8 drivers/gpu/drm/bridge/ite-it6263.c | 9 - drivers/gpu/drm/bridge/ite-it6505.c | 9 - drivers/gpu/drm/bridge/ite-it66121.c| 9 - drivers/gpu/drm/bridge/lontium-lt8912b.c| 9 - drivers/gpu/drm/bridge/lontium-lt9211.c | 8 +++- drivers/gpu/drm/bridge/lontium-lt9611.c | 9 - drivers/gpu/drm/bridge/lvds-codec.c | 9 - drivers/gpu/drm/bridge/microchip-lvds.c | 8 drivers/gpu/drm/bridge/nwl-dsi.c| 8 drivers/gpu/drm/bridge/parade-ps8622.c | 9 - drivers/gpu/drm/bridge/parade-ps8640.c | 9 - drivers/gpu/drm/bridge/sii9234.c| 9 - drivers/gpu/drm/bridge/sil-sii8620.c| 9 - drivers/gpu/drm/bridge/simple-bridge.c | 10 -- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c| 8 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 8 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c | 8 drivers/gpu/drm/bridge/tc358762.c | 9 - drivers/gpu/drm/bridge/tc358764.c | 9 - drivers/gpu/drm/bridge/tc358768.c | 9 - drivers/gpu/drm/bridge/tc358775.c | 9 - drivers/gpu/drm/bridge/thc63lvd1024.c | 8 drivers/gpu/drm/bridge/ti-dlpc3433.c| 9 - drivers/gpu/drm/bridge/ti-tdp158.c | 8 drivers/gpu/drm/bridge/ti-tfp410.c | 9 - drivers/gpu/drm/bridge/ti-tpd12s015.c | 9 - drivers/gpu/drm/mediatek/mtk_dp.c | 9 - drivers/gpu/drm/mediatek/mtk_dpi.c | 9 - drivers/gpu/drm/mediatek/mtk_dsi.c | 9 - drivers/gpu/drm/mediatek/mtk_hdmi.c | 9 - drivers/gpu/drm/meson/meson_encoder_cvbs.c | 12 ++-- drivers/gpu/drm/meson/meson_encoder_dsi.c | 12 ++-- drivers/gpu/drm/meson/meson_encoder_hdmi.c | 12 ++-- drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c | 9 - drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 10 -- 49 files changed, 201 insertions(+), 237 deletions(-) diff --git a
[PATCH v2 03/34] drm/bridge: analogix-anx6345: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- Cc: "Uwe Kleine-König" Cc: Andy Yan Cc: Dmitry Baryshkov Cc: Jani Nikula Cc: Sui Jingfeng --- drivers/gpu/drm/bridge/analogix/analogix-anx6345.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c index f2bafa6cf77956ecafc87aae3a2b6890bdb36cfa..f3fe47b12edca1f92ddd306d152be144df5649b5 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -664,9 +664,10 @@ static int anx6345_i2c_probe(struct i2c_client *client) struct device *dev; int i, err; - anx6345 = devm_kzalloc(&client->dev, sizeof(*anx6345), GFP_KERNEL); - if (!anx6345) - return -ENOMEM; + anx6345 = devm_drm_bridge_alloc(&client->dev, struct anx6345, bridge, + &anx6345_bridge_funcs); + if (IS_ERR(anx6345)) + return PTR_ERR(anx6345); mutex_init(&anx6345->lock); @@ -738,7 +739,6 @@ static int anx6345_i2c_probe(struct i2c_client *client) /* Look for supported chip ID */ anx6345_poweron(anx6345); if (anx6345_get_chip_id(anx6345)) { - anx6345->bridge.funcs = &anx6345_bridge_funcs; drm_bridge_add(&anx6345->bridge); return 0; -- 2.49.0
[PATCH v2 04/34] drm/bridge: anx7625: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- Cc: "Rob Herring (Arm)" Cc: Hsin-Te Yuan Cc: Jani Nikula Cc: Pin-yen Lin Cc: Sui Jingfeng Cc: Xin Ji --- drivers/gpu/drm/bridge/analogix/anx7625.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 8bfe477c476c045f8a08b6d646da7bae77693fdf..bdf8f7762e0c19d19e4c60ca0841edfc3625592c 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -2581,7 +2581,6 @@ static int anx7625_link_bridge(struct drm_dp_aux *aux) return ret; } - platform->bridge.funcs = &anx7625_bridge_funcs; platform->bridge.of_node = dev->of_node; if (!anx7625_of_panel_on_aux_bus(dev)) platform->bridge.ops |= DRM_BRIDGE_OP_EDID; @@ -2616,10 +2615,10 @@ static int anx7625_i2c_probe(struct i2c_client *client) return -ENODEV; } - platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); - if (!platform) { + platform = devm_drm_bridge_alloc(dev, struct anx7625_data, bridge, &anx7625_bridge_funcs); + if (IS_ERR(platform)) { DRM_DEV_ERROR(dev, "fail to allocate driver data\n"); - return -ENOMEM; + return PTR_ERR(platform); } pdata = &platform->pdata; -- 2.49.0
[PATCH v2 05/34] drm/bridge: cdns-dsi: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- Cc: Aradhya Bhatia Cc: Tomi Valkeinen --- drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c index b022dd6e6b6e9e43bf11583806e1a8d1e7431ae8..7604574da66606c103cc035dd94b0e211b64ebdc 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c @@ -1289,9 +1289,10 @@ static int cdns_dsi_drm_probe(struct platform_device *pdev) int ret, irq; u32 val; - dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); - if (!dsi) - return -ENOMEM; + dsi = devm_drm_bridge_alloc(&pdev->dev, struct cdns_dsi, input.bridge, + &cdns_dsi_bridge_funcs); + if (IS_ERR(dsi)) + return PTR_ERR(dsi); platform_set_drvdata(pdev, dsi); @@ -1349,7 +1350,6 @@ static int cdns_dsi_drm_probe(struct platform_device *pdev) * CDNS_DPI_INPUT. */ input->id = CDNS_DPI_INPUT; - input->bridge.funcs = &cdns_dsi_bridge_funcs; input->bridge.of_node = pdev->dev.of_node; /* Mask all interrupts before registering the IRQ handler. */ -- 2.49.0
[PATCH v2 02/34] platform: arm64: acer-aspire1-ec: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Acked-by: Ilpo Järvinen Signed-off-by: Luca Ceresoli --- Cc: "Bryan O'Donoghue" Cc: "Ilpo Järvinen" Cc: Hans de Goede --- drivers/platform/arm64/acer-aspire1-ec.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/platform/arm64/acer-aspire1-ec.c b/drivers/platform/arm64/acer-aspire1-ec.c index 958fe1bf5f85bb69ac7962f217de9f0b40cde9a1..438532a047e68799ac53a16a4c813fc16be997b9 100644 --- a/drivers/platform/arm64/acer-aspire1-ec.c +++ b/drivers/platform/arm64/acer-aspire1-ec.c @@ -452,9 +452,9 @@ static int aspire_ec_probe(struct i2c_client *client) int ret; u8 tmp; - ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL); - if (!ec) - return -ENOMEM; + ec = devm_drm_bridge_alloc(dev, struct aspire_ec, bridge, &aspire_ec_bridge_funcs); + if (IS_ERR(ec)) + return PTR_ERR(ec); ec->client = client; i2c_set_clientdata(client, ec); @@ -497,7 +497,6 @@ static int aspire_ec_probe(struct i2c_client *client) fwnode = device_get_named_child_node(dev, "connector"); if (fwnode) { INIT_WORK(&ec->work, aspire_ec_bridge_update_hpd_work); - ec->bridge.funcs = &aspire_ec_bridge_funcs; ec->bridge.of_node = to_of_node(fwnode); ec->bridge.ops = DRM_BRIDGE_OP_HPD; ec->bridge.type = DRM_MODE_CONNECTOR_USB; -- 2.49.0
[PATCH v2 14/34] drm/exynos: mic: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- Cc: Alim Akhtar Cc: Inki Dae Cc: Kyungmin Park Cc: Seung-Woo Kim --- drivers/gpu/drm/exynos/exynos_drm_mic.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c index b34ec67283370e3fa836c7df06e12e2fba524622..29a8366513fa70655c6ceec9a09db0158e7bb169 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c @@ -379,11 +379,11 @@ static int exynos_mic_probe(struct platform_device *pdev) struct resource res; int ret, i; - mic = devm_kzalloc(dev, sizeof(*mic), GFP_KERNEL); - if (!mic) { + mic = devm_drm_bridge_alloc(dev, struct exynos_mic, bridge, &mic_bridge_funcs); + if (IS_ERR(mic)) { DRM_DEV_ERROR(dev, "mic: Failed to allocate memory for MIC object\n"); - ret = -ENOMEM; + ret = PTR_ERR(mic); goto err; } @@ -421,7 +421,6 @@ static int exynos_mic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mic); - mic->bridge.funcs = &mic_bridge_funcs; mic->bridge.of_node = dev->of_node; drm_bridge_add(&mic->bridge); -- 2.49.0
[PATCH v2 10/34] drm/bridge: sii902x: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/sii902x.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 6de61d9fe06487856e8b3c32db3c8d8c25633fd8..882973e900628c0d972d32cd4ff3588432daa8e9 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -1135,7 +1135,6 @@ static int sii902x_init(struct sii902x *sii902x) if (ret) goto err_unreg_audio; - sii902x->bridge.funcs = &sii902x_bridge_funcs; sii902x->bridge.of_node = dev->of_node; sii902x->bridge.timings = &default_sii902x_timings; sii902x->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID; @@ -1170,9 +1169,9 @@ static int sii902x_probe(struct i2c_client *client) return -EIO; } - sii902x = devm_kzalloc(dev, sizeof(*sii902x), GFP_KERNEL); - if (!sii902x) - return -ENOMEM; + sii902x = devm_drm_bridge_alloc(dev, struct sii902x, bridge, &sii902x_bridge_funcs); + if (IS_ERR(sii902x)) + return PTR_ERR(sii902x); sii902x->i2c = client; sii902x->regmap = devm_regmap_init_i2c(client, &sii902x_regmap_config); -- 2.49.0
[PATCH v2 13/34] drm/bridge: ti-sn65dsi86: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Reviewed-by: Herve Codina Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index f72675766e01108d72033b8b83c25d3e4d8fd1a7..60224f476e1d048c693ab36a0a79b6897c6101a8 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -1317,7 +1317,6 @@ static int ti_sn_bridge_probe(struct auxiliary_device *adev, if (ret) return ret; - pdata->bridge.funcs = &ti_sn_bridge_funcs; pdata->bridge.of_node = np; pdata->bridge.type = pdata->next_bridge->type == DRM_MODE_CONNECTOR_DisplayPort ? DRM_MODE_CONNECTOR_DisplayPort : DRM_MODE_CONNECTOR_eDP; @@ -1907,9 +1906,9 @@ static int ti_sn65dsi86_probe(struct i2c_client *client) return -ENODEV; } - pdata = devm_kzalloc(dev, sizeof(struct ti_sn65dsi86), GFP_KERNEL); - if (!pdata) - return -ENOMEM; + pdata = devm_drm_bridge_alloc(dev, struct ti_sn65dsi86, bridge, &ti_sn_bridge_funcs); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); dev_set_drvdata(dev, pdata); pdata->dev = dev; -- 2.49.0
[PATCH v2 16/34] drm/msm/dp: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Ceresoli --- Cc: Abhinav Kumar Cc: Bjorn Andersson Cc: Marijn Suijten Cc: Rob Clark Cc: Sean Paul --- drivers/gpu/drm/msm/dp/dp_drm.c | 9 + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index cca57e56c906255a315e759e85a5af5982c80e9c..293f4745f1e20ba67da1d3fc218da3d90e1be588 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -296,14 +296,15 @@ int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev, struct msm_dp_bridge *msm_dp_bridge; struct drm_bridge *bridge; - msm_dp_bridge = devm_kzalloc(dev->dev, sizeof(*msm_dp_bridge), GFP_KERNEL); - if (!msm_dp_bridge) - return -ENOMEM; + msm_dp_bridge = devm_drm_bridge_alloc(dev->dev, struct msm_dp_bridge, bridge, + msm_dp_display->is_edp ? &msm_edp_bridge_ops : + &msm_dp_bridge_ops); + if (IS_ERR(msm_dp_bridge)) + return PTR_ERR(msm_dp_bridge); msm_dp_bridge->msm_dp_display = msm_dp_display; bridge = &msm_dp_bridge->bridge; - bridge->funcs = msm_dp_display->is_edp ? &msm_edp_bridge_ops : &msm_dp_bridge_ops; bridge->type = msm_dp_display->connector_type; bridge->ycbcr_420_allowed = yuv_supported; -- 2.49.0
[PATCH v2 06/34] drm/bridge: display-connector: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/display-connector.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c index 09c08a53d5bdc5c48f5d520472f5a311289d4862..badd2c7f91a186e9a47c5a4ddc870d269f3798ab 100644 --- a/drivers/gpu/drm/bridge/display-connector.c +++ b/drivers/gpu/drm/bridge/display-connector.c @@ -210,9 +210,10 @@ static int display_connector_probe(struct platform_device *pdev) const char *label = NULL; int ret; - conn = devm_kzalloc(&pdev->dev, sizeof(*conn), GFP_KERNEL); - if (!conn) - return -ENOMEM; + conn = devm_drm_bridge_alloc(&pdev->dev, struct display_connector, bridge, +&display_connector_bridge_funcs); + if (IS_ERR(conn)) + return PTR_ERR(conn); platform_set_drvdata(pdev, conn); @@ -362,7 +363,6 @@ static int display_connector_probe(struct platform_device *pdev) } } - conn->bridge.funcs = &display_connector_bridge_funcs; conn->bridge.of_node = pdev->dev.of_node; if (conn->bridge.ddc) -- 2.49.0
[PATCH v2 15/34] drm/mcde: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- Cc: Linus Walleij --- drivers/gpu/drm/mcde/mcde_dsi.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c index b302d8ec3ad0e82ace9c10194ae37948ebb8e753..a3423459dd7ac8395b77d0479a02ebb3a9ba259c 100644 --- a/drivers/gpu/drm/mcde/mcde_dsi.c +++ b/drivers/gpu/drm/mcde/mcde_dsi.c @@ -1138,7 +1138,6 @@ static int mcde_dsi_bind(struct device *dev, struct device *master, d->bridge_out = bridge; /* Create a bridge for this DSI channel */ - d->bridge.funcs = &mcde_dsi_bridge_funcs; d->bridge.of_node = dev->of_node; drm_bridge_add(&d->bridge); @@ -1174,9 +1173,9 @@ static int mcde_dsi_probe(struct platform_device *pdev) u32 dsi_id; int ret; - d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); - if (!d) - return -ENOMEM; + d = devm_drm_bridge_alloc(dev, struct mcde_dsi, bridge, &mcde_dsi_bridge_funcs); + if (IS_ERR(d)) + return PTR_ERR(d); d->dev = dev; platform_set_drvdata(pdev, d); -- 2.49.0
[PATCH v2 08/34] drm/bridge: megachips-stdpxxxx-ge-b850v3-fw: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- Cc: Ian Ray Cc: Martyn Welch Cc: Peter Senna Tschudin --- drivers/gpu/drm/bridge/megachips-stdp-ge-b850v3-fw.c | 11 --- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/megachips-stdp-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdp-ge-b850v3-fw.c index 15a5a1f644fc10182c55bc9e489ccb81d4f924f9..81dde9ed7bcf7cacae000d9da31a3a5c347ce037 100644 --- a/drivers/gpu/drm/bridge/megachips-stdp-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdp-ge-b850v3-fw.c @@ -225,13 +225,11 @@ static int ge_b850v3_lvds_init(struct device *dev) if (ge_b850v3_lvds_ptr) goto success; - ge_b850v3_lvds_ptr = devm_kzalloc(dev, - sizeof(*ge_b850v3_lvds_ptr), - GFP_KERNEL); - - if (!ge_b850v3_lvds_ptr) { + ge_b850v3_lvds_ptr = devm_drm_bridge_alloc(dev, struct ge_b850v3_lvds, bridge, + &ge_b850v3_lvds_funcs); + if (IS_ERR(ge_b850v3_lvds_ptr)) { mutex_unlock(&ge_b850v3_lvds_dev_mutex); - return -ENOMEM; + return PTR_ERR(ge_b850v3_lvds_ptr); } success: @@ -264,7 +262,6 @@ static int ge_b850v3_register(void) struct device *dev = &stdp4028_i2c->dev; /* drm bridge initialization */ - ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs; ge_b850v3_lvds_ptr->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID; ge_b850v3_lvds_ptr->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; -- 2.49.0
[PATCH v2 09/34] drm/bridge: nxp-ptn3460: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/nxp-ptn3460.c | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index 25d7c415478b14ef634bff4185a8dd8e866be0c6..7acb11f16dc19e87a84cc765b1cebef158662c00 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -261,10 +261,10 @@ static int ptn3460_probe(struct i2c_client *client) struct drm_bridge *panel_bridge; int ret; - ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL); - if (!ptn_bridge) { - return -ENOMEM; - } + ptn_bridge = devm_drm_bridge_alloc(dev, struct ptn3460_bridge, bridge, + &ptn3460_bridge_funcs); + if (IS_ERR(ptn_bridge)) + return PTR_ERR(ptn_bridge); panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); if (IS_ERR(panel_bridge)) @@ -300,7 +300,6 @@ static int ptn3460_probe(struct i2c_client *client) return ret; } - ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs; ptn_bridge->bridge.ops = DRM_BRIDGE_OP_EDID; ptn_bridge->bridge.type = DRM_MODE_CONNECTOR_LVDS; ptn_bridge->bridge.of_node = dev->of_node; -- 2.49.0
[PATCH v2 12/34] drm/bridge: tda998x: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Ceresoli --- Cc: Russell King --- drivers/gpu/drm/bridge/tda998x_drv.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/tda998x_drv.c b/drivers/gpu/drm/bridge/tda998x_drv.c index ac87033ba5372e32cb8dc3abafc8cf1ff8273103..850909f78a7bc0fab54a60880f9a0657e99056f3 100644 --- a/drivers/gpu/drm/bridge/tda998x_drv.c +++ b/drivers/gpu/drm/bridge/tda998x_drv.c @@ -1781,9 +1781,9 @@ static int tda998x_create(struct device *dev) u32 video; int rev_lo, rev_hi, ret; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + priv = devm_drm_bridge_alloc(dev, struct tda998x_priv, bridge, &tda998x_bridge_funcs); + if (IS_ERR(priv)) + return PTR_ERR(priv); dev_set_drvdata(dev, priv); @@ -1948,7 +1948,6 @@ static int tda998x_create(struct device *dev) tda998x_audio_codec_init(priv, &client->dev); } - priv->bridge.funcs = &tda998x_bridge_funcs; #ifdef CONFIG_OF priv->bridge.of_node = dev->of_node; #endif -- 2.49.0
[PATCH v2 18/34] drm/msm/hdmi: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Ceresoli --- Cc: Abhinav Kumar Cc: Marijn Suijten Cc: Rob Clark Cc: Sean Paul --- drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index ab6c8bc4a30b681f7de8ca7031f833795d1f7d94..7f71956806a25a1ab23293284da83ed4a8759c98 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -498,16 +498,15 @@ int msm_hdmi_bridge_init(struct hdmi *hdmi) struct hdmi_bridge *hdmi_bridge; int ret; - hdmi_bridge = devm_kzalloc(hdmi->dev->dev, - sizeof(*hdmi_bridge), GFP_KERNEL); - if (!hdmi_bridge) - return -ENOMEM; + hdmi_bridge = devm_drm_bridge_alloc(hdmi->dev->dev, struct hdmi_bridge, base, + &msm_hdmi_bridge_funcs); + if (IS_ERR(hdmi_bridge)) + return PTR_ERR(hdmi_bridge); hdmi_bridge->hdmi = hdmi; INIT_WORK(&hdmi_bridge->hpd_work, msm_hdmi_hotplug_work); bridge = &hdmi_bridge->base; - bridge->funcs = &msm_hdmi_bridge_funcs; bridge->ddc = hdmi->i2c; bridge->type = DRM_MODE_CONNECTOR_HDMIA; bridge->vendor = "Qualcomm"; -- 2.49.0
[PATCH v2 20/34] drm/omap: dss: dsi: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- Cc: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dsi.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 91ee63bfe0bc73e28877d0383812225867e167a4..b129e5a8d791507098c7b8d1bc54f54c4b453954 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -4701,7 +4701,6 @@ static const struct drm_bridge_funcs dsi_bridge_funcs = { static void dsi_bridge_init(struct dsi_data *dsi) { - dsi->bridge.funcs = &dsi_bridge_funcs; dsi->bridge.of_node = dsi->host.dev->of_node; dsi->bridge.type = DRM_MODE_CONNECTOR_DSI; @@ -4894,9 +4893,9 @@ static int dsi_probe(struct platform_device *pdev) unsigned int i; int r; - dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); - if (!dsi) - return -ENOMEM; + dsi = devm_drm_bridge_alloc(dev, struct dsi_data, bridge, &dsi_bridge_funcs); + if (IS_ERR(dsi)) + return PTR_ERR(dsi); dsi->dev = dev; dev_set_drvdata(dev, dsi); -- 2.49.0
[PATCH v2 07/34] drm/bridge: lt9611uxc: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index bb33c30d3f88878736815b270813a035222aead1..766da2cb45a7e2a79256185b8e2d3bd1eff3648f 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -775,9 +775,9 @@ static int lt9611uxc_probe(struct i2c_client *client) return -ENODEV; } - lt9611uxc = devm_kzalloc(dev, sizeof(*lt9611uxc), GFP_KERNEL); - if (!lt9611uxc) - return -ENOMEM; + lt9611uxc = devm_drm_bridge_alloc(dev, struct lt9611uxc, bridge, <9611uxc_bridge_funcs); + if (IS_ERR(lt9611uxc)) + return PTR_ERR(lt9611uxc); lt9611uxc->dev = dev; lt9611uxc->client = client; @@ -856,7 +856,6 @@ static int lt9611uxc_probe(struct i2c_client *client) i2c_set_clientdata(client, lt9611uxc); - lt9611uxc->bridge.funcs = <9611uxc_bridge_funcs; lt9611uxc->bridge.of_node = client->dev.of_node; lt9611uxc->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID; if (lt9611uxc->hpd_supported) -- 2.49.0
[PATCH v2 11/34] drm/bridge: dw-hdmi: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- Cc: Cristian Ciocaltea --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index deaba3b6f99789067d14b76d228b58816a09b395..8791408dd1ff2d3c3b223b4f7f6f00edb275abf0 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -,9 +,9 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, u8 config0; u8 config3; - hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); - if (!hdmi) - return ERR_PTR(-ENOMEM); + hdmi = devm_drm_bridge_alloc(dev, struct dw_hdmi, bridge, &dw_hdmi_bridge_funcs); + if (IS_ERR(hdmi)) + return hdmi; hdmi->plat_data = plat_data; hdmi->dev = dev; @@ -3495,7 +3495,6 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, } hdmi->bridge.driver_private = hdmi; - hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD; hdmi->bridge.interlace_allowed = true; -- 2.49.0
[PATCH v2 19/34] drm/omap: dss: dpi: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- Cc: "Rob Herring (Arm)" Cc: Helge Deller Cc: Kuninori Morimoto Cc: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/dpi.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 6eff97a091602f6d137095b3b7bf54fce17e8d3e..9f86db774c395db7e3396cbf2694748fc23c309d 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -562,7 +562,6 @@ static const struct drm_bridge_funcs dpi_bridge_funcs = { static void dpi_bridge_init(struct dpi_data *dpi) { - dpi->bridge.funcs = &dpi_bridge_funcs; dpi->bridge.of_node = dpi->pdev->dev.of_node; dpi->bridge.type = DRM_MODE_CONNECTOR_DPI; @@ -707,9 +706,9 @@ int dpi_init_port(struct dss_device *dss, struct platform_device *pdev, u32 datalines; int r; - dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL); - if (!dpi) - return -ENOMEM; + dpi = devm_drm_bridge_alloc(&pdev->dev, struct dpi_data, bridge, &dpi_bridge_funcs); + if (IS_ERR(dpi)) + return PTR_ERR(dpi); ep = of_graph_get_next_port_endpoint(port, NULL); if (!ep) -- 2.49.0
[PATCH v2 30/34] drm/bridge: imx8qxp-pixel-combiner: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. This driver embeds an array of channels in the main struct, and each channel embeds a drm_bridge. This prevents dynamic, refcount-based deallocation of the bridges. To make the new, dynamic bridge allocation possible: * change the array of channels into an array of channel pointers * allocate each channel using devm_drm_bridge_alloc() * adapt the code wherever using the channels Signed-off-by: Luca Ceresoli --- Cc: Liu Ying --- drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c | 18 -- 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c index 1f6fd488e7039e943351006d3373009f0c15cb08..40a8a5a53a781137e722309ff91692cf90d881da 100644 --- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c +++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c @@ -68,7 +68,7 @@ struct imx8qxp_pc_channel { struct imx8qxp_pc { struct device *dev; - struct imx8qxp_pc_channel ch[2]; + struct imx8qxp_pc_channel *ch[2]; struct clk *clk_apb; void __iomem *base; }; @@ -307,7 +307,14 @@ static int imx8qxp_pc_bridge_probe(struct platform_device *pdev) goto free_child; } - ch = &pc->ch[i]; + ch = devm_drm_bridge_alloc(dev, struct imx8qxp_pc_channel, bridge, + &imx8qxp_pc_bridge_funcs); + if (IS_ERR(ch)) { + ret = PTR_ERR(ch); + goto free_child; + } + + pc->ch[i] = ch; ch->pc = pc; ch->stream_id = i; @@ -333,7 +340,6 @@ static int imx8qxp_pc_bridge_probe(struct platform_device *pdev) of_node_put(remote); ch->bridge.driver_private = ch; - ch->bridge.funcs = &imx8qxp_pc_bridge_funcs; ch->bridge.of_node = child; ch->is_available = true; @@ -345,8 +351,8 @@ static int imx8qxp_pc_bridge_probe(struct platform_device *pdev) free_child: of_node_put(child); - if (i == 1 && pc->ch[0].next_bridge) - drm_bridge_remove(&pc->ch[0].bridge); + if (i == 1 && pc->ch[0]->next_bridge) + drm_bridge_remove(&pc->ch[0]->bridge); pm_runtime_disable(dev); return ret; @@ -359,7 +365,7 @@ static void imx8qxp_pc_bridge_remove(struct platform_device *pdev) int i; for (i = 0; i < 2; i++) { - ch = &pc->ch[i]; + ch = pc->ch[i]; if (!ch->is_available) continue; -- 2.49.0
[PATCH v2 26/34] drm/bridge: stm_lvds: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- Cc: Alexandre Torgue Cc: Maxime Coquelin Cc: Philippe Cornu Cc: Raphael Gallais-Pou Cc: Yannick Fertre --- drivers/gpu/drm/stm/lvds.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/stm/lvds.c b/drivers/gpu/drm/stm/lvds.c index a3ae9a93ce6670eb2c4dd36b3e572fcbca791a1c..07788e8d3d8302a3951e97d64736b721033998d3 100644 --- a/drivers/gpu/drm/stm/lvds.c +++ b/drivers/gpu/drm/stm/lvds.c @@ -1049,9 +1049,9 @@ static int lvds_probe(struct platform_device *pdev) dev_dbg(dev, "Probing LVDS driver...\n"); - lvds = devm_kzalloc(dev, sizeof(*lvds), GFP_KERNEL); - if (!lvds) - return -ENOMEM; + lvds = devm_drm_bridge_alloc(dev, struct stm_lvds, lvds_bridge, &lvds_bridge_funcs); + if (IS_ERR(lvds)) + return PTR_ERR(lvds); lvds->dev = dev; @@ -1164,7 +1164,6 @@ static int lvds_probe(struct platform_device *pdev) goto err_lvds_probe; } - lvds->lvds_bridge.funcs = &lvds_bridge_funcs; lvds->lvds_bridge.of_node = dev->of_node; lvds->hw_version = lvds_read(lvds, LVDS_VERR); -- 2.49.0
[PATCH v2 27/34] drm/vc4: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. This driver already implements refcounting of the struct vc4_dsi, which embeds struct drm_bridge. Now this is a duplicate of the refcounting implemented by the DRM bridge core, so convert the vc4_dsi_get/put() calls into drm_bridge_get/put() calls and get rid of the driver-specific refcounting implementation. Signed-off-by: Luca Ceresoli --- Cc: "Maíra Canal" Cc: Dave Stevenson Cc: Raspberry Pi Kernel Maintenance Changed in v2: - fix error code checking --- drivers/gpu/drm/vc4/vc4_dsi.c | 34 +- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index efc6f6078b026764c59cfb2a33b28a88b7018c3a..458e5d9879645f18bcbcaeeb71b5f1038f9581da 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -552,8 +552,6 @@ struct vc4_dsi { struct vc4_encoder encoder; struct mipi_dsi_host dsi_host; - struct kref kref; - struct platform_device *pdev; struct drm_bridge *out_bridge; @@ -1622,29 +1620,11 @@ static void vc4_dsi_dma_chan_release(void *ptr) dsi->reg_dma_chan = NULL; } -static void vc4_dsi_release(struct kref *kref) -{ - struct vc4_dsi *dsi = - container_of(kref, struct vc4_dsi, kref); - - kfree(dsi); -} - -static void vc4_dsi_get(struct vc4_dsi *dsi) -{ - kref_get(&dsi->kref); -} - -static void vc4_dsi_put(struct vc4_dsi *dsi) -{ - kref_put(&dsi->kref, &vc4_dsi_release); -} - static void vc4_dsi_release_action(struct drm_device *drm, void *ptr) { struct vc4_dsi *dsi = ptr; - vc4_dsi_put(dsi); + drm_bridge_put(&dsi->bridge); } static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) @@ -1655,7 +1635,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) struct drm_encoder *encoder = &dsi->encoder.base; int ret; - vc4_dsi_get(dsi); + drm_bridge_get(&dsi->bridge); ret = drmm_add_action_or_reset(drm, vc4_dsi_release_action, dsi); if (ret) @@ -1810,15 +1790,12 @@ static int vc4_dsi_dev_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct vc4_dsi *dsi; - dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); - if (!dsi) - return -ENOMEM; + dsi = devm_drm_bridge_alloc(&pdev->dev, struct vc4_dsi, bridge, &vc4_dsi_bridge_funcs); + if (IS_ERR(dsi)) + return PTR_ERR(dsi); dev_set_drvdata(dev, dsi); - kref_init(&dsi->kref); - dsi->pdev = pdev; - dsi->bridge.funcs = &vc4_dsi_bridge_funcs; #ifdef CONFIG_OF dsi->bridge.of_node = dev->of_node; #endif @@ -1836,7 +1813,6 @@ static void vc4_dsi_dev_remove(struct platform_device *pdev) struct vc4_dsi *dsi = dev_get_drvdata(dev); mipi_dsi_host_unregister(&dsi->dsi_host); - vc4_dsi_put(dsi); } struct platform_driver vc4_dsi_driver = { -- 2.49.0
[PATCH v2 24/34] drm/omap: dss: venc: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Switching from a non-devm to a devm allocation allows removing the kfree() in the remove function and in the probe error management code, and as a consequence to simplify the code flow by removing now unnecessary gotos. Signed-off-by: Luca Ceresoli --- Cc: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/venc.c | 23 --- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 50349518eda1630400529caf27ca4469bb09fc82..9b5d53dc361e654a2e4009c3c81b726f9ef76ced 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -664,7 +664,6 @@ static const struct drm_bridge_funcs venc_bridge_funcs = { static void venc_bridge_init(struct venc_device *venc) { - venc->bridge.funcs = &venc_bridge_funcs; venc->bridge.of_node = venc->pdev->dev.of_node; venc->bridge.ops = DRM_BRIDGE_OP_MODES; venc->bridge.type = DRM_MODE_CONNECTOR_SVIDEO; @@ -809,9 +808,9 @@ static int venc_probe(struct platform_device *pdev) struct venc_device *venc; int r; - venc = kzalloc(sizeof(*venc), GFP_KERNEL); - if (!venc) - return -ENOMEM; + venc = devm_drm_bridge_alloc(&pdev->dev, struct venc_device, bridge, &venc_bridge_funcs); + if (IS_ERR(venc)) + return PTR_ERR(venc); venc->pdev = pdev; @@ -824,26 +823,24 @@ static int venc_probe(struct platform_device *pdev) venc->config = &venc_config_pal_trm; venc->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(venc->base)) { - r = PTR_ERR(venc->base); - goto err_free; - } + if (IS_ERR(venc->base)) + return PTR_ERR(venc->base); venc->vdda_dac_reg = devm_regulator_get(&pdev->dev, "vdda"); if (IS_ERR(venc->vdda_dac_reg)) { r = PTR_ERR(venc->vdda_dac_reg); if (r != -EPROBE_DEFER) DSSERR("can't get VDDA_DAC regulator\n"); - goto err_free; + return r; } r = venc_get_clocks(venc); if (r) - goto err_free; + return r; r = venc_probe_of(venc); if (r) - goto err_free; + return r; pm_runtime_enable(&pdev->dev); @@ -861,8 +858,6 @@ static int venc_probe(struct platform_device *pdev) venc_uninit_output(venc); err_pm_disable: pm_runtime_disable(&pdev->dev); -err_free: - kfree(venc); return r; } @@ -875,8 +870,6 @@ static void venc_remove(struct platform_device *pdev) venc_uninit_output(venc); pm_runtime_disable(&pdev->dev); - - kfree(venc); } static __maybe_unused int venc_runtime_suspend(struct device *dev) -- 2.49.0
[PATCH v2 29/34] drm: zynqmp_dp: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. This driver has a peculiar structure. zynqmp_dpsub.c is the actual driver, which delegates to a submodule (zynqmp_dp.c) the allocation of a sub-structure embedding the drm_bridge and its initialization, however it does not delegate the drm_bridge_add(). Hence, following carefully the code flow, it is correct to change the allocation function and .funcs assignment in the submodule, while the drm_bridge_add() is not in that submodule. Signed-off-by: Luca Ceresoli --- Cc: Laurent Pinchart Cc: Michal Simek Cc: Tomi Valkeinen Changes in v2: - rebased on current drm-misc-next - remove the kfree() calls too, as we are converting from kzalloc+kfree, not from devm_kzalloc --- drivers/gpu/drm/xlnx/zynqmp_dp.c| 31 +++ drivers/gpu/drm/xlnx/zynqmp_dpsub.c | 1 - 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 238cbb49963efa6e8cc737d8a6e76250f6531276..02e1feaa611596a24217136ee8ce7f5d2f1900a2 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -2439,9 +2439,9 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub) struct zynqmp_dp *dp; int ret; - dp = kzalloc(sizeof(*dp), GFP_KERNEL); - if (!dp) - return -ENOMEM; + dp = devm_drm_bridge_alloc(&pdev->dev, struct zynqmp_dp, bridge, &zynqmp_dp_bridge_funcs); + if (IS_ERR(dp)) + return PTR_ERR(dp); dp->dev = &pdev->dev; dp->dpsub = dpsub; @@ -2454,31 +2454,25 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub) /* Acquire all resources (IOMEM, IRQ and PHYs). */ dp->iomem = devm_platform_ioremap_resource_byname(pdev, "dp"); - if (IS_ERR(dp->iomem)) { - ret = PTR_ERR(dp->iomem); - goto err_free; - } + if (IS_ERR(dp->iomem)) + return PTR_ERR(dp->iomem); dp->irq = platform_get_irq(pdev, 0); - if (dp->irq < 0) { - ret = dp->irq; - goto err_free; - } + if (dp->irq < 0) + return dp->irq; dp->reset = devm_reset_control_get(dp->dev, NULL); - if (IS_ERR(dp->reset)) { - ret = dev_err_probe(dp->dev, PTR_ERR(dp->reset), + if (IS_ERR(dp->reset)) + return dev_err_probe(dp->dev, PTR_ERR(dp->reset), "failed to get reset\n"); - goto err_free; - } ret = zynqmp_dp_reset(dp, true); if (ret < 0) - goto err_free; + return ret; ret = zynqmp_dp_reset(dp, false); if (ret < 0) - goto err_free; + return ret; ret = zynqmp_dp_phy_probe(dp); if (ret) @@ -2486,7 +2480,6 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub) /* Initialize the bridge. */ bridge = &dp->bridge; - bridge->funcs = &zynqmp_dp_bridge_funcs; bridge->ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD; bridge->type = DRM_MODE_CONNECTOR_DisplayPort; @@ -2539,8 +2532,6 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub) zynqmp_dp_phy_exit(dp); err_reset: zynqmp_dp_reset(dp, true); -err_free: - kfree(dp); return ret; } diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index 3a9544b97bc5311f9adeb57c08c837a04b6922fa..2764c4b17c5e49611db8adf41dd09e3134c2d524 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -180,7 +180,6 @@ static int zynqmp_dpsub_parse_dt(struct zynqmp_dpsub *dpsub) void zynqmp_dpsub_release(struct zynqmp_dpsub *dpsub) { kfree(dpsub->disp); - kfree(dpsub->dp); kfree(dpsub); } -- 2.49.0
[PATCH v2 17/34] drm/msm/dsi: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Reviewed-by: Dmitry Baryshkov Signed-off-by: Luca Ceresoli --- Cc: Abhinav Kumar Cc: Marijn Suijten Cc: Rob Clark Cc: Sean Paul --- drivers/gpu/drm/msm/dsi/dsi_manager.c | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 72ada9f2f043d2278e3ff2ff499fb52502330c68..ca400924d4eea89732905997d087e442ba9f336e 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -462,15 +462,14 @@ int msm_dsi_manager_connector_init(struct msm_dsi *msm_dsi, struct drm_connector *connector; int ret; - dsi_bridge = devm_kzalloc(msm_dsi->dev->dev, - sizeof(*dsi_bridge), GFP_KERNEL); - if (!dsi_bridge) - return -ENOMEM; + dsi_bridge = devm_drm_bridge_alloc(msm_dsi->dev->dev, struct dsi_bridge, base, + &dsi_mgr_bridge_funcs); + if (IS_ERR(dsi_bridge)) + return PTR_ERR(dsi_bridge); dsi_bridge->id = msm_dsi->id; bridge = &dsi_bridge->base; - bridge->funcs = &dsi_mgr_bridge_funcs; ret = devm_drm_bridge_add(msm_dsi->dev->dev, bridge); if (ret) -- 2.49.0
[PATCH v2 23/34] drm/omap: dss: sdi: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Switching from a non-devm to a devm allocation allows removing the kfree() in the remove function and in the probe error management code, and as a consequence to simplify the code flow by removing now unnecessary gotos. Signed-off-by: Luca Ceresoli --- Cc: "Rob Herring (Arm)" Cc: Kuninori Morimoto Cc: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/sdi.c | 25 - 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index e78826e4b560a2b9af2d8a5a38e181bd3e44d250..df4cbc683e2ca27ef5fc45f79b77dcdcd9ca529a 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -284,7 +284,6 @@ static const struct drm_bridge_funcs sdi_bridge_funcs = { static void sdi_bridge_init(struct sdi_device *sdi) { - sdi->bridge.funcs = &sdi_bridge_funcs; sdi->bridge.of_node = sdi->pdev->dev.of_node; sdi->bridge.type = DRM_MODE_CONNECTOR_LVDS; @@ -344,21 +343,19 @@ int sdi_init_port(struct dss_device *dss, struct platform_device *pdev, u32 datapairs; int r; - sdi = kzalloc(sizeof(*sdi), GFP_KERNEL); - if (!sdi) - return -ENOMEM; + sdi = devm_drm_bridge_alloc(&pdev->dev, struct sdi_device, bridge, &sdi_bridge_funcs); + if (IS_ERR(sdi)) + return PTR_ERR(sdi); ep = of_graph_get_next_port_endpoint(port, NULL); - if (!ep) { - r = 0; - goto err_free; - } + if (!ep) + return 0; r = of_property_read_u32(ep, "datapairs", &datapairs); of_node_put(ep); if (r) { DSSERR("failed to parse datapairs\n"); - goto err_free; + return r; } sdi->datapairs = datapairs; @@ -372,19 +369,14 @@ int sdi_init_port(struct dss_device *dss, struct platform_device *pdev, r = PTR_ERR(sdi->vdds_sdi_reg); if (r != -EPROBE_DEFER) DSSERR("can't get VDDS_SDI regulator\n"); - goto err_free; + return r; } r = sdi_init_output(sdi); if (r) - goto err_free; + return r; return 0; - -err_free: - kfree(sdi); - - return r; } void sdi_uninit_port(struct device_node *port) @@ -395,5 +387,4 @@ void sdi_uninit_port(struct device_node *port) return; sdi_uninit_output(sdi); - kfree(sdi); } -- 2.49.0
[PATCH v2 22/34] drm/omap: dss: hdmi5: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Switching from a non-devm to a devm allocation allows removing the kfree() in the remove function and in the probe error management code, and as a consequence to simplify the code flow by removing now unnecessary gotos. Signed-off-by: Luca Ceresoli --- Cc: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/hdmi5.c | 26 ++ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 0c98444d39a93d8336b4d8dbd45aa4521181c3b4..5636b3dfec1c9581118b20adecd268c03e882efb 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -480,7 +480,6 @@ static const struct drm_bridge_funcs hdmi5_bridge_funcs = { static void hdmi5_bridge_init(struct omap_hdmi *hdmi) { - hdmi->bridge.funcs = &hdmi5_bridge_funcs; hdmi->bridge.of_node = hdmi->pdev->dev.of_node; hdmi->bridge.ops = DRM_BRIDGE_OP_EDID; hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; @@ -727,9 +726,9 @@ static int hdmi5_probe(struct platform_device *pdev) int irq; int r; - hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); - if (!hdmi) - return -ENOMEM; + hdmi = devm_drm_bridge_alloc(&pdev->dev, struct omap_hdmi, bridge, &hdmi5_bridge_funcs); + if (IS_ERR(hdmi)) + return PTR_ERR(hdmi); hdmi->pdev = pdev; @@ -740,25 +739,24 @@ static int hdmi5_probe(struct platform_device *pdev) r = hdmi5_probe_of(hdmi); if (r) - goto err_free; + return r; r = hdmi_wp_init(pdev, &hdmi->wp, 5); if (r) - goto err_free; + return r; r = hdmi_phy_init(pdev, &hdmi->phy, 5); if (r) - goto err_free; + return r; r = hdmi5_core_init(pdev, &hdmi->core); if (r) - goto err_free; + return r; irq = platform_get_irq(pdev, 0); if (irq < 0) { DSSERR("platform_get_irq failed\n"); - r = -ENODEV; - goto err_free; + return -ENODEV; } r = devm_request_threaded_irq(&pdev->dev, irq, @@ -766,7 +764,7 @@ static int hdmi5_probe(struct platform_device *pdev) IRQF_ONESHOT, "OMAP HDMI", hdmi); if (r) { DSSERR("HDMI IRQ request failed\n"); - goto err_free; + return r; } hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda"); @@ -774,7 +772,7 @@ static int hdmi5_probe(struct platform_device *pdev) r = PTR_ERR(hdmi->vdda_reg); if (r != -EPROBE_DEFER) DSSERR("can't get VDDA regulator\n"); - goto err_free; + return r; } pm_runtime_enable(&pdev->dev); @@ -793,8 +791,6 @@ static int hdmi5_probe(struct platform_device *pdev) hdmi5_uninit_output(hdmi); err_pm_disable: pm_runtime_disable(&pdev->dev); -err_free: - kfree(hdmi); return r; } @@ -807,8 +803,6 @@ static void hdmi5_remove(struct platform_device *pdev) hdmi5_uninit_output(hdmi); pm_runtime_disable(&pdev->dev); - - kfree(hdmi); } static const struct of_device_id hdmi_of_match[] = { -- 2.49.0
[PATCH v2 28/34] drm/sti: dvo: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. This driver allocates the DRM bridge separately from the main driver private struct, which prevents using the new devm_drm_bridge_alloc() API. Simplify the code by replacing the struct drm_bridge pointer with an embedded struct drm_bridge inside the private struct, to make use of the new API with the same code flow. Signed-off-by: Luca Ceresoli --- Cc: Alain Volmat Cc: Raphael Gallais-Pou Changed in v2: - fix typos in commit message --- drivers/gpu/drm/sti/sti_dvo.c | 29 +++-- 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index 74a1eef4674eeabc445b53b380e325f785242024..7484d3c3f4ed5fac7eab408e30cbe2f6b87f27e5 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -97,7 +97,7 @@ struct sti_dvo { struct dvo_config *config; bool enabled; struct drm_encoder *encoder; - struct drm_bridge *bridge; + struct drm_bridge bridge; }; struct sti_dvo_connector { @@ -439,7 +439,6 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) struct drm_encoder *encoder; struct sti_dvo_connector *connector; struct drm_connector *drm_connector; - struct drm_bridge *bridge; int err; /* Set the drm device handle */ @@ -455,20 +454,14 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) connector->dvo = dvo; - bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); - if (!bridge) - return -ENOMEM; - - bridge->driver_private = dvo; - bridge->funcs = &sti_dvo_bridge_funcs; - bridge->of_node = dvo->dev.of_node; - drm_bridge_add(bridge); + dvo->bridge.driver_private = dvo; + dvo->bridge.of_node = dvo->dev.of_node; + drm_bridge_add(&dvo->bridge); - err = drm_bridge_attach(encoder, bridge, NULL, 0); + err = drm_bridge_attach(encoder, &dvo->bridge, NULL, 0); if (err) return err; - dvo->bridge = bridge; connector->encoder = encoder; dvo->encoder = encoder; @@ -490,7 +483,7 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) return 0; err_sysfs: - drm_bridge_remove(bridge); + drm_bridge_remove(&dvo->bridge); return -EINVAL; } @@ -499,7 +492,7 @@ static void sti_dvo_unbind(struct device *dev, { struct sti_dvo *dvo = dev_get_drvdata(dev); - drm_bridge_remove(dvo->bridge); + drm_bridge_remove(&dvo->bridge); } static const struct component_ops sti_dvo_ops = { @@ -515,10 +508,10 @@ static int sti_dvo_probe(struct platform_device *pdev) DRM_INFO("%s\n", __func__); - dvo = devm_kzalloc(dev, sizeof(*dvo), GFP_KERNEL); - if (!dvo) { - DRM_ERROR("Failed to allocate memory for DVO\n"); - return -ENOMEM; + dvo = devm_drm_bridge_alloc(dev, struct sti_dvo, bridge, &sti_dvo_bridge_funcs); + if (IS_ERR(dvo)) { + DRM_ERROR("Failed to allocate DVO\n"); + return PTR_ERR(dvo); } dvo->dev = pdev->dev; -- 2.49.0
[PATCH v2 25/34] drm/rcar-du: dsi: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Signed-off-by: Luca Ceresoli --- Cc: Kieran Bingham Cc: Laurent Pinchart Cc: Tomi Valkeinen --- drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c index 7ab8be46c7f6547f29b4d45af7ac704283da9dcd..1af4c73f7a887712aef8c8176b0d0338d9ca9727 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c @@ -918,7 +918,6 @@ static int rcar_mipi_dsi_host_attach(struct mipi_dsi_host *host, } /* Initialize the DRM bridge. */ - dsi->bridge.funcs = &rcar_mipi_dsi_bridge_ops; dsi->bridge.of_node = dsi->dev->of_node; drm_bridge_add(&dsi->bridge); @@ -1004,9 +1003,10 @@ static int rcar_mipi_dsi_probe(struct platform_device *pdev) struct rcar_mipi_dsi *dsi; int ret; - dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); - if (dsi == NULL) - return -ENOMEM; + dsi = devm_drm_bridge_alloc(&pdev->dev, struct rcar_mipi_dsi, bridge, + &rcar_mipi_dsi_bridge_ops); + if (IS_ERR(dsi)) + return PTR_ERR(dsi); platform_set_drvdata(pdev, dsi); -- 2.49.0
[PATCH v2 31/34] drm/bridge: imx8*-ldb: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. These two drivers are tangled together by the ldb_add_bridge_helper(), so they are converted at once. They also have a similar design, each embedding an array of channels in their main struct, and each channel embeds a drm_bridge. This prevents dynamic, refcount-based deallocation of the bridges. To make the new, dynamic bridge allocation possible: * change the array of channels into an array of channel pointers * allocate each channel using devm_drm_bridge_alloc() * adapt ldb_add_bridge_helper() to not set the funcs pointer (now done by devm_drm_bridge_alloc()) * adapt the code wherever using the channels Signed-off-by: Luca Ceresoli --- Cc: Liu Ying --- drivers/gpu/drm/bridge/imx/imx-ldb-helper.c | 4 +--- drivers/gpu/drm/bridge/imx/imx-ldb-helper.h | 3 +-- drivers/gpu/drm/bridge/imx/imx8qm-ldb.c | 32 ++--- drivers/gpu/drm/bridge/imx/imx8qxp-ldb.c| 20 -- 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c b/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c index 61347f6ec33d906264f7e06902b0d915d263f3f8..6149ba141a389a04b3c347a67f13e049328c07ff 100644 --- a/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c +++ b/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c @@ -190,8 +190,7 @@ int ldb_find_next_bridge_helper(struct ldb *ldb) } EXPORT_SYMBOL_GPL(ldb_find_next_bridge_helper); -void ldb_add_bridge_helper(struct ldb *ldb, - const struct drm_bridge_funcs *bridge_funcs) +void ldb_add_bridge_helper(struct ldb *ldb) { struct ldb_channel *ldb_ch; int i; @@ -203,7 +202,6 @@ void ldb_add_bridge_helper(struct ldb *ldb, continue; ldb_ch->bridge.driver_private = ldb_ch; - ldb_ch->bridge.funcs = bridge_funcs; ldb_ch->bridge.of_node = ldb_ch->np; drm_bridge_add(&ldb_ch->bridge); diff --git a/drivers/gpu/drm/bridge/imx/imx-ldb-helper.h b/drivers/gpu/drm/bridge/imx/imx-ldb-helper.h index 38a8a54b37a60e1be942aaa60b1d1bc375a7a131..de187e3269996d284ecad451dd857271056812e1 100644 --- a/drivers/gpu/drm/bridge/imx/imx-ldb-helper.h +++ b/drivers/gpu/drm/bridge/imx/imx-ldb-helper.h @@ -88,8 +88,7 @@ int ldb_init_helper(struct ldb *ldb); int ldb_find_next_bridge_helper(struct ldb *ldb); -void ldb_add_bridge_helper(struct ldb *ldb, - const struct drm_bridge_funcs *bridge_funcs); +void ldb_add_bridge_helper(struct ldb *ldb); void ldb_remove_bridge_helper(struct ldb *ldb); diff --git a/drivers/gpu/drm/bridge/imx/imx8qm-ldb.c b/drivers/gpu/drm/bridge/imx/imx8qm-ldb.c index 524aac751359f5cd377807508cbeeb6a597529e1..47aa65938e6a521cd6f111535f6feb3920a0dfb7 100644 --- a/drivers/gpu/drm/bridge/imx/imx8qm-ldb.c +++ b/drivers/gpu/drm/bridge/imx/imx8qm-ldb.c @@ -47,7 +47,7 @@ struct imx8qm_ldb_channel { struct imx8qm_ldb { struct ldb base; struct device *dev; - struct imx8qm_ldb_channel channel[MAX_LDB_CHAN_NUM]; + struct imx8qm_ldb_channel *channel[MAX_LDB_CHAN_NUM]; struct clk *clk_pixel; struct clk *clk_bypass; int active_chno; @@ -107,7 +107,7 @@ static int imx8qm_ldb_bridge_atomic_check(struct drm_bridge *bridge, if (is_split) { imx8qm_ldb_ch = - &imx8qm_ldb->channel[imx8qm_ldb->active_chno ^ 1]; + imx8qm_ldb->channel[imx8qm_ldb->active_chno ^ 1]; imx8qm_ldb_set_phy_cfg(imx8qm_ldb, di_clk, is_split, true, phy_cfg); ret = phy_validate(imx8qm_ldb_ch->phy, PHY_MODE_LVDS, 0, &opts); @@ -158,7 +158,7 @@ imx8qm_ldb_bridge_mode_set(struct drm_bridge *bridge, if (is_split) { imx8qm_ldb_ch = - &imx8qm_ldb->channel[imx8qm_ldb->active_chno ^ 1]; + imx8qm_ldb->channel[imx8qm_ldb->active_chno ^ 1]; imx8qm_ldb_set_phy_cfg(imx8qm_ldb, di_clk, is_split, true, phy_cfg); ret = phy_configure(imx8qm_ldb_ch->phy, &opts); @@ -226,13 +226,13 @@ static void imx8qm_ldb_bridge_atomic_enable(struct drm_bridge *bridge, } if (is_split) { - ret = phy_power_on(imx8qm_ldb->channel[0].phy); + ret = phy_power_on(imx8qm_ldb->channel[0]->phy); if (ret) DRM_DEV_ERROR(dev, "failed to power on channel0 PHY: %d\n", ret); - ret = phy_power_on(imx8qm_ldb->channel[1].phy); + ret = phy_power_on(imx8qm_ldb->channel[1]->phy); if (ret) DRM_DEV_ERROR(dev, "failed to power on channel1 PHY: %d\n", @@ -261,12 +261,12 @@ static void imx8qm_ldb_bridge_atomic_d
[PATCH v2 32/34] drm/bridge: tc358767: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Converting this driver is a bit convoluted because the drm_bridge funcs pointer differs based on the bridge mode. So the current code does: * tc_probe() * devm_kzalloc() private struct embedding drm_bridge * call tc_probe_bridge_endpoint() which * parses DT description into struct fields * computes the mode * calls different bridge init functions based on the mode * each sets a different bridge.funcs pointer The new API expects the funcs pointer to be known at alloc time, which does not fit in the current code structure. Solve this by moving the part of tc_probe_bridge_endpoint() computing the mode into a separate function, tc_probe_get_mode(), which does not need the private driver structure. So now the mode is known before allocation and so is the funcs pointer, while all other operations are still happening after allocation, directly into the private struct data, as they used to. This solution is chosen to minimize the changes in the driver logical code flow. The drawback is we now iterate twice over the endpoints. Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/tc358767.c | 56 --- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 7e5449fb86a3fcdae8255bc490d12c543ef3f8ae..61559467e2d22b4b1b4223c97766ca3bf58908fd 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -344,6 +344,14 @@ #define COLOR_BAR_MODE_BARS2 #define PLL_DBG0x0a04 +enum tc_mode { + mode_dpi_to_edp = BIT(1) | BIT(2), + mode_dpi_to_dp = BIT(1), + mode_dsi_to_edp = BIT(0) | BIT(2), + mode_dsi_to_dp = BIT(0), + mode_dsi_to_dpi = BIT(0) | BIT(1), +}; + static bool tc_test_pattern; module_param_named(test, tc_test_pattern, bool, 0644); @@ -2327,7 +2335,6 @@ static int tc_probe_dpi_bridge_endpoint(struct tc_data *tc) if (bridge) { tc->panel_bridge = bridge; tc->bridge.type = DRM_MODE_CONNECTOR_DPI; - tc->bridge.funcs = &tc_dpi_bridge_funcs; return 0; } @@ -2360,7 +2367,6 @@ static int tc_probe_edp_bridge_endpoint(struct tc_data *tc) tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; } - tc->bridge.funcs = &tc_edp_bridge_funcs; if (tc->hpd_pin >= 0) tc->bridge.ops |= DRM_BRIDGE_OP_DETECT; tc->bridge.ops |= DRM_BRIDGE_OP_EDID; @@ -2368,17 +2374,11 @@ static int tc_probe_edp_bridge_endpoint(struct tc_data *tc) return 0; } -static int tc_probe_bridge_endpoint(struct tc_data *tc) +static enum tc_mode tc_probe_get_mode(struct device *dev) { - struct device *dev = tc->dev; struct of_endpoint endpoint; struct device_node *node = NULL; - const u8 mode_dpi_to_edp = BIT(1) | BIT(2); - const u8 mode_dpi_to_dp = BIT(1); - const u8 mode_dsi_to_edp = BIT(0) | BIT(2); - const u8 mode_dsi_to_dp = BIT(0); - const u8 mode_dsi_to_dpi = BIT(0) | BIT(1); - u8 mode = 0; + enum tc_mode mode = 0; /* * Determine bridge configuration. @@ -2401,7 +2401,27 @@ static int tc_probe_bridge_endpoint(struct tc_data *tc) return -EINVAL; } mode |= BIT(endpoint.port); + } + + if (mode != mode_dpi_to_edp && + mode != mode_dpi_to_dp && + mode != mode_dsi_to_dpi && + mode != mode_dsi_to_edp && + mode != mode_dsi_to_dp) { + dev_warn(dev, "Invalid mode (0x%x) is not supported!\n", mode); + return -EINVAL; + } + + return mode; +} +static int tc_probe_bridge_endpoint(struct tc_data *tc, enum tc_mode mode) +{ + struct device *dev = tc->dev; + struct of_endpoint endpoint; + struct device_node *node = NULL; + + for_each_endpoint_of_node(dev->of_node, node) { if (endpoint.port == 2) { of_property_read_u8_array(node, "toshiba,pre-emphasis", tc->pre_emphasis, @@ -2427,24 +2447,28 @@ static int tc_probe_bridge_endpoint(struct tc_data *tc) return tc_probe_edp_bridge_endpoint(tc); } - dev_warn(dev, "Invalid mode (0x%x) is not supported!\n", mode); - + /* Should never happen, mode was validated by tc_probe_get_mode() */ return -EINVAL; } static int tc_probe(struct i2c_client *client) { struct device *dev = &client->dev; + const struct drm_bridge_funcs *funcs; struct tc_data *tc; + int mode; int ret; - tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL); - if (!tc) - return -ENOMEM; + mode = tc_probe_get_mode(dev); + funcs = (mode == mode_dsi_to_dpi) ? &tc_dp
[PATCH v2 33/34] drm/bridge: add devm_drm_put_bridge()
Bridges obtained via devm_drm_bridge_alloc(dev, ...) will be put when the requesting device (@dev) is removed. However drivers which obtained them may need to put the obtained reference explicitly. One such case is if they bind the devm removal action to a different device than the one implemented by the driver itself and which might be removed at a different time, such as bridge/panel.c. Add devm_drm_put_bridge() to manually release a devm-obtained bridge in such cases. Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/drm_bridge.c | 14 ++ include/drm/drm_bridge.h | 4 2 files changed, 18 insertions(+) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index b4c89ec01998b849018ce031c7cd84614e65e710..456363d86080b2a55035c3108c16afa4f9e57e06 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -1392,6 +1392,20 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np) EXPORT_SYMBOL(of_drm_find_bridge); #endif +/** + * devm_drm_put_bridge - Release a bridge reference obtained via devm + * @dev: device that got the bridge via devm + * @bridge: pointer to a struct drm_bridge obtained via devm + * + * Same as drm_bridge_put() for bridge pointers obtained via devm functions + * such as devm_drm_bridge_alloc(). + */ +void devm_drm_put_bridge(struct device *dev, struct drm_bridge *bridge) +{ + devm_release_action(dev, drm_bridge_put_void, bridge); +} +EXPORT_SYMBOL(devm_drm_put_bridge); + static void drm_bridge_debugfs_show_bridge(struct drm_printer *p, struct drm_bridge *bridge, unsigned int idx) diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 4e418a29a9ff9d014d6ac0910a5d9bcf7118195e..6f00a3998ed6d026332b0f1e3bb5bee3cb5158e0 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -1265,6 +1265,8 @@ static inline struct drm_bridge *devm_drm_of_get_bridge(struct device *dev, return ERR_PTR(-ENODEV); } +static inline void devm_drm_put_bridge(struct device *dev, struct drm_bridge *bridge) {} + static inline struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm, struct device_node *node, u32 port, @@ -1274,6 +1276,8 @@ static inline struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm, } #endif +void devm_drm_put_bridge(struct device *dev, struct drm_bridge *bridge); + void drm_bridge_debugfs_params(struct dentry *root); void drm_bridge_debugfs_encoder_params(struct dentry *root, struct drm_encoder *encoder); -- 2.49.0
[PATCH v2 21/34] drm/omap: dss: hdmi4: convert to devm_drm_bridge_alloc() API
This is the new API for allocating DRM bridges. Switching from a non-devm to a devm allocation allows removing the kfree() in the remove function and in the probe error management code, and as a consequence to simplify the code flow by removing now unnecessary gotos. Signed-off-by: Luca Ceresoli --- Cc: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/dss/hdmi4.c | 26 ++ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index a3b22952fdc32b5899dae82d413108c5c0a1c3c8..3cd612af24498b057c33eaecb3d43c8df76cd23e 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -505,7 +505,6 @@ static const struct drm_bridge_funcs hdmi4_bridge_funcs = { static void hdmi4_bridge_init(struct omap_hdmi *hdmi) { - hdmi->bridge.funcs = &hdmi4_bridge_funcs; hdmi->bridge.of_node = hdmi->pdev->dev.of_node; hdmi->bridge.ops = DRM_BRIDGE_OP_EDID; hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; @@ -761,9 +760,9 @@ static int hdmi4_probe(struct platform_device *pdev) int irq; int r; - hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); - if (!hdmi) - return -ENOMEM; + hdmi = devm_drm_bridge_alloc(&pdev->dev, struct omap_hdmi, bridge, &hdmi4_bridge_funcs); + if (IS_ERR(hdmi)) + return PTR_ERR(hdmi); hdmi->pdev = pdev; @@ -774,25 +773,24 @@ static int hdmi4_probe(struct platform_device *pdev) r = hdmi4_probe_of(hdmi); if (r) - goto err_free; + return r; r = hdmi_wp_init(pdev, &hdmi->wp, 4); if (r) - goto err_free; + return r; r = hdmi_phy_init(pdev, &hdmi->phy, 4); if (r) - goto err_free; + return r; r = hdmi4_core_init(pdev, &hdmi->core); if (r) - goto err_free; + return r; irq = platform_get_irq(pdev, 0); if (irq < 0) { DSSERR("platform_get_irq failed\n"); - r = -ENODEV; - goto err_free; + return -ENODEV; } r = devm_request_threaded_irq(&pdev->dev, irq, @@ -800,7 +798,7 @@ static int hdmi4_probe(struct platform_device *pdev) IRQF_ONESHOT, "OMAP HDMI", hdmi); if (r) { DSSERR("HDMI IRQ request failed\n"); - goto err_free; + return r; } hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda"); @@ -808,7 +806,7 @@ static int hdmi4_probe(struct platform_device *pdev) r = PTR_ERR(hdmi->vdda_reg); if (r != -EPROBE_DEFER) DSSERR("can't get VDDA regulator\n"); - goto err_free; + return r; } pm_runtime_enable(&pdev->dev); @@ -827,8 +825,6 @@ static int hdmi4_probe(struct platform_device *pdev) hdmi4_uninit_output(hdmi); err_pm_disable: pm_runtime_disable(&pdev->dev); -err_free: - kfree(hdmi); return r; } @@ -841,8 +837,6 @@ static void hdmi4_remove(struct platform_device *pdev) hdmi4_uninit_output(hdmi); pm_runtime_disable(&pdev->dev); - - kfree(hdmi); } static const struct of_device_id hdmi_of_match[] = { -- 2.49.0
[PATCH v7 0/2] Rework/Correction on minimum hblank calculation
Signed-off-by: Arun R Murthy --- Changes in v7: - EDITME: describe what is new in this series revision. - EDITME: use bulletpoints and terse descriptions. - Link to v6: https://lore.kernel.org/r/20250424-hblank-v6-0-3d10442d9...@intel.com Changes in v6: - EDITME: describe what is new in this series revision. - EDITME: use bulletpoints and terse descriptions. - Link to v5: https://lore.kernel.org/r/20250423-hblank-v5-0-6bee618bc...@intel.com Changes in v5: - EDITME: describe what is new in this series revision. - EDITME: use bulletpoints and terse descriptions. - Link to v4: https://lore.kernel.org/r/20250423-hblank-v4-0-8e513cc54...@intel.com Changes in v5: - EDITME: describe what is new in this series revision. - EDITME: use bulletpoints and terse descriptions. - Link to v4: https://lore.kernel.org/r/20250422-hblank-v4-0-bdb7bd9c4...@intel.com Changes in v3: - EDITME: describe what is new in this series revision. - EDITME: use bulletpoints and terse descriptions. - Link to v2: https://lore.kernel.org/r/20250415-hblank-v2-0-1a23e9d97...@intel.com Changes in v2: - EDITME: describe what is new in this series revision. - EDITME: use bulletpoints and terse descriptions. - Link to v1: https://lore.kernel.org/r/20250408-hblank-v1-0-4ba17aebe...@intel.com --- Arun R Murthy (2): drm/display/dp: Export fn to calculate link symbol cycles drm/i915/display: move min_hblank from dp_mst.c to dp.c drivers/gpu/drm/display/drm_dp_helper.c | 52 --- drivers/gpu/drm/i915/display/intel_display.c | 19 +++ drivers/gpu/drm/i915/display/intel_dp.c | 74 drivers/gpu/drm/i915/display/intel_dp.h | 2 + drivers/gpu/drm/i915/display/intel_dp_mst.c | 56 ++--- include/drm/display/drm_dp_helper.h | 2 + 6 files changed, 136 insertions(+), 69 deletions(-) --- base-commit: ada794bd93930fd265c2df8f38196994173e1fde change-id: 20250407-hblank-49b340aeba31 Best regards, -- Arun R Murthy
Re: [PATCH] Revert "drm/amd/display: Hardware cursor changes color when switched to software cursor"
On 2025-04-22 10:58, Melissa Wen wrote: > This reverts commit 272e6aab14bbf98d7a06b2b1cd6308a02d4a10a1. > > Applying degamma curve to the cursor by default breaks Linux userspace > expectation. > > On Linux, AMD display manager enables cursor degamma ROM just for > implict sRGB on HW versions where degamma is split into two blocks: > degamma ROM for pre-defined TFs and `gamma correction` for user/custom > curves, and degamma ROM settings doesn't apply to cursor plane. > > Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1513 > Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2803 > Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4144 > Reported-by: Michel Dänzer > Signed-off-by: Melissa Wen > --- > > Hi, > > I suspect there is a conflict of interest between OSes here, because > this is not the first time this mechanism has been removed from the > DC shared-code and after reintroduced [1]. > > I'd suggest that other OSes set the `dc_cursor_attributes > attribute_flags.bits.ENABLE_CURSOR_DEGAMMA` to true by default, rather > than removing the mechanism that is valid for the Linux driver. Similar > to what the Linux AMD DM does for the implicit sRGB [2][3], but in their > case, they just need to initialize with 1. > That's a good suggestion and I started that conversation with Windows devs. Is there an IGT test that would test for this behavior? Without an IGT test I think we're apt to end back here again at some point. Harry > Finally, thanks Michel for pointing this issue out to me and noticing > the similarity to previous solution. > > [1] https://gitlab.freedesktop.org/agd5f/linux/-/commit/d9fbd64e8e317 > [2] https://gitlab.freedesktop.org/agd5f/linux/-/commit/857b835f > [3] https://gitlab.freedesktop.org/agd5f/linux/-/commit/66eba12a > > Best Regards, > > Melissa > > drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c | 5 +++-- > 1 file changed, 3 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c > b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c > index 1236e0f9a256..712aff7e17f7 100644 > --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c > +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_cm.c > @@ -120,10 +120,11 @@ void dpp401_set_cursor_attributes( > enum dc_cursor_color_format color_format = > cursor_attributes->color_format; > int cur_rom_en = 0; > > - // DCN4 should always do Cursor degamma for Cursor Color modes > if (color_format == CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA || > color_format == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA) { > - cur_rom_en = 1; > + if > (cursor_attributes->attribute_flags.bits.ENABLE_CURSOR_DEGAMMA) { > + cur_rom_en = 1; > + } > } > > REG_UPDATE_3(CURSOR0_CONTROL,
Re: [PATCH v2 11/34] drm/bridge: dw-hdmi: convert to devm_drm_bridge_alloc() API
On 4/24/25 9:59 PM, Luca Ceresoli wrote: > This is the new API for allocating DRM bridges. > > Signed-off-by: Luca Ceresoli > > --- > > Cc: Cristian Ciocaltea > --- > drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 +++ > 1 file changed, 3 insertions(+), 4 deletions(-) Reviewed-by: Cristian Ciocaltea
Re: [PATCH 13/16] gpu: nova-core: Add support for VBIOS ucode extraction for boot
On Wed, Apr 23, 2025 at 05:02:58PM +0200, Danilo Krummrich wrote: [..] > > >> +data.extend_with(len, 0, GFP_KERNEL)?; > > >> +with_bar!(?bar0, |bar0_ref| { > > >> +let dst = &mut data[current_len..current_len + len]; > > >> +for (idx, chunk) in dst > > >> +.chunks_exact_mut(core::mem::size_of::()) > > >> +.enumerate() > > >> +{ > > >> +let addr = start + (idx * core::mem::size_of::()); > > >> +// Convert the u32 to a 4 byte array. We use the > > >> .to_ne_bytes() > > >> +// method out of convenience to convert the 32-bit > > >> integer as it > > >> +// is in memory into a byte array without any endianness > > >> +// conversion or byte-swapping. > > >> + > > >> chunk.copy_from_slice(&bar0_ref.try_read32(addr)?.to_ne_bytes()); > > >> +} > > >> +Ok(()) > > >> +})?; > > >> + > > >> +Ok(()) > > >> +} > > ..actually initially was: > > > > +with_bar!(self.bar0, |bar0| { > > +// Get current length > > +let current_len = self.data.len(); > > + > > +// Read ROM data bytes push directly to vector > > +for i in 0..bytes as usize { > > +// Read byte from the VBIOS ROM and push it to the data > > vector > > +let rom_addr = ROM_OFFSET + current_len + i; > > +let byte = bar0.try_readb(rom_addr)?; > > +self.data.push(byte, GFP_KERNEL)?; > > > > Where this bit could result in a lot of allocation. > > > > There was an unsafe() way of not having to do this but we settled with > > extends_with(). > > > > Thoughts? > > If I understand you correctly, you just want to make sure that subsequent > push() > calls don't re-allocate? If so, you can just use reserve() [1] and keep the > subsequent push() calls. > > [1] > https://rust.docs.kernel.org/kernel/alloc/kvec/struct.Vec.html#method.reserve Ok that does turn out to be cleaner! I replaced it with the following and it works. Let me know if it looks good now? Here's a preview: -data.extend_with(len, 0, GFP_KERNEL)?; +data.reserve(len, GFP_KERNEL)?; + with_bar_res!(bar0, |bar0_ref| { -let dst = &mut data[current_len..current_len + len]; -for (idx, chunk) in dst -.chunks_exact_mut(core::mem::size_of::()) -.enumerate() -{ -let addr = start + (idx * core::mem::size_of::()); -// Convert the u32 to a 4 byte array. We use the .to_ne_bytes() -// method out of convenience to convert the 32-bit integer as it -// is in memory into a byte array without any endianness -// conversion or byte-swapping. - chunk.copy_from_slice(&bar0_ref.try_read32(addr)?.to_ne_bytes()); +// Read ROM data bytes and push directly to vector +for i in 0..len { +// Read 32-bit word from the VBIOS ROM +let rom_addr = start + i * core::mem::size_of::(); +let word = bar0_ref.try_read32(rom_addr)?; + +// Convert the u32 to a 4 byte array and push each byte +word.to_ne_bytes().iter().try_for_each(|&b| data.push(b, GFP_KERNEL))?; } Thanks.
Re: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
On Thu, Apr 24, 2025 at 01:18:34PM +0100, Matthew Auld wrote: > Goal here is cut over to gpusvm and remove xe_hmm, relying instead on > common code. The core facilities we need are get_pages(), unmap_pages() > and free_pages() for a given useptr range, plus a vm level notifier > lock, which is now provided by gpusvm. > > v2: > - Reuse the same SVM vm struct we use for full SVM, that way we can > use the same lock (Matt B & Himal) > v3: > - Re-use svm_init/fini for userptr. > > Signed-off-by: Matthew Auld > Cc: Himal Prasad Ghimiray > Cc: Thomas Hellström > Cc: Matthew Brost > --- > drivers/gpu/drm/xe/Kconfig | 3 +- > drivers/gpu/drm/xe/Makefile | 1 - > drivers/gpu/drm/xe/xe_exec.c | 4 +- > drivers/gpu/drm/xe/xe_hmm.c | 325 --- > drivers/gpu/drm/xe/xe_hmm.h | 18 -- > drivers/gpu/drm/xe/xe_pt.c | 22 +-- > drivers/gpu/drm/xe/xe_svm.c | 32 +-- > drivers/gpu/drm/xe/xe_svm.h | 6 +- > drivers/gpu/drm/xe/xe_vm.c | 86 > drivers/gpu/drm/xe/xe_vm_types.h | 26 +-- > 10 files changed, 92 insertions(+), 431 deletions(-) > delete mode 100644 drivers/gpu/drm/xe/xe_hmm.c > delete mode 100644 drivers/gpu/drm/xe/xe_hmm.h > > diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig > index 9bce047901b2..1e63dde76c55 100644 > --- a/drivers/gpu/drm/xe/Kconfig > +++ b/drivers/gpu/drm/xe/Kconfig > @@ -43,7 +43,7 @@ config DRM_XE > select MMU_NOTIFIER > select WANT_DEV_COREDUMP > select AUXILIARY_BUS > - select HMM_MIRROR > + select DRM_GPUSVM select DRM_GPUSVM if !UML and DEVICE_PRIVATE GPUSVM won't compile on UML. That might have other implictions throughout the driver (e.g. compile out parts of userptr, disable userptr if at IOCTLs if DRM_GPUSVM is not selected, etc...). Rest of the patch LGTM. Matt > help > Experimental driver for Intel Xe series GPUs > > @@ -79,7 +79,6 @@ config DRM_XE_GPUSVM > depends on !UML > depends on DEVICE_PRIVATE > default y > - select DRM_GPUSVM > help > Enable this option if you want support for CPU to GPU address > mirroring. > diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile > index 3ecac0a38b82..f1123be158f8 100644 > --- a/drivers/gpu/drm/xe/Makefile > +++ b/drivers/gpu/drm/xe/Makefile > @@ -124,7 +124,6 @@ xe-y += xe_bb.o \ > xe_wait_user_fence.o \ > xe_wopcm.o > > -xe-$(CONFIG_HMM_MIRROR) += xe_hmm.o > xe-$(CONFIG_DRM_XE_GPUSVM) += xe_svm.o > > # graphics hardware monitoring (HWMON) support > diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c > index b75adfc99fb7..c0ce681076d5 100644 > --- a/drivers/gpu/drm/xe/xe_exec.c > +++ b/drivers/gpu/drm/xe/xe_exec.c > @@ -294,7 +294,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, > struct drm_file *file) > if (err) > goto err_put_job; > > - err = down_read_interruptible(&vm->userptr.notifier_lock); > + err = down_read_interruptible(&vm->svm.gpusvm.notifier_lock); > if (err) > goto err_put_job; > > @@ -336,7 +336,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, > struct drm_file *file) > > err_repin: > if (!xe_vm_in_lr_mode(vm)) > - up_read(&vm->userptr.notifier_lock); > + up_read(&vm->svm.gpusvm.notifier_lock); > err_put_job: > if (err) > xe_sched_job_put(job); > diff --git a/drivers/gpu/drm/xe/xe_hmm.c b/drivers/gpu/drm/xe/xe_hmm.c > deleted file mode 100644 > index 57b71956ddf4.. > --- a/drivers/gpu/drm/xe/xe_hmm.c > +++ /dev/null > @@ -1,325 +0,0 @@ > -// SPDX-License-Identifier: MIT > -/* > - * Copyright © 2024 Intel Corporation > - */ > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include "xe_hmm.h" > -#include "xe_vm.h" > -#include "xe_bo.h" > - > -static u64 xe_npages_in_range(unsigned long start, unsigned long end) > -{ > - return (end - start) >> PAGE_SHIFT; > -} > - > -static int xe_alloc_sg(struct xe_device *xe, struct sg_table *st, > -struct hmm_range *range, struct rw_semaphore > *notifier_sem) > -{ > - unsigned long i, npages, hmm_pfn; > - unsigned long num_chunks = 0; > - int ret; > - > - /* HMM docs says this is needed. */ > - ret = down_read_interruptible(notifier_sem); > - if (ret) > - return ret; > - > - if (mmu_interval_read_retry(range->notifier, range->notifier_seq)) { > - up_read(notifier_sem); > - return -EAGAIN; > - } > - > - npages = xe_npages_in_range(range->start, range->end); > - for (i = 0; i < npages;) { > - unsigned long len; > - > - hmm_pfn = range->hmm_pfns[i]; > - xe_assert(xe, hmm_pfn & HMM_PFN_VALID); > - > - len = 1UL << hmm_pfn_to_map_order(hmm_pfn)