Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / drivers / net / wireless / hermes.c
1 /* hermes.c
2  *
3  * Driver core for the "Hermes" wireless MAC controller, as used in
4  * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
5  * work on the hfa3841 and hfa3842 MAC controller chips used in the
6  * Prism II chipsets.
7  *
8  * This is not a complete driver, just low-level access routines for
9  * the MAC controller itself.
10  *
11  * Based on the prism2 driver from Absolute Value Systems' linux-wlan
12  * project, the Linux wvlan_cs driver, Lucent's HCF-Light
13  * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no
14  * particular order).
15  *
16  * Copyright (C) 2000, David Gibson, Linuxcare Australia.
17  * (C) Copyright David Gibson, IBM Corp. 2001-2003.
18  * 
19  * The contents of this file are subject to the Mozilla Public License
20  * Version 1.1 (the "License"); you may not use this file except in
21  * compliance with the License. You may obtain a copy of the License
22  * at http://www.mozilla.org/MPL/
23  *
24  * Software distributed under the License is distributed on an "AS IS"
25  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
26  * the License for the specific language governing rights and
27  * limitations under the License.
28  *
29  * Alternatively, the contents of this file may be used under the
30  * terms of the GNU General Public License version 2 (the "GPL"), in
31  * which case the provisions of the GPL are applicable instead of the
32  * above.  If you wish to allow the use of your version of this file
33  * only under the terms of the GPL and not to allow others to use your
34  * version of this file under the MPL, indicate your decision by
35  * deleting the provisions above and replace them with the notice and
36  * other provisions required by the GPL.  If you do not delete the
37  * provisions above, a recipient may use your version of this file
38  * under either the MPL or the GPL.
39  */
40
41 #include <linux/config.h>
42
43 #include <linux/module.h>
44 #include <linux/types.h>
45 #include <linux/threads.h>
46 #include <linux/smp.h>
47 #include <asm/io.h>
48 #include <linux/delay.h>
49 #include <linux/init.h>
50 #include <linux/kernel.h>
51 #include <linux/net.h>
52 #include <asm/errno.h>
53
54 #include "hermes.h"
55
56 MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
57 MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>"
58         " & David Gibson <hermes@gibson.dropbear.id.au>");
59 MODULE_LICENSE("Dual MPL/GPL");
60
61 /* These are maximum timeouts. Most often, card wil react much faster */
62 #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
63 #define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
64 #define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
65 #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
66
67 /*
68  * Debugging helpers
69  */
70
71 #define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \
72                         printk(stuff);} while (0)
73
74 #undef HERMES_DEBUG
75 #ifdef HERMES_DEBUG
76 #include <stdarg.h>
77
78 #define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff)
79
80 #else /* ! HERMES_DEBUG */
81
82 #define DEBUG(lvl, stuff...) do { } while (0)
83
84 #endif /* ! HERMES_DEBUG */
85
86
87 /*
88  * Internal functions
89  */
90
91 /* Issue a command to the chip. Waiting for it to complete is the caller's
92    problem.
93
94    Returns -EBUSY if the command register is busy, 0 on success.
95
96    Callable from any context.
97 */
98 static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0)
99 {
100         int k = CMD_BUSY_TIMEOUT;
101         u16 reg;
102
103         /* First wait for the command register to unbusy */
104         reg = hermes_read_regn(hw, CMD);
105         while ( (reg & HERMES_CMD_BUSY) && k ) {
106                 k--;
107                 udelay(1);
108                 reg = hermes_read_regn(hw, CMD);
109         }
110         if (reg & HERMES_CMD_BUSY) {
111                 return -EBUSY;
112         }
113
114         hermes_write_regn(hw, PARAM2, 0);
115         hermes_write_regn(hw, PARAM1, 0);
116         hermes_write_regn(hw, PARAM0, param0);
117         hermes_write_regn(hw, CMD, cmd);
118         
119         return 0;
120 }
121
122 /*
123  * Function definitions
124  */
125
126 void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
127 {
128         hw->iobase = address;
129         hw->reg_spacing = reg_spacing;
130         hw->inten = 0x0;
131
132 #ifdef HERMES_DEBUG_BUFFER
133         hw->dbufp = 0;
134         memset(&hw->dbuf, 0xff, sizeof(hw->dbuf));
135         memset(&hw->profile, 0, sizeof(hw->profile));
136 #endif
137 }
138
139 int hermes_init(hermes_t *hw)
140 {
141         u16 status, reg;
142         int err = 0;
143         int k;
144
145         /* We don't want to be interrupted while resetting the chipset */
146         hw->inten = 0x0;
147         hermes_write_regn(hw, INTEN, 0);
148         hermes_write_regn(hw, EVACK, 0xffff);
149
150         /* Normally it's a "can't happen" for the command register to
151            be busy when we go to issue a command because we are
152            serializing all commands.  However we want to have some
153            chance of resetting the card even if it gets into a stupid
154            state, so we actually wait to see if the command register
155            will unbusy itself here. */
156         k = CMD_BUSY_TIMEOUT;
157         reg = hermes_read_regn(hw, CMD);
158         while (k && (reg & HERMES_CMD_BUSY)) {
159                 if (reg == 0xffff) /* Special case - the card has probably been removed,
160                                       so don't wait for the timeout */
161                         return -ENODEV;
162
163                 k--;
164                 udelay(1);
165                 reg = hermes_read_regn(hw, CMD);
166         }
167         
168         /* No need to explicitly handle the timeout - if we've timed
169            out hermes_issue_cmd() will probably return -EBUSY below */
170
171         /* According to the documentation, EVSTAT may contain
172            obsolete event occurrence information.  We have to acknowledge
173            it by writing EVACK. */
174         reg = hermes_read_regn(hw, EVSTAT);
175         hermes_write_regn(hw, EVACK, reg);
176
177         /* We don't use hermes_docmd_wait here, because the reset wipes
178            the magic constant in SWSUPPORT0 away, and it gets confused */
179         err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0);
180         if (err)
181                 return err;
182
183         reg = hermes_read_regn(hw, EVSTAT);
184         k = CMD_INIT_TIMEOUT;
185         while ( (! (reg & HERMES_EV_CMD)) && k) {
186                 k--;
187                 udelay(10);
188                 reg = hermes_read_regn(hw, EVSTAT);
189         }
190
191         hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
192
193         if (! hermes_present(hw)) {
194                 DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
195                        hw->iobase);
196                 err = -ENODEV;
197                 goto out;
198         }
199                 
200         if (! (reg & HERMES_EV_CMD)) {
201                 printk(KERN_ERR "hermes @ %p: " 
202                        "Timeout waiting for card to reset (reg=0x%04x)!\n",
203                        hw->iobase, reg);
204                 err = -ETIMEDOUT;
205                 goto out;
206         }
207
208         status = hermes_read_regn(hw, STATUS);
209
210         hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
211
212         if (status & HERMES_STATUS_RESULT)
213                 err = -EIO;
214
215  out:
216         return err;
217 }
218
219 /* Issue a command to the chip, and (busy!) wait for it to
220  * complete.
221  *
222  * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
223  *
224  * Callable from any context, but locking is your problem. */
225 int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
226                       struct hermes_response *resp)
227 {
228         int err;
229         int k;
230         u16 reg;
231         u16 status;
232
233         err = hermes_issue_cmd(hw, cmd, parm0);
234         if (err) {
235                 if (! hermes_present(hw)) {
236                         if (net_ratelimit())
237                                 printk(KERN_WARNING "hermes @ %p: "
238                                        "Card removed while issuing command "
239                                        "0x%04x.\n", hw->iobase, cmd);
240                         err = -ENODEV;
241                 } else 
242                         if (net_ratelimit())
243                                 printk(KERN_ERR "hermes @ %p: "
244                                        "Error %d issuing command 0x%04x.\n",
245                                        hw->iobase, err, cmd);
246                 goto out;
247         }
248
249         reg = hermes_read_regn(hw, EVSTAT);
250         k = CMD_COMPL_TIMEOUT;
251         while ( (! (reg & HERMES_EV_CMD)) && k) {
252                 k--;
253                 udelay(10);
254                 reg = hermes_read_regn(hw, EVSTAT);
255         }
256
257         if (! hermes_present(hw)) {
258                 printk(KERN_WARNING "hermes @ %p: Card removed "
259                        "while waiting for command 0x%04x completion.\n",
260                        hw->iobase, cmd);
261                 err = -ENODEV;
262                 goto out;
263         }
264                 
265         if (! (reg & HERMES_EV_CMD)) {
266                 printk(KERN_ERR "hermes @ %p: Timeout waiting for "
267                        "command 0x%04x completion.\n", hw->iobase, cmd);
268                 err = -ETIMEDOUT;
269                 goto out;
270         }
271
272         status = hermes_read_regn(hw, STATUS);
273         if (resp) {
274                 resp->status = status;
275                 resp->resp0 = hermes_read_regn(hw, RESP0);
276                 resp->resp1 = hermes_read_regn(hw, RESP1);
277                 resp->resp2 = hermes_read_regn(hw, RESP2);
278         }
279
280         hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
281
282         if (status & HERMES_STATUS_RESULT)
283                 err = -EIO;
284
285  out:
286         return err;
287 }
288
289 int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
290 {
291         int err = 0;
292         int k;
293         u16 reg;
294         
295         if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) )
296                 return -EINVAL;
297
298         err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
299         if (err) {
300                 return err;
301         }
302
303         reg = hermes_read_regn(hw, EVSTAT);
304         k = ALLOC_COMPL_TIMEOUT;
305         while ( (! (reg & HERMES_EV_ALLOC)) && k) {
306                 k--;
307                 udelay(10);
308                 reg = hermes_read_regn(hw, EVSTAT);
309         }
310         
311         if (! hermes_present(hw)) {
312                 printk(KERN_WARNING "hermes @ %p: "
313                        "Card removed waiting for frame allocation.\n",
314                        hw->iobase);
315                 return -ENODEV;
316         }
317                 
318         if (! (reg & HERMES_EV_ALLOC)) {
319                 printk(KERN_ERR "hermes @ %p: "
320                        "Timeout waiting for frame allocation\n",
321                        hw->iobase);
322                 return -ETIMEDOUT;
323         }
324
325         *fid = hermes_read_regn(hw, ALLOCFID);
326         hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
327         
328         return 0;
329 }
330
331
332 /* Set up a BAP to read a particular chunk of data from card's internal buffer.
333  *
334  * Returns: < 0 on internal failure (errno), 0 on success, >0 on error
335  * from firmware
336  *
337  * Callable from any context */
338 static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
339 {
340         int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
341         int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
342         int k;
343         u16 reg;
344
345         /* Paranoia.. */
346         if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) )
347                 return -EINVAL;
348
349         k = HERMES_BAP_BUSY_TIMEOUT;
350         reg = hermes_read_reg(hw, oreg);
351         while ((reg & HERMES_OFFSET_BUSY) && k) {
352                 k--;
353                 udelay(1);
354                 reg = hermes_read_reg(hw, oreg);
355         }
356
357 #ifdef HERMES_DEBUG_BUFFER
358         hw->profile[HERMES_BAP_BUSY_TIMEOUT - k]++;
359
360         if (k < HERMES_BAP_BUSY_TIMEOUT) {
361                 struct hermes_debug_entry *e = 
362                         &hw->dbuf[(hw->dbufp++) % HERMES_DEBUG_BUFSIZE];
363                 e->bap = bap;
364                 e->id = id;
365                 e->offset = offset;
366                 e->cycles = HERMES_BAP_BUSY_TIMEOUT - k;
367         }
368 #endif
369
370         if (reg & HERMES_OFFSET_BUSY)
371                 return -ETIMEDOUT;
372
373         /* Now we actually set up the transfer */
374         hermes_write_reg(hw, sreg, id);
375         hermes_write_reg(hw, oreg, offset);
376
377         /* Wait for the BAP to be ready */
378         k = HERMES_BAP_BUSY_TIMEOUT;
379         reg = hermes_read_reg(hw, oreg);
380         while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
381                 k--;
382                 udelay(1);
383                 reg = hermes_read_reg(hw, oreg);
384         }
385
386         if (reg != offset) {
387                 printk(KERN_ERR "hermes @ %p: BAP%d offset %s: "
388                        "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap,
389                        (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
390                        reg, id, offset);
391
392                 if (reg & HERMES_OFFSET_BUSY) {
393                         return -ETIMEDOUT;
394                 }
395
396                 return -EIO;            /* error or wrong offset */
397         }
398
399         return 0;
400 }
401
402 /* Read a block of data from the chip's buffer, via the
403  * BAP. Synchronization/serialization is the caller's problem.  len
404  * must be even.
405  *
406  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
407  */
408 int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len,
409                      u16 id, u16 offset)
410 {
411         int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
412         int err = 0;
413
414         if ( (len < 0) || (len % 2) )
415                 return -EINVAL;
416
417         err = hermes_bap_seek(hw, bap, id, offset);
418         if (err)
419                 goto out;
420
421         /* Actually do the transfer */
422         hermes_read_words(hw, dreg, buf, len/2);
423
424  out:
425         return err;
426 }
427
428 /* Write a block of data to the chip's buffer, via the
429  * BAP. Synchronization/serialization is the caller's problem. len
430  * must be even.
431  *
432  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
433  */
434 int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len,
435                       u16 id, u16 offset)
436 {
437         int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
438         int err = 0;
439
440         if ( (len < 0) || (len % 2) )
441                 return -EINVAL;
442
443         err = hermes_bap_seek(hw, bap, id, offset);
444         if (err)
445                 goto out;
446         
447         /* Actually do the transfer */
448         hermes_write_words(hw, dreg, buf, len/2);
449
450  out:   
451         return err;
452 }
453
454 /* Read a Length-Type-Value record from the card.
455  *
456  * If length is NULL, we ignore the length read from the card, and
457  * read the entire buffer regardless. This is useful because some of
458  * the configuration records appear to have incorrect lengths in
459  * practice.
460  *
461  * Callable from user or bh context.  */
462 int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
463                     u16 *length, void *buf)
464 {
465         int err = 0;
466         int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
467         u16 rlength, rtype;
468         unsigned nwords;
469
470         if ( (bufsize < 0) || (bufsize % 2) )
471                 return -EINVAL;
472
473         err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
474         if (err)
475                 return err;
476
477         err = hermes_bap_seek(hw, bap, rid, 0);
478         if (err)
479                 return err;
480
481         rlength = hermes_read_reg(hw, dreg);
482
483         if (! rlength)
484                 return -ENODATA;
485
486         rtype = hermes_read_reg(hw, dreg);
487
488         if (length)
489                 *length = rlength;
490
491         if (rtype != rid)
492                 printk(KERN_WARNING "hermes @ %p: %s(): "
493                        "rid (0x%04x) does not match type (0x%04x)\n",
494                        hw->iobase, __FUNCTION__, rid, rtype);
495         if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
496                 printk(KERN_WARNING "hermes @ %p: "
497                        "Truncating LTV record from %d to %d bytes. "
498                        "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
499                        HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
500
501         nwords = min((unsigned)rlength - 1, bufsize / 2);
502         hermes_read_words(hw, dreg, buf, nwords);
503
504         return 0;
505 }
506
507 int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, 
508                      u16 length, const void *value)
509 {
510         int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
511         int err = 0;
512         unsigned count;
513
514         if (length == 0)
515                 return -EINVAL;
516
517         err = hermes_bap_seek(hw, bap, rid, 0);
518         if (err)
519                 return err;
520
521         hermes_write_reg(hw, dreg, length);
522         hermes_write_reg(hw, dreg, rid);
523
524         count = length - 1;
525
526         hermes_write_words(hw, dreg, value, count);
527
528         err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
529                                 rid, NULL);
530
531         return err;
532 }
533
534 EXPORT_SYMBOL(hermes_struct_init);
535 EXPORT_SYMBOL(hermes_init);
536 EXPORT_SYMBOL(hermes_docmd_wait);
537 EXPORT_SYMBOL(hermes_allocate);
538
539 EXPORT_SYMBOL(hermes_bap_pread);
540 EXPORT_SYMBOL(hermes_bap_pwrite);
541 EXPORT_SYMBOL(hermes_read_ltv);
542 EXPORT_SYMBOL(hermes_write_ltv);
543
544 static int __init init_hermes(void)
545 {
546         return 0;
547 }
548
549 static void __exit exit_hermes(void)
550 {
551 }
552
553 module_init(init_hermes);
554 module_exit(exit_hermes);