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 <hermes@gibson.dropbear.id.au>
17  * Copyright (C) 2001, David Gibson, IBM <hermes@gibson.dropbear.id.au>
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 <asm/errno.h>
52 
53 #include "hermes.h"
54 
55 static char version[] __initdata = "hermes.c: 4 Dec 2002 David Gibson <hermes@gibson.dropbear.id.au>";
56 MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
57 MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
58 #ifdef MODULE_LICENSE
59 MODULE_LICENSE("Dual MPL/GPL");
60 #endif
61 
62 /* These are maximum timeouts. Most often, card wil react much faster */
63 #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
64 #define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
65 #define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
66 #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
67 
68 /*
69  * Debugging helpers
70  */
71 
72 #define IO_TYPE(hw)	((hw)->io_space ? "IO " : "MEM ")
73 #define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %s0x%x: " , IO_TYPE(hw), hw->iobase); \
74 			printk(stuff);} while (0)
75 
76 #undef HERMES_DEBUG
77 #ifdef HERMES_DEBUG
78 #include <stdarg.h>
79 
80 #define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff)
81 
82 #else /* ! HERMES_DEBUG */
83 
84 #define DEBUG(lvl, stuff...) do { } while (0)
85 
86 #endif /* ! HERMES_DEBUG */
87 
88 
89 /*
90  * Internal functions
91  */
92 
93 /* Issue a command to the chip. Waiting for it to complete is the caller's
94    problem.
95 
96    Returns -EBUSY if the command register is busy, 0 on success.
97 
98    Callable from any context.
99 */
hermes_issue_cmd(hermes_t * hw,u16 cmd,u16 param0)100 static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0)
101 {
102 	int k = CMD_BUSY_TIMEOUT;
103 	u16 reg;
104 
105 	/* First wait for the command register to unbusy */
106 	reg = hermes_read_regn(hw, CMD);
107 	while ( (reg & HERMES_CMD_BUSY) && k ) {
108 		k--;
109 		udelay(1);
110 		reg = hermes_read_regn(hw, CMD);
111 	}
112 	if (reg & HERMES_CMD_BUSY) {
113 		return -EBUSY;
114 	}
115 
116 	hermes_write_regn(hw, PARAM2, 0);
117 	hermes_write_regn(hw, PARAM1, 0);
118 	hermes_write_regn(hw, PARAM0, param0);
119 	hermes_write_regn(hw, CMD, cmd);
120 
121 	return 0;
122 }
123 
124 /*
125  * Function definitions
126  */
127 
hermes_struct_init(hermes_t * hw,ulong address,int io_space,int reg_spacing)128 void hermes_struct_init(hermes_t *hw, ulong address,
129 			int io_space, int reg_spacing)
130 {
131 	hw->iobase = address;
132 	hw->io_space = io_space;
133 	hw->reg_spacing = reg_spacing;
134 	hw->inten = 0x0;
135 
136 #ifdef HERMES_DEBUG_BUFFER
137 	hw->dbufp = 0;
138 	memset(&hw->dbuf, 0xff, sizeof(hw->dbuf));
139 	memset(&hw->profile, 0, sizeof(hw->profile));
140 #endif
141 }
142 
hermes_init(hermes_t * hw)143 int hermes_init(hermes_t *hw)
144 {
145 	u16 status, reg;
146 	int err = 0;
147 	int k;
148 
149 	/* We don't want to be interrupted while resetting the chipset */
150 	hw->inten = 0x0;
151 	hermes_write_regn(hw, INTEN, 0);
152 	hermes_write_regn(hw, EVACK, 0xffff);
153 
154 	/* Normally it's a "can't happen" for the command register to
155            be busy when we go to issue a command because we are
156            serializing all commands.  However we want to have some
157            chance of resetting the card even if it gets into a stupid
158            state, so we actually wait to see if the command register
159            will unbusy itself here. */
160 	k = CMD_BUSY_TIMEOUT;
161 	reg = hermes_read_regn(hw, CMD);
162 	while (k && (reg & HERMES_CMD_BUSY)) {
163 		if (reg == 0xffff) /* Special case - the card has probably been removed,
164 				      so don't wait for the timeout */
165 			return -ENODEV;
166 
167 		k--;
168 		udelay(1);
169 		reg = hermes_read_regn(hw, CMD);
170 	}
171 
172 	/* No need to explicitly handle the timeout - if we've timed
173 	   out hermes_issue_cmd() will probably return -EBUSY below */
174 
175 	/* According to the documentation, EVSTAT may contain
176 	   obsolete event occurrence information.  We have to acknowledge
177 	   it by writing EVACK. */
178 	reg = hermes_read_regn(hw, EVSTAT);
179 	hermes_write_regn(hw, EVACK, reg);
180 
181 	/* We don't use hermes_docmd_wait here, because the reset wipes
182 	   the magic constant in SWSUPPORT0 away, and it gets confused */
183 	err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0);
184 	if (err)
185 		return err;
186 
187 	reg = hermes_read_regn(hw, EVSTAT);
188 	k = CMD_INIT_TIMEOUT;
189 	while ( (! (reg & HERMES_EV_CMD)) && k) {
190 		k--;
191 		udelay(10);
192 		reg = hermes_read_regn(hw, EVSTAT);
193 	}
194 
195 	hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
196 
197 	if (! hermes_present(hw)) {
198 		DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
199 		       hw->iobase);
200 		err = -ENODEV;
201 		goto out;
202 	}
203 
204 	if (! (reg & HERMES_EV_CMD)) {
205 		printk(KERN_ERR "hermes @ %s0x%lx: "
206 		       "Timeout waiting for card to reset (reg=0x%04x)!\n",
207 		       IO_TYPE(hw), hw->iobase, reg);
208 		err = -ETIMEDOUT;
209 		goto out;
210 	}
211 
212 	status = hermes_read_regn(hw, STATUS);
213 
214 	hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
215 
216 	if (status & HERMES_STATUS_RESULT)
217 		err = -EIO;
218 
219  out:
220 	return err;
221 }
222 
223 /* Issue a command to the chip, and (busy!) wait for it to
224  * complete.
225  *
226  * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
227  *
228  * Callable from any context, but locking is your problem. */
hermes_docmd_wait(hermes_t * hw,u16 cmd,u16 parm0,hermes_response_t * resp)229 int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp)
230 {
231 	int err;
232 	int k;
233 	u16 reg;
234 	u16 status;
235 
236 	err = hermes_issue_cmd(hw, cmd, parm0);
237 	if (err) {
238 		if (! hermes_present(hw)) {
239 			printk(KERN_WARNING "hermes @ %s0x%lx: "
240 			       "Card removed while issuing command.\n",
241 			       IO_TYPE(hw), hw->iobase);
242 			err = -ENODEV;
243 		} else
244 			printk(KERN_ERR "hermes @ %s0x%lx: Error %d issuing command.\n",
245 			       IO_TYPE(hw), hw->iobase, err);
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 @ %s0x%lx: "
259 		       "Card removed while waiting for command completion.\n",
260 		       IO_TYPE(hw), hw->iobase);
261 		err = -ENODEV;
262 		goto out;
263 	}
264 
265 	if (! (reg & HERMES_EV_CMD)) {
266 		printk(KERN_ERR "hermes @ %s0x%lx: "
267 		       "Timeout waiting for command completion.\n",
268 		       IO_TYPE(hw), hw->iobase);
269 		err = -ETIMEDOUT;
270 		goto out;
271 	}
272 
273 	status = hermes_read_regn(hw, STATUS);
274 	if (resp) {
275 		resp->status = status;
276 		resp->resp0 = hermes_read_regn(hw, RESP0);
277 		resp->resp1 = hermes_read_regn(hw, RESP1);
278 		resp->resp2 = hermes_read_regn(hw, RESP2);
279 	}
280 
281 	hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
282 
283 	if (status & HERMES_STATUS_RESULT)
284 		err = -EIO;
285 
286  out:
287 	return err;
288 }
289 
hermes_allocate(hermes_t * hw,u16 size,u16 * fid)290 int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
291 {
292 	int err = 0;
293 	int k;
294 	u16 reg;
295 
296 	if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) )
297 		return -EINVAL;
298 
299 	err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
300 	if (err) {
301 		return err;
302 	}
303 
304 	reg = hermes_read_regn(hw, EVSTAT);
305 	k = ALLOC_COMPL_TIMEOUT;
306 	while ( (! (reg & HERMES_EV_ALLOC)) && k) {
307 		k--;
308 		udelay(10);
309 		reg = hermes_read_regn(hw, EVSTAT);
310 	}
311 
312 	if (! hermes_present(hw)) {
313 		printk(KERN_WARNING "hermes @ %s0x%lx: "
314 		       "Card removed waiting for frame allocation.\n",
315 		       IO_TYPE(hw), hw->iobase);
316 		return -ENODEV;
317 	}
318 
319 	if (! (reg & HERMES_EV_ALLOC)) {
320 		printk(KERN_ERR "hermes @ %s0x%lx: "
321 		       "Timeout waiting for frame allocation\n",
322 		       IO_TYPE(hw), hw->iobase);
323 		return -ETIMEDOUT;
324 	}
325 
326 	*fid = hermes_read_regn(hw, ALLOCFID);
327 	hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
328 
329 	return 0;
330 }
331 
332 
333 /* Set up a BAP to read a particular chunk of data from card's internal buffer.
334  *
335  * Returns: < 0 on internal failure (errno), 0 on success, >0 on error
336  * from firmware
337  *
338  * Callable from any context */
hermes_bap_seek(hermes_t * hw,int bap,u16 id,u16 offset)339 static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
340 {
341 	int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
342 	int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
343 	int k;
344 	u16 reg;
345 
346 	/* Paranoia.. */
347 	if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) )
348 		return -EINVAL;
349 
350 	k = HERMES_BAP_BUSY_TIMEOUT;
351 	reg = hermes_read_reg(hw, oreg);
352 	while ((reg & HERMES_OFFSET_BUSY) && k) {
353 		k--;
354 		udelay(1);
355 		reg = hermes_read_reg(hw, oreg);
356 	}
357 
358 #ifdef HERMES_DEBUG_BUFFER
359 	hw->profile[HERMES_BAP_BUSY_TIMEOUT - k]++;
360 
361 	if (k < HERMES_BAP_BUSY_TIMEOUT) {
362 		struct hermes_debug_entry *e =
363 			&hw->dbuf[(hw->dbufp++) % HERMES_DEBUG_BUFSIZE];
364 		e->bap = bap;
365 		e->id = id;
366 		e->offset = offset;
367 		e->cycles = HERMES_BAP_BUSY_TIMEOUT - k;
368 	}
369 #endif
370 
371 	if (reg & HERMES_OFFSET_BUSY)
372 		return -ETIMEDOUT;
373 
374 	/* Now we actually set up the transfer */
375 	hermes_write_reg(hw, sreg, id);
376 	hermes_write_reg(hw, oreg, offset);
377 
378 	/* Wait for the BAP to be ready */
379 	k = HERMES_BAP_BUSY_TIMEOUT;
380 	reg = hermes_read_reg(hw, oreg);
381 	while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
382 		k--;
383 		udelay(1);
384 		reg = hermes_read_reg(hw, oreg);
385 	}
386 
387 	if (reg & HERMES_OFFSET_BUSY) {
388 		return -ETIMEDOUT;
389 	}
390 
391 	if (reg & HERMES_OFFSET_ERR) {
392 		return -EIO;
393 	}
394 
395 
396 	return 0;
397 }
398 
399 /* Read a block of data from the chip's buffer, via the
400  * BAP. Synchronization/serialization is the caller's problem.  len
401  * must be even.
402  *
403  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
404  */
hermes_bap_pread(hermes_t * hw,int bap,void * buf,unsigned len,u16 id,u16 offset)405 int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len,
406 		     u16 id, u16 offset)
407 {
408 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
409 	int err = 0;
410 
411 	if ( (len < 0) || (len % 2) )
412 		return -EINVAL;
413 
414 	err = hermes_bap_seek(hw, bap, id, offset);
415 	if (err)
416 		goto out;
417 
418 	/* Actually do the transfer */
419 	hermes_read_words(hw, dreg, buf, len/2);
420 
421  out:
422 	return err;
423 }
424 
425 /* Write a block of data to the chip's buffer, via the
426  * BAP. Synchronization/serialization is the caller's problem. len
427  * must be even.
428  *
429  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
430  */
hermes_bap_pwrite(hermes_t * hw,int bap,const void * buf,unsigned len,u16 id,u16 offset)431 int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len,
432 		      u16 id, u16 offset)
433 {
434 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
435 	int err = 0;
436 
437 	if ( (len < 0) || (len % 2) )
438 		return -EINVAL;
439 
440 	err = hermes_bap_seek(hw, bap, id, offset);
441 	if (err)
442 		goto out;
443 
444 	/* Actually do the transfer */
445 	hermes_write_words(hw, dreg, buf, len/2);
446 
447  out:
448 	return err;
449 }
450 
451 /* Write a block of data to the chip's buffer with padding if
452  * neccessary, via the BAP. Synchronization/serialization is the
453  * caller's problem. len must be even.
454  *
455  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
456  */
hermes_bap_pwrite_pad(hermes_t * hw,int bap,const void * buf,unsigned data_len,unsigned len,u16 id,u16 offset)457 int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, unsigned data_len, unsigned len,
458 		      u16 id, u16 offset)
459 {
460 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
461 	int err = 0;
462 
463 	if (len < 0 || len % 2 || data_len > len)
464 		return -EINVAL;
465 
466 	err = hermes_bap_seek(hw, bap, id, offset);
467 	if (err)
468 		goto out;
469 
470 	/* Transfer all the complete words of data */
471 	hermes_write_words(hw, dreg, buf, data_len/2);
472 	/* If there is an odd byte left over pad and transfer it */
473 	if (data_len & 1) {
474 		u8 end[2];
475 		end[1] = 0;
476 		end[0] = ((unsigned char *)buf)[data_len - 1];
477 		hermes_write_words(hw, dreg, end, 1);
478 		data_len ++;
479 	}
480 	/* Now send zeros for the padding */
481 	if (data_len < len)
482 		hermes_clear_words(hw, dreg, (len - data_len) / 2);
483 	/* Complete */
484  out:
485 	return err;
486 }
487 
488 /* Read a Length-Type-Value record from the card.
489  *
490  * If length is NULL, we ignore the length read from the card, and
491  * read the entire buffer regardless. This is useful because some of
492  * the configuration records appear to have incorrect lengths in
493  * practice.
494  *
495  * Callable from user or bh context.  */
hermes_read_ltv(hermes_t * hw,int bap,u16 rid,unsigned bufsize,u16 * length,void * buf)496 int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
497 		    u16 *length, void *buf)
498 {
499 	int err = 0;
500 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
501 	u16 rlength, rtype;
502 	unsigned nwords;
503 
504 	if ( (bufsize < 0) || (bufsize % 2) )
505 		return -EINVAL;
506 
507 	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
508 	if (err)
509 		goto out;
510 
511 	err = hermes_bap_seek(hw, bap, rid, 0);
512 	if (err)
513 		goto out;
514 
515 	rlength = hermes_read_reg(hw, dreg);
516 	rtype = hermes_read_reg(hw, dreg);
517 
518 	if (length)
519 		*length = rlength;
520 
521 	if (rtype != rid)
522 		printk(KERN_WARNING "hermes @ %s0x%lx: "
523 		       "hermes_read_ltv(): rid  (0x%04x) does not match type (0x%04x)\n",
524 		       IO_TYPE(hw), hw->iobase, rid, rtype);
525 	if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
526 		printk(KERN_WARNING "hermes @ %s0x%lx: "
527 		       "Truncating LTV record from %d to %d bytes. "
528 		       "(rid=0x%04x, len=0x%04x)\n",
529 		       IO_TYPE(hw), hw->iobase,
530 		       HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
531 
532 	nwords = min((unsigned)rlength - 1, bufsize / 2);
533 	hermes_read_words(hw, dreg, buf, nwords);
534 
535  out:
536 	return err;
537 }
538 
hermes_write_ltv(hermes_t * hw,int bap,u16 rid,u16 length,const void * value)539 int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
540 		     u16 length, const void *value)
541 {
542 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
543 	int err = 0;
544 	unsigned count;
545 
546 	if (length == 0)
547 		return -EINVAL;
548 
549 	err = hermes_bap_seek(hw, bap, rid, 0);
550 	if (err)
551 		goto out;
552 
553 	hermes_write_reg(hw, dreg, length);
554 	hermes_write_reg(hw, dreg, rid);
555 
556 	count = length - 1;
557 
558 	hermes_write_words(hw, dreg, value, count);
559 
560 	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
561 				rid, NULL);
562 
563  out:
564 	return err;
565 }
566 
567 EXPORT_SYMBOL(hermes_struct_init);
568 EXPORT_SYMBOL(hermes_init);
569 EXPORT_SYMBOL(hermes_docmd_wait);
570 EXPORT_SYMBOL(hermes_allocate);
571 
572 EXPORT_SYMBOL(hermes_bap_pread);
573 EXPORT_SYMBOL(hermes_bap_pwrite);
574 EXPORT_SYMBOL(hermes_bap_pwrite_pad);
575 EXPORT_SYMBOL(hermes_read_ltv);
576 EXPORT_SYMBOL(hermes_write_ltv);
577 
init_hermes(void)578 static int __init init_hermes(void)
579 {
580 	printk(KERN_DEBUG "%s\n", version);
581 
582 	return 0;
583 }
584 
exit_hermes(void)585 static void __exit exit_hermes(void)
586 {
587 }
588 
589 module_init(init_hermes);
590 module_exit(exit_hermes);
591