1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Copyright © 2022 Intel Corporation 4 */ 5 #ifndef __XE_PT_WALK__ 6 #define __XE_PT_WALK__ 7 8 #include <linux/pagewalk.h> 9 #include <linux/types.h> 10 11 /** 12 * struct xe_ptw - base class for driver pagetable subclassing. 13 * @children: Pointer to an array of children if any. 14 * @staging: Pointer to an array of staging if any. 15 * 16 * Drivers could subclass this, and if it's a page-directory, typically 17 * embed an array of xe_ptw pointers. 18 */ 19 struct xe_ptw { 20 struct xe_ptw **children; 21 struct xe_ptw **staging; 22 }; 23 24 /** 25 * struct xe_pt_walk - Embeddable struct for walk parameters 26 */ 27 struct xe_pt_walk { 28 /** @ops: The walk ops used for the pagewalk */ 29 const struct xe_pt_walk_ops *ops; 30 /** 31 * @shifts: Array of page-table entry shifts used for the 32 * different levels, starting out with the leaf level 0 33 * page-shift as the first entry. It's legal for this pointer to be 34 * changed during the walk. 35 */ 36 const u64 *shifts; 37 /** @max_level: Highest populated level in @sizes */ 38 unsigned int max_level; 39 /** 40 * @shared_pt_mode: Whether to skip all entries that are private 41 * to the address range and called only for entries that are 42 * shared with other address ranges. Such entries are referred to 43 * as shared pagetables. 44 */ 45 bool shared_pt_mode; 46 /** @staging: Walk staging PT structure */ 47 bool staging; 48 }; 49 50 /** 51 * typedef xe_pt_entry_fn - gpu page-table-walk callback-function 52 * @parent: The parent page.table. 53 * @offset: The offset (number of entries) into the page table. 54 * @level: The level of @parent. 55 * @addr: The virtual address. 56 * @next: The virtual address for the next call, or end address. 57 * @child: Pointer to pointer to child page-table at this @offset. The 58 * function may modify the value pointed to if, for example, allocating a 59 * child page table. 60 * @action: The walk action to take upon return. See <linux/pagewalk.h>. 61 * @walk: The walk parameters. 62 */ 63 typedef int (*xe_pt_entry_fn)(struct xe_ptw *parent, pgoff_t offset, 64 unsigned int level, u64 addr, u64 next, 65 struct xe_ptw **child, 66 enum page_walk_action *action, 67 struct xe_pt_walk *walk); 68 69 /** 70 * struct xe_pt_walk_ops - Walk callbacks. 71 */ 72 struct xe_pt_walk_ops { 73 /** 74 * @pt_entry: Callback to be called for each page table entry prior 75 * to descending to the next level. The returned value of the action 76 * function parameter is honored. 77 */ 78 xe_pt_entry_fn pt_entry; 79 /** 80 * @pt_post_descend: Callback to be called for each page table entry 81 * after return from descending to the next level. The returned value 82 * of the action function parameter is ignored. 83 */ 84 xe_pt_entry_fn pt_post_descend; 85 }; 86 87 int xe_pt_walk_range(struct xe_ptw *parent, unsigned int level, 88 u64 addr, u64 end, struct xe_pt_walk *walk); 89 90 int xe_pt_walk_shared(struct xe_ptw *parent, unsigned int level, 91 u64 addr, u64 end, struct xe_pt_walk *walk); 92 93 /** 94 * xe_pt_covers - Whether the address range covers an entire entry in @level 95 * @addr: Start of the range. 96 * @end: End of range + 1. 97 * @level: Page table level. 98 * @walk: Page table walk info. 99 * 100 * This function is a helper to aid in determining whether a leaf page table 101 * entry can be inserted at this @level. 102 * 103 * Return: Whether the range provided covers exactly an entry at this level. 104 */ 105 static inline bool xe_pt_covers(u64 addr, u64 end, unsigned int level, 106 const struct xe_pt_walk *walk) 107 { 108 u64 pt_size = 1ull << walk->shifts[level]; 109 110 return end - addr == pt_size && IS_ALIGNED(addr, pt_size); 111 } 112 113 /** 114 * xe_pt_num_entries: Number of page-table entries of a given range at this 115 * level 116 * @addr: Start address. 117 * @end: End address. 118 * @level: Page table level. 119 * @walk: Walk info. 120 * 121 * Return: The number of page table entries at this level between @start and 122 * @end. 123 */ 124 static inline pgoff_t 125 xe_pt_num_entries(u64 addr, u64 end, unsigned int level, 126 const struct xe_pt_walk *walk) 127 { 128 u64 pt_size = 1ull << walk->shifts[level]; 129 130 return (round_up(end, pt_size) - round_down(addr, pt_size)) >> 131 walk->shifts[level]; 132 } 133 134 /** 135 * xe_pt_offset: Offset of the page-table entry for a given address. 136 * @addr: The address. 137 * @level: Page table level. 138 * @walk: Walk info. 139 * 140 * Return: The page table entry offset for the given address in a 141 * page table with size indicated by @level. 142 */ 143 static inline pgoff_t 144 xe_pt_offset(u64 addr, unsigned int level, const struct xe_pt_walk *walk) 145 { 146 if (level < walk->max_level) 147 addr &= ((1ull << walk->shifts[level + 1]) - 1); 148 149 return addr >> walk->shifts[level]; 150 } 151 152 #endif 153