Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

staging: wfx: allow new PDS format

The device needs data about the antenna configuration. This information
in provided by PDS (Platform Data Set, this is the wording used in WF200
documentation) files.

Until now, the driver had to parse the PDS file before to send it. This
solution was not acceptable for the vanilla kernel. We have slightly
changed the PDS format so it is now an array of Type-Length-Value.

This patch allows to support new format and keep compatibility with
legacy format.

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
probe: allow new PDS format
Link: https://lore.kernel.org/r/20220211162659.528333-2-Jerome.Pouiller@silabs.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Jérôme Pouiller and committed by
Greg Kroah-Hartman
dcbecb49 1e7f32f7

+57 -17
+57 -17
drivers/staging/wfx/main.c
··· 33 33 #include "hif_tx_mib.h" 34 34 #include "hif_api_cmd.h" 35 35 36 - #define WFX_PDS_MAX_SIZE 1500 36 + #define WFX_PDS_TLV_TYPE 0x4450 // "PD" (Platform Data) in ascii little-endian 37 + #define WFX_PDS_MAX_CHUNK_SIZE 1500 37 38 38 39 MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WF200"); 39 40 MODULE_AUTHOR("Jérôme Pouiller <jerome.pouiller@silabs.com>"); ··· 163 162 return false; 164 163 } 165 164 166 - /* The device needs data about the antenna configuration. This information in provided by PDS 167 - * (Platform Data Set, this is the wording used in WF200 documentation) files. For hardware 168 - * integrators, the full process to create PDS files is described here: 169 - * https:github.com/SiliconLabs/wfx-firmware/blob/master/PDS/README.md 170 - * 171 - * So this function aims to send PDS to the device. However, the PDS file is often bigger than Rx 172 - * buffers of the chip, so it has to be sent in multiple parts. 165 + /* In legacy format, the PDS file is often bigger than Rx buffers of the chip, so it has to be sent 166 + * in multiple parts. 173 167 * 174 168 * In add, the PDS data cannot be split anywhere. The PDS files contains tree structures. Braces are 175 169 * used to enter/leave a level of the tree (in a JSON fashion). PDS files can only been split 176 170 * between root nodes. 177 171 */ 178 - int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len) 172 + int wfx_send_pds_legacy(struct wfx_dev *wdev, u8 *buf, size_t len) 179 173 { 180 174 int ret; 181 - int start, brace_level, i; 175 + int start = 0, brace_level = 0, i; 182 176 183 - start = 0; 184 - brace_level = 0; 185 - if (buf[0] != '{') { 186 - dev_err(wdev->dev, "valid PDS start with '{'. Did you forget to compress it?\n"); 187 - return -EINVAL; 188 - } 189 177 for (i = 1; i < len - 1; i++) { 190 178 if (buf[i] == '{') 191 179 brace_level++; ··· 182 192 brace_level--; 183 193 if (buf[i] == '}' && !brace_level) { 184 194 i++; 185 - if (i - start + 1 > WFX_PDS_MAX_SIZE) 195 + if (i - start + 1 > WFX_PDS_MAX_CHUNK_SIZE) 186 196 return -EFBIG; 187 197 buf[start] = '{'; 188 198 buf[i] = 0; ··· 208 218 buf[i] = ','; 209 219 start = i; 210 220 } 221 + } 222 + return 0; 223 + } 224 + 225 + /* The device needs data about the antenna configuration. This information in provided by PDS 226 + * (Platform Data Set, this is the wording used in WF200 documentation) files. For hardware 227 + * integrators, the full process to create PDS files is described here: 228 + * https://github.com/SiliconLabs/wfx-firmware/blob/master/PDS/README.md 229 + * 230 + * The PDS file is an array of Time-Length-Value structs. 231 + */ 232 + int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len) 233 + { 234 + int ret, chunk_type, chunk_len, chunk_num = 0; 235 + 236 + if (*buf == '{') 237 + return wfx_send_pds_legacy(wdev, buf, len); 238 + while (len > 0) { 239 + chunk_type = get_unaligned_le16(buf + 0); 240 + chunk_len = get_unaligned_le16(buf + 2); 241 + if (chunk_len > len) { 242 + dev_err(wdev->dev, "PDS:%d: corrupted file\n", chunk_num); 243 + return -EINVAL; 244 + } 245 + if (chunk_type != WFX_PDS_TLV_TYPE) { 246 + dev_info(wdev->dev, "PDS:%d: skip unknown data\n", chunk_num); 247 + goto next; 248 + } 249 + if (chunk_len > WFX_PDS_MAX_CHUNK_SIZE) 250 + dev_warn(wdev->dev, "PDS:%d: unexpectly large chunk\n", chunk_num); 251 + if (buf[4] != '{' || buf[chunk_len - 1] != '}') 252 + dev_warn(wdev->dev, "PDS:%d: unexpected content\n", chunk_num); 253 + 254 + ret = wfx_hif_configuration(wdev, buf + 4, chunk_len - 4); 255 + if (ret > 0) { 256 + dev_err(wdev->dev, "PDS:%d: invalid data (unsupported options?)\n", chunk_num); 257 + return -EINVAL; 258 + } 259 + if (ret == -ETIMEDOUT) { 260 + dev_err(wdev->dev, "PDS:%d: chip didn't reply (corrupted file?)\n", chunk_num); 261 + return ret; 262 + } 263 + if (ret) { 264 + dev_err(wdev->dev, "PDS:%d: chip returned an unknown error\n", chunk_num); 265 + return -EIO; 266 + } 267 + next: 268 + chunk_num++; 269 + len -= chunk_len; 270 + buf += chunk_len; 211 271 } 212 272 return 0; 213 273 }