lkml.org 
[lkml]   [2003]   [Jul]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH 2.4] fixes for airo.c
Date
hello

in 2.4.20+ airo.c is broken and can even kill keventd. this patch fixes it:
- sane locking with spinlocks and irqs disabled instead of the buggy locking
with semaphores
- fix transmit code
- safer unload ordering of disable irq, unregister_netdev, kfree
- fix possible loop-forever bug
- fix a buffer overflow

a previous version of the patch is tested by some people with good results.
against 2.4.22-pre6-bk. please apply.


rgds
-daniel


ps: a 2.6 version will follow soon...




--- 1.25/drivers/net/wireless/airo.c Wed Apr 23 19:43:55 2003
+++ edited/airo.c Thu Jul 17 22:19:02 2003
@@ -933,9 +933,8 @@
static void disable_MAC(struct airo_info *ai);
static void enable_interrupts(struct airo_info*);
static void disable_interrupts(struct airo_info*);
-static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
-static u16 sendcommand(struct airo_info *ai, Cmd *pCmd);
-static void completecommand(struct airo_info *ai, Resp *pRsp);
+static int issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
+static int issuecommand_nolock(struct airo_info*, Cmd *pCmd, Resp *pRsp);
static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
int whichbap);
@@ -945,13 +944,14 @@
int whichbap);
static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len);
+static int PC4500_readrid_nolock(struct airo_info*, u16 rid, void *pBuf, int len);
static int PC4500_writerid(struct airo_info*, u16 rid, const void
*pBuf, int len);
static int do_writerid( struct airo_info*, u16 rid, const void *rid_data,
int len );
static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw);
-static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket);
-static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket);
+static int transmit_802_3_packet(struct airo_info*, u16 txFid, char *pPacket, int len);
+static int transmit_802_11_packet(struct airo_info*, u16 txFid, char *pPacket, int len);

static void airo_interrupt( int irq, void* dev_id, struct pt_regs
*regs);
@@ -987,12 +987,11 @@
struct timer_list timer;
struct proc_dir_entry *proc_entry;
struct airo_info *next;
- spinlock_t aux_lock;
+ spinlock_t main_lock;
unsigned long flags;
#define FLAG_PROMISC IFF_PROMISC /* 0x100 - include/linux/if.h */
#define FLAG_RADIO_OFF 0x02 /* User disabling of MAC */
#define FLAG_RADIO_DOWN 0x08 /* ifup/ifdown disabling of MAC */
-#define FLAG_LOCKED 2 /* 0x04 - use as a bit offset */
#define FLAG_FLASHING 0x10
#define FLAG_ADHOC 0x01 /* Needed by MIC */
#define FLAG_MIC_CAPABLE 0x20
@@ -1003,14 +1002,8 @@
int whichbap);
unsigned short *flash;
tdsRssiEntry *rssi;
- struct semaphore sem;
struct task_struct *task;
struct tq_struct promisc_task;
- struct {
- struct sk_buff *skb;
- int fid;
- struct tq_struct task;
- } xmit, xmit11;
struct net_device *wifidev;
#ifdef WIRELESS_EXT
struct iw_statistics wstats; // wireless stats
@@ -1051,10 +1044,8 @@
if (first == 1) {
memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LISTBSS;
- if (down_interruptible(&ai->sem))
- return -ERESTARTSYS;
issuecommand(ai, &cmd, &rsp);
- up(&ai->sem);
+
/* Let the command take effect */
set_current_state (TASK_INTERRUPTIBLE);
ai->task = current;
@@ -1199,7 +1190,7 @@
statr->len = le16_to_cpu(statr->len);
for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s);

- for(s = &statr->beaconPeriod; s <= &statr->_reserved[9]; s++)
+ for(s = &statr->beaconPeriod; s <= &statr->_reserved1; s++)
*s = le16_to_cpu(*s);

return rc;
@@ -1312,44 +1303,15 @@
}
}

