/drivers/net/wireless/hostap/hostap_hw.c
https://bitbucket.org/wisechild/galaxy-nexus · C · 3424 lines · 2481 code · 579 blank · 364 comment · 486 complexity · bb1d47b2964c61ccab6534c0a8327f2c MD5 · raw file
Large files are truncated click here to view the full file
- /*
- * Host AP (software wireless LAN access point) driver for
- * Intersil Prism2/2.5/3.
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <j@w1.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation. See README and COPYING for
- * more details.
- *
- * FIX:
- * - there is currently no way of associating TX packets to correct wds device
- * when TX Exc/OK event occurs, so all tx_packets and some
- * tx_errors/tx_dropped are added to the main netdevice; using sw_support
- * field in txdesc might be used to fix this (using Alloc event to increment
- * tx_packets would need some further info in txfid table)
- *
- * Buffer Access Path (BAP) usage:
- * Prism2 cards have two separate BAPs for accessing the card memory. These
- * should allow concurrent access to two different frames and the driver
- * previously used BAP0 for sending data and BAP1 for receiving data.
- * However, there seems to be number of issues with concurrent access and at
- * least one know hardware bug in using BAP0 and BAP1 concurrently with PCI
- * Prism2.5. Therefore, the driver now only uses BAP0 for moving data between
- * host and card memories. BAP0 accesses are protected with local->baplock
- * (spin_lock_bh) to prevent concurrent use.
- */
- #include <asm/delay.h>
- #include <asm/uaccess.h>
- #include <linux/slab.h>
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/proc_fs.h>
- #include <linux/if_arp.h>
- #include <linux/delay.h>
- #include <linux/random.h>
- #include <linux/wait.h>
- #include <linux/sched.h>
- #include <linux/rtnetlink.h>
- #include <linux/wireless.h>
- #include <net/iw_handler.h>
- #include <net/lib80211.h>
- #include <asm/irq.h>
- #include "hostap_80211.h"
- #include "hostap.h"
- #include "hostap_ap.h"
- /* #define final_version */
- static int mtu = 1500;
- module_param(mtu, int, 0444);
- MODULE_PARM_DESC(mtu, "Maximum transfer unit");
- static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS };
- module_param_array(channel, int, NULL, 0444);
- MODULE_PARM_DESC(channel, "Initial channel");
- static char essid[33] = "test";
- module_param_string(essid, essid, sizeof(essid), 0444);
- MODULE_PARM_DESC(essid, "Host AP's ESSID");
- static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS };
- module_param_array(iw_mode, int, NULL, 0444);
- MODULE_PARM_DESC(iw_mode, "Initial operation mode");
- static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS };
- module_param_array(beacon_int, int, NULL, 0444);
- MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)");
- static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS };
- module_param_array(dtim_period, int, NULL, 0444);
- MODULE_PARM_DESC(dtim_period, "DTIM period");
- static char dev_template[16] = "wlan%d";
- module_param_string(dev_template, dev_template, sizeof(dev_template), 0444);
- MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: "
- "wlan%d)");
- #ifdef final_version
- #define EXTRA_EVENTS_WTERR 0
- #else
- /* check WTERR events (Wait Time-out) in development versions */
- #define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR
- #endif
- /* Events that will be using BAP0 */
- #define HFA384X_BAP0_EVENTS \
- (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX)
- /* event mask, i.e., events that will result in an interrupt */
- #define HFA384X_EVENT_MASK \
- (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \
- HFA384X_EV_CMD | HFA384X_EV_TICK | \
- EXTRA_EVENTS_WTERR)
- /* Default TX control flags: use 802.11 headers and request interrupt for
- * failed transmits. Frames that request ACK callback, will add
- * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy.
- */
- #define HFA384X_TX_CTRL_FLAGS \
- (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX)
- /* ca. 1 usec */
- #define HFA384X_CMD_BUSY_TIMEOUT 5000
- #define HFA384X_BAP_BUSY_TIMEOUT 50000
- /* ca. 10 usec */
- #define HFA384X_CMD_COMPL_TIMEOUT 20000
- #define HFA384X_DL_COMPL_TIMEOUT 1000000
- /* Wait times for initialization; yield to other processes to avoid busy
- * waiting for long time. */
- #define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */
- #define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */
- static void prism2_hw_reset(struct net_device *dev);
- static void prism2_check_sta_fw_version(local_info_t *local);
- #ifdef PRISM2_DOWNLOAD_SUPPORT
- /* hostap_download.c */
- static int prism2_download_aux_dump(struct net_device *dev,
- unsigned int addr, int len, u8 *buf);
- static u8 * prism2_read_pda(struct net_device *dev);
- static int prism2_download(local_info_t *local,
- struct prism2_download_param *param);
- static void prism2_download_free_data(struct prism2_download_data *dl);
- static int prism2_download_volatile(local_info_t *local,
- struct prism2_download_data *param);
- static int prism2_download_genesis(local_info_t *local,
- struct prism2_download_data *param);
- static int prism2_get_ram_size(local_info_t *local);
- #endif /* PRISM2_DOWNLOAD_SUPPORT */
- #ifndef final_version
- /* magic value written to SWSUPPORT0 reg. for detecting whether card is still
- * present */
- #define HFA384X_MAGIC 0x8A32
- #endif
- static u16 hfa384x_read_reg(struct net_device *dev, u16 reg)
- {
- return HFA384X_INW(reg);
- }
- static void hfa384x_read_regs(struct net_device *dev,
- struct hfa384x_regs *regs)
- {
- regs->cmd = HFA384X_INW(HFA384X_CMD_OFF);
- regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF);
- regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF);
- regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF);
- regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF);
- }
- /**
- * __hostap_cmd_queue_free - Free Prism2 command queue entry (private)
- * @local: pointer to private Host AP driver data
- * @entry: Prism2 command queue entry to be freed
- * @del_req: request the entry to be removed
- *
- * Internal helper function for freeing Prism2 command queue entries.
- * Caller must have acquired local->cmdlock before calling this function.
- */
- static inline void __hostap_cmd_queue_free(local_info_t *local,
- struct hostap_cmd_queue *entry,
- int del_req)
- {
- if (del_req) {
- entry->del_req = 1;
- if (!list_empty(&entry->list)) {
- list_del_init(&entry->list);
- local->cmd_queue_len--;
- }
- }
- if (atomic_dec_and_test(&entry->usecnt) && entry->del_req)
- kfree(entry);
- }
- /**
- * hostap_cmd_queue_free - Free Prism2 command queue entry
- * @local: pointer to private Host AP driver data
- * @entry: Prism2 command queue entry to be freed
- * @del_req: request the entry to be removed
- *
- * Free a Prism2 command queue entry.
- */
- static inline void hostap_cmd_queue_free(local_info_t *local,
- struct hostap_cmd_queue *entry,
- int del_req)
- {
- unsigned long flags;
- spin_lock_irqsave(&local->cmdlock, flags);
- __hostap_cmd_queue_free(local, entry, del_req);
- spin_unlock_irqrestore(&local->cmdlock, flags);
- }
- /**
- * prism2_clear_cmd_queue - Free all pending Prism2 command queue entries
- * @local: pointer to private Host AP driver data
- */
- static void prism2_clear_cmd_queue(local_info_t *local)
- {
- struct list_head *ptr, *n;
- unsigned long flags;
- struct hostap_cmd_queue *entry;
- spin_lock_irqsave(&local->cmdlock, flags);
- list_for_each_safe(ptr, n, &local->cmd_queue) {
- entry = list_entry(ptr, struct hostap_cmd_queue, list);
- atomic_inc(&entry->usecnt);
- printk(KERN_DEBUG "%s: removed pending cmd_queue entry "
- "(type=%d, cmd=0x%04x, param0=0x%04x)\n",
- local->dev->name, entry->type, entry->cmd,
- entry->param0);
- __hostap_cmd_queue_free(local, entry, 1);
- }
- if (local->cmd_queue_len) {
- /* This should not happen; print debug message and clear
- * queue length. */
- printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after "
- "flush\n", local->dev->name, local->cmd_queue_len);
- local->cmd_queue_len = 0;
- }
- spin_unlock_irqrestore(&local->cmdlock, flags);
- }
- /**
- * hfa384x_cmd_issue - Issue a Prism2 command to the hardware
- * @dev: pointer to net_device
- * @entry: Prism2 command queue entry to be issued
- */
- static int hfa384x_cmd_issue(struct net_device *dev,
- struct hostap_cmd_queue *entry)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- int tries;
- u16 reg;
- unsigned long flags;
- iface = netdev_priv(dev);
- local = iface->local;
- if (local->func->card_present && !local->func->card_present(local))
- return -ENODEV;
- if (entry->issued) {
- printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n",
- dev->name, entry);
- }
- /* wait until busy bit is clear; this should always be clear since the
- * commands are serialized */
- tries = HFA384X_CMD_BUSY_TIMEOUT;
- while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
- tries--;
- udelay(1);
- }
- #ifndef final_version
- if (tries != HFA384X_CMD_BUSY_TIMEOUT) {
- prism2_io_debug_error(dev, 1);
- printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy "
- "for %d usec\n", dev->name,
- HFA384X_CMD_BUSY_TIMEOUT - tries);
- }
- #endif
- if (tries == 0) {
- reg = HFA384X_INW(HFA384X_CMD_OFF);
- prism2_io_debug_error(dev, 2);
- printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - "
- "reg=0x%04x\n", dev->name, reg);
- return -ETIMEDOUT;
- }
- /* write command */
- spin_lock_irqsave(&local->cmdlock, flags);
- HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF);
- HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF);
- entry->issued = 1;
- spin_unlock_irqrestore(&local->cmdlock, flags);
- return 0;
- }
- /**
- * hfa384x_cmd - Issue a Prism2 command and wait (sleep) for completion
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- * @param1: value for Param1 register (pointer; %NULL if not used)
- * @resp0: pointer for Resp0 data or %NULL if Resp0 is not needed
- *
- * Issue given command (possibly after waiting in command queue) and sleep
- * until the command is completed (or timed out or interrupted). This can be
- * called only from user process context.
- */
- static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0,
- u16 *param1, u16 *resp0)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- int err, res, issue, issued = 0;
- unsigned long flags;
- struct hostap_cmd_queue *entry;
- DECLARE_WAITQUEUE(wait, current);
- iface = netdev_priv(dev);
- local = iface->local;
- if (in_interrupt()) {
- printk(KERN_DEBUG "%s: hfa384x_cmd called from interrupt "
- "context\n", dev->name);
- return -1;
- }
- if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) {
- printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n",
- dev->name);
- return -1;
- }
- if (signal_pending(current))
- return -EINTR;
- entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
- if (entry == NULL) {
- printk(KERN_DEBUG "%s: hfa384x_cmd - kmalloc failed\n",
- dev->name);
- return -ENOMEM;
- }
- atomic_set(&entry->usecnt, 1);
- entry->type = CMD_SLEEP;
- entry->cmd = cmd;
- entry->param0 = param0;
- if (param1)
- entry->param1 = *param1;
- init_waitqueue_head(&entry->compl);
- /* prepare to wait for command completion event, but do not sleep yet
- */
- add_wait_queue(&entry->compl, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&local->cmdlock, flags);
- issue = list_empty(&local->cmd_queue);
- if (issue)
- entry->issuing = 1;
- list_add_tail(&entry->list, &local->cmd_queue);
- local->cmd_queue_len++;
- spin_unlock_irqrestore(&local->cmdlock, flags);
- err = 0;
- if (!issue)
- goto wait_completion;
- if (signal_pending(current))
- err = -EINTR;
- if (!err) {
- if (hfa384x_cmd_issue(dev, entry))
- err = -ETIMEDOUT;
- else
- issued = 1;
- }
- wait_completion:
- if (!err && entry->type != CMD_COMPLETED) {
- /* sleep until command is completed or timed out */
- res = schedule_timeout(2 * HZ);
- } else
- res = -1;
- if (!err && signal_pending(current))
- err = -EINTR;
- if (err && issued) {
- /* the command was issued, so a CmdCompl event should occur
- * soon; however, there's a pending signal and
- * schedule_timeout() would be interrupted; wait a short period
- * of time to avoid removing entry from the list before
- * CmdCompl event */
- udelay(300);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&entry->compl, &wait);
- /* If entry->list is still in the list, it must be removed
- * first and in this case prism2_cmd_ev() does not yet have
- * local reference to it, and the data can be kfree()'d
- * here. If the command completion event is still generated,
- * it will be assigned to next (possibly) pending command, but
- * the driver will reset the card anyway due to timeout
- *
- * If the entry is not in the list prism2_cmd_ev() has a local
- * reference to it, but keeps cmdlock as long as the data is
- * needed, so the data can be kfree()'d here. */
- /* FIX: if the entry->list is in the list, it has not been completed
- * yet, so removing it here is somewhat wrong.. this could cause
- * references to freed memory and next list_del() causing NULL pointer
- * dereference.. it would probably be better to leave the entry in the
- * list and the list should be emptied during hw reset */
- spin_lock_irqsave(&local->cmdlock, flags);
- if (!list_empty(&entry->list)) {
- printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? "
- "(entry=%p, type=%d, res=%d)\n", dev->name, entry,
- entry->type, res);
- list_del_init(&entry->list);
- local->cmd_queue_len--;
- }
- spin_unlock_irqrestore(&local->cmdlock, flags);
- if (err) {
- printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n",
- dev->name, err);
- res = err;
- goto done;
- }
- if (entry->type != CMD_COMPLETED) {
- u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF);
- printk(KERN_DEBUG "%s: hfa384x_cmd: command was not "
- "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, "
- "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name,
- res, entry, entry->type, entry->cmd, entry->param0, reg,
- HFA384X_INW(HFA384X_INTEN_OFF));
- if (reg & HFA384X_EV_CMD) {
- /* Command completion event is pending, but the
- * interrupt was not delivered - probably an issue
- * with pcmcia-cs configuration. */
- printk(KERN_WARNING "%s: interrupt delivery does not "
- "seem to work\n", dev->name);
- }
- prism2_io_debug_error(dev, 3);
- res = -ETIMEDOUT;
- goto done;
- }
- if (resp0 != NULL)
- *resp0 = entry->resp0;
- #ifndef final_version
- if (entry->res) {
- printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, "
- "resp0=0x%04x\n",
- dev->name, cmd, entry->res, entry->resp0);
- }
- #endif /* final_version */
- res = entry->res;
- done:
- hostap_cmd_queue_free(local, entry, 1);
- return res;
- }
- /**
- * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- * @callback: command completion callback function (%NULL = no callback)
- * @context: context data to be given to the callback function
- *
- * Issue given command (possibly after waiting in command queue) and use
- * callback function to indicate command completion. This can be called both
- * from user and interrupt context. The callback function will be called in
- * hardware IRQ context. It can be %NULL, when no function is called when
- * command is completed.
- */
- static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0,
- void (*callback)(struct net_device *dev,
- long context, u16 resp0,
- u16 status),
- long context)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- int issue, ret;
- unsigned long flags;
- struct hostap_cmd_queue *entry;
- iface = netdev_priv(dev);
- local = iface->local;
- if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) {
- printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n",
- dev->name);
- return -1;
- }
- entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
- if (entry == NULL) {
- printk(KERN_DEBUG "%s: hfa384x_cmd_callback - kmalloc "
- "failed\n", dev->name);
- return -ENOMEM;
- }
- atomic_set(&entry->usecnt, 1);
- entry->type = CMD_CALLBACK;
- entry->cmd = cmd;
- entry->param0 = param0;
- entry->callback = callback;
- entry->context = context;
- spin_lock_irqsave(&local->cmdlock, flags);
- issue = list_empty(&local->cmd_queue);
- if (issue)
- entry->issuing = 1;
- list_add_tail(&entry->list, &local->cmd_queue);
- local->cmd_queue_len++;
- spin_unlock_irqrestore(&local->cmdlock, flags);
- if (issue && hfa384x_cmd_issue(dev, entry))
- ret = -ETIMEDOUT;
- else
- ret = 0;
- hostap_cmd_queue_free(local, entry, ret);
- return ret;
- }
- /**
- * __hfa384x_cmd_no_wait - Issue a Prism2 command (private)
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- * @io_debug_num: I/O debug error number
- *
- * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait().
- */
- static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0,
- int io_debug_num)
- {
- int tries;
- u16 reg;
- /* wait until busy bit is clear; this should always be clear since the
- * commands are serialized */
- tries = HFA384X_CMD_BUSY_TIMEOUT;
- while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
- tries--;
- udelay(1);
- }
- if (tries == 0) {
- reg = HFA384X_INW(HFA384X_CMD_OFF);
- prism2_io_debug_error(dev, io_debug_num);
- printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - "
- "reg=0x%04x\n", dev->name, io_debug_num, reg);
- return -ETIMEDOUT;
- }
- /* write command */
- HFA384X_OUTW(param0, HFA384X_PARAM0_OFF);
- HFA384X_OUTW(cmd, HFA384X_CMD_OFF);
- return 0;
- }
- /**
- * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- */
- static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0)
- {
- int res, tries;
- u16 reg;
- res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4);
- if (res)
- return res;
- /* wait for command completion */
- if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD)
- tries = HFA384X_DL_COMPL_TIMEOUT;
- else
- tries = HFA384X_CMD_COMPL_TIMEOUT;
- while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) &&
- tries > 0) {
- tries--;
- udelay(10);
- }
- if (tries == 0) {
- reg = HFA384X_INW(HFA384X_EVSTAT_OFF);
- prism2_io_debug_error(dev, 5);
- printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - "
- "reg=0x%04x\n", dev->name, reg);
- return -ETIMEDOUT;
- }
- res = (HFA384X_INW(HFA384X_STATUS_OFF) &
- (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) |
- BIT(8))) >> 8;
- #ifndef final_version
- if (res) {
- printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n",
- dev->name, cmd, res);
- }
- #endif
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
- return res;
- }
- /**
- * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- */
- static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd,
- u16 param0)
- {
- return __hfa384x_cmd_no_wait(dev, cmd, param0, 6);
- }
- /**
- * prism2_cmd_ev - Prism2 command completion event handler
- * @dev: pointer to net_device
- *
- * Interrupt handler for command completion events. Called by the main
- * interrupt handler in hardware IRQ context. Read Resp0 and status registers
- * from the hardware and ACK the event. Depending on the issued command type
- * either wake up the sleeping process that is waiting for command completion
- * or call the callback function. Issue the next command, if one is pending.
- */
- static void prism2_cmd_ev(struct net_device *dev)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- struct hostap_cmd_queue *entry = NULL;
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock(&local->cmdlock);
- if (!list_empty(&local->cmd_queue)) {
- entry = list_entry(local->cmd_queue.next,
- struct hostap_cmd_queue, list);
- atomic_inc(&entry->usecnt);
- list_del_init(&entry->list);
- local->cmd_queue_len--;
- if (!entry->issued) {
- printk(KERN_DEBUG "%s: Command completion event, but "
- "cmd not issued\n", dev->name);
- __hostap_cmd_queue_free(local, entry, 1);
- entry = NULL;
- }
- }
- spin_unlock(&local->cmdlock);
- if (!entry) {
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
- printk(KERN_DEBUG "%s: Command completion event, but no "
- "pending commands\n", dev->name);
- return;
- }
- entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF);
- entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) &
- (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) |
- BIT(9) | BIT(8))) >> 8;
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
- /* TODO: rest of the CmdEv handling could be moved to tasklet */
- if (entry->type == CMD_SLEEP) {
- entry->type = CMD_COMPLETED;
- wake_up_interruptible(&entry->compl);
- } else if (entry->type == CMD_CALLBACK) {
- if (entry->callback)
- entry->callback(dev, entry->context, entry->resp0,
- entry->res);
- } else {
- printk(KERN_DEBUG "%s: Invalid command completion type %d\n",
- dev->name, entry->type);
- }
- hostap_cmd_queue_free(local, entry, 1);
- /* issue next command, if pending */
- entry = NULL;
- spin_lock(&local->cmdlock);
- if (!list_empty(&local->cmd_queue)) {
- entry = list_entry(local->cmd_queue.next,
- struct hostap_cmd_queue, list);
- if (entry->issuing) {
- /* hfa384x_cmd() has already started issuing this
- * command, so do not start here */
- entry = NULL;
- }
- if (entry)
- atomic_inc(&entry->usecnt);
- }
- spin_unlock(&local->cmdlock);
- if (entry) {
- /* issue next command; if command issuing fails, remove the
- * entry from cmd_queue */
- int res = hfa384x_cmd_issue(dev, entry);
- spin_lock(&local->cmdlock);
- __hostap_cmd_queue_free(local, entry, res);
- spin_unlock(&local->cmdlock);
- }
- }
- static int hfa384x_wait_offset(struct net_device *dev, u16 o_off)
- {
- int tries = HFA384X_BAP_BUSY_TIMEOUT;
- int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY;
- while (res && tries > 0) {
- tries--;
- udelay(1);
- res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY;
- }
- return res;
- }
- /* Offset must be even */
- static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id,
- int offset)
- {
- u16 o_off, s_off;
- int ret = 0;
- if (offset % 2 || bap > 1)
- return -EINVAL;
- if (bap == BAP1) {
- o_off = HFA384X_OFFSET1_OFF;
- s_off = HFA384X_SELECT1_OFF;
- } else {
- o_off = HFA384X_OFFSET0_OFF;
- s_off = HFA384X_SELECT0_OFF;
- }
- if (hfa384x_wait_offset(dev, o_off)) {
- prism2_io_debug_error(dev, 7);
- printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n",
- dev->name);
- ret = -ETIMEDOUT;
- goto out;
- }
- HFA384X_OUTW(id, s_off);
- HFA384X_OUTW(offset, o_off);
- if (hfa384x_wait_offset(dev, o_off)) {
- prism2_io_debug_error(dev, 8);
- printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n",
- dev->name);
- ret = -ETIMEDOUT;
- goto out;
- }
- #ifndef final_version
- if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) {
- prism2_io_debug_error(dev, 9);
- printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error "
- "(%d,0x04%x,%d); reg=0x%04x\n",
- dev->name, bap, id, offset, HFA384X_INW(o_off));
- ret = -EINVAL;
- }
- #endif
- out:
- return ret;
- }
- static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
- int exact_len)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- int res, rlen = 0;
- struct hfa384x_rid_hdr rec;
- iface = netdev_priv(dev);
- local = iface->local;
- if (local->no_pri) {
- printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI "
- "f/w\n", dev->name, rid, len);
- return -ENOTTY; /* Well.. not really correct, but return
- * something unique enough.. */
- }
- if ((local->func->card_present && !local->func->card_present(local)) ||
- local->hw_downloading)
- return -ENODEV;
- res = mutex_lock_interruptible(&local->rid_bap_mtx);
- if (res)
- return res;
- res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL);
- if (res) {
- printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed "
- "(res=%d, rid=%04x, len=%d)\n",
- dev->name, res, rid, len);
- mutex_unlock(&local->rid_bap_mtx);
- return res;
- }
- spin_lock_bh(&local->baplock);
- res = hfa384x_setup_bap(dev, BAP0, rid, 0);
- if (!res)
- res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
- if (le16_to_cpu(rec.len) == 0) {
- /* RID not available */
- res = -ENODATA;
- }
- rlen = (le16_to_cpu(rec.len) - 1) * 2;
- if (!res && exact_len && rlen != len) {
- printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: "
- "rid=0x%04x, len=%d (expected %d)\n",
- dev->name, rid, rlen, len);
- res = -ENODATA;
- }
- if (!res)
- res = hfa384x_from_bap(dev, BAP0, buf, len);
- spin_unlock_bh(&local->baplock);
- mutex_unlock(&local->rid_bap_mtx);
- if (res) {
- if (res != -ENODATA)
- printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, "
- "len=%d) - failed - res=%d\n", dev->name, rid,
- len, res);
- if (res == -ETIMEDOUT)
- prism2_hw_reset(dev);
- return res;
- }
- return rlen;
- }
- static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_rid_hdr rec;
- int res;
- iface = netdev_priv(dev);
- local = iface->local;
- if (local->no_pri) {
- printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI "
- "f/w\n", dev->name, rid, len);
- return -ENOTTY; /* Well.. not really correct, but return
- * something unique enough.. */
- }
- if ((local->func->card_present && !local->func->card_present(local)) ||
- local->hw_downloading)
- return -ENODEV;
- rec.rid = cpu_to_le16(rid);
- /* RID len in words and +1 for rec.rid */
- rec.len = cpu_to_le16(len / 2 + len % 2 + 1);
- res = mutex_lock_interruptible(&local->rid_bap_mtx);
- if (res)
- return res;
- spin_lock_bh(&local->baplock);
- res = hfa384x_setup_bap(dev, BAP0, rid, 0);
- if (!res)
- res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec));
- if (!res)
- res = hfa384x_to_bap(dev, BAP0, buf, len);
- spin_unlock_bh(&local->baplock);
- if (res) {
- printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - "
- "failed - res=%d\n", dev->name, rid, len, res);
- mutex_unlock(&local->rid_bap_mtx);
- return res;
- }
- res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL);
- mutex_unlock(&local->rid_bap_mtx);
- if (res) {
- printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE "
- "failed (res=%d, rid=%04x, len=%d)\n",
- dev->name, res, rid, len);
- if (res == -ETIMEDOUT)
- prism2_hw_reset(dev);
- }
- return res;
- }
- static void hfa384x_disable_interrupts(struct net_device *dev)
- {
- /* disable interrupts and clear event status */
- HFA384X_OUTW(0, HFA384X_INTEN_OFF);
- HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
- }
- static void hfa384x_enable_interrupts(struct net_device *dev)
- {
- /* ack pending events and enable interrupts from selected events */
- HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
- HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF);
- }
- static void hfa384x_events_no_bap0(struct net_device *dev)
- {
- HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS,
- HFA384X_INTEN_OFF);
- }
- static void hfa384x_events_all(struct net_device *dev)
- {
- HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF);
- }
- static void hfa384x_events_only_cmd(struct net_device *dev)
- {
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF);
- }
- static u16 hfa384x_allocate_fid(struct net_device *dev, int len)
- {
- u16 fid;
- unsigned long delay;
- /* FIX: this could be replace with hfa384x_cmd() if the Alloc event
- * below would be handled like CmdCompl event (sleep here, wake up from
- * interrupt handler */
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) {
- printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n",
- dev->name, len);
- return 0xffff;
- }
- delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT;
- while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) &&
- time_before(jiffies, delay))
- yield();
- if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) {
- printk("%s: fid allocate, len=%d - timeout\n", dev->name, len);
- return 0xffff;
- }
- fid = HFA384X_INW(HFA384X_ALLOCFID_OFF);
- HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF);
- return fid;
- }
- static int prism2_reset_port(struct net_device *dev)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- int res;
- iface = netdev_priv(dev);
- local = iface->local;
- if (!local->dev_enabled)
- return 0;
- res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0,
- NULL, NULL);
- if (res)
- printk(KERN_DEBUG "%s: reset port failed to disable port\n",
- dev->name);
- else {
- res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0,
- NULL, NULL);
- if (res)
- printk(KERN_DEBUG "%s: reset port failed to enable "
- "port\n", dev->name);
- }
- /* It looks like at least some STA firmware versions reset
- * fragmentation threshold back to 2346 after enable command. Restore
- * the configured value, if it differs from this default. */
- if (local->fragm_threshold != 2346 &&
- hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
- local->fragm_threshold)) {
- printk(KERN_DEBUG "%s: failed to restore fragmentation "
- "threshold (%d) after Port0 enable\n",
- dev->name, local->fragm_threshold);
- }
- /* Some firmwares lose antenna selection settings on reset */
- (void) hostap_set_antsel(local);
- return res;
- }
- static int prism2_get_version_info(struct net_device *dev, u16 rid,
- const char *txt)
- {
- struct hfa384x_comp_ident comp;
- struct hostap_interface *iface;
- local_info_t *local;
- iface = netdev_priv(dev);
- local = iface->local;
- if (local->no_pri) {
- /* PRI f/w not yet available - cannot read RIDs */
- return -1;
- }
- if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) {
- printk(KERN_DEBUG "Could not get RID for component %s\n", txt);
- return -1;
- }
- printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt,
- __le16_to_cpu(comp.id), __le16_to_cpu(comp.major),
- __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant));
- return 0;
- }
- static int prism2_setup_rids(struct net_device *dev)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 tmp;
- int ret = 0;
- iface = netdev_priv(dev);
- local = iface->local;
- hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000);
- if (!local->fw_ap) {
- u16 tmp1 = hostap_get_porttype(local);
- ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp1);
- if (ret) {
- printk("%s: Port type setting to %d failed\n",
- dev->name, tmp1);
- goto fail;
- }
- }
- /* Setting SSID to empty string seems to kill the card in Host AP mode
- */
- if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') {
- ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID,
- local->essid);
- if (ret) {
- printk("%s: AP own SSID setting failed\n", dev->name);
- goto fail;
- }
- }
- ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN,
- PRISM2_DATA_MAXLEN);
- if (ret) {
- printk("%s: MAC data length setting to %d failed\n",
- dev->name, PRISM2_DATA_MAXLEN);
- goto fail;
- }
- if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) {
- printk("%s: Channel list read failed\n", dev->name);
- ret = -EINVAL;
- goto fail;
- }
- local->channel_mask = le16_to_cpu(tmp);
- if (local->channel < 1 || local->channel > 14 ||
- !(local->channel_mask & (1 << (local->channel - 1)))) {
- printk(KERN_WARNING "%s: Channel setting out of range "
- "(%d)!\n", dev->name, local->channel);
- ret = -EBUSY;
- goto fail;
- }
- ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel);
- if (ret) {
- printk("%s: Channel setting to %d failed\n",
- dev->name, local->channel);
- goto fail;
- }
- ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT,
- local->beacon_int);
- if (ret) {
- printk("%s: Beacon interval setting to %d failed\n",
- dev->name, local->beacon_int);
- /* this may fail with Symbol/Lucent firmware */
- if (ret == -ETIMEDOUT)
- goto fail;
- }
- ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD,
- local->dtim_period);
- if (ret) {
- printk("%s: DTIM period setting to %d failed\n",
- dev->name, local->dtim_period);
- /* this may fail with Symbol/Lucent firmware */
- if (ret == -ETIMEDOUT)
- goto fail;
- }
- ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE,
- local->is_promisc);
- if (ret)
- printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n",
- dev->name, local->is_promisc);
- if (!local->fw_ap) {
- ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID,
- local->essid);
- if (ret) {
- printk("%s: Desired SSID setting failed\n", dev->name);
- goto fail;
- }
- }
- /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and
- * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic
- * rates */
- if (local->tx_rate_control == 0) {
- local->tx_rate_control =
- HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS |
- HFA384X_RATES_5MBPS |
- HFA384X_RATES_11MBPS;
- }
- if (local->basic_rates == 0)
- local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS;
- if (!local->fw_ap) {
- ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL,
- local->tx_rate_control);
- if (ret) {
- printk("%s: TXRateControl setting to %d failed\n",
- dev->name, local->tx_rate_control);
- goto fail;
- }
- ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES,
- local->tx_rate_control);
- if (ret) {
- printk("%s: cnfSupportedRates setting to %d failed\n",
- dev->name, local->tx_rate_control);
- }
- ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
- local->basic_rates);
- if (ret) {
- printk("%s: cnfBasicRates setting to %d failed\n",
- dev->name, local->basic_rates);
- }
- ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1);
- if (ret) {
- printk("%s: Create IBSS setting to 1 failed\n",
- dev->name);
- }
- }
- if (local->name_set)
- (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME,
- local->name);
- if (hostap_set_encryption(local)) {
- printk(KERN_INFO "%s: could not configure encryption\n",
- dev->name);
- }
- (void) hostap_set_antsel(local);
- if (hostap_set_roaming(local)) {
- printk(KERN_INFO "%s: could not set host roaming\n",
- dev->name);
- }
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) &&
- hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec))
- printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n",
- dev->name, local->enh_sec);
- /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently
- * not working correctly (last seven counters report bogus values).
- * This has been fixed in 0.8.2, so enable 32-bit tallies only
- * beginning with that firmware version. Another bug fix for 32-bit
- * tallies in 1.4.0; should 16-bit tallies be used for some other
- * versions, too? */
- if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) {
- if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) {
- printk(KERN_INFO "%s: cnfThirty2Tally setting "
- "failed\n", dev->name);
- local->tallies32 = 0;
- } else
- local->tallies32 = 1;
- } else
- local->tallies32 = 0;
- hostap_set_auth_algs(local);
- if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
- local->fragm_threshold)) {
- printk(KERN_INFO "%s: setting FragmentationThreshold to %d "
- "failed\n", dev->name, local->fragm_threshold);
- }
- if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD,
- local->rts_threshold)) {
- printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n",
- dev->name, local->rts_threshold);
- }
- if (local->manual_retry_count >= 0 &&
- hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT,
- local->manual_retry_count)) {
- printk(KERN_INFO "%s: setting cnfAltRetryCount to %d failed\n",
- dev->name, local->manual_retry_count);
- }
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1) &&
- hfa384x_get_rid(dev, HFA384X_RID_CNFDBMADJUST, &tmp, 2, 1) == 2) {
- local->rssi_to_dBm = le16_to_cpu(tmp);
- }
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->wpa &&
- hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1)) {
- printk(KERN_INFO "%s: setting ssnHandlingMode to 1 failed\n",
- dev->name);
- }
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->generic_elem &&
- hfa384x_set_rid(dev, HFA384X_RID_GENERICELEMENT,
- local->generic_elem, local->generic_elem_len)) {
- printk(KERN_INFO "%s: setting genericElement failed\n",
- dev->name);
- }
- fail:
- return ret;
- }
- static int prism2_hw_init(struct net_device *dev, int initial)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- int ret, first = 1;
- unsigned long start, delay;
- PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n");
- iface = netdev_priv(dev);
- local = iface->local;
- clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits);
- init:
- /* initialize HFA 384x */
- ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0);
- if (ret) {
- printk(KERN_INFO "%s: first command failed - assuming card "
- "does not have primary firmware\n", dev_info);
- }
- if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) {
- /* EvStat has Cmd bit set in some cases, so retry once if no
- * wait was needed */
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
- printk(KERN_DEBUG "%s: init command completed too quickly - "
- "retrying\n", dev->name);
- first = 0;
- goto init;
- }
- start = jiffies;
- delay = jiffies + HFA384X_INIT_TIMEOUT;
- while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) &&
- time_before(jiffies, delay))
- yield();
- if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) {
- printk(KERN_DEBUG "%s: assuming no Primary image in "
- "flash - card initialization not completed\n",
- dev_info);
- local->no_pri = 1;
- #ifdef PRISM2_DOWNLOAD_SUPPORT
- if (local->sram_type == -1)
- local->sram_type = prism2_get_ram_size(local);
- #endif /* PRISM2_DOWNLOAD_SUPPORT */
- return 1;
- }
- local->no_pri = 0;
- printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n",
- (jiffies - start) * 1000 / HZ);
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
- return 0;
- }
- static int prism2_hw_init2(struct net_device *dev, int initial)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- int i;
- iface = netdev_priv(dev);
- local = iface->local;
- #ifdef PRISM2_DOWNLOAD_SUPPORT
- kfree(local->pda);
- if (local->no_pri)
- local->pda = NULL;
- else
- local->pda = prism2_read_pda(dev);
- #endif /* PRISM2_DOWNLOAD_SUPPORT */
- hfa384x_disable_interrupts(dev);
- #ifndef final_version
- HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF);
- if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) {
- printk("SWSUPPORT0 write/read failed: %04X != %04X\n",
- HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC);
- goto failed;
- }
- #endif
- if (initial || local->pri_only) {
- hfa384x_events_only_cmd(dev);
- /* get card version information */
- if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") ||
- prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) {
- hfa384x_disable_interrupts(dev);
- goto failed;
- }
- if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) {
- printk(KERN_DEBUG "%s: Failed to read STA f/w version "
- "- only Primary f/w present\n", dev->name);
- local->pri_only = 1;
- return 0;
- }
- local->pri_only = 0;
- hfa384x_disable_interrupts(dev);
- }
- /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and
- * enable interrupts before this. This would also require some sort of
- * sleeping AllocEv waiting */
- /* allocate TX FIDs */
- local->txfid_len = PRISM2_TXFID_LEN;
- for (i = 0; i < PRISM2_TXFID_COUNT; i++) {
- local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len);
- if (local->txfid[i] == 0xffff && local->txfid_len > 1600) {
- local->txfid[i] = hfa384x_allocate_fid(dev, 1600);
- if (local->txfid[i] != 0xffff) {
- printk(KERN_DEBUG "%s: Using shorter TX FID "
- "(1600 bytes)\n", dev->name);
- local->txfid_len = 1600;
- }
- }
- if (local->txfid[i] == 0xffff)
- goto failed;
- local->intransmitfid[i] = PRISM2_TXFID_EMPTY;
- }
- hfa384x_events_only_cmd(dev);
- if (initial) {
- struct list_head *ptr;
- prism2_check_sta_fw_version(local);
- if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR,
- dev->dev_addr, 6, 1) < 0) {
- printk("%s: could not get own MAC address\n",
- dev->name);
- }
- list_for_each(ptr, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- memcpy(iface->dev->dev_addr, dev->dev_addr, ETH_ALEN);
- }
- } else if (local->fw_ap)
- prism2_check_sta_fw_version(local);
- prism2_setup_rids(dev);
- /* MAC is now configured, but port 0 is not yet enabled */
- return 0;
- failed:
- if (!local->no_pri)
- printk(KERN_WARNING "%s: Initialization failed\n", dev_info);
- return 1;
- }
- static int prism2_hw_enable(struct net_device *dev, int initial)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- int was_resetting;
- iface = netdev_priv(dev);
- local = iface->local;
- was_resetting = local->hw_resetting;
- if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) {
- printk("%s: MAC port 0 enabling failed\n", dev->name);
- return 1;
- }
- local->hw_ready = 1;
- local->hw_reset_tries = 0;
- local->hw_resetting = 0;
- hfa384x_enable_interrupts(dev);
- /* at least D-Link DWL-650 seems to require additional port reset
- * before it starts acting as an AP, so reset port automatically
- * here just in case */
- if (initial && prism2_reset_port(dev)) {
- printk("%s: MAC port 0 reseting failed\n", dev->name);
- return 1;
- }
- if (was_resetting && netif_queue_stopped(dev)) {
- /* If hw_reset() was called during pending transmit, netif
- * queue was stopped. Wake it up now since the wlan card has
- * been resetted. */
- netif_wake_queue(dev);
- }
- return 0;
- }
- static int prism2_hw_config(struct net_device *dev, int initial)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- iface = netdev_priv(dev);
- local = iface->local;
- if (local->hw_downloading)
- return 1;
- if (prism2_hw_init(dev, initial)) {
- return local->no_pri ? 0 : 1;
- }
- if (prism2_hw_init2(dev, initial))
- return 1;
- /* Enable firmware if secondary image is loaded and at least one of the
- * netdevices is up. */
- if (!local->pri_only &&
- (initial == 0 || (initial == 2 && local->num_dev_open > 0))) {
- if (!local->dev_enabled)
- prism2_callback(local, PRISM2_CALLBACK_ENABLE);
- local->dev_enabled = 1;
- return prism2_hw_enable(dev, initial);
- }
- return 0;
- }
- static void prism2_hw_shutdown(struct net_device *dev, int no_disable)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- iface = netdev_priv(dev);
- local = iface->local;
- /* Allow only command completion events during disable */
- hfa384x_events_only_cmd(dev);
- local->hw_ready = 0;
- if (local->dev_enabled)
- prism2_callback(local, PRISM2_CALLBACK_DISABLE);
- local->dev_enabled = 0;
- if (local->func->card_present && !local->func->card_present(local)) {
- printk(KERN_DEBUG "%s: card already removed or not configured "
- "during shutdown\n", dev->name);
- return;
- }
- if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 &&
- hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL))
- printk(KERN_WARNING "%s: Shutdown failed\n", dev_info);
- hfa384x_disable_interrupts(dev);
- if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL)
- hfa384x_events_only_cmd(dev);
- else
- prism2_clear_cmd_queue(local);
- }
- static void prism2_hw_reset(struct net_device *dev)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- #if 0
- static long last_reset = 0;
- /* do not reset card more than once per second to avoid ending up in a
- * busy loop reseting the card */
- if (time_before_eq(jiffies, last_reset + HZ))
- return;
- last_reset = jiffies;
- #endif
- iface = netdev_priv(dev);
- local = iface->local;
- if (in_interrupt()) {
- printk(KERN_DEBUG "%s: driver bug - prism2_hw_reset() called "
- "in interrupt context\n", dev->name);
- return;
- }
- if (local->hw_downloading)
- return;
- if (local->hw_resetting) {
- printk(KERN_WARNING "%s: %s: already resetting card - "
- "ignoring reset request\n", dev_info, dev->name);
- return;
- }
- local->hw_reset_tries++;
- if (local->hw_reset_tries > 10) {
- printk(KERN_WARNING "%s: too many reset tries, skipping\n",
- dev->name);
- return;
- }
- printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name);
- hfa384x_disable_interrupts(dev);
- local->hw_resetting = 1;
- if (local->func->cor_sreset) {
- /* Host system seems to hang in some cases with high traffic
- * load or shared interrupts during COR sreset. Disable shared
- * interrupts during reset to avoid these crashes. COS sreset
- * takes quite a long time, so it is unfortunate that this
- * seems to be needed. Anyway, I do not know of any better way
- * of avoiding the crash. */
- disable_irq(dev->irq);
- local->func->cor_sreset(local);
- enable_irq(dev->irq);
- }
- prism2_hw_shutdown(dev, 1);
- prism2_hw_config(dev, 0);
- local->hw_resetting = 0;
- #ifdef PRISM2_DOWNLOAD_SUPPORT
- if (local->dl_pri) {
- printk(KERN_DEBUG "%s: persistent download of primary "
- "firmware\n", dev->name);
- if (prism2_download_genesis(local, local->dl_pri) < 0)
- printk(KERN_WARNING "%s: download (PRI) failed\n",
- dev->name);
- }
- if (local->dl_sec) {
- printk(KERN_DEBUG "%s: persistent download of secondary "
- "firmware\n", dev->name);
- if (prism2_download_volatile(local, local->dl_sec) < 0)
- printk(KERN_WARNING "%s: download (SEC) failed\n",
- dev->name);
- }
- #endif /* PRISM2_DOWNLOAD_SUPPORT */
- /* TODO: restore beacon TIM bits for STAs that have buffered frames */
- }
- static void prism2_schedule_reset(local_info_t *local)
- {
- schedule_work(&local->reset_queue);
- }
- /* Called only as scheduled task after noticing card timeout in interrupt
- * context */
- static void handle_reset_queue(struct work_struct *work)
- {
- local_info_t *local = container_of(work, local_info_t, reset_queue);
- printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name);
- prism2_hw_reset(local->dev);
- if (netif_queue_stopped(local->dev)) {
- int i;
- for (i = 0; i < PRISM2_TXFID_COUNT; i++)
- if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) {
- PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: "
- "wake up queue\n");
- netif_wake_queue(local->dev);
- break;
- }
- }
- }
- static int prism2_get_txfid_idx(local_info_t *local)
- {
- int idx, end;
- unsigned long flags;
- spin_lock_irqsave(&local->txfidlock, flags);
- end = idx = local->next_txfid;
- do {
- if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) {
- local->intransmitfid[idx] = PRISM2_TXFID_RESERVED;
- spin_unlock_irqrestore(&local->txfidlock, flags);
- return idx;
- }
- idx++;
- if (idx >= PRISM2_TXFID_COUNT)
- idx = 0;
- } while (idx != end);
- spin_unlock_irqrestore(&local->txfidlock, flags);
- PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: "
- "packet dropped\n");
- local->dev->stats.tx_dropped++;
- return -1;
- }
- /* Called only from hardware IRQ */
- static void prism2_transmit_cb(struct net_device *dev, long context,
- u16 resp0, u16 res)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- int idx = (int) context;
- iface = netdev_priv(dev);
- local = iface->local;
- if (res) {
- printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n",
- dev->name, res);
- return;
- }
- if (idx < 0 || idx >= PRISM2_TXFID_COUNT) {
- printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid "
- "idx=%d\n", dev->name, idx);
- return;
- }
- if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
- printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called "
- "with no pending transmit\n", dev->name);
- }
- if (netif_queue_stopped(dev)) {
- /* ready for next TX, so wake up queue that was stopped in
- * prism2_transmit() */
- netif_wake_queue(dev);
- }
- spin_lock(&local->txfidlock);
- /* With reclaim, Resp0 contains new txfid for transmit; the old txfid
- * will be automatically allocated for the next TX frame */
- local->intransmitfid[idx] = resp0;
- PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, "
- "resp0=0x%04x, transmit_txfid=0x%04x\n",
- dev->name, idx, local->txfid[idx],
- resp0, local->intransmitfid[local->next_txfid]);
- idx++;
- if (idx >= PRISM2_TXFID_COUNT)
- idx = 0;
- local->next_txfid = idx;
- /* check if all TX buffers are occupied */
- do {
- if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) {
- spin_unlock(&local->txfidlock);
- return;
- }
- idx++;
- if (idx >= PRISM2_TXFID_COUNT)
- idx = 0;
- } while (idx != local->next_txfid);
- spin_unlock(&local->txfidlock);
- /* no empty TX buffers, stop queue */
- netif_stop_queue(dev);
- }
- /* Called only from software IRQ if PCI bus master is not used (with bus master
- * this can be called both from software and hardware IRQ) */
- static int prism2_transmit(struct net_device *dev, int idx)
- {
- struct hostap_interface *iface;
- local_info_t *local;
- int res;
- iface = netdev_priv(dev);
- local = iface->local;
- /* The driver tries to stop netif queue so that there would not be
- * more than one attempt to transmit frames going on; check that this
- * is really the case */
- if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
- printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called "
- "when previous TX was pending\n", dev->name);
- return -1;
- }
- /* stop the queue for the time that transmit is pending */
- netif_stop_queue(dev);
- /* transmit packet */
- res = hfa384x_cmd_callback(
- dev,
- HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM,
- local->txfid[idx],
- prism2_transmit_cb, (long) idx);
- if (res) {
- printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT "
- "failed (res=%d)\n", dev…