1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * drivers/net/ethernet/rocker/rocker_tlv.h - Rocker switch device driver 4 * Copyright (c) 2014-2016 Jiri Pirko <jiri@mellanox.com> 5 * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com> 6 */ 7 8 #ifndef _ROCKER_TLV_H 9 #define _ROCKER_TLV_H 10 11 #include <linux/types.h> 12 13 #include "rocker_hw.h" 14 #include "rocker.h" 15 16 #define ROCKER_TLV_ALIGNTO 8U 17 #define ROCKER_TLV_ALIGN(len) \ 18 (((len) + ROCKER_TLV_ALIGNTO - 1) & ~(ROCKER_TLV_ALIGNTO - 1)) 19 #define ROCKER_TLV_HDRLEN ROCKER_TLV_ALIGN(sizeof(struct rocker_tlv)) 20 21 /* <------- ROCKER_TLV_HDRLEN -------> <--- ROCKER_TLV_ALIGN(payload) ---> 22 * +-----------------------------+- - -+- - - - - - - - - - - - - - -+- - -+ 23 * | Header | Pad | Payload | Pad | 24 * | (struct rocker_tlv) | ing | | ing | 25 * +-----------------------------+- - -+- - - - - - - - - - - - - - -+- - -+ 26 * <--------------------------- tlv->len --------------------------> 27 */ 28 29 static inline struct rocker_tlv *rocker_tlv_next(const struct rocker_tlv *tlv, 30 int *remaining) 31 { 32 int totlen = ROCKER_TLV_ALIGN(tlv->len); 33 34 *remaining -= totlen; 35 return (struct rocker_tlv *) ((char *) tlv + totlen); 36 } 37 38 static inline int rocker_tlv_ok(const struct rocker_tlv *tlv, int remaining) 39 { 40 return remaining >= (int) ROCKER_TLV_HDRLEN && 41 tlv->len >= ROCKER_TLV_HDRLEN && 42 tlv->len <= remaining; 43 } 44 45 #define rocker_tlv_for_each(pos, head, len, rem) \ 46 for (pos = head, rem = len; \ 47 rocker_tlv_ok(pos, rem); \ 48 pos = rocker_tlv_next(pos, &(rem))) 49 50 #define rocker_tlv_for_each_nested(pos, tlv, rem) \ 51 rocker_tlv_for_each(pos, rocker_tlv_data(tlv), \ 52 rocker_tlv_len(tlv), rem) 53 54 static inline int rocker_tlv_attr_size(int payload) 55 { 56 return ROCKER_TLV_HDRLEN + payload; 57 } 58 59 static inline int rocker_tlv_total_size(int payload) 60 { 61 return ROCKER_TLV_ALIGN(rocker_tlv_attr_size(payload)); 62 } 63 64 static inline int rocker_tlv_padlen(int payload) 65 { 66 return rocker_tlv_total_size(payload) - rocker_tlv_attr_size(payload); 67 } 68 69 static inline int rocker_tlv_type(const struct rocker_tlv *tlv) 70 { 71 return tlv->type; 72 } 73 74 static inline void *rocker_tlv_data(const struct rocker_tlv *tlv) 75 { 76 return (char *) tlv + ROCKER_TLV_HDRLEN; 77 } 78 79 static inline int rocker_tlv_len(const struct rocker_tlv *tlv) 80 { 81 return tlv->len - ROCKER_TLV_HDRLEN; 82 } 83 84 static inline u8 rocker_tlv_get_u8(const struct rocker_tlv *tlv) 85 { 86 return *(u8 *) rocker_tlv_data(tlv); 87 } 88 89 static inline u16 rocker_tlv_get_u16(const struct rocker_tlv *tlv) 90 { 91 return *(u16 *) rocker_tlv_data(tlv); 92 } 93 94 static inline __be16 rocker_tlv_get_be16(const struct rocker_tlv *tlv) 95 { 96 return *(__be16 *) rocker_tlv_data(tlv); 97 } 98 99 static inline u32 rocker_tlv_get_u32(const struct rocker_tlv *tlv) 100 { 101 return *(u32 *) rocker_tlv_data(tlv); 102 } 103 104 static inline u64 rocker_tlv_get_u64(const struct rocker_tlv *tlv) 105 { 106 return *(u64 *) rocker_tlv_data(tlv); 107 } 108 109 void rocker_tlv_parse(const struct rocker_tlv **tb, int maxtype, 110 const char *buf, int buf_len); 111 112 static inline void rocker_tlv_parse_nested(const struct rocker_tlv **tb, 113 int maxtype, 114 const struct rocker_tlv *tlv) 115 { 116 rocker_tlv_parse(tb, maxtype, rocker_tlv_data(tlv), 117 rocker_tlv_len(tlv)); 118 } 119 120 static inline void 121 rocker_tlv_parse_desc(const struct rocker_tlv **tb, int maxtype, 122 const struct rocker_desc_info *desc_info) 123 { 124 rocker_tlv_parse(tb, maxtype, desc_info->data, 125 desc_info->desc->tlv_size); 126 } 127 128 static inline struct rocker_tlv * 129 rocker_tlv_start(struct rocker_desc_info *desc_info) 130 { 131 return (struct rocker_tlv *) ((char *) desc_info->data + 132 desc_info->tlv_size); 133 } 134 135 int rocker_tlv_put(struct rocker_desc_info *desc_info, 136 int attrtype, int attrlen, const void *data); 137 138 static inline int 139 rocker_tlv_put_u8(struct rocker_desc_info *desc_info, int attrtype, u8 value) 140 { 141 u8 tmp = value; /* work around GCC PR81715 */ 142 143 return rocker_tlv_put(desc_info, attrtype, sizeof(u8), &tmp); 144 } 145 146 static inline int 147 rocker_tlv_put_u16(struct rocker_desc_info *desc_info, int attrtype, u16 value) 148 { 149 u16 tmp = value; 150 151 return rocker_tlv_put(desc_info, attrtype, sizeof(u16), &tmp); 152 } 153 154 static inline int 155 rocker_tlv_put_be16(struct rocker_desc_info *desc_info, int attrtype, __be16 value) 156 { 157 __be16 tmp = value; 158 159 return rocker_tlv_put(desc_info, attrtype, sizeof(__be16), &tmp); 160 } 161 162 static inline int 163 rocker_tlv_put_u32(struct rocker_desc_info *desc_info, int attrtype, u32 value) 164 { 165 u32 tmp = value; 166 167 return rocker_tlv_put(desc_info, attrtype, sizeof(u32), &tmp); 168 } 169 170 static inline int 171 rocker_tlv_put_be32(struct rocker_desc_info *desc_info, int attrtype, __be32 value) 172 { 173 __be32 tmp = value; 174 175 return rocker_tlv_put(desc_info, attrtype, sizeof(__be32), &tmp); 176 } 177 178 static inline int 179 rocker_tlv_put_u64(struct rocker_desc_info *desc_info, int attrtype, u64 value) 180 { 181 u64 tmp = value; 182 183 return rocker_tlv_put(desc_info, attrtype, sizeof(u64), &tmp); 184 } 185 186 static inline struct rocker_tlv * 187 rocker_tlv_nest_start(struct rocker_desc_info *desc_info, int attrtype) 188 { 189 struct rocker_tlv *start = rocker_tlv_start(desc_info); 190 191 if (rocker_tlv_put(desc_info, attrtype, 0, NULL) < 0) 192 return NULL; 193 194 return start; 195 } 196 197 static inline void rocker_tlv_nest_end(struct rocker_desc_info *desc_info, 198 struct rocker_tlv *start) 199 { 200 start->len = (char *) rocker_tlv_start(desc_info) - (char *) start; 201 } 202 203 static inline void rocker_tlv_nest_cancel(struct rocker_desc_info *desc_info, 204 const struct rocker_tlv *start) 205 { 206 desc_info->tlv_size = (const char *) start - desc_info->data; 207 } 208 209 #endif 210