blob: 705fe668b969819761584dbd25276eed403f756d [file] [log] [blame]
Jouni Malinenff1d2762005-05-12 22:54:16 -04001static int prism2_enable_aux_port(struct net_device *dev, int enable)
2{
3 u16 val, reg;
4 int i, tries;
5 unsigned long flags;
6 struct hostap_interface *iface;
7 local_info_t *local;
8
9 iface = netdev_priv(dev);
10 local = iface->local;
11
12 if (local->no_pri) {
13 if (enable) {
14 PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux "
15 "port is already enabled\n", dev->name);
16 }
17 return 0;
18 }
19
20 spin_lock_irqsave(&local->cmdlock, flags);
21
22 /* wait until busy bit is clear */
23 tries = HFA384X_CMD_BUSY_TIMEOUT;
24 while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
25 tries--;
26 udelay(1);
27 }
28 if (tries == 0) {
29 reg = HFA384X_INW(HFA384X_CMD_OFF);
30 spin_unlock_irqrestore(&local->cmdlock, flags);
31 printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n",
32 dev->name, reg);
33 return -ETIMEDOUT;
34 }
35
36 val = HFA384X_INW(HFA384X_CONTROL_OFF);
37
38 if (enable) {
39 HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF);
40 HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF);
41 HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF);
42
43 if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED)
44 printk("prism2_enable_aux_port: was not disabled!?\n");
45 val &= ~HFA384X_AUX_PORT_MASK;
46 val |= HFA384X_AUX_PORT_ENABLE;
47 } else {
48 HFA384X_OUTW(0, HFA384X_PARAM0_OFF);
49 HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
50 HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
51
52 if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED)
53 printk("prism2_enable_aux_port: was not enabled!?\n");
54 val &= ~HFA384X_AUX_PORT_MASK;
55 val |= HFA384X_AUX_PORT_DISABLE;
56 }
57 HFA384X_OUTW(val, HFA384X_CONTROL_OFF);
58
59 udelay(5);
60
61 i = 10000;
62 while (i > 0) {
63 val = HFA384X_INW(HFA384X_CONTROL_OFF);
64 val &= HFA384X_AUX_PORT_MASK;
65
66 if ((enable && val == HFA384X_AUX_PORT_ENABLED) ||
67 (!enable && val == HFA384X_AUX_PORT_DISABLED))
68 break;
69
70 udelay(10);
71 i--;
72 }
73
74 spin_unlock_irqrestore(&local->cmdlock, flags);
75
76 if (i == 0) {
77 printk("prism2_enable_aux_port(%d) timed out\n",
78 enable);
79 return -ETIMEDOUT;
80 }
81
82 return 0;
83}
84
85
86static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len,
87 void *buf)
88{
89 u16 page, offset;
90 if (addr & 1 || len & 1)
91 return -1;
92
93 page = addr >> 7;
94 offset = addr & 0x7f;
95
96 HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
97 HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
98
99 udelay(5);
100
101#ifdef PRISM2_PCI
102 {
Al Viro8a9faf32007-12-21 03:30:16 -0500103 __le16 *pos = (__le16 *) buf;
Jouni Malinenff1d2762005-05-12 22:54:16 -0400104 while (len > 0) {
105 *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF);
106 len -= 2;
107 }
108 }
109#else /* PRISM2_PCI */
110 HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2);
111#endif /* PRISM2_PCI */
112
113 return 0;
114}
115
116
117static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len,
118 void *buf)
119{
120 u16 page, offset;
121 if (addr & 1 || len & 1)
122 return -1;
123
124 page = addr >> 7;
125 offset = addr & 0x7f;
126
127 HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
128 HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
129
130 udelay(5);
131
132#ifdef PRISM2_PCI
133 {
Al Viro8a9faf32007-12-21 03:30:16 -0500134 __le16 *pos = (__le16 *) buf;
Jouni Malinenff1d2762005-05-12 22:54:16 -0400135 while (len > 0) {
136 HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF);
137 len -= 2;
138 }
139 }
140#else /* PRISM2_PCI */
141 HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2);
142#endif /* PRISM2_PCI */
143
144 return 0;
145}
146
147
148static int prism2_pda_ok(u8 *buf)
149{
Al Viro8a9faf32007-12-21 03:30:16 -0500150 __le16 *pda = (__le16 *) buf;
Jouni Malinenff1d2762005-05-12 22:54:16 -0400151 int pos;
152 u16 len, pdr;
153
154 if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff &&
155 buf[3] == 0x00)
156 return 0;
157
158 pos = 0;
159 while (pos + 1 < PRISM2_PDA_SIZE / 2) {
160 len = le16_to_cpu(pda[pos]);
161 pdr = le16_to_cpu(pda[pos + 1]);
162 if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2)
163 return 0;
164
165 if (pdr == 0x0000 && len == 2) {
166 /* PDA end found */
167 return 1;
168 }
169
170 pos += len + 1;
171 }
172
173 return 0;
174}
175
176
David Howells6bbefe82013-04-10 21:13:23 +0100177#define prism2_download_aux_dump_npages 65536
178
179struct prism2_download_aux_dump {
180 local_info_t *local;
181 u16 page[0x80];
182};
183
184static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v)
Jouni Malinenff1d2762005-05-12 22:54:16 -0400185{
David Howells6bbefe82013-04-10 21:13:23 +0100186 struct prism2_download_aux_dump *ctx = m->private;
Jouni Malinenff1d2762005-05-12 22:54:16 -0400187
David Howells6bbefe82013-04-10 21:13:23 +0100188 hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page);
189 seq_write(m, ctx->page, 0x80);
Jouni Malinenff1d2762005-05-12 22:54:16 -0400190 return 0;
191}
192
David Howells6bbefe82013-04-10 21:13:23 +0100193static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos)
194{
195 struct prism2_download_aux_dump *ctx = m->private;
196 prism2_enable_aux_port(ctx->local->dev, 1);
197 if (*_pos >= prism2_download_aux_dump_npages)
198 return NULL;
199 return (void *)((unsigned long)*_pos + 1);
200}
201
202static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos)
203{
204 ++*_pos;
205 if (*_pos >= prism2_download_aux_dump_npages)
206 return NULL;
207 return (void *)((unsigned long)*_pos + 1);
208}
209
210static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v)
211{
212 struct prism2_download_aux_dump *ctx = m->private;
213 prism2_enable_aux_port(ctx->local->dev, 0);
214}
215
216static const struct seq_operations prism2_download_aux_dump_proc_seqops = {
217 .start = prism2_download_aux_dump_proc_start,
218 .next = prism2_download_aux_dump_proc_next,
219 .stop = prism2_download_aux_dump_proc_stop,
220 .show = prism2_download_aux_dump_proc_show,
221};
222
223static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file)
224{
225 int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops,
226 sizeof(struct prism2_download_aux_dump));
227 if (ret == 0) {
228 struct seq_file *m = file->private_data;
229 m->private = PDE_DATA(inode);
230 }
231 return ret;
232}
233
234static const struct file_operations prism2_download_aux_dump_proc_fops = {
235 .open = prism2_download_aux_dump_proc_open,
236 .read = seq_read,
237 .llseek = seq_lseek,
238 .release = seq_release_private,
239};
240
Jouni Malinenff1d2762005-05-12 22:54:16 -0400241
242static u8 * prism2_read_pda(struct net_device *dev)
243{
244 u8 *buf;
245 int res, i, found = 0;
246#define NUM_PDA_ADDRS 4
247 unsigned int pda_addr[NUM_PDA_ADDRS] = {
248 0x7f0000 /* others than HFA3841 */,
249 0x3f0000 /* HFA3841 */,
250 0x390000 /* apparently used in older cards */,
251 0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */,
252 };
253
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800254 buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL);
Jouni Malinenff1d2762005-05-12 22:54:16 -0400255 if (buf == NULL)
256 return NULL;
257
258 /* Note: wlan card should be in initial state (just after init cmd)
259 * and no other operations should be performed concurrently. */
260
261 prism2_enable_aux_port(dev, 1);
262
263 for (i = 0; i < NUM_PDA_ADDRS; i++) {
264 PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x",
265 dev->name, pda_addr[i]);
266 res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf);
267 if (res)
268 continue;
269 if (res == 0 && prism2_pda_ok(buf)) {
270 PDEBUG2(DEBUG_EXTRA2, ": OK\n");
271 found = 1;
272 break;
273 } else {
274 PDEBUG2(DEBUG_EXTRA2, ": failed\n");
275 }
276 }
277
278 prism2_enable_aux_port(dev, 0);
279
280 if (!found) {
281 printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name);
282 kfree(buf);
283 buf = NULL;
284 }
285
286 return buf;
287}
288
289
290static int prism2_download_volatile(local_info_t *local,
291 struct prism2_download_data *param)
292{
293 struct net_device *dev = local->dev;
294 int ret = 0, i;
295 u16 param0, param1;
296
297 if (local->hw_downloading) {
298 printk(KERN_WARNING "%s: Already downloading - aborting new "
299 "request\n", dev->name);
300 return -1;
301 }
302
303 local->hw_downloading = 1;
304 if (local->pri_only) {
305 hfa384x_disable_interrupts(dev);
306 } else {
307 prism2_hw_shutdown(dev, 0);
308
309 if (prism2_hw_init(dev, 0)) {
310 printk(KERN_WARNING "%s: Could not initialize card for"
311 " download\n", dev->name);
312 ret = -1;
313 goto out;
314 }
315 }
316
317 if (prism2_enable_aux_port(dev, 1)) {
318 printk(KERN_WARNING "%s: Could not enable AUX port\n",
319 dev->name);
320 ret = -1;
321 goto out;
322 }
323
324 param0 = param->start_addr & 0xffff;
325 param1 = param->start_addr >> 16;
326
327 HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
328 HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
329 if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
330 (HFA384X_PROGMODE_ENABLE_VOLATILE << 8),
331 param0)) {
332 printk(KERN_WARNING "%s: Download command execution failed\n",
333 dev->name);
334 ret = -1;
335 goto out;
336 }
337
338 for (i = 0; i < param->num_areas; i++) {
339 PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
340 dev->name, param->data[i].len, param->data[i].addr);
341 if (hfa384x_to_aux(dev, param->data[i].addr,
342 param->data[i].len, param->data[i].data)) {
343 printk(KERN_WARNING "%s: RAM download at 0x%08x "
344 "(len=%d) failed\n", dev->name,
345 param->data[i].addr, param->data[i].len);
346 ret = -1;
347 goto out;
348 }
349 }
350
351 HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
352 HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
353 if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
354 (HFA384X_PROGMODE_DISABLE << 8), param0)) {
355 printk(KERN_WARNING "%s: Download command execution failed\n",
356 dev->name);
357 ret = -1;
358 goto out;
359 }
360 /* ProgMode disable causes the hardware to restart itself from the
361 * given starting address. Give hw some time and ACK command just in
362 * case restart did not happen. */
363 mdelay(5);
364 HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
365
366 if (prism2_enable_aux_port(dev, 0)) {
367 printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
368 dev->name);
369 /* continue anyway.. restart should have taken care of this */
370 }
371
372 mdelay(5);
373 local->hw_downloading = 0;
374 if (prism2_hw_config(dev, 2)) {
375 printk(KERN_WARNING "%s: Card configuration after RAM "
376 "download failed\n", dev->name);
377 ret = -1;
378 goto out;
379 }
380
381 out:
382 local->hw_downloading = 0;
383 return ret;
384}
385
386
387static int prism2_enable_genesis(local_info_t *local, int hcr)
388{
389 struct net_device *dev = local->dev;
390 u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff };
391 u8 readbuf[4];
392
393 printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n",
394 dev->name, hcr);
395 local->func->cor_sreset(local);
396 hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
397 local->func->genesis_reset(local, hcr);
398
399 /* Readback test */
400 hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
401 hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
402 hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
403
404 if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) {
405 printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n",
406 hcr);
407 return 0;
408 } else {
409 printk(KERN_DEBUG "Readback test failed, HCR 0x%02x "
410 "write %02x %02x %02x %02x read %02x %02x %02x %02x\n",
411 hcr, initseq[0], initseq[1], initseq[2], initseq[3],
412 readbuf[0], readbuf[1], readbuf[2], readbuf[3]);
413 return 1;
414 }
415}
416
417
418static int prism2_get_ram_size(local_info_t *local)
419{
420 int ret;
421
422 /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */
423 if (prism2_enable_genesis(local, 0x1f) == 0)
424 ret = 8;
425 else if (prism2_enable_genesis(local, 0x0f) == 0)
426 ret = 16;
427 else
428 ret = -1;
429
430 /* Disable genesis mode */
431 local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17);
432
433 return ret;
434}
435
436
437static int prism2_download_genesis(local_info_t *local,
438 struct prism2_download_data *param)
439{
440 struct net_device *dev = local->dev;
441 int ram16 = 0, i;
442 int ret = 0;
443
444 if (local->hw_downloading) {
445 printk(KERN_WARNING "%s: Already downloading - aborting new "
446 "request\n", dev->name);
447 return -EBUSY;
448 }
449
450 if (!local->func->genesis_reset || !local->func->cor_sreset) {
451 printk(KERN_INFO "%s: Genesis mode downloading not supported "
452 "with this hwmodel\n", dev->name);
453 return -EOPNOTSUPP;
454 }
455
456 local->hw_downloading = 1;
457
458 if (prism2_enable_aux_port(dev, 1)) {
459 printk(KERN_DEBUG "%s: failed to enable AUX port\n",
460 dev->name);
461 ret = -EIO;
462 goto out;
463 }
464
465 if (local->sram_type == -1) {
466 /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */
467 if (prism2_enable_genesis(local, 0x1f) == 0) {
468 ram16 = 0;
469 PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 "
470 "SRAM\n", dev->name);
471 } else if (prism2_enable_genesis(local, 0x0f) == 0) {
472 ram16 = 1;
473 PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 "
474 "SRAM\n", dev->name);
475 } else {
476 printk(KERN_DEBUG "%s: Could not initiate genesis "
477 "mode\n", dev->name);
478 ret = -EIO;
479 goto out;
480 }
481 } else {
482 if (prism2_enable_genesis(local, local->sram_type == 8 ?
483 0x1f : 0x0f)) {
484 printk(KERN_DEBUG "%s: Failed to set Genesis "
485 "mode (sram_type=%d)\n", dev->name,
486 local->sram_type);
487 ret = -EIO;
488 goto out;
489 }
490 ram16 = local->sram_type != 8;
491 }
492
493 for (i = 0; i < param->num_areas; i++) {
494 PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
495 dev->name, param->data[i].len, param->data[i].addr);
496 if (hfa384x_to_aux(dev, param->data[i].addr,
497 param->data[i].len, param->data[i].data)) {
498 printk(KERN_WARNING "%s: RAM download at 0x%08x "
499 "(len=%d) failed\n", dev->name,
500 param->data[i].addr, param->data[i].len);
501 ret = -EIO;
502 goto out;
503 }
504 }
505
506 PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n");
507 local->func->genesis_reset(local, ram16 ? 0x07 : 0x17);
508 if (prism2_enable_aux_port(dev, 0)) {
509 printk(KERN_DEBUG "%s: Failed to disable AUX port\n",
510 dev->name);
511 }
512
513 mdelay(5);
514 local->hw_downloading = 0;
515
516 PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n");
517 /*
518 * Make sure the INIT command does not generate a command completion
519 * event by disabling interrupts.
520 */
521 hfa384x_disable_interrupts(dev);
522 if (prism2_hw_init(dev, 1)) {
523 printk(KERN_DEBUG "%s: Initialization after genesis mode "
524 "download failed\n", dev->name);
525 ret = -EIO;
526 goto out;
527 }
528
529 PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n");
530 if (prism2_hw_init2(dev, 1)) {
531 printk(KERN_DEBUG "%s: Initialization(2) after genesis mode "
532 "download failed\n", dev->name);
533 ret = -EIO;
534 goto out;
535 }
536
537 out:
538 local->hw_downloading = 0;
539 return ret;
540}
541
542
543#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
544/* Note! Non-volatile downloading functionality has not yet been tested
545 * thoroughly and it may corrupt flash image and effectively kill the card that
546 * is being updated. You have been warned. */
547
548static inline int prism2_download_block(struct net_device *dev,
549 u32 addr, u8 *data,
550 u32 bufaddr, int rest_len)
551{
552 u16 param0, param1;
553 int block_len;
554
555 block_len = rest_len < 4096 ? rest_len : 4096;
556
557 param0 = addr & 0xffff;
558 param1 = addr >> 16;
559
560 HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF);
561 HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
562
563 if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
564 (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8),
565 param0)) {
566 printk(KERN_WARNING "%s: Flash download command execution "
567 "failed\n", dev->name);
568 return -1;
569 }
570
571 if (hfa384x_to_aux(dev, bufaddr, block_len, data)) {
572 printk(KERN_WARNING "%s: flash download at 0x%08x "
573 "(len=%d) failed\n", dev->name, addr, block_len);
574 return -1;
575 }
576
577 HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
578 HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
579 if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
580 (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8),
581 0)) {
582 printk(KERN_WARNING "%s: Flash write command execution "
583 "failed\n", dev->name);
584 return -1;
585 }
586
587 return block_len;
588}
589
590
591static int prism2_download_nonvolatile(local_info_t *local,
592 struct prism2_download_data *dl)
593{
594 struct net_device *dev = local->dev;
595 int ret = 0, i;
596 struct {
Al Viro8a9faf32007-12-21 03:30:16 -0500597 __le16 page;
598 __le16 offset;
599 __le16 len;
Jouni Malinenff1d2762005-05-12 22:54:16 -0400600 } dlbuffer;
601 u32 bufaddr;
602
603 if (local->hw_downloading) {
604 printk(KERN_WARNING "%s: Already downloading - aborting new "
605 "request\n", dev->name);
606 return -1;
607 }
608
609 ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER,
610 &dlbuffer, 6, 0);
611
612 if (ret < 0) {
613 printk(KERN_WARNING "%s: Could not read download buffer "
614 "parameters\n", dev->name);
615 goto out;
616 }
617
Jouni Malinenff1d2762005-05-12 22:54:16 -0400618 printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n",
Al Viro8a9faf32007-12-21 03:30:16 -0500619 le16_to_cpu(dlbuffer.len),
620 le16_to_cpu(dlbuffer.page),
621 le16_to_cpu(dlbuffer.offset));
Jouni Malinenff1d2762005-05-12 22:54:16 -0400622
Al Viro8a9faf32007-12-21 03:30:16 -0500623 bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset);
Jouni Malinenff1d2762005-05-12 22:54:16 -0400624
625 local->hw_downloading = 1;
626
627 if (!local->pri_only) {
628 prism2_hw_shutdown(dev, 0);
629
630 if (prism2_hw_init(dev, 0)) {
631 printk(KERN_WARNING "%s: Could not initialize card for"
632 " download\n", dev->name);
633 ret = -1;
634 goto out;
635 }
636 }
637
638 hfa384x_disable_interrupts(dev);
639
640 if (prism2_enable_aux_port(dev, 1)) {
641 printk(KERN_WARNING "%s: Could not enable AUX port\n",
642 dev->name);
643 ret = -1;
644 goto out;
645 }
646
647 printk(KERN_DEBUG "%s: starting flash download\n", dev->name);
648 for (i = 0; i < dl->num_areas; i++) {
649 int rest_len = dl->data[i].len;
650 int data_off = 0;
651
652 while (rest_len > 0) {
653 int block_len;
654
655 block_len = prism2_download_block(
656 dev, dl->data[i].addr + data_off,
657 dl->data[i].data + data_off, bufaddr,
658 rest_len);
659
660 if (block_len < 0) {
661 ret = -1;
662 goto out;
663 }
664
665 rest_len -= block_len;
666 data_off += block_len;
667 }
668 }
669
670 HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
671 HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
672 if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
673 (HFA384X_PROGMODE_DISABLE << 8), 0)) {
674 printk(KERN_WARNING "%s: Download command execution failed\n",
675 dev->name);
676 ret = -1;
677 goto out;
678 }
679
680 if (prism2_enable_aux_port(dev, 0)) {
681 printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
682 dev->name);
683 /* continue anyway.. restart should have taken care of this */
684 }
685
686 mdelay(5);
687
688 local->func->hw_reset(dev);
689 local->hw_downloading = 0;
690 if (prism2_hw_config(dev, 2)) {
691 printk(KERN_WARNING "%s: Card configuration after flash "
692 "download failed\n", dev->name);
693 ret = -1;
694 } else {
695 printk(KERN_INFO "%s: Card initialized successfully after "
696 "flash download\n", dev->name);
697 }
698
699 out:
700 local->hw_downloading = 0;
701 return ret;
702}
703#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
704
705
706static void prism2_download_free_data(struct prism2_download_data *dl)
707{
708 int i;
709
710 if (dl == NULL)
711 return;
712
713 for (i = 0; i < dl->num_areas; i++)
714 kfree(dl->data[i].data);
715 kfree(dl);
716}
717
718
719static int prism2_download(local_info_t *local,
720 struct prism2_download_param *param)
721{
722 int ret = 0;
723 int i;
724 u32 total_len = 0;
725 struct prism2_download_data *dl = NULL;
726
727 printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x "
728 "num_areas=%d\n",
729 param->dl_cmd, param->start_addr, param->num_areas);
730
731 if (param->num_areas > 100) {
732 ret = -EINVAL;
733 goto out;
734 }
735
Yan Burmanb0471bb72006-12-02 13:33:40 +0200736 dl = kzalloc(sizeof(*dl) + param->num_areas *
Jouni Malinenff1d2762005-05-12 22:54:16 -0400737 sizeof(struct prism2_download_data_area), GFP_KERNEL);
738 if (dl == NULL) {
739 ret = -ENOMEM;
740 goto out;
741 }
Jouni Malinenff1d2762005-05-12 22:54:16 -0400742 dl->dl_cmd = param->dl_cmd;
743 dl->start_addr = param->start_addr;
744 dl->num_areas = param->num_areas;
745 for (i = 0; i < param->num_areas; i++) {
746 PDEBUG(DEBUG_EXTRA2,
747 " area %d: addr=0x%08x len=%d ptr=0x%p\n",
748 i, param->data[i].addr, param->data[i].len,
749 param->data[i].ptr);
750
751 dl->data[i].addr = param->data[i].addr;
752 dl->data[i].len = param->data[i].len;
753
754 total_len += param->data[i].len;
755 if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN ||
756 total_len > PRISM2_MAX_DOWNLOAD_LEN) {
757 ret = -E2BIG;
758 goto out;
759 }
760
761 dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL);
762 if (dl->data[i].data == NULL) {
763 ret = -ENOMEM;
764 goto out;
765 }
766
767 if (copy_from_user(dl->data[i].data, param->data[i].ptr,
768 param->data[i].len)) {
769 ret = -EFAULT;
770 goto out;
771 }
772 }
773
774 switch (param->dl_cmd) {
775 case PRISM2_DOWNLOAD_VOLATILE:
776 case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT:
777 ret = prism2_download_volatile(local, dl);
778 break;
779 case PRISM2_DOWNLOAD_VOLATILE_GENESIS:
780 case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT:
781 ret = prism2_download_genesis(local, dl);
782 break;
783 case PRISM2_DOWNLOAD_NON_VOLATILE:
784#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
785 ret = prism2_download_nonvolatile(local, dl);
786#else /* PRISM2_NON_VOLATILE_DOWNLOAD */
787 printk(KERN_INFO "%s: non-volatile downloading not enabled\n",
788 local->dev->name);
789 ret = -EOPNOTSUPP;
790#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
791 break;
792 default:
793 printk(KERN_DEBUG "%s: unsupported download command %d\n",
794 local->dev->name, param->dl_cmd);
795 ret = -EINVAL;
796 break;
Joe Perchesee289b62010-05-17 22:47:34 -0700797 }
Jouni Malinenff1d2762005-05-12 22:54:16 -0400798
799 out:
800 if (ret == 0 && dl &&
801 param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) {
802 prism2_download_free_data(local->dl_pri);
803 local->dl_pri = dl;
804 } else if (ret == 0 && dl &&
805 param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) {
806 prism2_download_free_data(local->dl_sec);
807 local->dl_sec = dl;
808 } else
809 prism2_download_free_data(dl);
810
811 return ret;
812}