17c5b184dSJason Gunthorpe /* SPDX-License-Identifier: GPL-2.0-only */
27c5b184dSJason Gunthorpe /*
37c5b184dSJason Gunthorpe * Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES
47c5b184dSJason Gunthorpe *
57c5b184dSJason Gunthorpe * Default definitions for formats that don't define these functions.
67c5b184dSJason Gunthorpe */
77c5b184dSJason Gunthorpe #ifndef __GENERIC_PT_PT_FMT_DEFAULTS_H
87c5b184dSJason Gunthorpe #define __GENERIC_PT_PT_FMT_DEFAULTS_H
97c5b184dSJason Gunthorpe
107c5b184dSJason Gunthorpe #include "pt_defs.h"
117c5b184dSJason Gunthorpe #include <linux/log2.h>
127c5b184dSJason Gunthorpe
137c5b184dSJason Gunthorpe /* Header self-compile default defines */
147c5b184dSJason Gunthorpe #ifndef pt_load_entry_raw
157c5b184dSJason Gunthorpe #include "fmt/amdv1.h"
167c5b184dSJason Gunthorpe #endif
177c5b184dSJason Gunthorpe
187c5b184dSJason Gunthorpe /*
197c5b184dSJason Gunthorpe * The format must provide PT_GRANULE_LG2SZ, PT_TABLEMEM_LG2SZ, and
207c5b184dSJason Gunthorpe * PT_ITEM_WORD_SIZE. They must be the same at every level excluding the top.
217c5b184dSJason Gunthorpe */
227c5b184dSJason Gunthorpe #ifndef pt_table_item_lg2sz
pt_table_item_lg2sz(const struct pt_state * pts)237c5b184dSJason Gunthorpe static inline unsigned int pt_table_item_lg2sz(const struct pt_state *pts)
247c5b184dSJason Gunthorpe {
257c5b184dSJason Gunthorpe return PT_GRANULE_LG2SZ +
267c5b184dSJason Gunthorpe (PT_TABLEMEM_LG2SZ - ilog2(PT_ITEM_WORD_SIZE)) * pts->level;
277c5b184dSJason Gunthorpe }
287c5b184dSJason Gunthorpe #endif
297c5b184dSJason Gunthorpe
307c5b184dSJason Gunthorpe #ifndef pt_pgsz_lg2_to_level
pt_pgsz_lg2_to_level(struct pt_common * common,unsigned int pgsize_lg2)317c5b184dSJason Gunthorpe static inline unsigned int pt_pgsz_lg2_to_level(struct pt_common *common,
327c5b184dSJason Gunthorpe unsigned int pgsize_lg2)
337c5b184dSJason Gunthorpe {
347c5b184dSJason Gunthorpe return ((unsigned int)(pgsize_lg2 - PT_GRANULE_LG2SZ)) /
357c5b184dSJason Gunthorpe (PT_TABLEMEM_LG2SZ - ilog2(PT_ITEM_WORD_SIZE));
367c5b184dSJason Gunthorpe }
377c5b184dSJason Gunthorpe #endif
387c5b184dSJason Gunthorpe
397c5b184dSJason Gunthorpe /*
407c5b184dSJason Gunthorpe * If not supplied by the format then contiguous pages are not supported.
417c5b184dSJason Gunthorpe *
427c5b184dSJason Gunthorpe * If contiguous pages are supported then the format must also provide
437c5b184dSJason Gunthorpe * pt_contig_count_lg2() if it supports a single contiguous size per level,
447c5b184dSJason Gunthorpe * or pt_possible_sizes() if it supports multiple sizes per level.
457c5b184dSJason Gunthorpe */
467c5b184dSJason Gunthorpe #ifndef pt_entry_num_contig_lg2
pt_entry_num_contig_lg2(const struct pt_state * pts)477c5b184dSJason Gunthorpe static inline unsigned int pt_entry_num_contig_lg2(const struct pt_state *pts)
487c5b184dSJason Gunthorpe {
497c5b184dSJason Gunthorpe return ilog2(1);
507c5b184dSJason Gunthorpe }
517c5b184dSJason Gunthorpe
527c5b184dSJason Gunthorpe /*
537c5b184dSJason Gunthorpe * Return the number of contiguous OA items forming an entry at this table level
547c5b184dSJason Gunthorpe */
pt_contig_count_lg2(const struct pt_state * pts)557c5b184dSJason Gunthorpe static inline unsigned short pt_contig_count_lg2(const struct pt_state *pts)
567c5b184dSJason Gunthorpe {
577c5b184dSJason Gunthorpe return ilog2(1);
587c5b184dSJason Gunthorpe }
597c5b184dSJason Gunthorpe #endif
607c5b184dSJason Gunthorpe
617c5b184dSJason Gunthorpe /* If not supplied by the format then dirty tracking is not supported */
627c5b184dSJason Gunthorpe #ifndef pt_entry_is_write_dirty
pt_entry_is_write_dirty(const struct pt_state * pts)637c5b184dSJason Gunthorpe static inline bool pt_entry_is_write_dirty(const struct pt_state *pts)
647c5b184dSJason Gunthorpe {
657c5b184dSJason Gunthorpe return false;
667c5b184dSJason Gunthorpe }
677c5b184dSJason Gunthorpe
pt_entry_make_write_clean(struct pt_state * pts)687c5b184dSJason Gunthorpe static inline void pt_entry_make_write_clean(struct pt_state *pts)
697c5b184dSJason Gunthorpe {
707c5b184dSJason Gunthorpe }
717c5b184dSJason Gunthorpe
pt_dirty_supported(struct pt_common * common)727c5b184dSJason Gunthorpe static inline bool pt_dirty_supported(struct pt_common *common)
737c5b184dSJason Gunthorpe {
747c5b184dSJason Gunthorpe return false;
757c5b184dSJason Gunthorpe }
767c5b184dSJason Gunthorpe #else
777c5b184dSJason Gunthorpe /* If not supplied then dirty tracking is always enabled */
787c5b184dSJason Gunthorpe #ifndef pt_dirty_supported
pt_dirty_supported(struct pt_common * common)797c5b184dSJason Gunthorpe static inline bool pt_dirty_supported(struct pt_common *common)
807c5b184dSJason Gunthorpe {
817c5b184dSJason Gunthorpe return true;
827c5b184dSJason Gunthorpe }
837c5b184dSJason Gunthorpe #endif
847c5b184dSJason Gunthorpe #endif
857c5b184dSJason Gunthorpe
867c5b184dSJason Gunthorpe #ifndef pt_entry_make_write_dirty
pt_entry_make_write_dirty(struct pt_state * pts)877c5b184dSJason Gunthorpe static inline bool pt_entry_make_write_dirty(struct pt_state *pts)
887c5b184dSJason Gunthorpe {
897c5b184dSJason Gunthorpe return false;
907c5b184dSJason Gunthorpe }
917c5b184dSJason Gunthorpe #endif
927c5b184dSJason Gunthorpe
937c5b184dSJason Gunthorpe /*
947c5b184dSJason Gunthorpe * Format supplies either:
957c5b184dSJason Gunthorpe * pt_entry_oa - OA is at the start of a contiguous entry
967c5b184dSJason Gunthorpe * or
977c5b184dSJason Gunthorpe * pt_item_oa - OA is adjusted for every item in a contiguous entry
987c5b184dSJason Gunthorpe *
997c5b184dSJason Gunthorpe * Build the missing one
1007c5b184dSJason Gunthorpe *
1017c5b184dSJason Gunthorpe * The internal helper _pt_entry_oa_fast() allows generating
1027c5b184dSJason Gunthorpe * an efficient pt_entry_oa_exact(), it doesn't care which
1037c5b184dSJason Gunthorpe * option is selected.
1047c5b184dSJason Gunthorpe */
1057c5b184dSJason Gunthorpe #ifdef pt_entry_oa
pt_item_oa(const struct pt_state * pts)1067c5b184dSJason Gunthorpe static inline pt_oaddr_t pt_item_oa(const struct pt_state *pts)
1077c5b184dSJason Gunthorpe {
1087c5b184dSJason Gunthorpe return pt_entry_oa(pts) |
1097c5b184dSJason Gunthorpe log2_mul(pts->index, pt_table_item_lg2sz(pts));
1107c5b184dSJason Gunthorpe }
1117c5b184dSJason Gunthorpe #define _pt_entry_oa_fast pt_entry_oa
1127c5b184dSJason Gunthorpe #endif
1137c5b184dSJason Gunthorpe
1147c5b184dSJason Gunthorpe #ifdef pt_item_oa
pt_entry_oa(const struct pt_state * pts)1157c5b184dSJason Gunthorpe static inline pt_oaddr_t pt_entry_oa(const struct pt_state *pts)
1167c5b184dSJason Gunthorpe {
1177c5b184dSJason Gunthorpe return log2_set_mod(pt_item_oa(pts), 0,
1187c5b184dSJason Gunthorpe pt_entry_num_contig_lg2(pts) +
1197c5b184dSJason Gunthorpe pt_table_item_lg2sz(pts));
1207c5b184dSJason Gunthorpe }
1217c5b184dSJason Gunthorpe #define _pt_entry_oa_fast pt_item_oa
1227c5b184dSJason Gunthorpe #endif
1237c5b184dSJason Gunthorpe
1247c5b184dSJason Gunthorpe /*
1257c5b184dSJason Gunthorpe * If not supplied by the format then use the constant
1267c5b184dSJason Gunthorpe * PT_MAX_OUTPUT_ADDRESS_LG2.
1277c5b184dSJason Gunthorpe */
1287c5b184dSJason Gunthorpe #ifndef pt_max_oa_lg2
1297c5b184dSJason Gunthorpe static inline unsigned int
pt_max_oa_lg2(const struct pt_common * common)1307c5b184dSJason Gunthorpe pt_max_oa_lg2(const struct pt_common *common)
1317c5b184dSJason Gunthorpe {
1327c5b184dSJason Gunthorpe return PT_MAX_OUTPUT_ADDRESS_LG2;
1337c5b184dSJason Gunthorpe }
1347c5b184dSJason Gunthorpe #endif
1357c5b184dSJason Gunthorpe
1367c5b184dSJason Gunthorpe #ifndef pt_has_system_page_size
pt_has_system_page_size(const struct pt_common * common)1377c5b184dSJason Gunthorpe static inline bool pt_has_system_page_size(const struct pt_common *common)
1387c5b184dSJason Gunthorpe {
1397c5b184dSJason Gunthorpe return PT_GRANULE_LG2SZ == PAGE_SHIFT;
1407c5b184dSJason Gunthorpe }
1417c5b184dSJason Gunthorpe #endif
1427c5b184dSJason Gunthorpe
1437c5b184dSJason Gunthorpe /*
1447c5b184dSJason Gunthorpe * If not supplied by the format then assume only one contiguous size determined
1457c5b184dSJason Gunthorpe * by pt_contig_count_lg2()
1467c5b184dSJason Gunthorpe */
1477c5b184dSJason Gunthorpe #ifndef pt_possible_sizes
1487c5b184dSJason Gunthorpe static inline unsigned short pt_contig_count_lg2(const struct pt_state *pts);
1497c5b184dSJason Gunthorpe
1507c5b184dSJason Gunthorpe /* Return a bitmap of possible leaf page sizes at this level */
pt_possible_sizes(const struct pt_state * pts)1517c5b184dSJason Gunthorpe static inline pt_vaddr_t pt_possible_sizes(const struct pt_state *pts)
1527c5b184dSJason Gunthorpe {
1537c5b184dSJason Gunthorpe unsigned int isz_lg2 = pt_table_item_lg2sz(pts);
1547c5b184dSJason Gunthorpe
1557c5b184dSJason Gunthorpe if (!pt_can_have_leaf(pts))
1567c5b184dSJason Gunthorpe return 0;
1577c5b184dSJason Gunthorpe return log2_to_int(isz_lg2) |
1587c5b184dSJason Gunthorpe log2_to_int(pt_contig_count_lg2(pts) + isz_lg2);
1597c5b184dSJason Gunthorpe }
1607c5b184dSJason Gunthorpe #endif
1617c5b184dSJason Gunthorpe
1627c5b184dSJason Gunthorpe /* If not supplied by the format then use 0. */
1637c5b184dSJason Gunthorpe #ifndef pt_full_va_prefix
pt_full_va_prefix(const struct pt_common * common)1647c5b184dSJason Gunthorpe static inline pt_vaddr_t pt_full_va_prefix(const struct pt_common *common)
1657c5b184dSJason Gunthorpe {
1667c5b184dSJason Gunthorpe return 0;
1677c5b184dSJason Gunthorpe }
1687c5b184dSJason Gunthorpe #endif
1697c5b184dSJason Gunthorpe
1707c5b184dSJason Gunthorpe /* If not supplied by the format then zero fill using PT_ITEM_WORD_SIZE */
1717c5b184dSJason Gunthorpe #ifndef pt_clear_entries
pt_clear_entries64(struct pt_state * pts,unsigned int num_contig_lg2)1727c5b184dSJason Gunthorpe static inline void pt_clear_entries64(struct pt_state *pts,
1737c5b184dSJason Gunthorpe unsigned int num_contig_lg2)
1747c5b184dSJason Gunthorpe {
1757c5b184dSJason Gunthorpe u64 *tablep = pt_cur_table(pts, u64) + pts->index;
1767c5b184dSJason Gunthorpe u64 *end = tablep + log2_to_int(num_contig_lg2);
1777c5b184dSJason Gunthorpe
1787c5b184dSJason Gunthorpe PT_WARN_ON(log2_mod(pts->index, num_contig_lg2));
1797c5b184dSJason Gunthorpe for (; tablep != end; tablep++)
1807c5b184dSJason Gunthorpe WRITE_ONCE(*tablep, 0);
1817c5b184dSJason Gunthorpe }
1827c5b184dSJason Gunthorpe
pt_clear_entries32(struct pt_state * pts,unsigned int num_contig_lg2)1837c5b184dSJason Gunthorpe static inline void pt_clear_entries32(struct pt_state *pts,
1847c5b184dSJason Gunthorpe unsigned int num_contig_lg2)
1857c5b184dSJason Gunthorpe {
1867c5b184dSJason Gunthorpe u32 *tablep = pt_cur_table(pts, u32) + pts->index;
1877c5b184dSJason Gunthorpe u32 *end = tablep + log2_to_int(num_contig_lg2);
1887c5b184dSJason Gunthorpe
1897c5b184dSJason Gunthorpe PT_WARN_ON(log2_mod(pts->index, num_contig_lg2));
1907c5b184dSJason Gunthorpe for (; tablep != end; tablep++)
1917c5b184dSJason Gunthorpe WRITE_ONCE(*tablep, 0);
1927c5b184dSJason Gunthorpe }
1937c5b184dSJason Gunthorpe
pt_clear_entries(struct pt_state * pts,unsigned int num_contig_lg2)1947c5b184dSJason Gunthorpe static inline void pt_clear_entries(struct pt_state *pts,
1957c5b184dSJason Gunthorpe unsigned int num_contig_lg2)
1967c5b184dSJason Gunthorpe {
1977c5b184dSJason Gunthorpe if (PT_ITEM_WORD_SIZE == sizeof(u32))
1987c5b184dSJason Gunthorpe pt_clear_entries32(pts, num_contig_lg2);
1997c5b184dSJason Gunthorpe else
2007c5b184dSJason Gunthorpe pt_clear_entries64(pts, num_contig_lg2);
2017c5b184dSJason Gunthorpe }
2027c5b184dSJason Gunthorpe #define pt_clear_entries pt_clear_entries
2037c5b184dSJason Gunthorpe #endif
2047c5b184dSJason Gunthorpe
205*bcc64b57SJason Gunthorpe /* If not supplied then SW bits are not supported */
206*bcc64b57SJason Gunthorpe #ifdef pt_sw_bit
pt_test_sw_bit_acquire(struct pt_state * pts,unsigned int bitnr)207*bcc64b57SJason Gunthorpe static inline bool pt_test_sw_bit_acquire(struct pt_state *pts,
208*bcc64b57SJason Gunthorpe unsigned int bitnr)
209*bcc64b57SJason Gunthorpe {
210*bcc64b57SJason Gunthorpe /* Acquire, pairs with pt_set_sw_bit_release() */
211*bcc64b57SJason Gunthorpe smp_mb();
212*bcc64b57SJason Gunthorpe /* For a contiguous entry the sw bit is only stored in the first item. */
213*bcc64b57SJason Gunthorpe return pts->entry & pt_sw_bit(bitnr);
214*bcc64b57SJason Gunthorpe }
215*bcc64b57SJason Gunthorpe #define pt_test_sw_bit_acquire pt_test_sw_bit_acquire
216*bcc64b57SJason Gunthorpe
pt_set_sw_bit_release(struct pt_state * pts,unsigned int bitnr)217*bcc64b57SJason Gunthorpe static inline void pt_set_sw_bit_release(struct pt_state *pts,
218*bcc64b57SJason Gunthorpe unsigned int bitnr)
219*bcc64b57SJason Gunthorpe {
220*bcc64b57SJason Gunthorpe #if !IS_ENABLED(CONFIG_GENERIC_ATOMIC64)
221*bcc64b57SJason Gunthorpe if (PT_ITEM_WORD_SIZE == sizeof(u64)) {
222*bcc64b57SJason Gunthorpe u64 *entryp = pt_cur_table(pts, u64) + pts->index;
223*bcc64b57SJason Gunthorpe u64 old_entry = pts->entry;
224*bcc64b57SJason Gunthorpe u64 new_entry;
225*bcc64b57SJason Gunthorpe
226*bcc64b57SJason Gunthorpe do {
227*bcc64b57SJason Gunthorpe new_entry = old_entry | pt_sw_bit(bitnr);
228*bcc64b57SJason Gunthorpe } while (!try_cmpxchg64_release(entryp, &old_entry, new_entry));
229*bcc64b57SJason Gunthorpe pts->entry = new_entry;
230*bcc64b57SJason Gunthorpe return;
231*bcc64b57SJason Gunthorpe }
232*bcc64b57SJason Gunthorpe #endif
233*bcc64b57SJason Gunthorpe if (PT_ITEM_WORD_SIZE == sizeof(u32)) {
234*bcc64b57SJason Gunthorpe u32 *entryp = pt_cur_table(pts, u32) + pts->index;
235*bcc64b57SJason Gunthorpe u32 old_entry = pts->entry;
236*bcc64b57SJason Gunthorpe u32 new_entry;
237*bcc64b57SJason Gunthorpe
238*bcc64b57SJason Gunthorpe do {
239*bcc64b57SJason Gunthorpe new_entry = old_entry | pt_sw_bit(bitnr);
240*bcc64b57SJason Gunthorpe } while (!try_cmpxchg_release(entryp, &old_entry, new_entry));
241*bcc64b57SJason Gunthorpe pts->entry = new_entry;
242*bcc64b57SJason Gunthorpe } else
243*bcc64b57SJason Gunthorpe BUILD_BUG();
244*bcc64b57SJason Gunthorpe }
245*bcc64b57SJason Gunthorpe #define pt_set_sw_bit_release pt_set_sw_bit_release
246*bcc64b57SJason Gunthorpe #else
pt_max_sw_bit(struct pt_common * common)247*bcc64b57SJason Gunthorpe static inline unsigned int pt_max_sw_bit(struct pt_common *common)
248*bcc64b57SJason Gunthorpe {
249*bcc64b57SJason Gunthorpe return 0;
250*bcc64b57SJason Gunthorpe }
251*bcc64b57SJason Gunthorpe
252*bcc64b57SJason Gunthorpe extern void __pt_no_sw_bit(void);
pt_test_sw_bit_acquire(struct pt_state * pts,unsigned int bitnr)253*bcc64b57SJason Gunthorpe static inline bool pt_test_sw_bit_acquire(struct pt_state *pts,
254*bcc64b57SJason Gunthorpe unsigned int bitnr)
255*bcc64b57SJason Gunthorpe {
256*bcc64b57SJason Gunthorpe __pt_no_sw_bit();
257*bcc64b57SJason Gunthorpe return false;
258*bcc64b57SJason Gunthorpe }
259*bcc64b57SJason Gunthorpe
pt_set_sw_bit_release(struct pt_state * pts,unsigned int bitnr)260*bcc64b57SJason Gunthorpe static inline void pt_set_sw_bit_release(struct pt_state *pts,
261*bcc64b57SJason Gunthorpe unsigned int bitnr)
262*bcc64b57SJason Gunthorpe {
263*bcc64b57SJason Gunthorpe __pt_no_sw_bit();
264*bcc64b57SJason Gunthorpe }
265*bcc64b57SJason Gunthorpe #endif
266*bcc64b57SJason Gunthorpe
2677c5b184dSJason Gunthorpe /*
2687c5b184dSJason Gunthorpe * Format can call in the pt_install_leaf_entry() to check the arguments are all
2697c5b184dSJason Gunthorpe * aligned correctly.
2707c5b184dSJason Gunthorpe */
pt_check_install_leaf_args(struct pt_state * pts,pt_oaddr_t oa,unsigned int oasz_lg2)2717c5b184dSJason Gunthorpe static inline bool pt_check_install_leaf_args(struct pt_state *pts,
2727c5b184dSJason Gunthorpe pt_oaddr_t oa,
2737c5b184dSJason Gunthorpe unsigned int oasz_lg2)
2747c5b184dSJason Gunthorpe {
2757c5b184dSJason Gunthorpe unsigned int isz_lg2 = pt_table_item_lg2sz(pts);
2767c5b184dSJason Gunthorpe
2777c5b184dSJason Gunthorpe if (PT_WARN_ON(oalog2_mod(oa, oasz_lg2)))
2787c5b184dSJason Gunthorpe return false;
2797c5b184dSJason Gunthorpe
2807c5b184dSJason Gunthorpe #ifdef pt_possible_sizes
2817c5b184dSJason Gunthorpe if (PT_WARN_ON(isz_lg2 > oasz_lg2 ||
2827c5b184dSJason Gunthorpe oasz_lg2 > isz_lg2 + pt_num_items_lg2(pts)))
2837c5b184dSJason Gunthorpe return false;
2847c5b184dSJason Gunthorpe #else
2857c5b184dSJason Gunthorpe if (PT_WARN_ON(oasz_lg2 != isz_lg2 &&
2867c5b184dSJason Gunthorpe oasz_lg2 != isz_lg2 + pt_contig_count_lg2(pts)))
2877c5b184dSJason Gunthorpe return false;
2887c5b184dSJason Gunthorpe #endif
2897c5b184dSJason Gunthorpe
2907c5b184dSJason Gunthorpe if (PT_WARN_ON(oalog2_mod(pts->index, oasz_lg2 - isz_lg2)))
2917c5b184dSJason Gunthorpe return false;
2927c5b184dSJason Gunthorpe return true;
2937c5b184dSJason Gunthorpe }
2947c5b184dSJason Gunthorpe
2957c5b184dSJason Gunthorpe #endif
296