Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 440fd528 authored by Thierry Reding's avatar Thierry Reding Committed by Dave Airlie
Browse files

drm/mm: Support 4 GiB and larger ranges



The current implementation is limited by the number of addresses that
fit into an unsigned long. This causes problems on 32-bit Tegra where
unsigned long is 32-bit but drm_mm is used to manage an IOVA space of
4 GiB. Given the 32-bit limitation, the range is limited to 4 GiB - 1
(or 4 GiB - 4 KiB for page granularity).

This commit changes the start and size of the range to be an unsigned
64-bit integer, thus allowing much larger ranges to be supported.

[airlied: fix i915 warnings and coloring callback]

Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Reviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

fixupo
parent ed9ed50c
Loading
Loading
Loading
Loading
+79 −73
Original line number Diff line number Diff line
@@ -91,29 +91,29 @@
 */

static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
						unsigned long size,
						u64 size,
						unsigned alignment,
						unsigned long color,
						enum drm_mm_search_flags flags);
static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,
						unsigned long size,
						u64 size,
						unsigned alignment,
						unsigned long color,
						unsigned long start,
						unsigned long end,
						u64 start,
						u64 end,
						enum drm_mm_search_flags flags);

static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
				 struct drm_mm_node *node,
				 unsigned long size, unsigned alignment,
				 u64 size, unsigned alignment,
				 unsigned long color,
				 enum drm_mm_allocator_flags flags)
{
	struct drm_mm *mm = hole_node->mm;
	unsigned long hole_start = drm_mm_hole_node_start(hole_node);
	unsigned long hole_end = drm_mm_hole_node_end(hole_node);
	unsigned long adj_start = hole_start;
	unsigned long adj_end = hole_end;
	u64 hole_start = drm_mm_hole_node_start(hole_node);
	u64 hole_end = drm_mm_hole_node_end(hole_node);
	u64 adj_start = hole_start;
	u64 adj_end = hole_end;

	BUG_ON(node->allocated);

@@ -124,12 +124,15 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
		adj_start = adj_end - size;

	if (alignment) {
		unsigned tmp = adj_start % alignment;
		if (tmp) {
		u64 tmp = adj_start;
		unsigned rem;

		rem = do_div(tmp, alignment);
		if (rem) {
			if (flags & DRM_MM_CREATE_TOP)
				adj_start -= tmp;
				adj_start -= rem;
			else
				adj_start += alignment - tmp;
				adj_start += alignment - rem;
		}
	}

@@ -176,9 +179,9 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
{
	struct drm_mm_node *hole;
	unsigned long end = node->start + node->size;
	unsigned long hole_start;
	unsigned long hole_end;
	u64 end = node->start + node->size;
	u64 hole_start;
	u64 hole_end;

	BUG_ON(node == NULL);

@@ -227,7 +230,7 @@ EXPORT_SYMBOL(drm_mm_reserve_node);
 * 0 on success, -ENOSPC if there's no suitable hole.
 */
int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node,
			       unsigned long size, unsigned alignment,
			       u64 size, unsigned alignment,
			       unsigned long color,
			       enum drm_mm_search_flags sflags,
			       enum drm_mm_allocator_flags aflags)
@@ -246,16 +249,16 @@ EXPORT_SYMBOL(drm_mm_insert_node_generic);

static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
				       struct drm_mm_node *node,
				       unsigned long size, unsigned alignment,
				       u64 size, unsigned alignment,
				       unsigned long color,
				       unsigned long start, unsigned long end,
				       u64 start, u64 end,
				       enum drm_mm_allocator_flags flags)
{
	struct drm_mm *mm = hole_node->mm;
	unsigned long hole_start = drm_mm_hole_node_start(hole_node);
	unsigned long hole_end = drm_mm_hole_node_end(hole_node);
	unsigned long adj_start = hole_start;
	unsigned long adj_end = hole_end;
	u64 hole_start = drm_mm_hole_node_start(hole_node);
	u64 hole_end = drm_mm_hole_node_end(hole_node);
	u64 adj_start = hole_start;
	u64 adj_end = hole_end;

	BUG_ON(!hole_node->hole_follows || node->allocated);

@@ -271,12 +274,15 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
		mm->color_adjust(hole_node, color, &adj_start, &adj_end);