-static void airo_do_xmit(struct net_device *dev) {
- u16 status;
- int i;
- struct airo_info *priv = dev->priv;
- struct sk_buff *skb = priv->xmit.skb;
- int fid = priv->xmit.fid;
- u32 *fids = priv->fids;
-
- if (down_trylock(&priv->sem) != 0) {
- netif_stop_queue(dev);
- priv->xmit.task.routine = (void (*)(void *))airo_do_xmit;
- priv->xmit.task.data = (void *)dev;
- schedule_task(&priv->xmit.task);
- return;
- }
- status = transmit_802_3_packet (priv, fids[fid], skb->data);
- up(&priv->sem);
-
- i = 0;
- if ( status == SUCCESS ) {
- dev->trans_start = jiffies;
- for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++);
- } else {
- priv->fids[fid] &= 0xffff;
- priv->stats.tx_window_errors++;
- }
- if (i < MAX_FIDS / 2)
- netif_wake_queue(dev);
- else
- netif_stop_queue(dev);
- dev_kfree_skb(skb);
-}
-
-static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
- s16 len;
+static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ int len;
int i;
+ int ret = 0;
+ int status;
+ unsigned long flags;
struct airo_info *priv = dev->priv;
- u32 *fids = priv->fids;
+ int *fids = priv->fids;

if ( skb == NULL ) {
printk( KERN_ERR "airo: skb == NULL!!!\n" );
@@ -1357,61 +1319,50 @@
}

/* Find a vacant FID */
- for( i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++ );
+ spin_lock_irqsave(&priv->main_lock, flags);
+ for (i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++);

- if ( i == MAX_FIDS / 2 ) {
- priv->stats.tx_fifo_errors++;
- dev_kfree_skb(skb);
- } else {
- /* check min length*/
- len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- /* Mark fid as used & save length for later */
- fids[i] |= (len << 16);
- priv->xmit.skb = skb;
- priv->xmit.fid = i;
- airo_do_xmit(dev);
- }
- return 0;
-}
-
-static void airo_do_xmit11(struct net_device *dev) {
- u16 status;
- int i;
- struct airo_info *priv = dev->priv;
- struct sk_buff *skb = priv->xmit11.skb;
- int fid = priv->xmit11.fid;
- u32 *fids = priv->fids;
-
- if (down_trylock(&priv->sem) != 0) {
+ if (i + 1 >= MAX_FIDS / 2) {
netif_stop_queue(dev);
- priv->xmit11.task.routine = (void (*)(void *))airo_do_xmit11;
- priv->xmit11.task.data = (void *)dev;
- schedule_task(&priv->xmit11.task);
- return;
+
+ /* we cannot transmit */
+ if (i == MAX_FIDS / 2) {
+ priv->stats.tx_fifo_errors++;
+ ret = 1;
+ goto tx_done;
+ }
}
- status = transmit_802_11_packet (priv, fids[fid], skb->data);
- up(&priv->sem);
+
+ /* check min length*/
+ len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ status = transmit_802_3_packet (priv, fids[i], skb->data, len);

- i = MAX_FIDS / 2;
- if ( status == SUCCESS ) {
+ if (status == SUCCESS) {
+ /* Mark fid as used & save length for later */
+ fids[i] |= (len << 16);
dev->trans_start = jiffies;
- for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++);
- } else {
- priv->fids[fid] &= 0xffff;
+ }
+ else {
priv->stats.tx_window_errors++;
+ ret = 1;
}
- if (i < MAX_FIDS)
- netif_wake_queue(dev);
- else
- netif_stop_queue(dev);
- dev_kfree_skb(skb);
+
+tx_done:
+ spin_unlock_irqrestore(&priv->main_lock, flags);
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
}

-static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
- s16 len;
+static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev)
+{
+ int len;
int i;
+ int ret = 0;
+ int status;
+ unsigned long flags;
struct airo_info *priv = dev->priv;
- u32 *fids = priv->fids;
+ int *fids = priv->fids;

if ( skb == NULL ) {
printk( KERN_ERR "airo: skb == NULL!!!\n" );
@@ -1419,21 +1370,39 @@
}

/* Find a vacant FID */
+ spin_lock_irqsave(&priv->main_lock, flags);
for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ );

- if ( i == MAX_FIDS ) {
- priv->stats.tx_fifo_errors++;
- dev_kfree_skb(skb);
- } else {
- /* check min length*/
- len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- /* Mark fid as used & save length for later */
+ if (i + 1 >= MAX_FIDS) {
+ netif_stop_queue(dev);
+
+ /* we cannot transmit */
+ if (i == MAX_FIDS) {
+ priv->stats.tx_fifo_errors++;
+ ret = 1;
+ goto tx_done;
+ }
+ }
+
+ /* check min length*/
+ len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ status = transmit_802_11_packet (priv, fids[i], skb->data, len);
+
+ if (status == SUCCESS) {
+ /* Mark fid as used & save length for later */
fids[i] |= (len << 16);
- priv->xmit11.skb = skb;
- priv->xmit11.fid = i;
- airo_do_xmit11(dev);
+ dev->trans_start = jiffies;
}
- return 0;
+ else {
+ priv->stats.tx_window_errors++;
+ ret = 1;
+ }
+
+tx_done:
+ spin_unlock_irqrestore(&priv->main_lock, flags);
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
}

