Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.14 554 lines 14 kB view raw
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 56MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller"); 57MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>" 58 " & David Gibson <hermes@gibson.dropbear.id.au>"); 59MODULE_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*/ 98static 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 126void 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 139int 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. */ 225int 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 289int 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 */ 338static 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 */ 408int 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 */ 434int 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. */ 462int 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 507int 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 534EXPORT_SYMBOL(hermes_struct_init); 535EXPORT_SYMBOL(hermes_init); 536EXPORT_SYMBOL(hermes_docmd_wait); 537EXPORT_SYMBOL(hermes_allocate); 538 539EXPORT_SYMBOL(hermes_bap_pread); 540EXPORT_SYMBOL(hermes_bap_pwrite); 541EXPORT_SYMBOL(hermes_read_ltv); 542EXPORT_SYMBOL(hermes_write_ltv); 543 544static int __init init_hermes(void) 545{ 546 return 0; 547} 548 549static void __exit exit_hermes(void) 550{ 551} 552 553module_init(init_hermes); 554module_exit(exit_hermes);