diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-18 18:02:35 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-18 18:02:35 -0700 |
commit | 334d094504c2fe1c44211ecb49146ae6bca8c321 (patch) | |
tree | d3c0f68e4b9f8e3d2ccc39e7dfe5de0534a5fad9 /drivers/net/wireless/libertas/main.c | |
parent | d1a4be630fb068f251d64b62919f143c49ca8057 (diff) | |
parent | d1643d24c61b725bef399cc1cf2944b4c9c23177 (diff) | |
download | op-kernel-dev-334d094504c2fe1c44211ecb49146ae6bca8c321.zip op-kernel-dev-334d094504c2fe1c44211ecb49146ae6bca8c321.tar.gz |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.26
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.26: (1090 commits)
[NET]: Fix and allocate less memory for ->priv'less netdevices
[IPV6]: Fix dangling references on error in fib6_add().
[NETLABEL]: Fix NULL deref in netlbl_unlabel_staticlist_gen() if ifindex not found
[PKT_SCHED]: Fix datalen check in tcf_simp_init().
[INET]: Uninline the __inet_inherit_port call.
[INET]: Drop the inet_inherit_port() call.
SCTP: Initialize partial_bytes_acked to 0, when all of the data is acked.
[netdrvr] forcedeth: internal simplifications; changelog removal
phylib: factor out get_phy_id from within get_phy_device
PHY: add BCM5464 support to broadcom PHY driver
cxgb3: Fix __must_check warning with dev_dbg.
tc35815: Statistics cleanup
natsemi: fix MMIO for PPC 44x platforms
[TIPC]: Cleanup of TIPC reference table code
[TIPC]: Optimized initialization of TIPC reference table
[TIPC]: Remove inlining of reference table locking routines
e1000: convert uint16_t style integers to u16
ixgb: convert uint16_t style integers to u16
sb1000.c: make const arrays static
sb1000.c: stop inlining largish static functions
...
Diffstat (limited to 'drivers/net/wireless/libertas/main.c')
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 289 |
1 files changed, 169 insertions, 120 deletions
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 4d4e2f3..406f54d 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -10,6 +10,7 @@ #include <linux/netdevice.h> #include <linux/if_arp.h> #include <linux/kthread.h> +#include <linux/kfifo.h> #include <net/iw_handler.h> #include <net/ieee80211.h> @@ -19,8 +20,8 @@ #include "dev.h" #include "wext.h" #include "debugfs.h" +#include "scan.h" #include "assoc.h" -#include "join.h" #include "cmd.h" #define DRIVER_RELEASE_VERSION "323.p0" @@ -37,6 +38,11 @@ EXPORT_SYMBOL_GPL(lbs_debug); module_param_named(libertas_debug, lbs_debug, int, 0644); +/* This global structure is used to send the confirm_sleep command as + * fast as possible down to the firmware. */ +struct cmd_confirm_sleep confirm_sleep; + + #define LBS_TX_PWR_DEFAULT 20 /*100mW */ #define LBS_TX_PWR_US_DEFAULT 20 /*100mW */ #define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */ @@ -277,10 +283,10 @@ static ssize_t lbs_rtap_set(struct device *dev, struct lbs_private *priv = to_net_dev(dev)->priv; sscanf(buf, "%x", &monitor_mode); - if (monitor_mode != LBS_MONITOR_OFF) { - if(priv->monitormode == monitor_mode) + if (monitor_mode) { + if (priv->monitormode == monitor_mode) return strlen(buf); - if (priv->monitormode == LBS_MONITOR_OFF) { + if (!priv->monitormode) { if (priv->infra_open || priv->mesh_open) return -EBUSY; if (priv->mode == IW_MODE_INFRA) @@ -293,9 +299,9 @@ static ssize_t lbs_rtap_set(struct device *dev, } else { - if (priv->monitormode == LBS_MONITOR_OFF) + if (!priv->monitormode) return strlen(buf); - priv->monitormode = LBS_MONITOR_OFF; + priv->monitormode = 0; lbs_remove_rtap(priv); if (priv->currenttxskb) { @@ -392,7 +398,7 @@ static int lbs_dev_open(struct net_device *dev) spin_lock_irq(&priv->driver_lock); - if (priv->monitormode != LBS_MONITOR_OFF) { + if (priv->monitormode) { ret = -EBUSY; goto out; } @@ -475,10 +481,9 @@ static void lbs_tx_timeout(struct net_device *dev) dev->trans_start = jiffies; - if (priv->currenttxskb) { - priv->eventcause = 0x01000000; - lbs_send_tx_feedback(priv); - } + if (priv->currenttxskb) + lbs_send_tx_feedback(priv, 0); + /* XX: Shouldn't we also call into the hw-specific driver to kick it somehow? */ lbs_host_to_card_done(priv); @@ -531,34 +536,27 @@ static int lbs_set_mac_address(struct net_device *dev, void *addr) int ret = 0; struct lbs_private *priv = (struct lbs_private *) dev->priv; struct sockaddr *phwaddr = addr; + struct cmd_ds_802_11_mac_address cmd; lbs_deb_enter(LBS_DEB_NET); /* In case it was called from the mesh device */ - dev = priv->dev ; - - memset(priv->current_addr, 0, ETH_ALEN); - - /* dev->dev_addr is 8 bytes */ - lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN); - - lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN); - memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN); + dev = priv->dev; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, 0, NULL); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + memcpy(cmd.macadd, phwaddr->sa_data, ETH_ALEN); + ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd); if (ret) { lbs_deb_net("set MAC address failed\n"); - ret = -1; goto done; } - lbs_deb_hex(LBS_DEB_NET, "priv->macaddr", priv->current_addr, ETH_ALEN); - memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN); + memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN); + memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN); if (priv->mesh_dev) - memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN); + memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN); done: lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); @@ -581,45 +579,45 @@ static int lbs_copy_multicast_address(struct lbs_private *priv, static void lbs_set_multicast_list(struct net_device *dev) { struct lbs_private *priv = dev->priv; - int oldpacketfilter; + int old_mac_control; DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_NET); - oldpacketfilter = priv->currentpacketfilter; + old_mac_control = priv->mac_control; if (dev->flags & IFF_PROMISC) { lbs_deb_net("enable promiscuous mode\n"); - priv->currentpacketfilter |= + priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE; - priv->currentpacketfilter &= + priv->mac_control &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE | CMD_ACT_MAC_MULTICAST_ENABLE); } else { /* Multicast */ - priv->currentpacketfilter &= + priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; if (dev->flags & IFF_ALLMULTI || dev->mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) { lbs_deb_net( "enabling all multicast\n"); - priv->currentpacketfilter |= + priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; - priv->currentpacketfilter &= + priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; } else { - priv->currentpacketfilter &= + priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; if (!dev->mc_count) { lbs_deb_net("no multicast addresses, " "disabling multicast\n"); - priv->currentpacketfilter &= + priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; } else { int i; - priv->currentpacketfilter |= + priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE; priv->nr_of_multicastmacaddr = @@ -642,9 +640,8 @@ static void lbs_set_multicast_list(struct net_device *dev) } } - if (priv->currentpacketfilter != oldpacketfilter) { - lbs_set_mac_packet_filter(priv); - } + if (priv->mac_control != old_mac_control) + lbs_set_mac_control(priv); lbs_deb_leave(LBS_DEB_NET); } @@ -662,7 +659,6 @@ static int lbs_thread(void *data) struct net_device *dev = data; struct lbs_private *priv = dev->priv; wait_queue_t wait; - u8 ireg = 0; lbs_deb_enter(LBS_DEB_THREAD); @@ -670,9 +666,10 @@ static int lbs_thread(void *data) for (;;) { int shouldsleep; + u8 resp_idx; - lbs_deb_thread( "main-thread 111: intcounter=%d currenttxskb=%p dnld_sent=%d\n", - priv->intcounter, priv->currenttxskb, priv->dnld_sent); + lbs_deb_thread("1: currenttxskb %p, dnld_sent %d\n", + priv->currenttxskb, priv->dnld_sent); add_wait_queue(&priv->waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); @@ -684,8 +681,6 @@ static int lbs_thread(void *data) shouldsleep = 1; /* We need to wait until we're _told_ to die */ else if (priv->psstate == PS_STATE_SLEEP) shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */ - else if (priv->intcounter) - shouldsleep = 0; /* Interrupt pending. Deal with it now */ else if (priv->cmd_timed_out) shouldsleep = 0; /* Command timed out. Recover */ else if (!priv->fw_ready) @@ -698,29 +693,34 @@ static int lbs_thread(void *data) shouldsleep = 1; /* Can't send a command; one already running */ else if (!list_empty(&priv->cmdpendingq)) shouldsleep = 0; /* We have a command to send */ + else if (__kfifo_len(priv->event_fifo)) + shouldsleep = 0; /* We have an event to process */ + else if (priv->resp_len[priv->resp_idx]) + shouldsleep = 0; /* We have a command response */ else shouldsleep = 1; /* No command */ if (shouldsleep) { - lbs_deb_thread("main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n", - priv->connect_status, priv->intcounter, - priv->psmode, priv->psstate); + lbs_deb_thread("sleeping, connect_status %d, " + "ps_mode %d, ps_state %d\n", + priv->connect_status, + priv->psmode, priv->psstate); spin_unlock_irq(&priv->driver_lock); schedule(); } else spin_unlock_irq(&priv->driver_lock); - lbs_deb_thread("main-thread 222 (waking up): intcounter=%d currenttxskb=%p dnld_sent=%d\n", - priv->intcounter, priv->currenttxskb, priv->dnld_sent); + lbs_deb_thread("2: currenttxskb %p, dnld_send %d\n", + priv->currenttxskb, priv->dnld_sent); set_current_state(TASK_RUNNING); remove_wait_queue(&priv->waitq, &wait); - lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d\n", - priv->intcounter, priv->currenttxskb, priv->dnld_sent); + lbs_deb_thread("3: currenttxskb %p, dnld_sent %d\n", + priv->currenttxskb, priv->dnld_sent); if (kthread_should_stop()) { - lbs_deb_thread("main-thread: break from main thread\n"); + lbs_deb_thread("break from main thread\n"); break; } @@ -729,35 +729,23 @@ static int lbs_thread(void *data) continue; } - spin_lock_irq(&priv->driver_lock); - - if (priv->intcounter) { - u8 int_status; - - priv->intcounter = 0; - int_status = priv->hw_get_int_status(priv, &ireg); - - if (int_status) { - lbs_deb_thread("main-thread: reading HOST_INT_STATUS_REG failed\n"); - spin_unlock_irq(&priv->driver_lock); - continue; - } - priv->hisregcpy |= ireg; - } - - lbs_deb_thread("main-thread 444: intcounter=%d currenttxskb=%p dnld_sent=%d\n", - priv->intcounter, priv->currenttxskb, priv->dnld_sent); + lbs_deb_thread("4: currenttxskb %p, dnld_sent %d\n", + priv->currenttxskb, priv->dnld_sent); - /* command response? */ - if (priv->hisregcpy & MRVDRV_CMD_UPLD_RDY) { - lbs_deb_thread("main-thread: cmd response ready\n"); - - priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY; + spin_lock_irq(&priv->driver_lock); + /* Process any pending command response */ + resp_idx = priv->resp_idx; + if (priv->resp_len[resp_idx]) { spin_unlock_irq(&priv->driver_lock); - lbs_process_rx_command(priv); + lbs_process_command_response(priv, + priv->resp_buf[resp_idx], + priv->resp_len[resp_idx]); spin_lock_irq(&priv->driver_lock); + priv->resp_len[resp_idx] = 0; } + spin_unlock_irq(&priv->driver_lock); + /* command timeout stuff */ if (priv->cmd_timed_out && priv->cur_cmd) { struct cmd_ctrl_node *cmdnode = priv->cur_cmd; @@ -778,21 +766,18 @@ static int lbs_thread(void *data) } priv->cmd_timed_out = 0; - /* Any Card Event */ - if (priv->hisregcpy & MRVDRV_CARDEVENT) { - lbs_deb_thread("main-thread: Card Event Activity\n"); - - priv->hisregcpy &= ~MRVDRV_CARDEVENT; + /* Process hardware events, e.g. card removed, link lost */ + spin_lock_irq(&priv->driver_lock); + while (__kfifo_len(priv->event_fifo)) { + u32 event; - if (priv->hw_read_event_cause(priv)) { - lbs_pr_alert("main-thread: hw_read_event_cause failed\n"); - spin_unlock_irq(&priv->driver_lock); - continue; - } - spin_unlock_irq(&priv->driver_lock); - lbs_process_event(priv); - } else + __kfifo_get(priv->event_fifo, (unsigned char *) &event, + sizeof(event)); spin_unlock_irq(&priv->driver_lock); + lbs_process_event(priv, event); + spin_lock_irq(&priv->driver_lock); + } + spin_unlock_irq(&priv->driver_lock); if (!priv->fw_ready) continue; @@ -801,10 +786,12 @@ static int lbs_thread(void *data) if (priv->psstate == PS_STATE_PRE_SLEEP && !priv->dnld_sent && !priv->cur_cmd) { if (priv->connect_status == LBS_CONNECTED) { - lbs_deb_thread("main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p dnld_sent=%d cur_cmd=%p, confirm now\n", - priv->intcounter, priv->currenttxskb, priv->dnld_sent, priv->cur_cmd); + lbs_deb_thread("pre-sleep, currenttxskb %p, " + "dnld_sent %d, cur_cmd %p\n", + priv->currenttxskb, priv->dnld_sent, + priv->cur_cmd); - lbs_ps_confirm_sleep(priv, (u16) priv->psmode); + lbs_ps_confirm_sleep(priv); } else { /* workaround for firmware sending * deauth/linkloss event immediately @@ -812,7 +799,8 @@ static int lbs_thread(void *data) * after firmware fixes it */ priv->psstate = PS_STATE_AWAKE; - lbs_pr_alert("main-thread: ignore PS_SleepConfirm in non-connected state\n"); + lbs_pr_alert("ignore PS_SleepConfirm in " + "non-connected state\n"); } } @@ -945,7 +933,7 @@ static int lbs_setup_firmware(struct lbs_private *priv) goto done; } - lbs_set_mac_packet_filter(priv); + lbs_set_mac_control(priv); ret = lbs_get_data_rate(priv); if (ret < 0) { @@ -985,6 +973,18 @@ out: lbs_deb_leave(LBS_DEB_CMD); } +static void lbs_sync_channel_worker(struct work_struct *work) +{ + struct lbs_private *priv = container_of(work, struct lbs_private, + sync_channel); + + lbs_deb_enter(LBS_DEB_MAIN); + if (lbs_update_channel(priv)) + lbs_pr_info("Channel synchronization failed."); + lbs_deb_leave(LBS_DEB_MAIN); +} + + static int lbs_init_adapter(struct lbs_private *priv) { size_t bufsize; @@ -1009,14 +1009,6 @@ static int lbs_init_adapter(struct lbs_private *priv) &priv->network_free_list); } - priv->lbs_ps_confirm_sleep.seqnum = cpu_to_le16(++priv->seqnum); - priv->lbs_ps_confirm_sleep.command = - cpu_to_le16(CMD_802_11_PS_MODE); - priv->lbs_ps_confirm_sleep.size = - cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); - priv->lbs_ps_confirm_sleep.action = - cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); - memset(priv->current_addr, 0xff, ETH_ALEN); priv->connect_status = LBS_DISCONNECTED; @@ -1024,7 +1016,7 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; priv->mode = IW_MODE_INFRA; priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; - priv->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; + priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; priv->radioon = RADIO_ON; priv->auto_rate = 1; priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; @@ -1045,7 +1037,18 @@ static int lbs_init_adapter(struct lbs_private *priv) /* Allocate the command buffers */ if (lbs_allocate_cmd_buffer(priv)) { lbs_pr_err("Out of memory allocating command buffers\n"); - ret = -1; + ret = -ENOMEM; + goto out; + } + priv->resp_idx = 0; + priv->resp_len[0] = priv->resp_len[1] = 0; + + /* Create the event FIFO */ + priv->event_fifo = kfifo_alloc(sizeof(u32) * 16, GFP_KERNEL, NULL); + if (IS_ERR(priv->event_fifo)) { + lbs_pr_err("Out of memory allocating event FIFO buffer\n"); + ret = -ENOMEM; + goto out; } out: @@ -1059,6 +1062,8 @@ static void lbs_free_adapter(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_MAIN); lbs_free_cmd_buffer(priv); + if (priv->event_fifo) + kfifo_free(priv->event_fifo); del_timer(&priv->command_timer); kfree(priv->networks); priv->networks = NULL; @@ -1128,7 +1133,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->work_thread = create_singlethread_workqueue("lbs_worker"); INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); - INIT_WORK(&priv->sync_channel, lbs_sync_channel); + INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker); sprintf(priv->mesh_ssid, "mesh"); priv->mesh_ssid_len = 4; @@ -1380,7 +1385,7 @@ static void lbs_remove_mesh(struct lbs_private *priv) * @param cfp_no A pointer to CFP number * @return A pointer to CFP */ -struct chan_freq_power *lbs_get_region_cfp_table(u8 region, u8 band, int *cfp_no) +struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no) { int i, end; @@ -1414,7 +1419,7 @@ int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band) memset(priv->region_channel, 0, sizeof(priv->region_channel)); - cfp = lbs_get_region_cfp_table(region, band, &cfp_no); + cfp = lbs_get_region_cfp_table(region, &cfp_no); if (cfp != NULL) { priv->region_channel[i].nrcfp = cfp_no; priv->region_channel[i].CFP = cfp; @@ -1433,31 +1438,49 @@ out: return ret; } -/** - * @brief This function handles the interrupt. it will change PS - * state if applicable. it will wake up main_thread to handle - * the interrupt event as well. - * - * @param dev A pointer to net_device structure - * @return n/a - */ -void lbs_interrupt(struct lbs_private *priv) +void lbs_queue_event(struct lbs_private *priv, u32 event) +{ + unsigned long flags; + + lbs_deb_enter(LBS_DEB_THREAD); + spin_lock_irqsave(&priv->driver_lock, flags); + + if (priv->psstate == PS_STATE_SLEEP) + priv->psstate = PS_STATE_AWAKE; + + __kfifo_put(priv->event_fifo, (unsigned char *) &event, sizeof(u32)); + + wake_up_interruptible(&priv->waitq); + + spin_unlock_irqrestore(&priv->driver_lock, flags); + lbs_deb_leave(LBS_DEB_THREAD); +} +EXPORT_SYMBOL_GPL(lbs_queue_event); + +void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx) { lbs_deb_enter(LBS_DEB_THREAD); - lbs_deb_thread("lbs_interrupt: intcounter=%d\n", priv->intcounter); - priv->intcounter++; if (priv->psstate == PS_STATE_SLEEP) priv->psstate = PS_STATE_AWAKE; + + /* Swap buffers by flipping the response index */ + BUG_ON(resp_idx > 1); + priv->resp_idx = resp_idx; + wake_up_interruptible(&priv->waitq); lbs_deb_leave(LBS_DEB_THREAD); } -EXPORT_SYMBOL_GPL(lbs_interrupt); +EXPORT_SYMBOL_GPL(lbs_notify_command_response); static int __init lbs_init_module(void) { lbs_deb_enter(LBS_DEB_MAIN); + memset(&confirm_sleep, 0, sizeof(confirm_sleep)); + confirm_sleep.hdr.command = cpu_to_le16(CMD_802_11_PS_MODE); + confirm_sleep.hdr.size = cpu_to_le16(sizeof(confirm_sleep)); + confirm_sleep.action = cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); lbs_debugfs_init(); lbs_deb_leave(LBS_DEB_MAIN); return 0; @@ -1554,6 +1577,32 @@ out: return ret; } +#ifndef CONFIG_IEEE80211 +const char *escape_essid(const char *essid, u8 essid_len) +{ + static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + const char *s = essid; + char *d = escaped; + + if (ieee80211_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "<hidden>", sizeof("<hidden>")); + return escaped; + } + + essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); + while (essid_len--) { + if (*s == '\0') { + *d++ = '\\'; + *d++ = '0'; + s++; + } else { + *d++ = *s++; + } + } + *d = '\0'; + return escaped; +} +#endif module_init(lbs_init_module); module_exit(lbs_exit_module); |