struct net_device_stats *airo_get_stats(struct net_device *dev)
@@ -1463,36 +1432,19 @@
return &local->stats;
}

-static void airo_end_promisc(struct airo_info *ai) {
- Resp rsp;
-
- if ((IN4500(ai, EVSTAT) & EV_CMD) != 0) {
- completecommand(ai, &rsp);
- up(&ai->sem);
- } else {
- ai->promisc_task.routine = (void (*)(void *))airo_end_promisc;
- ai->promisc_task.data = (void *)ai;
- schedule_task(&ai->promisc_task);
- }
-}
-
-static void airo_set_promisc(struct airo_info *ai) {
+static void airo_set_promisc(struct airo_info *ai)
+{
Cmd cmd;
+ Resp rsp;

- if (down_trylock(&ai->sem) == 0) {
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd=CMD_SETMODE;
- cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
- sendcommand(ai, &cmd);
- airo_end_promisc(ai);
- } else {
- ai->promisc_task.routine = (void (*)(void *))airo_set_promisc;
- ai->promisc_task.data = (void *)ai;
- schedule_task(&ai->promisc_task);
- }
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.cmd = CMD_SETMODE;
+ cmd.parm0 = (ai->flags & IFF_PROMISC) ? PROMISC : NOPROMISC;
+ issuecommand(ai, &cmd, &rsp);
}

-static void airo_set_multicast_list(struct net_device *dev) {
+static void airo_set_multicast_list(struct net_device *dev)
+{
struct airo_info *ai = dev->priv;

if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
@@ -1557,11 +1509,10 @@
{
struct airo_info *ai = dev->priv;
flush_scheduled_tasks();
- if (ai->flash)
- kfree(ai->flash);
- if (ai->rssi)
- kfree(ai->rssi);
- takedown_proc_entry( dev, ai );
+
+ disable_interrupts(ai);
+ free_irq(dev->irq, dev);
+
if (ai->registered) {
unregister_netdev( dev );
if (ai->wifidev) {
@@ -1571,9 +1522,15 @@
}
ai->registered = 0;
}
- disable_interrupts(ai);
- free_irq( dev->irq, dev );
- if (auto_wep) del_timer_sync(&ai->timer);
+
+ if (ai->flash)
+ kfree(ai->flash);
+ if (ai->rssi)
+ kfree(ai->rssi);
+ takedown_proc_entry( dev, ai );
+
+ if (auto_wep)
+ del_timer_sync(&ai->timer);
if (freeres) {
/* PCMCIA frees this stuff, so only for PCI and ISA */
release_region( dev->base_addr, 64 );
@@ -1670,8 +1627,7 @@
ai->wifidev = 0;
ai->registered = 0;
ai->dev = dev;
- ai->aux_lock = SPIN_LOCK_UNLOCKED;
- sema_init(&ai->sem, 1);
+ ai->main_lock = SPIN_LOCK_UNLOCKED;
ai->need_commit = 0;
ai->config.len = 0;
rc = add_airo_dev( dev );
@@ -1736,7 +1692,6 @@
ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2);

setup_proc_entry( dev, dev->priv ); /* XXX check for failure */
- netif_start_queue(dev);
SET_MODULE_OWNER(dev);
return dev;

@@ -1800,47 +1755,31 @@
EXPORT_SYMBOL(reset_airo_card);

#if WIRELESS_EXT > 13
+/* must be called with lock held */
static void airo_send_event(struct net_device *dev) {
struct airo_info *ai = dev->priv;
union iwreq_data wrqu;
StatusRid status_rid;

- if (down_trylock(&ai->sem) == 0) {
- __set_bit(FLAG_LOCKED, &ai->flags);
- PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid));
- clear_bit(FLAG_LOCKED, &ai->flags);
- up(&ai->sem);
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ PC4500_readrid_nolock(ai, RID_STATUS, &status_rid, sizeof(status_rid));

- /* Send event to user space */
- wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
- } else {
- ai->event_task.routine = (void (*)(void *))airo_send_event;
- ai->event_task.data = (void *)dev;
- schedule_task(&ai->event_task);
- }
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+ /* Send event to user space */
+ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
}
#endif

static void airo_read_mic(struct airo_info *ai) {
+#ifdef MICSUPPORT
MICRid mic_rid;

- if (down_trylock(&ai->sem) == 0) {
- __set_bit(FLAG_LOCKED, &ai->flags);
- PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid));
- clear_bit(FLAG_LOCKED, &ai->flags);
- up(&ai->sem);
-#ifdef MICSUPPORT
- micinit (ai, &mic_rid);
+ PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid));
+ micinit (ai, &mic_rid);
#endif
- } else {
- ai->mic_task.routine = (void (*)(void *))airo_read_mic;
- ai->mic_task.data = (void *)ai;
- schedule_task(&ai->mic_task);
- }
}

