Re: [PATCH v4 22/24] drm/msm/dsi: remove temp data from global pll structure
On Wed, Mar 31, 2021 at 3:58 AM Dmitry Baryshkov wrote: > > The 7nm, 10nm and 14nm drivers would store interim data used during > VCO/PLL rate setting in the global dsi_pll_Nnm structure. Move this data > structures to the onstack storage. While we are at it, drop > unused/static 'config' data, unused config fields, etc. > > Signed-off-by: Dmitry Baryshkov > Reviewed-by: Abhinav Kumar > Tested-by: Stephen Boyd # on sc7180 lazor Hey Dmitry, Just wanted to give you a heads up. Peter Collingbourne reported today that his db845c wasn't booting to display for him on his 4k monitor. It works fine on a 1080p screen, and while 4k isn't supported (yet?), normally the board should fall back to 1080p when connected to a 4k monitor. I was able to reproduce this myself and I see the errors below[1]. I dug back and found that things were working ok on v5.12 w/ the recently merged commit d1a97648ae028 ("drm/bridge: lt9611: Fix handling of 4k panels"), and started digging around. Seeing a bunch of changes to the drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c file, I tried reverting a chunk of the changes since 5.12 to that, and that got it working again. I've narrowed it down to this change - 001d8dc33875 ("drm/msm/dsi: remove temp data from global pll structure") upstream (also reverting following 6e2ad9c3bfca and 36c5dde5fdf0 first - but its reverting this change that actually makes it work again). I've not managed to really look into the change to see what might be going wrong yet (its late and I'm about to crash), but I wanted to give you a heads up. If you have any ideas for me to try I'm happy to give them a go. thanks -john [1]: [ 19.846857] msm_dsi_phy ae94400.dsi-phy: [drm:dsi_pll_10nm_vco_prepare] *ERROR* DSI PLL(0) lock failed, status=0x [ 19.857925] msm_dsi_phy ae94400.dsi-phy: [drm:dsi_pll_10nm_vco_prepare] *ERROR* PLL(0) lock failed [ 19.866978] dsi_link_clk_enable_6g: Failed to enable dsi byte clk [ 19.873124] msm_dsi_host_power_on: failed to enable link clocks. ret=-110 [ 19.879987] dsi_mgr_bridge_pre_enable: power on host 0 failed, -110 [ 19.886309] Turning OFF PHY while PLL is on [ 20.415019] lt9611 10-003b: video check: hactive_a=0, hactive_b=0, vactive=0, v_total=0, h_total_sysclk=0 [ 20.481062] [drm:dpu_encoder_phys_vid_wait_for_commit_done:528] [dpu error]vblank timeout [ 20.489306] [drm:dpu_kms_wait_for_commit_done:453] [dpu error]wait for commit done returned -110 [ 20.513031] [drm:dpu_encoder_frame_done_timeout:2161] [dpu error]enc31 frame done timeout [ 20.553059] [drm:dpu_encoder_phys_vid_wait_for_commit_done:528] [dpu error]vblank timeout [ 20.561300] [drm:dpu_kms_wait_for_commit_done:453] [dpu error]wait for commit done returned -110 [ 20.625054] [drm:dpu_encoder_phys_vid_wait_for_commit_done:528] [dpu error]vblank timeout [ 20.633299] [drm:dpu_kms_wait_for_commit_done:453] [dpu error]wait for commit done returned -110 [ 20.657033] [drm:dpu_encoder_frame_done_timeout:2161] [dpu error]enc31 frame done timeout [ 20.697065] [drm:dpu_encoder_phys_vid_wait_for_commit_done:528] [dpu error]vblank timeout [ 20.705316] [drm:dpu_kms_wait_for_commit_done:453] [dpu error]wait for commit done returned -110 [ 20.769066] [drm:dpu_encoder_phys_vid_wait_for_commit_done:528] [dpu error]vblank timeout [ 20.777330] [drm:dpu_kms_wait_for_commit_done:453] [dpu error]wait for commit done returned -110 [ 20.801035] [drm:dpu_encoder_frame_done_timeout:2161] [dpu error]enc31 frame done timeout [ 20.845049] [drm:dpu_encoder_phys_vid_wait_for_commit_done:528] [dpu error]vblank timeout ...
Re: [PATCH 2/6] dma-buf: Add dma_resv_get_singleton (v6)
Am 10.06.21 um 23:09 schrieb Jason Ekstrand: Add a helper function to get a single fence representing all fences in a dma_resv object. This fence is either the only one in the object or all not signaled fences of the object in a flatted out dma_fence_array. v2 (Jason Ekstrand): - Take reference of fences both for creating the dma_fence_array and in the case where we return one fence. - Handle the case where dma_resv_get_list() returns NULL v3 (Jason Ekstrand): - Add an _rcu suffix because it is read-only - Rewrite to use dma_resv_get_fences_rcu so it's RCU-safe - Add an EXPORT_SYMBOL_GPL declaration - Re-author the patch to Jason since very little is left of Christian König's original patch - Remove the extra fence argument v4 (Jason Ekstrand): - Restore the extra fence argument v5 (Daniel Vetter): - Rename from _rcu to _unlocked since it doesn't leak RCU details to the caller - Fix docs - Use ERR_PTR for error handling rather than an output dma_fence** v5 (Jason Ekstrand): - Drop the extra fence param and leave that to a separate patch v6 (Jason Ekstrand): - Rename to dma_resv_get_singleton to match the new naming convention for dma_resv helpers which work without taking a lock. Signed-off-by: Jason Ekstrand Reviewed-by: Daniel Vetter Reviewed-by: Christian König Cc: Christian König Cc: Maarten Lankhorst --- drivers/dma-buf/dma-resv.c | 91 ++ include/linux/dma-resv.h | 1 + 2 files changed, 92 insertions(+) diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index f26c71747d43a..1b26aa7e5d81c 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -34,6 +34,8 @@ */ #include +#include +#include #include #include #include @@ -50,6 +52,10 @@ * write-side updates. */ +#define dma_fence_deep_dive_for_each(fence, chain, index, head) \ + dma_fence_chain_for_each(chain, head) \ + dma_fence_array_for_each(fence, index, chain) + DEFINE_WD_CLASS(reservation_ww_class); EXPORT_SYMBOL(reservation_ww_class); @@ -495,6 +501,91 @@ int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl, } EXPORT_SYMBOL_GPL(dma_resv_get_fences); +/** + * dma_resv_get_singleton - get a single fence for the dma_resv object + * @obj: the reservation object + * + * Get a single fence representing all unsignaled fences in the dma_resv object + * plus the given extra fence. If we got only one fence return a new + * reference to that, otherwise return a dma_fence_array object. + * + * RETURNS + * The singleton dma_fence on success or an ERR_PTR on failure + */ +struct dma_fence *dma_resv_get_singleton(struct dma_resv *obj) +{ + struct dma_fence *result, **resv_fences, *fence, *chain, **fences; + struct dma_fence_array *array; + unsigned int num_resv_fences, num_fences; + unsigned int err, i, j; + + err = dma_resv_get_fences(obj, NULL, &num_resv_fences, &resv_fences); + if (err) + return ERR_PTR(err); + + if (num_resv_fences == 0) + return NULL; + + num_fences = 0; + result = NULL; + + for (i = 0; i < num_resv_fences; ++i) { + dma_fence_deep_dive_for_each(fence, chain, j, resv_fences[i]) { + if (dma_fence_is_signaled(fence)) + continue; + + result = fence; + ++num_fences; + } + } + + if (num_fences <= 1) { + result = dma_fence_get(result); + goto put_resv_fences; + } + + fences = kmalloc_array(num_fences, sizeof(struct dma_fence *), + GFP_KERNEL); + if (!fences) { + result = ERR_PTR(-ENOMEM); + goto put_resv_fences; + } + + num_fences = 0; + for (i = 0; i < num_resv_fences; ++i) { + dma_fence_deep_dive_for_each(fence, chain, j, resv_fences[i]) { + if (!dma_fence_is_signaled(fence)) + fences[num_fences++] = dma_fence_get(fence); + } + } + + if (num_fences <= 1) { + result = num_fences ? fences[0] : NULL; + kfree(fences); + goto put_resv_fences; + } + + array = dma_fence_array_create(num_fences, fences, + dma_fence_context_alloc(1), + 1, false); + if (array) { + result = &array->base; + } else { + result = ERR_PTR(-ENOMEM); + while (num_fences--) + dma_fence_put(fences[num_fences]); + kfree(fences); + } + +put_resv_fences: + while (num_resv_fences--) + dma_fence_put(resv_fences[num_resv_fences]); + kfree(resv_fences); + + ret
Re: [PATCH v5 1/1] drm/doc: document drm_mode_get_plane
On Thu, 10 Jun 2021 17:38:24 -0300 Leandro Ribeiro wrote: > Add a small description and document struct fields of > drm_mode_get_plane. > > Signed-off-by: Leandro Ribeiro > --- > include/uapi/drm/drm_mode.h | 35 +++ > 1 file changed, 35 insertions(+) > > diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h > index 9b6722d45f36..698559d9336b 100644 > --- a/include/uapi/drm/drm_mode.h > +++ b/include/uapi/drm/drm_mode.h > @@ -312,16 +312,51 @@ struct drm_mode_set_plane { > __u32 src_w; > }; > > +/** > + * struct drm_mode_get_plane - Get plane metadata. > + * > + * Userspace can perform a GETPLANE ioctl to retrieve information about a > + * plane. > + * > + * To retrieve the number of formats supported, set @count_format_types to > zero > + * and call the ioctl. @count_format_types will be updated with the value. > + * > + * To retrieve these formats, allocate an array with the memory needed to > store > + * @count_format_types formats. Point @format_type_ptr to this array and call > + * the ioctl again (with @count_format_types still set to the value returned > in > + * the first ioctl call). > + */ > struct drm_mode_get_plane { > + /** > + * @plane_id: Object ID of the plane whose information should be > + * retrieved. Set by caller. > + */ > __u32 plane_id; > > + /** @crtc_id: Object ID of the current CRTC. */ > __u32 crtc_id; > + /** @fb_id: Object ID of the current fb. */ > __u32 fb_id; > > + /** > + * @possible_crtcs: Bitmask of CRTC's compatible with the plane. CRTC's > + * are created and they receive an index, which corresponds to their > + * position in the bitmask. Bit N corresponds to > + * :ref:`CRTC index` N. > + */ > __u32 possible_crtcs; > + /** > + * @gamma_size: Number of entries of the legacy gamma lookup table. > + * Deprecated. > + */ > __u32 gamma_size; Hi, I wonder, has this field ever been used? "The legacy gamma" refers to CRTC gamma LUT AFAIK, but this here is about planes. I forgot that at first, so didn't see anything funny. Anyway, whether the doc for this field is as is, or is changed to "never used" or "unused" or "reserved" or whatever, you have my: Reviewed-by: Pekka Paalanen With the caveat that I didn't actually build the docs to see how they look. Thanks, pq > > + /** @count_format_types: Number of formats. */ > __u32 count_format_types; > + /** > + * @format_type_ptr: Pointer to ``__u32`` array of formats that are > + * supported by the plane. These formats do not require modifiers. > + */ > __u64 format_type_ptr; > }; > > -- > 2.31.1 > pgpVTIU2kwbRW.pgp Description: OpenPGP digital signature
Re: [Intel-gfx] [PATCH 0/5] dma-fence, i915: Stop allowing SLAB_TYPESAFE_BY_RCU for dma_fence
On Fri, Jun 11, 2021 at 8:55 AM Christian König wrote: > > Am 10.06.21 um 22:42 schrieb Daniel Vetter: > > On Thu, Jun 10, 2021 at 10:10 PM Jason Ekstrand > > wrote: > >> On Thu, Jun 10, 2021 at 8:35 AM Jason Ekstrand > >> wrote: > >>> On Thu, Jun 10, 2021 at 6:30 AM Daniel Vetter > >>> wrote: > On Thu, Jun 10, 2021 at 11:39 AM Christian König > wrote: > > Am 10.06.21 um 11:29 schrieb Tvrtko Ursulin: > >> On 09/06/2021 22:29, Jason Ekstrand wrote: > >>> We've tried to keep it somewhat contained by doing most of the hard > >>> work > >>> to prevent access of recycled objects via dma_fence_get_rcu_safe(). > >>> However, a quick grep of kernel sources says that, of the 30 instances > >>> of dma_fence_get_rcu*, only 11 of them use dma_fence_get_rcu_safe(). > >>> It's likely there bear traps in DRM and related subsystems just > >>> waiting > >>> for someone to accidentally step in them. > >> ...because dma_fence_get_rcu_safe apears to be about whether the > >> *pointer* to the fence itself is rcu protected, not about the fence > >> object itself. > > Yes, exactly that. > >>> The fact that both of you think this either means that I've completely > >>> missed what's going on with RCUs here (possible but, in this case, I > >>> think unlikely) or RCUs on dma fences should scare us all. > >> Taking a step back for a second and ignoring SLAB_TYPESAFE_BY_RCU as > >> such, I'd like to ask a slightly different question: What are the > >> rules about what is allowed to be done under the RCU read lock and > >> what guarantees does a driver need to provide? > >> > >> I think so far that we've all agreed on the following: > >> > >> 1. Freeing an unsignaled fence is ok as long as it doesn't have any > >> pending callbacks. (Callbacks should hold a reference anyway). > >> > >> 2. The pointer race solved by dma_fence_get_rcu_safe is real and > >> requires the loop to sort out. > >> > >> But let's say I have a dma_fence pointer that I got from, say, calling > >> dma_resv_excl_fence() under rcu_read_lock(). What am I allowed to do > >> with it under the RCU lock? What assumptions can I make? Is this > >> code, for instance, ok? > >> > >> rcu_read_lock(); > >> fence = dma_resv_excl_fence(obj); > >> idle = !fence || test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags); > >> rcu_read_unlock(); > >> > >> This code very much looks correct under the following assumptions: > >> > >> 1. A valid fence pointer stays alive under the RCU read lock > >> 2. SIGNALED_BIT is set-once (it's never unset after being set). > >> > >> However, if it were, we wouldn't have dma_resv_test_singnaled(), now > >> would we? :-) > >> > >> The moment you introduce ANY dma_fence recycling that recycles a > >> dma_fence within a single RCU grace period, all your assumptions break > >> down. SLAB_TYPESAFE_BY_RCU is just one way that i915 does this. We > >> also have a little i915_request recycler to try and help with memory > >> pressure scenarios in certain critical sections that also doesn't > >> respect RCU grace periods. And, as mentioned multiple times, our > >> recycling leaks into every other driver because, thanks to i915's > >> choice, the above 4-line code snippet isn't valid ANYWHERE in the > >> kernel. > >> > >> So the question I'm raising isn't so much about the rules today. > >> Today, we live in the wild wild west where everything is YOLO. But > >> where do we want to go? Do we like this wild west world? So we want > >> more consistency under the RCU read lock? If so, what do we want the > >> rules to be? > >> > >> One option would be to accept the wild-west world we live in and say > >> "The RCU read lock gains you nothing. If you want to touch the guts > >> of a dma_fence, take a reference". But, at that point, we're eating > >> two atomics for every time someone wants to look at a dma_fence. Do > >> we want that? > >> > >> Alternatively, and this what I think Daniel and I were trying to > >> propose here, is that we place some constraints on dma_fence > >> recycling. Specifically that, under the RCU read lock, the fence > >> doesn't suddenly become a new fence. All of the immutability and > >> once-mutability guarantees of various bits of dma_fence hold as long > >> as you have the RCU read lock. > > Yeah this is suboptimal. Too many potential bugs, not enough benefits. > > > > This entire __rcu business started so that there would be a lockless > > way to get at fences, or at least the exclusive one. That did not > > really pan out. I think we have a few options: > > > > - drop the idea of rcu/lockless dma-fence access outright. A quick > > sequence of grabbing the lock, acquiring the dma_fence and then > > dropping your lock again is probably plenty good. There's a lot of > > call_rcu and other stuff we could probably delete. I have no idea what > > the perf impact across all the drivers would be. > > The question is maybe not the perf impact
Re: [PATCH 3/6] dma-buf: Document DMA_BUF_IOCTL_SYNC (v2)
Am 10.06.21 um 23:09 schrieb Jason Ekstrand: This adds a new "DMA Buffer ioctls" section to the dma-buf docs and adds documentation for DMA_BUF_IOCTL_SYNC. v2 (Daniel Vetter): - Fix a couple typos - Add commentary about synchronization with other devices - Use item list format for describing flags Signed-off-by: Jason Ekstrand Cc: Daniel Vetter Cc: Christian König Cc: Sumit Semwal Acked-by: Christian König --- Documentation/driver-api/dma-buf.rst | 8 + include/uapi/linux/dma-buf.h | 46 +++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst index 7f21425d9435a..0d4c13ec1a800 100644 --- a/Documentation/driver-api/dma-buf.rst +++ b/Documentation/driver-api/dma-buf.rst @@ -88,6 +88,9 @@ consider though: - The DMA buffer FD is also pollable, see `Implicit Fence Poll Support`_ below for details. +- The DMA buffer FD also supports a few dma-buf-specific ioctls, see + `DMA Buffer ioctls`_ below for details. + Basic Operation and Device DMA Access ~ @@ -106,6 +109,11 @@ Implicit Fence Poll Support .. kernel-doc:: drivers/dma-buf/dma-buf.c :doc: implicit fence polling +DMA Buffer ioctls +~ + +.. kernel-doc:: include/uapi/linux/dma-buf.h + Kernel Functions and Structures Reference ~ diff --git a/include/uapi/linux/dma-buf.h b/include/uapi/linux/dma-buf.h index 7f30393b92c3b..1c131002fe1ee 100644 --- a/include/uapi/linux/dma-buf.h +++ b/include/uapi/linux/dma-buf.h @@ -22,8 +22,52 @@ #include -/* begin/end dma-buf functions used for userspace mmap. */ +/** + * struct dma_buf_sync - Synchronize with CPU access. + * + * When a DMA buffer is accessed from the CPU via mmap, it is not always + * possible to guarantee coherency between the CPU-visible map and underlying + * memory. To manage coherency, DMA_BUF_IOCTL_SYNC must be used to bracket + * any CPU access to give the kernel the chance to shuffle memory around if + * needed. + * + * Prior to accessing the map, the client must call DMA_BUF_IOCTL_SYNC + * with DMA_BUF_SYNC_START and the appropriate read/write flags. Once the + * access is complete, the client should call DMA_BUF_IOCTL_SYNC with + * DMA_BUF_SYNC_END and the same read/write flags. + * + * The synchronization provided via DMA_BUF_IOCTL_SYNC only provides cache + * coherency. It does not prevent other processes or devices from + * accessing the memory at the same time. If synchronization with a GPU or + * other device driver is required, it is the client's responsibility to + * wait for buffer to be ready for reading or writing. If the driver or + * API with which the client is interacting uses implicit synchronization, + * this can be done via poll() on the DMA buffer file descriptor. If the + * driver or API requires explicit synchronization, the client may have to + * wait on a sync_file or other synchronization primitive outside the scope + * of the DMA buffer API. + */ struct dma_buf_sync { + /** +* @flags: Set of access flags +* +* DMA_BUF_SYNC_START: +* Indicates the start of a map access session. +* +* DMA_BUF_SYNC_END: +* Indicates the end of a map access session. +* +* DMA_BUF_SYNC_READ: +* Indicates that the mapped DMA buffer will be read by the +* client via the CPU map. +* +* DMA_BUF_SYNC_WRITE: +* Indicates that the mapped DMA buffer will be written by the +* client via the CPU map. +* +* DMA_BUF_SYNC_RW: +* An alias for DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE. +*/ __u64 flags; };
Re: [PATCH] drm: Lock pointer access in drm_master_release()
On Fri, Jun 11, 2021 at 4:18 AM Desmond Cheong Zhi Xi wrote: On 11/6/21 12:48 am, Daniel Vetter wrote: > > On Thu, Jun 10, 2021 at 11:21:39PM +0800, Desmond Cheong Zhi Xi wrote: > >> On 10/6/21 6:10 pm, Daniel Vetter wrote: > >>> On Wed, Jun 09, 2021 at 05:21:19PM +0800, Desmond Cheong Zhi Xi wrote: > This patch eliminates the following smatch warning: > drivers/gpu/drm/drm_auth.c:320 drm_master_release() warn: unlocked > access 'master' (line 318) expected lock '&dev->master_mutex' > > The 'file_priv->master' field should be protected by the mutex lock to > '&dev->master_mutex'. This is because other processes can concurrently > modify this field and free the current 'file_priv->master' > pointer. This could result in a use-after-free error when 'master' is > dereferenced in subsequent function calls to > 'drm_legacy_lock_master_cleanup()' or to 'drm_lease_revoke()'. > > An example of a scenario that would produce this error can be seen > from a similar bug in 'drm_getunique()' that was reported by Syzbot: > https://syzkaller.appspot.com/bug?id=148d2f1dfac64af52ffd27b661981a540724f803 > > In the Syzbot report, another process concurrently acquired the > device's master mutex in 'drm_setmaster_ioctl()', then overwrote > 'fpriv->master' in 'drm_new_set_master()'. The old value of > 'fpriv->master' was subsequently freed before the mutex was unlocked. > > Reported-by: Dan Carpenter > Signed-off-by: Desmond Cheong Zhi Xi > >>> > >>> Thanks a lot. I've done an audit of this code, and I found another > >>> potential problem in drm_is_current_master. The callers from drm_auth.c > >>> hold the dev->master_mutex, but all the external ones dont. I think we > >>> need to split this into a _locked function for use within drm_auth.c, and > >>> the exported one needs to grab the dev->master_mutex while it's checking > >>> master status. Ofc there will still be races, those are ok, but right now > >>> we run the risk of use-after free problems in drm_lease_owner. > >>> > >>> Are you up to do that fix too? > >>> > >> > >> Hi Daniel, > >> > >> Thanks for the pointer, I'm definitely up for it! > >> > >>> I think the drm_lease.c code also needs an audit, there we'd need to make > >>> sure that we hold hold either the lock or a full master reference to avoid > >>> the use-after-free issues here. > >>> > >> > >> I'd be happy to look into drm_lease.c as well. > >> > >>> Patch merged to drm-misc-fixes with cc: stable. > >>> -Daniel > >>> > --- > drivers/gpu/drm/drm_auth.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c > index f00e5abdbbf4..b59b26a71ad5 100644 > --- a/drivers/gpu/drm/drm_auth.c > +++ b/drivers/gpu/drm/drm_auth.c > @@ -315,9 +315,10 @@ int drm_master_open(struct drm_file *file_priv) > void drm_master_release(struct drm_file *file_priv) > { > struct drm_device *dev = file_priv->minor->dev; > - struct drm_master *master = file_priv->master; > + struct drm_master *master; > > mutex_lock(&dev->master_mutex); > + master = file_priv->master; > if (file_priv->magic) > idr_remove(&file_priv->master->magic_map, > file_priv->magic); > -- > 2.25.1 > > >>> > >> > >> From what I can see, there are other places in the kernel that could use > >> the > >> _locked version of drm_is_current_master as well, such as drm_mode_getfb in > >> drm_framebuffer.c. I'll take a closer look, and if the changes make sense > >> I'll prepare a patch series for them. > > > > Oh maybe we have a naming confusion: the _locked is the one where the > > caller must grab the lock already, whereas drm_is_current_master would > > grab the master_mutex internally to do the check. The one in > > drm_framebuffer.c looks like it'd need the internal one since there's no > > other need to grab the master_mutex. > > -Daniel > > > > Ah ok got it, I think I confused myself earlier. > > Just to check, may I include you in a Reported-by: tag? Sure. -Daniel -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
[Bug 213391] AMDGPU retries page fault with some specific processes amdgpu and sometimes followed [gfxhub0] retry page fault until *ERROR* ring gfx timeout, but soft recovered
https://bugzilla.kernel.org/show_bug.cgi?id=213391 --- Comment #9 from Michel Dänzer (mic...@daenzer.net) --- If you can, reverting to an older version of the files under /lib/firmware/amdgpu/ may avoid the hangs. -- You may reply to this email to add a comment. You are receiving this mail because: You are watching the assignee of the bug.
Re: [PATCH v5 1/1] drm/doc: document drm_mode_get_plane
On Fri, Jun 11, 2021 at 9:20 AM Pekka Paalanen wrote: > > On Thu, 10 Jun 2021 17:38:24 -0300 > Leandro Ribeiro wrote: > > > Add a small description and document struct fields of > > drm_mode_get_plane. > > > > Signed-off-by: Leandro Ribeiro > > --- > > include/uapi/drm/drm_mode.h | 35 +++ > > 1 file changed, 35 insertions(+) > > > > diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h > > index 9b6722d45f36..698559d9336b 100644 > > --- a/include/uapi/drm/drm_mode.h > > +++ b/include/uapi/drm/drm_mode.h > > @@ -312,16 +312,51 @@ struct drm_mode_set_plane { > > __u32 src_w; > > }; > > > > +/** > > + * struct drm_mode_get_plane - Get plane metadata. > > + * > > + * Userspace can perform a GETPLANE ioctl to retrieve information about a > > + * plane. > > + * > > + * To retrieve the number of formats supported, set @count_format_types to > > zero > > + * and call the ioctl. @count_format_types will be updated with the value. > > + * > > + * To retrieve these formats, allocate an array with the memory needed to > > store > > + * @count_format_types formats. Point @format_type_ptr to this array and > > call > > + * the ioctl again (with @count_format_types still set to the value > > returned in > > + * the first ioctl call). > > + */ > > struct drm_mode_get_plane { > > + /** > > + * @plane_id: Object ID of the plane whose information should be > > + * retrieved. Set by caller. > > + */ > > __u32 plane_id; > > > > + /** @crtc_id: Object ID of the current CRTC. */ > > __u32 crtc_id; > > + /** @fb_id: Object ID of the current fb. */ > > __u32 fb_id; > > > > + /** > > + * @possible_crtcs: Bitmask of CRTC's compatible with the plane. > > CRTC's > > + * are created and they receive an index, which corresponds to their > > + * position in the bitmask. Bit N corresponds to > > + * :ref:`CRTC index` N. > > + */ > > __u32 possible_crtcs; > > + /** > > + * @gamma_size: Number of entries of the legacy gamma lookup table. > > + * Deprecated. > > + */ > > __u32 gamma_size; > > Hi, > > I wonder, has this field ever been used? > > "The legacy gamma" refers to CRTC gamma LUT AFAIK, but this here is > about planes. I forgot that at first, so didn't see anything funny. Yeah "Deprecated" isn't really conveying that this was never used or implemented anywehere ever. I think we should put that into the docs to make this clear, otherwise someone is going to wonder whether maybe they still need to parse it since it's only deprecated and there's no other plane gamma (yet). I wouldn't even put any further docs than that in it, because stating that it's the number of entries for something we never implemented is going to be confusing at best :-) -Daniel > > Anyway, whether the doc for this field is as is, or is changed to > "never used" or "unused" or "reserved" or whatever, you have my: > > Reviewed-by: Pekka Paalanen > > With the caveat that I didn't actually build the docs to see how they > look. > > > Thanks, > pq > > > > > + /** @count_format_types: Number of formats. */ > > __u32 count_format_types; > > + /** > > + * @format_type_ptr: Pointer to ``__u32`` array of formats that are > > + * supported by the plane. These formats do not require modifiers. > > + */ > > __u64 format_type_ptr; > > }; > > > > -- > > 2.31.1 > > > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
Re: [Intel-gfx] [PATCH 0/5] dma-fence, i915: Stop allowing SLAB_TYPESAFE_BY_RCU for dma_fence
Am 11.06.21 um 09:20 schrieb Daniel Vetter: On Fri, Jun 11, 2021 at 8:55 AM Christian König wrote: Am 10.06.21 um 22:42 schrieb Daniel Vetter: On Thu, Jun 10, 2021 at 10:10 PM Jason Ekstrand wrote: On Thu, Jun 10, 2021 at 8:35 AM Jason Ekstrand wrote: On Thu, Jun 10, 2021 at 6:30 AM Daniel Vetter wrote: On Thu, Jun 10, 2021 at 11:39 AM Christian König wrote: Am 10.06.21 um 11:29 schrieb Tvrtko Ursulin: On 09/06/2021 22:29, Jason Ekstrand wrote: We've tried to keep it somewhat contained by doing most of the hard work to prevent access of recycled objects via dma_fence_get_rcu_safe(). However, a quick grep of kernel sources says that, of the 30 instances of dma_fence_get_rcu*, only 11 of them use dma_fence_get_rcu_safe(). It's likely there bear traps in DRM and related subsystems just waiting for someone to accidentally step in them. ...because dma_fence_get_rcu_safe apears to be about whether the *pointer* to the fence itself is rcu protected, not about the fence object itself. Yes, exactly that. The fact that both of you think this either means that I've completely missed what's going on with RCUs here (possible but, in this case, I think unlikely) or RCUs on dma fences should scare us all. Taking a step back for a second and ignoring SLAB_TYPESAFE_BY_RCU as such, I'd like to ask a slightly different question: What are the rules about what is allowed to be done under the RCU read lock and what guarantees does a driver need to provide? I think so far that we've all agreed on the following: 1. Freeing an unsignaled fence is ok as long as it doesn't have any pending callbacks. (Callbacks should hold a reference anyway). 2. The pointer race solved by dma_fence_get_rcu_safe is real and requires the loop to sort out. But let's say I have a dma_fence pointer that I got from, say, calling dma_resv_excl_fence() under rcu_read_lock(). What am I allowed to do with it under the RCU lock? What assumptions can I make? Is this code, for instance, ok? rcu_read_lock(); fence = dma_resv_excl_fence(obj); idle = !fence || test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags); rcu_read_unlock(); This code very much looks correct under the following assumptions: 1. A valid fence pointer stays alive under the RCU read lock 2. SIGNALED_BIT is set-once (it's never unset after being set). However, if it were, we wouldn't have dma_resv_test_singnaled(), now would we? :-) The moment you introduce ANY dma_fence recycling that recycles a dma_fence within a single RCU grace period, all your assumptions break down. SLAB_TYPESAFE_BY_RCU is just one way that i915 does this. We also have a little i915_request recycler to try and help with memory pressure scenarios in certain critical sections that also doesn't respect RCU grace periods. And, as mentioned multiple times, our recycling leaks into every other driver because, thanks to i915's choice, the above 4-line code snippet isn't valid ANYWHERE in the kernel. So the question I'm raising isn't so much about the rules today. Today, we live in the wild wild west where everything is YOLO. But where do we want to go? Do we like this wild west world? So we want more consistency under the RCU read lock? If so, what do we want the rules to be? One option would be to accept the wild-west world we live in and say "The RCU read lock gains you nothing. If you want to touch the guts of a dma_fence, take a reference". But, at that point, we're eating two atomics for every time someone wants to look at a dma_fence. Do we want that? Alternatively, and this what I think Daniel and I were trying to propose here, is that we place some constraints on dma_fence recycling. Specifically that, under the RCU read lock, the fence doesn't suddenly become a new fence. All of the immutability and once-mutability guarantees of various bits of dma_fence hold as long as you have the RCU read lock. Yeah this is suboptimal. Too many potential bugs, not enough benefits. This entire __rcu business started so that there would be a lockless way to get at fences, or at least the exclusive one. That did not really pan out. I think we have a few options: - drop the idea of rcu/lockless dma-fence access outright. A quick sequence of grabbing the lock, acquiring the dma_fence and then dropping your lock again is probably plenty good. There's a lot of call_rcu and other stuff we could probably delete. I have no idea what the perf impact across all the drivers would be. The question is maybe not the perf impact, but rather if that is possible over all. IIRC we now have some cases in TTM where RCU is mandatory and we simply don't have any other choice than using it. Adding Thomas Hellstrom. Where is that stuff? If we end up with all the dma_resv locking complexity just for an oddball, then I think that would be rather big bummer. This is during buffer destruction. See the call to dma_resv_copy_fences(). But that is basically just using a dma_resv function which acc
Re: [PATCH 5/6] RFC: dma-buf: Add an extra fence to dma_resv_get_singleton_unlocked
Am 10.06.21 um 23:09 schrieb Jason Ekstrand: For dma-buf sync_file import, we want to get all the fences on a dma_resv plus one more. We could wrap the fence we get back in an array fence or we could make dma_resv_get_singleton_unlocked take "one more" to make this case easier. Signed-off-by: Jason Ekstrand Reviewed-by: Daniel Vetter Reviewed-by: Christian König Cc: Christian König Cc: Maarten Lankhorst --- drivers/dma-buf/dma-buf.c | 2 +- drivers/dma-buf/dma-resv.c | 23 +-- include/linux/dma-resv.h | 3 ++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 41b14b53cdda3..831828d71b646 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -389,7 +389,7 @@ static long dma_buf_export_sync_file(struct dma_buf *dmabuf, return fd; if (arg.flags & DMA_BUF_SYNC_WRITE) { - fence = dma_resv_get_singleton(dmabuf->resv); + fence = dma_resv_get_singleton(dmabuf->resv, NULL); if (IS_ERR(fence)) { ret = PTR_ERR(fence); goto err_put_fd; diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index 1b26aa7e5d81c..7c48c23239b4b 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -504,6 +504,7 @@ EXPORT_SYMBOL_GPL(dma_resv_get_fences); /** * dma_resv_get_singleton - get a single fence for the dma_resv object * @obj: the reservation object + * @extra: extra fence to add to the resulting array * * Get a single fence representing all unsignaled fences in the dma_resv object * plus the given extra fence. If we got only one fence return a new @@ -512,7 +513,8 @@ EXPORT_SYMBOL_GPL(dma_resv_get_fences); * RETURNS * The singleton dma_fence on success or an ERR_PTR on failure */ -struct dma_fence *dma_resv_get_singleton(struct dma_resv *obj) +struct dma_fence *dma_resv_get_singleton(struct dma_resv *obj, +struct dma_fence *extra) { struct dma_fence *result, **resv_fences, *fence, *chain, **fences; struct dma_fence_array *array; @@ -523,7 +525,7 @@ struct dma_fence *dma_resv_get_singleton(struct dma_resv *obj) if (err) return ERR_PTR(err); - if (num_resv_fences == 0) + if (num_resv_fences == 0 && !extra) return NULL; num_fences = 0; @@ -539,6 +541,16 @@ struct dma_fence *dma_resv_get_singleton(struct dma_resv *obj) } } + if (extra) { + dma_fence_deep_dive_for_each(fence, chain, j, extra) { + if (dma_fence_is_signaled(fence)) + continue; + + result = fence; + ++num_fences; + } + } + if (num_fences <= 1) { result = dma_fence_get(result); goto put_resv_fences; @@ -559,6 +571,13 @@ struct dma_fence *dma_resv_get_singleton(struct dma_resv *obj) } } + if (extra) { + dma_fence_deep_dive_for_each(fence, chain, j, extra) { + if (dma_fence_is_signaled(fence)) + fences[num_fences++] = dma_fence_get(fence); + } + } + if (num_fences <= 1) { result = num_fences ? fences[0] : NULL; kfree(fences); diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h index d60982975a786..f970e03fc1a08 100644 --- a/include/linux/dma-resv.h +++ b/include/linux/dma-resv.h @@ -275,7 +275,8 @@ void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence); int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl, unsigned *pshared_count, struct dma_fence ***pshared); int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src); -struct dma_fence *dma_resv_get_singleton(struct dma_resv *obj); +struct dma_fence *dma_resv_get_singleton(struct dma_resv *obj, +struct dma_fence *extra); long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr, unsigned long timeout); bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all);
Re: [PATCH 1/7] dma-buf: some dma_fence_chain improvements
On Thu, Jun 10, 2021 at 11:17:54AM +0200, Christian König wrote: > The callback and the irq work are never used at the same > time. Putting them into an union saves us 24 bytes and > makes the structure only 120 bytes in size. Yeah pushing below 128 bytes makes sense. > > Signed-off-by: Christian König > --- > drivers/dma-buf/dma-fence-chain.c | 2 +- > include/linux/dma-fence-chain.h | 8 +--- > 2 files changed, 6 insertions(+), 4 deletions(-) > > diff --git a/drivers/dma-buf/dma-fence-chain.c > b/drivers/dma-buf/dma-fence-chain.c > index 7d129e68ac70..1b4cb3e5cec9 100644 > --- a/drivers/dma-buf/dma-fence-chain.c > +++ b/drivers/dma-buf/dma-fence-chain.c > @@ -137,6 +137,7 @@ static void dma_fence_chain_cb(struct dma_fence *f, > struct dma_fence_cb *cb) > struct dma_fence_chain *chain; > > chain = container_of(cb, typeof(*chain), cb); > + init_irq_work(&chain->work, dma_fence_chain_irq_work); > irq_work_queue(&chain->work); > dma_fence_put(f); > } > @@ -239,7 +240,6 @@ void dma_fence_chain_init(struct dma_fence_chain *chain, > rcu_assign_pointer(chain->prev, prev); > chain->fence = fence; > chain->prev_seqno = 0; > - init_irq_work(&chain->work, dma_fence_chain_irq_work); > > /* Try to reuse the context of the previous chain node. */ > if (prev_chain && __dma_fence_is_later(seqno, prev->seqno, prev->ops)) { > diff --git a/include/linux/dma-fence-chain.h b/include/linux/dma-fence-chain.h > index 10462a029da2..9d6a062be640 100644 > --- a/include/linux/dma-fence-chain.h > +++ b/include/linux/dma-fence-chain.h > @@ -25,12 +25,14 @@ > */ > struct dma_fence_chain { > struct dma_fence base; > - spinlock_t lock; > struct dma_fence __rcu *prev; > u64 prev_seqno; > struct dma_fence *fence; > - struct dma_fence_cb cb; > - struct irq_work work; Can you pls pull the kerneldoc inline here for these too and extend the comments that @work is only used from the callback, at which point we don't need @cb anymore? For union lifetime tricks we really should document this in the datastructure docs. With that: Reviewed-by: Daniel Vetter I also think it'd be good to specify this clearly in the kerneldoc for dma_fence_add_callback() with something like: "Note that the registered @cb structure is no longer in use by the signalling code by the time @func is called, and can therefore be used again. This is useful when @func launches a work item because it allows us to put both the struct dma_fence_cb and the work struct (e.g. struct work_struct) into a union to save space." Feel free to includ this in this patch here or do a separate one. Cheers, Daniel > + union { > + struct dma_fence_cb cb; > + struct irq_work work; > + }; > + spinlock_t lock; > }; > > extern const struct dma_fence_ops dma_fence_chain_ops; > -- > 2.25.1 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
Re: [PATCH 2/7] dma-buf: add dma_fence_chain_alloc/free
On Thu, Jun 10, 2021 at 11:17:55AM +0200, Christian König wrote: > Add a common allocation helper. Cleaning up the mix of kzalloc/kmalloc > and some unused code in the selftest. > > Signed-off-by: Christian König > --- > drivers/dma-buf/st-dma-fence-chain.c | 16 -- > drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c| 4 ++-- > drivers/gpu/drm/drm_syncobj.c | 6 ++--- > .../gpu/drm/i915/gem/i915_gem_execbuffer.c| 6 ++--- > drivers/gpu/drm/msm/msm_gem_submit.c | 6 ++--- > include/linux/dma-fence-chain.h | 22 +++ > 6 files changed, 35 insertions(+), 25 deletions(-) > > diff --git a/drivers/dma-buf/st-dma-fence-chain.c > b/drivers/dma-buf/st-dma-fence-chain.c > index 9525f7f56119..8ce1ea59d31b 100644 > --- a/drivers/dma-buf/st-dma-fence-chain.c > +++ b/drivers/dma-buf/st-dma-fence-chain.c > @@ -58,28 +58,20 @@ static struct dma_fence *mock_fence(void) > return &f->base; > } > > -static inline struct mock_chain { > - struct dma_fence_chain base; > -} *to_mock_chain(struct dma_fence *f) { > - return container_of(f, struct mock_chain, base.base); > -} > - > static struct dma_fence *mock_chain(struct dma_fence *prev, > struct dma_fence *fence, > u64 seqno) > { > - struct mock_chain *f; > + struct dma_fence_chain *f; > > - f = kmalloc(sizeof(*f), GFP_KERNEL); > + f = dma_fence_chain_alloc(); > if (!f) > return NULL; > > - dma_fence_chain_init(&f->base, > - dma_fence_get(prev), > - dma_fence_get(fence), > + dma_fence_chain_init(f, dma_fence_get(prev), dma_fence_get(fence), >seqno); > > - return &f->base.base; > + return &f->base; > } > > static int sanitycheck(void *arg) > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > index 90136f9dedd6..325e82621467 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > @@ -1124,7 +1124,7 @@ static int > amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p > > dep->chain = NULL; > if (syncobj_deps[i].point) { > - dep->chain = kmalloc(sizeof(*dep->chain), GFP_KERNEL); > + dep->chain = dma_fence_chain_alloc(); > if (!dep->chain) > return -ENOMEM; > } > @@ -1132,7 +1132,7 @@ static int > amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p > dep->syncobj = drm_syncobj_find(p->filp, > syncobj_deps[i].handle); > if (!dep->syncobj) { > - kfree(dep->chain); > + dma_fence_chain_free(dep->chain); > return -EINVAL; > } > dep->point = syncobj_deps[i].point; > diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c > index fdd2ec87cdd1..1c5b9ef6da37 100644 > --- a/drivers/gpu/drm/drm_syncobj.c > +++ b/drivers/gpu/drm/drm_syncobj.c > @@ -861,7 +861,7 @@ static int drm_syncobj_transfer_to_timeline(struct > drm_file *file_private, >&fence); > if (ret) > goto err; > - chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); > + chain = dma_fence_chain_alloc(); > if (!chain) { > ret = -ENOMEM; > goto err1; > @@ -1402,10 +1402,10 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device > *dev, void *data, > goto err_points; > } > for (i = 0; i < args->count_handles; i++) { > - chains[i] = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); > + chains[i] = dma_fence_chain_alloc(); > if (!chains[i]) { > for (j = 0; j < i; j++) > - kfree(chains[j]); > + dma_fence_chain_free(chains[j]); > ret = -ENOMEM; > goto err_chains; > } > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > index 66789111a24b..a22cb86730b3 100644 > --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > @@ -2983,7 +2983,7 @@ __free_fence_array(struct eb_fence *fences, unsigned > int n) > while (n--) { > drm_syncobj_put(ptr_mask_bits(fences[n].syncobj, 2)); > dma_fence_put(fences[n].dma_fence); > - kfree(fences[n].chain_fence); > + dma_fence_chain_free(fences[n].chain_fence); > } > kvfree(fences); > } > @@ -3097,9 +3097,7 @@ add_timeline_fence_array(struct i915_execbuffer *eb, >
Re: [PATCH 3/7] dma-buf: add dma_fence_chain_alloc/free self tests
On Thu, Jun 10, 2021 at 11:17:56AM +0200, Christian König wrote: > Exercise the newly added functions. > > Signed-off-by: Christian König I have honestly no idea what this checks. Spawning a few threads to validate kmalloc/kfree feels a bit silly. Now testing whether we correctly rcu-delay the freeing here would make some sense, but even that feels a bit silly. I guess if you want this explain with comments what it does and why? -Daniel > --- > drivers/dma-buf/st-dma-fence-chain.c | 48 > 1 file changed, 48 insertions(+) > > diff --git a/drivers/dma-buf/st-dma-fence-chain.c > b/drivers/dma-buf/st-dma-fence-chain.c > index 8ce1ea59d31b..855c129c6093 100644 > --- a/drivers/dma-buf/st-dma-fence-chain.c > +++ b/drivers/dma-buf/st-dma-fence-chain.c > @@ -95,6 +95,53 @@ static int sanitycheck(void *arg) > return err; > } > > +static int __alloc_free(void *arg) > +{ > + atomic_t *counter = arg; > + int i, j; > + > + for (i = 0; i < 1024; ++i) { > + struct dma_fence_chain *chains[64]; > + > + for (j = 0; j < ARRAY_SIZE(chains); ++j) > + chains[j] = dma_fence_chain_alloc(); > + > + for (j = 0; j < ARRAY_SIZE(chains); ++j) > + dma_fence_chain_free(chains[j]); > + > + atomic_add(ARRAY_SIZE(chains), counter); > + } > + return 0; > +} > + > +static int alloc_free(void *arg) > +{ > + struct task_struct *threads[8]; > + atomic_t counter = ATOMIC_INIT(0); > + int i, err = 0; > + > + for (i = 0; i < ARRAY_SIZE(threads); i++) { > + threads[i] = kthread_run(__alloc_free, &counter, "dmabuf/%d", > + i); > + if (IS_ERR(threads[i])) { > + err = PTR_ERR(threads[i]); > + break; > + } > + } > + > + while (i--) { > + int ret; > + > + ret = kthread_stop(threads[i]); > + if (ret && !err) > + err = ret; > + } > + > + pr_info("Completed %u cycles\n", atomic_read(&counter)); > + > + return err; > +} > + > struct fence_chains { > unsigned int chain_length; > struct dma_fence **fences; > @@ -677,6 +724,7 @@ int dma_fence_chain(void) > { > static const struct subtest tests[] = { > SUBTEST(sanitycheck), > + SUBTEST(alloc_free), > SUBTEST(find_seqno), > SUBTEST(find_signaled), > SUBTEST(find_out_of_order), > -- > 2.25.1 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
Re: [PATCH 04/11] drm/ingenic: Move no_vblank to private state
Hi Daniel, Le mar., juin 1 2021 at 17:48:12 +0200, Daniel Vetter a écrit : On Fri, May 28, 2021 at 12:20:58AM +0100, Paul Cercueil wrote: This information is carried from the ".atomic_check" to the ".atomic_commit_tail"; as such it is state-specific, and should be moved to the private state structure. Signed-off-by: Paul Cercueil Not sure this applies to your hw, but drm_crtc_state.no_vblank exists. Might want to move to that instead of rolling your own. Or explain why you need your own here in your own private state. It does look quite a bit like you're just rolling your own version of this support that helpers gained meanwhile. If I use drm_crtc_state->no_vblank, then I need a custom .atomic_commit_tail() that only calls drm_atomic_helper_wait_for_vblanks() when !no_vblank. That works, but I don't understand why drm_atomic_helper_commit_tail() doesn't do that by default, and makes me think I'm using it wrong. Cheers, -Paul -Daniel --- drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 41 --- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index e81084eb3b0e..639994329c60 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -66,6 +66,8 @@ struct jz_soc_info { struct ingenic_drm_private_state { struct drm_private_state base; + + bool no_vblank; }; struct ingenic_drm { @@ -87,7 +89,6 @@ struct ingenic_drm { dma_addr_t dma_hwdescs_phys; bool panel_is_sharp; - bool no_vblank; /* * clk_mutex is used to synchronize the pixel clock rate update with @@ -113,6 +114,30 @@ to_ingenic_drm_priv_state(struct drm_private_state *state) return container_of(state, struct ingenic_drm_private_state, base); } +static struct ingenic_drm_private_state * +ingenic_drm_get_priv_state(struct ingenic_drm *priv, struct drm_atomic_state *state) +{ + struct drm_private_state *priv_state; + + priv_state = drm_atomic_get_private_obj_state(state, &priv->private_obj); + if (IS_ERR(priv_state)) + return ERR_CAST(priv_state); + + return to_ingenic_drm_priv_state(priv_state); +} + +static struct ingenic_drm_private_state * +ingenic_drm_get_new_priv_state(struct ingenic_drm *priv, struct drm_atomic_state *state) +{ + struct drm_private_state *priv_state; + + priv_state = drm_atomic_get_new_private_obj_state(state, &priv->private_obj); + if (!priv_state) + return NULL; + + return to_ingenic_drm_priv_state(priv_state); +} + static bool ingenic_drm_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -268,6 +293,7 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc, crtc); struct ingenic_drm *priv = drm_crtc_get_priv(crtc); struct drm_plane_state *f1_state, *f0_state, *ipu_state = NULL; + struct ingenic_drm_private_state *priv_state; if (crtc_state->gamma_lut && drm_color_lut_size(crtc_state->gamma_lut) != ARRAY_SIZE(priv->dma_hwdescs->palette)) { @@ -299,9 +325,13 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc, } } + priv_state = ingenic_drm_get_priv_state(priv, state); + if (IS_ERR(priv_state)) + return PTR_ERR(priv_state); + /* If all the planes are disabled, we won't get a VBLANK IRQ */ - priv->no_vblank = !f1_state->fb && !f0_state->fb && -!(ipu_state && ipu_state->fb); + priv_state->no_vblank = !f1_state->fb && !f0_state->fb && + !(ipu_state && ipu_state->fb); } return 0; @@ -727,6 +757,7 @@ static void ingenic_drm_atomic_helper_commit_tail(struct drm_atomic_state *old_s */ struct drm_device *dev = old_state->dev; struct ingenic_drm *priv = drm_device_get_priv(dev); + struct ingenic_drm_private_state *priv_state; drm_atomic_helper_commit_modeset_disables(dev, old_state); @@ -736,7 +767,9 @@ static void ingenic_drm_atomic_helper_commit_tail(struct drm_atomic_state *old_s drm_atomic_helper_commit_hw_done(old_state); - if (!priv->no_vblank) + priv_state = ingenic_drm_get_new_priv_state(priv, old_state); + + if (!priv_state || !priv_state->no_vblank) drm_atomic_helper_wait_for_vblanks(dev, old_state); drm_atomic_helper_cleanup_planes(dev, old_state); -- 2.30.2 -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
Re: [PATCH v3] Documentation: gpu: Mention the requirements for new properties
On Thursday, June 10th, 2021 at 23:00, Daniel Vetter wrote: > If there's a strong consensus that we really need this then I'm not > going to nack this, but this really needs a pile of acks from > compositor folks that they're willing to live with the resulting > fallout this will likely bring. Your cc list seems to have an absence > of compositor folks, but instead every driver maintainer. That's > backwards. We make uapi for userspace, not for kernel driver > maintainers! In wlroots we have a policy of only allowing standard KMS properties to be used. Any vendor-specific property is going to be less well-defined, less widely useful, potentially have more design issues, potentially overlap in functionality with other vendor-specific properties, likely have some hardware-specific assumptions, etc. What matters here is discussing with other driver & user-space folks to make sure the new property's design is sound. Designing uAPI is hard. If kernel folks are struggling with a user-space implementation, they should discuss with user-space folks to see which project would be interested. There's a chance a compositor will be interested in the new property and will just do the user-space part for you, if not we can suggest candidate projects. tl;dr strong agree with Daniel here.
Re: [Intel-gfx] [PATCH v4 12/17] drm/i915/pxp: start the arb session on demand
On Thu, Jun 10, 2021 at 03:44:37PM -0700, Daniele Ceraolo Spurio wrote: > > > On 6/2/2021 11:14 AM, Rodrigo Vivi wrote: > > On Mon, May 24, 2021 at 10:47:58PM -0700, Daniele Ceraolo Spurio wrote: > > > Now that we can handle destruction and re-creation of the arb session, > > > we can postpone the start of the session to the first submission that > > > requires it, to avoid keeping it running with no user. > > > > > > Signed-off-by: Daniele Ceraolo Spurio > > > --- > > > .../gpu/drm/i915/gem/i915_gem_execbuffer.c| 8 ++-- > > > drivers/gpu/drm/i915/pxp/intel_pxp.c | 37 --- > > > drivers/gpu/drm/i915/pxp/intel_pxp.h | 4 +- > > > drivers/gpu/drm/i915/pxp/intel_pxp_irq.c | 2 +- > > > drivers/gpu/drm/i915/pxp/intel_pxp_session.c | 6 +-- > > > drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 10 + > > > drivers/gpu/drm/i915/pxp/intel_pxp_types.h| 3 ++ > > > 7 files changed, 39 insertions(+), 31 deletions(-) > > > > > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > > > b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > > > index a11e9d5767bf..c08e28847064 100644 > > > --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > > > @@ -2948,9 +2948,11 @@ eb_select_engine(struct i915_execbuffer *eb) > > > intel_gt_pm_get(ce->engine->gt); > > > if (i915_gem_context_uses_protected_content(eb->gem_context)) { > > > - err = intel_pxp_wait_for_arb_start(&ce->engine->gt->pxp); > > > - if (err) > > > - goto err; > > > + if (!intel_pxp_is_active(&ce->engine->gt->pxp)) { > > > + err = intel_pxp_start(&ce->engine->gt->pxp); > > > + if (err) > > > + goto err; > > > + } > > > if (i915_gem_context_invalidated(eb->gem_context)) { > > > err = -EACCES; > > > diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c > > > b/drivers/gpu/drm/i915/pxp/intel_pxp.c > > > index f713d3423cea..2291c68fd3a0 100644 > > > --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c > > > +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c > > > @@ -77,6 +77,7 @@ void intel_pxp_init(struct intel_pxp *pxp) > > > init_completion(&pxp->termination); > > > complete_all(&pxp->termination); > > > + mutex_init(&pxp->arb_mutex); > > > INIT_WORK(&pxp->session_work, intel_pxp_session_work); > > > ret = create_vcs_context(pxp); > > > @@ -113,7 +114,7 @@ void intel_pxp_mark_termination_in_progress(struct > > > intel_pxp *pxp) > > > reinit_completion(&pxp->termination); > > > } > > > -static void intel_pxp_queue_termination(struct intel_pxp *pxp) > > > +static void pxp_queue_termination(struct intel_pxp *pxp) > > > { > > > struct intel_gt *gt = pxp_to_gt(pxp); > > > @@ -132,31 +133,41 @@ static void intel_pxp_queue_termination(struct > > > intel_pxp *pxp) > > >* the arb session is restarted from the irq work when we receive the > > >* termination completion interrupt > > >*/ > > > -int intel_pxp_wait_for_arb_start(struct intel_pxp *pxp) > > > +int intel_pxp_start(struct intel_pxp *pxp) > > > { > > > + int ret = 0; > > > + > > > if (!intel_pxp_is_enabled(pxp)) > > > - return 0; > > > + return -ENODEV; > > > + > > > + mutex_lock(&pxp->arb_mutex); > > > + > > > + if (pxp->arb_is_valid) > > > + goto unlock; > > > + > > > + pxp_queue_termination(pxp); > > > if (!wait_for_completion_timeout(&pxp->termination, > > > - msecs_to_jiffies(100))) > > > - return -ETIMEDOUT; > > > + msecs_to_jiffies(100))) { > > > + ret = -ETIMEDOUT; > > > + goto unlock; > > > + } > > > + > > > + /* make sure the compiler doesn't optimize the double access */ > > > + barrier(); > > > if (!pxp->arb_is_valid) > > > - return -EIO; > > > + ret = -EIO; > > > - return 0; > > > +unlock: > > > + mutex_unlock(&pxp->arb_mutex); > > > + return ret; > > > } > > > void intel_pxp_init_hw(struct intel_pxp *pxp) > > > { > > > kcr_pxp_enable(pxp_to_gt(pxp)); > > > intel_pxp_irq_enable(pxp); > > > - > > > - /* > > > - * the session could've been attacked while we weren't loaded, so > > > - * handle it as if it was and re-create it. > > > - */ > > > - intel_pxp_queue_termination(pxp); > > > } > > > void intel_pxp_fini_hw(struct intel_pxp *pxp) > > > diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h > > > b/drivers/gpu/drm/i915/pxp/intel_pxp.h > > > index 91c1a2056309..1f9871e64096 100644 > > > --- a/drivers/gpu/drm/i915/pxp/intel_pxp.h > > > +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h > > > @@ -32,7 +32,7 @@ void intel_pxp_init_hw(struct intel_pxp *pxp); > > > void intel_pxp_fini_hw(struct intel_pxp *pxp); > > > void intel_pxp_mark_termination_in_progress(str
Re: [PATCH v4 13/17] drm/i915/pxp: Enable PXP power management
On Thu, Jun 10, 2021 at 03:58:13PM -0700, Daniele Ceraolo Spurio wrote: > > > On 6/2/2021 9:20 AM, Rodrigo Vivi wrote: > > On Mon, May 24, 2021 at 10:47:59PM -0700, Daniele Ceraolo Spurio wrote: > > > From: "Huang, Sean Z" > > > > > > During the power event S3+ sleep/resume, hardware will lose all the > > > encryption keys for every hardware session, even though the > > > session state might still be marked as alive after resume. Therefore, > > > we should consider the session as dead on suspend and invalidate all the > > > objects. The session will be automatically restarted on the first > > > protected submission on resume. > > > > > > v2: runtime suspend also invalidates the keys > > > v3: fix return codes, simplify rpm ops (Chris), use the new worker func > > > v4: invalidate the objects on suspend, don't re-create the arb sesson on > > > resume (delayed to first submission). > > > > > > Signed-off-by: Huang, Sean Z > > > Signed-off-by: Daniele Ceraolo Spurio > > > Cc: Chris Wilson > > > Cc: Rodrigo Vivi > > > --- > > > drivers/gpu/drm/i915/Makefile| 1 + > > > drivers/gpu/drm/i915/gt/intel_gt_pm.c| 15 +++- > > > drivers/gpu/drm/i915/i915_drv.c | 2 + > > > drivers/gpu/drm/i915/pxp/intel_pxp_irq.c | 11 -- > > > drivers/gpu/drm/i915/pxp/intel_pxp_pm.c | 40 > > > drivers/gpu/drm/i915/pxp/intel_pxp_pm.h | 23 +++ > > > drivers/gpu/drm/i915/pxp/intel_pxp_session.c | 38 ++- > > > drivers/gpu/drm/i915/pxp/intel_pxp_tee.c | 9 + > > > 8 files changed, 124 insertions(+), 15 deletions(-) > > > create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_pm.c > > > create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_pm.h > > > > > > diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile > > > index 29331bbb3e98..9cce0bf9a50f 100644 > > > --- a/drivers/gpu/drm/i915/Makefile > > > +++ b/drivers/gpu/drm/i915/Makefile > > > @@ -278,6 +278,7 @@ i915-$(CONFIG_DRM_I915_PXP) += \ > > > pxp/intel_pxp.o \ > > > pxp/intel_pxp_cmd.o \ > > > pxp/intel_pxp_irq.o \ > > > + pxp/intel_pxp_pm.o \ > > > pxp/intel_pxp_session.o \ > > > pxp/intel_pxp_tee.o > > > diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c > > > b/drivers/gpu/drm/i915/gt/intel_gt_pm.c > > > index aef3084e8b16..91151a02f7a2 100644 > > > --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c > > > +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c > > > @@ -19,6 +19,7 @@ > > > #include "intel_rc6.h" > > > #include "intel_rps.h" > > > #include "intel_wakeref.h" > > > +#include "pxp/intel_pxp_pm.h" > > > static void user_forcewake(struct intel_gt *gt, bool suspend) > > > { > > > @@ -265,6 +266,8 @@ int intel_gt_resume(struct intel_gt *gt) > > > intel_uc_resume(>->uc); > > > + intel_pxp_resume(>->pxp); > > > + > > > user_forcewake(gt, false); > > > out_fw: > > > @@ -299,6 +302,7 @@ void intel_gt_suspend_prepare(struct intel_gt *gt) > > > user_forcewake(gt, true); > > > wait_for_suspend(gt); > > > + intel_pxp_suspend(>->pxp); > > > intel_uc_suspend(>->uc); > > > } > > > @@ -349,6 +353,7 @@ void intel_gt_suspend_late(struct intel_gt *gt) > > > void intel_gt_runtime_suspend(struct intel_gt *gt) > > > { > > > + intel_pxp_suspend(>->pxp); > > > intel_uc_runtime_suspend(>->uc); > > > GT_TRACE(gt, "\n"); > > > @@ -356,11 +361,19 @@ void intel_gt_runtime_suspend(struct intel_gt *gt) > > > int intel_gt_runtime_resume(struct intel_gt *gt) > > > { > > > + int ret; > > > + > > > GT_TRACE(gt, "\n"); > > > intel_gt_init_swizzling(gt); > > > intel_ggtt_restore_fences(gt->ggtt); > > > - return intel_uc_runtime_resume(>->uc); > > > + ret = intel_uc_runtime_resume(>->uc); > > > + if (ret) > > > + return ret; > > > + > > > + intel_pxp_resume(>->pxp); > > > + > > > + return 0; > > > } > > > static ktime_t __intel_gt_get_awake_time(const struct intel_gt *gt) > > > diff --git a/drivers/gpu/drm/i915/i915_drv.c > > > b/drivers/gpu/drm/i915/i915_drv.c > > > index 2f06bb7b3ed2..6543e5577709 100644 > > > --- a/drivers/gpu/drm/i915/i915_drv.c > > > +++ b/drivers/gpu/drm/i915/i915_drv.c > > > @@ -68,6 +68,8 @@ > > > #include "gt/intel_gt_pm.h" > > > #include "gt/intel_rc6.h" > > > +#include "pxp/intel_pxp_pm.h" > > > + > > > #include "i915_debugfs.h" > > > #include "i915_drv.h" > > > #include "i915_ioc32.h" > > > diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c > > > b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c > > > index a230d0034e50..9e5847c653f2 100644 > > > --- a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c > > > +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c > > > @@ -9,6 +9,7 @@ > > > #include "gt/intel_gt_irq.h" > > > #include "i915_irq.h" > > > #include "i915_reg.h" > > > +#include "intel_runtime_pm.h" > > > /** > > >* intel_pxp_irq_handler -
Re: [Intel-gfx] [PATCH] drm/i915: Add relocation exceptions for two other platforms
On Fri, Jun 11, 2021 at 08:09:00AM +0200, Zbigniew Kempczyński wrote: > On Thu, Jun 10, 2021 at 10:36:12AM -0400, Rodrigo Vivi wrote: > > On Thu, Jun 10, 2021 at 12:39:55PM +0200, Zbigniew Kempczyński wrote: > > > We have established previously we stop using relocations starting > > > from gen12 platforms with Tigerlake as an exception. We keep this > > > statement but we want to enable relocations conditionally for > > > Rocketlake and Alderlake under require_force_probe flag set. > > > > > > Keeping relocations under require_force_probe flag is interim solution > > > until IGTs will be rewritten to use softpin. > > > > hmm... to be really honest I'm not so happy that we are introducing > > a new criteria to the force_probe. > > > > The criteria was to have a functional driver and not to track uapi. > > > > But on the other hand I do recognize that the current definition > > of the flag allows that, because we have established that with > > this behavior, the "driver for new Intel graphics devices that > > are recognized but not properly supported by this kernel version" > > (as stated in the Kconfig for the DRM_I915_FORCE_PROBE). > > > > However... > > > > > > > > v2: - remove inline from function definition (Jani) > > > - fix indentation > > > > > > v3: change to GRAPHICS_VER() (Zbigniew) > > > > > > Signed-off-by: Zbigniew Kempczyński > > > Cc: Dave Airlie > > > Cc: Daniel Vetter > > > Cc: Jason Ekstrand > > > Acked-by: Dave Airlie > > > --- > > > .../gpu/drm/i915/gem/i915_gem_execbuffer.c| 24 +++ > > > 1 file changed, 19 insertions(+), 5 deletions(-) > > > > > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > > > b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > > > index a8abc9af5ff4..30c4f0549ea0 100644 > > > --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > > > @@ -491,16 +491,30 @@ eb_unreserve_vma(struct eb_vma *ev) > > > ev->flags &= ~__EXEC_OBJECT_RESERVED; > > > } > > > > > > +static bool platform_has_relocs_enabled(const struct i915_execbuffer *eb) > > > +{ > > > + /* > > > + * Relocations are disallowed starting from gen12 with Tigerlake > > > + * as an exception. We allow temporarily use relocations for Rocketlake > > > + * and Alderlake when require_force_probe flag is set. > > > + */ > > > + if (GRAPHICS_VER(eb->i915) < 12 || IS_TIGERLAKE(eb->i915)) > > > + return true; > > > + > > > + if (INTEL_INFO(eb->i915)->require_force_probe && > > > + (IS_ROCKETLAKE(eb->i915) > > > > This ship has sailed... RKL is not protected by this flag any longer. > > Should this be on the TGL side now? > > +Lucas > > I think no, RKL has relocations disabled so we cannot put it to TGL side. > So if RKL is already released then putting it under require_force_probe > flag is wrong and only I can do is to remove it from that condition. > There's no option to unblock RKL on IGT CI until we rewrite all the tests. > We have to rely then on ADL* with require_force_probe flag to check how > ADL will work with relocations. So... I'm confused now. I'm missing the point of this patch then. I thought the reason was to protect from any user space to attempt to use the relocation, unless using the force_probe temporarily only for these platforms. But if I'm understanding correctly now it is only to silence CI?! Is that the case? Is the CI noise so bad? > > > > > > || IS_ALDERLAKE_S(eb->i915) || > > > + IS_ALDERLAKE_P(eb->i915))) > > > > How to ensure that we will easily catch this when removing the > > flag? > > > > I mean, should we have a GEM_BUG or drm_err message when these > > platforms in this list has not the required_force_probe? > > I don't think we need GEM_BUG()/drm_err() - when IGT tests will support > both - reloc + no-reloc - then condition will be limited to: > > if (GRAPHICS_VER(eb->i915) < 12 || IS_TIGERLAKE(eb->i915)) > return true; > > return false; > > so require_force_probe condition will be deleted and we won't need it > anymore (IGTs will be ready). yes... but then, when we remove the flag we will forget to come here and remove this check. Oh, and I just thought that we might need drm_error when the protection doesn't exist for the platform, but also a drm_info to the user to tell this is a temporary accepted behavior, but that will be removed later The concern is if any other userspace was using the flag and suddently move to a version without the flag, it would be considered a regression... > > -- > Zbigniew > > > > > > + return true; > > > + > > > + return false; > > > +} > > > + > > > static int > > > eb_validate_vma(struct i915_execbuffer *eb, > > > struct drm_i915_gem_exec_object2 *entry, > > > struct i915_vma *vma) > > > { > > > - /* Relocations are disallowed for all platforms after TGL-LP. This > > > - * also covers all platforms with local memory. > > > - */
Re: [PATCH 4/7] dma-buf: add dma_fence_chain_garbage_collect
On Thu, Jun 10, 2021 at 11:17:57AM +0200, Christian König wrote: > Add some rather sophisticated lockless garbage collection > for dma_fence_chain objects. > > For this keep all initialized dma_fence_chain nodes an a > queue and trigger garbage collection before a new one is > allocated. > > Signed-off-by: Christian König Uh hand-rolled lockless list, I'm not a fan. But the real question here is why? This is a global list, so it's going to look great on your desktop, but gpus are for servers now and those are NUMA. So just from that pov doing garbage-collection individually still feels like a much better idea. So what's the problem your trying to solve here? -Daniel > --- > drivers/dma-buf/dma-fence-chain.c | 160 +- > include/linux/dma-fence-chain.h | 5 + > 2 files changed, 142 insertions(+), 23 deletions(-) > > diff --git a/drivers/dma-buf/dma-fence-chain.c > b/drivers/dma-buf/dma-fence-chain.c > index 1b4cb3e5cec9..c2f0b69eabb7 100644 > --- a/drivers/dma-buf/dma-fence-chain.c > +++ b/drivers/dma-buf/dma-fence-chain.c > @@ -9,8 +9,53 @@ > > #include > > +static struct dma_fence_chain __rcu *fifo_front; > +static struct dma_fence_chain __rcu **fifo_back = &fifo_front; > + > static bool dma_fence_chain_enable_signaling(struct dma_fence *fence); > > +/** > + * dma_fence_chain_enqueue - enqeue a chain node for garbage collection > + * @chain: the chain node to enqueue > + * > + * Add the chain node to the end of the gc fifo. > + */ > +static void dma_fence_chain_enqueue(struct dma_fence_chain *chain) > +{ > + struct dma_fence_chain __rcu **tmp; > + > + RCU_INIT_POINTER(chain->next, NULL); > + tmp = xchg((struct dma_fence_chain __force ***)&fifo_back, > +&chain->next); > + > + /* This is intentionally unordered since we only need the fifo for gc */ > + rcu_assign_pointer(*tmp, chain); > +} > + > +/** > + * dma_fence_chain_dequeue - deqeueue a chain node for garbage collection > + * > + * Remove the first chain node from the gc fifo while making sure that always > + * keep at least one node on the fifo for lockless fifo implementation. > + * Returns the dequeued chain node or NULL. > + */ > +static struct dma_fence_chain *dma_fence_chain_dequeue(void) > +{ > + struct dma_fence_chain *chain, *tmp; > + > + rcu_read_lock(); > + chain = rcu_dereference(fifo_front); > + /* Never dequeue the last chain node for lockless fifo */ > + if (unlikely(!chain || !rcu_access_pointer(chain->next))) { > + rcu_read_unlock(); > + return NULL; > + } > + tmp = cmpxchg((struct dma_fence_chain __force **)&fifo_front, > + chain, rcu_access_pointer(chain->next)); > + rcu_read_unlock(); > + return tmp == chain ? chain : NULL; > +} > + > /** > * dma_fence_chain_get_prev - use RCU to get a reference to the previous > fence > * @chain: chain node to get the previous node from > @@ -28,6 +73,43 @@ static struct dma_fence *dma_fence_chain_get_prev(struct > dma_fence_chain *chain) > return prev; > } > > +/** > + * dma_fence_chain_try_replace - try to replace the prev node > + * @chain: Chain node we try to replace prev. > + * @prev: the old prev node > + * > + * Try to replace the previous chain node when it or its containing fence is > + * signaled. Returns true if we tried, false if we need to wait. > + */ > +static bool dma_fence_chain_try_replace(struct dma_fence_chain *chain, > + struct dma_fence *prev) > +{ > + struct dma_fence *replacement, *tmp; > + struct dma_fence_chain *prev_chain; > + > + prev_chain = to_dma_fence_chain(prev); > + if (prev_chain) { > + if (!dma_fence_is_signaled(prev_chain->fence)) > + return false; > + > + replacement = dma_fence_chain_get_prev(prev_chain); > + } else { > + if (!dma_fence_is_signaled(prev)) > + return false; > + > + replacement = NULL; > + } > + > + tmp = cmpxchg((struct dma_fence __force **)&chain->prev, prev, > + replacement); > + if (tmp == prev) > + dma_fence_put(tmp); > + else > + dma_fence_put(replacement); > + > + return true; > +} > + > /** > * dma_fence_chain_walk - chain walking function > * @fence: current chain node > @@ -38,8 +120,8 @@ static struct dma_fence *dma_fence_chain_get_prev(struct > dma_fence_chain *chain) > */ > struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence) > { > - struct dma_fence_chain *chain, *prev_chain; > - struct dma_fence *prev, *replacement, *tmp; > + struct dma_fence_chain *chain; > + struct dma_fence *prev; > > chain = to_dma_fence_chain(fence); > if (!chain) { > @@ -48,26 +130,8 @@ struct dma_fence *dma_fence_chain_walk(struct dma_fence > *fence) > } > > while ((prev = dma_fence_chain_get_prev(chain))) { > -
Re: [PATCH v4 22/24] drm/msm/dsi: remove temp data from global pll structure
Hi, On Fri, 11 Jun 2021 at 10:07, John Stultz wrote: > > On Wed, Mar 31, 2021 at 3:58 AM Dmitry Baryshkov > wrote: > > > > The 7nm, 10nm and 14nm drivers would store interim data used during > > VCO/PLL rate setting in the global dsi_pll_Nnm structure. Move this data > > structures to the onstack storage. While we are at it, drop > > unused/static 'config' data, unused config fields, etc. > > > > Signed-off-by: Dmitry Baryshkov > > Reviewed-by: Abhinav Kumar > > Tested-by: Stephen Boyd # on sc7180 lazor > > Hey Dmitry, > Just wanted to give you a heads up. Peter Collingbourne reported > today that his db845c wasn't booting to display for him on his 4k > monitor. It works fine on a 1080p screen, and while 4k isn't supported > (yet?), normally the board should fall back to 1080p when connected > to a 4k monitor. I was able to reproduce this myself and I see the > errors below[1]. It looks like I made a mistake testing these patches with the splash screen disabled. Stephen Boyd has proposed a fix few days ago (will be included into the 5.13). Could you check that it fixes the problem for you? https://lore.kernel.org/linux-arm-msm/20210608195519.125561-1-swb...@chromium.org/ > > I dug back and found that things were working ok on v5.12 w/ the > recently merged commit d1a97648ae028 ("drm/bridge: lt9611: Fix > handling of 4k panels"), and started digging around. > > Seeing a bunch of changes to the > drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c file, I tried reverting a > chunk of the changes since 5.12 to that, and that got it working > again. I've narrowed it down to this change - > 001d8dc33875 ("drm/msm/dsi: remove temp data from global pll > structure") upstream (also reverting following 6e2ad9c3bfca and > 36c5dde5fdf0 first - but its reverting this change that actually makes > it work again). > > I've not managed to really look into the change to see what might be > going wrong yet (its late and I'm about to crash), but I wanted to > give you a heads up. If you have any ideas for me to try I'm happy to > give them a go. > > thanks > -john > > [1]: > [ 19.846857] msm_dsi_phy ae94400.dsi-phy: > [drm:dsi_pll_10nm_vco_prepare] *ERROR* DSI PLL(0) lock failed, > status=0x > [ 19.857925] msm_dsi_phy ae94400.dsi-phy: > [drm:dsi_pll_10nm_vco_prepare] *ERROR* PLL(0) lock failed > [ 19.866978] dsi_link_clk_enable_6g: Failed to enable dsi byte clk > [ 19.873124] msm_dsi_host_power_on: failed to enable link clocks. ret=-110 > [ 19.879987] dsi_mgr_bridge_pre_enable: power on host 0 failed, -110 > [ 19.886309] Turning OFF PHY while PLL is on > [ 20.415019] lt9611 10-003b: video check: hactive_a=0, hactive_b=0, > vactive=0, v_total=0, h_total_sysclk=0 > [ 20.481062] [drm:dpu_encoder_phys_vid_wait_for_commit_done:528] > [dpu error]vblank timeout > [ 20.489306] [drm:dpu_kms_wait_for_commit_done:453] [dpu error]wait > for commit done returned -110 > [ 20.513031] [drm:dpu_encoder_frame_done_timeout:2161] [dpu > error]enc31 frame done timeout > [ 20.553059] [drm:dpu_encoder_phys_vid_wait_for_commit_done:528] > [dpu error]vblank timeout > [ 20.561300] [drm:dpu_kms_wait_for_commit_done:453] [dpu error]wait > for commit done returned -110 > [ 20.625054] [drm:dpu_encoder_phys_vid_wait_for_commit_done:528] > [dpu error]vblank timeout > [ 20.633299] [drm:dpu_kms_wait_for_commit_done:453] [dpu error]wait > for commit done returned -110 > [ 20.657033] [drm:dpu_encoder_frame_done_timeout:2161] [dpu > error]enc31 frame done timeout > [ 20.697065] [drm:dpu_encoder_phys_vid_wait_for_commit_done:528] > [dpu error]vblank timeout > [ 20.705316] [drm:dpu_kms_wait_for_commit_done:453] [dpu error]wait > for commit done returned -110 > [ 20.769066] [drm:dpu_encoder_phys_vid_wait_for_commit_done:528] > [dpu error]vblank timeout > [ 20.777330] [drm:dpu_kms_wait_for_commit_done:453] [dpu error]wait > for commit done returned -110 > [ 20.801035] [drm:dpu_encoder_frame_done_timeout:2161] [dpu > error]enc31 frame done timeout > [ 20.845049] [drm:dpu_encoder_phys_vid_wait_for_commit_done:528] > [dpu error]vblank timeout > ... -- With best wishes Dmitry
Re: [PATCH 04/11] drm/ingenic: Move no_vblank to private state
On Thu, Jun 10, 2021 at 04:09:19PM +0100, Paul Cercueil wrote: > Hi Daniel, > > Le mar., juin 1 2021 at 17:48:12 +0200, Daniel Vetter a > écrit : > > On Fri, May 28, 2021 at 12:20:58AM +0100, Paul Cercueil wrote: > > > This information is carried from the ".atomic_check" to the > > > ".atomic_commit_tail"; as such it is state-specific, and should be > > > moved > > > to the private state structure. > > > > > > Signed-off-by: Paul Cercueil > > > > Not sure this applies to your hw, but drm_crtc_state.no_vblank exists. > > Might want to move to that instead of rolling your own. Or explain why > > you > > need your own here in your own private state. It does look quite a bit > > like you're just rolling your own version of this support that helpers > > gained meanwhile. > > If I use drm_crtc_state->no_vblank, then I need a custom > .atomic_commit_tail() that only calls drm_atomic_helper_wait_for_vblanks() > when !no_vblank. That works, but I don't understand why > drm_atomic_helper_commit_tail() doesn't do that by default, and makes me > think I'm using it wrong. So the recommendation is to have your own commit_tail and use drm_atomic_helper_wait_for_flip_done(). But also if wait_for_vblanks dies on you, there's a driver bug: If vblanks arent available, then the drm_crtc_vblank_get should fail. If that's not the case then I guess some bigger issues to be fixed because userspace might also do a vblank wait (for timing the next frame), so that really needs to work correctly. That's kinda why I put that wait_for_vblank in there by default, it forces drivers to be correct. If you're wondering how that's done: This is why the driver ->enable_vblank callback can return an error code. So maybe the real fix here is in there, and everything else can stay as-is? Another thing is that if you call drm_crtc_vblank_on/off correctly, this should also work out correctly - attempted vblank waits outside of when the vblank is running should fail. Maybe something fell off here in this area because it's tricky, but the infrastructure should be here already. -Daniel > > Cheers, > -Paul > > > -Daniel > > > > > > > --- > > > drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 41 > > > --- > > > 1 file changed, 37 insertions(+), 4 deletions(-) > > > > > > diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c > > > b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c > > > index e81084eb3b0e..639994329c60 100644 > > > --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c > > > +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c > > > @@ -66,6 +66,8 @@ struct jz_soc_info { > > > > > > struct ingenic_drm_private_state { > > > struct drm_private_state base; > > > + > > > +bool no_vblank; > > > }; > > > > > > struct ingenic_drm { > > > @@ -87,7 +89,6 @@ struct ingenic_drm { > > > dma_addr_t dma_hwdescs_phys; > > > > > > bool panel_is_sharp; > > > -bool no_vblank; > > > > > > /* > > >* clk_mutex is used to synchronize the pixel clock rate update > > > with > > > @@ -113,6 +114,30 @@ to_ingenic_drm_priv_state(struct > > > drm_private_state *state) > > > return container_of(state, struct ingenic_drm_private_state, > > > base); > > > } > > > > > > +static struct ingenic_drm_private_state * > > > +ingenic_drm_get_priv_state(struct ingenic_drm *priv, struct > > > drm_atomic_state *state) > > > +{ > > > +struct drm_private_state *priv_state; > > > + > > > +priv_state = drm_atomic_get_private_obj_state(state, > > > &priv->private_obj); > > > +if (IS_ERR(priv_state)) > > > +return ERR_CAST(priv_state); > > > + > > > +return to_ingenic_drm_priv_state(priv_state); > > > +} > > > + > > > +static struct ingenic_drm_private_state * > > > +ingenic_drm_get_new_priv_state(struct ingenic_drm *priv, struct > > > drm_atomic_state *state) > > > +{ > > > +struct drm_private_state *priv_state; > > > + > > > +priv_state = drm_atomic_get_new_private_obj_state(state, > > > &priv->private_obj); > > > +if (!priv_state) > > > +return NULL; > > > + > > > +return to_ingenic_drm_priv_state(priv_state); > > > +} > > > + > > > static bool ingenic_drm_writeable_reg(struct device *dev, unsigned > > > int reg) > > > { > > > switch (reg) { > > > @@ -268,6 +293,7 @@ static int ingenic_drm_crtc_atomic_check(struct > > > drm_crtc *crtc, > > > > > > crtc); > > > struct ingenic_drm *priv = drm_crtc_get_priv(crtc); > > > struct drm_plane_state *f1_state, *f0_state, *ipu_state = NULL; > > > +struct ingenic_drm_private_state *priv_state; > > > > > > if (crtc_state->gamma_lut && > > > drm_color_lut_size(crtc_state->gamma_lut) != > > > ARRAY_SIZE(priv->dma_hwdescs->palette)) { > > > @@ -299,9 +325,13 @@ s
Re: [PATCH 6/7] drm/amdgpu: unwrap fence chains in the explicit sync fence
On Thu, Jun 10, 2021 at 11:17:59AM +0200, Christian König wrote: > Unwrap a the explicit fence if it is a dma_fence_chain and > sync to the first fence not matching the owner rules. > > Signed-off-by: Christian König > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 118 +-- > 1 file changed, 68 insertions(+), 50 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c > index 1b2ceccaf5b0..862eb3c1c4c5 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c > @@ -28,6 +28,8 @@ > *Christian König > */ > > +#include > + > #include "amdgpu.h" > #include "amdgpu_trace.h" > #include "amdgpu_amdkfd.h" > @@ -186,6 +188,55 @@ int amdgpu_sync_vm_fence(struct amdgpu_sync *sync, > struct dma_fence *fence) > return amdgpu_sync_fence(sync, fence); > } > > +/* Determine based on the owner and mode if we should sync to a fence or not > */ > +static bool amdgpu_sync_test_fence(struct amdgpu_device *adev, > +enum amdgpu_sync_mode mode, > +void *owner, struct dma_fence *f) > +{ > + void *fence_owner = amdgpu_sync_get_owner(f); > + > + /* Always sync to moves, no matter what */ > + if (fence_owner == AMDGPU_FENCE_OWNER_UNDEFINED) > + return true; > + > + /* We only want to trigger KFD eviction fences on > + * evict or move jobs. Skip KFD fences otherwise. > + */ > + if (fence_owner == AMDGPU_FENCE_OWNER_KFD && > + owner != AMDGPU_FENCE_OWNER_UNDEFINED) > + return false; > + > + /* Never sync to VM updates either. */ > + if (fence_owner == AMDGPU_FENCE_OWNER_VM && > + owner != AMDGPU_FENCE_OWNER_UNDEFINED) > + return false; > + > + /* Ignore fences depending on the sync mode */ > + switch (mode) { > + case AMDGPU_SYNC_ALWAYS: > + return true; > + > + case AMDGPU_SYNC_NE_OWNER: > + if (amdgpu_sync_same_dev(adev, f) && > + fence_owner == owner) > + return false; > + break; > + > + case AMDGPU_SYNC_EQ_OWNER: > + if (amdgpu_sync_same_dev(adev, f) && > + fence_owner != owner) > + return false; > + break; > + > + case AMDGPU_SYNC_EXPLICIT: > + return false; > + } > + > + WARN(debug_evictions && fence_owner == AMDGPU_FENCE_OWNER_KFD, > + "Adding eviction fence to sync obj"); > + return true; > +} > + > /** > * amdgpu_sync_resv - sync to a reservation object > * > @@ -211,67 +262,34 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, struct > amdgpu_sync *sync, > > /* always sync to the exclusive fence */ > f = dma_resv_excl_fence(resv); > - r = amdgpu_sync_fence(sync, f); > + dma_fence_chain_for_each(f, f) { Jason has some helper for deep-walking fence chains/arrays here I think. Might want to look into that, so that we have some consistency in how we pile up multiple exclusive fences. Anyway pretty much one of the versions I had in mind too, except I didn't type it up. Acked-by: Daniel Vetter > + struct dma_fence_chain *chain = to_dma_fence_chain(f); > + > + if (amdgpu_sync_test_fence(adev, mode, owner, chain ? > +chain->fence : f)) { > + r = amdgpu_sync_fence(sync, f); > + dma_fence_put(f); > + if (r) > + return r; > + break; > + } > + } > > flist = dma_resv_shared_list(resv); > - if (!flist || r) > - return r; > + if (!flist) > + return 0; > > for (i = 0; i < flist->shared_count; ++i) { > - void *fence_owner; > - > f = rcu_dereference_protected(flist->shared[i], > dma_resv_held(resv)); > > - fence_owner = amdgpu_sync_get_owner(f); > - > - /* Always sync to moves, no matter what */ > - if (fence_owner == AMDGPU_FENCE_OWNER_UNDEFINED) { > + if (amdgpu_sync_test_fence(adev, mode, owner, f)) { > r = amdgpu_sync_fence(sync, f); > if (r) > - break; > - } > - > - /* We only want to trigger KFD eviction fences on > - * evict or move jobs. Skip KFD fences otherwise. > - */ > - if (fence_owner == AMDGPU_FENCE_OWNER_KFD && > - owner != AMDGPU_FENCE_OWNER_UNDEFINED) > - continue; > - > - /* Never sync to VM updates either. */ > - if (fence_owner == AMDGPU_FENCE_OWNER_VM && > - owner != AMDGPU_FENCE_OWNER_UNDEFINED) > - continue; > - > -
[PATCH v7 0/4] Add MIPI rx DPI support
Hi all, this patch series implement MIPI rx DPI feature. Please help to review. This is the v7 version, rebase DT on the latest code, removed HDCP patch(I'll upload HDCP feature by a new patch). Any mistakes, please let me know, I'll fix it in the next series. Change history: v7: - Rebase DT on the latest branch 'drm-misc-next'. - Remove HDCP patch. v6: Fix kernel robot compile warning v5: Fix Rob Herring, Hsin-Yi, Robert Foss comments - Rebase code on the branch 'drm-misc-next', refer video-interfaces.yaml - Seprate HDCP function to a new patch - Fix driver not correctly get 'bus-type' 'data-lanes' - Add audio HDMI codec function support v4: Fix Rob Herring comment - Rebase code on the branch 'drm-misc-next' - Change 'analogix,hdcp-support' type to boolean v3: Fix Rob Herring, Dan Carpenter, Nicolas comment - Split the patch, fix not correct return data - Fix several coding format - Split DP tx swing register setting to two property - Add HDCP support vender flag - remove 'analogix,swing-setting' and 'analogix,mipi-dpi-in' property v2: Fix Rob Herring comment - Fix yamllint warnings/errors in analogix,anx7625.yaml - Fix kernel robot compile warning v1: initial MIPI rx DPI feature support Xin Ji (4): dt-bindings:drm/bridge:anx7625:add vendor define flags drm/bridge: anx7625: fix not correct return value drm/bridge: anx7625: add MIPI DPI input feature drm/bridge: anx7625: add HDMI audio function .../display/bridge/analogix,anx7625.yaml | 57 ++- drivers/gpu/drm/bridge/analogix/anx7625.c | 458 -- drivers/gpu/drm/bridge/analogix/anx7625.h | 23 +- 3 files changed, 484 insertions(+), 54 deletions(-) -- 2.25.1
[PATCH v7 1/4] dt-bindings:drm/bridge:anx7625:add vendor define flags
Add 'bus-type' and 'data-lanes' define for port0. Define DP tx lane0, lane1 swing register array define, and audio enable flag. Signed-off-by: Xin Ji --- .../display/bridge/analogix,anx7625.yaml | 57 ++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml index ab48ab2f4240..9e604d19a3d5 100644 --- a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml +++ b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml @@ -43,6 +43,26 @@ properties: vdd33-supply: description: Regulator that provides the supply 3.3V power. + analogix,lane0-swing: +$ref: /schemas/types.yaml#/definitions/uint32-array +minItems: 1 +maxItems: 20 +description: + an array of swing register setting for DP tx lane0 PHY, please don't + add this property, or contact vendor. + + analogix,lane1-swing: +$ref: /schemas/types.yaml#/definitions/uint32-array +minItems: 1 +maxItems: 20 +description: + an array of swing register setting for DP tx lane1 PHY, please don't + add this property, or contact vendor. + + analogix,audio-enable: +type: boolean +description: let the driver enable audio HDMI codec function or not. + ports: $ref: /schemas/graph.yaml#/properties/ports @@ -50,13 +70,43 @@ properties: port@0: $ref: /schemas/graph.yaml#/properties/port description: - Video port for MIPI DSI input. + MIPI DSI/DPI input. + +properties: + endpoint: +$ref: /schemas/media/video-interfaces.yaml# +type: object +additionalProperties: false + +properties: + remote-endpoint: true + bus-type: true + data-lanes: true + +required: + - remote-endpoint + +required: + - endpoint + port@1: $ref: /schemas/graph.yaml#/properties/port description: Video port for panel or connector. +properties: + endpoint: +$ref: /schemas/media/video-interfaces.yaml# +type: object +additionalProperties: false + +properties: + remote-endpoint: true + +required: + - remote-endpoint + required: - port@0 - port@1 @@ -87,6 +137,9 @@ examples: vdd10-supply = <&pp1000_mipibrdg>; vdd18-supply = <&pp1800_mipibrdg>; vdd33-supply = <&pp3300_mipibrdg>; +analogix,audio-enable; +analogix,lane0-swing = <0x14 0x54 0x64 0x74 0x29 0x7b 0x77 0x5b>; +analogix,lane1-swing = <0x14 0x54 0x64 0x74 0x29 0x7b 0x77 0x5b>; ports { #address-cells = <1>; @@ -96,6 +149,8 @@ examples: reg = <0>; anx7625_in: endpoint { remote-endpoint = <&mipi_dsi>; +bus-type = <5>; +data-lanes = <0 1 2 3>; }; }; -- 2.25.1
[PATCH v7 2/4] drm/bridge: anx7625: fix not correct return value
At some time, the original code may return non zero value, force return 0 if operation finished. Reviewed-by: Robert Foss Signed-off-by: Xin Ji --- drivers/gpu/drm/bridge/analogix/anx7625.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 7519b7a0f29d..048080e75016 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -191,10 +191,10 @@ static int wait_aux_op_finish(struct anx7625_data *ctx) AP_AUX_CTRL_STATUS); if (val < 0 || (val & 0x0F)) { DRM_DEV_ERROR(dev, "aux status %02x\n", val); - val = -EIO; + return -EIO; } - return val; + return 0; } static int anx7625_video_mute_control(struct anx7625_data *ctx, -- 2.25.1
[PATCH v7 3/4] drm/bridge: anx7625: add MIPI DPI input feature
Add MIPI rx DPI input feature support. Reviewed-by: Robert Foss Signed-off-by: Xin Ji --- drivers/gpu/drm/bridge/analogix/anx7625.c | 245 -- drivers/gpu/drm/bridge/analogix/anx7625.h | 18 +- 2 files changed, 203 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 048080e75016..fb2301a92704 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -152,18 +152,18 @@ static int anx7625_write_and(struct anx7625_data *ctx, return anx7625_reg_write(ctx, client, offset, (val & (mask))); } -static int anx7625_write_and_or(struct anx7625_data *ctx, - struct i2c_client *client, - u8 offset, u8 and_mask, u8 or_mask) +static int anx7625_config_bit_matrix(struct anx7625_data *ctx) { - int val; + int i, ret; - val = anx7625_reg_read(ctx, client, offset); - if (val < 0) - return val; + ret = anx7625_write_or(ctx, ctx->i2c.tx_p2_client, + AUDIO_CONTROL_REGISTER, 0x80); + for (i = 0; i < 13; i++) + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, +VIDEO_BIT_MATRIX_12 + i, +0x18 + i); - return anx7625_reg_write(ctx, client, -offset, (val & and_mask) | (or_mask)); + return ret; } static int anx7625_read_ctrl_status_p0(struct anx7625_data *ctx) @@ -221,38 +221,6 @@ static int anx7625_video_mute_control(struct anx7625_data *ctx, return ret; } -static int anx7625_config_audio_input(struct anx7625_data *ctx) -{ - struct device *dev = &ctx->client->dev; - int ret; - - /* Channel num */ - ret = anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, - AUDIO_CHANNEL_STATUS_6, I2S_CH_2 << 5); - - /* FS */ - ret |= anx7625_write_and_or(ctx, ctx->i2c.tx_p2_client, - AUDIO_CHANNEL_STATUS_4, - 0xf0, AUDIO_FS_48K); - /* Word length */ - ret |= anx7625_write_and_or(ctx, ctx->i2c.tx_p2_client, - AUDIO_CHANNEL_STATUS_5, - 0xf0, AUDIO_W_LEN_24_24MAX); - /* I2S */ - ret |= anx7625_write_or(ctx, ctx->i2c.tx_p2_client, - AUDIO_CHANNEL_STATUS_6, I2S_SLAVE_MODE); - ret |= anx7625_write_and(ctx, ctx->i2c.tx_p2_client, -AUDIO_CONTROL_REGISTER, ~TDM_TIMING_MODE); - /* Audio change flag */ - ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client, - AP_AV_STATUS, AP_AUDIO_CHG); - - if (ret < 0) - DRM_DEV_ERROR(dev, "fail to config audio.\n"); - - return ret; -} - /* Reduction of fraction a/b */ static void anx7625_reduction_of_a_fraction(unsigned long *a, unsigned long *b) { @@ -412,7 +380,7 @@ static int anx7625_dsi_video_timing_config(struct anx7625_data *ctx) ret |= anx7625_write_and(ctx, ctx->i2c.rx_p1_client, MIPI_LANE_CTRL_0, 0xfc); ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, - MIPI_LANE_CTRL_0, 3); + MIPI_LANE_CTRL_0, ctx->pdata.mipi_lanes - 1); /* Htotal */ htotal = ctx->dt.hactive.min + ctx->dt.hfront_porch.min + @@ -597,6 +565,76 @@ static int anx7625_dsi_config(struct anx7625_data *ctx) return ret; } +static int anx7625_api_dpi_config(struct anx7625_data *ctx) +{ + struct device *dev = &ctx->client->dev; + u16 freq = ctx->dt.pixelclock.min / 1000; + int ret; + + /* configure pixel clock */ + ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, + PIXEL_CLOCK_L, freq & 0xFF); + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, +PIXEL_CLOCK_H, (freq >> 8)); + + /* set DPI mode */ + /* set to DPI PLL module sel */ + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p1_client, +MIPI_DIGITAL_PLL_9, 0x20); + /* power down MIPI */ + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p1_client, +MIPI_LANE_CTRL_10, 0x08); + /* enable DPI mode */ + ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p1_client, +MIPI_DIGITAL_PLL_18, 0x1C); + /* set first edge */ + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, +VIDEO_CONTROL_0, 0x06); + if (ret < 0) + DRM_DEV_ERROR(dev, "IO error : dpi phy set failed.\n"); + + return ret; +} + +static int anx7625_dpi_config(struct anx7625_data *ctx) +{ + struct device *dev = &ctx->clien
[PATCH v7 4/4] drm/bridge: anx7625: add HDMI audio function
Add audio HDMI codec function support, enable it through device true flag "analogix,audio-enable". Reviewed-by: Robert Foss Signed-off-by: Xin Ji --- drivers/gpu/drm/bridge/analogix/anx7625.c | 227 ++ drivers/gpu/drm/bridge/analogix/anx7625.h | 5 + 2 files changed, 232 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index fb2301a92704..85ee1fb8b678 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -32,6 +32,8 @@ #include #include +#include + #include #include "anx7625.h" @@ -152,6 +154,20 @@ static int anx7625_write_and(struct anx7625_data *ctx, return anx7625_reg_write(ctx, client, offset, (val & (mask))); } +static int anx7625_write_and_or(struct anx7625_data *ctx, + struct i2c_client *client, + u8 offset, u8 and_mask, u8 or_mask) +{ + int val; + + val = anx7625_reg_read(ctx, client, offset); + if (val < 0) + return val; + + return anx7625_reg_write(ctx, client, +offset, (val & and_mask) | (or_mask)); +} + static int anx7625_config_bit_matrix(struct anx7625_data *ctx) { int i, ret; @@ -1324,6 +1340,9 @@ static int anx7625_parse_dt(struct device *dev, else DRM_DEV_DEBUG_DRIVER(dev, "found MIPI DSI host node.\n"); + if (of_property_read_bool(np, "analogix,audio-enable")) + pdata->audio_en = 1; + ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL); if (ret < 0) { if (ret == -ENODEV) @@ -1394,6 +1413,208 @@ static enum drm_connector_status anx7625_sink_detect(struct anx7625_data *ctx) connector_status_disconnected; } +static int anx7625_audio_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *fmt, + struct hdmi_codec_params *params) +{ + struct anx7625_data *ctx = dev_get_drvdata(dev); + int wl, ch, rate; + int ret = 0; + + if (fmt->fmt != HDMI_DSP_A) { + DRM_DEV_ERROR(dev, "only supports DSP_A\n"); + return -EINVAL; + } + + DRM_DEV_DEBUG_DRIVER(dev, "setting %d Hz, %d bit, %d channels\n", +params->sample_rate, params->sample_width, +params->cea.channels); + + ret |= anx7625_write_and_or(ctx, ctx->i2c.tx_p2_client, + AUDIO_CHANNEL_STATUS_6, + ~I2S_SLAVE_MODE, + TDM_SLAVE_MODE); + + /* Word length */ + switch (params->sample_width) { + case 16: + wl = AUDIO_W_LEN_16_20MAX; + break; + case 18: + wl = AUDIO_W_LEN_18_20MAX; + break; + case 20: + wl = AUDIO_W_LEN_20_20MAX; + break; + case 24: + wl = AUDIO_W_LEN_24_24MAX; + break; + default: + DRM_DEV_DEBUG_DRIVER(dev, "wordlength: %d bit not support", +params->sample_width); + return -EINVAL; + } + ret |= anx7625_write_and_or(ctx, ctx->i2c.tx_p2_client, + AUDIO_CHANNEL_STATUS_5, + 0xf0, wl); + + /* Channel num */ + switch (params->cea.channels) { + case 2: + ch = I2S_CH_2; + break; + case 4: + ch = TDM_CH_4; + break; + case 6: + ch = TDM_CH_6; + break; + case 8: + ch = TDM_CH_8; + break; + default: + DRM_DEV_DEBUG_DRIVER(dev, "channel number: %d not support", +params->cea.channels); + return -EINVAL; + } + ret |= anx7625_write_and_or(ctx, ctx->i2c.tx_p2_client, + AUDIO_CHANNEL_STATUS_6, 0x1f, ch << 5); + if (ch > I2S_CH_2) + ret |= anx7625_write_or(ctx, ctx->i2c.tx_p2_client, + AUDIO_CHANNEL_STATUS_6, AUDIO_LAYOUT); + else + ret |= anx7625_write_and(ctx, ctx->i2c.tx_p2_client, + AUDIO_CHANNEL_STATUS_6, ~AUDIO_LAYOUT); + + /* FS */ + switch (params->sample_rate) { + case 32000: + rate = AUDIO_FS_32K; + break; + case 44100: + rate = AUDIO_FS_441K; + break; + case 48000: + rate = AUDIO_FS_48K; + break; + case 88200: + rate = AUDIO_FS_882K; + break; + case 96000: + rate = AUDIO_FS_96K; + break; + case
Re: [PATCH 7/7] drm/amdgpu: rework dma_resv handling
On Thu, Jun 10, 2021 at 11:18:00AM +0200, Christian König wrote: > Drop the workaround and instead implement a better solution. > > Basically we are now chaining all submissions using a dma_fence_chain > container and adding them as exclusive fence to the dma_resv object. > > This way other drivers can still sync to the single exclusive fence > while amdgpu only sync to fences from different processes. > > Signed-off-by: Christian König > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 1 + > drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 54 + > drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 65 - > drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 +- > drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 +- > drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 1 - > 6 files changed, 47 insertions(+), 79 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h > b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h > index a130e766cbdb..c905a4cfc173 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h > @@ -34,6 +34,7 @@ struct amdgpu_fpriv; > struct amdgpu_bo_list_entry { > struct ttm_validate_buffer tv; > struct amdgpu_bo_va *bo_va; > + struct dma_fence_chain *chain; > uint32_tpriority; > struct page **user_pages; > booluser_invalidated; > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > index 325e82621467..f6f3029f958d 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > @@ -587,6 +587,20 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser > *p, > goto out; > } > > + amdgpu_bo_list_for_each_entry(e, p->bo_list) { > + struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); > + > + e->bo_va = amdgpu_vm_bo_find(vm, bo); > + > + if (bo->tbo.base.dma_buf && !amdgpu_bo_explicit_sync(bo)) { > + e->chain = dma_fence_chain_alloc(); > + if (!e->chain) { > + r = -ENOMEM; > + goto error_validate; > + } > + } > + } > + > amdgpu_cs_get_threshold_for_moves(p->adev, &p->bytes_moved_threshold, > &p->bytes_moved_vis_threshold); > p->bytes_moved = 0; > @@ -614,15 +628,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser > *p, > gws = p->bo_list->gws_obj; > oa = p->bo_list->oa_obj; > > - amdgpu_bo_list_for_each_entry(e, p->bo_list) { > - struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); > - > - /* Make sure we use the exclusive slot for shared BOs */ > - if (bo->prime_shared_count) > - e->tv.num_shared = 0; > - e->bo_va = amdgpu_vm_bo_find(vm, bo); > - } > - > if (gds) { > p->job->gds_base = amdgpu_bo_gpu_offset(gds) >> PAGE_SHIFT; > p->job->gds_size = amdgpu_bo_size(gds) >> PAGE_SHIFT; > @@ -644,8 +649,13 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser > *p, > } > > error_validate: > - if (r) > + if (r) { > + amdgpu_bo_list_for_each_entry(e, p->bo_list) { > + dma_fence_chain_free(e->chain); > + e->chain = NULL; > + } > ttm_eu_backoff_reservation(&p->ticket, &p->validated); > + } > out: > return r; > } > @@ -685,9 +695,17 @@ static void amdgpu_cs_parser_fini(struct > amdgpu_cs_parser *parser, int error, > { > unsigned i; > > - if (error && backoff) > + if (error && backoff) { > + struct amdgpu_bo_list_entry *e; > + > + amdgpu_bo_list_for_each_entry(e, parser->bo_list) { > + dma_fence_chain_free(e->chain); > + e->chain = NULL; > + } > + > ttm_eu_backoff_reservation(&parser->ticket, > &parser->validated); > + } > > for (i = 0; i < parser->num_post_deps; i++) { > drm_syncobj_put(parser->post_deps[i].syncobj); > @@ -1260,6 +1278,20 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, > > amdgpu_vm_move_to_lru_tail(p->adev, &fpriv->vm); > > + amdgpu_bo_list_for_each_entry(e, p->bo_list) { > + struct dma_resv *resv = e->tv.bo->base.resv; > + struct dma_fence_chain *chain = e->chain; > + > + if (!chain) > + continue; > + > + dma_fence_chain_init(chain, dma_resv_excl_fence(resv), > + dma_fence_get(p->fence), 1); > + > + rcu_assign_pointer(resv->fence_excl, &chain->base); So for safety since this is now
[PULL] topic/i915-ttm
Pull request for drm-misc-next and drm-intel-gt-next. topic/i915-ttm-2021-06-11: drm-misc and drm-intel pull request for topic/i915-ttm: - Convert i915 lmem handling to ttm. - Add a patch to temporarily add a driver_private member to vma_node. - Use this to allow mixed object mmap handling for i915. The following changes since commit 1bd8a7dc28c1c410f1ceefae1f2a97c06d1a67c2: Merge tag 'exynos-drm-next-for-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next (2021-06-11 14:19:12 +1000) are available in the Git repository at: git://anongit.freedesktop.org/drm/drm-misc tags/topic/i915-ttm-2021-06-11 for you to fetch changes up to cf3e3e86d77970211e0983130e896ae242601003: drm/i915: Use ttm mmap handling for ttm bo's. (2021-06-11 10:53:25 +0200) drm-misc and drm-intel pull request for topic/i915-ttm: - Convert i915 lmem handling to ttm. - Add a patch to temporarily add a driver_private member to vma_node. - Use this to allow mixed object mmap handling for i915. Maarten Lankhorst (2): drm/vma: Add a driver_private member to vma_node. drm/i915: Use ttm mmap handling for ttm bo's. Thomas Hellström (2): drm/i915/ttm: Introduce a TTM i915 gem object backend drm/i915/lmem: Verify checks for lmem residency drivers/gpu/drm/drm_gem.c | 9 - drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_create.c | 9 +- drivers/gpu/drm/i915/gem/i915_gem_lmem.c | 126 ++-- drivers/gpu/drm/i915/gem/i915_gem_lmem.h | 5 - drivers/gpu/drm/i915/gem/i915_gem_mman.c | 83 ++- drivers/gpu/drm/i915/gem/i915_gem_object.c | 143 +++-- drivers/gpu/drm/i915/gem/i915_gem_object.h | 19 +- drivers/gpu/drm/i915/gem/i915_gem_object_types.h | 30 +- drivers/gpu/drm/i915/gem/i915_gem_pages.c | 3 +- drivers/gpu/drm/i915/gem/i915_gem_region.c | 6 +- drivers/gpu/drm/i915/gem/i915_gem_ttm.c| 647 + drivers/gpu/drm/i915/gem/i915_gem_ttm.h| 48 ++ drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c | 90 +-- drivers/gpu/drm/i915/gt/intel_region_lmem.c| 3 +- drivers/gpu/drm/i915/i915_gem.c| 5 +- drivers/gpu/drm/i915/intel_memory_region.c | 1 - drivers/gpu/drm/i915/intel_memory_region.h | 1 - drivers/gpu/drm/i915/intel_region_ttm.c| 8 +- drivers/gpu/drm/i915/intel_region_ttm.h| 11 +- drivers/gpu/drm/i915/selftests/igt_mmap.c | 25 +- drivers/gpu/drm/i915/selftests/igt_mmap.h | 12 +- include/drm/drm_vma_manager.h | 2 +- 24 files changed, 1039 insertions(+), 250 deletions(-) create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h
Re: [Intel-gfx] [PATCH 0/5] dma-fence, i915: Stop allowing SLAB_TYPESAFE_BY_RCU for dma_fence
On Fri, Jun 11, 2021 at 09:42:07AM +0200, Christian König wrote: > Am 11.06.21 um 09:20 schrieb Daniel Vetter: > > On Fri, Jun 11, 2021 at 8:55 AM Christian König > > wrote: > > > Am 10.06.21 um 22:42 schrieb Daniel Vetter: > > > > On Thu, Jun 10, 2021 at 10:10 PM Jason Ekstrand > > > > wrote: > > > > > On Thu, Jun 10, 2021 at 8:35 AM Jason Ekstrand > > > > > wrote: > > > > > > On Thu, Jun 10, 2021 at 6:30 AM Daniel Vetter > > > > > > wrote: > > > > > > > On Thu, Jun 10, 2021 at 11:39 AM Christian König > > > > > > > wrote: > > > > > > > > Am 10.06.21 um 11:29 schrieb Tvrtko Ursulin: > > > > > > > > > On 09/06/2021 22:29, Jason Ekstrand wrote: > > > > > > > > > > We've tried to keep it somewhat contained by doing most of > > > > > > > > > > the hard work > > > > > > > > > > to prevent access of recycled objects via > > > > > > > > > > dma_fence_get_rcu_safe(). > > > > > > > > > > However, a quick grep of kernel sources says that, of the > > > > > > > > > > 30 instances > > > > > > > > > > of dma_fence_get_rcu*, only 11 of them use > > > > > > > > > > dma_fence_get_rcu_safe(). > > > > > > > > > > It's likely there bear traps in DRM and related subsystems > > > > > > > > > > just waiting > > > > > > > > > > for someone to accidentally step in them. > > > > > > > > > ...because dma_fence_get_rcu_safe apears to be about whether > > > > > > > > > the > > > > > > > > > *pointer* to the fence itself is rcu protected, not about the > > > > > > > > > fence > > > > > > > > > object itself. > > > > > > > > Yes, exactly that. > > > > > > The fact that both of you think this either means that I've > > > > > > completely > > > > > > missed what's going on with RCUs here (possible but, in this case, I > > > > > > think unlikely) or RCUs on dma fences should scare us all. > > > > > Taking a step back for a second and ignoring SLAB_TYPESAFE_BY_RCU as > > > > > such, I'd like to ask a slightly different question: What are the > > > > > rules about what is allowed to be done under the RCU read lock and > > > > > what guarantees does a driver need to provide? > > > > > > > > > > I think so far that we've all agreed on the following: > > > > > > > > > >1. Freeing an unsignaled fence is ok as long as it doesn't have any > > > > > pending callbacks. (Callbacks should hold a reference anyway). > > > > > > > > > >2. The pointer race solved by dma_fence_get_rcu_safe is real and > > > > > requires the loop to sort out. > > > > > > > > > > But let's say I have a dma_fence pointer that I got from, say, calling > > > > > dma_resv_excl_fence() under rcu_read_lock(). What am I allowed to do > > > > > with it under the RCU lock? What assumptions can I make? Is this > > > > > code, for instance, ok? > > > > > > > > > > rcu_read_lock(); > > > > > fence = dma_resv_excl_fence(obj); > > > > > idle = !fence || test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags); > > > > > rcu_read_unlock(); > > > > > > > > > > This code very much looks correct under the following assumptions: > > > > > > > > > >1. A valid fence pointer stays alive under the RCU read lock > > > > >2. SIGNALED_BIT is set-once (it's never unset after being set). > > > > > > > > > > However, if it were, we wouldn't have dma_resv_test_singnaled(), now > > > > > would we? :-) > > > > > > > > > > The moment you introduce ANY dma_fence recycling that recycles a > > > > > dma_fence within a single RCU grace period, all your assumptions break > > > > > down. SLAB_TYPESAFE_BY_RCU is just one way that i915 does this. We > > > > > also have a little i915_request recycler to try and help with memory > > > > > pressure scenarios in certain critical sections that also doesn't > > > > > respect RCU grace periods. And, as mentioned multiple times, our > > > > > recycling leaks into every other driver because, thanks to i915's > > > > > choice, the above 4-line code snippet isn't valid ANYWHERE in the > > > > > kernel. > > > > > > > > > > So the question I'm raising isn't so much about the rules today. > > > > > Today, we live in the wild wild west where everything is YOLO. But > > > > > where do we want to go? Do we like this wild west world? So we want > > > > > more consistency under the RCU read lock? If so, what do we want the > > > > > rules to be? > > > > > > > > > > One option would be to accept the wild-west world we live in and say > > > > > "The RCU read lock gains you nothing. If you want to touch the guts > > > > > of a dma_fence, take a reference". But, at that point, we're eating > > > > > two atomics for every time someone wants to look at a dma_fence. Do > > > > > we want that? > > > > > > > > > > Alternatively, and this what I think Daniel and I were trying to > > > > > propose here, is that we place some constraints on dma_fence > > > > > recycling. Specifically that, under the RCU read lock, the fence > > > > > doesn't suddenly become a new fence. All of the immutability and > > > > > once-mutability guarantees of
Re: [PATCH] drm: set DRM_RENDER_ALLOW flag on DRM_IOCTL_MODE_CREATE/DESTROY_DUMB ioctls
On Thu, Jun 10, 2021 at 02:36:59PM -0700, Dongwon Kim wrote: > Render clients should be able to create/destroy dumb object to import > and use it as render buffer in case the default DRM device is different > from the render device (i.e. kmsro). > > Signed-off-by: Dongwon Kim Uh no. Well I know everyone just hacks around this, but the idea behind dumb buffer objects is that they're for kms scanout only. Furthermore on many drivers they allocate a limited resource like CMA memory. Handing that out like candy isn't a great idea. And it's exactly those drivers that kmsro currently is used for where the display driver needs special memory. -Daniel > --- > drivers/gpu/drm/drm_ioctl.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c > index 98ae00661656..f2f72e132741 100644 > --- a/drivers/gpu/drm/drm_ioctl.c > +++ b/drivers/gpu/drm/drm_ioctl.c > @@ -685,9 +685,9 @@ static const struct drm_ioctl_desc drm_ioctls[] = { > DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, 0), > DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, > DRM_MASTER), > DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, > DRM_MASTER), > - DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, > 0), > + DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, > DRM_RENDER_ALLOW), > DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, 0), > - DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, > 0), > + DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, > DRM_RENDER_ALLOW), > DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, > drm_mode_obj_get_properties_ioctl, 0), > DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, > drm_mode_obj_set_property_ioctl, DRM_MASTER), > DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, > DRM_MASTER), > -- > 2.20.1 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
[PATCH] drm/amd/display: Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A check
Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A check that was performed in the drm_mode_is_420_only() case, but not in the drm_mode_is_420_also() && force_yuv420_output case. Without further knowledge if YCbCr 4:2:0 is supported outside of HDMI, there is no reason to use RGB when the display reports drm_mode_is_420_only() even on a non HDMI connection. This patch also moves both checks in the same if-case. This eliminates an extra else-if-case. Signed-off-by: Werner Sembach --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 + 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 652cc1a0e450..dc18e6c2e698 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5163,10 +5163,7 @@ static void fill_stream_properties_from_drm_display_mode( timing_out->v_border_bottom = 0; /* TODO: un-hardcode */ if (drm_mode_is_420_only(info, mode_in) - && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) - timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; - else if (drm_mode_is_420_also(info, mode_in) - && aconnector->force_yuv420_output) + || (drm_mode_is_420_also(info, mode_in) && aconnector->force_yuv420_output)) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444) && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) -- 2.31.1
Re: [Intel-gfx] [PATCH 0/5] dma-fence, i915: Stop allowing SLAB_TYPESAFE_BY_RCU for dma_fence
Am 11.06.21 um 11:33 schrieb Daniel Vetter: On Fri, Jun 11, 2021 at 09:42:07AM +0200, Christian König wrote: Am 11.06.21 um 09:20 schrieb Daniel Vetter: On Fri, Jun 11, 2021 at 8:55 AM Christian König wrote: Am 10.06.21 um 22:42 schrieb Daniel Vetter: On Thu, Jun 10, 2021 at 10:10 PM Jason Ekstrand wrote: On Thu, Jun 10, 2021 at 8:35 AM Jason Ekstrand wrote: On Thu, Jun 10, 2021 at 6:30 AM Daniel Vetter wrote: On Thu, Jun 10, 2021 at 11:39 AM Christian König wrote: Am 10.06.21 um 11:29 schrieb Tvrtko Ursulin: On 09/06/2021 22:29, Jason Ekstrand wrote: We've tried to keep it somewhat contained by doing most of the hard work to prevent access of recycled objects via dma_fence_get_rcu_safe(). However, a quick grep of kernel sources says that, of the 30 instances of dma_fence_get_rcu*, only 11 of them use dma_fence_get_rcu_safe(). It's likely there bear traps in DRM and related subsystems just waiting for someone to accidentally step in them. ...because dma_fence_get_rcu_safe apears to be about whether the *pointer* to the fence itself is rcu protected, not about the fence object itself. Yes, exactly that. The fact that both of you think this either means that I've completely missed what's going on with RCUs here (possible but, in this case, I think unlikely) or RCUs on dma fences should scare us all. Taking a step back for a second and ignoring SLAB_TYPESAFE_BY_RCU as such, I'd like to ask a slightly different question: What are the rules about what is allowed to be done under the RCU read lock and what guarantees does a driver need to provide? I think so far that we've all agreed on the following: 1. Freeing an unsignaled fence is ok as long as it doesn't have any pending callbacks. (Callbacks should hold a reference anyway). 2. The pointer race solved by dma_fence_get_rcu_safe is real and requires the loop to sort out. But let's say I have a dma_fence pointer that I got from, say, calling dma_resv_excl_fence() under rcu_read_lock(). What am I allowed to do with it under the RCU lock? What assumptions can I make? Is this code, for instance, ok? rcu_read_lock(); fence = dma_resv_excl_fence(obj); idle = !fence || test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags); rcu_read_unlock(); This code very much looks correct under the following assumptions: 1. A valid fence pointer stays alive under the RCU read lock 2. SIGNALED_BIT is set-once (it's never unset after being set). However, if it were, we wouldn't have dma_resv_test_singnaled(), now would we? :-) The moment you introduce ANY dma_fence recycling that recycles a dma_fence within a single RCU grace period, all your assumptions break down. SLAB_TYPESAFE_BY_RCU is just one way that i915 does this. We also have a little i915_request recycler to try and help with memory pressure scenarios in certain critical sections that also doesn't respect RCU grace periods. And, as mentioned multiple times, our recycling leaks into every other driver because, thanks to i915's choice, the above 4-line code snippet isn't valid ANYWHERE in the kernel. So the question I'm raising isn't so much about the rules today. Today, we live in the wild wild west where everything is YOLO. But where do we want to go? Do we like this wild west world? So we want more consistency under the RCU read lock? If so, what do we want the rules to be? One option would be to accept the wild-west world we live in and say "The RCU read lock gains you nothing. If you want to touch the guts of a dma_fence, take a reference". But, at that point, we're eating two atomics for every time someone wants to look at a dma_fence. Do we want that? Alternatively, and this what I think Daniel and I were trying to propose here, is that we place some constraints on dma_fence recycling. Specifically that, under the RCU read lock, the fence doesn't suddenly become a new fence. All of the immutability and once-mutability guarantees of various bits of dma_fence hold as long as you have the RCU read lock. Yeah this is suboptimal. Too many potential bugs, not enough benefits. This entire __rcu business started so that there would be a lockless way to get at fences, or at least the exclusive one. That did not really pan out. I think we have a few options: - drop the idea of rcu/lockless dma-fence access outright. A quick sequence of grabbing the lock, acquiring the dma_fence and then dropping your lock again is probably plenty good. There's a lot of call_rcu and other stuff we could probably delete. I have no idea what the perf impact across all the drivers would be. The question is maybe not the perf impact, but rather if that is possible over all. IIRC we now have some cases in TTM where RCU is mandatory and we simply don't have any other choice than using it. Adding Thomas Hellstrom. Where is that stuff? If we end up with all the dma_resv locking complexity just for an oddball, then I think that would be rather big bummer. This is during buffer de
Re: [PATCH 3/7] dma-buf: add dma_fence_chain_alloc/free self tests
Am 11.06.21 um 09:58 schrieb Daniel Vetter: On Thu, Jun 10, 2021 at 11:17:56AM +0200, Christian König wrote: Exercise the newly added functions. Signed-off-by: Christian König I have honestly no idea what this checks. Spawning a few threads to validate kmalloc/kfree feels a bit silly. Now testing whether we correctly rcu-delay the freeing here would make some sense, but even that feels a bit silly. I guess if you want this explain with comments what it does and why? This was soley to figure out if the garbage collection is working properly and how much overhead it generates. No actual need to commit it. Christian. -Daniel --- drivers/dma-buf/st-dma-fence-chain.c | 48 1 file changed, 48 insertions(+) diff --git a/drivers/dma-buf/st-dma-fence-chain.c b/drivers/dma-buf/st-dma-fence-chain.c index 8ce1ea59d31b..855c129c6093 100644 --- a/drivers/dma-buf/st-dma-fence-chain.c +++ b/drivers/dma-buf/st-dma-fence-chain.c @@ -95,6 +95,53 @@ static int sanitycheck(void *arg) return err; } +static int __alloc_free(void *arg) +{ + atomic_t *counter = arg; + int i, j; + + for (i = 0; i < 1024; ++i) { + struct dma_fence_chain *chains[64]; + + for (j = 0; j < ARRAY_SIZE(chains); ++j) + chains[j] = dma_fence_chain_alloc(); + + for (j = 0; j < ARRAY_SIZE(chains); ++j) + dma_fence_chain_free(chains[j]); + + atomic_add(ARRAY_SIZE(chains), counter); + } + return 0; +} + +static int alloc_free(void *arg) +{ + struct task_struct *threads[8]; + atomic_t counter = ATOMIC_INIT(0); + int i, err = 0; + + for (i = 0; i < ARRAY_SIZE(threads); i++) { + threads[i] = kthread_run(__alloc_free, &counter, "dmabuf/%d", +i); + if (IS_ERR(threads[i])) { + err = PTR_ERR(threads[i]); + break; + } + } + + while (i--) { + int ret; + + ret = kthread_stop(threads[i]); + if (ret && !err) + err = ret; + } + + pr_info("Completed %u cycles\n", atomic_read(&counter)); + + return err; +} + struct fence_chains { unsigned int chain_length; struct dma_fence **fences; @@ -677,6 +724,7 @@ int dma_fence_chain(void) { static const struct subtest tests[] = { SUBTEST(sanitycheck), + SUBTEST(alloc_free), SUBTEST(find_seqno), SUBTEST(find_signaled), SUBTEST(find_out_of_order), -- 2.25.1
Re: [PATCH 4/7] dma-buf: add dma_fence_chain_garbage_collect
Am 11.06.21 um 10:58 schrieb Daniel Vetter: On Thu, Jun 10, 2021 at 11:17:57AM +0200, Christian König wrote: Add some rather sophisticated lockless garbage collection for dma_fence_chain objects. For this keep all initialized dma_fence_chain nodes an a queue and trigger garbage collection before a new one is allocated. Signed-off-by: Christian König Uh hand-rolled lockless list, I'm not a fan. But the real question here is why? This is a global list, so it's going to look great on your desktop, but gpus are for servers now and those are NUMA. So just from that pov doing garbage-collection individually still feels like a much better idea. Yeah, I was pondering on that quite a bit as well. That why I added the multi threaded alloc/free test. So what's the problem your trying to solve here? I was not sure if the chain is garbage collected enough when used for the dma_resv exclusive object. But I think we could just drop this for now and just see how it goes. Christian. -Daniel --- drivers/dma-buf/dma-fence-chain.c | 160 +- include/linux/dma-fence-chain.h | 5 + 2 files changed, 142 insertions(+), 23 deletions(-) diff --git a/drivers/dma-buf/dma-fence-chain.c b/drivers/dma-buf/dma-fence-chain.c index 1b4cb3e5cec9..c2f0b69eabb7 100644 --- a/drivers/dma-buf/dma-fence-chain.c +++ b/drivers/dma-buf/dma-fence-chain.c @@ -9,8 +9,53 @@ #include +static struct dma_fence_chain __rcu *fifo_front; +static struct dma_fence_chain __rcu **fifo_back = &fifo_front; + static bool dma_fence_chain_enable_signaling(struct dma_fence *fence); +/** + * dma_fence_chain_enqueue - enqeue a chain node for garbage collection + * @chain: the chain node to enqueue + * + * Add the chain node to the end of the gc fifo. + */ +static void dma_fence_chain_enqueue(struct dma_fence_chain *chain) +{ + struct dma_fence_chain __rcu **tmp; + + RCU_INIT_POINTER(chain->next, NULL); + tmp = xchg((struct dma_fence_chain __force ***)&fifo_back, + &chain->next); + + /* This is intentionally unordered since we only need the fifo for gc */ + rcu_assign_pointer(*tmp, chain); +} + +/** + * dma_fence_chain_dequeue - deqeueue a chain node for garbage collection + * + * Remove the first chain node from the gc fifo while making sure that always + * keep at least one node on the fifo for lockless fifo implementation. + * Returns the dequeued chain node or NULL. + */ +static struct dma_fence_chain *dma_fence_chain_dequeue(void) +{ + struct dma_fence_chain *chain, *tmp; + + rcu_read_lock(); + chain = rcu_dereference(fifo_front); + /* Never dequeue the last chain node for lockless fifo */ + if (unlikely(!chain || !rcu_access_pointer(chain->next))) { + rcu_read_unlock(); + return NULL; + } + tmp = cmpxchg((struct dma_fence_chain __force **)&fifo_front, + chain, rcu_access_pointer(chain->next)); + rcu_read_unlock(); + return tmp == chain ? chain : NULL; +} + /** * dma_fence_chain_get_prev - use RCU to get a reference to the previous fence * @chain: chain node to get the previous node from @@ -28,6 +73,43 @@ static struct dma_fence *dma_fence_chain_get_prev(struct dma_fence_chain *chain) return prev; } +/** + * dma_fence_chain_try_replace - try to replace the prev node + * @chain: Chain node we try to replace prev. + * @prev: the old prev node + * + * Try to replace the previous chain node when it or its containing fence is + * signaled. Returns true if we tried, false if we need to wait. + */ +static bool dma_fence_chain_try_replace(struct dma_fence_chain *chain, + struct dma_fence *prev) +{ + struct dma_fence *replacement, *tmp; + struct dma_fence_chain *prev_chain; + + prev_chain = to_dma_fence_chain(prev); + if (prev_chain) { + if (!dma_fence_is_signaled(prev_chain->fence)) + return false; + + replacement = dma_fence_chain_get_prev(prev_chain); + } else { + if (!dma_fence_is_signaled(prev)) + return false; + + replacement = NULL; + } + + tmp = cmpxchg((struct dma_fence __force **)&chain->prev, prev, + replacement); + if (tmp == prev) + dma_fence_put(tmp); + else + dma_fence_put(replacement); + + return true; +} + /** * dma_fence_chain_walk - chain walking function * @fence: current chain node @@ -38,8 +120,8 @@ static struct dma_fence *dma_fence_chain_get_prev(struct dma_fence_chain *chain) */ struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence) { - struct dma_fence_chain *chain, *prev_chain; - struct dma_fence *prev, *replacement, *tmp; + struct dma_fence_chain *chain; + struct dma_fence *prev; chain = to_dma_fence_chain(f
Re: [PATCH 6/7] drm/amdgpu: unwrap fence chains in the explicit sync fence
Am 11.06.21 um 11:07 schrieb Daniel Vetter: On Thu, Jun 10, 2021 at 11:17:59AM +0200, Christian König wrote: Unwrap a the explicit fence if it is a dma_fence_chain and sync to the first fence not matching the owner rules. Signed-off-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 118 +-- 1 file changed, 68 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index 1b2ceccaf5b0..862eb3c1c4c5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -28,6 +28,8 @@ *Christian König */ +#include + #include "amdgpu.h" #include "amdgpu_trace.h" #include "amdgpu_amdkfd.h" @@ -186,6 +188,55 @@ int amdgpu_sync_vm_fence(struct amdgpu_sync *sync, struct dma_fence *fence) return amdgpu_sync_fence(sync, fence); } +/* Determine based on the owner and mode if we should sync to a fence or not */ +static bool amdgpu_sync_test_fence(struct amdgpu_device *adev, + enum amdgpu_sync_mode mode, + void *owner, struct dma_fence *f) +{ + void *fence_owner = amdgpu_sync_get_owner(f); + + /* Always sync to moves, no matter what */ + if (fence_owner == AMDGPU_FENCE_OWNER_UNDEFINED) + return true; + + /* We only want to trigger KFD eviction fences on +* evict or move jobs. Skip KFD fences otherwise. +*/ + if (fence_owner == AMDGPU_FENCE_OWNER_KFD && + owner != AMDGPU_FENCE_OWNER_UNDEFINED) + return false; + + /* Never sync to VM updates either. */ + if (fence_owner == AMDGPU_FENCE_OWNER_VM && + owner != AMDGPU_FENCE_OWNER_UNDEFINED) + return false; + + /* Ignore fences depending on the sync mode */ + switch (mode) { + case AMDGPU_SYNC_ALWAYS: + return true; + + case AMDGPU_SYNC_NE_OWNER: + if (amdgpu_sync_same_dev(adev, f) && + fence_owner == owner) + return false; + break; + + case AMDGPU_SYNC_EQ_OWNER: + if (amdgpu_sync_same_dev(adev, f) && + fence_owner != owner) + return false; + break; + + case AMDGPU_SYNC_EXPLICIT: + return false; + } + + WARN(debug_evictions && fence_owner == AMDGPU_FENCE_OWNER_KFD, +"Adding eviction fence to sync obj"); + return true; +} + /** * amdgpu_sync_resv - sync to a reservation object * @@ -211,67 +262,34 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, struct amdgpu_sync *sync, /* always sync to the exclusive fence */ f = dma_resv_excl_fence(resv); - r = amdgpu_sync_fence(sync, f); + dma_fence_chain_for_each(f, f) { Jason has some helper for deep-walking fence chains/arrays here I think. Might want to look into that, so that we have some consistency in how we pile up multiple exclusive fences. Well those helpers are not from Jason, but from me :) But no, for now the deep inspection is not really helpful here since grabbing a reference to a certain chain node is what that makes the handling easier and faster here. Thinking more about it that should also make it possible for the garbage collection to kick in properly. Anyway pretty much one of the versions I had in mind too, except I didn't type it up. Acked-by: Daniel Vetter Thanks, Christian. + struct dma_fence_chain *chain = to_dma_fence_chain(f); + + if (amdgpu_sync_test_fence(adev, mode, owner, chain ? + chain->fence : f)) { + r = amdgpu_sync_fence(sync, f); + dma_fence_put(f); + if (r) + return r; + break; + } + } flist = dma_resv_shared_list(resv); - if (!flist || r) - return r; + if (!flist) + return 0; for (i = 0; i < flist->shared_count; ++i) { - void *fence_owner; - f = rcu_dereference_protected(flist->shared[i], dma_resv_held(resv)); - fence_owner = amdgpu_sync_get_owner(f); - - /* Always sync to moves, no matter what */ - if (fence_owner == AMDGPU_FENCE_OWNER_UNDEFINED) { + if (amdgpu_sync_test_fence(adev, mode, owner, f)) { r = amdgpu_sync_fence(sync, f); if (r) - break; - } - - /* We only want to trigger KFD eviction fences on -* evict or move jobs. Skip KFD fences otherwise. -*/ - if (fence_owner == AMDGPU_FENCE_OWNER_KFD && -
Re: [PATCH] modified: gpu/drm/panfrost/panfrost_gpu.c
On 10/06/2021 14:06, Chunyou Tang wrote: > Hi Steven, Hi Chunyou, For some reason I'm not directly receiving your emails (only via the list) - can you double check your email configuration? >>> The GPU exception fault status register(0x3C),the low 8 bit is the >>> EXCEPTION_TYPE.We can see the description at P3-78 in spec. > > You can see the spec > . Thanks - please include that in the commit message - there are many TRMs (one for each GPU) so without the information about exactly which specification the page number is pretty useless. Sadly this documentation isn't public which would be even better but I don't think there are any public specs for this information. >> However this change is correct - panfrost_exception_name() should be >> taking only the lower 8 bits. Even better though would be to to report >> the full raw fault information as well as the high bits can contain >> useful information: >> >> dev_warn(pfdev->dev, "GPU Fault 0x%08x (%s) at 0x%016llx\n", >> fault_status, >> panfrost_exception_name(pfdev, fault_status & 0xFF), >> address); > > So I change it according to what you said? Yes, please send a v2. Thanks, Steve > ?? Thu, 10 Jun 2021 11:41:52 +0100 > Steven Price : > >> The subject should have the prefix "drm/panfrost" and should mention >> what the patch is changing (not just the filename). >> >> On 09/06/2021 07:38, ChunyouTang wrote: >>> From: tangchunyou >>> >>> The GPU exception fault status register(0x3C),the low 8 bit is the >>> EXCEPTION_TYPE.We can see the description at P3-78 in spec. >> >> Nit: When referring to a spec it's always good to mention the name - >> I'm not sure which specification you found this in. >> >>> >>> Signed-off-by: tangchunyou >>> --- >>> drivers/gpu/drm/panfrost/panfrost_gpu.c | 2 +- >>> 1 file changed, 1 insertion(+), 1 deletion(-) >>> >>> diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c >>> b/drivers/gpu/drm/panfrost/panfrost_gpu.c index >>> 2aae636f1cf5..1fffb6a0b24f 100644 --- >>> a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ >>> b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -33,7 +33,7 @@ static >>> irqreturn_t panfrost_gpu_irq_handler(int irq, void *data) address >>> |= gpu_read(pfdev, GPU_FAULT_ADDRESS_LO); >>> dev_warn(pfdev->dev, "GPU Fault 0x%08x (%s) at >>> 0x%016llx\n", >>> -fault_status & 0xFF, >>> panfrost_exception_name(pfdev, fault_status), >>> +fault_status & 0xFF, >>> panfrost_exception_name(pfdev, fault_status & 0xFF), >> >> However this change is correct - panfrost_exception_name() should be >> taking only the lower 8 bits. Even better though would be to to report >> the full raw fault information as well as the high bits can contain >> useful information: >> >> dev_warn(pfdev->dev, "GPU Fault 0x%08x (%s) at 0x%016llx\n", >> fault_status, >> panfrost_exception_name(pfdev, fault_status & 0xFF), >> address); >> >> Thanks, >> >> Steve >> >>> address); >>> >>> if (state & GPU_IRQ_MULTIPLE_FAULT) >>> > >
Re: [PATCH 7/7] drm/amdgpu: rework dma_resv handling
Am 11.06.21 um 11:17 schrieb Daniel Vetter: On Thu, Jun 10, 2021 at 11:18:00AM +0200, Christian König wrote: Drop the workaround and instead implement a better solution. Basically we are now chaining all submissions using a dma_fence_chain container and adding them as exclusive fence to the dma_resv object. This way other drivers can still sync to the single exclusive fence while amdgpu only sync to fences from different processes. Signed-off-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 54 + drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 65 - drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 +- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 1 - 6 files changed, 47 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h index a130e766cbdb..c905a4cfc173 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h @@ -34,6 +34,7 @@ struct amdgpu_fpriv; struct amdgpu_bo_list_entry { struct ttm_validate_buffer tv; struct amdgpu_bo_va *bo_va; + struct dma_fence_chain *chain; uint32_tpriority; struct page **user_pages; booluser_invalidated; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 325e82621467..f6f3029f958d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -587,6 +587,20 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, goto out; } + amdgpu_bo_list_for_each_entry(e, p->bo_list) { + struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); + + e->bo_va = amdgpu_vm_bo_find(vm, bo); + + if (bo->tbo.base.dma_buf && !amdgpu_bo_explicit_sync(bo)) { + e->chain = dma_fence_chain_alloc(); + if (!e->chain) { + r = -ENOMEM; + goto error_validate; + } + } + } + amdgpu_cs_get_threshold_for_moves(p->adev, &p->bytes_moved_threshold, &p->bytes_moved_vis_threshold); p->bytes_moved = 0; @@ -614,15 +628,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, gws = p->bo_list->gws_obj; oa = p->bo_list->oa_obj; - amdgpu_bo_list_for_each_entry(e, p->bo_list) { - struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); - - /* Make sure we use the exclusive slot for shared BOs */ - if (bo->prime_shared_count) - e->tv.num_shared = 0; - e->bo_va = amdgpu_vm_bo_find(vm, bo); - } - if (gds) { p->job->gds_base = amdgpu_bo_gpu_offset(gds) >> PAGE_SHIFT; p->job->gds_size = amdgpu_bo_size(gds) >> PAGE_SHIFT; @@ -644,8 +649,13 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, } error_validate: - if (r) + if (r) { + amdgpu_bo_list_for_each_entry(e, p->bo_list) { + dma_fence_chain_free(e->chain); + e->chain = NULL; + } ttm_eu_backoff_reservation(&p->ticket, &p->validated); + } out: return r; } @@ -685,9 +695,17 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, { unsigned i; - if (error && backoff) + if (error && backoff) { + struct amdgpu_bo_list_entry *e; + + amdgpu_bo_list_for_each_entry(e, parser->bo_list) { + dma_fence_chain_free(e->chain); + e->chain = NULL; + } + ttm_eu_backoff_reservation(&parser->ticket, &parser->validated); + } for (i = 0; i < parser->num_post_deps; i++) { drm_syncobj_put(parser->post_deps[i].syncobj); @@ -1260,6 +1278,20 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, amdgpu_vm_move_to_lru_tail(p->adev, &fpriv->vm); + amdgpu_bo_list_for_each_entry(e, p->bo_list) { + struct dma_resv *resv = e->tv.bo->base.resv; + struct dma_fence_chain *chain = e->chain; + + if (!chain) + continue; + + dma_fence_chain_init(chain, dma_resv_excl_fence(resv), +dma_fence_get(p->fence), 1); + + rcu_assign_pointer(resv->fence_excl, &chain->base); So for safety since this is now driver interface I was thinking off a helper which does this entire dance and _also_
Re: [PATCH -next] drm/panfrost: Fix missing clk_disable_unprepare() on error in panfrost_clk_init()
On 08/06/2021 15:38, Wei Yongjun wrote: > Fix the missing clk_disable_unprepare() before return > from panfrost_clk_init() in the error handling case. > > Fixes: b681af0bc1cc ("drm: panfrost: add optional bus_clock") > Reported-by: Hulk Robot > Signed-off-by: Wei Yongjun Reviewed-by: Steven Price I'll push this to drm-misc-next. Thanks, Steve > --- > drivers/gpu/drm/panfrost/panfrost_device.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c > b/drivers/gpu/drm/panfrost/panfrost_device.c > index 125ed973feaa..a2a09c51eed7 100644 > --- a/drivers/gpu/drm/panfrost/panfrost_device.c > +++ b/drivers/gpu/drm/panfrost/panfrost_device.c > @@ -54,7 +54,8 @@ static int panfrost_clk_init(struct panfrost_device *pfdev) > if (IS_ERR(pfdev->bus_clock)) { > dev_err(pfdev->dev, "get bus_clock failed %ld\n", > PTR_ERR(pfdev->bus_clock)); > - return PTR_ERR(pfdev->bus_clock); > + err = PTR_ERR(pfdev->bus_clock); > + goto disable_clock; > } > > if (pfdev->bus_clock) { >
Re: [PATCH] modified: gpu/drm/panfrost/panfrost_gpu.c
?? Fri, 11 Jun 2021 11:10:16 +0100 Steven Price : > On 10/06/2021 14:06, Chunyou Tang wrote: > > Hi Steven, > > Hi Chunyou, > > For some reason I'm not directly receiving your emails (only via the > list) - can you double check your email configuration? > > >>> The GPU exception fault status register(0x3C),the low 8 bit is the > >>> EXCEPTION_TYPE.We can see the description at P3-78 in spec. > > > > You can see the spec > > . > > Thanks - please include that in the commit message - there are many > TRMs (one for each GPU) so without the information about exactly which > specification the page number is pretty useless. Sadly this > documentation isn't public which would be even better but I don't > think there are any public specs for this information. > > >> However this change is correct - panfrost_exception_name() should > >> be taking only the lower 8 bits. Even better though would be to to > >> report the full raw fault information as well as the high bits can > >> contain useful information: > >> > >>dev_warn(pfdev->dev, "GPU Fault 0x%08x (%s) at > >> 0x%016llx\n", fault_status, > >> panfrost_exception_name(pfdev, fault_status & > >> 0xFF), address); > > > > So I change it according to what you said? > > Yes, please send a v2. > > Thanks, > > Steve > > > ?? Thu, 10 Jun 2021 11:41:52 +0100 > > Steven Price : > > > >> The subject should have the prefix "drm/panfrost" and should > >> mention what the patch is changing (not just the filename). > >> > >> On 09/06/2021 07:38, ChunyouTang wrote: ok > >>> From: tangchunyou > >>> > >>> The GPU exception fault status register(0x3C),the low 8 bit is the > >>> EXCEPTION_TYPE.We can see the description at P3-78 in spec. > >> > >> Nit: When referring to a spec it's always good to mention the name > >> - I'm not sure which specification you found this in. > >> > >>> > >>> Signed-off-by: tangchunyou > >>> --- > >>> drivers/gpu/drm/panfrost/panfrost_gpu.c | 2 +- > >>> 1 file changed, 1 insertion(+), 1 deletion(-) > >>> > >>> diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c > >>> b/drivers/gpu/drm/panfrost/panfrost_gpu.c index > >>> 2aae636f1cf5..1fffb6a0b24f 100644 --- > >>> a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ > >>> b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -33,7 +33,7 @@ static > >>> irqreturn_t panfrost_gpu_irq_handler(int irq, void *data) address > >>> |= gpu_read(pfdev, GPU_FAULT_ADDRESS_LO); > >>> dev_warn(pfdev->dev, "GPU Fault 0x%08x (%s) at > >>> 0x%016llx\n", > >>> - fault_status & 0xFF, > >>> panfrost_exception_name(pfdev, fault_status), > >>> + fault_status & 0xFF, > >>> panfrost_exception_name(pfdev, fault_status & 0xFF), > >> > >> However this change is correct - panfrost_exception_name() should > >> be taking only the lower 8 bits. Even better though would be to to > >> report the full raw fault information as well as the high bits can > >> contain useful information: > >> > >>dev_warn(pfdev->dev, "GPU Fault 0x%08x (%s) at > >> 0x%016llx\n", fault_status, > >> panfrost_exception_name(pfdev, fault_status & > >> 0xFF), address); > >> > >> Thanks, > >> > >> Steve > >> > >>>address); > >>> > >>> if (state & GPU_IRQ_MULTIPLE_FAULT) > >>> > > > >
Re: [PATCH] drm: set DRM_RENDER_ALLOW flag on DRM_IOCTL_MODE_CREATE/DESTROY_DUMB ioctls
On Fri, 11 Jun 2021 at 10:47, Daniel Vetter wrote: > > On Thu, Jun 10, 2021 at 02:36:59PM -0700, Dongwon Kim wrote: > > Render clients should be able to create/destroy dumb object to import > > and use it as render buffer in case the default DRM device is different > > from the render device (i.e. kmsro). > > > > Signed-off-by: Dongwon Kim > > Uh no. > > Well I know everyone just hacks around this, but the idea behind dumb > buffer objects is that they're for kms scanout only. Furthermore on many > drivers they allocate a limited resource like CMA memory. Handing that out > like candy isn't a great idea. > > And it's exactly those drivers that kmsro currently is used for where the > display driver needs special memory. Couldn't agree more. Perhaps we should add an inline comment and/or reference to a thread why? -Emil
Re: [PULL] topic/i915-ttm
Quoting Maarten Lankhorst (2021-06-11 12:27:15) > Pull request for drm-misc-next and drm-intel-gt-next. > > topic/i915-ttm-2021-06-11: > drm-misc and drm-intel pull request for topic/i915-ttm: > - Convert i915 lmem handling to ttm. > - Add a patch to temporarily add a driver_private member to vma_node. > - Use this to allow mixed object mmap handling for i915. > The following changes since commit 1bd8a7dc28c1c410f1ceefae1f2a97c06d1a67c2: > > Merge tag 'exynos-drm-next-for-v5.14' of > git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into > drm-next (2021-06-11 14:19:12 +1000) This base is not in drm-misc-next or drm-intel-gt-next, so effectively we would end up pulling 478 extra commits from drm-next as a result. And also causing all the warnings for those commits. I don't think we should do that? The common ancestor would be ccd1950c2f7e38ae45aeefb99a08b39407cd6c63 "Merge tag 'drm-intel-gt-next-2021-05-28' of git://anongit.freedesktop.org/drm/drm-intel into drm-next" Should we re-do the topic branch based on that? However the DIM docs[1] indeed do say: "For topic branches shared within the gpu/drm subsystem, base it on the latest drm-next branch." I think the docs don't take into account the current period where drm-next is being actively updated as we speak. Should we update the docs to use 'git merge-base' or something else? Regards, Joonas [1]: https://drm.pages.freedesktop.org/maintainer-tools/dim.html#cross-subsystem-topic-branches > > are available in the Git repository at: > > git://anongit.freedesktop.org/drm/drm-misc tags/topic/i915-ttm-2021-06-11 > > for you to fetch changes up to cf3e3e86d77970211e0983130e896ae242601003: > > drm/i915: Use ttm mmap handling for ttm bo's. (2021-06-11 10:53:25 +0200) > > > drm-misc and drm-intel pull request for topic/i915-ttm: > - Convert i915 lmem handling to ttm. > - Add a patch to temporarily add a driver_private member to vma_node. > - Use this to allow mixed object mmap handling for i915. > > > Maarten Lankhorst (2): > drm/vma: Add a driver_private member to vma_node. > drm/i915: Use ttm mmap handling for ttm bo's. > > Thomas Hellström (2): > drm/i915/ttm: Introduce a TTM i915 gem object backend > drm/i915/lmem: Verify checks for lmem residency > > drivers/gpu/drm/drm_gem.c | 9 - > drivers/gpu/drm/i915/Makefile | 1 + > drivers/gpu/drm/i915/display/intel_display.c | 2 +- > drivers/gpu/drm/i915/gem/i915_gem_create.c | 9 +- > drivers/gpu/drm/i915/gem/i915_gem_lmem.c | 126 ++-- > drivers/gpu/drm/i915/gem/i915_gem_lmem.h | 5 - > drivers/gpu/drm/i915/gem/i915_gem_mman.c | 83 ++- > drivers/gpu/drm/i915/gem/i915_gem_object.c | 143 +++-- > drivers/gpu/drm/i915/gem/i915_gem_object.h | 19 +- > drivers/gpu/drm/i915/gem/i915_gem_object_types.h | 30 +- > drivers/gpu/drm/i915/gem/i915_gem_pages.c | 3 +- > drivers/gpu/drm/i915/gem/i915_gem_region.c | 6 +- > drivers/gpu/drm/i915/gem/i915_gem_ttm.c| 647 > + > drivers/gpu/drm/i915/gem/i915_gem_ttm.h| 48 ++ > drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c | 90 +-- > drivers/gpu/drm/i915/gt/intel_region_lmem.c| 3 +- > drivers/gpu/drm/i915/i915_gem.c| 5 +- > drivers/gpu/drm/i915/intel_memory_region.c | 1 - > drivers/gpu/drm/i915/intel_memory_region.h | 1 - > drivers/gpu/drm/i915/intel_region_ttm.c| 8 +- > drivers/gpu/drm/i915/intel_region_ttm.h| 11 +- > drivers/gpu/drm/i915/selftests/igt_mmap.c | 25 +- > drivers/gpu/drm/i915/selftests/igt_mmap.h | 12 +- > include/drm/drm_vma_manager.h | 2 +- > 24 files changed, 1039 insertions(+), 250 deletions(-) > create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c > create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h
Re: [PULL] topic/i915-ttm
Quoting Joonas Lahtinen (2021-06-11 13:40:56) > Quoting Maarten Lankhorst (2021-06-11 12:27:15) > > Pull request for drm-misc-next and drm-intel-gt-next. > > > > topic/i915-ttm-2021-06-11: > > drm-misc and drm-intel pull request for topic/i915-ttm: > > - Convert i915 lmem handling to ttm. > > - Add a patch to temporarily add a driver_private member to vma_node. > > - Use this to allow mixed object mmap handling for i915. > > The following changes since commit 1bd8a7dc28c1c410f1ceefae1f2a97c06d1a67c2: > > > > Merge tag 'exynos-drm-next-for-v5.14' of > > git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into > > drm-next (2021-06-11 14:19:12 +1000) > > This base is not in drm-misc-next or drm-intel-gt-next, so effectively > we would end up pulling 478 extra commits from drm-next as a result. And > also causing all the warnings for those commits. I don't think we should > do that? > > The common ancestor would be ccd1950c2f7e38ae45aeefb99a08b39407cd6c63 > "Merge tag 'drm-intel-gt-next-2021-05-28' of > git://anongit.freedesktop.org/drm/drm-intel into drm-next" > Should we re-do the topic branch based on that? This problem seems to come from the fact that only the PR from yesterday that got merged to drm-next had the dependency patches. The previous backmerge of drm-next was requested too early. I've solved this with least hassle by backmerging drm-next again and then applying the PR to drm-intel-gt-next. I think drm-misc-next should do the same (exact commit was 1bd8a7dc28c1c410f1ceefae1f2a97c06d1a67c2). Regards, Joonas > However the DIM docs[1] indeed do say: "For topic branches shared within > the gpu/drm subsystem, base it on the latest drm-next branch." I think > the docs don't take into account the current period where drm-next is > being actively updated as we speak. > > Should we update the docs to use 'git merge-base' or something else? > > Regards, Joonas > > [1]: > https://drm.pages.freedesktop.org/maintainer-tools/dim.html#cross-subsystem-topic-branches > > > > > are available in the Git repository at: > > > > git://anongit.freedesktop.org/drm/drm-misc tags/topic/i915-ttm-2021-06-11 > > > > for you to fetch changes up to cf3e3e86d77970211e0983130e896ae242601003: > > > > drm/i915: Use ttm mmap handling for ttm bo's. (2021-06-11 10:53:25 +0200) > > > > > > drm-misc and drm-intel pull request for topic/i915-ttm: > > - Convert i915 lmem handling to ttm. > > - Add a patch to temporarily add a driver_private member to vma_node. > > - Use this to allow mixed object mmap handling for i915. > > > > > > Maarten Lankhorst (2): > > drm/vma: Add a driver_private member to vma_node. > > drm/i915: Use ttm mmap handling for ttm bo's. > > > > Thomas Hellström (2): > > drm/i915/ttm: Introduce a TTM i915 gem object backend > > drm/i915/lmem: Verify checks for lmem residency > > > > drivers/gpu/drm/drm_gem.c | 9 - > > drivers/gpu/drm/i915/Makefile | 1 + > > drivers/gpu/drm/i915/display/intel_display.c | 2 +- > > drivers/gpu/drm/i915/gem/i915_gem_create.c | 9 +- > > drivers/gpu/drm/i915/gem/i915_gem_lmem.c | 126 ++-- > > drivers/gpu/drm/i915/gem/i915_gem_lmem.h | 5 - > > drivers/gpu/drm/i915/gem/i915_gem_mman.c | 83 ++- > > drivers/gpu/drm/i915/gem/i915_gem_object.c | 143 +++-- > > drivers/gpu/drm/i915/gem/i915_gem_object.h | 19 +- > > drivers/gpu/drm/i915/gem/i915_gem_object_types.h | 30 +- > > drivers/gpu/drm/i915/gem/i915_gem_pages.c | 3 +- > > drivers/gpu/drm/i915/gem/i915_gem_region.c | 6 +- > > drivers/gpu/drm/i915/gem/i915_gem_ttm.c| 647 > > + > > drivers/gpu/drm/i915/gem/i915_gem_ttm.h| 48 ++ > > drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c | 90 +-- > > drivers/gpu/drm/i915/gt/intel_region_lmem.c| 3 +- > > drivers/gpu/drm/i915/i915_gem.c| 5 +- > > drivers/gpu/drm/i915/intel_memory_region.c | 1 - > > drivers/gpu/drm/i915/intel_memory_region.h | 1 - > > drivers/gpu/drm/i915/intel_region_ttm.c| 8 +- > > drivers/gpu/drm/i915/intel_region_ttm.h| 11 +- > > drivers/gpu/drm/i915/selftests/igt_mmap.c | 25 +- > > drivers/gpu/drm/i915/selftests/igt_mmap.h | 12 +- > > include/drm/drm_vma_manager.h | 2 +- > > 24 files changed, 1039 insertions(+), 250 deletions(-) > > create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.c > > create mode 100644 drivers/gpu/drm/i915/gem/i915_gem_ttm.h
Re: [PATCH 1/4] drm/ttm: add a pointer to the allocating BO into ttm_resource
Am 11.06.21 um 07:34 schrieb Thomas Hellström (Intel): Hi, Christian, I know you have a lot on your plate, and that the drm community is a bit lax about following the kernel patch submitting guidelines, but now that we're also spinning up a number of Intel developers on TTM could we please make a better effort with cover letters and commit messages so that they understand what the purpose and end goal of the series is. A reviewer shouldn't have to look at the last patch to try to get an understanding what the series is doing and why. Sorry, that was send out this early unintentionally. See it more like an RFC. On 6/10/21 1:05 PM, Christian König wrote: We are going to need this for the next patch and it allows us to clean up amdgpu as well. The amdgpu changes are not reflected in the commit title. Signed-off-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c | 47 - drivers/gpu/drm/ttm/ttm_resource.c | 1 + include/drm/ttm/ttm_resource.h | 1 + 3 files changed, 19 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c index 194f9eecf89c..8e3f5da44e4f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c @@ -26,23 +26,12 @@ #include "amdgpu.h" -struct amdgpu_gtt_node { - struct ttm_buffer_object *tbo; - struct ttm_range_mgr_node base; -}; - static inline struct amdgpu_gtt_mgr * to_gtt_mgr(struct ttm_resource_manager *man) { return container_of(man, struct amdgpu_gtt_mgr, manager); } -static inline struct amdgpu_gtt_node * -to_amdgpu_gtt_node(struct ttm_resource *res) -{ - return container_of(res, struct amdgpu_gtt_node, base.base); -} - /** * DOC: mem_info_gtt_total * @@ -107,9 +96,9 @@ const struct attribute_group amdgpu_gtt_mgr_attr_group = { */ bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *res) { - struct amdgpu_gtt_node *node = to_amdgpu_gtt_node(res); + struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res); - return drm_mm_node_allocated(&node->base.mm_nodes[0]); + return drm_mm_node_allocated(&node->mm_nodes[0]); } /** @@ -129,7 +118,7 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, { struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); uint32_t num_pages = PFN_UP(tbo->base.size); - struct amdgpu_gtt_node *node; + struct ttm_range_mgr_node *node; int r; spin_lock(&mgr->lock); @@ -141,19 +130,17 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, atomic64_sub(num_pages, &mgr->available); spin_unlock(&mgr->lock); - node = kzalloc(struct_size(node, base.mm_nodes, 1), GFP_KERNEL); + node = kzalloc(struct_size(node, mm_nodes, 1), GFP_KERNEL); if (!node) { r = -ENOMEM; goto err_out; } - node->tbo = tbo; - ttm_resource_init(tbo, place, &node->base.base); - + ttm_resource_init(tbo, place, &node->base); if (place->lpfn) { spin_lock(&mgr->lock); r = drm_mm_insert_node_in_range(&mgr->mm, - &node->base.mm_nodes[0], + &node->mm_nodes[0], num_pages, tbo->page_alignment, 0, place->fpfn, place->lpfn, DRM_MM_INSERT_BEST); @@ -161,14 +148,14 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, if (unlikely(r)) goto err_free; - node->base.base.start = node->base.mm_nodes[0].start; + node->base.start = node->mm_nodes[0].start; } else { - node->base.mm_nodes[0].start = 0; - node->base.mm_nodes[0].size = node->base.base.num_pages; - node->base.base.start = AMDGPU_BO_INVALID_OFFSET; + node->mm_nodes[0].start = 0; + node->mm_nodes[0].size = node->base.num_pages; + node->base.start = AMDGPU_BO_INVALID_OFFSET; } - *res = &node->base.base; + *res = &node->base; return 0; err_free: @@ -191,12 +178,12 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man, struct ttm_resource *res) { - struct amdgpu_gtt_node *node = to_amdgpu_gtt_node(res); + struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res); struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); spin_lock(&mgr->lock); - if (drm_mm_node_allocated(&node->base.mm_nodes[0])) - drm_mm_remove_node(&node->base.mm_nodes[0]); + if (drm_mm_node_allocated(&node->mm_nodes[0])) + drm_mm_remove_node(&node->mm_nodes[0]); spin_unlock(&mgr->lock); atomic64_add(res->num_pages, &mgr->available); @@ -228,14 +215,14 @@ uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man) int amdgpu_gtt_mgr_recover(struct ttm_resource_man
Re: [PATCH 2/7] dma-buf: add dma_fence_chain_alloc/free
Am 11.06.21 um 09:54 schrieb Daniel Vetter: On Thu, Jun 10, 2021 at 11:17:55AM +0200, Christian König wrote: Add a common allocation helper. Cleaning up the mix of kzalloc/kmalloc and some unused code in the selftest. Signed-off-by: Christian König --- drivers/dma-buf/st-dma-fence-chain.c | 16 -- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c| 4 ++-- drivers/gpu/drm/drm_syncobj.c | 6 ++--- .../gpu/drm/i915/gem/i915_gem_execbuffer.c| 6 ++--- drivers/gpu/drm/msm/msm_gem_submit.c | 6 ++--- include/linux/dma-fence-chain.h | 22 +++ 6 files changed, 35 insertions(+), 25 deletions(-) diff --git a/drivers/dma-buf/st-dma-fence-chain.c b/drivers/dma-buf/st-dma-fence-chain.c index 9525f7f56119..8ce1ea59d31b 100644 --- a/drivers/dma-buf/st-dma-fence-chain.c +++ b/drivers/dma-buf/st-dma-fence-chain.c @@ -58,28 +58,20 @@ static struct dma_fence *mock_fence(void) return &f->base; } -static inline struct mock_chain { - struct dma_fence_chain base; -} *to_mock_chain(struct dma_fence *f) { - return container_of(f, struct mock_chain, base.base); -} - static struct dma_fence *mock_chain(struct dma_fence *prev, struct dma_fence *fence, u64 seqno) { - struct mock_chain *f; + struct dma_fence_chain *f; - f = kmalloc(sizeof(*f), GFP_KERNEL); + f = dma_fence_chain_alloc(); if (!f) return NULL; - dma_fence_chain_init(&f->base, -dma_fence_get(prev), -dma_fence_get(fence), + dma_fence_chain_init(f, dma_fence_get(prev), dma_fence_get(fence), seqno); - return &f->base.base; + return &f->base; } static int sanitycheck(void *arg) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 90136f9dedd6..325e82621467 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1124,7 +1124,7 @@ static int amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p dep->chain = NULL; if (syncobj_deps[i].point) { - dep->chain = kmalloc(sizeof(*dep->chain), GFP_KERNEL); + dep->chain = dma_fence_chain_alloc(); if (!dep->chain) return -ENOMEM; } @@ -1132,7 +1132,7 @@ static int amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p dep->syncobj = drm_syncobj_find(p->filp, syncobj_deps[i].handle); if (!dep->syncobj) { - kfree(dep->chain); + dma_fence_chain_free(dep->chain); return -EINVAL; } dep->point = syncobj_deps[i].point; diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index fdd2ec87cdd1..1c5b9ef6da37 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -861,7 +861,7 @@ static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private, &fence); if (ret) goto err; - chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); + chain = dma_fence_chain_alloc(); if (!chain) { ret = -ENOMEM; goto err1; @@ -1402,10 +1402,10 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data, goto err_points; } for (i = 0; i < args->count_handles; i++) { - chains[i] = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); + chains[i] = dma_fence_chain_alloc(); if (!chains[i]) { for (j = 0; j < i; j++) - kfree(chains[j]); + dma_fence_chain_free(chains[j]); ret = -ENOMEM; goto err_chains; } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 66789111a24b..a22cb86730b3 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -2983,7 +2983,7 @@ __free_fence_array(struct eb_fence *fences, unsigned int n) while (n--) { drm_syncobj_put(ptr_mask_bits(fences[n].syncobj, 2)); dma_fence_put(fences[n].dma_fence); - kfree(fences[n].chain_fence); + dma_fence_chain_free(fences[n].chain_fence); } kvfree(fences); } @@ -3097,9 +3097,7 @@ add_timeline_fence_array(struct i915_execbuffer *eb, return -EINVAL; } - f->chain_fence
[PATCH 1/5] dma-buf: fix dma_resv_test_signaled test_all handling
As the name implies if testing all fences is requested we should indeed test all fences and not skip the exclusive one because we see shared ones. Signed-off-by: Christian König --- drivers/dma-buf/dma-resv.c | 33 - 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index f26c71747d43..c66bfdde9454 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -615,25 +615,21 @@ static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence) */ bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all) { - unsigned int seq, shared_count; + struct dma_fence *fence; + unsigned int seq; int ret; rcu_read_lock(); retry: ret = true; - shared_count = 0; seq = read_seqcount_begin(&obj->seq); if (test_all) { struct dma_resv_list *fobj = dma_resv_shared_list(obj); - unsigned int i; - - if (fobj) - shared_count = fobj->shared_count; + unsigned int i, shared_count; + shared_count = fobj ? fobj->shared_count : 0; for (i = 0; i < shared_count; ++i) { - struct dma_fence *fence; - fence = rcu_dereference(fobj->shared[i]); ret = dma_resv_test_signaled_single(fence); if (ret < 0) @@ -641,24 +637,19 @@ bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all) else if (!ret) break; } - - if (read_seqcount_retry(&obj->seq, seq)) - goto retry; } - if (!shared_count) { - struct dma_fence *fence_excl = dma_resv_excl_fence(obj); - - if (fence_excl) { - ret = dma_resv_test_signaled_single(fence_excl); - if (ret < 0) - goto retry; + fence = dma_resv_excl_fence(obj); + if (fence) { + ret = dma_resv_test_signaled_single(fence); + if (ret < 0) + goto retry; - if (read_seqcount_retry(&obj->seq, seq)) - goto retry; - } } + if (read_seqcount_retry(&obj->seq, seq)) + goto retry; + rcu_read_unlock(); return ret; } -- 2.25.1
[PATCH 5/5] drm/amdgpu: rework dma_resv handling v2
Drop the workaround and instead implement a better solution. Basically we are now chaining all submissions using a dma_fence_chain container and adding them as exclusive fence to the dma_resv object. This way other drivers can still sync to the single exclusive fence while amdgpu only sync to fences from different processes. v2: polish kerneldoc a bit Signed-off-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 54 + drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 65 - drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 +- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 1 - 6 files changed, 47 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h index a130e766cbdb..c905a4cfc173 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h @@ -34,6 +34,7 @@ struct amdgpu_fpriv; struct amdgpu_bo_list_entry { struct ttm_validate_buffer tv; struct amdgpu_bo_va *bo_va; + struct dma_fence_chain *chain; uint32_tpriority; struct page **user_pages; booluser_invalidated; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 325e82621467..f6f3029f958d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -587,6 +587,20 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, goto out; } + amdgpu_bo_list_for_each_entry(e, p->bo_list) { + struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); + + e->bo_va = amdgpu_vm_bo_find(vm, bo); + + if (bo->tbo.base.dma_buf && !amdgpu_bo_explicit_sync(bo)) { + e->chain = dma_fence_chain_alloc(); + if (!e->chain) { + r = -ENOMEM; + goto error_validate; + } + } + } + amdgpu_cs_get_threshold_for_moves(p->adev, &p->bytes_moved_threshold, &p->bytes_moved_vis_threshold); p->bytes_moved = 0; @@ -614,15 +628,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, gws = p->bo_list->gws_obj; oa = p->bo_list->oa_obj; - amdgpu_bo_list_for_each_entry(e, p->bo_list) { - struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); - - /* Make sure we use the exclusive slot for shared BOs */ - if (bo->prime_shared_count) - e->tv.num_shared = 0; - e->bo_va = amdgpu_vm_bo_find(vm, bo); - } - if (gds) { p->job->gds_base = amdgpu_bo_gpu_offset(gds) >> PAGE_SHIFT; p->job->gds_size = amdgpu_bo_size(gds) >> PAGE_SHIFT; @@ -644,8 +649,13 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, } error_validate: - if (r) + if (r) { + amdgpu_bo_list_for_each_entry(e, p->bo_list) { + dma_fence_chain_free(e->chain); + e->chain = NULL; + } ttm_eu_backoff_reservation(&p->ticket, &p->validated); + } out: return r; } @@ -685,9 +695,17 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, { unsigned i; - if (error && backoff) + if (error && backoff) { + struct amdgpu_bo_list_entry *e; + + amdgpu_bo_list_for_each_entry(e, parser->bo_list) { + dma_fence_chain_free(e->chain); + e->chain = NULL; + } + ttm_eu_backoff_reservation(&parser->ticket, &parser->validated); + } for (i = 0; i < parser->num_post_deps; i++) { drm_syncobj_put(parser->post_deps[i].syncobj); @@ -1260,6 +1278,20 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, amdgpu_vm_move_to_lru_tail(p->adev, &fpriv->vm); + amdgpu_bo_list_for_each_entry(e, p->bo_list) { + struct dma_resv *resv = e->tv.bo->base.resv; + struct dma_fence_chain *chain = e->chain; + + if (!chain) + continue; + + dma_fence_chain_init(chain, dma_resv_excl_fence(resv), +dma_fence_get(p->fence), 1); + + rcu_assign_pointer(resv->fence_excl, &chain->base); + e->chain = NULL; + } + ttm_eu_fence_buffer_objects(&p->ticket, &p->validated, p->fence); mutex_unlock(&p->adev->notifier_lock); diff --git a/drivers/gpu/
[PATCH 3/5] dma-buf: add dma_fence_chain_alloc/free v2
Add a common allocation helper. Cleaning up the mix of kzalloc/kmalloc and some unused code in the selftest. v2: polish kernel doc a bit Signed-off-by: Christian König Reviewed-by: Daniel Vetter --- drivers/dma-buf/st-dma-fence-chain.c | 16 - drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c| 4 ++-- drivers/gpu/drm/drm_syncobj.c | 6 ++--- .../gpu/drm/i915/gem/i915_gem_execbuffer.c| 6 ++--- drivers/gpu/drm/msm/msm_gem_submit.c | 6 ++--- include/linux/dma-fence-chain.h | 23 +++ 6 files changed, 36 insertions(+), 25 deletions(-) diff --git a/drivers/dma-buf/st-dma-fence-chain.c b/drivers/dma-buf/st-dma-fence-chain.c index 9525f7f56119..8ce1ea59d31b 100644 --- a/drivers/dma-buf/st-dma-fence-chain.c +++ b/drivers/dma-buf/st-dma-fence-chain.c @@ -58,28 +58,20 @@ static struct dma_fence *mock_fence(void) return &f->base; } -static inline struct mock_chain { - struct dma_fence_chain base; -} *to_mock_chain(struct dma_fence *f) { - return container_of(f, struct mock_chain, base.base); -} - static struct dma_fence *mock_chain(struct dma_fence *prev, struct dma_fence *fence, u64 seqno) { - struct mock_chain *f; + struct dma_fence_chain *f; - f = kmalloc(sizeof(*f), GFP_KERNEL); + f = dma_fence_chain_alloc(); if (!f) return NULL; - dma_fence_chain_init(&f->base, -dma_fence_get(prev), -dma_fence_get(fence), + dma_fence_chain_init(f, dma_fence_get(prev), dma_fence_get(fence), seqno); - return &f->base.base; + return &f->base; } static int sanitycheck(void *arg) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 90136f9dedd6..325e82621467 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1124,7 +1124,7 @@ static int amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p dep->chain = NULL; if (syncobj_deps[i].point) { - dep->chain = kmalloc(sizeof(*dep->chain), GFP_KERNEL); + dep->chain = dma_fence_chain_alloc(); if (!dep->chain) return -ENOMEM; } @@ -1132,7 +1132,7 @@ static int amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p dep->syncobj = drm_syncobj_find(p->filp, syncobj_deps[i].handle); if (!dep->syncobj) { - kfree(dep->chain); + dma_fence_chain_free(dep->chain); return -EINVAL; } dep->point = syncobj_deps[i].point; diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index fdd2ec87cdd1..1c5b9ef6da37 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -861,7 +861,7 @@ static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private, &fence); if (ret) goto err; - chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); + chain = dma_fence_chain_alloc(); if (!chain) { ret = -ENOMEM; goto err1; @@ -1402,10 +1402,10 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data, goto err_points; } for (i = 0; i < args->count_handles; i++) { - chains[i] = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); + chains[i] = dma_fence_chain_alloc(); if (!chains[i]) { for (j = 0; j < i; j++) - kfree(chains[j]); + dma_fence_chain_free(chains[j]); ret = -ENOMEM; goto err_chains; } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 66789111a24b..a22cb86730b3 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -2983,7 +2983,7 @@ __free_fence_array(struct eb_fence *fences, unsigned int n) while (n--) { drm_syncobj_put(ptr_mask_bits(fences[n].syncobj, 2)); dma_fence_put(fences[n].dma_fence); - kfree(fences[n].chain_fence); + dma_fence_chain_free(fences[n].chain_fence); } kvfree(fences); } @@ -3097,9 +3097,7 @@ add_timeline_fence_array(struct i915_execbuffer *eb, return -EINVAL; } - f->chain_fence = -
[PATCH 2/5] dma-buf: some dma_fence_chain improvements
The callback and the irq work are never used at the same time. Putting them into an union saves us 24 bytes and makes the structure only 120 bytes in size. Signed-off-by: Christian König Reviewed-by: Daniel Vetter --- drivers/dma-buf/dma-fence-chain.c | 2 +- include/linux/dma-fence-chain.h | 27 +-- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/dma-buf/dma-fence-chain.c b/drivers/dma-buf/dma-fence-chain.c index 7d129e68ac70..1b4cb3e5cec9 100644 --- a/drivers/dma-buf/dma-fence-chain.c +++ b/drivers/dma-buf/dma-fence-chain.c @@ -137,6 +137,7 @@ static void dma_fence_chain_cb(struct dma_fence *f, struct dma_fence_cb *cb) struct dma_fence_chain *chain; chain = container_of(cb, typeof(*chain), cb); + init_irq_work(&chain->work, dma_fence_chain_irq_work); irq_work_queue(&chain->work); dma_fence_put(f); } @@ -239,7 +240,6 @@ void dma_fence_chain_init(struct dma_fence_chain *chain, rcu_assign_pointer(chain->prev, prev); chain->fence = fence; chain->prev_seqno = 0; - init_irq_work(&chain->work, dma_fence_chain_irq_work); /* Try to reuse the context of the previous chain node. */ if (prev_chain && __dma_fence_is_later(seqno, prev->seqno, prev->ops)) { diff --git a/include/linux/dma-fence-chain.h b/include/linux/dma-fence-chain.h index 10462a029da2..c6eb3aa45668 100644 --- a/include/linux/dma-fence-chain.h +++ b/include/linux/dma-fence-chain.h @@ -16,21 +16,36 @@ /** * struct dma_fence_chain - fence to represent an node of a fence chain * @base: fence base class - * @lock: spinlock for fence handling * @prev: previous fence of the chain * @prev_seqno: original previous seqno before garbage collection * @fence: encapsulated fence - * @cb: callback structure for signaling - * @work: irq work item for signaling + * @lock: spinlock for fence handling */ struct dma_fence_chain { struct dma_fence base; - spinlock_t lock; struct dma_fence __rcu *prev; u64 prev_seqno; struct dma_fence *fence; - struct dma_fence_cb cb; - struct irq_work work; + union { + /** +* @cb: callback for signaling +* +* This is used to add the callback for signaling the +* complection of the fence chain. Never used at the same time +* as the irq work. +*/ + struct dma_fence_cb cb; + + /** +* @work: irq work item for signaling +* +* Irq work structure to allow us to add the callback without +* running into lock inversion. Never used at the same time as +* the callback. +*/ + struct irq_work work; + }; + spinlock_t lock; }; extern const struct dma_fence_ops dma_fence_chain_ops; -- 2.25.1
[PATCH 4/5] drm/amdgpu: unwrap fence chains in the explicit sync fence
Unwrap the explicit fence if it is a dma_fence_chain and sync to the first fence not matching the owner rules. Signed-off-by: Christian König Acked-by: Daniel Vetter --- drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 118 +-- 1 file changed, 68 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index 1b2ceccaf5b0..862eb3c1c4c5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -28,6 +28,8 @@ *Christian König */ +#include + #include "amdgpu.h" #include "amdgpu_trace.h" #include "amdgpu_amdkfd.h" @@ -186,6 +188,55 @@ int amdgpu_sync_vm_fence(struct amdgpu_sync *sync, struct dma_fence *fence) return amdgpu_sync_fence(sync, fence); } +/* Determine based on the owner and mode if we should sync to a fence or not */ +static bool amdgpu_sync_test_fence(struct amdgpu_device *adev, + enum amdgpu_sync_mode mode, + void *owner, struct dma_fence *f) +{ + void *fence_owner = amdgpu_sync_get_owner(f); + + /* Always sync to moves, no matter what */ + if (fence_owner == AMDGPU_FENCE_OWNER_UNDEFINED) + return true; + + /* We only want to trigger KFD eviction fences on +* evict or move jobs. Skip KFD fences otherwise. +*/ + if (fence_owner == AMDGPU_FENCE_OWNER_KFD && + owner != AMDGPU_FENCE_OWNER_UNDEFINED) + return false; + + /* Never sync to VM updates either. */ + if (fence_owner == AMDGPU_FENCE_OWNER_VM && + owner != AMDGPU_FENCE_OWNER_UNDEFINED) + return false; + + /* Ignore fences depending on the sync mode */ + switch (mode) { + case AMDGPU_SYNC_ALWAYS: + return true; + + case AMDGPU_SYNC_NE_OWNER: + if (amdgpu_sync_same_dev(adev, f) && + fence_owner == owner) + return false; + break; + + case AMDGPU_SYNC_EQ_OWNER: + if (amdgpu_sync_same_dev(adev, f) && + fence_owner != owner) + return false; + break; + + case AMDGPU_SYNC_EXPLICIT: + return false; + } + + WARN(debug_evictions && fence_owner == AMDGPU_FENCE_OWNER_KFD, +"Adding eviction fence to sync obj"); + return true; +} + /** * amdgpu_sync_resv - sync to a reservation object * @@ -211,67 +262,34 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, struct amdgpu_sync *sync, /* always sync to the exclusive fence */ f = dma_resv_excl_fence(resv); - r = amdgpu_sync_fence(sync, f); + dma_fence_chain_for_each(f, f) { + struct dma_fence_chain *chain = to_dma_fence_chain(f); + + if (amdgpu_sync_test_fence(adev, mode, owner, chain ? + chain->fence : f)) { + r = amdgpu_sync_fence(sync, f); + dma_fence_put(f); + if (r) + return r; + break; + } + } flist = dma_resv_shared_list(resv); - if (!flist || r) - return r; + if (!flist) + return 0; for (i = 0; i < flist->shared_count; ++i) { - void *fence_owner; - f = rcu_dereference_protected(flist->shared[i], dma_resv_held(resv)); - fence_owner = amdgpu_sync_get_owner(f); - - /* Always sync to moves, no matter what */ - if (fence_owner == AMDGPU_FENCE_OWNER_UNDEFINED) { + if (amdgpu_sync_test_fence(adev, mode, owner, f)) { r = amdgpu_sync_fence(sync, f); if (r) - break; - } - - /* We only want to trigger KFD eviction fences on -* evict or move jobs. Skip KFD fences otherwise. -*/ - if (fence_owner == AMDGPU_FENCE_OWNER_KFD && - owner != AMDGPU_FENCE_OWNER_UNDEFINED) - continue; - - /* Never sync to VM updates either. */ - if (fence_owner == AMDGPU_FENCE_OWNER_VM && - owner != AMDGPU_FENCE_OWNER_UNDEFINED) - continue; - - /* Ignore fences depending on the sync mode */ - switch (mode) { - case AMDGPU_SYNC_ALWAYS: - break; - - case AMDGPU_SYNC_NE_OWNER: - if (amdgpu_sync_same_dev(adev, f) && - fence_owner == owner) - continue; - break; - - case AMDGPU_SYNC_EQ_OWNER: -
Re: [PATCH v3] Documentation: gpu: Mention the requirements for new properties
On Fri, Jun 11, 2021 at 08:14:59AM +, Simon Ser wrote: > On Thursday, June 10th, 2021 at 23:00, Daniel Vetter > wrote: > > > If there's a strong consensus that we really need this then I'm not > > going to nack this, but this really needs a pile of acks from > > compositor folks that they're willing to live with the resulting > > fallout this will likely bring. Your cc list seems to have an absence > > of compositor folks, but instead every driver maintainer. That's > > backwards. We make uapi for userspace, not for kernel driver > > maintainers! > > In wlroots we have a policy of only allowing standard KMS properties to > be used. Any vendor-specific property is going to be less well-defined, > less widely useful, potentially have more design issues, potentially > overlap in functionality with other vendor-specific properties, likely > have some hardware-specific assumptions, etc. > > What matters here is discussing with other driver & user-space folks to > make sure the new property's design is sound. Designing uAPI is hard. > > If kernel folks are struggling with a user-space implementation, they > should discuss with user-space folks to see which project would be > interested. There's a chance a compositor will be interested in the new > property and will just do the user-space part for you, if not we can > suggest candidate projects. > > tl;dr strong agree with Daniel here. I think the assumption you and Daniel are making is that the first implementation of a new KMS property can be made standard from day one and that it will work for any late comer driver as is, without having to make changes to its behaviour in a significant way. In my experience that is not the case. I think we have moved from the times when we were trying to implement in the Linux world features that were available in the hardware but needed a kernel and userspace API. The set of properties that exist in KMS cover a lot of needed functionality and I don't expect to see new properties for stuff that is already supported by hardware. What I'm expected to see in the future is new functionality that gets implemented by one hardware vendor and the kernel developers trying to enable that for userspace. It could be that the new property is generic, but there is no way of testing that on more than one implementation yet, so I'd say we are generous calling it "standard property". When the second or third hardware vendor comes along and starts supporting that property with their own set of extra requirements, then we can call it "standard". Then comes the effort cost: would it be easier to start with a vendor property that only the vendor needs to support (and can submit patches into the compositors to do so) and when the standard property gets added moves to that, or should we start with a generic property that gets implemented by the compositors (maybe, but then only one vendor supports it) and then later when we actually standardise the property we will have to carry backwards compatibility code in the kernel to handle the old behaviour for old userspace? My proposal to Maxime was for the former option to be reflected in the documentation, but I would like to hear your thoughts. Best regards, Liviu -- | I would like to | | fix the world, | | but they're not | | giving me the | \ source code! / --- ¯\_(ツ)_/¯
Re: nouveau broken on Riva TNT2 in 5.13.0-rc4: NULL pointer dereference in nouveau_bo_sync_for_device
Am 10.06.21 um 19:59 schrieb Christian König: Am 10.06.21 um 19:50 schrieb Ondrej Zary: [SNIP] I can't see how this is called from the nouveau code, only possibility I see is that it is maybe called through the AGP code somehow. Yes, you're right: [ 13.192663] Call Trace: [ 13.192678] dump_stack+0x54/0x68 [ 13.192690] ttm_tt_init+0x11/0x8a [ttm] [ 13.192699] ttm_agp_tt_create+0x39/0x51 [ttm] [ 13.192840] nouveau_ttm_tt_create+0x17/0x22 [nouveau] [ 13.192856] ttm_tt_create+0x78/0x8c [ttm] [ 13.192864] ttm_bo_handle_move_mem+0x7d/0xca [ttm] [ 13.192873] ttm_bo_validate+0x92/0xc8 [ttm] [ 13.192883] ttm_bo_init_reserved+0x216/0x243 [ttm] [ 13.192892] ttm_bo_init+0x45/0x65 [ttm] [ 13.193018] ? nouveau_bo_del_io_reserve_lru+0x48/0x48 [nouveau] [ 13.193150] nouveau_bo_init+0x8c/0x94 [nouveau] [ 13.193273] ? nouveau_bo_del_io_reserve_lru+0x48/0x48 [nouveau] [ 13.193407] nouveau_bo_new+0x44/0x57 [nouveau] [ 13.193537] nouveau_channel_prep+0xa3/0x269 [nouveau] [ 13.193665] nouveau_channel_new+0x3c/0x5f7 [nouveau] [ 13.193679] ? slab_free_freelist_hook+0x3b/0xa7 [ 13.193686] ? kfree+0x9e/0x11a [ 13.193781] ? nvif_object_sclass_put+0xd/0x16 [nouveau] [ 13.193908] nouveau_drm_device_init+0x2e2/0x646 [nouveau] [ 13.193924] ? pci_enable_device_flags+0x1e/0xac [ 13.194052] nouveau_drm_probe+0xeb/0x188 [nouveau] [ 13.194182] ? nouveau_drm_device_init+0x646/0x646 [nouveau] [ 13.194195] pci_device_probe+0x89/0xe9 [ 13.194205] really_probe+0x127/0x2a7 [ 13.194212] driver_probe_device+0x5b/0x87 [ 13.194219] device_driver_attach+0x2e/0x41 [ 13.194226] __driver_attach+0x7c/0x83 [ 13.194232] bus_for_each_dev+0x4c/0x66 [ 13.194238] driver_attach+0x14/0x16 [ 13.194244] ? device_driver_attach+0x41/0x41 [ 13.194251] bus_add_driver+0xc5/0x16c [ 13.194258] driver_register+0x87/0xb9 [ 13.194265] __pci_register_driver+0x38/0x3b [ 13.194271] ? 0xf0c0d000 [ 13.194362] nouveau_drm_init+0x14c/0x1000 [nouveau] How is ttm_dma_tt->dma_address allocated? Mhm, I need to double check how AGP is supposed to work. Since barely anybody is using it these days it is something which breaks from time to time. I have no idea how that ever worked in the first place since AGP isn't supposed to sync between CPU/GPU. Everything is coherent for that case. Anyway here is a patch which adds a check to those functions if the dma_address array is allocated in the first place. Please test it. Thanks, Christian. Thanks for the backtrace, Christian. I cannot find any assignment executed (in the working code): $ git grep dma_address\ = drivers/gpu/ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c: sg->sgl->dma_address = addr; drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c: dma_address = &dma->dma_address[offset >> PAGE_SHIFT]; drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c: dma_address = (mm_node->start << PAGE_SHIFT) + offset; drivers/gpu/drm/i915/gvt/scheduler.c: sg->dma_address = addr; drivers/gpu/drm/i915/i915_gpu_error.c: sg->dma_address = it; drivers/gpu/drm/ttm/ttm_tt.c: ttm->dma_address = (void *) (ttm->ttm.pages + ttm->ttm.num_pages); drivers/gpu/drm/ttm/ttm_tt.c: ttm->dma_address = kvmalloc_array(ttm->ttm.num_pages, drivers/gpu/drm/ttm/ttm_tt.c: ttm_dma->dma_address = NULL; drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c: viter->dma_address = &__vmw_piter_phys_addr; drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c: viter->dma_address = &__vmw_piter_dma_addr; drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c: viter->dma_address = &__vmw_piter_sg_addr; The 2 cases in ttm_tt.c are in ttm_dma_tt_alloc_page_directory() and ttm_sg_tt_alloc_page_directory(). Confirmed by adding printk()s that they're NOT called. >From 5370102729c6ecb280712c40b92ff7b9f58c6e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 11 Jun 2021 14:34:50 +0200 Subject: [PATCH] drm/nouveau: check dma_address array for CPU/GPU sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AGP for example doesn't have a dma_address array. Signed-off-by: Christian König --- drivers/gpu/drm/nouveau/nouveau_bo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 085023624fb0..1a52590f5303 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -551,7 +551,7 @@ nouveau_bo_sync_for_device(struct nouveau_bo *nvbo) struct ttm_tt *ttm_dma = (struct ttm_tt *)nvbo->bo.ttm; int i, j; - if (!ttm_dma) + if (!ttm_dma || !ttm_dma->dma_address) return; if (!ttm_dma->pages) { NV_DEBUG(drm, "ttm_dma 0x%p: pages NULL\n", ttm_dma); @@ -587,7 +587,7 @@ nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo) struct ttm_tt *ttm_dma = (struct ttm_tt *)nvbo->bo.ttm; int i, j; - if (!ttm_dma) + if (!ttm_dma || !ttm_dma->dma_address) return; if (!ttm_dma->pages) { NV_D
Re: [PATCH 06/10] vfio/mdev: Remove CONFIG_VFIO_MDEV_DEVICE
On Mon, Jun 07 2021, Jason Gunthorpe wrote: > For some reason the vfio_mdev shim mdev_driver has its own module and > kconfig. As the next patch requires access to it from mdev.ko merge the > two modules together and remove VFIO_MDEV_DEVICE. > > A later patch deletes this driver entirely. > > Signed-off-by: Jason Gunthorpe > --- > Documentation/s390/vfio-ap.rst | 1 - > arch/s390/Kconfig| 2 +- > drivers/gpu/drm/i915/Kconfig | 2 +- > drivers/vfio/mdev/Kconfig| 7 --- > drivers/vfio/mdev/Makefile | 3 +-- > drivers/vfio/mdev/mdev_core.c| 16 ++-- > drivers/vfio/mdev/mdev_private.h | 2 ++ > drivers/vfio/mdev/vfio_mdev.c| 24 +--- > samples/Kconfig | 6 +++--- > 9 files changed, 23 insertions(+), 40 deletions(-) I think you missed my earlier Reviewed-by: Cornelia Huck
Re: [PATCH v3] Documentation: gpu: Mention the requirements for new properties
> What I'm expected to see in the future is new functionality that gets > implemented by > one hardware vendor and the kernel developers trying to enable that for > userspace. It > could be that the new property is generic, but there is no way of testing > that on > more than one implementation yet, so I'd say we are generous calling it > "standard > property". When the second or third hardware vendor comes along and starts > supporting > that property with their own set of extra requirements, then we can call it > "standard". Then comes the effort cost: would it be easier to start with a > vendor > property that only the vendor needs to support (and can submit patches into > the > compositors to do so) and when the standard property gets added moves to > that, or > should we start with a generic property that gets implemented by the > compositors > (maybe, but then only one vendor supports it) and then later when we actually > standardise the property we will have to carry backwards compatibility code > in the > kernel to handle the old behaviour for old userspace? My proposal to Maxime > was for > the former option to be reflected in the documentation, but I would like to > hear your > thoughts. Just my 2c - if the mainline kernel isn't willing to commit to a feature for upstream userspace to use, why does that feature belong in the kernel at all? I don't see much value in exposing hardware for the sake of exposing it when, practically, Linux userspace /can't/ use it as-is. Might these vendor properties be used on downstream Android userspaces? That's not generally an upstream goal to support.
[PATCH] drm/i915: Fix busy ioctl commentary
From: Tvrtko Ursulin Just tidy one instance of incorrect context parameter name and a stray sentence ending from before reporting was converted to be class based. Signed-off-by: Tvrtko Ursulin --- include/uapi/drm/i915_drm.h | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index c2c7759b7d2e..a1cb4aa035a9 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -1348,12 +1348,11 @@ struct drm_i915_gem_busy { * reading from the object simultaneously. * * The value of each engine class is the same as specified in the -* I915_CONTEXT_SET_ENGINES parameter and via perf, i.e. +* I915_CONTEXT_PARAM_ENGINES context parameter and via perf, i.e. * I915_ENGINE_CLASS_RENDER, I915_ENGINE_CLASS_COPY, etc. -* reported as active itself. Some hardware may have parallel -* execution engines, e.g. multiple media engines, which are -* mapped to the same class identifier and so are not separately -* reported for busyness. +* Some hardware may have parallel execution engines, e.g. multiple +* media engines, which are mapped to the same class identifier and so +* are not separately reported for busyness. * * Caveat emptor: * Only the boolean result of this query is reliable; that is whether -- 2.30.2
Re: [PATCH v3] Documentation: gpu: Mention the requirements for new properties
On Fri, Jun 11, 2021 at 08:56:04AM -0400, Alyssa Rosenzweig wrote: > > What I'm expected to see in the future is new functionality that gets > > implemented by > > one hardware vendor and the kernel developers trying to enable that for > > userspace. It > > could be that the new property is generic, but there is no way of testing > > that on > > more than one implementation yet, so I'd say we are generous calling it > > "standard > > property". When the second or third hardware vendor comes along and starts > > supporting > > that property with their own set of extra requirements, then we can call it > > "standard". Then comes the effort cost: would it be easier to start with a > > vendor > > property that only the vendor needs to support (and can submit patches into > > the > > compositors to do so) and when the standard property gets added moves to > > that, or > > should we start with a generic property that gets implemented by the > > compositors > > (maybe, but then only one vendor supports it) and then later when we > > actually > > standardise the property we will have to carry backwards compatibility code > > in the > > kernel to handle the old behaviour for old userspace? My proposal to Maxime > > was for > > the former option to be reflected in the documentation, but I would like to > > hear your > > thoughts. > > Just my 2c - if the mainline kernel isn't willing to commit to a feature > for upstream userspace to use, why does that feature belong in the > kernel at all? I don't see much value in exposing hardware for the sake > of exposing it when, practically, Linux userspace /can't/ use it as-is. > > Might these vendor properties be used on downstream Android userspaces? > That's not generally an upstream goal to support. I think the assumption is that we are willing to commit to supporting a feature for userspace, just that (I personally) lack the confidence that I will be getting the feature right on the first attempt and using only one vendor hardware. And that supporting potential mistakes I might've made in the first version is harder if the feature was deemed "standard". I'm talking from my experience with the writeback connector. We almost committed the feature twice before more people chipped in and asked us for changes, but that was lucky. Best regards, Liviu -- | I would like to | | fix the world, | | but they're not | | giving me the | \ source code! / --- ¯\_(ツ)_/¯
Re: [PATCH v5 4/5] iommu/arm-smmu-qcom: Add stall support
On Thu, Jun 10, 2021 at 02:44:12PM -0700, Rob Clark wrote: > From: Rob Clark > > Add, via the adreno-smmu-priv interface, a way for the GPU to request > the SMMU to stall translation on faults, and then later resume the > translation, either retrying or terminating the current translation. > > This will be used on the GPU side to "freeze" the GPU while we snapshot > useful state for devcoredump. > Acked-by: Jordan Crouse > Signed-off-by: Rob Clark > --- > drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 33 ++ > include/linux/adreno-smmu-priv.h | 7 + > 2 files changed, 40 insertions(+) > > diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > index b2e31ea84128..61fc645c1325 100644 > --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c > @@ -13,6 +13,7 @@ struct qcom_smmu { > struct arm_smmu_device smmu; > bool bypass_quirk; > u8 bypass_cbndx; > + u32 stall_enabled; > }; > > static struct qcom_smmu *to_qcom_smmu(struct arm_smmu_device *smmu) > @@ -23,12 +24,17 @@ static struct qcom_smmu *to_qcom_smmu(struct > arm_smmu_device *smmu) > static void qcom_adreno_smmu_write_sctlr(struct arm_smmu_device *smmu, int > idx, > u32 reg) > { > + struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); > + > /* >* On the GPU device we want to process subsequent transactions after a >* fault to keep the GPU from hanging >*/ > reg |= ARM_SMMU_SCTLR_HUPCF; > > + if (qsmmu->stall_enabled & BIT(idx)) > + reg |= ARM_SMMU_SCTLR_CFCFG; > + > arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, reg); > } > > @@ -48,6 +54,31 @@ static void qcom_adreno_smmu_get_fault_info(const void > *cookie, > info->contextidr = arm_smmu_cb_read(smmu, cfg->cbndx, > ARM_SMMU_CB_CONTEXTIDR); > } > > +static void qcom_adreno_smmu_set_stall(const void *cookie, bool enabled) > +{ > + struct arm_smmu_domain *smmu_domain = (void *)cookie; > + struct arm_smmu_cfg *cfg = &smmu_domain->cfg; > + struct qcom_smmu *qsmmu = to_qcom_smmu(smmu_domain->smmu); > + > + if (enabled) > + qsmmu->stall_enabled |= BIT(cfg->cbndx); > + else > + qsmmu->stall_enabled &= ~BIT(cfg->cbndx); > +} > + > +static void qcom_adreno_smmu_resume_translation(const void *cookie, bool > terminate) > +{ > + struct arm_smmu_domain *smmu_domain = (void *)cookie; > + struct arm_smmu_cfg *cfg = &smmu_domain->cfg; > + struct arm_smmu_device *smmu = smmu_domain->smmu; > + u32 reg = 0; > + > + if (terminate) > + reg |= ARM_SMMU_RESUME_TERMINATE; > + > + arm_smmu_cb_write(smmu, cfg->cbndx, ARM_SMMU_CB_RESUME, reg); > +} > + > #define QCOM_ADRENO_SMMU_GPU_SID 0 > > static bool qcom_adreno_smmu_is_gpu_device(struct device *dev) > @@ -173,6 +204,8 @@ static int qcom_adreno_smmu_init_context(struct > arm_smmu_domain *smmu_domain, > priv->get_ttbr1_cfg = qcom_adreno_smmu_get_ttbr1_cfg; > priv->set_ttbr0_cfg = qcom_adreno_smmu_set_ttbr0_cfg; > priv->get_fault_info = qcom_adreno_smmu_get_fault_info; > + priv->set_stall = qcom_adreno_smmu_set_stall; > + priv->resume_translation = qcom_adreno_smmu_resume_translation; > > return 0; > } > diff --git a/include/linux/adreno-smmu-priv.h > b/include/linux/adreno-smmu-priv.h > index 53fe32fb9214..c637e0997f6d 100644 > --- a/include/linux/adreno-smmu-priv.h > +++ b/include/linux/adreno-smmu-priv.h > @@ -45,6 +45,11 @@ struct adreno_smmu_fault_info { > * TTBR0 translation is enabled with the specified cfg > * @get_fault_info: Called by the GPU fault handler to get information about > * the fault > + * @set_stall: Configure whether stall on fault (CFCFG) is enabled. Call > + * before set_ttbr0_cfg(). If stalling on fault is enabled, > + * the GPU driver must call resume_translation() > + * @resume_translation: Resume translation after a fault > + * > * > * The GPU driver (drm/msm) and adreno-smmu work together for controlling > * the GPU's SMMU instance. This is by necessity, as the GPU is directly > @@ -60,6 +65,8 @@ struct adreno_smmu_priv { > const struct io_pgtable_cfg *(*get_ttbr1_cfg)(const void *cookie); > int (*set_ttbr0_cfg)(const void *cookie, const struct io_pgtable_cfg > *cfg); > void (*get_fault_info)(const void *cookie, struct adreno_smmu_fault_info > *info); > +void (*set_stall)(const void *cookie, bool enabled); > +void (*resume_translation)(const void *cookie, bool terminate); > }; > > #endif /* __ADRENO_SMMU_PRIV_H */ > -- > 2.31.1 >
Re: [PATCH v5 5/5] drm/msm: devcoredump iommu fault support
On Thu, Jun 10, 2021 at 02:44:13PM -0700, Rob Clark wrote: > From: Rob Clark > > Wire up support to stall the SMMU on iova fault, and collect a devcore- > dump snapshot for easier debugging of faults. > > Currently this is a6xx-only, but mostly only because so far it is the > only one using adreno-smmu-priv. Acked-by: Jordan Crouse > Signed-off-by: Rob Clark > --- > drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 19 +++- > drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 38 +++- > drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 42 ++ > drivers/gpu/drm/msm/adreno/adreno_gpu.c | 15 +++ > drivers/gpu/drm/msm/msm_gem.h | 1 + > drivers/gpu/drm/msm/msm_gem_submit.c| 1 + > drivers/gpu/drm/msm/msm_gpu.c | 48 + > drivers/gpu/drm/msm/msm_gpu.h | 17 > drivers/gpu/drm/msm/msm_gpummu.c| 5 +++ > drivers/gpu/drm/msm/msm_iommu.c | 11 + > drivers/gpu/drm/msm/msm_mmu.h | 1 + > 11 files changed, 186 insertions(+), 12 deletions(-) > > diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c > b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c > index eb030b00bff4..7a271de9a212 100644 > --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c > +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c > @@ -1200,6 +1200,15 @@ static void a5xx_fault_detect_irq(struct msm_gpu *gpu) > struct drm_device *dev = gpu->dev; > struct msm_ringbuffer *ring = gpu->funcs->active_ring(gpu); > > + /* > + * If stalled on SMMU fault, we could trip the GPU's hang detection, > + * but the fault handler will trigger the devcore dump, and we want > + * to otherwise resume normally rather than killing the submit, so > + * just bail. > + */ > + if (gpu_read(gpu, REG_A5XX_RBBM_STATUS3) & BIT(24)) > + return; > + > DRM_DEV_ERROR(dev->dev, "gpu fault ring %d fence %x status %8.8X rb > %4.4x/%4.4x ib1 %16.16llX/%4.4x ib2 %16.16llX/%4.4x\n", > ring ? ring->id : -1, ring ? ring->seqno : 0, > gpu_read(gpu, REG_A5XX_RBBM_STATUS), > @@ -1523,6 +1532,7 @@ static struct msm_gpu_state *a5xx_gpu_state_get(struct > msm_gpu *gpu) > { > struct a5xx_gpu_state *a5xx_state = kzalloc(sizeof(*a5xx_state), > GFP_KERNEL); > + bool stalled = !!(gpu_read(gpu, REG_A5XX_RBBM_STATUS3) & BIT(24)); > > if (!a5xx_state) > return ERR_PTR(-ENOMEM); > @@ -1535,8 +1545,13 @@ static struct msm_gpu_state *a5xx_gpu_state_get(struct > msm_gpu *gpu) > > a5xx_state->base.rbbm_status = gpu_read(gpu, REG_A5XX_RBBM_STATUS); > > - /* Get the HLSQ regs with the help of the crashdumper */ > - a5xx_gpu_state_get_hlsq_regs(gpu, a5xx_state); > + /* > + * Get the HLSQ regs with the help of the crashdumper, but only if > + * we are not stalled in an iommu fault (in which case the crashdumper > + * would not have access to memory) > + */ > + if (!stalled) > + a5xx_gpu_state_get_hlsq_regs(gpu, a5xx_state); > > a5xx_set_hwcg(gpu, true); > > diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c > b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c > index fc19db10bff1..c3699408bd1f 100644 > --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c > +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c > @@ -1081,6 +1081,16 @@ static int a6xx_fault_handler(void *arg, unsigned long > iova, int flags, void *da > struct msm_gpu *gpu = arg; > struct adreno_smmu_fault_info *info = data; > const char *type = "UNKNOWN"; > + const char *block; > + bool do_devcoredump = info && !READ_ONCE(gpu->crashstate); > + > + /* > + * If we aren't going to be resuming later from fault_worker, then do > + * it now. > + */ > + if (!do_devcoredump) { > + gpu->aspace->mmu->funcs->resume_translation(gpu->aspace->mmu); > + } > > /* >* Print a default message if we couldn't get the data from the > @@ -1104,15 +1114,30 @@ static int a6xx_fault_handler(void *arg, unsigned > long iova, int flags, void *da > else if (info->fsr & ARM_SMMU_FSR_EF) > type = "EXTERNAL"; > > + block = a6xx_fault_block(gpu, info->fsynr1 & 0xff); > + > pr_warn_ratelimited("*** gpu fault: ttbr0=%.16llx iova=%.16lx dir=%s > type=%s source=%s (%u,%u,%u,%u)\n", > info->ttbr0, iova, > - flags & IOMMU_FAULT_WRITE ? "WRITE" : "READ", type, > - a6xx_fault_block(gpu, info->fsynr1 & 0xff), > + flags & IOMMU_FAULT_WRITE ? "WRITE" : "READ", > + type, block, > gpu_read(gpu, REG_A6XX_CP_SCRATCH_REG(4)), > gpu_read(gpu, REG_A6XX_CP_SCRATCH_REG(5)), > gpu_read(gpu, REG_A6XX_CP_SCRATCH_REG(6)), > gpu_read(gpu, REG_A6XX_CP_SCRATCH_REG(7))); > > + if (do_devcor
[PATCH] drm/nouveau/gk20a: fix NULL dereference on allocation failure
If memory allocation fails, `node->base.imem` does not get populated, causing a NULL pointer dereference on instobj destruction. Fix this by dereferencing it only if the allocation was successful. Signed-off-by: Mikko Perttunen --- drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c index 648ecf5a8fbc..66d60d8bec60 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c @@ -296,12 +296,12 @@ gk20a_instobj_dtor_dma(struct nvkm_memory *memory) { struct gk20a_instobj_dma *node = gk20a_instobj_dma(memory); struct gk20a_instmem *imem = node->base.imem; - struct device *dev = imem->base.subdev.device->dev; if (unlikely(!node->base.vaddr)) goto out; - dma_free_attrs(dev, (u64)node->base.mn->length << PAGE_SHIFT, + dma_free_attrs(imem->base.subdev.device->dev, + (u64)node->base.mn->length << PAGE_SHIFT, node->base.vaddr, node->handle, imem->attrs); out: -- 2.30.1
Re: [Intel-gfx] [PATCH] drm/i915: Fix busy ioctl commentary
On Fri, 11 Jun 2021 at 14:22, Tvrtko Ursulin wrote: > > From: Tvrtko Ursulin > > Just tidy one instance of incorrect context parameter name and a stray > sentence ending from before reporting was converted to be class based. > > Signed-off-by: Tvrtko Ursulin Reviewed-by: Matthew Auld
Re: [PATCH 2/7] dma-buf: add dma_fence_chain_alloc/free
On Fri, Jun 11, 2021 at 1:48 PM Christian König wrote: > > Am 11.06.21 um 09:54 schrieb Daniel Vetter: > > On Thu, Jun 10, 2021 at 11:17:55AM +0200, Christian König wrote: > >> Add a common allocation helper. Cleaning up the mix of kzalloc/kmalloc > >> and some unused code in the selftest. > >> > >> Signed-off-by: Christian König > >> --- > >> drivers/dma-buf/st-dma-fence-chain.c | 16 -- > >> drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c| 4 ++-- > >> drivers/gpu/drm/drm_syncobj.c | 6 ++--- > >> .../gpu/drm/i915/gem/i915_gem_execbuffer.c| 6 ++--- > >> drivers/gpu/drm/msm/msm_gem_submit.c | 6 ++--- > >> include/linux/dma-fence-chain.h | 22 +++ > >> 6 files changed, 35 insertions(+), 25 deletions(-) > >> > >> diff --git a/drivers/dma-buf/st-dma-fence-chain.c > >> b/drivers/dma-buf/st-dma-fence-chain.c > >> index 9525f7f56119..8ce1ea59d31b 100644 > >> --- a/drivers/dma-buf/st-dma-fence-chain.c > >> +++ b/drivers/dma-buf/st-dma-fence-chain.c > >> @@ -58,28 +58,20 @@ static struct dma_fence *mock_fence(void) > >> return &f->base; > >> } > >> > >> -static inline struct mock_chain { > >> -struct dma_fence_chain base; > >> -} *to_mock_chain(struct dma_fence *f) { > >> -return container_of(f, struct mock_chain, base.base); > >> -} > >> - > >> static struct dma_fence *mock_chain(struct dma_fence *prev, > >> struct dma_fence *fence, > >> u64 seqno) > >> { > >> -struct mock_chain *f; > >> +struct dma_fence_chain *f; > >> > >> -f = kmalloc(sizeof(*f), GFP_KERNEL); > >> +f = dma_fence_chain_alloc(); > >> if (!f) > >> return NULL; > >> > >> -dma_fence_chain_init(&f->base, > >> - dma_fence_get(prev), > >> - dma_fence_get(fence), > >> +dma_fence_chain_init(f, dma_fence_get(prev), dma_fence_get(fence), > >> seqno); > >> > >> -return &f->base.base; > >> +return &f->base; > >> } > >> > >> static int sanitycheck(void *arg) > >> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > >> b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > >> index 90136f9dedd6..325e82621467 100644 > >> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > >> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > >> @@ -1124,7 +1124,7 @@ static int > >> amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p > >> > >> dep->chain = NULL; > >> if (syncobj_deps[i].point) { > >> -dep->chain = kmalloc(sizeof(*dep->chain), GFP_KERNEL); > >> +dep->chain = dma_fence_chain_alloc(); > >> if (!dep->chain) > >> return -ENOMEM; > >> } > >> @@ -1132,7 +1132,7 @@ static int > >> amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p > >> dep->syncobj = drm_syncobj_find(p->filp, > >> syncobj_deps[i].handle); > >> if (!dep->syncobj) { > >> -kfree(dep->chain); > >> +dma_fence_chain_free(dep->chain); > >> return -EINVAL; > >> } > >> dep->point = syncobj_deps[i].point; > >> diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c > >> index fdd2ec87cdd1..1c5b9ef6da37 100644 > >> --- a/drivers/gpu/drm/drm_syncobj.c > >> +++ b/drivers/gpu/drm/drm_syncobj.c > >> @@ -861,7 +861,7 @@ static int drm_syncobj_transfer_to_timeline(struct > >> drm_file *file_private, > >> &fence); > >> if (ret) > >> goto err; > >> -chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); > >> +chain = dma_fence_chain_alloc(); > >> if (!chain) { > >> ret = -ENOMEM; > >> goto err1; > >> @@ -1402,10 +1402,10 @@ drm_syncobj_timeline_signal_ioctl(struct > >> drm_device *dev, void *data, > >> goto err_points; > >> } > >> for (i = 0; i < args->count_handles; i++) { > >> -chains[i] = kzalloc(sizeof(struct dma_fence_chain), > >> GFP_KERNEL); > >> +chains[i] = dma_fence_chain_alloc(); > >> if (!chains[i]) { > >> for (j = 0; j < i; j++) > >> -kfree(chains[j]); > >> +dma_fence_chain_free(chains[j]); > >> ret = -ENOMEM; > >> goto err_chains; > >> } > >> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > >> b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > >> index 66789111a24b..a22cb86730b3 100644 > >> --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > >> +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > >> @@ -2983,7 +2983,7 @@ __free_fence_array(struct eb_fence *fences, unsigned > >>
Re: [PATCH 1/5] dma-buf: fix dma_resv_test_signaled test_all handling
On Fri, Jun 11, 2021 at 02:02:57PM +0200, Christian König wrote: > As the name implies if testing all fences is requested we > should indeed test all fences and not skip the exclusive > one because we see shared ones. > > Signed-off-by: Christian König Hm I thought we've had the rule that when both fences exist, then collectively the shared ones must signale no earlier than the exclusive one. That's at least the contract we've implemented in dma_resv.h. But I've also found a bunch of drivers who are a lot more yolo on this. I think there's a solid case here to just always take all the fences if we ask for all the shared ones, but if we go that way then I'd say - clear kerneldoc patch to really hammer this in (currently we're not good at all in this regard) - going through drivers a bit to check for this (I have some of that done already in my earlier series, need to respin it and send it out) But I'm kinda not seeing why this needs to be in this patch series here. -Daniel > --- > drivers/dma-buf/dma-resv.c | 33 - > 1 file changed, 12 insertions(+), 21 deletions(-) > > diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c > index f26c71747d43..c66bfdde9454 100644 > --- a/drivers/dma-buf/dma-resv.c > +++ b/drivers/dma-buf/dma-resv.c > @@ -615,25 +615,21 @@ static inline int dma_resv_test_signaled_single(struct > dma_fence *passed_fence) > */ > bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all) > { > - unsigned int seq, shared_count; > + struct dma_fence *fence; > + unsigned int seq; > int ret; > > rcu_read_lock(); > retry: > ret = true; > - shared_count = 0; > seq = read_seqcount_begin(&obj->seq); > > if (test_all) { > struct dma_resv_list *fobj = dma_resv_shared_list(obj); > - unsigned int i; > - > - if (fobj) > - shared_count = fobj->shared_count; > + unsigned int i, shared_count; > > + shared_count = fobj ? fobj->shared_count : 0; > for (i = 0; i < shared_count; ++i) { > - struct dma_fence *fence; > - > fence = rcu_dereference(fobj->shared[i]); > ret = dma_resv_test_signaled_single(fence); > if (ret < 0) > @@ -641,24 +637,19 @@ bool dma_resv_test_signaled(struct dma_resv *obj, bool > test_all) > else if (!ret) > break; > } > - > - if (read_seqcount_retry(&obj->seq, seq)) > - goto retry; > } > > - if (!shared_count) { > - struct dma_fence *fence_excl = dma_resv_excl_fence(obj); > - > - if (fence_excl) { > - ret = dma_resv_test_signaled_single(fence_excl); > - if (ret < 0) > - goto retry; > + fence = dma_resv_excl_fence(obj); > + if (fence) { > + ret = dma_resv_test_signaled_single(fence); > + if (ret < 0) > + goto retry; > > - if (read_seqcount_retry(&obj->seq, seq)) > - goto retry; > - } > } > > + if (read_seqcount_retry(&obj->seq, seq)) > + goto retry; > + > rcu_read_unlock(); > return ret; > } > -- > 2.25.1 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
Re: [PATCH 3/5] dma-buf: add dma_fence_chain_alloc/free v2
On Fri, Jun 11, 2021 at 02:02:59PM +0200, Christian König wrote: > Add a common allocation helper. Cleaning up the mix of kzalloc/kmalloc > and some unused code in the selftest. > > v2: polish kernel doc a bit > > Signed-off-by: Christian König > Reviewed-by: Daniel Vetter Given how absolutely wrong I was I'm not sure this r-b here is justified :-) > --- > drivers/dma-buf/st-dma-fence-chain.c | 16 - > drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c| 4 ++-- > drivers/gpu/drm/drm_syncobj.c | 6 ++--- > .../gpu/drm/i915/gem/i915_gem_execbuffer.c| 6 ++--- > drivers/gpu/drm/msm/msm_gem_submit.c | 6 ++--- > include/linux/dma-fence-chain.h | 23 +++ > 6 files changed, 36 insertions(+), 25 deletions(-) > > diff --git a/drivers/dma-buf/st-dma-fence-chain.c > b/drivers/dma-buf/st-dma-fence-chain.c > index 9525f7f56119..8ce1ea59d31b 100644 > --- a/drivers/dma-buf/st-dma-fence-chain.c > +++ b/drivers/dma-buf/st-dma-fence-chain.c > @@ -58,28 +58,20 @@ static struct dma_fence *mock_fence(void) > return &f->base; > } > > -static inline struct mock_chain { > - struct dma_fence_chain base; > -} *to_mock_chain(struct dma_fence *f) { > - return container_of(f, struct mock_chain, base.base); > -} > - > static struct dma_fence *mock_chain(struct dma_fence *prev, > struct dma_fence *fence, > u64 seqno) > { > - struct mock_chain *f; > + struct dma_fence_chain *f; > > - f = kmalloc(sizeof(*f), GFP_KERNEL); > + f = dma_fence_chain_alloc(); > if (!f) > return NULL; > > - dma_fence_chain_init(&f->base, > - dma_fence_get(prev), > - dma_fence_get(fence), > + dma_fence_chain_init(f, dma_fence_get(prev), dma_fence_get(fence), >seqno); > > - return &f->base.base; > + return &f->base; > } > > static int sanitycheck(void *arg) > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > index 90136f9dedd6..325e82621467 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > @@ -1124,7 +1124,7 @@ static int > amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p > > dep->chain = NULL; > if (syncobj_deps[i].point) { > - dep->chain = kmalloc(sizeof(*dep->chain), GFP_KERNEL); > + dep->chain = dma_fence_chain_alloc(); > if (!dep->chain) > return -ENOMEM; > } > @@ -1132,7 +1132,7 @@ static int > amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p > dep->syncobj = drm_syncobj_find(p->filp, > syncobj_deps[i].handle); > if (!dep->syncobj) { > - kfree(dep->chain); > + dma_fence_chain_free(dep->chain); > return -EINVAL; > } > dep->point = syncobj_deps[i].point; > diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c > index fdd2ec87cdd1..1c5b9ef6da37 100644 > --- a/drivers/gpu/drm/drm_syncobj.c > +++ b/drivers/gpu/drm/drm_syncobj.c > @@ -861,7 +861,7 @@ static int drm_syncobj_transfer_to_timeline(struct > drm_file *file_private, >&fence); > if (ret) > goto err; > - chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); > + chain = dma_fence_chain_alloc(); > if (!chain) { > ret = -ENOMEM; > goto err1; > @@ -1402,10 +1402,10 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device > *dev, void *data, > goto err_points; > } > for (i = 0; i < args->count_handles; i++) { > - chains[i] = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); > + chains[i] = dma_fence_chain_alloc(); > if (!chains[i]) { > for (j = 0; j < i; j++) > - kfree(chains[j]); > + dma_fence_chain_free(chains[j]); > ret = -ENOMEM; > goto err_chains; > } > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > index 66789111a24b..a22cb86730b3 100644 > --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c > @@ -2983,7 +2983,7 @@ __free_fence_array(struct eb_fence *fences, unsigned > int n) > while (n--) { > drm_syncobj_put(ptr_mask_bits(fences[n].syncobj, 2)); > dma_fence_put(fences[n].dma_fence); > - kfree(fences[n].chain_fence); > + dma_fence_chain_free(fences[n].chain_
Re: [PATCH 1/5] dma-buf: fix dma_resv_test_signaled test_all handling
Am 11.06.21 um 16:47 schrieb Daniel Vetter: On Fri, Jun 11, 2021 at 02:02:57PM +0200, Christian König wrote: As the name implies if testing all fences is requested we should indeed test all fences and not skip the exclusive one because we see shared ones. Signed-off-by: Christian König Hm I thought we've had the rule that when both fences exist, then collectively the shared ones must signale no earlier than the exclusive one. That's at least the contract we've implemented in dma_resv.h. But I've also found a bunch of drivers who are a lot more yolo on this. I think there's a solid case here to just always take all the fences if we ask for all the shared ones, but if we go that way then I'd say - clear kerneldoc patch to really hammer this in (currently we're not good at all in this regard) - going through drivers a bit to check for this (I have some of that done already in my earlier series, need to respin it and send it out) But I'm kinda not seeing why this needs to be in this patch series here. You mentioned that this is a problem in the last patch and if you ask me that's just a bug or at least very inconsistent. See dma_resv_wait_timeout() always waits for all fences, including the exclusive one even if shared ones are present. But dma_resv_test_signaled() ignores the exclusive one if shared ones are present. The only other driver I could find trying to make use of this is nouveau and I already provided a fix for this as well. I just think that this is the more defensive approach to fix this and have at least the core functions consistent on the handling. Christian. -Daniel --- drivers/dma-buf/dma-resv.c | 33 - 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index f26c71747d43..c66bfdde9454 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -615,25 +615,21 @@ static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence) */ bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all) { - unsigned int seq, shared_count; + struct dma_fence *fence; + unsigned int seq; int ret; rcu_read_lock(); retry: ret = true; - shared_count = 0; seq = read_seqcount_begin(&obj->seq); if (test_all) { struct dma_resv_list *fobj = dma_resv_shared_list(obj); - unsigned int i; - - if (fobj) - shared_count = fobj->shared_count; + unsigned int i, shared_count; + shared_count = fobj ? fobj->shared_count : 0; for (i = 0; i < shared_count; ++i) { - struct dma_fence *fence; - fence = rcu_dereference(fobj->shared[i]); ret = dma_resv_test_signaled_single(fence); if (ret < 0) @@ -641,24 +637,19 @@ bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all) else if (!ret) break; } - - if (read_seqcount_retry(&obj->seq, seq)) - goto retry; } - if (!shared_count) { - struct dma_fence *fence_excl = dma_resv_excl_fence(obj); - - if (fence_excl) { - ret = dma_resv_test_signaled_single(fence_excl); - if (ret < 0) - goto retry; + fence = dma_resv_excl_fence(obj); + if (fence) { + ret = dma_resv_test_signaled_single(fence); + if (ret < 0) + goto retry; - if (read_seqcount_retry(&obj->seq, seq)) - goto retry; - } } + if (read_seqcount_retry(&obj->seq, seq)) + goto retry; + rcu_read_unlock(); return ret; } -- 2.25.1
Re: [PATCH 3/5] dma-buf: add dma_fence_chain_alloc/free v2
Am 11.06.21 um 16:52 schrieb Daniel Vetter: On Fri, Jun 11, 2021 at 02:02:59PM +0200, Christian König wrote: Add a common allocation helper. Cleaning up the mix of kzalloc/kmalloc and some unused code in the selftest. v2: polish kernel doc a bit Signed-off-by: Christian König Reviewed-by: Daniel Vetter Given how absolutely wrong I was I'm not sure this r-b here is justified :-) Ups, that was also not added intentionally. It's just to hot in my flat and to few hours till the weekend. --- drivers/dma-buf/st-dma-fence-chain.c | 16 - drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c| 4 ++-- drivers/gpu/drm/drm_syncobj.c | 6 ++--- .../gpu/drm/i915/gem/i915_gem_execbuffer.c| 6 ++--- drivers/gpu/drm/msm/msm_gem_submit.c | 6 ++--- include/linux/dma-fence-chain.h | 23 +++ 6 files changed, 36 insertions(+), 25 deletions(-) diff --git a/drivers/dma-buf/st-dma-fence-chain.c b/drivers/dma-buf/st-dma-fence-chain.c index 9525f7f56119..8ce1ea59d31b 100644 --- a/drivers/dma-buf/st-dma-fence-chain.c +++ b/drivers/dma-buf/st-dma-fence-chain.c @@ -58,28 +58,20 @@ static struct dma_fence *mock_fence(void) return &f->base; } -static inline struct mock_chain { - struct dma_fence_chain base; -} *to_mock_chain(struct dma_fence *f) { - return container_of(f, struct mock_chain, base.base); -} - static struct dma_fence *mock_chain(struct dma_fence *prev, struct dma_fence *fence, u64 seqno) { - struct mock_chain *f; + struct dma_fence_chain *f; - f = kmalloc(sizeof(*f), GFP_KERNEL); + f = dma_fence_chain_alloc(); if (!f) return NULL; - dma_fence_chain_init(&f->base, -dma_fence_get(prev), -dma_fence_get(fence), + dma_fence_chain_init(f, dma_fence_get(prev), dma_fence_get(fence), seqno); - return &f->base.base; + return &f->base; } static int sanitycheck(void *arg) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 90136f9dedd6..325e82621467 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1124,7 +1124,7 @@ static int amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p dep->chain = NULL; if (syncobj_deps[i].point) { - dep->chain = kmalloc(sizeof(*dep->chain), GFP_KERNEL); + dep->chain = dma_fence_chain_alloc(); if (!dep->chain) return -ENOMEM; } @@ -1132,7 +1132,7 @@ static int amdgpu_cs_process_syncobj_timeline_out_dep(struct amdgpu_cs_parser *p dep->syncobj = drm_syncobj_find(p->filp, syncobj_deps[i].handle); if (!dep->syncobj) { - kfree(dep->chain); + dma_fence_chain_free(dep->chain); return -EINVAL; } dep->point = syncobj_deps[i].point; diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index fdd2ec87cdd1..1c5b9ef6da37 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -861,7 +861,7 @@ static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private, &fence); if (ret) goto err; - chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); + chain = dma_fence_chain_alloc(); if (!chain) { ret = -ENOMEM; goto err1; @@ -1402,10 +1402,10 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data, goto err_points; } for (i = 0; i < args->count_handles; i++) { - chains[i] = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL); + chains[i] = dma_fence_chain_alloc(); if (!chains[i]) { for (j = 0; j < i; j++) - kfree(chains[j]); + dma_fence_chain_free(chains[j]); ret = -ENOMEM; goto err_chains; } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 66789111a24b..a22cb86730b3 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -2983,7 +2983,7 @@ __free_fence_array(struct eb_fence *fences, unsigned int n) while (n--) { drm_syncobj_put(ptr_mask_bits(fences[n].syncobj, 2)); dma_fence_put(fences[n].dma_fence); - kfree(fences[n].chain_fence); + d
[PATCH v2 0/4] drm/i915: Move system memory to TTM for discrete
Early implementation of moving system memory for discrete cards over to TTM. We first add the notion of objects being migratable under the object lock to i915 gem, and add some asserts to verify that objects are either locked or pinned when the placement is checked by the gem code. Patch 2 and 3 deals with updating the i915 gem bookkeeping after a TTM move, Patch 4 moves system over from shmem to TTM for discrete Note that the mock device doesn't consider itself discrete so the TTM system path is not checked by the mock selftests. v2: - Style fixes (reported by Matthew Auld) - Drop the last patch (migration) It needs selftests and some additional work. - Unconditionally add VM_IO at mmap time. Thomas Hellström (4): drm/i915: Update object placement flags to be mutable drm/i915/ttm: Adjust gem flags and caching settings after a move drm/i915/ttm: Calculate the object placement at get_pages time drm/i915/ttm: Use TTM for system memory drivers/gpu/drm/i915/gem/i915_gem_internal.c | 4 +- drivers/gpu/drm/i915/gem/i915_gem_mman.c | 12 +- drivers/gpu/drm/i915/gem/i915_gem_object.c| 38 +++ drivers/gpu/drm/i915/gem/i915_gem_object.h| 14 +- .../gpu/drm/i915/gem/i915_gem_object_types.h | 20 +- drivers/gpu/drm/i915/gem/i915_gem_pages.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_phys.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 10 +- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 224 ++ drivers/gpu/drm/i915/gem/i915_gem_userptr.c | 4 +- .../drm/i915/gem/selftests/huge_gem_object.c | 4 +- .../gpu/drm/i915/gem/selftests/huge_pages.c | 5 +- .../drm/i915/gem/selftests/i915_gem_mman.c| 4 +- .../drm/i915/gem/selftests/i915_gem_phys.c| 3 +- drivers/gpu/drm/i915/i915_drv.h | 3 - drivers/gpu/drm/i915/intel_memory_region.c| 7 +- drivers/gpu/drm/i915/intel_memory_region.h| 8 + drivers/gpu/drm/i915/intel_region_ttm.c | 8 +- drivers/gpu/drm/i915/intel_region_ttm.h | 2 + 19 files changed, 278 insertions(+), 96 deletions(-) -- 2.31.1
[PATCH v2 1/4] drm/i915: Update object placement flags to be mutable
The object ops i915_GEM_OBJECT_HAS_IOMEM and the object I915_BO_ALLOC_STRUCT_PAGE flags are considered immutable by much of our code. Introduce a new mem_flags member to hold these and make sure checks for these flags being set are either done under the object lock or with pages properly pinned. The flags will change during migration under the object lock. Signed-off-by: Thomas Hellström v2: - Unconditionally set VM_IO on our VMAs in line with the rest core gem and TTM. Since the bo might be migrated while the VMA is still alive, there is no sense, whether or not it maps iomem might change. --- drivers/gpu/drm/i915/gem/i915_gem_internal.c | 4 +- drivers/gpu/drm/i915/gem/i915_gem_mman.c | 12 +++--- drivers/gpu/drm/i915/gem/i915_gem_object.c| 38 +++ drivers/gpu/drm/i915/gem/i915_gem_object.h| 14 ++- .../gpu/drm/i915/gem/i915_gem_object_types.h | 20 +- drivers/gpu/drm/i915/gem/i915_gem_pages.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_phys.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 10 +++-- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_userptr.c | 4 +- .../drm/i915/gem/selftests/huge_gem_object.c | 4 +- .../gpu/drm/i915/gem/selftests/huge_pages.c | 5 +-- .../drm/i915/gem/selftests/i915_gem_mman.c| 4 +- .../drm/i915/gem/selftests/i915_gem_phys.c| 3 +- 14 files changed, 79 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_internal.c b/drivers/gpu/drm/i915/gem/i915_gem_internal.c index ce6b664b10aa..13b217f75055 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_internal.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_internal.c @@ -177,8 +177,8 @@ i915_gem_object_create_internal(struct drm_i915_private *i915, return ERR_PTR(-ENOMEM); drm_gem_private_object_init(&i915->drm, &obj->base, size); - i915_gem_object_init(obj, &i915_gem_object_internal_ops, &lock_class, -I915_BO_ALLOC_STRUCT_PAGE); + i915_gem_object_init(obj, &i915_gem_object_internal_ops, &lock_class, 0); + obj->mem_flags |= I915_BO_FLAG_STRUCT_PAGE; /* * Mark the object as volatile, such that the pages are marked as diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c index 2fd155742bd2..6497a2dbdab9 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@ -684,7 +684,7 @@ __assign_mmap_offset(struct drm_i915_gem_object *obj, if (mmap_type != I915_MMAP_TYPE_GTT && !i915_gem_object_has_struct_page(obj) && - !i915_gem_object_type_has(obj, I915_GEM_OBJECT_HAS_IOMEM)) + !i915_gem_object_has_iomem(obj)) return -ENODEV; mmo = mmap_offset_attach(obj, mmap_type, file); @@ -708,7 +708,12 @@ __assign_mmap_offset_handle(struct drm_file *file, if (!obj) return -ENOENT; + err = i915_gem_object_lock_interruptible(obj, NULL); + if (err) + goto out_put; err = __assign_mmap_offset(obj, mmap_type, offset, file); + i915_gem_object_unlock(obj); +out_put: i915_gem_object_put(obj); return err; } @@ -932,10 +937,7 @@ int i915_gem_mmap(struct file *filp, struct vm_area_struct *vma) return PTR_ERR(anon); } - vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; - - if (i915_gem_object_has_iomem(obj)) - vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO; /* * We keep the ref on mmo->obj, not vm_file, but we require diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index cf18c430d51f..07e8ff9a8aae 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -475,6 +475,44 @@ bool i915_gem_object_migratable(struct drm_i915_gem_object *obj) return obj->mm.n_placements > 1; } +/** + * i915_gem_object_has_struct_page - Whether the object is page-backed + * @obj: The object to query. + * + * This function should only be called while the object is locked or pinned, + * otherwise the page backing may change under the caller. + * + * Return: True if page-backed, false otherwise. + */ +bool i915_gem_object_has_struct_page(const struct drm_i915_gem_object *obj) +{ +#ifdef CONFIG_LOCKDEP + if (IS_DGFX(to_i915(obj->base.dev)) && + i915_gem_object_evictable((void __force *)obj)) + assert_object_held_shared(obj); +#endif + return obj->mem_flags & I915_BO_FLAG_STRUCT_PAGE; +} + +/** + * i915_gem_object_has_iomem - Whether the object is iomem-backed + * @obj: The object to query. + * + * This function should only be called while the object is locked or pinned, + * otherwise the iomem backing may change under the caller. + * + * Retur
[PATCH v2 3/4] drm/i915/ttm: Calculate the object placement at get_pages time
Instead of relying on a static placement, calculate at get_pages() time. This should work for LMEM regions and system for now. For stolen we need to take preallocated range into account. That well be added later. Signed-off-by: Thomas Hellström --- v2: - Fixed a style issue (Reported by Matthew Auld) --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 92 ++--- drivers/gpu/drm/i915/intel_region_ttm.c | 8 ++- drivers/gpu/drm/i915/intel_region_ttm.h | 2 + 3 files changed, 75 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 45ef1d101937..fd3d11728229 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -24,6 +24,11 @@ #define I915_TTM_PRIO_NO_PAGES 1 #define I915_TTM_PRIO_HAS_PAGES 2 +/* + * Size of struct ttm_place vector in on-stack struct ttm_placement allocs + */ +#define I915_TTM_MAX_PLACEMENTS 10 + /** * struct i915_ttm_tt - TTM page vector with additional private information * @ttm: The base TTM page vector. @@ -42,32 +47,18 @@ struct i915_ttm_tt { struct sg_table *cached_st; }; -static const struct ttm_place lmem0_sys_placement_flags[] = { - { - .fpfn = 0, - .lpfn = 0, - .mem_type = I915_PL_LMEM0, - .flags = 0, - }, { - .fpfn = 0, - .lpfn = 0, - .mem_type = I915_PL_SYSTEM, - .flags = 0, - } -}; - -static struct ttm_placement i915_lmem0_placement = { - .num_placement = 1, - .placement = &lmem0_sys_placement_flags[0], - .num_busy_placement = 1, - .busy_placement = &lmem0_sys_placement_flags[0], +static const struct ttm_place sys_placement_flags = { + .fpfn = 0, + .lpfn = 0, + .mem_type = I915_PL_SYSTEM, + .flags = 0, }; static struct ttm_placement i915_sys_placement = { .num_placement = 1, - .placement = &lmem0_sys_placement_flags[1], + .placement = &sys_placement_flags, .num_busy_placement = 1, - .busy_placement = &lmem0_sys_placement_flags[1], + .busy_placement = &sys_placement_flags, }; static bool gpu_binds_iomem(struct ttm_resource *mem) @@ -83,6 +74,55 @@ static bool cpu_maps_iomem(struct ttm_resource *mem) static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj); +static enum ttm_caching +i915_ttm_select_tt_caching(const struct drm_i915_gem_object *obj) +{ + /* +* Objects only allowed in system get cached cpu-mappings. +* Other objects get WC mapping for now. Even if in system. +*/ + if (obj->mm.region->type == INTEL_MEMORY_SYSTEM && + obj->mm.n_placements <= 1) + return ttm_cached; + + return ttm_write_combined; +} + +static void +i915_ttm_place_from_region(const struct intel_memory_region *mr, + struct ttm_place *place) +{ + memset(place, 0, sizeof(*place)); + place->mem_type = intel_region_to_ttm_type(mr); +} + +static void +i915_ttm_placement_from_obj(const struct drm_i915_gem_object *obj, + struct ttm_place *requested, + struct ttm_place *busy, + struct ttm_placement *placement) +{ + unsigned int num_allowed = obj->mm.n_placements; + unsigned int i; + + placement->num_placement = 1; + i915_ttm_place_from_region(num_allowed ? obj->mm.placements[0] : + obj->mm.region, requested); + + /* Cache this on object? */ + placement->num_busy_placement = num_allowed; + for (i = 0; i < placement->num_busy_placement; ++i) + i915_ttm_place_from_region(obj->mm.placements[i], busy + i); + + if (num_allowed == 0) { + *busy = *requested; + placement->num_busy_placement = 1; + } + + placement->placement = requested; + placement->busy_placement = busy; +} + static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags) { @@ -100,7 +140,8 @@ static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo, man->use_tt) page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC; - ret = ttm_tt_init(&i915_tt->ttm, bo, page_flags, ttm_write_combined); + ret = ttm_tt_init(&i915_tt->ttm, bo, page_flags, + i915_ttm_select_tt_caching(obj)); if (ret) { kfree(i915_tt); return NULL; @@ -465,10 +506,13 @@ static int i915_ttm_get_pages(struct drm_i915_gem_object *obj) .no_wait_gpu = false, }; struct sg_table *st; + struct ttm_place requested, busy[I915_TTM_MAX_PLACEMENTS]; + struct ttm_placement placement; int ret; /* Move to the requested placement. */ - ret = ttm_bo_valid
[PATCH v2 2/4] drm/i915/ttm: Adjust gem flags and caching settings after a move
After a TTM move we need to update the i915 gem flags and caching settings to reflect the new placement. Also introduce gpu_binds_iomem() and cpu_maps_iomem() to clean up the various ways we previously used to detect this. Finally, initialize the TTM object reserved to be able to update flags and caching before anyone else gets hold of the object. Signed-off-by: Thomas Hellström --- v2: - Style fixes (Reported by Matthew Auld) --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 112 +++- 1 file changed, 90 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 33ab47f1e05b..45ef1d101937 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -70,6 +70,17 @@ static struct ttm_placement i915_sys_placement = { .busy_placement = &lmem0_sys_placement_flags[1], }; +static bool gpu_binds_iomem(struct ttm_resource *mem) +{ + return mem->mem_type != TTM_PL_SYSTEM; +} + +static bool cpu_maps_iomem(struct ttm_resource *mem) +{ + /* Once / if we support GGTT, this is also false for cached ttm_tts */ + return mem->mem_type != TTM_PL_SYSTEM; +} + static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj); static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo, @@ -175,6 +186,41 @@ static void i915_ttm_free_cached_io_st(struct drm_i915_gem_object *obj) obj->ttm.cached_io_st = NULL; } +static void +i915_ttm_adjust_domains_after_cpu_move(struct drm_i915_gem_object *obj) +{ + struct ttm_buffer_object *bo = i915_gem_to_ttm(obj); + + if (cpu_maps_iomem(bo->resource) || bo->ttm->caching != ttm_cached) { + obj->write_domain = I915_GEM_DOMAIN_WC; + obj->read_domains = I915_GEM_DOMAIN_WC; + } else { + obj->write_domain = I915_GEM_DOMAIN_CPU; + obj->read_domains = I915_GEM_DOMAIN_CPU; + } +} + +static void i915_ttm_adjust_gem_after_move(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *i915 = to_i915(obj->base.dev); + struct ttm_buffer_object *bo = i915_gem_to_ttm(obj); + unsigned int cache_level; + + obj->mem_flags &= ~(I915_BO_FLAG_STRUCT_PAGE | I915_BO_FLAG_IOMEM); + + obj->mem_flags |= cpu_maps_iomem(bo->resource) ? I915_BO_FLAG_IOMEM : + I915_BO_FLAG_STRUCT_PAGE; + + if ((HAS_LLC(i915) || HAS_SNOOP(i915)) && !gpu_binds_iomem(bo->resource) && + bo->ttm->caching == ttm_cached) { + cache_level = I915_CACHE_LLC; + } else { + cache_level = I915_CACHE_NONE; + } + + i915_gem_object_set_cache_coherency(obj, cache_level); +} + static void i915_ttm_purge(struct drm_i915_gem_object *obj) { struct ttm_buffer_object *bo = i915_gem_to_ttm(obj); @@ -190,8 +236,10 @@ static void i915_ttm_purge(struct drm_i915_gem_object *obj) /* TTM's purge interface. Note that we might be reentering. */ ret = ttm_bo_validate(bo, &place, &ctx); - if (!ret) { + obj->write_domain = 0; + obj->read_domains = 0; + i915_ttm_adjust_gem_after_move(obj); i915_ttm_free_cached_io_st(obj); obj->mm.madv = __I915_MADV_PURGED; } @@ -273,12 +321,15 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj, struct ttm_resource *res) { struct ttm_buffer_object *bo = i915_gem_to_ttm(obj); - struct ttm_resource_manager *man = - ttm_manager_type(bo->bdev, res->mem_type); - if (man->use_tt) + if (!gpu_binds_iomem(res)) return i915_ttm_tt_get_st(bo->ttm); + /* +* If CPU mapping differs, we need to add the ttm_tt pages to +* the resulting st. Might make sense for GGTT. +*/ + GEM_WARN_ON(!cpu_maps_iomem(res)); return intel_region_ttm_node_to_st(obj->mm.region, res); } @@ -290,8 +341,6 @@ static int i915_ttm_move(struct ttm_buffer_object *bo, bool evict, struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); struct ttm_resource_manager *dst_man = ttm_manager_type(bo->bdev, dst_mem->mem_type); - struct ttm_resource_manager *src_man = - ttm_manager_type(bo->bdev, bo->resource->mem_type); struct intel_memory_region *dst_reg, *src_reg; union { struct ttm_kmap_iter_tt tt; @@ -332,34 +381,36 @@ static int i915_ttm_move(struct ttm_buffer_object *bo, bool evict, if (IS_ERR(dst_st)) return PTR_ERR(dst_st); - /* If we start mapping GGTT, we can no longer use man::use_tt here. */ - dst_iter = dst_man->use_tt ? + dst_iter = !cpu_maps_iomem(dst_mem) ? ttm_kmap_iter_tt_init(&_dst_iter.tt, bo->ttm) : ttm_kmap_iter_iomap_init(&_dst_iter.io, &dst_reg->iomap,
[PATCH v2 4/4] drm/i915/ttm: Use TTM for system memory
For discrete, use TTM for both cached and WC system memory. That means we currently rely on the TTM memory accounting / shrinker. For cached system memory we should consider remaining shmem-backed, which can be implemented from our ttm_tt_populate calback. We can then also reuse our own very elaborate shrinker for that memory. Signed-off-by: Thomas Hellström --- v2: - Fix IS_ERR_OR_NULL() check to IS_ERR() (Reported by Matthew Auld) --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c| 22 ++ drivers/gpu/drm/i915/i915_drv.h| 3 --- drivers/gpu/drm/i915/intel_memory_region.c | 7 ++- drivers/gpu/drm/i915/intel_memory_region.h | 8 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index fd3d11728229..0940c1d7c5e6 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -755,3 +755,25 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem, /* i915 wants -ENXIO when out of memory region space. */ return (ret == -ENOSPC) ? -ENXIO : ret; } + +static const struct intel_memory_region_ops ttm_system_region_ops = { + .init_object = __i915_gem_ttm_object_init, +}; + +struct intel_memory_region * +i915_gem_ttm_system_setup(struct drm_i915_private *i915, + u16 type, u16 instance) +{ + struct intel_memory_region *mr; + + mr = intel_memory_region_create(i915, 0, + totalram_pages() << PAGE_SHIFT, + PAGE_SIZE, 0, + type, instance, + &ttm_system_region_ops); + if (IS_ERR(mr)) + return mr; + + intel_memory_region_set_name(mr, "system-ttm"); + return mr; +} diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 38ff2fb89744..9643bebb951d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1751,9 +1751,6 @@ void i915_gem_cleanup_userptr(struct drm_i915_private *dev_priv); void i915_gem_init_early(struct drm_i915_private *dev_priv); void i915_gem_cleanup_early(struct drm_i915_private *dev_priv); -struct intel_memory_region *i915_gem_shmem_setup(struct drm_i915_private *i915, -u16 type, u16 instance); - static inline void i915_gem_drain_freed_objects(struct drm_i915_private *i915) { /* diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c index 12fb5423fd5e..0b016bdb8b84 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.c +++ b/drivers/gpu/drm/i915/intel_memory_region.c @@ -220,7 +220,12 @@ int intel_memory_regions_hw_probe(struct drm_i915_private *i915) instance = intel_region_map[i].instance; switch (type) { case INTEL_MEMORY_SYSTEM: - mem = i915_gem_shmem_setup(i915, type, instance); + if (IS_DGFX(i915)) + mem = i915_gem_ttm_system_setup(i915, type, + instance); + else + mem = i915_gem_shmem_setup(i915, type, + instance); break; case INTEL_MEMORY_STOLEN_LOCAL: mem = i915_gem_stolen_lmem_setup(i915, type, instance); diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h index c7e635d62e1a..1a2bb9fc9de5 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.h +++ b/drivers/gpu/drm/i915/intel_memory_region.h @@ -143,4 +143,12 @@ void intel_memory_region_unreserve(struct intel_memory_region *mem); int intel_memory_region_reserve(struct intel_memory_region *mem, resource_size_t offset, resource_size_t size); + +struct intel_memory_region * +i915_gem_ttm_system_setup(struct drm_i915_private *i915, + u16 type, u16 instance); +struct intel_memory_region * +i915_gem_shmem_setup(struct drm_i915_private *i915, +u16 type, u16 instance); + #endif -- 2.31.1
Re: [PATCH 1/5] dma-buf: fix dma_resv_test_signaled test_all handling
On Fri, Jun 11, 2021 at 04:53:11PM +0200, Christian König wrote: > > > Am 11.06.21 um 16:47 schrieb Daniel Vetter: > > On Fri, Jun 11, 2021 at 02:02:57PM +0200, Christian König wrote: > > > As the name implies if testing all fences is requested we > > > should indeed test all fences and not skip the exclusive > > > one because we see shared ones. > > > > > > Signed-off-by: Christian König > > Hm I thought we've had the rule that when both fences exist, then > > collectively the shared ones must signale no earlier than the exclusive > > one. > > > > That's at least the contract we've implemented in dma_resv.h. But I've > > also found a bunch of drivers who are a lot more yolo on this. > > > > I think there's a solid case here to just always take all the fences if we > > ask for all the shared ones, but if we go that way then I'd say > > - clear kerneldoc patch to really hammer this in (currently we're not good > >at all in this regard) > > - going through drivers a bit to check for this (I have some of that done > >already in my earlier series, need to respin it and send it out) > > > > But I'm kinda not seeing why this needs to be in this patch series here. > > You mentioned that this is a problem in the last patch and if you ask me > that's just a bug or at least very inconsistent. > > See dma_resv_wait_timeout() always waits for all fences, including the > exclusive one even if shared ones are present. But dma_resv_test_signaled() > ignores the exclusive one if shared ones are present. Hm the only one I thought I've mentioned is that dma_buf_poll doesn't use dma_fence_get_rcu_safe where I think it should. Different problem. I think this is one you spotted. > The only other driver I could find trying to make use of this is nouveau and > I already provided a fix for this as well. i915 also does this, and I think I've found a few more. > I just think that this is the more defensive approach to fix this and have > at least the core functions consistent on the handling. Oh fully agree, it's just current dma_resv docs aren't the greatest, and hacking on semantics without updating the docs isn't great. Especially when it's ad-hoc. -Daniel > > Christian. > > > -Daniel > > > > > --- > > > drivers/dma-buf/dma-resv.c | 33 - > > > 1 file changed, 12 insertions(+), 21 deletions(-) > > > > > > diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c > > > index f26c71747d43..c66bfdde9454 100644 > > > --- a/drivers/dma-buf/dma-resv.c > > > +++ b/drivers/dma-buf/dma-resv.c > > > @@ -615,25 +615,21 @@ static inline int > > > dma_resv_test_signaled_single(struct dma_fence *passed_fence) > > >*/ > > > bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all) > > > { > > > - unsigned int seq, shared_count; > > > + struct dma_fence *fence; > > > + unsigned int seq; > > > int ret; > > > rcu_read_lock(); > > > retry: > > > ret = true; > > > - shared_count = 0; > > > seq = read_seqcount_begin(&obj->seq); > > > if (test_all) { > > > struct dma_resv_list *fobj = dma_resv_shared_list(obj); > > > - unsigned int i; > > > - > > > - if (fobj) > > > - shared_count = fobj->shared_count; > > > + unsigned int i, shared_count; > > > + shared_count = fobj ? fobj->shared_count : 0; > > > for (i = 0; i < shared_count; ++i) { > > > - struct dma_fence *fence; > > > - > > > fence = rcu_dereference(fobj->shared[i]); > > > ret = dma_resv_test_signaled_single(fence); > > > if (ret < 0) > > > @@ -641,24 +637,19 @@ bool dma_resv_test_signaled(struct dma_resv *obj, > > > bool test_all) > > > else if (!ret) > > > break; > > > } > > > - > > > - if (read_seqcount_retry(&obj->seq, seq)) > > > - goto retry; > > > } > > > - if (!shared_count) { > > > - struct dma_fence *fence_excl = dma_resv_excl_fence(obj); > > > - > > > - if (fence_excl) { > > > - ret = dma_resv_test_signaled_single(fence_excl); > > > - if (ret < 0) > > > - goto retry; > > > + fence = dma_resv_excl_fence(obj); > > > + if (fence) { > > > + ret = dma_resv_test_signaled_single(fence); > > > + if (ret < 0) > > > + goto retry; > > > - if (read_seqcount_retry(&obj->seq, seq)) > > > - goto retry; > > > - } > > > } > > > + if (read_seqcount_retry(&obj->seq, seq)) > > > + goto retry; > > > + > > > rcu_read_unlock(); > > > return ret; > > > } > > > -- > > > 2.25.1 > > > > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch
Re: [PATCH 5/5] drm/amdgpu: rework dma_resv handling v2
On Fri, Jun 11, 2021 at 02:03:01PM +0200, Christian König wrote: > Drop the workaround and instead implement a better solution. > > Basically we are now chaining all submissions using a dma_fence_chain > container and adding them as exclusive fence to the dma_resv object. > > This way other drivers can still sync to the single exclusive fence > while amdgpu only sync to fences from different processes. > > v2: polish kerneldoc a bit There is no kerneldoc here, and otherwise this patch looks unchanged from the previous round. Hit send a bit too quickly? -Daniel > > Signed-off-by: Christian König > --- > drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 1 + > drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 54 + > drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 65 - > drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 +- > drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 +- > drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 1 - > 6 files changed, 47 insertions(+), 79 deletions(-) > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h > b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h > index a130e766cbdb..c905a4cfc173 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h > @@ -34,6 +34,7 @@ struct amdgpu_fpriv; > struct amdgpu_bo_list_entry { > struct ttm_validate_buffer tv; > struct amdgpu_bo_va *bo_va; > + struct dma_fence_chain *chain; > uint32_tpriority; > struct page **user_pages; > booluser_invalidated; > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > index 325e82621467..f6f3029f958d 100644 > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > @@ -587,6 +587,20 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser > *p, > goto out; > } > > + amdgpu_bo_list_for_each_entry(e, p->bo_list) { > + struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); > + > + e->bo_va = amdgpu_vm_bo_find(vm, bo); > + > + if (bo->tbo.base.dma_buf && !amdgpu_bo_explicit_sync(bo)) { > + e->chain = dma_fence_chain_alloc(); > + if (!e->chain) { > + r = -ENOMEM; > + goto error_validate; > + } > + } > + } > + > amdgpu_cs_get_threshold_for_moves(p->adev, &p->bytes_moved_threshold, > &p->bytes_moved_vis_threshold); > p->bytes_moved = 0; > @@ -614,15 +628,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser > *p, > gws = p->bo_list->gws_obj; > oa = p->bo_list->oa_obj; > > - amdgpu_bo_list_for_each_entry(e, p->bo_list) { > - struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); > - > - /* Make sure we use the exclusive slot for shared BOs */ > - if (bo->prime_shared_count) > - e->tv.num_shared = 0; > - e->bo_va = amdgpu_vm_bo_find(vm, bo); > - } > - > if (gds) { > p->job->gds_base = amdgpu_bo_gpu_offset(gds) >> PAGE_SHIFT; > p->job->gds_size = amdgpu_bo_size(gds) >> PAGE_SHIFT; > @@ -644,8 +649,13 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser > *p, > } > > error_validate: > - if (r) > + if (r) { > + amdgpu_bo_list_for_each_entry(e, p->bo_list) { > + dma_fence_chain_free(e->chain); > + e->chain = NULL; > + } > ttm_eu_backoff_reservation(&p->ticket, &p->validated); > + } > out: > return r; > } > @@ -685,9 +695,17 @@ static void amdgpu_cs_parser_fini(struct > amdgpu_cs_parser *parser, int error, > { > unsigned i; > > - if (error && backoff) > + if (error && backoff) { > + struct amdgpu_bo_list_entry *e; > + > + amdgpu_bo_list_for_each_entry(e, parser->bo_list) { > + dma_fence_chain_free(e->chain); > + e->chain = NULL; > + } > + > ttm_eu_backoff_reservation(&parser->ticket, > &parser->validated); > + } > > for (i = 0; i < parser->num_post_deps; i++) { > drm_syncobj_put(parser->post_deps[i].syncobj); > @@ -1260,6 +1278,20 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, > > amdgpu_vm_move_to_lru_tail(p->adev, &fpriv->vm); > > + amdgpu_bo_list_for_each_entry(e, p->bo_list) { > + struct dma_resv *resv = e->tv.bo->base.resv; > + struct dma_fence_chain *chain = e->chain; > + > + if (!chain) > + continue; > + > + dma_fence_chain_init(chain, dma_resv_excl_fence(resv), > +
Re: [PATCH v10 07/10] mm: Device exclusive memory access
On Fri, Jun 11, 2021 at 01:43:20PM +1000, Alistair Popple wrote: > On Friday, 11 June 2021 11:00:34 AM AEST Peter Xu wrote: > > On Fri, Jun 11, 2021 at 09:17:14AM +1000, Alistair Popple wrote: > > > On Friday, 11 June 2021 9:04:19 AM AEST Peter Xu wrote: > > > > On Fri, Jun 11, 2021 at 12:21:26AM +1000, Alistair Popple wrote: > > > > > > Hmm, the thing is.. to me FOLL_SPLIT_PMD should have similar effect > > > > > > to explicit > > > > > > call split_huge_pmd_address(), afaict. Since both of them use > > > > > > __split_huge_pmd() > > > > > > internally which will generate that unwanted CLEAR notify. > > > > > > > > > > Agree that gup calls __split_huge_pmd() via split_huge_pmd_address() > > > > > which will always CLEAR. However gup only calls > > > > > split_huge_pmd_address() if it > > > > > finds a thp pmd. In follow_pmd_mask() we have: > > > > > > > > > > if (likely(!pmd_trans_huge(pmdval))) > > > > > return follow_page_pte(vma, address, pmd, flags, > > > > > &ctx->pgmap); > > > > > > > > > > So I don't think we have a problem here. > > > > > > > > Sorry I didn't follow here.. We do FOLL_SPLIT_PMD after this check, > > > > right? I > > > > mean, if it's a thp for the current mm, afaict pmd_trans_huge() should > > > > return > > > > true above, so we'll skip follow_page_pte(); then we'll check > > > > FOLL_SPLIT_PMD > > > > and do the split, then the CLEAR notify. Hmm.. Did I miss something? > > > > > > That seems correct - if the thp is not mapped with a pmd we won't split > > > and we > > > won't CLEAR. If there is a thp pmd we will split and CLEAR, but in that > > > case it > > > is fine - we will retry, but the retry will won't CLEAR because the pmd > > > has > > > already been split. > > > > Aha! > > > > > > > > The issue arises with doing it unconditionally in make device exclusive > > > is that > > > you *always* CLEAR even if there is no thp pmd to split. Or at least > > > that's my > > > understanding, please let me know if it doesn't make sense. > > > > Exactly. But if you see what I meant here, even if it can work like this, > > it > > sounds still fragile, isn't it? I just feel something is slightly off > > there.. > > > > IMHO split_huge_pmd() checked pmd before calling __split_huge_pmd() for > > performance, afaict, because if it's not a thp even without locking, then it > > won't be, so further __split_huge_pmd() is not necessary. > > > > IOW, it's very legal if someday we'd like to let split_huge_pmd() call > > __split_huge_pmd() directly, then AFAIU device exclusive API will be the 1st > > one to be broken with that seems-to-be-irrelevant change I'm afraid.. > > Well I would argue the performance of memory notifiers is becoming > increasingly > important, and a change that causes them to be called unnecessarily is > therefore not very legal. Likely the correct fix here is to optimise > __split_huge_pmd() to only call the notifier if it's actually going to split a > pmd. As you said though that's a completely different story which I think > would > be best done as a separate series. Right, maybe I can look a bit more into that later; but my whole point was to express that one functionality shouldn't depend on such a trivial detail of implementation of other modules (thp split in this case). > > > This lets me goes back a step to think about why do we need this notifier at > > all to cover this whole range of make_device_exclusive() procedure.. > > > > What I am thinking is, we're afraid some CPU accesses this page so the pte > > got > > quickly restored when device atomic operation is carrying on. Then with > > this > > notifier we'll be able to cancel it. Makes perfect sense. > > > > However do we really need to register this notifier so early? The thing is > > the > > GPU driver still has all the page locks, so even if there's a race to > > restore > > the ptes, they'll block at taking the page lock until the driver releases > > it. > > > > IOW, I'm wondering whether the "non-fragile" way to do this is not do > > mmu_interval_notifier_insert() that early: what if we register that notifier > > after make_device_exclusive_range() returns but before page_unlock() > > somehow? > > So before page_unlock(), race is protected fully by the lock itself; after > > that, it's done by mmu notifier. Then maybe we don't need to worry about > > all > > these notifications during marking exclusive (while we shouldn't)? > > The notifier is needed to protect against races with pte changes. Once a page > has been marked for exclusive access the driver will update it's page tables > to > allow atomic access to the page. However in the meantime the page could become > unmapped entirely or write protected. > > As I understand things the page lock won't protect against these kind of pte > changes, hence the need for mmu_interval_read_begin/retry which allows the > driver to hold a mutex protecting against invalidations via blocking the > no
Re: [Intel-gfx] [PATCH 0/5] dma-fence, i915: Stop allowing SLAB_TYPESAFE_BY_RCU for dma_fence
On Fri, Jun 11, 2021 at 12:03:31PM +0200, Christian König wrote: > Am 11.06.21 um 11:33 schrieb Daniel Vetter: > > On Fri, Jun 11, 2021 at 09:42:07AM +0200, Christian König wrote: > > > Am 11.06.21 um 09:20 schrieb Daniel Vetter: > > > > On Fri, Jun 11, 2021 at 8:55 AM Christian König > > > > wrote: > > > > > Am 10.06.21 um 22:42 schrieb Daniel Vetter: > > > > > > On Thu, Jun 10, 2021 at 10:10 PM Jason Ekstrand > > > > > > wrote: > > > > > > > On Thu, Jun 10, 2021 at 8:35 AM Jason Ekstrand > > > > > > > wrote: > > > > > > > > On Thu, Jun 10, 2021 at 6:30 AM Daniel Vetter > > > > > > > > wrote: > > > > > > > > > On Thu, Jun 10, 2021 at 11:39 AM Christian König > > > > > > > > > wrote: > > > > > > > > > > Am 10.06.21 um 11:29 schrieb Tvrtko Ursulin: > > > > > > > > > > > On 09/06/2021 22:29, Jason Ekstrand wrote: > > > > > > > > > > > > We've tried to keep it somewhat contained by doing most > > > > > > > > > > > > of the hard work > > > > > > > > > > > > to prevent access of recycled objects via > > > > > > > > > > > > dma_fence_get_rcu_safe(). > > > > > > > > > > > > However, a quick grep of kernel sources says that, of > > > > > > > > > > > > the 30 instances > > > > > > > > > > > > of dma_fence_get_rcu*, only 11 of them use > > > > > > > > > > > > dma_fence_get_rcu_safe(). > > > > > > > > > > > > It's likely there bear traps in DRM and related > > > > > > > > > > > > subsystems just waiting > > > > > > > > > > > > for someone to accidentally step in them. > > > > > > > > > > > ...because dma_fence_get_rcu_safe apears to be about > > > > > > > > > > > whether the > > > > > > > > > > > *pointer* to the fence itself is rcu protected, not about > > > > > > > > > > > the fence > > > > > > > > > > > object itself. > > > > > > > > > > Yes, exactly that. > > > > > > > > The fact that both of you think this either means that I've > > > > > > > > completely > > > > > > > > missed what's going on with RCUs here (possible but, in this > > > > > > > > case, I > > > > > > > > think unlikely) or RCUs on dma fences should scare us all. > > > > > > > Taking a step back for a second and ignoring SLAB_TYPESAFE_BY_RCU > > > > > > > as > > > > > > > such, I'd like to ask a slightly different question: What are > > > > > > > the > > > > > > > rules about what is allowed to be done under the RCU read lock and > > > > > > > what guarantees does a driver need to provide? > > > > > > > > > > > > > > I think so far that we've all agreed on the following: > > > > > > > > > > > > > > 1. Freeing an unsignaled fence is ok as long as it doesn't > > > > > > > have any > > > > > > > pending callbacks. (Callbacks should hold a reference anyway). > > > > > > > > > > > > > > 2. The pointer race solved by dma_fence_get_rcu_safe is real > > > > > > > and > > > > > > > requires the loop to sort out. > > > > > > > > > > > > > > But let's say I have a dma_fence pointer that I got from, say, > > > > > > > calling > > > > > > > dma_resv_excl_fence() under rcu_read_lock(). What am I allowed > > > > > > > to do > > > > > > > with it under the RCU lock? What assumptions can I make? Is this > > > > > > > code, for instance, ok? > > > > > > > > > > > > > > rcu_read_lock(); > > > > > > > fence = dma_resv_excl_fence(obj); > > > > > > > idle = !fence || test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, > > > > > > > &fence->flags); > > > > > > > rcu_read_unlock(); > > > > > > > > > > > > > > This code very much looks correct under the following assumptions: > > > > > > > > > > > > > > 1. A valid fence pointer stays alive under the RCU read lock > > > > > > > 2. SIGNALED_BIT is set-once (it's never unset after being > > > > > > > set). > > > > > > > > > > > > > > However, if it were, we wouldn't have dma_resv_test_singnaled(), > > > > > > > now > > > > > > > would we? :-) > > > > > > > > > > > > > > The moment you introduce ANY dma_fence recycling that recycles a > > > > > > > dma_fence within a single RCU grace period, all your assumptions > > > > > > > break > > > > > > > down. SLAB_TYPESAFE_BY_RCU is just one way that i915 does this. > > > > > > > We > > > > > > > also have a little i915_request recycler to try and help with > > > > > > > memory > > > > > > > pressure scenarios in certain critical sections that also doesn't > > > > > > > respect RCU grace periods. And, as mentioned multiple times, our > > > > > > > recycling leaks into every other driver because, thanks to i915's > > > > > > > choice, the above 4-line code snippet isn't valid ANYWHERE in the > > > > > > > kernel. > > > > > > > > > > > > > > So the question I'm raising isn't so much about the rules today. > > > > > > > Today, we live in the wild wild west where everything is YOLO. > > > > > > > But > > > > > > > where do we want to go? Do we like this wild west world? So we > > > > > > > want > > > > > > > more consistency under the RCU read lock? If so, what do we want > > > > > > > the > > > > > > > rules to be? > > > > > > >
Re: [PATCH 5/5] drm/amdgpu: rework dma_resv handling v2
Am 11.06.21 um 16:56 schrieb Daniel Vetter: On Fri, Jun 11, 2021 at 02:03:01PM +0200, Christian König wrote: Drop the workaround and instead implement a better solution. Basically we are now chaining all submissions using a dma_fence_chain container and adding them as exclusive fence to the dma_resv object. This way other drivers can still sync to the single exclusive fence while amdgpu only sync to fences from different processes. v2: polish kerneldoc a bit There is no kerneldoc here, and otherwise this patch looks unchanged from the previous round. Hit send a bit too quickly? Ah, there it went! It's just to hot here, that was meant to be added to the other patch and I was really wondering why it wasn't there! Going to call it a day or rather week and will look at that again on Monday. Christian. -Daniel Signed-off-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 54 + drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 65 - drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 +- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 1 - 6 files changed, 47 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h index a130e766cbdb..c905a4cfc173 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h @@ -34,6 +34,7 @@ struct amdgpu_fpriv; struct amdgpu_bo_list_entry { struct ttm_validate_buffer tv; struct amdgpu_bo_va *bo_va; + struct dma_fence_chain *chain; uint32_tpriority; struct page **user_pages; booluser_invalidated; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 325e82621467..f6f3029f958d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -587,6 +587,20 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, goto out; } + amdgpu_bo_list_for_each_entry(e, p->bo_list) { + struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); + + e->bo_va = amdgpu_vm_bo_find(vm, bo); + + if (bo->tbo.base.dma_buf && !amdgpu_bo_explicit_sync(bo)) { + e->chain = dma_fence_chain_alloc(); + if (!e->chain) { + r = -ENOMEM; + goto error_validate; + } + } + } + amdgpu_cs_get_threshold_for_moves(p->adev, &p->bytes_moved_threshold, &p->bytes_moved_vis_threshold); p->bytes_moved = 0; @@ -614,15 +628,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, gws = p->bo_list->gws_obj; oa = p->bo_list->oa_obj; - amdgpu_bo_list_for_each_entry(e, p->bo_list) { - struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); - - /* Make sure we use the exclusive slot for shared BOs */ - if (bo->prime_shared_count) - e->tv.num_shared = 0; - e->bo_va = amdgpu_vm_bo_find(vm, bo); - } - if (gds) { p->job->gds_base = amdgpu_bo_gpu_offset(gds) >> PAGE_SHIFT; p->job->gds_size = amdgpu_bo_size(gds) >> PAGE_SHIFT; @@ -644,8 +649,13 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, } error_validate: - if (r) + if (r) { + amdgpu_bo_list_for_each_entry(e, p->bo_list) { + dma_fence_chain_free(e->chain); + e->chain = NULL; + } ttm_eu_backoff_reservation(&p->ticket, &p->validated); + } out: return r; } @@ -685,9 +695,17 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, { unsigned i; - if (error && backoff) + if (error && backoff) { + struct amdgpu_bo_list_entry *e; + + amdgpu_bo_list_for_each_entry(e, parser->bo_list) { + dma_fence_chain_free(e->chain); + e->chain = NULL; + } + ttm_eu_backoff_reservation(&parser->ticket, &parser->validated); + } for (i = 0; i < parser->num_post_deps; i++) { drm_syncobj_put(parser->post_deps[i].syncobj); @@ -1260,6 +1278,20 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, amdgpu_vm_move_to_lru_tail(p->adev, &fpriv->vm); + amdgpu_bo_list_for_each_entry(e, p->bo_list) { + struct dma_resv *resv = e->tv.bo->base.resv; + struct dma_fence_chain *chain = e->chain
Re: [PATCH 4/7] dma-buf: add dma_fence_chain_garbage_collect
On Fri, Jun 11, 2021 at 12:07:00PM +0200, Christian König wrote: > Am 11.06.21 um 10:58 schrieb Daniel Vetter: > > On Thu, Jun 10, 2021 at 11:17:57AM +0200, Christian König wrote: > > > Add some rather sophisticated lockless garbage collection > > > for dma_fence_chain objects. > > > > > > For this keep all initialized dma_fence_chain nodes an a > > > queue and trigger garbage collection before a new one is > > > allocated. > > > > > > Signed-off-by: Christian König > > Uh hand-rolled lockless list, I'm not a fan. > > > > But the real question here is why? This is a global list, so it's going to > > look great on your desktop, but gpus are for servers now and those are > > NUMA. So just from that pov doing garbage-collection individually still > > feels like a much better idea. > > Yeah, I was pondering on that quite a bit as well. That why I added the > multi threaded alloc/free test. > > > So what's the problem your trying to solve here? > > I was not sure if the chain is garbage collected enough when used for the > dma_resv exclusive object. > > But I think we could just drop this for now and just see how it goes. Yeah I think fixing a perf/tuning problem when we're hitting it is much better than trying to guess what it might be and writing something really clever to anticipate that. We generally get it wrong. Also with the explaination of what it tests added the testcase makes sense. Just some documentation or comment would have helped. -Daniel > > Christian. > > > -Daniel > > > > > --- > > > drivers/dma-buf/dma-fence-chain.c | 160 +- > > > include/linux/dma-fence-chain.h | 5 + > > > 2 files changed, 142 insertions(+), 23 deletions(-) > > > > > > diff --git a/drivers/dma-buf/dma-fence-chain.c > > > b/drivers/dma-buf/dma-fence-chain.c > > > index 1b4cb3e5cec9..c2f0b69eabb7 100644 > > > --- a/drivers/dma-buf/dma-fence-chain.c > > > +++ b/drivers/dma-buf/dma-fence-chain.c > > > @@ -9,8 +9,53 @@ > > > #include > > > +static struct dma_fence_chain __rcu *fifo_front; > > > +static struct dma_fence_chain __rcu **fifo_back = &fifo_front; > > > + > > > static bool dma_fence_chain_enable_signaling(struct dma_fence *fence); > > > +/** > > > + * dma_fence_chain_enqueue - enqeue a chain node for garbage collection > > > + * @chain: the chain node to enqueue > > > + * > > > + * Add the chain node to the end of the gc fifo. > > > + */ > > > +static void dma_fence_chain_enqueue(struct dma_fence_chain *chain) > > > +{ > > > + struct dma_fence_chain __rcu **tmp; > > > + > > > + RCU_INIT_POINTER(chain->next, NULL); > > > + tmp = xchg((struct dma_fence_chain __force ***)&fifo_back, > > > +&chain->next); > > > + > > > + /* This is intentionally unordered since we only need the fifo for gc */ > > > + rcu_assign_pointer(*tmp, chain); > > > +} > > > + > > > +/** > > > + * dma_fence_chain_dequeue - deqeueue a chain node for garbage collection > > > + * > > > + * Remove the first chain node from the gc fifo while making sure that > > > always > > > + * keep at least one node on the fifo for lockless fifo implementation. > > > + * Returns the dequeued chain node or NULL. > > > + */ > > > +static struct dma_fence_chain *dma_fence_chain_dequeue(void) > > > +{ > > > + struct dma_fence_chain *chain, *tmp; > > > + > > > + rcu_read_lock(); > > > + chain = rcu_dereference(fifo_front); > > > + /* Never dequeue the last chain node for lockless fifo */ > > > + if (unlikely(!chain || !rcu_access_pointer(chain->next))) { > > > + rcu_read_unlock(); > > > + return NULL; > > > + } > > > + tmp = cmpxchg((struct dma_fence_chain __force **)&fifo_front, > > > + chain, rcu_access_pointer(chain->next)); > > > + rcu_read_unlock(); > > > + return tmp == chain ? chain : NULL; > > > +} > > > + > > > /** > > >* dma_fence_chain_get_prev - use RCU to get a reference to the > > > previous fence > > >* @chain: chain node to get the previous node from > > > @@ -28,6 +73,43 @@ static struct dma_fence > > > *dma_fence_chain_get_prev(struct dma_fence_chain *chain) > > > return prev; > > > } > > > +/** > > > + * dma_fence_chain_try_replace - try to replace the prev node > > > + * @chain: Chain node we try to replace prev. > > > + * @prev: the old prev node > > > + * > > > + * Try to replace the previous chain node when it or its containing > > > fence is > > > + * signaled. Returns true if we tried, false if we need to wait. > > > + */ > > > +static bool dma_fence_chain_try_replace(struct dma_fence_chain *chain, > > > + struct dma_fence *prev) > > > +{ > > > + struct dma_fence *replacement, *tmp; > > > + struct dma_fence_chain *prev_chain; > > > + > > > + prev_chain = to_dma_fence_chain(prev); > > > + if (prev_chain) { > > > + if (!dma_fence_is_signaled(prev_chain->fence)) > > > + return false; > > > + > > > + replacement = dma_fence_chain_get_prev(prev_chain); > > > + } else
Re: [PATCH 6/7] drm/amdgpu: unwrap fence chains in the explicit sync fence
On Fri, Jun 11, 2021 at 12:09:19PM +0200, Christian König wrote: > Am 11.06.21 um 11:07 schrieb Daniel Vetter: > > On Thu, Jun 10, 2021 at 11:17:59AM +0200, Christian König wrote: > > > Unwrap a the explicit fence if it is a dma_fence_chain and > > > sync to the first fence not matching the owner rules. > > > > > > Signed-off-by: Christian König > > > --- > > > drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 118 +-- > > > 1 file changed, 68 insertions(+), 50 deletions(-) > > > > > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c > > > b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c > > > index 1b2ceccaf5b0..862eb3c1c4c5 100644 > > > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c > > > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c > > > @@ -28,6 +28,8 @@ > > >*Christian König > > >*/ > > > +#include > > > + > > > #include "amdgpu.h" > > > #include "amdgpu_trace.h" > > > #include "amdgpu_amdkfd.h" > > > @@ -186,6 +188,55 @@ int amdgpu_sync_vm_fence(struct amdgpu_sync *sync, > > > struct dma_fence *fence) > > > return amdgpu_sync_fence(sync, fence); > > > } > > > +/* Determine based on the owner and mode if we should sync to a fence or > > > not */ > > > +static bool amdgpu_sync_test_fence(struct amdgpu_device *adev, > > > +enum amdgpu_sync_mode mode, > > > +void *owner, struct dma_fence *f) > > > +{ > > > + void *fence_owner = amdgpu_sync_get_owner(f); > > > + > > > + /* Always sync to moves, no matter what */ > > > + if (fence_owner == AMDGPU_FENCE_OWNER_UNDEFINED) > > > + return true; > > > + > > > + /* We only want to trigger KFD eviction fences on > > > + * evict or move jobs. Skip KFD fences otherwise. > > > + */ > > > + if (fence_owner == AMDGPU_FENCE_OWNER_KFD && > > > + owner != AMDGPU_FENCE_OWNER_UNDEFINED) > > > + return false; > > > + > > > + /* Never sync to VM updates either. */ > > > + if (fence_owner == AMDGPU_FENCE_OWNER_VM && > > > + owner != AMDGPU_FENCE_OWNER_UNDEFINED) > > > + return false; > > > + > > > + /* Ignore fences depending on the sync mode */ > > > + switch (mode) { > > > + case AMDGPU_SYNC_ALWAYS: > > > + return true; > > > + > > > + case AMDGPU_SYNC_NE_OWNER: > > > + if (amdgpu_sync_same_dev(adev, f) && > > > + fence_owner == owner) > > > + return false; > > > + break; > > > + > > > + case AMDGPU_SYNC_EQ_OWNER: > > > + if (amdgpu_sync_same_dev(adev, f) && > > > + fence_owner != owner) > > > + return false; > > > + break; > > > + > > > + case AMDGPU_SYNC_EXPLICIT: > > > + return false; > > > + } > > > + > > > + WARN(debug_evictions && fence_owner == AMDGPU_FENCE_OWNER_KFD, > > > + "Adding eviction fence to sync obj"); > > > + return true; > > > +} > > > + > > > /** > > >* amdgpu_sync_resv - sync to a reservation object > > >* > > > @@ -211,67 +262,34 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, > > > struct amdgpu_sync *sync, > > > /* always sync to the exclusive fence */ > > > f = dma_resv_excl_fence(resv); > > > - r = amdgpu_sync_fence(sync, f); > > > + dma_fence_chain_for_each(f, f) { > > Jason has some helper for deep-walking fence chains/arrays here I think. > > Might want to look into that, so that we have some consistency in how we > > pile up multiple exclusive fences. > > Well those helpers are not from Jason, but from me :) > > But no, for now the deep inspection is not really helpful here since > grabbing a reference to a certain chain node is what that makes the handling > easier and faster here. > > Thinking more about it that should also make it possible for the garbage > collection to kick in properly. Hm this is tricky to reason about, but yeah with this here it's a true chain, and you just need to connect them. But then if a buffer is on multiple engines, collapsing things down occasionally might be useful. But maybe we need to do that in the bigger rework where exclusive fences are also just in the dma_fence_list with a "this is an exclusive one btw" tag. I think for the vk import case doing the deep scan makes more sense, it's a once-per-frame thing, and there's a much bigger chance that you have a pile of fences from different engines on it already. I think a comment explaining why we think deep scan isn't a good idea here would be good, just so we can appreciate our foolishness when it all goes wrong :-) -Daniel > > > > Anyway pretty much one of the versions I had in mind too, except I didn't > > type it up. > > > > Acked-by: Daniel Vetter > > Thanks, > Christian. > > > > > > + struct dma_fence_chain *chain = to_dma_fence_chain(f); > > > + > > > + if (amdgpu_sync_test_fence(adev, mode, owner, chain ? > > > +chain->fence : f)) { > > > + r = amdgpu_sync_fence(sync, f); > > > +
Re: [PATCH 7/7] drm/amdgpu: rework dma_resv handling
On Fri, Jun 11, 2021 at 12:12:45PM +0200, Christian König wrote: > Am 11.06.21 um 11:17 schrieb Daniel Vetter: > > On Thu, Jun 10, 2021 at 11:18:00AM +0200, Christian König wrote: > > > Drop the workaround and instead implement a better solution. > > > > > > Basically we are now chaining all submissions using a dma_fence_chain > > > container and adding them as exclusive fence to the dma_resv object. > > > > > > This way other drivers can still sync to the single exclusive fence > > > while amdgpu only sync to fences from different processes. > > > > > > Signed-off-by: Christian König > > > --- > > > drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 1 + > > > drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 54 + > > > drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 65 - > > > drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 +- > > > drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 +- > > > drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 1 - > > > 6 files changed, 47 insertions(+), 79 deletions(-) > > > > > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h > > > b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h > > > index a130e766cbdb..c905a4cfc173 100644 > > > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h > > > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h > > > @@ -34,6 +34,7 @@ struct amdgpu_fpriv; > > > struct amdgpu_bo_list_entry { > > > struct ttm_validate_buffer tv; > > > struct amdgpu_bo_va *bo_va; > > > + struct dma_fence_chain *chain; > > > uint32_tpriority; > > > struct page **user_pages; > > > booluser_invalidated; > > > diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > > > b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > > > index 325e82621467..f6f3029f958d 100644 > > > --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > > > +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c > > > @@ -587,6 +587,20 @@ static int amdgpu_cs_parser_bos(struct > > > amdgpu_cs_parser *p, > > > goto out; > > > } > > > + amdgpu_bo_list_for_each_entry(e, p->bo_list) { > > > + struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); > > > + > > > + e->bo_va = amdgpu_vm_bo_find(vm, bo); > > > + > > > + if (bo->tbo.base.dma_buf && !amdgpu_bo_explicit_sync(bo)) { > > > + e->chain = dma_fence_chain_alloc(); > > > + if (!e->chain) { > > > + r = -ENOMEM; > > > + goto error_validate; > > > + } > > > + } > > > + } > > > + > > > amdgpu_cs_get_threshold_for_moves(p->adev, > > > &p->bytes_moved_threshold, > > > > > > &p->bytes_moved_vis_threshold); > > > p->bytes_moved = 0; > > > @@ -614,15 +628,6 @@ static int amdgpu_cs_parser_bos(struct > > > amdgpu_cs_parser *p, > > > gws = p->bo_list->gws_obj; > > > oa = p->bo_list->oa_obj; > > > - amdgpu_bo_list_for_each_entry(e, p->bo_list) { > > > - struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); > > > - > > > - /* Make sure we use the exclusive slot for shared BOs */ > > > - if (bo->prime_shared_count) > > > - e->tv.num_shared = 0; > > > - e->bo_va = amdgpu_vm_bo_find(vm, bo); > > > - } > > > - > > > if (gds) { > > > p->job->gds_base = amdgpu_bo_gpu_offset(gds) >> > > > PAGE_SHIFT; > > > p->job->gds_size = amdgpu_bo_size(gds) >> PAGE_SHIFT; > > > @@ -644,8 +649,13 @@ static int amdgpu_cs_parser_bos(struct > > > amdgpu_cs_parser *p, > > > } > > > error_validate: > > > - if (r) > > > + if (r) { > > > + amdgpu_bo_list_for_each_entry(e, p->bo_list) { > > > + dma_fence_chain_free(e->chain); > > > + e->chain = NULL; > > > + } > > > ttm_eu_backoff_reservation(&p->ticket, &p->validated); > > > + } > > > out: > > > return r; > > > } > > > @@ -685,9 +695,17 @@ static void amdgpu_cs_parser_fini(struct > > > amdgpu_cs_parser *parser, int error, > > > { > > > unsigned i; > > > - if (error && backoff) > > > + if (error && backoff) { > > > + struct amdgpu_bo_list_entry *e; > > > + > > > + amdgpu_bo_list_for_each_entry(e, parser->bo_list) { > > > + dma_fence_chain_free(e->chain); > > > + e->chain = NULL; > > > + } > > > + > > > ttm_eu_backoff_reservation(&parser->ticket, > > > &parser->validated); > > > + } > > > for (i = 0; i < parser->num_post_deps; i++) { > > > drm_syncobj_put(parser->post_deps[i].syncobj); > > > @@ -1260,6 +1278,20 @@ static int amdgpu_cs_submit(struct > > > amdgpu_cs_parser *p, > > > amdgpu_vm_move_t
Re: [PATCH v3] Documentation: gpu: Mention the requirements for new properties
On Fri, Jun 11, 2021 at 09:53:19AM +0300, Tomi Valkeinen wrote: > On 11/06/2021 08:54, Maxime Ripard wrote: > > Hi, > > > > On Thu, Jun 10, 2021 at 11:00:05PM +0200, Daniel Vetter wrote: > > > On Thu, Jun 10, 2021 at 7:47 PM Maxime Ripard wrote: > > > > > > > > New KMS properties come with a bunch of requirements to avoid each > > > > driver from running their own, inconsistent, set of properties, > > > > eventually leading to issues like property conflicts, inconsistencies > > > > between drivers and semantics, etc. > > > > > > > > Let's document what we expect. > > > > > > > > Cc: Alexandre Belloni > > > > Cc: Alexandre Torgue > > > > Cc: Alex Deucher > > > > Cc: Alison Wang > > > > Cc: Alyssa Rosenzweig > > > > Cc: Andrew Jeffery > > > > Cc: Andrzej Hajda > > > > Cc: Anitha Chrisanthus > > > > Cc: Benjamin Gaignard > > > > Cc: Ben Skeggs > > > > Cc: Boris Brezillon > > > > Cc: Brian Starkey > > > > Cc: Chen Feng > > > > Cc: Chen-Yu Tsai > > > > Cc: Christian Gmeiner > > > > Cc: "Christian König" > > > > Cc: Chun-Kuang Hu > > > > Cc: Edmund Dea > > > > Cc: Eric Anholt > > > > Cc: Fabio Estevam > > > > Cc: Gerd Hoffmann > > > > Cc: Haneen Mohammed > > > > Cc: Hans de Goede > > > > Cc: "Heiko Stübner" > > > > Cc: Huang Rui > > > > Cc: Hyun Kwon > > > > Cc: Inki Dae > > > > Cc: Jani Nikula > > > > Cc: Jernej Skrabec > > > > Cc: Jerome Brunet > > > > Cc: Joel Stanley > > > > Cc: John Stultz > > > > Cc: Jonas Karlman > > > > Cc: Jonathan Hunter > > > > Cc: Joonas Lahtinen > > > > Cc: Joonyoung Shim > > > > Cc: Jyri Sarha > > > > Cc: Kevin Hilman > > > > Cc: Kieran Bingham > > > > Cc: Krzysztof Kozlowski > > > > Cc: Kyungmin Park > > > > Cc: Laurent Pinchart > > > > Cc: Linus Walleij > > > > Cc: Liviu Dudau > > > > Cc: Lucas Stach > > > > Cc: Ludovic Desroches > > > > Cc: Marek Vasut > > > > Cc: Martin Blumenstingl > > > > Cc: Matthias Brugger > > > > Cc: Maxime Coquelin > > > > Cc: Maxime Ripard > > > > Cc: Melissa Wen > > > > Cc: Neil Armstrong > > > > Cc: Nicolas Ferre > > > > Cc: "Noralf Trønnes" > > > > Cc: NXP Linux Team > > > > Cc: Oleksandr Andrushchenko > > > > Cc: Patrik Jakobsson > > > > Cc: Paul Cercueil > > > > Cc: Pengutronix Kernel Team > > > > Cc: Philippe Cornu > > > > Cc: Philipp Zabel > > > > Cc: Qiang Yu > > > > Cc: Rob Clark > > > > Cc: Robert Foss > > > > Cc: Rob Herring > > > > Cc: Rodrigo Siqueira > > > > Cc: Rodrigo Vivi > > > > Cc: Roland Scheidegger > > > > Cc: Russell King > > > > Cc: Sam Ravnborg > > > > Cc: Sandy Huang > > > > Cc: Sascha Hauer > > > > Cc: Sean Paul > > > > Cc: Seung-Woo Kim > > > > Cc: Shawn Guo > > > > Cc: Stefan Agner > > > > Cc: Steven Price > > > > Cc: Sumit Semwal > > > > Cc: Thierry Reding > > > > Cc: Tian Tao > > > > Cc: Tomeu Vizoso > > > > Cc: Tomi Valkeinen > > > > Cc: VMware Graphics > > > > Cc: Xinliang Liu > > > > Cc: Xinwei Kong > > > > Cc: Yannick Fertre > > > > Cc: Zack Rusin > > > > Reviewed-by: Daniel Vetter > > > > Signed-off-by: Maxime Ripard > > > > > > > > --- > > > > > > > > Changes from v2: > > > >- Take into account the feedback from Laurent and Lidiu to no longer > > > > force generic properties, but prefix vendor-specific properties > > > > with > > > > the vendor name > > > > > > I'm pretty sure my r-b was without this ... > > > > Yeah, sorry. I wanted to tell you on IRC that you wanted to have a > > second look, but I shouldn't have kept it and caught you by surprise > > indeed. > > > > > Why exactly do we need this? KMS is meant to be fairly generic (bugs > > > throw a wrench around here sometimes, and semantics can be tricky). If > > > we open up the door to yolo vendor properties in upstream, then that > > > goal is pretty much written off. And we've been there with vendor > > > properties, it's a giantic mess. > > > > > > Minimally drop my r-b, I'm definitely not in support of this idea. > > > > So the argument Lidiu and Laurent made was that in some cases, getting a > > generic property right with only a couple of users is hard. So they > > advocated for the right to keep non-generic properties. I can get the > > argument, and no-one else said that was wrong, so it felt like the > > consensus was there. > > I also think that (maybe mainly on embedded side) we may have 1) esoteric HW > features which perhaps can't even be made generic, and 2) features which may > or may not be generic, but for which support cannot be added to any common > opensource userspace projects like X or Weston, as the only use cases for > the features are specialized low level apps (often customer's closed-source > apps). > > While I agree with Daniel's "gigantic mess" problem, it would also be quite > nice to have a way to support all the HW features upstream instead of > carrying them in vendor trees. So this means to be able to accomodate this "vendor properties are totally fine, go wild" exception we also need to throw "open source use
[PATCH v9 00/14] Restricted DMA
This series implements mitigations for lack of DMA access control on systems without an IOMMU, which could result in the DMA accessing the system memory at unexpected times and/or unexpected addresses, possibly leading to data leakage or corruption. For example, we plan to use the PCI-e bus for Wi-Fi and that PCI-e bus is not behind an IOMMU. As PCI-e, by design, gives the device full access to system memory, a vulnerability in the Wi-Fi firmware could easily escalate to a full system exploit (remote wifi exploits: [1a], [1b] that shows a full chain of exploits; [2], [3]). To mitigate the security concerns, we introduce restricted DMA. Restricted DMA utilizes the existing swiotlb to bounce streaming DMA in and out of a specially allocated region and does memory allocation from the same region. The feature on its own provides a basic level of protection against the DMA overwriting buffer contents at unexpected times. However, to protect against general data leakage and system memory corruption, the system needs to provide a way to restrict the DMA to a predefined memory region (this is usually done at firmware level, e.g. MPU in ATF on some ARM platforms [4]). [1a] https://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html [1b] https://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_11.html [2] https://blade.tencent.com/en/advisories/qualpwn/ [3] https://www.bleepingcomputer.com/news/security/vulnerabilities-found-in-highly-popular-firmware-for-wifi-chips/ [4] https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.c#L132 v9: Address the comments in v7 to - set swiotlb active pool to dev->dma_io_tlb_mem - get rid of get_io_tlb_mem - dig out the device struct for is_swiotlb_active - move debugfs_create_dir out of swiotlb_create_debugfs - do set_memory_decrypted conditionally in swiotlb_init_io_tlb_mem - use IS_ENABLED in kernel/dma/direct.c - fix redefinition of 'of_dma_set_restricted_buffer' v8: - Fix reserved-memory.txt and add the reg property in example. - Fix sizeof for of_property_count_elems_of_size in drivers/of/address.c#of_dma_set_restricted_buffer. - Apply Will's suggestion to try the OF node having DMA configuration in drivers/of/address.c#of_dma_set_restricted_buffer. - Fix typo in the comment of drivers/of/address.c#of_dma_set_restricted_buffer. - Add error message for PageHighMem in kernel/dma/swiotlb.c#rmem_swiotlb_device_init and move it to rmem_swiotlb_setup. - Fix the message string in rmem_swiotlb_setup. https://lore.kernel.org/patchwork/cover/1437112/ v7: Fix debugfs, PageHighMem and comment style in rmem_swiotlb_device_init https://lore.kernel.org/patchwork/cover/1431031/ v6: Address the comments in v5 https://lore.kernel.org/patchwork/cover/1423201/ v5: Rebase on latest linux-next https://lore.kernel.org/patchwork/cover/1416899/ v4: - Fix spinlock bad magic - Use rmem->name for debugfs entry - Address the comments in v3 https://lore.kernel.org/patchwork/cover/1378113/ v3: Using only one reserved memory region for both streaming DMA and memory allocation. https://lore.kernel.org/patchwork/cover/1360992/ v2: Building on top of swiotlb. https://lore.kernel.org/patchwork/cover/1280705/ v1: Using dma_map_ops. https://lore.kernel.org/patchwork/cover/1271660/ Claire Chang (14): swiotlb: Refactor swiotlb init functions swiotlb: Refactor swiotlb_create_debugfs swiotlb: Set dev->dma_io_tlb_mem to the swiotlb pool used swiotlb: Add restricted DMA pool initialization swiotlb: Update is_swiotlb_buffer to add a struct device argument swiotlb: Update is_swiotlb_active to add a struct device argument swiotlb: Bounce data from/to restricted DMA pool if available swiotlb: Move alloc_size to find_slots swiotlb: Refactor swiotlb_tbl_unmap_single dma-direct: Add a new wrapper __dma_direct_free_pages() swiotlb: Add restricted DMA alloc/free support. dma-direct: Allocate memory from restricted DMA pool if available dt-bindings: of: Add restricted DMA pool of: Add plumbing for restricted DMA pool .../reserved-memory/reserved-memory.txt | 36 ++- drivers/gpu/drm/i915/gem/i915_gem_internal.c | 2 +- drivers/gpu/drm/nouveau/nouveau_ttm.c | 2 +- drivers/iommu/dma-iommu.c | 12 +- drivers/of/address.c | 33 +++ drivers/of/device.c | 6 + drivers/of/of_private.h | 6 + drivers/pci/xen-pcifront.c| 2 +- drivers/xen/swiotlb-xen.c | 2 +- include/linux/device.h| 4 + include/linux/swiotlb.h | 45 +++- kernel/dma/Kconfig| 14 + kernel/dma/direct.c | 62 +++-- kernel/dma/direct.h | 9 +- kernel/dma/swiotlb.c | 242 +++
[PATCH v9 01/14] swiotlb: Refactor swiotlb init functions
Add a new function, swiotlb_init_io_tlb_mem, for the io_tlb_mem struct initialization to make the code reusable. Signed-off-by: Claire Chang --- kernel/dma/swiotlb.c | 53 ++-- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 8ca7d505d61c..1a1208c81e85 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -168,9 +168,32 @@ void __init swiotlb_update_mem_attributes(void) memset(vaddr, 0, bytes); } -int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose) +static void swiotlb_init_io_tlb_mem(struct io_tlb_mem *mem, phys_addr_t start, + unsigned long nslabs, bool late_alloc, + bool memory_decrypted) { + void *vaddr = phys_to_virt(start); unsigned long bytes = nslabs << IO_TLB_SHIFT, i; + + mem->nslabs = nslabs; + mem->start = start; + mem->end = mem->start + bytes; + mem->index = 0; + mem->late_alloc = late_alloc; + spin_lock_init(&mem->lock); + for (i = 0; i < mem->nslabs; i++) { + mem->slots[i].list = IO_TLB_SEGSIZE - io_tlb_offset(i); + mem->slots[i].orig_addr = INVALID_PHYS_ADDR; + mem->slots[i].alloc_size = 0; + } + + if (memory_decrypted) + set_memory_decrypted((unsigned long)vaddr, bytes >> PAGE_SHIFT); + memset(vaddr, 0, bytes); +} + +int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose) +{ struct io_tlb_mem *mem; size_t alloc_size; @@ -186,16 +209,8 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose) if (!mem) panic("%s: Failed to allocate %zu bytes align=0x%lx\n", __func__, alloc_size, PAGE_SIZE); - mem->nslabs = nslabs; - mem->start = __pa(tlb); - mem->end = mem->start + bytes; - mem->index = 0; - spin_lock_init(&mem->lock); - for (i = 0; i < mem->nslabs; i++) { - mem->slots[i].list = IO_TLB_SEGSIZE - io_tlb_offset(i); - mem->slots[i].orig_addr = INVALID_PHYS_ADDR; - mem->slots[i].alloc_size = 0; - } + + swiotlb_init_io_tlb_mem(mem, __pa(tlb), nslabs, false, false); io_tlb_default_mem = mem; if (verbose) @@ -282,7 +297,6 @@ swiotlb_late_init_with_default_size(size_t default_size) int swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs) { - unsigned long bytes = nslabs << IO_TLB_SHIFT, i; struct io_tlb_mem *mem; if (swiotlb_force == SWIOTLB_NO_FORCE) @@ -297,20 +311,7 @@ swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs) if (!mem) return -ENOMEM; - mem->nslabs = nslabs; - mem->start = virt_to_phys(tlb); - mem->end = mem->start + bytes; - mem->index = 0; - mem->late_alloc = 1; - spin_lock_init(&mem->lock); - for (i = 0; i < mem->nslabs; i++) { - mem->slots[i].list = IO_TLB_SEGSIZE - io_tlb_offset(i); - mem->slots[i].orig_addr = INVALID_PHYS_ADDR; - mem->slots[i].alloc_size = 0; - } - - set_memory_decrypted((unsigned long)tlb, bytes >> PAGE_SHIFT); - memset(tlb, 0, bytes); + swiotlb_init_io_tlb_mem(mem, virt_to_phys(tlb), nslabs, true, true); io_tlb_default_mem = mem; swiotlb_print_info(); -- 2.32.0.272.g935e593368-goog
[PATCH v9 02/14] swiotlb: Refactor swiotlb_create_debugfs
Split the debugfs creation to make the code reusable for supporting different bounce buffer pools, e.g. restricted DMA pool. Signed-off-by: Claire Chang --- kernel/dma/swiotlb.c | 23 --- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 1a1208c81e85..8a3e2b3b246d 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -64,6 +64,9 @@ enum swiotlb_force swiotlb_force; struct io_tlb_mem *io_tlb_default_mem; +#ifdef CONFIG_DEBUG_FS +static struct dentry *debugfs_dir; +#endif /* * Max segment that we can provide which (if pages are contingous) will @@ -664,18 +667,24 @@ EXPORT_SYMBOL_GPL(is_swiotlb_active); #ifdef CONFIG_DEBUG_FS -static int __init swiotlb_create_debugfs(void) +static void swiotlb_create_debugfs_files(struct io_tlb_mem *mem) { - struct io_tlb_mem *mem = io_tlb_default_mem; - - if (!mem) - return 0; - mem->debugfs = debugfs_create_dir("swiotlb", NULL); debugfs_create_ulong("io_tlb_nslabs", 0400, mem->debugfs, &mem->nslabs); debugfs_create_ulong("io_tlb_used", 0400, mem->debugfs, &mem->used); +} + +static int __init swiotlb_create_default_debugfs(void) +{ + struct io_tlb_mem *mem = io_tlb_default_mem; + + debugfs_dir = debugfs_create_dir("swiotlb", NULL); + if (mem) { + mem->debugfs = debugfs_dir; + swiotlb_create_debugfs_files(mem); + } return 0; } -late_initcall(swiotlb_create_debugfs); +late_initcall(swiotlb_create_default_debugfs); #endif -- 2.32.0.272.g935e593368-goog
[PATCH v9 03/14] swiotlb: Set dev->dma_io_tlb_mem to the swiotlb pool used
Always have the pointer to the swiotlb pool used in struct device. This could help simplify the code for other pools. Signed-off-by: Claire Chang --- drivers/of/device.c | 3 +++ include/linux/device.h | 4 include/linux/swiotlb.h | 8 kernel/dma/swiotlb.c| 8 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/of/device.c b/drivers/of/device.c index c5a9473a5fb1..1defdf15ba95 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -165,6 +165,9 @@ int of_dma_configure_id(struct device *dev, struct device_node *np, arch_setup_dma_ops(dev, dma_start, size, iommu, coherent); + if (IS_ENABLED(CONFIG_SWIOTLB)) + swiotlb_set_io_tlb_default_mem(dev); + return 0; } EXPORT_SYMBOL_GPL(of_dma_configure_id); diff --git a/include/linux/device.h b/include/linux/device.h index 4443e12238a0..2e9a378c9100 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -432,6 +432,7 @@ struct dev_links_info { * @dma_pools: Dma pools (if dma'ble device). * @dma_mem: Internal for coherent mem override. * @cma_area: Contiguous memory area for dma allocations + * @dma_io_tlb_mem: Pointer to the swiotlb pool used. Not for driver use. * @archdata: For arch-specific additions. * @of_node: Associated device tree node. * @fwnode:Associated device node supplied by platform firmware. @@ -540,6 +541,9 @@ struct device { #ifdef CONFIG_DMA_CMA struct cma *cma_area; /* contiguous memory area for dma allocations */ +#endif +#ifdef CONFIG_SWIOTLB + struct io_tlb_mem *dma_io_tlb_mem; #endif /* arch specific additions */ struct dev_archdata archdata; diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 216854a5e513..008125ccd509 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -108,6 +108,11 @@ static inline bool is_swiotlb_buffer(phys_addr_t paddr) return mem && paddr >= mem->start && paddr < mem->end; } +static inline void swiotlb_set_io_tlb_default_mem(struct device *dev) +{ + dev->dma_io_tlb_mem = io_tlb_default_mem; +} + void __init swiotlb_exit(void); unsigned int swiotlb_max_segment(void); size_t swiotlb_max_mapping_size(struct device *dev); @@ -119,6 +124,9 @@ static inline bool is_swiotlb_buffer(phys_addr_t paddr) { return false; } +static inline void swiotlb_set_io_tlb_default_mem(struct device *dev) +{ +} static inline void swiotlb_exit(void) { } diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 8a3e2b3b246d..29b950ab1351 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -344,7 +344,7 @@ void __init swiotlb_exit(void) static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size, enum dma_data_direction dir) { - struct io_tlb_mem *mem = io_tlb_default_mem; + struct io_tlb_mem *mem = dev->dma_io_tlb_mem; int index = (tlb_addr - mem->start) >> IO_TLB_SHIFT; phys_addr_t orig_addr = mem->slots[index].orig_addr; size_t alloc_size = mem->slots[index].alloc_size; @@ -426,7 +426,7 @@ static unsigned int wrap_index(struct io_tlb_mem *mem, unsigned int index) static int find_slots(struct device *dev, phys_addr_t orig_addr, size_t alloc_size) { - struct io_tlb_mem *mem = io_tlb_default_mem; + struct io_tlb_mem *mem = dev->dma_io_tlb_mem; unsigned long boundary_mask = dma_get_seg_boundary(dev); dma_addr_t tbl_dma_addr = phys_to_dma_unencrypted(dev, mem->start) & boundary_mask; @@ -503,7 +503,7 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr, size_t mapping_size, size_t alloc_size, enum dma_data_direction dir, unsigned long attrs) { - struct io_tlb_mem *mem = io_tlb_default_mem; + struct io_tlb_mem *mem = dev->dma_io_tlb_mem; unsigned int offset = swiotlb_align_offset(dev, orig_addr); unsigned int i; int index; @@ -554,7 +554,7 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr, size_t mapping_size, enum dma_data_direction dir, unsigned long attrs) { - struct io_tlb_mem *mem = io_tlb_default_mem; + struct io_tlb_mem *mem = hwdev->dma_io_tlb_mem; unsigned long flags; unsigned int offset = swiotlb_align_offset(hwdev, tlb_addr); int index = (tlb_addr - offset - mem->start) >> IO_TLB_SHIFT; -- 2.32.0.272.g935e593368-goog
[PATCH v9 04/14] swiotlb: Add restricted DMA pool initialization
Add the initialization function to create restricted DMA pools from matching reserved-memory nodes. Signed-off-by: Claire Chang --- include/linux/swiotlb.h | 3 +- kernel/dma/Kconfig | 14 kernel/dma/swiotlb.c| 75 + 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 008125ccd509..ec0c01796c8a 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -72,7 +72,8 @@ extern enum swiotlb_force swiotlb_force; * range check to see if the memory was in fact allocated by this * API. * @nslabs:The number of IO TLB blocks (in groups of 64) between @start and - * @end. This is command line adjustable via setup_io_tlb_npages. + * @end. For default swiotlb, this is command line adjustable via + * setup_io_tlb_npages. * @used: The number of used IO TLB block. * @list: The free list describing the number of free entries available * from each index. diff --git a/kernel/dma/Kconfig b/kernel/dma/Kconfig index 77b405508743..3e961dc39634 100644 --- a/kernel/dma/Kconfig +++ b/kernel/dma/Kconfig @@ -80,6 +80,20 @@ config SWIOTLB bool select NEED_DMA_MAP_STATE +config DMA_RESTRICTED_POOL + bool "DMA Restricted Pool" + depends on OF && OF_RESERVED_MEM + select SWIOTLB + help + This enables support for restricted DMA pools which provide a level of + DMA memory protection on systems with limited hardware protection + capabilities, such as those lacking an IOMMU. + + For more information see + + and . + If unsure, say "n". + # # Should be selected if we can mmap non-coherent mappings to userspace. # The only thing that is really required is a way to set an uncached bit diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 29b950ab1351..c4a071d6a63f 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -39,6 +39,13 @@ #ifdef CONFIG_DEBUG_FS #include #endif +#ifdef CONFIG_DMA_RESTRICTED_POOL +#include +#include +#include +#include +#include +#endif #include #include @@ -688,3 +695,71 @@ static int __init swiotlb_create_default_debugfs(void) late_initcall(swiotlb_create_default_debugfs); #endif + +#ifdef CONFIG_DMA_RESTRICTED_POOL +static int rmem_swiotlb_device_init(struct reserved_mem *rmem, + struct device *dev) +{ + struct io_tlb_mem *mem = rmem->priv; + unsigned long nslabs = rmem->size >> IO_TLB_SHIFT; + + /* +* Since multiple devices can share the same pool, the private data, +* io_tlb_mem struct, will be initialized by the first device attached +* to it. +*/ + if (!mem) { + mem = kzalloc(struct_size(mem, slots, nslabs), GFP_KERNEL); + if (!mem) + return -ENOMEM; + + swiotlb_init_io_tlb_mem(mem, rmem->base, nslabs, false, true); + + rmem->priv = mem; + + if (IS_ENABLED(CONFIG_DEBUG_FS)) { + mem->debugfs = + debugfs_create_dir(rmem->name, debugfs_dir); + swiotlb_create_debugfs_files(mem); + } + } + + dev->dma_io_tlb_mem = mem; + + return 0; +} + +static void rmem_swiotlb_device_release(struct reserved_mem *rmem, + struct device *dev) +{ + dev->dma_io_tlb_mem = io_tlb_default_mem; +} + +static const struct reserved_mem_ops rmem_swiotlb_ops = { + .device_init = rmem_swiotlb_device_init, + .device_release = rmem_swiotlb_device_release, +}; + +static int __init rmem_swiotlb_setup(struct reserved_mem *rmem) +{ + unsigned long node = rmem->fdt_node; + + if (of_get_flat_dt_prop(node, "reusable", NULL) || + of_get_flat_dt_prop(node, "linux,cma-default", NULL) || + of_get_flat_dt_prop(node, "linux,dma-default", NULL) || + of_get_flat_dt_prop(node, "no-map", NULL)) + return -EINVAL; + + if (PageHighMem(pfn_to_page(PHYS_PFN(rmem->base { + pr_err("Restricted DMA pool must be accessible within the linear mapping."); + return -EINVAL; + } + + rmem->ops = &rmem_swiotlb_ops; + pr_info("Reserved memory: created restricted DMA pool at %pa, size %ld MiB\n", + &rmem->base, (unsigned long)rmem->size / SZ_1M); + return 0; +} + +RESERVEDMEM_OF_DECLARE(dma, "restricted-dma-pool", rmem_swiotlb_setup); +#endif /* CONFIG_DMA_RESTRICTED_POOL */ -- 2.32.0.272.g935e593368-goog
[PATCH v9 05/14] swiotlb: Update is_swiotlb_buffer to add a struct device argument
Update is_swiotlb_buffer to add a struct device argument. This will be useful later to allow for restricted DMA pool. Signed-off-by: Claire Chang --- drivers/iommu/dma-iommu.c | 12 ++-- drivers/xen/swiotlb-xen.c | 2 +- include/linux/swiotlb.h | 7 --- kernel/dma/direct.c | 6 +++--- kernel/dma/direct.h | 6 +++--- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 5d96fcc45fec..1a6a08908245 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -506,7 +506,7 @@ static void __iommu_dma_unmap_swiotlb(struct device *dev, dma_addr_t dma_addr, __iommu_dma_unmap(dev, dma_addr, size); - if (unlikely(is_swiotlb_buffer(phys))) + if (unlikely(is_swiotlb_buffer(dev, phys))) swiotlb_tbl_unmap_single(dev, phys, size, dir, attrs); } @@ -577,7 +577,7 @@ static dma_addr_t __iommu_dma_map_swiotlb(struct device *dev, phys_addr_t phys, } iova = __iommu_dma_map(dev, phys, aligned_size, prot, dma_mask); - if (iova == DMA_MAPPING_ERROR && is_swiotlb_buffer(phys)) + if (iova == DMA_MAPPING_ERROR && is_swiotlb_buffer(dev, phys)) swiotlb_tbl_unmap_single(dev, phys, org_size, dir, attrs); return iova; } @@ -783,7 +783,7 @@ static void iommu_dma_sync_single_for_cpu(struct device *dev, if (!dev_is_dma_coherent(dev)) arch_sync_dma_for_cpu(phys, size, dir); - if (is_swiotlb_buffer(phys)) + if (is_swiotlb_buffer(dev, phys)) swiotlb_sync_single_for_cpu(dev, phys, size, dir); } @@ -796,7 +796,7 @@ static void iommu_dma_sync_single_for_device(struct device *dev, return; phys = iommu_iova_to_phys(iommu_get_dma_domain(dev), dma_handle); - if (is_swiotlb_buffer(phys)) + if (is_swiotlb_buffer(dev, phys)) swiotlb_sync_single_for_device(dev, phys, size, dir); if (!dev_is_dma_coherent(dev)) @@ -817,7 +817,7 @@ static void iommu_dma_sync_sg_for_cpu(struct device *dev, if (!dev_is_dma_coherent(dev)) arch_sync_dma_for_cpu(sg_phys(sg), sg->length, dir); - if (is_swiotlb_buffer(sg_phys(sg))) + if (is_swiotlb_buffer(dev, sg_phys(sg))) swiotlb_sync_single_for_cpu(dev, sg_phys(sg), sg->length, dir); } @@ -834,7 +834,7 @@ static void iommu_dma_sync_sg_for_device(struct device *dev, return; for_each_sg(sgl, sg, nelems, i) { - if (is_swiotlb_buffer(sg_phys(sg))) + if (is_swiotlb_buffer(dev, sg_phys(sg))) swiotlb_sync_single_for_device(dev, sg_phys(sg), sg->length, dir); diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 24d11861ac7d..0c4fb34f11ab 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -100,7 +100,7 @@ static int is_xen_swiotlb_buffer(struct device *dev, dma_addr_t dma_addr) * in our domain. Therefore _only_ check address within our domain. */ if (pfn_valid(PFN_DOWN(paddr))) - return is_swiotlb_buffer(paddr); + return is_swiotlb_buffer(dev, paddr); return 0; } diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index ec0c01796c8a..921b469c6ad2 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -2,6 +2,7 @@ #ifndef __LINUX_SWIOTLB_H #define __LINUX_SWIOTLB_H +#include #include #include #include @@ -102,9 +103,9 @@ struct io_tlb_mem { }; extern struct io_tlb_mem *io_tlb_default_mem; -static inline bool is_swiotlb_buffer(phys_addr_t paddr) +static inline bool is_swiotlb_buffer(struct device *dev, phys_addr_t paddr) { - struct io_tlb_mem *mem = io_tlb_default_mem; + struct io_tlb_mem *mem = dev->dma_io_tlb_mem; return mem && paddr >= mem->start && paddr < mem->end; } @@ -121,7 +122,7 @@ bool is_swiotlb_active(void); void __init swiotlb_adjust_size(unsigned long size); #else #define swiotlb_force SWIOTLB_NO_FORCE -static inline bool is_swiotlb_buffer(phys_addr_t paddr) +static inline bool is_swiotlb_buffer(struct device *dev, phys_addr_t paddr) { return false; } diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index f737e3347059..84c9feb5474a 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -343,7 +343,7 @@ void dma_direct_sync_sg_for_device(struct device *dev, for_each_sg(sgl, sg, nents, i) { phys_addr_t paddr = dma_to_phys(dev, sg_dma_address(sg)); - if (unlikely(is_swiotlb_buffer(paddr))) + if (unlikely(is_swiotlb_buffer(dev, paddr))) swiotlb_sync_single_for_device(dev, paddr, sg->length,
[PATCH v9 06/14] swiotlb: Update is_swiotlb_active to add a struct device argument
Update is_swiotlb_active to add a struct device argument. This will be useful later to allow for restricted DMA pool. Signed-off-by: Claire Chang --- drivers/gpu/drm/i915/gem/i915_gem_internal.c | 2 +- drivers/gpu/drm/nouveau/nouveau_ttm.c| 2 +- drivers/pci/xen-pcifront.c | 2 +- include/linux/swiotlb.h | 4 ++-- kernel/dma/direct.c | 2 +- kernel/dma/swiotlb.c | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_internal.c b/drivers/gpu/drm/i915/gem/i915_gem_internal.c index ce6b664b10aa..89a894354263 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_internal.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_internal.c @@ -42,7 +42,7 @@ static int i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj) max_order = MAX_ORDER; #ifdef CONFIG_SWIOTLB - if (is_swiotlb_active()) { + if (is_swiotlb_active(obj->base.dev->dev)) { unsigned int max_segment; max_segment = swiotlb_max_segment(); diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index f4c2e46b6fe1..2ca9d9a9e5d5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -276,7 +276,7 @@ nouveau_ttm_init(struct nouveau_drm *drm) } #if IS_ENABLED(CONFIG_SWIOTLB) && IS_ENABLED(CONFIG_X86) - need_swiotlb = is_swiotlb_active(); + need_swiotlb = is_swiotlb_active(dev->dev); #endif ret = ttm_device_init(&drm->ttm.bdev, &nouveau_bo_driver, drm->dev->dev, diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index b7a8f3a1921f..0d56985bfe81 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -693,7 +693,7 @@ static int pcifront_connect_and_init_dma(struct pcifront_device *pdev) spin_unlock(&pcifront_dev_lock); - if (!err && !is_swiotlb_active()) { + if (!err && !is_swiotlb_active(&pdev->xdev->dev)) { err = pci_xen_swiotlb_init_late(); if (err) dev_err(&pdev->xdev->dev, "Could not setup SWIOTLB!\n"); diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 921b469c6ad2..06cf17a80f5c 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -118,7 +118,7 @@ static inline void swiotlb_set_io_tlb_default_mem(struct device *dev) void __init swiotlb_exit(void); unsigned int swiotlb_max_segment(void); size_t swiotlb_max_mapping_size(struct device *dev); -bool is_swiotlb_active(void); +bool is_swiotlb_active(struct device *dev); void __init swiotlb_adjust_size(unsigned long size); #else #define swiotlb_force SWIOTLB_NO_FORCE @@ -141,7 +141,7 @@ static inline size_t swiotlb_max_mapping_size(struct device *dev) return SIZE_MAX; } -static inline bool is_swiotlb_active(void) +static inline bool is_swiotlb_active(struct device *dev) { return false; } diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index 84c9feb5474a..7a88c34d0867 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -495,7 +495,7 @@ int dma_direct_supported(struct device *dev, u64 mask) size_t dma_direct_max_mapping_size(struct device *dev) { /* If SWIOTLB is active, use its maximum mapping size */ - if (is_swiotlb_active() && + if (is_swiotlb_active(dev) && (dma_addressing_limited(dev) || swiotlb_force == SWIOTLB_FORCE)) return swiotlb_max_mapping_size(dev); return SIZE_MAX; diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index c4a071d6a63f..21e99907edd6 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -666,9 +666,9 @@ size_t swiotlb_max_mapping_size(struct device *dev) return ((size_t)IO_TLB_SIZE) * IO_TLB_SEGSIZE; } -bool is_swiotlb_active(void) +bool is_swiotlb_active(struct device *dev) { - return io_tlb_default_mem != NULL; + return dev->dma_io_tlb_mem != NULL; } EXPORT_SYMBOL_GPL(is_swiotlb_active); -- 2.32.0.272.g935e593368-goog
[PATCH v9 07/14] swiotlb: Bounce data from/to restricted DMA pool if available
Regardless of swiotlb setting, the restricted DMA pool is preferred if available. The restricted DMA pools provide a basic level of protection against the DMA overwriting buffer contents at unexpected times. However, to protect against general data leakage and system memory corruption, the system needs to provide a way to lock down the memory access, e.g., MPU. Note that is_dev_swiotlb_force doesn't check if swiotlb_force == SWIOTLB_FORCE. Otherwise the memory allocation behavior with default swiotlb will be changed by the following patche ("dma-direct: Allocate memory from restricted DMA pool if available"). Signed-off-by: Claire Chang --- include/linux/swiotlb.h | 10 +- kernel/dma/direct.c | 3 ++- kernel/dma/direct.h | 3 ++- kernel/dma/swiotlb.c| 1 + 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 06cf17a80f5c..8200c100fe10 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -85,6 +85,7 @@ extern enum swiotlb_force swiotlb_force; * unmap calls. * @debugfs: The dentry to debugfs. * @late_alloc:%true if allocated using the page allocator + * @force_swiotlb: %true if swiotlb is forced */ struct io_tlb_mem { phys_addr_t start; @@ -95,6 +96,7 @@ struct io_tlb_mem { spinlock_t lock; struct dentry *debugfs; bool late_alloc; + bool force_swiotlb; struct io_tlb_slot { phys_addr_t orig_addr; size_t alloc_size; @@ -115,6 +117,11 @@ static inline void swiotlb_set_io_tlb_default_mem(struct device *dev) dev->dma_io_tlb_mem = io_tlb_default_mem; } +static inline bool is_dev_swiotlb_force(struct device *dev) +{ + return dev->dma_io_tlb_mem->force_swiotlb; +} + void __init swiotlb_exit(void); unsigned int swiotlb_max_segment(void); size_t swiotlb_max_mapping_size(struct device *dev); @@ -126,8 +133,9 @@ static inline bool is_swiotlb_buffer(struct device *dev, phys_addr_t paddr) { return false; } -static inline void swiotlb_set_io_tlb_default_mem(struct device *dev) +static inline bool is_dev_swiotlb_force(struct device *dev) { + return false; } static inline void swiotlb_exit(void) { diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index 7a88c34d0867..078f7087e466 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -496,7 +496,8 @@ size_t dma_direct_max_mapping_size(struct device *dev) { /* If SWIOTLB is active, use its maximum mapping size */ if (is_swiotlb_active(dev) && - (dma_addressing_limited(dev) || swiotlb_force == SWIOTLB_FORCE)) + (dma_addressing_limited(dev) || swiotlb_force == SWIOTLB_FORCE || +is_dev_swiotlb_force(dev))) return swiotlb_max_mapping_size(dev); return SIZE_MAX; } diff --git a/kernel/dma/direct.h b/kernel/dma/direct.h index 13e9e7158d94..f94813674e23 100644 --- a/kernel/dma/direct.h +++ b/kernel/dma/direct.h @@ -87,7 +87,8 @@ static inline dma_addr_t dma_direct_map_page(struct device *dev, phys_addr_t phys = page_to_phys(page) + offset; dma_addr_t dma_addr = phys_to_dma(dev, phys); - if (unlikely(swiotlb_force == SWIOTLB_FORCE)) + if (unlikely(swiotlb_force == SWIOTLB_FORCE) || + is_dev_swiotlb_force(dev)) return swiotlb_map(dev, phys, size, dir, attrs); if (unlikely(!dma_capable(dev, dma_addr, size, true))) { diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 21e99907edd6..e5ccc198d0a7 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -714,6 +714,7 @@ static int rmem_swiotlb_device_init(struct reserved_mem *rmem, return -ENOMEM; swiotlb_init_io_tlb_mem(mem, rmem->base, nslabs, false, true); + mem->force_swiotlb = true; rmem->priv = mem; -- 2.32.0.272.g935e593368-goog
[PATCH v9 08/14] swiotlb: Move alloc_size to find_slots
Move the maintenance of alloc_size to find_slots for better code reusability later. Signed-off-by: Claire Chang --- kernel/dma/swiotlb.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index e5ccc198d0a7..364c6c822063 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -486,8 +486,11 @@ static int find_slots(struct device *dev, phys_addr_t orig_addr, return -1; found: - for (i = index; i < index + nslots; i++) + for (i = index; i < index + nslots; i++) { mem->slots[i].list = 0; + mem->slots[i].alloc_size = + alloc_size - ((i - index) << IO_TLB_SHIFT); + } for (i = index - 1; io_tlb_offset(i) != IO_TLB_SEGSIZE - 1 && mem->slots[i].list; i--) @@ -542,11 +545,8 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr, * This is needed when we sync the memory. Then we sync the buffer if * needed. */ - for (i = 0; i < nr_slots(alloc_size + offset); i++) { + for (i = 0; i < nr_slots(alloc_size + offset); i++) mem->slots[index + i].orig_addr = slot_addr(orig_addr, i); - mem->slots[index + i].alloc_size = - alloc_size - (i << IO_TLB_SHIFT); - } tlb_addr = slot_addr(mem->start, index) + offset; if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) && (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)) -- 2.32.0.272.g935e593368-goog
[PATCH v9 09/14] swiotlb: Refactor swiotlb_tbl_unmap_single
Add a new function, release_slots, to make the code reusable for supporting different bounce buffer pools, e.g. restricted DMA pool. Signed-off-by: Claire Chang --- kernel/dma/swiotlb.c | 35 --- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 364c6c822063..a6562573f090 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -554,27 +554,15 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr, return tlb_addr; } -/* - * tlb_addr is the physical address of the bounce buffer to unmap. - */ -void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr, - size_t mapping_size, enum dma_data_direction dir, - unsigned long attrs) +static void release_slots(struct device *dev, phys_addr_t tlb_addr) { - struct io_tlb_mem *mem = hwdev->dma_io_tlb_mem; + struct io_tlb_mem *mem = dev->dma_io_tlb_mem; unsigned long flags; - unsigned int offset = swiotlb_align_offset(hwdev, tlb_addr); + unsigned int offset = swiotlb_align_offset(dev, tlb_addr); int index = (tlb_addr - offset - mem->start) >> IO_TLB_SHIFT; int nslots = nr_slots(mem->slots[index].alloc_size + offset); int count, i; - /* -* First, sync the memory before unmapping the entry -*/ - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) && - (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)) - swiotlb_bounce(hwdev, tlb_addr, mapping_size, DMA_FROM_DEVICE); - /* * Return the buffer to the free list by setting the corresponding * entries to indicate the number of contiguous entries available. @@ -609,6 +597,23 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr, spin_unlock_irqrestore(&mem->lock, flags); } +/* + * tlb_addr is the physical address of the bounce buffer to unmap. + */ +void swiotlb_tbl_unmap_single(struct device *dev, phys_addr_t tlb_addr, + size_t mapping_size, enum dma_data_direction dir, + unsigned long attrs) +{ + /* +* First, sync the memory before unmapping the entry +*/ + if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) && + (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)) + swiotlb_bounce(dev, tlb_addr, mapping_size, DMA_FROM_DEVICE); + + release_slots(dev, tlb_addr); +} + void swiotlb_sync_single_for_device(struct device *dev, phys_addr_t tlb_addr, size_t size, enum dma_data_direction dir) { -- 2.32.0.272.g935e593368-goog
[PATCH v9 10/14] dma-direct: Add a new wrapper __dma_direct_free_pages()
Add a new wrapper __dma_direct_free_pages() that will be useful later for swiotlb_free(). Signed-off-by: Claire Chang --- kernel/dma/direct.c | 14 ++ 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index 078f7087e466..eb4098323bbc 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -75,6 +75,12 @@ static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size) min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit); } +static void __dma_direct_free_pages(struct device *dev, struct page *page, + size_t size) +{ + dma_free_contiguous(dev, page, size); +} + static struct page *__dma_direct_alloc_pages(struct device *dev, size_t size, gfp_t gfp) { @@ -237,7 +243,7 @@ void *dma_direct_alloc(struct device *dev, size_t size, return NULL; } out_free_pages: - dma_free_contiguous(dev, page, size); + __dma_direct_free_pages(dev, page, size); return NULL; } @@ -273,7 +279,7 @@ void dma_direct_free(struct device *dev, size_t size, else if (IS_ENABLED(CONFIG_ARCH_HAS_DMA_CLEAR_UNCACHED)) arch_dma_clear_uncached(cpu_addr, size); - dma_free_contiguous(dev, dma_direct_to_page(dev, dma_addr), size); + __dma_direct_free_pages(dev, dma_direct_to_page(dev, dma_addr), size); } struct page *dma_direct_alloc_pages(struct device *dev, size_t size, @@ -310,7 +316,7 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size, *dma_handle = phys_to_dma_direct(dev, page_to_phys(page)); return page; out_free_pages: - dma_free_contiguous(dev, page, size); + __dma_direct_free_pages(dev, page, size); return NULL; } @@ -329,7 +335,7 @@ void dma_direct_free_pages(struct device *dev, size_t size, if (force_dma_unencrypted(dev)) set_memory_encrypted((unsigned long)vaddr, 1 << page_order); - dma_free_contiguous(dev, page, size); + __dma_direct_free_pages(dev, page, size); } #if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ -- 2.32.0.272.g935e593368-goog
[PATCH v9 11/14] swiotlb: Add restricted DMA alloc/free support.
Add the functions, swiotlb_{alloc,free} to support the memory allocation from restricted DMA pool. Signed-off-by: Claire Chang --- include/linux/swiotlb.h | 15 +++ kernel/dma/swiotlb.c| 35 +-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 8200c100fe10..d3374497a4f8 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -162,4 +162,19 @@ static inline void swiotlb_adjust_size(unsigned long size) extern void swiotlb_print_info(void); extern void swiotlb_set_max_segment(unsigned int); +#ifdef CONFIG_DMA_RESTRICTED_POOL +struct page *swiotlb_alloc(struct device *dev, size_t size); +bool swiotlb_free(struct device *dev, struct page *page, size_t size); +#else +static inline struct page *swiotlb_alloc(struct device *dev, size_t size) +{ + return NULL; +} +static inline bool swiotlb_free(struct device *dev, struct page *page, + size_t size) +{ + return false; +} +#endif /* CONFIG_DMA_RESTRICTED_POOL */ + #endif /* __LINUX_SWIOTLB_H */ diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index a6562573f090..0a19858da5b8 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -461,8 +461,9 @@ static int find_slots(struct device *dev, phys_addr_t orig_addr, index = wrap = wrap_index(mem, ALIGN(mem->index, stride)); do { - if ((slot_addr(tbl_dma_addr, index) & iotlb_align_mask) != - (orig_addr & iotlb_align_mask)) { + if (orig_addr && + (slot_addr(tbl_dma_addr, index) & iotlb_align_mask) != + (orig_addr & iotlb_align_mask)) { index = wrap_index(mem, index + 1); continue; } @@ -702,6 +703,36 @@ late_initcall(swiotlb_create_default_debugfs); #endif #ifdef CONFIG_DMA_RESTRICTED_POOL +struct page *swiotlb_alloc(struct device *dev, size_t size) +{ + struct io_tlb_mem *mem = dev->dma_io_tlb_mem; + phys_addr_t tlb_addr; + int index; + + if (!mem) + return NULL; + + index = find_slots(dev, 0, size); + if (index == -1) + return NULL; + + tlb_addr = slot_addr(mem->start, index); + + return pfn_to_page(PFN_DOWN(tlb_addr)); +} + +bool swiotlb_free(struct device *dev, struct page *page, size_t size) +{ + phys_addr_t tlb_addr = page_to_phys(page); + + if (!is_swiotlb_buffer(dev, tlb_addr)) + return false; + + release_slots(dev, tlb_addr); + + return true; +} + static int rmem_swiotlb_device_init(struct reserved_mem *rmem, struct device *dev) { -- 2.32.0.272.g935e593368-goog
[PATCH v9 12/14] dma-direct: Allocate memory from restricted DMA pool if available
The restricted DMA pool is preferred if available. The restricted DMA pools provide a basic level of protection against the DMA overwriting buffer contents at unexpected times. However, to protect against general data leakage and system memory corruption, the system needs to provide a way to lock down the memory access, e.g., MPU. Note that since coherent allocation needs remapping, one must set up another device coherent pool by shared-dma-pool and use dma_alloc_from_dev_coherent instead for atomic coherent allocation. Signed-off-by: Claire Chang --- kernel/dma/direct.c | 37 - 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index eb4098323bbc..73fc4c659ba7 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -78,6 +78,9 @@ static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size) static void __dma_direct_free_pages(struct device *dev, struct page *page, size_t size) { + if (IS_ENABLED(CONFIG_DMA_RESTRICTED_POOL) && + swiotlb_free(dev, page, size)) + return; dma_free_contiguous(dev, page, size); } @@ -92,7 +95,17 @@ static struct page *__dma_direct_alloc_pages(struct device *dev, size_t size, gfp |= dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask, &phys_limit); - page = dma_alloc_contiguous(dev, size, gfp); + if (IS_ENABLED(CONFIG_DMA_RESTRICTED_POOL)) { + page = swiotlb_alloc(dev, size); + if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) { + __dma_direct_free_pages(dev, page, size); + page = NULL; + } + return page; + } + + if (!page) + page = dma_alloc_contiguous(dev, size, gfp); if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) { dma_free_contiguous(dev, page, size); page = NULL; @@ -148,7 +161,7 @@ void *dma_direct_alloc(struct device *dev, size_t size, gfp |= __GFP_NOWARN; if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) && - !force_dma_unencrypted(dev)) { + !force_dma_unencrypted(dev) && !is_dev_swiotlb_force(dev)) { page = __dma_direct_alloc_pages(dev, size, gfp & ~__GFP_ZERO); if (!page) return NULL; @@ -161,18 +174,23 @@ void *dma_direct_alloc(struct device *dev, size_t size, } if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_SET_UNCACHED) && - !IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) && - !dev_is_dma_coherent(dev)) + !IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) && !dev_is_dma_coherent(dev) && + !is_dev_swiotlb_force(dev)) return arch_dma_alloc(dev, size, dma_handle, gfp, attrs); /* * Remapping or decrypting memory may block. If either is required and * we can't block, allocate the memory from the atomic pools. +* If restricted DMA (i.e., is_dev_swiotlb_force) is required, one must +* set up another device coherent pool by shared-dma-pool and use +* dma_alloc_from_dev_coherent instead. */ if (IS_ENABLED(CONFIG_DMA_COHERENT_POOL) && !gfpflags_allow_blocking(gfp) && (force_dma_unencrypted(dev) || -(IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) && !dev_is_dma_coherent(dev +(IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) && + !dev_is_dma_coherent(dev))) && + !is_dev_swiotlb_force(dev)) return dma_direct_alloc_from_pool(dev, size, dma_handle, gfp); /* we always manually zero the memory once we are done */ @@ -253,15 +271,15 @@ void dma_direct_free(struct device *dev, size_t size, unsigned int page_order = get_order(size); if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) && - !force_dma_unencrypted(dev)) { + !force_dma_unencrypted(dev) && !is_dev_swiotlb_force(dev)) { /* cpu_addr is a struct page cookie, not a kernel address */ dma_free_contiguous(dev, cpu_addr, size); return; } if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_SET_UNCACHED) && - !IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) && - !dev_is_dma_coherent(dev)) { + !IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) && !dev_is_dma_coherent(dev) && + !is_dev_swiotlb_force(dev)) { arch_dma_free(dev, size, cpu_addr, dma_addr, attrs); return; } @@ -289,7 +307,8 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size, void *ret; if (IS_ENABLED(CONFIG_DMA_COHERENT_POOL) && - force_dma_unencrypted(dev) && !gfpflags_allow_blocking(gfp)) + force_dma_unencrypted(dev) && !gfpflags_allow_blocking(gfp) && +
[PATCH v9 13/14] dt-bindings: of: Add restricted DMA pool
Introduce the new compatible string, restricted-dma-pool, for restricted DMA. One can specify the address and length of the restricted DMA memory region by restricted-dma-pool in the reserved-memory node. Signed-off-by: Claire Chang --- .../reserved-memory/reserved-memory.txt | 36 +-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt index e8d3096d922c..46804f24df05 100644 --- a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt +++ b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt @@ -51,6 +51,23 @@ compatible (optional) - standard definition used as a shared pool of DMA buffers for a set of devices. It can be used by an operating system to instantiate the necessary pool management subsystem if necessary. +- restricted-dma-pool: This indicates a region of memory meant to be + used as a pool of restricted DMA buffers for a set of devices. The + memory region would be the only region accessible to those devices. + When using this, the no-map and reusable properties must not be set, + so the operating system can create a virtual mapping that will be used + for synchronization. The main purpose for restricted DMA is to + mitigate the lack of DMA access control on systems without an IOMMU, + which could result in the DMA accessing the system memory at + unexpected times and/or unexpected addresses, possibly leading to data + leakage or corruption. The feature on its own provides a basic level + of protection against the DMA overwriting buffer contents at + unexpected times. However, to protect against general data leakage and + system memory corruption, the system needs to provide way to lock down + the memory access, e.g., MPU. Note that since coherent allocation + needs remapping, one must set up another device coherent pool by + shared-dma-pool and use dma_alloc_from_dev_coherent instead for atomic + coherent allocation. - vendor specific string in the form ,[-] no-map (optional) - empty property - Indicates the operating system must not create a virtual mapping @@ -85,10 +102,11 @@ memory-region-names (optional) - a list of names, one for each corresponding Example --- -This example defines 3 contiguous regions are defined for Linux kernel: +This example defines 4 contiguous regions for Linux kernel: one default of all device drivers (named linux,cma@7200 and 64MiB in size), -one dedicated to the framebuffer device (named framebuffer@7800, 8MiB), and -one for multimedia processing (named multimedia-memory@7700, 64MiB). +one dedicated to the framebuffer device (named framebuffer@7800, 8MiB), +one for multimedia processing (named multimedia-memory@7700, 64MiB), and +one for restricted dma pool (named restricted_dma_reserved@0x5000, 64MiB). / { #address-cells = <1>; @@ -120,6 +138,11 @@ one for multimedia processing (named multimedia-memory@7700, 64MiB). compatible = "acme,multimedia-memory"; reg = <0x7700 0x400>; }; + + restricted_dma_reserved: restricted_dma_reserved { + compatible = "restricted-dma-pool"; + reg = <0x5000 0x400>; + }; }; /* ... */ @@ -138,4 +161,11 @@ one for multimedia processing (named multimedia-memory@7700, 64MiB). memory-region = <&multimedia_reserved>; /* ... */ }; + + pcie_device: pcie_device@0,0 { + reg = <0x8301 0x0 0x 0x0 0x0010 + 0x8301 0x0 0x0010 0x0 0x0010>; + memory-region = <&restricted_dma_mem_reserved>; + /* ... */ + }; }; -- 2.32.0.272.g935e593368-goog
[PATCH v9 14/14] of: Add plumbing for restricted DMA pool
If a device is not behind an IOMMU, we look up the device node and set up the restricted DMA when the restricted-dma-pool is presented. Signed-off-by: Claire Chang --- drivers/of/address.c| 33 + drivers/of/device.c | 3 +++ drivers/of/of_private.h | 6 ++ 3 files changed, 42 insertions(+) diff --git a/drivers/of/address.c b/drivers/of/address.c index 3b2acca7e363..c8066d95ff0e 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -1001,6 +1002,38 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map) of_node_put(node); return ret; } + +int of_dma_set_restricted_buffer(struct device *dev, struct device_node *np) +{ + struct device_node *node, *of_node = dev->of_node; + int count, i; + + count = of_property_count_elems_of_size(of_node, "memory-region", + sizeof(u32)); + /* +* If dev->of_node doesn't exist or doesn't contain memory-region, try +* the OF node having DMA configuration. +*/ + if (count <= 0) { + of_node = np; + count = of_property_count_elems_of_size( + of_node, "memory-region", sizeof(u32)); + } + + for (i = 0; i < count; i++) { + node = of_parse_phandle(of_node, "memory-region", i); + /* +* There might be multiple memory regions, but only one +* restricted-dma-pool region is allowed. +*/ + if (of_device_is_compatible(node, "restricted-dma-pool") && + of_device_is_available(node)) + return of_reserved_mem_device_init_by_idx(dev, of_node, + i); + } + + return 0; +} #endif /* CONFIG_HAS_DMA */ /** diff --git a/drivers/of/device.c b/drivers/of/device.c index 1defdf15ba95..ba4656e77502 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -168,6 +168,9 @@ int of_dma_configure_id(struct device *dev, struct device_node *np, if (IS_ENABLED(CONFIG_SWIOTLB)) swiotlb_set_io_tlb_default_mem(dev); + if (!iommu) + return of_dma_set_restricted_buffer(dev, np); + return 0; } EXPORT_SYMBOL_GPL(of_dma_configure_id); diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index 631489f7f8c0..376462798f7e 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -163,12 +163,18 @@ struct bus_dma_region; #if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_HAS_DMA) int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map); +int of_dma_set_restricted_buffer(struct device *dev, struct device_node *np); #else static inline int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map) { return -ENODEV; } +static inline int of_dma_set_restricted_buffer(struct device *dev, + struct device_node *np) +{ + return -ENODEV; +} #endif void fdt_init_reserved_mem(void); -- 2.32.0.272.g935e593368-goog
Re: [PATCH v8 00/15] Restricted DMA
v9 here: https://lore.kernel.org/patchwork/cover/1445081/ On Mon, Jun 7, 2021 at 11:28 AM Claire Chang wrote: > > On Sat, Jun 5, 2021 at 1:48 AM Will Deacon wrote: > > > > Hi Claire, > > > > On Thu, May 27, 2021 at 08:58:30PM +0800, Claire Chang wrote: > > > This series implements mitigations for lack of DMA access control on > > > systems without an IOMMU, which could result in the DMA accessing the > > > system memory at unexpected times and/or unexpected addresses, possibly > > > leading to data leakage or corruption. > > > > > > For example, we plan to use the PCI-e bus for Wi-Fi and that PCI-e bus is > > > not behind an IOMMU. As PCI-e, by design, gives the device full access to > > > system memory, a vulnerability in the Wi-Fi firmware could easily escalate > > > to a full system exploit (remote wifi exploits: [1a], [1b] that shows a > > > full chain of exploits; [2], [3]). > > > > > > To mitigate the security concerns, we introduce restricted DMA. Restricted > > > DMA utilizes the existing swiotlb to bounce streaming DMA in and out of a > > > specially allocated region and does memory allocation from the same > > > region. > > > The feature on its own provides a basic level of protection against the > > > DMA > > > overwriting buffer contents at unexpected times. However, to protect > > > against general data leakage and system memory corruption, the system > > > needs > > > to provide a way to restrict the DMA to a predefined memory region (this > > > is > > > usually done at firmware level, e.g. MPU in ATF on some ARM platforms > > > [4]). > > > > > > [1a] > > > https://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_4.html > > > [1b] > > > https://googleprojectzero.blogspot.com/2017/04/over-air-exploiting-broadcoms-wi-fi_11.html > > > [2] https://blade.tencent.com/en/advisories/qualpwn/ > > > [3] > > > https://www.bleepingcomputer.com/news/security/vulnerabilities-found-in-highly-popular-firmware-for-wifi-chips/ > > > [4] > > > https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.c#L132 > > > > > > v8: > > > - Fix reserved-memory.txt and add the reg property in example. > > > - Fix sizeof for of_property_count_elems_of_size in > > > drivers/of/address.c#of_dma_set_restricted_buffer. > > > - Apply Will's suggestion to try the OF node having DMA configuration in > > > drivers/of/address.c#of_dma_set_restricted_buffer. > > > - Fix typo in the comment of > > > drivers/of/address.c#of_dma_set_restricted_buffer. > > > - Add error message for PageHighMem in > > > kernel/dma/swiotlb.c#rmem_swiotlb_device_init and move it to > > > rmem_swiotlb_setup. > > > - Fix the message string in rmem_swiotlb_setup. > > > > Thanks for the v8. It works for me out of the box on arm64 under KVM, so: > > > > Tested-by: Will Deacon > > > > Note that something seems to have gone wrong with the mail threading, so > > the last 5 patches ended up as a separate thread for me. Probably worth > > posting again with all the patches in one place, if you can. > > Thanks for testing. > > Christoph also added some comments in v7, so I'll prepare v9. > > > > > Cheers, > > > > Will
Re: [PATCH v9 03/14] swiotlb: Set dev->dma_io_tlb_mem to the swiotlb pool used
I'm not sure if this would break arch/x86/pci/sta2x11-fixup.c swiotlb_late_init_with_default_size is called here https://elixir.bootlin.com/linux/v5.13-rc5/source/arch/x86/pci/sta2x11-fixup.c#L60 On Fri, Jun 11, 2021 at 11:27 PM Claire Chang wrote: > > Always have the pointer to the swiotlb pool used in struct device. This > could help simplify the code for other pools. > > Signed-off-by: Claire Chang > --- > drivers/of/device.c | 3 +++ > include/linux/device.h | 4 > include/linux/swiotlb.h | 8 > kernel/dma/swiotlb.c| 8 > 4 files changed, 19 insertions(+), 4 deletions(-) > > diff --git a/drivers/of/device.c b/drivers/of/device.c > index c5a9473a5fb1..1defdf15ba95 100644 > --- a/drivers/of/device.c > +++ b/drivers/of/device.c > @@ -165,6 +165,9 @@ int of_dma_configure_id(struct device *dev, struct > device_node *np, > > arch_setup_dma_ops(dev, dma_start, size, iommu, coherent); > > + if (IS_ENABLED(CONFIG_SWIOTLB)) > + swiotlb_set_io_tlb_default_mem(dev); > + > return 0; > } > EXPORT_SYMBOL_GPL(of_dma_configure_id); > diff --git a/include/linux/device.h b/include/linux/device.h > index 4443e12238a0..2e9a378c9100 100644 > --- a/include/linux/device.h > +++ b/include/linux/device.h > @@ -432,6 +432,7 @@ struct dev_links_info { > * @dma_pools: Dma pools (if dma'ble device). > * @dma_mem: Internal for coherent mem override. > * @cma_area: Contiguous memory area for dma allocations > + * @dma_io_tlb_mem: Pointer to the swiotlb pool used. Not for driver use. > * @archdata: For arch-specific additions. > * @of_node: Associated device tree node. > * @fwnode:Associated device node supplied by platform firmware. > @@ -540,6 +541,9 @@ struct device { > #ifdef CONFIG_DMA_CMA > struct cma *cma_area; /* contiguous memory area for dma >allocations */ > +#endif > +#ifdef CONFIG_SWIOTLB > + struct io_tlb_mem *dma_io_tlb_mem; > #endif > /* arch specific additions */ > struct dev_archdata archdata; > diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h > index 216854a5e513..008125ccd509 100644 > --- a/include/linux/swiotlb.h > +++ b/include/linux/swiotlb.h > @@ -108,6 +108,11 @@ static inline bool is_swiotlb_buffer(phys_addr_t paddr) > return mem && paddr >= mem->start && paddr < mem->end; > } > > +static inline void swiotlb_set_io_tlb_default_mem(struct device *dev) > +{ > + dev->dma_io_tlb_mem = io_tlb_default_mem; > +} > + > void __init swiotlb_exit(void); > unsigned int swiotlb_max_segment(void); > size_t swiotlb_max_mapping_size(struct device *dev); > @@ -119,6 +124,9 @@ static inline bool is_swiotlb_buffer(phys_addr_t paddr) > { > return false; > } > +static inline void swiotlb_set_io_tlb_default_mem(struct device *dev) > +{ > +} > static inline void swiotlb_exit(void) > { > } > diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c > index 8a3e2b3b246d..29b950ab1351 100644 > --- a/kernel/dma/swiotlb.c > +++ b/kernel/dma/swiotlb.c > @@ -344,7 +344,7 @@ void __init swiotlb_exit(void) > static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t > size, >enum dma_data_direction dir) > { > - struct io_tlb_mem *mem = io_tlb_default_mem; > + struct io_tlb_mem *mem = dev->dma_io_tlb_mem; > int index = (tlb_addr - mem->start) >> IO_TLB_SHIFT; > phys_addr_t orig_addr = mem->slots[index].orig_addr; > size_t alloc_size = mem->slots[index].alloc_size; > @@ -426,7 +426,7 @@ static unsigned int wrap_index(struct io_tlb_mem *mem, > unsigned int index) > static int find_slots(struct device *dev, phys_addr_t orig_addr, > size_t alloc_size) > { > - struct io_tlb_mem *mem = io_tlb_default_mem; > + struct io_tlb_mem *mem = dev->dma_io_tlb_mem; > unsigned long boundary_mask = dma_get_seg_boundary(dev); > dma_addr_t tbl_dma_addr = > phys_to_dma_unencrypted(dev, mem->start) & boundary_mask; > @@ -503,7 +503,7 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, > phys_addr_t orig_addr, > size_t mapping_size, size_t alloc_size, > enum dma_data_direction dir, unsigned long attrs) > { > - struct io_tlb_mem *mem = io_tlb_default_mem; > + struct io_tlb_mem *mem = dev->dma_io_tlb_mem; > unsigned int offset = swiotlb_align_offset(dev, orig_addr); > unsigned int i; > int index; > @@ -554,7 +554,7 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, > phys_addr_t tlb_addr, > size_t mapping_size, enum dma_data_direction > dir, > unsigned long attrs) > { > - struct io_tlb_mem *mem = io_tlb_default_mem; > + struct io_tlb_mem *mem = hwdev->dma_io_tlb_mem; > unsigned long flags; > unsigned int offset = swiotlb_align_
Re: [PATCH v9 06/14] swiotlb: Update is_swiotlb_active to add a struct device argument
I don't have the HW to verify the change. Hopefully I use the right device struct for is_swiotlb_active.
Re: [PATCH v2 3/4] drm/i915/ttm: Calculate the object placement at get_pages time
On Fri, 11 Jun 2021 at 15:55, Thomas Hellström wrote: > > Instead of relying on a static placement, calculate at get_pages() time. > This should work for LMEM regions and system for now. For stolen we need > to take preallocated range into account. That well be added later. That will be > > Signed-off-by: Thomas Hellström > --- > v2: > - Fixed a style issue (Reported by Matthew Auld) > --- > drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 92 ++--- > drivers/gpu/drm/i915/intel_region_ttm.c | 8 ++- > drivers/gpu/drm/i915/intel_region_ttm.h | 2 + > 3 files changed, 75 insertions(+), 27 deletions(-) > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > index 45ef1d101937..fd3d11728229 100644 > --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > @@ -24,6 +24,11 @@ > #define I915_TTM_PRIO_NO_PAGES 1 > #define I915_TTM_PRIO_HAS_PAGES 2 > > +/* > + * Size of struct ttm_place vector in on-stack struct ttm_placement allocs > + */ > +#define I915_TTM_MAX_PLACEMENTS 10 I915_TTM_MAX_PLACEMENTS INTEL_REGION_UNKNOWN ? > + > /** > * struct i915_ttm_tt - TTM page vector with additional private information > * @ttm: The base TTM page vector. > @@ -42,32 +47,18 @@ struct i915_ttm_tt { > struct sg_table *cached_st; > }; > > -static const struct ttm_place lmem0_sys_placement_flags[] = { > - { > - .fpfn = 0, > - .lpfn = 0, > - .mem_type = I915_PL_LMEM0, > - .flags = 0, > - }, { > - .fpfn = 0, > - .lpfn = 0, > - .mem_type = I915_PL_SYSTEM, > - .flags = 0, > - } > -}; > - > -static struct ttm_placement i915_lmem0_placement = { > - .num_placement = 1, > - .placement = &lmem0_sys_placement_flags[0], > - .num_busy_placement = 1, > - .busy_placement = &lmem0_sys_placement_flags[0], > +static const struct ttm_place sys_placement_flags = { > + .fpfn = 0, > + .lpfn = 0, > + .mem_type = I915_PL_SYSTEM, > + .flags = 0, > }; > > static struct ttm_placement i915_sys_placement = { > .num_placement = 1, > - .placement = &lmem0_sys_placement_flags[1], > + .placement = &sys_placement_flags, > .num_busy_placement = 1, > - .busy_placement = &lmem0_sys_placement_flags[1], > + .busy_placement = &sys_placement_flags, > }; > > static bool gpu_binds_iomem(struct ttm_resource *mem) > @@ -83,6 +74,55 @@ static bool cpu_maps_iomem(struct ttm_resource *mem) > > static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj); > > +static enum ttm_caching > +i915_ttm_select_tt_caching(const struct drm_i915_gem_object *obj) > +{ > + /* > +* Objects only allowed in system get cached cpu-mappings. > +* Other objects get WC mapping for now. Even if in system. > +*/ > + if (obj->mm.region->type == INTEL_MEMORY_SYSTEM && > + obj->mm.n_placements <= 1) > + return ttm_cached; > + > + return ttm_write_combined; > +} > + > +static void > +i915_ttm_place_from_region(const struct intel_memory_region *mr, > + struct ttm_place *place) > +{ > + memset(place, 0, sizeof(*place)); > + place->mem_type = intel_region_to_ttm_type(mr); > +} > + > +static void > +i915_ttm_placement_from_obj(const struct drm_i915_gem_object *obj, > + struct ttm_place *requested, > + struct ttm_place *busy, > + struct ttm_placement *placement) > +{ > + unsigned int num_allowed = obj->mm.n_placements; > + unsigned int i; > + > + placement->num_placement = 1; > + i915_ttm_place_from_region(num_allowed ? obj->mm.placements[0] : > + obj->mm.region, requested); > + > + /* Cache this on object? */ > + placement->num_busy_placement = num_allowed; > + for (i = 0; i < placement->num_busy_placement; ++i) > + i915_ttm_place_from_region(obj->mm.placements[i], busy + i); > + > + if (num_allowed == 0) { > + *busy = *requested; > + placement->num_busy_placement = 1; > + } > + > + placement->placement = requested; > + placement->busy_placement = busy; > +} > + > static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo, > uint32_t page_flags) > { > @@ -100,7 +140,8 @@ static struct ttm_tt *i915_ttm_tt_create(struct > ttm_buffer_object *bo, > man->use_tt) > page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC; > > - ret = ttm_tt_init(&i915_tt->ttm, bo, page_flags, ttm_write_combined); > + ret = ttm_tt_init(&i915_tt->ttm, bo, page_flags, > + i915_ttm_select_tt_caching(obj)); > if (ret) { > kfree(i915_tt); >
Re: [PATCH v2 1/4] drm/i915: Update object placement flags to be mutable
On Fri, 11 Jun 2021 at 15:55, Thomas Hellström wrote: > > The object ops i915_GEM_OBJECT_HAS_IOMEM and the object > I915_BO_ALLOC_STRUCT_PAGE flags are considered immutable by > much of our code. Introduce a new mem_flags member to hold these > and make sure checks for these flags being set are either done > under the object lock or with pages properly pinned. The flags > will change during migration under the object lock. > > Signed-off-by: Thomas Hellström Reviewed-by: Matthew Auld
Re: [Intel-gfx] [PATCH v2 2/4] drm/i915/ttm: Adjust gem flags and caching settings after a move
On Fri, 11 Jun 2021 at 15:55, Thomas Hellström wrote: > > After a TTM move we need to update the i915 gem flags and caching > settings to reflect the new placement. > Also introduce gpu_binds_iomem() and cpu_maps_iomem() to clean up the > various ways we previously used to detect this. > Finally, initialize the TTM object reserved to be able to update > flags and caching before anyone else gets hold of the object. Hmm, why do we need to update it after a move? Is it not static? i.e we just consider the mm.placements/region to determine the correct domain and cache tracking? Or maybe it doesn't really matter either way? > > Signed-off-by: Thomas Hellström > --- > v2: > - Style fixes (Reported by Matthew Auld) > --- > drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 112 +++- > 1 file changed, 90 insertions(+), 22 deletions(-) > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > index 33ab47f1e05b..45ef1d101937 100644 > --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > @@ -70,6 +70,17 @@ static struct ttm_placement i915_sys_placement = { > .busy_placement = &lmem0_sys_placement_flags[1], > }; > > +static bool gpu_binds_iomem(struct ttm_resource *mem) > +{ > + return mem->mem_type != TTM_PL_SYSTEM; > +} > + > +static bool cpu_maps_iomem(struct ttm_resource *mem) > +{ > + /* Once / if we support GGTT, this is also false for cached ttm_tts */ > + return mem->mem_type != TTM_PL_SYSTEM; > +} > + > static void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj); > > static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo, > @@ -175,6 +186,41 @@ static void i915_ttm_free_cached_io_st(struct > drm_i915_gem_object *obj) > obj->ttm.cached_io_st = NULL; > } > > +static void > +i915_ttm_adjust_domains_after_cpu_move(struct drm_i915_gem_object *obj) > +{ > + struct ttm_buffer_object *bo = i915_gem_to_ttm(obj); > + > + if (cpu_maps_iomem(bo->resource) || bo->ttm->caching != ttm_cached) { > + obj->write_domain = I915_GEM_DOMAIN_WC; > + obj->read_domains = I915_GEM_DOMAIN_WC; > + } else { > + obj->write_domain = I915_GEM_DOMAIN_CPU; > + obj->read_domains = I915_GEM_DOMAIN_CPU; > + } > +} > + > +static void i915_ttm_adjust_gem_after_move(struct drm_i915_gem_object *obj) > +{ > + struct drm_i915_private *i915 = to_i915(obj->base.dev); > + struct ttm_buffer_object *bo = i915_gem_to_ttm(obj); > + unsigned int cache_level; > + > + obj->mem_flags &= ~(I915_BO_FLAG_STRUCT_PAGE | I915_BO_FLAG_IOMEM); > + > + obj->mem_flags |= cpu_maps_iomem(bo->resource) ? I915_BO_FLAG_IOMEM : > + I915_BO_FLAG_STRUCT_PAGE; > + > + if ((HAS_LLC(i915) || HAS_SNOOP(i915)) && > !gpu_binds_iomem(bo->resource) && > + bo->ttm->caching == ttm_cached) { > + cache_level = I915_CACHE_LLC; > + } else { > + cache_level = I915_CACHE_NONE; > + } Nit: no need for the braces. > + > + i915_gem_object_set_cache_coherency(obj, cache_level); > +} > + > static void i915_ttm_purge(struct drm_i915_gem_object *obj) > { > struct ttm_buffer_object *bo = i915_gem_to_ttm(obj); > @@ -190,8 +236,10 @@ static void i915_ttm_purge(struct drm_i915_gem_object > *obj) > > /* TTM's purge interface. Note that we might be reentering. */ > ret = ttm_bo_validate(bo, &place, &ctx); > - > if (!ret) { > + obj->write_domain = 0; > + obj->read_domains = 0; > + i915_ttm_adjust_gem_after_move(obj); > i915_ttm_free_cached_io_st(obj); > obj->mm.madv = __I915_MADV_PURGED; > } > @@ -273,12 +321,15 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object > *obj, > struct ttm_resource *res) > { > struct ttm_buffer_object *bo = i915_gem_to_ttm(obj); > - struct ttm_resource_manager *man = > - ttm_manager_type(bo->bdev, res->mem_type); > > - if (man->use_tt) > + if (!gpu_binds_iomem(res)) > return i915_ttm_tt_get_st(bo->ttm); > > + /* > +* If CPU mapping differs, we need to add the ttm_tt pages to > +* the resulting st. Might make sense for GGTT. > +*/ > + GEM_WARN_ON(!cpu_maps_iomem(res)); > return intel_region_ttm_node_to_st(obj->mm.region, res); > } > > @@ -290,8 +341,6 @@ static int i915_ttm_move(struct ttm_buffer_object *bo, > bool evict, > struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); > struct ttm_resource_manager *dst_man = > ttm_manager_type(bo->bdev, dst_mem->mem_type); > - struct ttm_resource_manager *src_man = > - ttm_manager_type(bo->bdev, bo->resource->mem_type); > struct intel_memory_region *dst_reg, *src_reg; > union { >