From nobody Mon Feb 9 19:42:30 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7365D1DE4F8 for ; Tue, 18 Feb 2025 23:29:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739921363; cv=pass; b=ozYQwI4Voq+0WnhAgzlNfNwv6ImZ7r7cN522D4fwYic3pkLEoKTZuxOVKHukfNt6Nhxcc2F4ak9+ufp+2P1CjSBw2r/rFnjsTryOB8VGPBsTU2qZ4mjdunX1/GoZWWmRi4RtdrtTlSJViYUHW2AUTRMYvLqVbmtKA3ZLsLr/y9k= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739921363; c=relaxed/simple; bh=W0YDHKm8aVZqW1TVxmsFzMDkaR5JPZQbmAhgoV+3P2g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=iI7C1gQUgJI+22olQP7WLhYzYN6bl2NkrOCo8syxVe/lqtGVw6xPI3ekAjMev7ySAu8C3PVb4Zaft5v8A0Zd9LDV9oO0IaISRo1GR/I8m5GZvrsF+Ew+cUvO71koGDEdPa8HWRy8yFB5LKTuiqywZx8fNDbhcoYE/iMrYL7oHh4= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=adrian.larumbe@collabora.com header.b=goQi3QnU; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=adrian.larumbe@collabora.com header.b="goQi3QnU" ARC-Seal: i=1; a=rsa-sha256; t=1739921344; cv=none; d=zohomail.com; s=zohoarc; b=RuyA0qYHE59i9UeK6jSfX+vKYF2pBJDcnJVG7va5kUfSTIk5jFN9ElBtkdnbN64Nzesvxv3whjj4eHuC2152ZxI5/8TTQi7uO79sxq6zPsY4M+DLbZTeZaYIM0tAtnNWUEgOoAWoKlVwHppUYthA44QDE9QNVf5Obm93RJQKSXU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1739921344; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To; bh=lxIiOljX+8RCkQFRb8Qc1CK/237y/rJX69Kr+P0hkwg=; b=TGwkodcGf1i/Jv04xgiPBhLO9NrPPS/XDKsYKoPkXGpam+bF7ZAYsnwVzq/s8fSPK163/Gu3Dq66CT098bKyYlxzWU46dylQc4BnhX8zB5/DKBys6r4nj157DVzx4ae3Fe2uCBpW5nwFT4rdsLUQcwuR9jA3FcKlJl2Tju8KZMY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=adrian.larumbe@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1739921344; s=zohomail; d=collabora.com; i=adrian.larumbe@collabora.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-ID:In-Reply-To:References:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Reply-To; bh=lxIiOljX+8RCkQFRb8Qc1CK/237y/rJX69Kr+P0hkwg=; b=goQi3QnU9PXH3+xd3RZvDZ+f09wsssdxlkz4goU4WmQefz985Zww0D1TKAQP8qMG czdr9dc96AlszkwAyLxfjMr95dEiDI3b2HoQhQI5dqIvMw3dz+C07NbQOVca5zopDer oS15tMIH2nyDW3pLDqKp+XU7AyIZtaRZCncxKWR8= Received: by mx.zohomail.com with SMTPS id 1739921342252847.3662481768877; Tue, 18 Feb 2025 15:29:02 -0800 (PST) From: =?UTF-8?q?Adri=C3=A1n=20Larumbe?= To: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon , Steven Price , Rob Herring , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter Cc: kernel@collabora.com, =?UTF-8?q?Adri=C3=A1n=20Larumbe?= Subject: [RFC PATCH 5/7] drm/shmem: Implement sparse allocation of pages for shmem objects Date: Tue, 18 Feb 2025 23:25:35 +0000 Message-ID: <20250218232552.3450939-6-adrian.larumbe@collabora.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20250218232552.3450939-1-adrian.larumbe@collabora.com> References: <20250218232552.3450939-1-adrian.larumbe@collabora.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Add a new function that lets drivers allocate pages for a subset of the shm= em object's virtual address range. Expand the shmem object's definition to inc= lude an RSS field, since it's different from the base GEM object's virtual size. Add also new function for putting the pages of a sparse page array. There is refactorisation potential with drm_gem_put_pages, but it is yet to be decid= ed what this should look like. Signed-off-by: Adri=C3=A1n Larumbe --- drivers/gpu/drm/drm_gem.c | 32 +++++++ drivers/gpu/drm/drm_gem_shmem_helper.c | 123 ++++++++++++++++++++++++- include/drm/drm_gem.h | 3 + include/drm/drm_gem_shmem_helper.h | 12 +++ 4 files changed, 165 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index ee811764c3df..930c5219e1e9 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -679,6 +679,38 @@ void drm_gem_put_pages(struct drm_gem_object *obj, str= uct page **pages, } EXPORT_SYMBOL(drm_gem_put_pages); =20 +void drm_gem_put_sparse_xarray(struct xarray *pa, unsigned long idx, + unsigned int npages, bool dirty, bool accessed) +{ + struct folio_batch fbatch; + struct page *page; + + folio_batch_init(&fbatch); + + xa_for_each(pa, idx, page) { + struct folio *folio =3D page_folio(page); + + if (dirty) + folio_mark_dirty(folio); + if (accessed) + folio_mark_accessed(folio); + + /* Undo the reference we took when populating the table */ + if (!folio_batch_add(&fbatch, folio)) + drm_gem_check_release_batch(&fbatch); + + xa_erase(pa, idx); + + idx +=3D folio_nr_pages(folio) - 1; + } + + if (folio_batch_count(&fbatch)) + drm_gem_check_release_batch(&fbatch); + + WARN_ON((idx+1) !=3D npages); +} +EXPORT_SYMBOL(drm_gem_put_sparse_xarray); + static int objects_lookup(struct drm_file *filp, u32 *handle, int count, struct drm_gem_object **objs) { diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_g= em_shmem_helper.c index d63e42be2d72..40f7f6812195 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -10,7 +10,6 @@ #include #include #include -#include =20 #ifdef CONFIG_X86 #include @@ -161,6 +160,18 @@ struct drm_gem_shmem_object *drm_gem_shmem_create_with= _mnt(struct drm_device *de } EXPORT_SYMBOL_GPL(drm_gem_shmem_create_with_mnt); =20 +static void drm_gem_shmem_put_pages_sparse(struct drm_gem_shmem_object *sh= mem) +{ + unsigned int n_pages =3D shmem->rss_size / PAGE_SIZE; + + drm_WARN_ON(shmem->base.dev, (shmem->rss_size & (PAGE_SIZE - 1)) !=3D 0); + drm_WARN_ON(shmem->base.dev, !shmem->sparse); + + drm_gem_put_sparse_xarray(&shmem->xapages, 0, n_pages, + shmem->pages_mark_dirty_on_put, + shmem->pages_mark_accessed_on_put); +} + /** * drm_gem_shmem_free - Free resources associated with a shmem GEM object * @shmem: shmem GEM object to free @@ -264,10 +275,15 @@ void drm_gem_shmem_put_pages(struct drm_gem_shmem_obj= ect *shmem) set_pages_array_wb(shmem->pages, obj->size >> PAGE_SHIFT); #endif =20 - drm_gem_put_pages(obj, shmem->pages, - shmem->pages_mark_dirty_on_put, - shmem->pages_mark_accessed_on_put); - shmem->pages =3D NULL; + if (!shmem->sparse) { + drm_gem_put_pages(obj, shmem->pages, + shmem->pages_mark_dirty_on_put, + shmem->pages_mark_accessed_on_put); + shmem->pages =3D NULL; + } else { + drm_gem_shmem_put_pages_sparse(shmem); + xa_destroy(&shmem->xapages); + } } EXPORT_SYMBOL(drm_gem_shmem_put_pages); =20 @@ -765,6 +781,81 @@ static struct sg_table *drm_gem_shmem_get_pages_sgt_lo= cked(struct drm_gem_shmem_ return ERR_PTR(ret); } =20 +static struct sg_table *drm_gem_shmem_get_sparse_pages_locked(struct drm_g= em_shmem_object *shmem, + unsigned int n_pages, + pgoff_t page_offset) +{ + struct drm_gem_object *obj =3D &shmem->base; + gfp_t mask =3D GFP_KERNEL | GFP_NOWAIT; + size_t size =3D n_pages * PAGE_SIZE; + struct address_space *mapping; + struct sg_table *sgt; + struct page *page; + bool first_alloc; + int ret, i; + + if (!shmem->sparse) + return ERR_PTR(-EINVAL); + + /* If the mapping exists, then bail out immediately */ + if (xa_load(&shmem->xapages, page_offset) !=3D NULL) + return ERR_PTR(-EEXIST); + + dma_resv_assert_held(shmem->base.resv); + + first_alloc =3D xa_empty(&shmem->xapages); + + mapping =3D shmem->base.filp->f_mapping; + mapping_set_unevictable(mapping); + + for (i =3D 0; i < n_pages; i++) { + page =3D shmem_read_mapping_page_nonblocking(mapping, page_offset + i); + if (IS_ERR(page)) { + ret =3D PTR_ERR(page); + goto err_free_pages; + } + + /* Add the page into the xarray */ + ret =3D xa_err(xa_store(&shmem->xapages, page_offset + i, page, mask)); + if (ret) { + put_page(page); + goto err_free_pages; + } + } + + sgt =3D kzalloc(sizeof(*sgt), mask); + if (!sgt) { + ret =3D -ENOMEM; + goto err_free_pages; + } + + ret =3D sg_alloc_table_from_page_xarray(sgt, &shmem->xapages, page_offset= , n_pages, 0, size, mask); + if (ret) + goto err_free_sgtable; + + ret =3D dma_map_sgtable(obj->dev->dev, sgt, DMA_BIDIRECTIONAL, 0); + if (ret) + goto err_free_sgtable; + + if (first_alloc) + shmem->pages_use_count =3D 1; + + shmem->rss_size +=3D size; + + return sgt; + +err_free_sgtable: + kfree(sgt); +err_free_pages: + while (--i) { + page =3D xa_erase(&shmem->xapages, page_offset + i); + if (drm_WARN_ON(obj->dev, !page)) + continue; + put_page(page); + } + return ERR_PTR(ret); +} + /** * drm_gem_shmem_get_pages_sgt - Pin pages, dma map them, and return a * scatter/gather table for a shmem GEM object. @@ -796,6 +887,28 @@ struct sg_table *drm_gem_shmem_get_pages_sgt(struct dr= m_gem_shmem_object *shmem) } EXPORT_SYMBOL_GPL(drm_gem_shmem_get_pages_sgt); =20 +struct sg_table *drm_gem_shmem_get_sparse_pages_sgt(struct drm_gem_shmem_o= bject *shmem, + unsigned int n_pages, pgoff_t page_offset) +{ + struct drm_gem_object *obj =3D &shmem->base; + struct sg_table *sgt; + int ret; + + if (drm_WARN_ON(obj->dev, !shmem->sparse)) + return ERR_PTR(-EINVAL); + + ret =3D dma_resv_lock(shmem->base.resv, NULL); + if (ret) + return ERR_PTR(ret); + + sgt =3D drm_gem_shmem_get_sparse_pages_locked(shmem, n_pages, page_offset= ); + + dma_resv_unlock(shmem->base.resv); + + return sgt; +} +EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sparse_pages_sgt); + /** * drm_gem_shmem_prime_import_sg_table - Produce a shmem GEM object from * another driver's scatter/gather table of pinned pages diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index fdae947682cd..4fd45169a3af 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -38,6 +38,7 @@ #include #include #include +#include =20 #include =20 @@ -532,6 +533,8 @@ int drm_gem_create_mmap_offset_size(struct drm_gem_obje= ct *obj, size_t size); struct page **drm_gem_get_pages(struct drm_gem_object *obj); void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, bool dirty, bool accessed); +void drm_gem_put_sparse_xarray(struct xarray *pa, unsigned long idx, + unsigned int npages, bool dirty, bool accessed); =20 void drm_gem_lock(struct drm_gem_object *obj); void drm_gem_unlock(struct drm_gem_object *obj); diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem= _helper.h index 902039cfc4ce..fcd84c8cf8e7 100644 --- a/include/drm/drm_gem_shmem_helper.h +++ b/include/drm/drm_gem_shmem_helper.h @@ -44,6 +44,14 @@ struct drm_gem_shmem_object { */ unsigned int pages_use_count; =20 + /** + * @rss_size: + * + * Size of the object RSS, in bytes. + * lifetime. + */ + size_t rss_size; + /** * @madv: State for madvise * @@ -107,6 +115,7 @@ struct drm_gem_shmem_object { container_of(obj, struct drm_gem_shmem_object, base) =20 struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, = size_t size); +struct drm_gem_shmem_object *drm_gem_shmem_create_sparse(struct drm_device= *dev, size_t size); struct drm_gem_shmem_object *drm_gem_shmem_create_with_mnt(struct drm_devi= ce *dev, size_t size, struct vfsmount *gemfs); @@ -138,6 +147,9 @@ void drm_gem_shmem_purge(struct drm_gem_shmem_object *s= hmem); struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_shmem_object *s= hmem); struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *= shmem); =20 +struct sg_table *drm_gem_shmem_get_sparse_pages_sgt(struct drm_gem_shmem_o= bject *shmem, + unsigned int n_pages, pgoff_t page_offset); + void drm_gem_shmem_print_info(const struct drm_gem_shmem_object *shmem, struct drm_printer *p, unsigned int indent); =20 --=20 2.47.1