static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
@@ -1853,6 +1792,7 @@
if (!netif_device_present(dev))
return;

+ spin_lock(&apriv->main_lock);
for (;;) {
status = IN4500( apriv, EVSTAT );
if ( !(status & STATUS_INTS) || status == 0xffff ) break;
@@ -1869,7 +1809,8 @@

if ( status & EV_MIC ) {
OUT4500( apriv, EVACK, EV_MIC );
- airo_read_mic( apriv );
+ if (apriv->flags & FLAG_MIC_CAPABLE)
+ airo_read_mic( apriv );
}
if ( status & EV_LINK ) {
#if WIRELESS_EXT > 13
@@ -2118,10 +2059,14 @@
index = i;
/* Set up to be used again */
apriv->fids[i] &= 0xffff;
+
+ if (i < MAX_FIDS / 2)
+ netif_wake_queue(dev);
+ else
+ netif_wake_queue(apriv->wifidev);
}
}
if (index != -1) {
- netif_wake_queue(dev);
if (status & EV_TXEXC)
get_tx_error(apriv, index);
}
@@ -2137,6 +2082,7 @@

if (savedInterrupts)
OUT4500( apriv, EVINTEN, savedInterrupts );
+ spin_unlock(&apriv->main_lock);

/* done.. */
return;
@@ -2172,8 +2118,8 @@
return rc;
}

-static int enable_MAC( struct airo_info *ai, Resp *rsp ) {
- int rc;
+static int enable_MAC( struct airo_info *ai, Resp *rsp )
+{
Cmd cmd;

/* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions
@@ -2185,45 +2131,41 @@
if (ai->flags & (FLAG_RADIO_OFF|FLAG_RADIO_DOWN)) return SUCCESS;
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_ENABLE;
- if (test_bit(FLAG_LOCKED, &ai->flags) != 0)
- return issuecommand(ai, &cmd, rsp);
-
- if (down_interruptible(&ai->sem))
- return -ERESTARTSYS;
- rc = issuecommand(ai, &cmd, rsp);
- up(&ai->sem);
- return rc;
+ return issuecommand(ai, &cmd, rsp);
}

-static void disable_MAC( struct airo_info *ai ) {
+static void disable_MAC(struct airo_info *ai)
+{
Cmd cmd;
Resp rsp;

memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_DISABLE; // disable in case already enabled
- if (test_bit(FLAG_LOCKED, &ai->flags) != 0) {
- issuecommand(ai, &cmd, &rsp);
- return;
- }
-
- if (down_interruptible(&ai->sem))
- return;
issuecommand(ai, &cmd, &rsp);
- up(&ai->sem);
}

-static void enable_interrupts( struct airo_info *ai ) {
+static void enable_interrupts(struct airo_info *ai)
+{
+ unsigned long flags;
+ u16 status;
+ spin_lock_irqsave(&ai->main_lock, flags);
+
/* Reset the status register */
- u16 status = IN4500( ai, EVSTAT );
+ status = IN4500( ai, EVSTAT );
OUT4500( ai, EVACK, status );
+
/* Enable the interrupts */
OUT4500( ai, EVINTEN, STATUS_INTS );
- /* Note there is a race condition between the last two lines that
- I dont know how to get rid of right now... */
+
+ spin_unlock_irqrestore(&ai->main_lock, flags);
}

-static void disable_interrupts( struct airo_info *ai ) {
+static void disable_interrupts(struct airo_info *ai)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&ai->main_lock, flags);
OUT4500( ai, EVINTEN, 0 );
+ spin_unlock_irqrestore(&ai->main_lock, flags);
}