	if (alignment) {
		unsigned tmp = adj_start % alignment;
		if (tmp) {
		u64 tmp = adj_start;
		unsigned rem;

		rem = do_div(tmp, alignment);
		if (rem) {
			if (flags & DRM_MM_CREATE_TOP)
				adj_start -= tmp;
				adj_start -= rem;
			else
				adj_start += alignment - tmp;
				adj_start += alignment - rem;
		}
	}

@@ -324,9 +330,9 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
 * 0 on success, -ENOSPC if there's no suitable hole.
 */
int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node,
					unsigned long size, unsigned alignment,
					u64 size, unsigned alignment,
					unsigned long color,
					unsigned long start, unsigned long end,
					u64 start, u64 end,
					enum drm_mm_search_flags sflags,
					enum drm_mm_allocator_flags aflags)
{
@@ -387,32 +393,34 @@ void drm_mm_remove_node(struct drm_mm_node *node)
}
EXPORT_SYMBOL(drm_mm_remove_node);

static int check_free_hole(unsigned long start, unsigned long end,
			   unsigned long size, unsigned alignment)
static int check_free_hole(u64 start, u64 end, u64 size, unsigned alignment)
{
	if (end - start < size)
		return 0;

	if (alignment) {
		unsigned tmp = start % alignment;
		u64 tmp = start;
		unsigned rem;

		rem = do_div(tmp, alignment);
		if (tmp)
			start += alignment - tmp;
			start += alignment - rem;
	}

	return end >= start + size;
}

static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
						      unsigned long size,
						      u64 size,
						      unsigned alignment,
						      unsigned long color,
						      enum drm_mm_search_flags flags)
{
	struct drm_mm_node *entry;
	struct drm_mm_node *best;
	unsigned long adj_start;
	unsigned long adj_end;
	unsigned long best_size;
	u64 adj_start;
	u64 adj_end;
	u64 best_size;

	BUG_ON(mm->scanned_blocks);

@@ -421,7 +429,7 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,

	__drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
			       flags & DRM_MM_SEARCH_BELOW) {
		unsigned long hole_size = adj_end - adj_start;
		u64 hole_size = adj_end - adj_start;

		if (mm->color_adjust) {
			mm->color_adjust(entry, color, &adj_start, &adj_end);
@@ -445,18 +453,18 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
}

static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,
							unsigned long size,
							u64 size,
							unsigned alignment,
							unsigned long color,
							unsigned long start,
							unsigned long end,
							u64 start,
							u64 end,
							enum drm_mm_search_flags flags)
{
	struct drm_mm_node *entry;
	struct drm_mm_node *best;
	unsigned long adj_start;
	unsigned long adj_end;
	unsigned long best_size;
	u64 adj_start;
	u64 adj_end;
	u64 best_size;

	BUG_ON(mm->scanned_blocks);

@@ -465,7 +473,7 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_

