176 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2/* Copyright (c) Meta Platforms, Inc. and affiliates. */3 4#ifndef _FBNIC_TLV_H_5#define _FBNIC_TLV_H_6 7#include <asm/byteorder.h>8#include <linux/bits.h>9#include <linux/const.h>10#include <linux/types.h>11 12#define FBNIC_TLV_MSG_ALIGN(len) ALIGN(len, sizeof(u32))13#define FBNIC_TLV_MSG_SIZE(len) \14 (FBNIC_TLV_MSG_ALIGN(len) / sizeof(u32))15 16/* TLV Header Format17 * 3 2 118 * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 019 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+20 * | Length |M|I|RSV| Type / ID |21 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+22 *23 * The TLV header format described above will be used for transferring24 * messages between the host and the firmware. To ensure byte ordering25 * we have defined all fields as being little endian.26 * Type/ID: Identifier for message and/or attribute27 * RSV: Reserved field for future use, likely as additional flags28 * I: cannot_ignore flag, identifies if unrecognized attribute can be ignored29 * M: is_msg, indicates that this is the start of a new message30 * Length: Total length of message in dwords including header31 * or32 * Total length of attribute in bytes including header33 */34struct fbnic_tlv_hdr {35#if defined(__LITTLE_ENDIAN_BITFIELD)36 u16 type : 12; /* 0 .. 11 Type / ID */37 u16 rsvd : 2; /* 12 .. 13 Reserved for future use */38 u16 cannot_ignore : 1; /* 14 Attribute can be ignored */39 u16 is_msg : 1; /* 15 Header belongs to message */40#elif defined(__BIG_ENDIAN_BITFIELD)41 u16 is_msg : 1; /* 15 Header belongs to message */42 u16 cannot_ignore : 1; /* 14 Attribute can be ignored */43 u16 rsvd : 2; /* 13 .. 12 Reserved for future use */44 u16 type : 12; /* 11 .. 0 Type / ID */45#else46#error "Missing defines from byteorder.h"47#endif48 __le16 len; /* 16 .. 32 length including TLV header */49};50 51#define FBNIC_TLV_RESULTS_MAX 3252 53struct fbnic_tlv_msg {54 struct fbnic_tlv_hdr hdr;55 __le32 value[];56};57 58#define FBNIC_TLV_MSG_ID_UNKNOWN USHRT_MAX59 60enum fbnic_tlv_type {61 FBNIC_TLV_STRING,62 FBNIC_TLV_FLAG,63 FBNIC_TLV_UNSIGNED,64 FBNIC_TLV_SIGNED,65 FBNIC_TLV_BINARY,66 FBNIC_TLV_NESTED,67 FBNIC_TLV_ARRAY,68 __FBNIC_TLV_MAX_TYPE69};70 71/* TLV Index72 * Defines the relationship between the attribute IDs and their types.73 * For each entry in the index there will be a size and type associated74 * with it so that we can use this to parse the data and verify it matches75 * the expected layout.76 */77struct fbnic_tlv_index {78 u16 id;79 u16 len;80 enum fbnic_tlv_type type;81};82 83#define TLV_MAX_DATA (PAGE_SIZE - 512)84#define FBNIC_TLV_ATTR_ID_UNKNOWN USHRT_MAX85#define FBNIC_TLV_ATTR_STRING(id, len) { id, len, FBNIC_TLV_STRING }86#define FBNIC_TLV_ATTR_FLAG(id) { id, 0, FBNIC_TLV_FLAG }87#define FBNIC_TLV_ATTR_U32(id) { id, sizeof(u32), FBNIC_TLV_UNSIGNED }88#define FBNIC_TLV_ATTR_U64(id) { id, sizeof(u64), FBNIC_TLV_UNSIGNED }89#define FBNIC_TLV_ATTR_S32(id) { id, sizeof(s32), FBNIC_TLV_SIGNED }90#define FBNIC_TLV_ATTR_S64(id) { id, sizeof(s64), FBNIC_TLV_SIGNED }91#define FBNIC_TLV_ATTR_MAC_ADDR(id) { id, ETH_ALEN, FBNIC_TLV_BINARY }92#define FBNIC_TLV_ATTR_NESTED(id) { id, 0, FBNIC_TLV_NESTED }93#define FBNIC_TLV_ATTR_ARRAY(id) { id, 0, FBNIC_TLV_ARRAY }94#define FBNIC_TLV_ATTR_RAW_DATA(id) { id, TLV_MAX_DATA, FBNIC_TLV_BINARY }95#define FBNIC_TLV_ATTR_LAST { FBNIC_TLV_ATTR_ID_UNKNOWN, 0, 0 }96 97struct fbnic_tlv_parser {98 u16 id;99 const struct fbnic_tlv_index *attr;100 int (*func)(void *opaque,101 struct fbnic_tlv_msg **results);102};103 104#define FBNIC_TLV_PARSER(id, attr, func) { FBNIC_TLV_MSG_ID_##id, attr, func }105 106static inline void *107fbnic_tlv_attr_get_value_ptr(struct fbnic_tlv_msg *attr)108{109 return (void *)&attr->value[0];110}111 112static inline bool fbnic_tlv_attr_get_bool(struct fbnic_tlv_msg *attr)113{114 return !!attr;115}116 117u64 fbnic_tlv_attr_get_unsigned(struct fbnic_tlv_msg *attr);118s64 fbnic_tlv_attr_get_signed(struct fbnic_tlv_msg *attr);119size_t fbnic_tlv_attr_get_string(struct fbnic_tlv_msg *attr, char *str,120 size_t max_size);121 122#define get_unsigned_result(id, location) \123do { \124 struct fbnic_tlv_msg *result = results[id]; \125 if (result) \126 location = fbnic_tlv_attr_get_unsigned(result); \127} while (0)128 129#define get_signed_result(id, location) \130do { \131 struct fbnic_tlv_msg *result = results[id]; \132 if (result) \133 location = fbnic_tlv_attr_get_signed(result); \134} while (0)135 136#define get_string_result(id, size, str, max_size) \137do { \138 struct fbnic_tlv_msg *result = results[id]; \139 if (result) \140 size = fbnic_tlv_attr_get_string(result, str, max_size); \141} while (0)142 143#define get_bool(id) (!!(results[id]))144 145struct fbnic_tlv_msg *fbnic_tlv_msg_alloc(u16 msg_id);146int fbnic_tlv_attr_put_flag(struct fbnic_tlv_msg *msg, const u16 attr_id);147int fbnic_tlv_attr_put_value(struct fbnic_tlv_msg *msg, const u16 attr_id,148 const void *value, const int len);149int __fbnic_tlv_attr_put_int(struct fbnic_tlv_msg *msg, const u16 attr_id,150 s64 value, const int len);151#define fbnic_tlv_attr_put_int(msg, attr_id, value) \152 __fbnic_tlv_attr_put_int(msg, attr_id, value, \153 FBNIC_TLV_MSG_ALIGN(sizeof(value)))154int fbnic_tlv_attr_put_mac_addr(struct fbnic_tlv_msg *msg, const u16 attr_id,155 const u8 *mac_addr);156int fbnic_tlv_attr_put_string(struct fbnic_tlv_msg *msg, u16 attr_id,157 const char *string);158struct fbnic_tlv_msg *fbnic_tlv_attr_nest_start(struct fbnic_tlv_msg *msg,159 u16 attr_id);160void fbnic_tlv_attr_nest_stop(struct fbnic_tlv_msg *msg);161void fbnic_tlv_attr_addr_copy(u8 *dest, struct fbnic_tlv_msg *src);162int fbnic_tlv_attr_parse_array(struct fbnic_tlv_msg *attr, int len,163 struct fbnic_tlv_msg **results,164 const struct fbnic_tlv_index *tlv_index,165 u16 tlv_attr_id, size_t array_len);166int fbnic_tlv_attr_parse(struct fbnic_tlv_msg *attr, int len,167 struct fbnic_tlv_msg **results,168 const struct fbnic_tlv_index *tlv_index);169int fbnic_tlv_msg_parse(void *opaque, struct fbnic_tlv_msg *msg,170 const struct fbnic_tlv_parser *parser);171int fbnic_tlv_parser_error(void *opaque, struct fbnic_tlv_msg **results);172 173#define FBNIC_TLV_MSG_ERROR \174 FBNIC_TLV_PARSER(UNKNOWN, NULL, fbnic_tlv_parser_error)175#endif /* _FBNIC_TLV_H_ */176