static u16 setup_card(struct airo_info *ai, u8 *mac)
@@ -2246,23 +2188,20 @@
/* The NOP is the first step in getting the card going */
cmd.cmd = NOP;
cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
- if (down_interruptible(&ai->sem))
+ if (spin_is_locked(&ai->main_lock))
return ERROR;
- if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
- up(&ai->sem);
+ if (issuecommand(ai, &cmd, &rsp) != SUCCESS)
return ERROR;
- }
+
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_DISABLE; // disable in case already enabled
- if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
- up(&ai->sem);
+ if (issuecommand( ai, &cmd, &rsp) != SUCCESS )
return ERROR;
- }
+

// Let's figure out if we need to use the AUX port
cmd.cmd = CMD_ENABLEAUX;
if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
- up(&ai->sem);
printk(KERN_ERR "airo: Error checking for AUX port\n");
return ERROR;
}
@@ -2273,7 +2212,7 @@
ai->bap_read = aux_bap_read;
printk(KERN_DEBUG "airo: Doing AUX bap_reads\n");
}
- up(&ai->sem);
+
if (ai->config.len == 0) {
tdsRssiRid rssi_rid;
CapabilityRid cap_rid;
@@ -2378,50 +2317,35 @@
}
return SUCCESS;
}
+static int issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
+ int rc;
+ unsigned long flags;

-static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
- // Im really paranoid about letting it run forever!
- int max_tries = 600000;
-
- if (sendcommand(ai, pCmd) == (u16)ERROR)
- return ERROR;
-
- while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
- if (!in_interrupt() && (max_tries & 255) == 0)
- schedule();
- }
- if ( max_tries == -1 ) {
- printk( KERN_ERR
- "airo: Max tries exceeded waiting for command\n" );
- return ERROR;
- }
- completecommand(ai, pRsp);
- return SUCCESS;
+ spin_lock_irqsave(&ai->main_lock, flags);
+ rc = issuecommand_nolock(ai, pCmd, pRsp);
+ spin_unlock_irqrestore(&ai->main_lock, flags);
+ return rc;
}

-static u16 sendcommand(struct airo_info *ai, Cmd *pCmd) {
- // Im really paranoid about letting it run forever!
+static int issuecommand_nolock(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
+ // Im really paranoid about letting it run forever!
int max_tries = 600000;
- u16 cmd;

OUT4500(ai, PARAM0, pCmd->parm0);
OUT4500(ai, PARAM1, pCmd->parm1);
OUT4500(ai, PARAM2, pCmd->parm2);
OUT4500(ai, COMMAND, pCmd->cmd);
- while ( max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0 &&
- (cmd = IN4500(ai, COMMAND)) != 0 )
- if (cmd == pCmd->cmd)
- // PC4500 didn't notice command, try again
- OUT4500(ai, COMMAND, pCmd->cmd);
- if ( max_tries == -1 ) {
+ while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
+ if (IN4500(ai, COMMAND) == pCmd->cmd) {
+ // PC4500 didn't notice command, try again
+ OUT4500(ai, COMMAND, pCmd->cmd);
+ }
+ }
+ if (max_tries == -1) {
printk( KERN_ERR
"airo: Max tries exceeded when issueing command\n" );
return ERROR;
}
- return SUCCESS;
-}
-
-static void completecommand(struct airo_info *ai, Resp *pRsp) {
// command completed
pRsp->status = IN4500(ai, STATUS);
pRsp->rsp0 = IN4500(ai, RESP0);
@@ -2434,8 +2358,10 @@
}
// acknowledge processing the status/response
OUT4500(ai, EVACK, EV_CMD);
+ return SUCCESS;
}

+
/* Sets up the bap to start exchange data. whichbap should
* be one of the BAP0 or BAP1 defines. Locks should be held before
* calling! */
@@ -2500,9 +2426,7 @@
u16 next;
int words;
int i;
- long flags;

- spin_lock_irqsave(&ai->aux_lock, flags);
page = IN4500(ai, SWS0+whichbap);
offset = IN4500(ai, SWS2+whichbap);
next = aux_setup(ai, page, offset, &len);
@@ -2522,7 +2446,6 @@
next = aux_setup(ai, next, 4, &len);
}
}
- spin_unlock_irqrestore(&ai->aux_lock, flags);
return SUCCESS;
}