	__drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
			       flags & DRM_MM_SEARCH_BELOW) {
		unsigned long hole_size = adj_end - adj_start;
		u64 hole_size = adj_end - adj_start;

		if (adj_start < start)
			adj_start = start;
@@ -561,7 +569,7 @@ EXPORT_SYMBOL(drm_mm_replace_node);
 * adding/removing nodes to/from the scan list are allowed.
 */
void drm_mm_init_scan(struct drm_mm *mm,
		      unsigned long size,
		      u64 size,
		      unsigned alignment,
		      unsigned long color)
{
@@ -594,11 +602,11 @@ EXPORT_SYMBOL(drm_mm_init_scan);
 * adding/removing nodes to/from the scan list are allowed.
 */
void drm_mm_init_scan_with_range(struct drm_mm *mm,
				 unsigned long size,
				 u64 size,
				 unsigned alignment,
				 unsigned long color,
				 unsigned long start,
				 unsigned long end)
				 u64 start,
				 u64 end)
{
	mm->scan_color = color;
	mm->scan_alignment = alignment;
@@ -627,8 +635,8 @@ bool drm_mm_scan_add_block(struct drm_mm_node *node)
{
	struct drm_mm *mm = node->mm;
	struct drm_mm_node *prev_node;
	unsigned long hole_start, hole_end;
	unsigned long adj_start, adj_end;
	u64 hole_start, hole_end;
	u64 adj_start, adj_end;

	mm->scanned_blocks++;

@@ -731,7 +739,7 @@ EXPORT_SYMBOL(drm_mm_clean);
 *
 * Note that @mm must be cleared to 0 before calling this function.
 */
void drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
void drm_mm_init(struct drm_mm * mm, u64 start, u64 size)
{
	INIT_LIST_HEAD(&mm->hole_stack);
	mm->scanned_blocks = 0;
@@ -766,18 +774,17 @@ void drm_mm_takedown(struct drm_mm * mm)
}
EXPORT_SYMBOL(drm_mm_takedown);

static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
static u64 drm_mm_debug_hole(struct drm_mm_node *entry,
				     const char *prefix)
{
	unsigned long hole_start, hole_end, hole_size;
	u64 hole_start, hole_end, hole_size;

	if (entry->hole_follows) {
		hole_start = drm_mm_hole_node_start(entry);
		hole_end = drm_mm_hole_node_end(entry);
		hole_size = hole_end - hole_start;
		printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
			prefix, hole_start, hole_end,
			hole_size);
		pr_debug("%s %#llx-%#llx: %llu: free\n", prefix, hole_start,
			 hole_end, hole_size);
		return hole_size;
	}

@@ -792,35 +799,34 @@ static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
{
	struct drm_mm_node *entry;
	unsigned long total_used = 0, total_free = 0, total = 0;
	u64 total_used = 0, total_free = 0, total = 0;

	total_free += drm_mm_debug_hole(&mm->head_node, prefix);

	drm_mm_for_each_node(entry, mm) {
		printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: used\n",
			prefix, entry->start, entry->start + entry->size,
			entry->size);
		pr_debug("%s %#llx-%#llx: %llu: used\n", prefix, entry->start,
			 entry->start + entry->size, entry->size);
		total_used += entry->size;
		total_free += drm_mm_debug_hole(entry, prefix);
	}
	total = total_free + total_used;

	printk(KERN_DEBUG "%s total: %lu, used %lu free %lu\n", prefix, total,
	pr_debug("%s total: %llu, used %llu free %llu\n", prefix, total,
		 total_used, total_free);
}
EXPORT_SYMBOL(drm_mm_debug_table);

#if defined(CONFIG_DEBUG_FS)
static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry)
static u64 drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry)
{
	unsigned long hole_start, hole_end, hole_size;
	u64 hole_start, hole_end, hole_size;

	if (entry->hole_follows) {
		hole_start = drm_mm_hole_node_start(entry);
		hole_end = drm_mm_hole_node_end(entry);
		hole_size = hole_end - hole_start;
		seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
				hole_start, hole_end, hole_size);
		seq_printf(m, "%#llx-%#llx: %llu: free\n", hole_start,
			   hole_end, hole_size);
		return hole_size;
	}

@@ -835,20 +841,20 @@ static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *en
int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
{
	struct drm_mm_node *entry;
	unsigned long total_used = 0, total_free = 0, total = 0;
	u64 total_used = 0, total_free = 0, total = 0;

	total_free += drm_mm_dump_hole(m, &mm->head_node);

	drm_mm_for_each_node(entry, mm) {
		seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: used\n",
				entry->start, entry->start + entry->size,
				entry->size);
		seq_printf(m, "%#016llx-%#016llx: %llu: used\n", entry->start,
			   entry->start + entry->size, entry->size);
		total_used += entry->size;
		total_free += drm_mm_dump_hole(m, entry);
	}
	total = total_free + total_used;

	seq_printf(m, "total: %lu, used %lu free %lu\n", total, total_used, total_free);
	seq_printf(m, "total: %llu, used %llu free %llu\n", total,
		   total_used, total_free);
	return 0;
}
EXPORT_SYMBOL(drm_mm_dump_table);
+2 −2
Original line number Diff line number Diff line
@@ -152,12 +152,12 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
			seq_puts(m, " (pp");
		else
			seq_puts(m, " (g");
		seq_printf(m, "gtt offset: %08lx, size: %08lx, type: %u)",
		seq_printf(m, "gtt offset: %08llx, size: %08llx, type: %u)",
			   vma->node.start, vma->node.size,
			   vma->ggtt_view.type);
	}
	if (obj->stolen)
		seq_printf(m, " (stolen: %08lx)", obj->stolen->start);
		seq_printf(m, " (stolen: %08llx)", obj->stolen->start);
	if (obj->pin_mappable || obj->fault_mappable) {
		char s[3], *t = s;
		if (obj->pin_mappable)
+3 −3
Original line number Diff line number Diff line
@@ -1145,7 +1145,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)

	ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true);

	DRM_DEBUG_DRIVER("Allocated pde space (%ldM) at GTT entry: %lx\n",
	DRM_DEBUG_DRIVER("Allocated pde space (%lldM) at GTT entry: %llx\n",
			 ppgtt->node.size >> 20,
			 ppgtt->node.start / PAGE_SIZE);

@@ -1713,8 +1713,8 @@ void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)

