Hi Jason, On Mon, Jun 16, 2025 at 03:06:04PM -0300, Jason Gunthorpe wrote: > The generic API is intended to be separated from the implementation of > page table algorithms. It contains only accessors for walking and > manipulating the table and helpers that are useful for building an > implementation. Memory management is not in the generic API, but part of > the implementation. > > Using a multi-compilation approach the implementation module would include > headers in this order: > > common.h > defs_FMT.h > pt_defs.h > FMT.h > pt_common.h > IMPLEMENTATION.h > > Where each compilation unit would have a combination of FMT and > IMPLEMENTATION to produce a per-format per-implementation module. > > The API is designed so that the format headers have minimal logic, and > default implementations are provided if the format doesn't include one. > > Generally formats provide their code via an inline function using the > pattern: > > static inline FMTpt_XX(..) {} > #define pt_XX FMTpt_XX > > The common code then enforces a function signature so that there is no > drift in function arguments, or accidental polymorphic functions (as has > been slightly troublesome in mm). Use of function-like #defines are > avoided in the format even though many of the functions are small enough. > > Provide kdocs for the API surface. > > This is enough to implement the 8 initial format variations with all of > their features: > * Entries comprised of contiguous blocks of IO PTEs for larger page > sizes (AMDv1, ARMv8) > * Multi-level tables, up to 6 levels. Runtime selected top level > * Runtime variable table level size (ARM's concatenated tables) > * Expandable top level (AMDv1) > * Optional leaf entries at any level > * 32 bit/64 bit virtual and output addresses, using every bit > * Sign extended addressing (x86) > * Dirty tracking > > A basic simple format takes about 200 lines to declare the require inline > functions. > > Tested-by: Alejandro Jimenez <alejandro.j.jimenez@xxxxxxxxxx> > Signed-off-by: Jason Gunthorpe <jgg@xxxxxxxxxx> > --- ../.. > +static __always_inline struct pt_range _pt_top_range(struct pt_common *common, > + uintptr_t top_of_table) > +{ > + struct pt_range range = { > + .common = common, > + .top_table = > + (struct pt_table_p *)(top_of_table & > + ~(uintptr_t)PT_TOP_LEVEL_MASK), > +#ifdef PT_FIXED_TOP_LEVEL I am not able to find definition for above macro. Was it intentional to leave the macro 'PT_FIXED_TOP_LEVEL' undefined? Thanks, Ankit > + .top_level = PT_FIXED_TOP_LEVEL, > +#else > + .top_level = top_of_table % (1 << PT_TOP_LEVEL_BITS), > +#endif > + }; > + struct pt_state pts = { .range = &range, .level = range.top_level }; > + unsigned int max_vasz_lg2; > + > + max_vasz_lg2 = common->max_vasz_lg2; > + if (pt_feature(common, PT_FEAT_DYNAMIC_TOP) && > + pts.level != PT_MAX_TOP_LEVEL) > + max_vasz_lg2 = min_t(unsigned int, common->max_vasz_lg2, > + pt_num_items_lg2(&pts) + > + pt_table_item_lg2sz(&pts)); > + > + /* > + * The top range will default to the lower region only with sign extend. > + */ > + range.max_vasz_lg2 = max_vasz_lg2; > + if (pt_feature(common, PT_FEAT_SIGN_EXTEND)) > + max_vasz_lg2--; > + > + range.va = fvalog2_set_mod(pt_full_va_prefix(common), 0, max_vasz_lg2); > + range.last_va = > + fvalog2_set_mod_max(pt_full_va_prefix(common), max_vasz_lg2); > + return range; > +} > -- > 2.43.0 >