@@ -2561,7 +2484,7 @@
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = accmd;
cmd.parm0 = rid;
- status = issuecommand(ai, &cmd, &rsp);
+ status = issuecommand_nolock(ai, &cmd, &rsp);
if (status != 0) return status;
if ( (rsp.status & 0x7F00) != 0) {
return (accmd << 8) + (rsp.rsp0 & 0xFF);
@@ -2570,25 +2493,16 @@
}

/* Note, that we are using BAP1 which is also used by transmit, so
- * we must get a lock. */
-static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len)
+ * it must be called with main_lock held. */
+static int PC4500_readrid_nolock(struct airo_info *ai, u16 rid, void *pBuf, int len)
{
- u16 status, dolock = 0;
- int rc = SUCCESS;
+ u16 status;
+
+ if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS)
+ return status;
+ if (bap_setup(ai, rid, 0, BAP1) != SUCCESS)
+ return ERROR;

- if (test_bit(FLAG_LOCKED, &ai->flags) == 0) {
- dolock = 1;
- if (down_interruptible(&ai->sem))
- return ERROR;
- }
- if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS) {
- rc = status;
- goto done;
- }
- if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
- rc = ERROR;
- goto done;
- }
// read the rid length field
bap_read(ai, pBuf, 2, BAP1);
// length for remaining part of rid
@@ -2599,30 +2513,34 @@
"airo: Rid %x has a length of %d which is too short\n",
(int)rid,
(int)len );
- rc = ERROR;
- goto done;
+ return ERROR;
}
// read remainder of the rid
- rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
-done:
- if (dolock)
- up(&ai->sem);
- return rc;
+ return bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
}

+static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&ai->main_lock, flags);
+ rc = PC4500_readrid_nolock(ai, rid, pBuf, len);
+ spin_unlock_irqrestore(&ai->main_lock, flags);
+ return rc;
+}
/* Note, that we are using BAP1 which is also used by transmit, so
* make sure this isnt called when a transmit is happening */
static int PC4500_writerid(struct airo_info *ai, u16 rid,
const void *pBuf, int len)
{
- u16 status, dolock = 0;
+ u16 status;
+ unsigned long flags;
int rc = SUCCESS;

- if (test_bit(FLAG_LOCKED, &ai->flags) == 0) {
- dolock = 1;
- if (down_interruptible(&ai->sem))
- return ERROR;
- }
+ *(u16*)pBuf = cpu_to_le16((u16)len);
+
+ spin_lock_irqsave(&ai->main_lock, flags);
// --- first access so that we can write the rid data
if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
rc = status;
@@ -2636,9 +2554,8 @@
bap_write(ai, pBuf, len, BAP1);
// ---now commit the rid data
rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
- done:
- if (dolock)
- up(&ai->sem);
+done:
+ spin_unlock_irqrestore(&ai->main_lock, flags);
return rc;
}

@@ -2646,6 +2563,8 @@
one for now. */
static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
{
+ unsigned long flags;
+ unsigned int loop = 3000;
Cmd cmd;
Resp rsp;
u16 txFid;
@@ -2653,20 +2572,25 @@

cmd.cmd = CMD_ALLOCATETX;
cmd.parm0 = lenPayload;
- if (down_interruptible(&ai->sem))
- return ERROR;
- if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
- txFid = 0;
+ spin_lock_irqsave(&ai->main_lock, flags);
+ if (issuecommand_nolock(ai, &cmd, &rsp) != SUCCESS) {
+ txFid = ERROR;
goto done;
}
if ( (rsp.status & 0xFF00) != 0) {
- txFid = 0;
+ txFid = ERROR;
goto done;
}
+
/* wait for the allocate event/indication
- * It makes me kind of nervous that this can just sit here and spin,
- * but in practice it only loops like four times. */
- while ( (IN4500(ai, EVSTAT) & EV_ALLOC) == 0) ;
+ * in practice it only loops like four times. */
+ while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop)
+ ; /* nada */
+ if (!loop) {
+ txFid = ERROR;
+ goto done;
+ }
+
// get the allocated fid and acknowledge
txFid = IN4500(ai, TXALLOCFID);
OUT4500(ai, EVACK, EV_ALLOC);
@@ -2688,7 +2612,7 @@
bap_write(ai, &txControl, sizeof(txControl), BAP1);

done:
- up(&ai->sem);
+ spin_unlock_irqrestore(&ai->main_lock, flags);

