xref: /linux/drivers/iommu/generic_pt/pt_fmt_defaults.h (revision 7c5b184db7145fd417785377337bd15c4fe1d0f4)
1*7c5b184dSJason Gunthorpe /* SPDX-License-Identifier: GPL-2.0-only */
2*7c5b184dSJason Gunthorpe /*
3*7c5b184dSJason Gunthorpe  * Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES
4*7c5b184dSJason Gunthorpe  *
5*7c5b184dSJason Gunthorpe  * Default definitions for formats that don't define these functions.
6*7c5b184dSJason Gunthorpe  */
7*7c5b184dSJason Gunthorpe #ifndef __GENERIC_PT_PT_FMT_DEFAULTS_H
8*7c5b184dSJason Gunthorpe #define __GENERIC_PT_PT_FMT_DEFAULTS_H
9*7c5b184dSJason Gunthorpe 
10*7c5b184dSJason Gunthorpe #include "pt_defs.h"
11*7c5b184dSJason Gunthorpe #include <linux/log2.h>
12*7c5b184dSJason Gunthorpe 
13*7c5b184dSJason Gunthorpe /* Header self-compile default defines */
14*7c5b184dSJason Gunthorpe #ifndef pt_load_entry_raw
15*7c5b184dSJason Gunthorpe #include "fmt/amdv1.h"
16*7c5b184dSJason Gunthorpe #endif
17*7c5b184dSJason Gunthorpe 
18*7c5b184dSJason Gunthorpe /*
19*7c5b184dSJason Gunthorpe  * The format must provide PT_GRANULE_LG2SZ, PT_TABLEMEM_LG2SZ, and
20*7c5b184dSJason Gunthorpe  * PT_ITEM_WORD_SIZE. They must be the same at every level excluding the top.
21*7c5b184dSJason Gunthorpe  */
22*7c5b184dSJason Gunthorpe #ifndef pt_table_item_lg2sz
23*7c5b184dSJason Gunthorpe static inline unsigned int pt_table_item_lg2sz(const struct pt_state *pts)
24*7c5b184dSJason Gunthorpe {
25*7c5b184dSJason Gunthorpe 	return PT_GRANULE_LG2SZ +
26*7c5b184dSJason Gunthorpe 	       (PT_TABLEMEM_LG2SZ - ilog2(PT_ITEM_WORD_SIZE)) * pts->level;
27*7c5b184dSJason Gunthorpe }
28*7c5b184dSJason Gunthorpe #endif
29*7c5b184dSJason Gunthorpe 
30*7c5b184dSJason Gunthorpe #ifndef pt_pgsz_lg2_to_level
31*7c5b184dSJason Gunthorpe static inline unsigned int pt_pgsz_lg2_to_level(struct pt_common *common,
32*7c5b184dSJason Gunthorpe 						unsigned int pgsize_lg2)
33*7c5b184dSJason Gunthorpe {
34*7c5b184dSJason Gunthorpe 	return ((unsigned int)(pgsize_lg2 - PT_GRANULE_LG2SZ)) /
35*7c5b184dSJason Gunthorpe 	       (PT_TABLEMEM_LG2SZ - ilog2(PT_ITEM_WORD_SIZE));
36*7c5b184dSJason Gunthorpe }
37*7c5b184dSJason Gunthorpe #endif
38*7c5b184dSJason Gunthorpe 
39*7c5b184dSJason Gunthorpe /*
40*7c5b184dSJason Gunthorpe  * If not supplied by the format then contiguous pages are not supported.
41*7c5b184dSJason Gunthorpe  *
42*7c5b184dSJason Gunthorpe  * If contiguous pages are supported then the format must also provide
43*7c5b184dSJason Gunthorpe  * pt_contig_count_lg2() if it supports a single contiguous size per level,
44*7c5b184dSJason Gunthorpe  * or pt_possible_sizes() if it supports multiple sizes per level.
45*7c5b184dSJason Gunthorpe  */
46*7c5b184dSJason Gunthorpe #ifndef pt_entry_num_contig_lg2
47*7c5b184dSJason Gunthorpe static inline unsigned int pt_entry_num_contig_lg2(const struct pt_state *pts)
48*7c5b184dSJason Gunthorpe {
49*7c5b184dSJason Gunthorpe 	return ilog2(1);
50*7c5b184dSJason Gunthorpe }
51*7c5b184dSJason Gunthorpe 
52*7c5b184dSJason Gunthorpe /*
53*7c5b184dSJason Gunthorpe  * Return the number of contiguous OA items forming an entry at this table level
54*7c5b184dSJason Gunthorpe  */
55*7c5b184dSJason Gunthorpe static inline unsigned short pt_contig_count_lg2(const struct pt_state *pts)
56*7c5b184dSJason Gunthorpe {
57*7c5b184dSJason Gunthorpe 	return ilog2(1);
58*7c5b184dSJason Gunthorpe }
59*7c5b184dSJason Gunthorpe #endif
60*7c5b184dSJason Gunthorpe 
61*7c5b184dSJason Gunthorpe /* If not supplied by the format then dirty tracking is not supported */
62*7c5b184dSJason Gunthorpe #ifndef pt_entry_is_write_dirty
63*7c5b184dSJason Gunthorpe static inline bool pt_entry_is_write_dirty(const struct pt_state *pts)
64*7c5b184dSJason Gunthorpe {
65*7c5b184dSJason Gunthorpe 	return false;
66*7c5b184dSJason Gunthorpe }
67*7c5b184dSJason Gunthorpe 
68*7c5b184dSJason Gunthorpe static inline void pt_entry_make_write_clean(struct pt_state *pts)
69*7c5b184dSJason Gunthorpe {
70*7c5b184dSJason Gunthorpe }
71*7c5b184dSJason Gunthorpe 
72*7c5b184dSJason Gunthorpe static inline bool pt_dirty_supported(struct pt_common *common)
73*7c5b184dSJason Gunthorpe {
74*7c5b184dSJason Gunthorpe 	return false;
75*7c5b184dSJason Gunthorpe }
76*7c5b184dSJason Gunthorpe #else
77*7c5b184dSJason Gunthorpe /* If not supplied then dirty tracking is always enabled */
78*7c5b184dSJason Gunthorpe #ifndef pt_dirty_supported
79*7c5b184dSJason Gunthorpe static inline bool pt_dirty_supported(struct pt_common *common)
80*7c5b184dSJason Gunthorpe {
81*7c5b184dSJason Gunthorpe 	return true;
82*7c5b184dSJason Gunthorpe }
83*7c5b184dSJason Gunthorpe #endif
84*7c5b184dSJason Gunthorpe #endif
85*7c5b184dSJason Gunthorpe 
86*7c5b184dSJason Gunthorpe #ifndef pt_entry_make_write_dirty
87*7c5b184dSJason Gunthorpe static inline bool pt_entry_make_write_dirty(struct pt_state *pts)
88*7c5b184dSJason Gunthorpe {
89*7c5b184dSJason Gunthorpe 	return false;
90*7c5b184dSJason Gunthorpe }
91*7c5b184dSJason Gunthorpe #endif
92*7c5b184dSJason Gunthorpe 
93*7c5b184dSJason Gunthorpe /*
94*7c5b184dSJason Gunthorpe  * Format supplies either:
95*7c5b184dSJason Gunthorpe  *   pt_entry_oa - OA is at the start of a contiguous entry
96*7c5b184dSJason Gunthorpe  * or
97*7c5b184dSJason Gunthorpe  *   pt_item_oa  - OA is adjusted for every item in a contiguous entry
98*7c5b184dSJason Gunthorpe  *
99*7c5b184dSJason Gunthorpe  * Build the missing one
100*7c5b184dSJason Gunthorpe  *
101*7c5b184dSJason Gunthorpe  * The internal helper _pt_entry_oa_fast() allows generating
102*7c5b184dSJason Gunthorpe  * an efficient pt_entry_oa_exact(), it doesn't care which
103*7c5b184dSJason Gunthorpe  * option is selected.
104*7c5b184dSJason Gunthorpe  */
105*7c5b184dSJason Gunthorpe #ifdef pt_entry_oa
106*7c5b184dSJason Gunthorpe static inline pt_oaddr_t pt_item_oa(const struct pt_state *pts)
107*7c5b184dSJason Gunthorpe {
108*7c5b184dSJason Gunthorpe 	return pt_entry_oa(pts) |
109*7c5b184dSJason Gunthorpe 	       log2_mul(pts->index, pt_table_item_lg2sz(pts));
110*7c5b184dSJason Gunthorpe }
111*7c5b184dSJason Gunthorpe #define _pt_entry_oa_fast pt_entry_oa
112*7c5b184dSJason Gunthorpe #endif
113*7c5b184dSJason Gunthorpe 
114*7c5b184dSJason Gunthorpe #ifdef pt_item_oa
115*7c5b184dSJason Gunthorpe static inline pt_oaddr_t pt_entry_oa(const struct pt_state *pts)
116*7c5b184dSJason Gunthorpe {
117*7c5b184dSJason Gunthorpe 	return log2_set_mod(pt_item_oa(pts), 0,
118*7c5b184dSJason Gunthorpe 			    pt_entry_num_contig_lg2(pts) +
119*7c5b184dSJason Gunthorpe 				    pt_table_item_lg2sz(pts));
120*7c5b184dSJason Gunthorpe }
121*7c5b184dSJason Gunthorpe #define _pt_entry_oa_fast pt_item_oa
122*7c5b184dSJason Gunthorpe #endif
123*7c5b184dSJason Gunthorpe 
124*7c5b184dSJason Gunthorpe /*
125*7c5b184dSJason Gunthorpe  * If not supplied by the format then use the constant
126*7c5b184dSJason Gunthorpe  * PT_MAX_OUTPUT_ADDRESS_LG2.
127*7c5b184dSJason Gunthorpe  */
128*7c5b184dSJason Gunthorpe #ifndef pt_max_oa_lg2
129*7c5b184dSJason Gunthorpe static inline unsigned int
130*7c5b184dSJason Gunthorpe pt_max_oa_lg2(const struct pt_common *common)
131*7c5b184dSJason Gunthorpe {
132*7c5b184dSJason Gunthorpe 	return PT_MAX_OUTPUT_ADDRESS_LG2;
133*7c5b184dSJason Gunthorpe }
134*7c5b184dSJason Gunthorpe #endif
135*7c5b184dSJason Gunthorpe 
136*7c5b184dSJason Gunthorpe #ifndef pt_has_system_page_size
137*7c5b184dSJason Gunthorpe static inline bool pt_has_system_page_size(const struct pt_common *common)
138*7c5b184dSJason Gunthorpe {
139*7c5b184dSJason Gunthorpe 	return PT_GRANULE_LG2SZ == PAGE_SHIFT;
140*7c5b184dSJason Gunthorpe }
141*7c5b184dSJason Gunthorpe #endif
142*7c5b184dSJason Gunthorpe 
143*7c5b184dSJason Gunthorpe /*
144*7c5b184dSJason Gunthorpe  * If not supplied by the format then assume only one contiguous size determined
145*7c5b184dSJason Gunthorpe  * by pt_contig_count_lg2()
146*7c5b184dSJason Gunthorpe  */
147*7c5b184dSJason Gunthorpe #ifndef pt_possible_sizes
148*7c5b184dSJason Gunthorpe static inline unsigned short pt_contig_count_lg2(const struct pt_state *pts);
149*7c5b184dSJason Gunthorpe 
150*7c5b184dSJason Gunthorpe /* Return a bitmap of possible leaf page sizes at this level */
151*7c5b184dSJason Gunthorpe static inline pt_vaddr_t pt_possible_sizes(const struct pt_state *pts)
152*7c5b184dSJason Gunthorpe {
153*7c5b184dSJason Gunthorpe 	unsigned int isz_lg2 = pt_table_item_lg2sz(pts);
154*7c5b184dSJason Gunthorpe 
155*7c5b184dSJason Gunthorpe 	if (!pt_can_have_leaf(pts))
156*7c5b184dSJason Gunthorpe 		return 0;
157*7c5b184dSJason Gunthorpe 	return log2_to_int(isz_lg2) |
158*7c5b184dSJason Gunthorpe 	       log2_to_int(pt_contig_count_lg2(pts) + isz_lg2);
159*7c5b184dSJason Gunthorpe }
160*7c5b184dSJason Gunthorpe #endif
161*7c5b184dSJason Gunthorpe 
162*7c5b184dSJason Gunthorpe /* If not supplied by the format then use 0. */
163*7c5b184dSJason Gunthorpe #ifndef pt_full_va_prefix
164*7c5b184dSJason Gunthorpe static inline pt_vaddr_t pt_full_va_prefix(const struct pt_common *common)
165*7c5b184dSJason Gunthorpe {
166*7c5b184dSJason Gunthorpe 	return 0;
167*7c5b184dSJason Gunthorpe }
168*7c5b184dSJason Gunthorpe #endif
169*7c5b184dSJason Gunthorpe 
170*7c5b184dSJason Gunthorpe /* If not supplied by the format then zero fill using PT_ITEM_WORD_SIZE */
171*7c5b184dSJason Gunthorpe #ifndef pt_clear_entries
172*7c5b184dSJason Gunthorpe static inline void pt_clear_entries64(struct pt_state *pts,
173*7c5b184dSJason Gunthorpe 				      unsigned int num_contig_lg2)
174*7c5b184dSJason Gunthorpe {
175*7c5b184dSJason Gunthorpe 	u64 *tablep = pt_cur_table(pts, u64) + pts->index;
176*7c5b184dSJason Gunthorpe 	u64 *end = tablep + log2_to_int(num_contig_lg2);
177*7c5b184dSJason Gunthorpe 
178*7c5b184dSJason Gunthorpe 	PT_WARN_ON(log2_mod(pts->index, num_contig_lg2));
179*7c5b184dSJason Gunthorpe 	for (; tablep != end; tablep++)
180*7c5b184dSJason Gunthorpe 		WRITE_ONCE(*tablep, 0);
181*7c5b184dSJason Gunthorpe }
182*7c5b184dSJason Gunthorpe 
183*7c5b184dSJason Gunthorpe static inline void pt_clear_entries32(struct pt_state *pts,
184*7c5b184dSJason Gunthorpe 				      unsigned int num_contig_lg2)
185*7c5b184dSJason Gunthorpe {
186*7c5b184dSJason Gunthorpe 	u32 *tablep = pt_cur_table(pts, u32) + pts->index;
187*7c5b184dSJason Gunthorpe 	u32 *end = tablep + log2_to_int(num_contig_lg2);
188*7c5b184dSJason Gunthorpe 
189*7c5b184dSJason Gunthorpe 	PT_WARN_ON(log2_mod(pts->index, num_contig_lg2));
190*7c5b184dSJason Gunthorpe 	for (; tablep != end; tablep++)
191*7c5b184dSJason Gunthorpe 		WRITE_ONCE(*tablep, 0);
192*7c5b184dSJason Gunthorpe }
193*7c5b184dSJason Gunthorpe 
194*7c5b184dSJason Gunthorpe static inline void pt_clear_entries(struct pt_state *pts,
195*7c5b184dSJason Gunthorpe 				    unsigned int num_contig_lg2)
196*7c5b184dSJason Gunthorpe {
197*7c5b184dSJason Gunthorpe 	if (PT_ITEM_WORD_SIZE == sizeof(u32))
198*7c5b184dSJason Gunthorpe 		pt_clear_entries32(pts, num_contig_lg2);
199*7c5b184dSJason Gunthorpe 	else
200*7c5b184dSJason Gunthorpe 		pt_clear_entries64(pts, num_contig_lg2);
201*7c5b184dSJason Gunthorpe }
202*7c5b184dSJason Gunthorpe #define pt_clear_entries pt_clear_entries
203*7c5b184dSJason Gunthorpe #endif
204*7c5b184dSJason Gunthorpe 
205*7c5b184dSJason Gunthorpe /*
206*7c5b184dSJason Gunthorpe  * Format can call in the pt_install_leaf_entry() to check the arguments are all
207*7c5b184dSJason Gunthorpe  * aligned correctly.
208*7c5b184dSJason Gunthorpe  */
209*7c5b184dSJason Gunthorpe static inline bool pt_check_install_leaf_args(struct pt_state *pts,
210*7c5b184dSJason Gunthorpe 					      pt_oaddr_t oa,
211*7c5b184dSJason Gunthorpe 					      unsigned int oasz_lg2)
212*7c5b184dSJason Gunthorpe {
213*7c5b184dSJason Gunthorpe 	unsigned int isz_lg2 = pt_table_item_lg2sz(pts);
214*7c5b184dSJason Gunthorpe 
215*7c5b184dSJason Gunthorpe 	if (PT_WARN_ON(oalog2_mod(oa, oasz_lg2)))
216*7c5b184dSJason Gunthorpe 		return false;
217*7c5b184dSJason Gunthorpe 
218*7c5b184dSJason Gunthorpe #ifdef pt_possible_sizes
219*7c5b184dSJason Gunthorpe 	if (PT_WARN_ON(isz_lg2 > oasz_lg2 ||
220*7c5b184dSJason Gunthorpe 		       oasz_lg2 > isz_lg2 + pt_num_items_lg2(pts)))
221*7c5b184dSJason Gunthorpe 		return false;
222*7c5b184dSJason Gunthorpe #else
223*7c5b184dSJason Gunthorpe 	if (PT_WARN_ON(oasz_lg2 != isz_lg2 &&
224*7c5b184dSJason Gunthorpe 		       oasz_lg2 != isz_lg2 + pt_contig_count_lg2(pts)))
225*7c5b184dSJason Gunthorpe 		return false;
226*7c5b184dSJason Gunthorpe #endif
227*7c5b184dSJason Gunthorpe 
228*7c5b184dSJason Gunthorpe 	if (PT_WARN_ON(oalog2_mod(pts->index, oasz_lg2 - isz_lg2)))
229*7c5b184dSJason Gunthorpe 		return false;
230*7c5b184dSJason Gunthorpe 	return true;
231*7c5b184dSJason Gunthorpe }
232*7c5b184dSJason Gunthorpe 
233*7c5b184dSJason Gunthorpe #endif
234