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