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 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 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 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 */ 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 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 687c5b184dSJason Gunthorpe static inline void pt_entry_make_write_clean(struct pt_state *pts) 697c5b184dSJason Gunthorpe { 707c5b184dSJason Gunthorpe } 717c5b184dSJason Gunthorpe 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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); 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 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 */ 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