Commit 56881d07 authored by Stanislav Fomichev's avatar Stanislav Fomichev Committed by Jakub Kicinski
Browse files

ynl: support directional specs in ynl-gen-c.py



The intent is to generate ethtool uapi headers. For now, some of the
things are hard-coded:
- <FAMILY>_MSG_{USER,KERNEL}_MAX
- the split between USER and KERNEL messages

Signed-off-by: default avatarStanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20241204155549.641348-4-sdf@fomichev.me


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 8c843ecd
Loading
Loading
Loading
Loading
+87 −31
Original line number Diff line number Diff line
@@ -2419,6 +2419,87 @@ def uapi_enum_start(family, cw, obj, ckey='', enum_name='enum-name'):
    cw.block_start(line=start_line)


def render_uapi_unified(family, cw, max_by_define, separate_ntf):
    max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX"))
    cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX"))
    max_value = f"({cnt_name} - 1)"

    uapi_enum_start(family, cw, family['operations'], 'enum-name')
    val = 0
    for op in family.msgs.values():
        if separate_ntf and ('notify' in op or 'event' in op):
            continue

        suffix = ','
        if op.value != val:
            suffix = f" = {op.value},"
            val = op.value
        cw.p(op.enum_name + suffix)
        val += 1
    cw.nl()
    cw.p(cnt_name + ('' if max_by_define else ','))
    if not max_by_define:
        cw.p(f"{max_name} = {max_value}")
    cw.block_end(line=';')
    if max_by_define:
        cw.p(f"#define {max_name} {max_value}")
    cw.nl()


def render_uapi_directional(family, cw, max_by_define):
    max_name = f"{family.op_prefix}USER_MAX"
    cnt_name = f"__{family.op_prefix}USER_CNT"
    max_value = f"({cnt_name} - 1)"

    cw.block_start(line='enum')
    cw.p(c_upper(f'{family.name}_MSG_USER_NONE = 0,'))
    val = 0
    for op in family.msgs.values():
        if 'do' in op and 'event' not in op:
            suffix = ','
            if op.value and op.value != val:
                suffix = f" = {op.value},"
                val = op.value
            cw.p(op.enum_name + suffix)
            val += 1
    cw.nl()
    cw.p(cnt_name + ('' if max_by_define else ','))
    if not max_by_define:
        cw.p(f"{max_name} = {max_value}")
    cw.block_end(line=';')
    if max_by_define:
        cw.p(f"#define {max_name} {max_value}")
    cw.nl()

    max_name = f"{family.op_prefix}KERNEL_MAX"
    cnt_name = f"__{family.op_prefix}KERNEL_CNT"
    max_value = f"({cnt_name} - 1)"

    cw.block_start(line='enum')
    cw.p(c_upper(f'{family.name}_MSG_KERNEL_NONE = 0,'))
    val = 0
    for op in family.msgs.values():
        if ('do' in op and 'reply' in op['do']) or 'notify' in op or 'event' in op:
            enum_name = op.enum_name
            if 'event' not in op and 'notify' not in op:
                enum_name = f'{enum_name}_REPLY'

            suffix = ','
            if op.value and op.value != val:
                suffix = f" = {op.value},"
                val = op.value
            cw.p(enum_name + suffix)
            val += 1
    cw.nl()
    cw.p(cnt_name + ('' if max_by_define else ','))
    if not max_by_define:
        cw.p(f"{max_name} = {max_value}")
    cw.block_end(line=';')
    if max_by_define:
        cw.p(f"#define {max_name} {max_value}")
    cw.nl()


def render_uapi(family, cw):
    hdr_prot = f"_UAPI_LINUX_{c_upper(family.uapi_header_name)}_H"
    hdr_prot = hdr_prot.replace('/', '_')
@@ -2523,30 +2604,12 @@ def render_uapi(family, cw):
    # Commands
    separate_ntf = 'async-prefix' in family['operations']

    max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX"))
    cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX"))
    max_value = f"({cnt_name} - 1)"

    uapi_enum_start(family, cw, family['operations'], 'enum-name')
    val = 0
    for op in family.msgs.values():
        if separate_ntf and ('notify' in op or 'event' in op):
            continue

        suffix = ','
        if op.value != val:
            suffix = f" = {op.value},"
            val = op.value
        cw.p(op.enum_name + suffix)
        val += 1
    cw.nl()
    cw.p(cnt_name + ('' if max_by_define else ','))
    if not max_by_define:
        cw.p(f"{max_name} = {max_value}")
    cw.block_end(line=';')
    if max_by_define:
        cw.p(f"#define {max_name} {max_value}")
    cw.nl()
    if family.msg_id_model == 'unified':
        render_uapi_unified(family, cw, max_by_define, separate_ntf)
    elif family.msg_id_model == 'directional':
        render_uapi_directional(family, cw, max_by_define)
    else:
        raise Exception(f'Unsupported message enum-model {family.msg_id_model}')

    if separate_ntf:
        uapi_enum_start(family, cw, family['operations'], enum_name='async-enum')
@@ -2670,13 +2733,6 @@ def main():
        os.sys.exit(1)
        return

    supported_models = ['unified']
    if args.mode in ['user', 'kernel']:
        supported_models += ['directional']
    if parsed.msg_id_model not in supported_models:
        print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation')
        os.sys.exit(1)

    cw = CodeWriter(BaseNlLib(), args.out_file, overwrite=(not args.cmp_out))

    _, spec_kernel = find_kernel_root(args.spec)