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