static void i915_gtt_color_adjust(struct drm_mm_node *node,
				  unsigned long color,
				  unsigned long *start,
				  unsigned long *end)
				  u64 *start,
				  u64 *end)
{
	if (node->color != color)
		*start += 4096;
+26 −26
Original line number Diff line number Diff line
@@ -68,8 +68,8 @@ struct drm_mm_node {
	unsigned scanned_preceeds_hole : 1;
	unsigned allocated : 1;
	unsigned long color;
	unsigned long start;
	unsigned long size;
	u64 start;
	u64 size;
	struct drm_mm *mm;
};

@@ -82,16 +82,16 @@ struct drm_mm {
	unsigned int scan_check_range : 1;
	unsigned scan_alignment;
	unsigned long scan_color;
	unsigned long scan_size;
	unsigned long scan_hit_start;
	unsigned long scan_hit_end;
	u64 scan_size;
	u64 scan_hit_start;
	u64 scan_hit_end;
	unsigned scanned_blocks;
	unsigned long scan_start;
	unsigned long scan_end;
	u64 scan_start;
	u64 scan_end;
	struct drm_mm_node *prev_scanned_node;

	void (*color_adjust)(struct drm_mm_node *node, unsigned long color,
			     unsigned long *start, unsigned long *end);
			     u64 *start, u64 *end);
};

/**
@@ -124,7 +124,7 @@ static inline bool drm_mm_initialized(struct drm_mm *mm)
	return mm->hole_stack.next;
}

static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_node)
static inline u64 __drm_mm_hole_node_start(struct drm_mm_node *hole_node)
{
	return hole_node->start + hole_node->size;
}
@@ -140,13 +140,13 @@ static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_no
 * Returns:
 * Start of the subsequent hole.
 */
static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node)
static inline u64 drm_mm_hole_node_start(struct drm_mm_node *hole_node)
{
	BUG_ON(!hole_node->hole_follows);
	return __drm_mm_hole_node_start(hole_node);
}

static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node)
static inline u64 __drm_mm_hole_node_end(struct drm_mm_node *hole_node)
{
	return list_entry(hole_node->node_list.next,
			  struct drm_mm_node, node_list)->start;
@@ -163,7 +163,7 @@ static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node
 * Returns:
 * End of the subsequent hole.
 */
static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
static inline u64 drm_mm_hole_node_end(struct drm_mm_node *hole_node)
{
	return __drm_mm_hole_node_end(hole_node);
}
@@ -222,7 +222,7 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node);

int drm_mm_insert_node_generic(struct drm_mm *mm,
			       struct drm_mm_node *node,
			       unsigned long size,
			       u64 size,
			       unsigned alignment,
			       unsigned long color,
			       enum drm_mm_search_flags sflags,
@@ -245,7 +245,7 @@ int drm_mm_insert_node_generic(struct drm_mm *mm,
 */
static inline int drm_mm_insert_node(struct drm_mm *mm,
				     struct drm_mm_node *node,
				     unsigned long size,
				     u64 size,
				     unsigned alignment,
				     enum drm_mm_search_flags flags)
{
@@ -255,11 +255,11 @@ static inline int drm_mm_insert_node(struct drm_mm *mm,

int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
					struct drm_mm_node *node,
					unsigned long size,
					u64 size,
					unsigned alignment,
					unsigned long color,
					unsigned long start,
					unsigned long end,
					u64 start,
					u64 end,
					enum drm_mm_search_flags sflags,
					enum drm_mm_allocator_flags aflags);
/**
@@ -282,10 +282,10 @@ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
 */
static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
					      struct drm_mm_node *node,
					      unsigned long size,
					      u64 size,
					      unsigned alignment,
					      unsigned long start,
					      unsigned long end,
					      u64 start,
					      u64 end,
					      enum drm_mm_search_flags flags)
{
	return drm_mm_insert_node_in_range_generic(mm, node, size, alignment,
@@ -296,21 +296,21 @@ static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
void drm_mm_remove_node(struct drm_mm_node *node);
void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new);
void drm_mm_init(struct drm_mm *mm,
		 unsigned long start,
		 unsigned long size);
		 u64 start,
		 u64 size);
void drm_mm_takedown(struct drm_mm *mm);
bool drm_mm_clean(struct drm_mm *mm);

void drm_mm_init_scan(struct drm_mm *mm,
		      unsigned long size,
		      u64 size,
		      unsigned alignment,
		      unsigned long color);
void drm_mm_init_scan_with_range(struct drm_mm *mm,
				 unsigned long size,
				 u64 size,
				 unsigned alignment,
				 unsigned long color,
				 unsigned long start,
				 unsigned long end);
				 u64 start,
				 u64 end);
bool drm_mm_scan_add_block(struct drm_mm_node *node);
bool drm_mm_scan_remove_block(struct drm_mm_node *node);