return txFid;
}
@@ -2696,17 +2620,14 @@
/* In general BAP1 is dedicated to transmiting packets. However,
since we need a BAP when accessing RIDs, we also use BAP1 for that.
Make sure the BAP1 spinlock is held when this is called. */
-static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
+static int transmit_802_3_packet(struct airo_info *ai, u16 txFid, char *pPacket, int len)
{
u16 payloadLen;
Cmd cmd;
Resp rsp;
int miclen = 0;
- u16 txFid = len;
MICBuffer pMic;

- len >>= 16;
-
if (len < ETH_ALEN * 2) {
printk( KERN_WARNING "Short packet %d\n", len );
return ERROR;
@@ -2737,12 +2658,12 @@
memset( &cmd, 0, sizeof( cmd ) );
cmd.cmd = CMD_TRANSMIT;
cmd.parm0 = txFid;
- if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
+ if (issuecommand_nolock(ai, &cmd, &rsp) != SUCCESS) return ERROR;
if ( (rsp.status & 0xFF00) != 0) return ERROR;
return SUCCESS;
}

-static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
+static int transmit_802_11_packet(struct airo_info *ai, u16 txFid, char *pPacket, int len)
{
u16 fc, payloadLen;
Cmd cmd;
@@ -2753,8 +2674,6 @@
u16 gaplen;
u8 gap[6];
} gap;
- u16 txFid = len;
- len >>= 16;
gap.gaplen = 6;

fc = le16_to_cpu(*(const u16*)pPacket);
@@ -2796,7 +2715,7 @@
memset( &cmd, 0, sizeof( cmd ) );
cmd.cmd = CMD_TRANSMIT;
cmd.parm0 = txFid;
- if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
+ if (issuecommand_nolock(ai, &cmd, &rsp) != SUCCESS) return ERROR;
if ( (rsp.status & 0xFF00) != 0) return ERROR;
return SUCCESS;
}
@@ -3865,10 +3784,7 @@

memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LISTBSS;
- if (down_interruptible(&ai->sem))
- return -ERESTARTSYS;
issuecommand(ai, &cmd, &rsp);
- up(&ai->sem);
data->readlen = 0;
return 0;
}
@@ -3932,13 +3848,6 @@

if (!(apriv->flags & FLAG_FLASHING) && (linkstat != 0x400)) {
/* We don't have a link so try changing the authtype */
- if (down_trylock(&apriv->sem) != 0) {
- apriv->timer.expires = RUN_AT(1);
- add_timer(&apriv->timer);
- return;
- }
- __set_bit(FLAG_LOCKED, &apriv->flags);
-
readConfigRid(apriv);
disable_MAC(apriv);
switch(apriv->config.authType) {
@@ -3964,8 +3873,6 @@
apriv->need_commit = 1;
writeConfigRid(apriv);
enable_MAC(apriv, &rsp);
- clear_bit(FLAG_LOCKED, &apriv->flags);
- up(&apriv->sem);

/* Schedule check to see if the change worked */
apriv->timer.expires = RUN_AT(HZ*3);
@@ -4144,7 +4051,11 @@
struct airo_info *local = dev->priv;
StatusRid status_rid; /* Card status info */

- readStatusRid(local, &status_rid);
+ if (local->config.opmode & MODE_STA_ESS)
+ status_rid.channel = local->config.channelSet;
+ else
+ readStatusRid(local, &status_rid);
+

/* Will return zero in infrastructure mode */
#ifdef WEXT_USECHANNELS
@@ -4255,11 +4166,8 @@
return -EINVAL;
else if (!memcmp(bcast, awrq->sa_data, ETH_ALEN)) {
memset(&cmd, 0, sizeof(cmd));
- cmd.cmd=CMD_LOSE_SYNC;
- if (down_interruptible(&local->sem))
- return -ERESTARTSYS;
+ cmd.cmd = CMD_LOSE_SYNC;
issuecommand(local, &cmd, &rsp);
- up(&local->sem);
} else {
memset(&APList_rid, 0, sizeof(APList_rid));
APList_rid.len = sizeof(APList_rid);
@@ -5141,11 +5049,8 @@
/* Initiate a scan command */
memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LISTBSS;
- if (down_interruptible(&ai->sem))
- return -ERESTARTSYS;
issuecommand(ai, &cmd, &rsp);
ai->scan_timestamp = jiffies;
- up(&ai->sem);

/* At this point, just return to the user. */

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:46    [W:1.107 / U:0.080 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site