1 /*
2  * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* Algorithmic part of the firmware download.
18  * To be included in the container file providing framework
19  */
20 
21 #define wil_err_fw(wil, fmt, arg...) wil_err(wil, "ERR[ FW ]" fmt, ##arg)
22 #define wil_dbg_fw(wil, fmt, arg...) wil_dbg(wil, "DBG[ FW ]" fmt, ##arg)
23 #define wil_hex_dump_fw(prefix_str, prefix_type, rowsize,		\
24 			groupsize, buf, len, ascii)			\
25 			print_hex_dump_debug("DBG[ FW ]" prefix_str,	\
26 					     prefix_type, rowsize,	\
27 					     groupsize, buf, len, ascii)
28 
29 #define FW_ADDR_CHECK(ioaddr, val, msg) do { \
30 		ioaddr = wmi_buffer(wil, val); \
31 		if (!ioaddr) { \
32 			wil_err_fw(wil, "bad " msg ": 0x%08x\n", \
33 				   le32_to_cpu(val)); \
34 			return -EINVAL; \
35 		} \
36 	} while (0)
37 
38 /**
39  * wil_fw_verify - verify firmware file validity
40  *
41  * perform various checks for the firmware file header.
42  * records are not validated.
43  *
44  * Return file size or negative error
45  */
46 static int wil_fw_verify(struct wil6210_priv *wil, const u8 *data, size_t size)
47 {
48 	const struct wil_fw_record_head *hdr = (const void *)data;
49 	struct wil_fw_record_file_header fh;
50 	const struct wil_fw_record_file_header *fh_;
51 	u32 crc;
52 	u32 dlen;
53 
54 	if (size % 4) {
55 		wil_err_fw(wil, "image size not aligned: %zu\n", size);
56 		return -EINVAL;
57 	}
58 	/* have enough data for the file header? */
59 	if (size < sizeof(*hdr) + sizeof(fh)) {
60 		wil_err_fw(wil, "file too short: %zu bytes\n", size);
61 		return -EINVAL;
62 	}
63 
64 	/* start with the file header? */
65 	if (le16_to_cpu(hdr->type) != wil_fw_type_file_header) {
66 		wil_err_fw(wil, "no file header\n");
67 		return -EINVAL;
68 	}
69 
70 	/* data_len */
71 	fh_ = (struct wil_fw_record_file_header *)&hdr[1];
72 	dlen = le32_to_cpu(fh_->data_len);
73 	if (dlen % 4) {
74 		wil_err_fw(wil, "data length not aligned: %lu\n", (ulong)dlen);
75 		return -EINVAL;
76 	}
77 	if (size < dlen) {
78 		wil_err_fw(wil, "file truncated at %zu/%lu\n",
79 			   size, (ulong)dlen);
80 		return -EINVAL;
81 	}
82 	if (dlen < sizeof(*hdr) + sizeof(fh)) {
83 		wil_err_fw(wil, "data length too short: %lu\n", (ulong)dlen);
84 		return -EINVAL;
85 	}
86 
87 	/* signature */
88 	if (le32_to_cpu(fh_->signature) != WIL_FW_SIGNATURE) {
89 		wil_err_fw(wil, "bad header signature: 0x%08x\n",
90 			   le32_to_cpu(fh_->signature));
91 		return -EINVAL;
92 	}
93 
94 	/* version */
95 	if (le32_to_cpu(fh_->version) > WIL_FW_FMT_VERSION) {
96 		wil_err_fw(wil, "unsupported header version: %d\n",
97 			   le32_to_cpu(fh_->version));
98 		return -EINVAL;
99 	}
100 
101 	/* checksum. ~crc32(~0, data, size) when fh.crc set to 0*/
102 	fh = *fh_;
103 	fh.crc = 0;
104 
105 	crc = crc32_le(~0, (unsigned char const *)hdr, sizeof(*hdr));
106 	crc = crc32_le(crc, (unsigned char const *)&fh, sizeof(fh));
107 	crc = crc32_le(crc, (unsigned char const *)&fh_[1],
108 		       dlen - sizeof(*hdr) - sizeof(fh));
109 	crc = ~crc;
110 
111 	if (crc != le32_to_cpu(fh_->crc)) {
112 		wil_err_fw(wil, "checksum mismatch:"
113 			   " calculated for %lu bytes 0x%08x != 0x%08x\n",
114 			   (ulong)dlen, crc, le32_to_cpu(fh_->crc));
115 		return -EINVAL;
116 	}
117 
118 	return (int)dlen;
119 }
120 
121 static int fw_ignore_section(struct wil6210_priv *wil, const void *data,
122 			     size_t size)
123 {
124 	return 0;
125 }
126 
127 static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
128 			     size_t size)
129 {
130 	wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true);
131 
132 	return 0;
133 }
134 
135 static int
136 fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
137 		       size_t size)
138 {
139 	const struct wil_fw_record_capabilities *rec = data;
140 	size_t capa_size;
141 
142 	if (size < sizeof(*rec) ||
143 	    le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC)
144 		return 0;
145 
146 	capa_size = size - offsetof(struct wil_fw_record_capabilities,
147 				    capabilities);
148 	bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
149 	memcpy(wil->fw_capabilities, rec->capabilities,
150 	       min(sizeof(wil->fw_capabilities), capa_size));
151 	wil_hex_dump_fw("CAPA", DUMP_PREFIX_OFFSET, 16, 1,
152 			rec->capabilities, capa_size, false);
153 	return 0;
154 }
155 
156 static int fw_handle_data(struct wil6210_priv *wil, const void *data,
157 			  size_t size)
158 {
159 	const struct wil_fw_record_data *d = data;
160 	void __iomem *dst;
161 	size_t s = size - sizeof(*d);
162 
163 	if (size < sizeof(*d) + sizeof(u32)) {
164 		wil_err_fw(wil, "data record too short: %zu\n", size);
165 		return -EINVAL;
166 	}
167 
168 	FW_ADDR_CHECK(dst, d->addr, "address");
169 	wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
170 		   s);
171 	wil_memcpy_toio_32(dst, d->data, s);
172 	wmb(); /* finish before processing next record */
173 
174 	return 0;
175 }
176 
177 static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
178 			  size_t size)
179 {
180 	const struct wil_fw_record_fill *d = data;
181 	void __iomem *dst;
182 	u32 v;
183 	size_t s = (size_t)le32_to_cpu(d->size);
184 
185 	if (size != sizeof(*d)) {
186 		wil_err_fw(wil, "bad size for fill record: %zu\n", size);
187 		return -EINVAL;
188 	}
189 
190 	if (s < sizeof(u32)) {
191 		wil_err_fw(wil, "fill size too short: %zu\n", s);
192 		return -EINVAL;
193 	}
194 
195 	if (s % sizeof(u32)) {
196 		wil_err_fw(wil, "fill size not aligned: %zu\n", s);
197 		return -EINVAL;
198 	}
199 
200 	FW_ADDR_CHECK(dst, d->addr, "address");
201 
202 	v = le32_to_cpu(d->value);
203 	wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
204 		   le32_to_cpu(d->addr), v, s);
205 	wil_memset_toio_32(dst, v, s);
206 	wmb(); /* finish before processing next record */
207 
208 	return 0;
209 }
210 
211 static int fw_handle_file_header(struct wil6210_priv *wil, const void *data,
212 				 size_t size)
213 {
214 	const struct wil_fw_record_file_header *d = data;
215 
216 	if (size != sizeof(*d)) {
217 		wil_err_fw(wil, "file header length incorrect: %zu\n", size);
218 		return -EINVAL;
219 	}
220 
221 	wil_dbg_fw(wil, "new file, ver. %d, %i bytes\n",
222 		   d->version, d->data_len);
223 	wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, d->comment,
224 			sizeof(d->comment), true);
225 
226 	if (!memcmp(d->comment, WIL_FW_VERSION_PREFIX,
227 		    WIL_FW_VERSION_PREFIX_LEN))
228 		memcpy(wil->fw_version,
229 		       d->comment + WIL_FW_VERSION_PREFIX_LEN,
230 		       min(sizeof(d->comment) - WIL_FW_VERSION_PREFIX_LEN,
231 			   sizeof(wil->fw_version) - 1));
232 
233 	return 0;
234 }
235 
236 static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data,
237 				  size_t size)
238 {
239 	const struct wil_fw_record_direct_write *d = data;
240 	const struct wil_fw_data_dwrite *block = d->data;
241 	int n, i;
242 
243 	if (size % sizeof(*block)) {
244 		wil_err_fw(wil, "record size not aligned on %zu: %zu\n",
245 			   sizeof(*block), size);
246 		return -EINVAL;
247 	}
248 	n = size / sizeof(*block);
249 
250 	for (i = 0; i < n; i++) {
251 		void __iomem *dst;
252 		u32 m = le32_to_cpu(block[i].mask);
253 		u32 v = le32_to_cpu(block[i].value);
254 		u32 x, y;
255 
256 		FW_ADDR_CHECK(dst, block[i].addr, "address");
257 
258 		x = readl(dst);
259 		y = (x & m) | (v & ~m);
260 		wil_dbg_fw(wil, "write [0x%08x] <== 0x%08x "
261 			   "(old 0x%08x val 0x%08x mask 0x%08x)\n",
262 			   le32_to_cpu(block[i].addr), y, x, v, m);
263 		writel(y, dst);
264 		wmb(); /* finish before processing next record */
265 	}
266 
267 	return 0;
268 }
269 
270 static int gw_write(struct wil6210_priv *wil, void __iomem *gwa_addr,
271 		    void __iomem *gwa_cmd, void __iomem *gwa_ctl, u32 gw_cmd,
272 		    u32 a)
273 {
274 	unsigned delay = 0;
275 
276 	writel(a, gwa_addr);
277 	writel(gw_cmd, gwa_cmd);
278 	wmb(); /* finish before activate gw */
279 
280 	writel(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */
281 	do {
282 		udelay(1); /* typical time is few usec */
283 		if (delay++ > 100) {
284 			wil_err_fw(wil, "gw timeout\n");
285 			return -EINVAL;
286 		}
287 	} while (readl(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */
288 
289 	return 0;
290 }
291 
292 static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data,
293 				  size_t size)
294 {
295 	const struct wil_fw_record_gateway_data *d = data;
296 	const struct wil_fw_data_gw *block = d->data;
297 	void __iomem *gwa_addr;
298 	void __iomem *gwa_val;
299 	void __iomem *gwa_cmd;
300 	void __iomem *gwa_ctl;
301 	u32 gw_cmd;
302 	int n, i;
303 
304 	if (size < sizeof(*d) + sizeof(*block)) {
305 		wil_err_fw(wil, "gateway record too short: %zu\n", size);
306 		return -EINVAL;
307 	}
308 
309 	if ((size - sizeof(*d)) % sizeof(*block)) {
310 		wil_err_fw(wil, "gateway record data size"
311 			   " not aligned on %zu: %zu\n",
312 			   sizeof(*block), size - sizeof(*d));
313 		return -EINVAL;
314 	}
315 	n = (size - sizeof(*d)) / sizeof(*block);
316 
317 	gw_cmd = le32_to_cpu(d->command);
318 
319 	wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n",
320 		   n, gw_cmd);
321 
322 	FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
323 	FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr");
324 	FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
325 	FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
326 
327 	wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x"
328 		   " cmd 0x%08x ctl 0x%08x\n",
329 		   le32_to_cpu(d->gateway_addr_addr),
330 		   le32_to_cpu(d->gateway_value_addr),
331 		   le32_to_cpu(d->gateway_cmd_addr),
332 		   le32_to_cpu(d->gateway_ctrl_address));
333 
334 	for (i = 0; i < n; i++) {
335 		int rc;
336 		u32 a = le32_to_cpu(block[i].addr);
337 		u32 v = le32_to_cpu(block[i].value);
338 
339 		wil_dbg_fw(wil, "  gw write[%3d] [0x%08x] <== 0x%08x\n",
340 			   i, a, v);
341 
342 		writel(v, gwa_val);
343 		rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a);
344 		if (rc)
345 			return rc;
346 	}
347 
348 	return 0;
349 }
350 
351 static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data,
352 				   size_t size)
353 {
354 	const struct wil_fw_record_gateway_data4 *d = data;
355 	const struct wil_fw_data_gw4 *block = d->data;
356 	void __iomem *gwa_addr;
357 	void __iomem *gwa_val[ARRAY_SIZE(block->value)];
358 	void __iomem *gwa_cmd;
359 	void __iomem *gwa_ctl;
360 	u32 gw_cmd;
361 	int n, i, k;
362 
363 	if (size < sizeof(*d) + sizeof(*block)) {
364 		wil_err_fw(wil, "gateway4 record too short: %zu\n", size);
365 		return -EINVAL;
366 	}
367 
368 	if ((size - sizeof(*d)) % sizeof(*block)) {
369 		wil_err_fw(wil, "gateway4 record data size"
370 			   " not aligned on %zu: %zu\n",
371 			   sizeof(*block), size - sizeof(*d));
372 		return -EINVAL;
373 	}
374 	n = (size - sizeof(*d)) / sizeof(*block);
375 
376 	gw_cmd = le32_to_cpu(d->command);
377 
378 	wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n",
379 		   n, gw_cmd);
380 
381 	FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
382 	for (k = 0; k < ARRAY_SIZE(block->value); k++)
383 		FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k],
384 			      "gateway_value_addr");
385 	FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
386 	FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
387 
388 	wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n",
389 		   le32_to_cpu(d->gateway_addr_addr),
390 		   le32_to_cpu(d->gateway_cmd_addr),
391 		   le32_to_cpu(d->gateway_ctrl_address));
392 	wil_hex_dump_fw("val addresses: ", DUMP_PREFIX_NONE, 16, 4,
393 			d->gateway_value_addr, sizeof(d->gateway_value_addr),
394 			false);
395 
396 	for (i = 0; i < n; i++) {
397 		int rc;
398 		u32 a = le32_to_cpu(block[i].addr);
399 		u32 v[ARRAY_SIZE(block->value)];
400 
401 		for (k = 0; k < ARRAY_SIZE(block->value); k++)
402 			v[k] = le32_to_cpu(block[i].value[k]);
403 
404 		wil_dbg_fw(wil, "  gw4 write[%3d] [0x%08x] <==\n", i, a);
405 		wil_hex_dump_fw("    val ", DUMP_PREFIX_NONE, 16, 4, v,
406 				sizeof(v), false);
407 
408 		for (k = 0; k < ARRAY_SIZE(block->value); k++)
409 			writel(v[k], gwa_val[k]);
410 		rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a);
411 		if (rc)
412 			return rc;
413 	}
414 
415 	return 0;
416 }
417 
418 static const struct {
419 	int type;
420 	int (*load_handler)(struct wil6210_priv *wil, const void *data,
421 			    size_t size);
422 	int (*parse_handler)(struct wil6210_priv *wil, const void *data,
423 			     size_t size);
424 } wil_fw_handlers[] = {
425 	{wil_fw_type_comment, fw_handle_comment, fw_handle_capabilities},
426 	{wil_fw_type_data, fw_handle_data, fw_ignore_section},
427 	{wil_fw_type_fill, fw_handle_fill, fw_ignore_section},
428 	/* wil_fw_type_action */
429 	/* wil_fw_type_verify */
430 	{wil_fw_type_file_header, fw_handle_file_header,
431 		fw_handle_file_header},
432 	{wil_fw_type_direct_write, fw_handle_direct_write, fw_ignore_section},
433 	{wil_fw_type_gateway_data, fw_handle_gateway_data, fw_ignore_section},
434 	{wil_fw_type_gateway_data4, fw_handle_gateway_data4,
435 		fw_ignore_section},
436 };
437 
438 static int wil_fw_handle_record(struct wil6210_priv *wil, int type,
439 				const void *data, size_t size, bool load)
440 {
441 	int i;
442 
443 	for (i = 0; i < ARRAY_SIZE(wil_fw_handlers); i++)
444 		if (wil_fw_handlers[i].type == type)
445 			return load ?
446 				wil_fw_handlers[i].load_handler(
447 					wil, data, size) :
448 				wil_fw_handlers[i].parse_handler(
449 					wil, data, size);
450 
451 	wil_err_fw(wil, "unknown record type: %d\n", type);
452 	return -EINVAL;
453 }
454 
455 /**
456  * wil_fw_process - process section from FW file
457  * if load is true: Load the FW and uCode code and data to the
458  * corresponding device memory regions,
459  * otherwise only parse and look for capabilities
460  *
461  * Return error code
462  */
463 static int wil_fw_process(struct wil6210_priv *wil, const void *data,
464 			  size_t size, bool load)
465 {
466 	int rc = 0;
467 	const struct wil_fw_record_head *hdr;
468 	size_t s, hdr_sz;
469 
470 	for (hdr = data;; hdr = (const void *)hdr + s, size -= s) {
471 		if (size < sizeof(*hdr))
472 			break;
473 		hdr_sz = le32_to_cpu(hdr->size);
474 		s = sizeof(*hdr) + hdr_sz;
475 		if (s > size)
476 			break;
477 		if (hdr_sz % 4) {
478 			wil_err_fw(wil, "unaligned record size: %zu\n",
479 				   hdr_sz);
480 			return -EINVAL;
481 		}
482 		rc = wil_fw_handle_record(wil, le16_to_cpu(hdr->type),
483 					  &hdr[1], hdr_sz, load);
484 		if (rc)
485 			return rc;
486 	}
487 	if (size) {
488 		wil_err_fw(wil, "unprocessed bytes: %zu\n", size);
489 		if (size >= sizeof(*hdr)) {
490 			wil_err_fw(wil, "Stop at offset %ld"
491 				   " record type %d [%zd bytes]\n",
492 				   (long)((const void *)hdr - data),
493 				   le16_to_cpu(hdr->type), hdr_sz);
494 		}
495 		return -EINVAL;
496 	}
497 
498 	return rc;
499 }
500 
501 /**
502  * wil_request_firmware - Request firmware
503  *
504  * Request firmware image from the file
505  * If load is true, load firmware to device, otherwise
506  * only parse and extract capabilities
507  *
508  * Return error code
509  */
510 int wil_request_firmware(struct wil6210_priv *wil, const char *name,
511 			 bool load)
512 {
513 	int rc, rc1;
514 	const struct firmware *fw;
515 	size_t sz;
516 	const void *d;
517 
518 	rc = request_firmware(&fw, name, wil_to_dev(wil));
519 	if (rc) {
520 		wil_err_fw(wil, "Failed to load firmware %s\n", name);
521 		return rc;
522 	}
523 	wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size);
524 
525 	for (sz = fw->size, d = fw->data; sz; sz -= rc1, d += rc1) {
526 		rc1 = wil_fw_verify(wil, d, sz);
527 		if (rc1 < 0) {
528 			rc = rc1;
529 			goto out;
530 		}
531 		rc = wil_fw_process(wil, d, rc1, load);
532 		if (rc < 0)
533 			goto out;
534 	}
535 
536 out:
537 	release_firmware(fw);
538 	return rc;
539 }
540 
541 /**
542  * wil_fw_verify_file_exists - checks if firmware file exist
543  *
544  * @wil: driver context
545  * @name: firmware file name
546  *
547  * return value - boolean, true for success, false for failure
548  */
549 bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name)
550 {
551 	const struct firmware *fw;
552 	int rc;
553 
554 	rc = request_firmware(&fw, name, wil_to_dev(wil));
555 	if (!rc)
556 		release_firmware(fw);
557 	else
558 		wil_dbg_fw(wil, "<%s> not available: %d\n", name, rc);
559 	return !rc;
560 }
561