Skip to content

Commit d3f6bac

Browse files
BobBecketttursulin
authored andcommitted
drm/i915: stop abusing swiotlb_max_segment
swiotlb_max_segment used to return either the maximum size that swiotlb could bounce, or for Xen PV PAGE_SIZE even if swiotlb could bounce buffer larger mappings. This made i915 on Xen PV work as it bypasses the coherency aspect of the DMA API and can't cope with bounce buffering and this avoided bounce buffering for the Xen/PV case. So instead of adding this hack back, check for Xen/PV directly in i915 for the Xen case and otherwise use the proper DMA API helper to query the maximum mapping size. Replace swiotlb_max_segment() calls with dma_max_mapping_size(). In i915_gem_object_get_pages_internal() no longer consider max_segment only if CONFIG_SWIOTLB is enabled. There can be other (iommu related) causes of specific max segment sizes. Fixes: a2daa27 ("swiotlb: simplify swiotlb_max_segment") Reported-by: Marek Marczykowski-Górecki <[email protected]> Signed-off-by: Robert Beckett <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> [hch: added the Xen hack, rewrote the changelog] Reviewed-by: Tvrtko Ursulin <[email protected]> Signed-off-by: Tvrtko Ursulin <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] (cherry picked from commit 78a07fe) Signed-off-by: Tvrtko Ursulin <[email protected]>
1 parent d7164a5 commit d3f6bac

File tree

5 files changed

+29
-32
lines changed

5 files changed

+29
-32
lines changed

drivers/gpu/drm/i915/gem/i915_gem_internal.c

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
#include <linux/scatterlist.h>
88
#include <linux/slab.h>
9-
#include <linux/swiotlb.h>
109

1110
#include "i915_drv.h"
1211
#include "i915_gem.h"
@@ -38,22 +37,12 @@ static int i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj)
3837
struct scatterlist *sg;
3938
unsigned int sg_page_sizes;
4039
unsigned int npages;
41-
int max_order;
40+
int max_order = MAX_ORDER;
41+
unsigned int max_segment;
4242
gfp_t gfp;
4343

44-
max_order = MAX_ORDER;
45-
#ifdef CONFIG_SWIOTLB
46-
if (is_swiotlb_active(obj->base.dev->dev)) {
47-
unsigned int max_segment;
48-
49-
max_segment = swiotlb_max_segment();
50-
if (max_segment) {
51-
max_segment = max_t(unsigned int, max_segment,
52-
PAGE_SIZE) >> PAGE_SHIFT;
53-
max_order = min(max_order, ilog2(max_segment));
54-
}
55-
}
56-
#endif
44+
max_segment = i915_sg_segment_size(i915->drm.dev) >> PAGE_SHIFT;
45+
max_order = min(max_order, get_order(max_segment));
5746

5847
gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_RECLAIMABLE;
5948
if (IS_I965GM(i915) || IS_I965G(i915)) {

drivers/gpu/drm/i915/gem/i915_gem_shmem.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ static int shmem_get_pages(struct drm_i915_gem_object *obj)
194194
struct intel_memory_region *mem = obj->mm.region;
195195
struct address_space *mapping = obj->base.filp->f_mapping;
196196
const unsigned long page_count = obj->base.size / PAGE_SIZE;
197-
unsigned int max_segment = i915_sg_segment_size();
197+
unsigned int max_segment = i915_sg_segment_size(i915->drm.dev);
198198
struct sg_table *st;
199199
struct sgt_iter sgt_iter;
200200
struct page *page;

drivers/gpu/drm/i915/gem/i915_gem_ttm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ static int i915_ttm_tt_shmem_populate(struct ttm_device *bdev,
189189
struct drm_i915_private *i915 = container_of(bdev, typeof(*i915), bdev);
190190
struct intel_memory_region *mr = i915->mm.regions[INTEL_MEMORY_SYSTEM];
191191
struct i915_ttm_tt *i915_tt = container_of(ttm, typeof(*i915_tt), ttm);
192-
const unsigned int max_segment = i915_sg_segment_size();
192+
const unsigned int max_segment = i915_sg_segment_size(i915->drm.dev);
193193
const size_t size = (size_t)ttm->num_pages << PAGE_SHIFT;
194194
struct file *filp = i915_tt->filp;
195195
struct sgt_iter sgt_iter;
@@ -538,7 +538,7 @@ static struct i915_refct_sgt *i915_ttm_tt_get_st(struct ttm_tt *ttm)
538538
ret = sg_alloc_table_from_pages_segment(st,
539539
ttm->pages, ttm->num_pages,
540540
0, (unsigned long)ttm->num_pages << PAGE_SHIFT,
541-
i915_sg_segment_size(), GFP_KERNEL);
541+
i915_sg_segment_size(i915_tt->dev), GFP_KERNEL);
542542
if (ret) {
543543
st->sgl = NULL;
544544
return ERR_PTR(ret);

drivers/gpu/drm/i915/gem/i915_gem_userptr.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ static void i915_gem_object_userptr_drop_ref(struct drm_i915_gem_object *obj)
129129
static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
130130
{
131131
const unsigned long num_pages = obj->base.size >> PAGE_SHIFT;
132-
unsigned int max_segment = i915_sg_segment_size();
132+
unsigned int max_segment = i915_sg_segment_size(obj->base.dev->dev);
133133
struct sg_table *st;
134134
unsigned int sg_page_sizes;
135135
struct page **pvec;

drivers/gpu/drm/i915/i915_scatterlist.h

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99

1010
#include <linux/pfn.h>
1111
#include <linux/scatterlist.h>
12-
#include <linux/swiotlb.h>
12+
#include <linux/dma-mapping.h>
13+
#include <xen/xen.h>
1314

1415
#include "i915_gem.h"
1516

@@ -127,19 +128,26 @@ static inline unsigned int i915_sg_dma_sizes(struct scatterlist *sg)
127128
return page_sizes;
128129
}
129130

130-
static inline unsigned int i915_sg_segment_size(void)
131+
static inline unsigned int i915_sg_segment_size(struct device *dev)
131132
{
132-
unsigned int size = swiotlb_max_segment();
133-
134-
if (size == 0)
135-
size = UINT_MAX;
136-
137-
size = rounddown(size, PAGE_SIZE);
138-
/* swiotlb_max_segment_size can return 1 byte when it means one page. */
139-
if (size < PAGE_SIZE)
140-
size = PAGE_SIZE;
141-
142-
return size;
133+
size_t max = min_t(size_t, UINT_MAX, dma_max_mapping_size(dev));
134+
135+
/*
136+
* For Xen PV guests pages aren't contiguous in DMA (machine) address
137+
* space. The DMA API takes care of that both in dma_alloc_* (by
138+
* calling into the hypervisor to make the pages contiguous) and in
139+
* dma_map_* (by bounce buffering). But i915 abuses ignores the
140+
* coherency aspects of the DMA API and thus can't cope with bounce
141+
* buffering actually happening, so add a hack here to force small
142+
* allocations and mappings when running in PV mode on Xen.
143+
*
144+
* Note this will still break if bounce buffering is required for other
145+
* reasons, like confidential computing hypervisors or PCIe root ports
146+
* with addressing limitations.
147+
*/
148+
if (xen_pv_domain())
149+
max = PAGE_SIZE;
150+
return round_down(max, PAGE_SIZE);
143151
}
144152

145153
bool i915_sg_trim(struct sg_table *orig_st);

0 commit comments

Comments
 (0)