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