ok, here we go...can you test the attached patch please? tested to compile only...against 2.4.22-pre5 -daniel
===== airo.c 1.25 vs edited ===== --- 1.25/drivers/net/wireless/airo.c Wed Apr 23 19:43:55 2003 +++ edited/airo.c Sun Jul 13 23:24:57 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 lock_issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp); +static int issuecommand(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); @@ -950,8 +949,8 @@ 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); @@ -988,11 +987,11 @@ 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); + lock_issuecommand(ai, &cmd, &rsp); + /* Let the command take effect */ set_current_state (TASK_INTERRUPTIBLE); ai->task = current; @@ -1312,42 +1303,13 @@ } } -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) { +static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ s16 len; int i; + int ret = 0; + int status; + long flags; struct airo_info *priv = dev->priv; u32 *fids = priv->fids; @@ -1357,59 +1319,48 @@ } /* Find a vacant FID */ - 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; -} + spin_lock_irqsave(&priv->main_lock, flags); + for (i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++); -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) { +static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) +{ s16 len; int i; + int ret = 0; + int status; + long flags; struct airo_info *priv = dev->priv; u32 *fids = priv->fids; @@ -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; + lock_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) { @@ -1671,7 +1623,7 @@ 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 ); @@ -1805,42 +1757,25 @@ 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(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) { @@ -2173,7 +2108,6 @@ } static int enable_MAC( struct airo_info *ai, Resp *rsp ) { - int rc; Cmd cmd; /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions @@ -2185,14 +2119,7 @@ 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 lock_issuecommand(ai, &cmd, rsp); } static void disable_MAC( struct airo_info *ai ) { @@ -2201,15 +2128,7 @@ 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); + lock_issuecommand(ai, &cmd, &rsp); } static void enable_interrupts( struct airo_info *ai ) { @@ -2246,23 +2165,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 (lock_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 ( lock_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); + if (lock_issuecommand(ai, &cmd, &rsp) != SUCCESS) { printk(KERN_ERR "airo: Error checking for AUX port\n"); return ERROR; } @@ -2273,7 +2189,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 +2294,35 @@ } return SUCCESS; } +static int lock_issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { + int rc; + 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(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! - int max_tries = 600000; - u16 cmd; +static int issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { + int max_tries = 3000; 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); + 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 +2335,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! */ @@ -2573,14 +2476,11 @@ * we must get a lock. */ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len) { - u16 status, dolock = 0; + u16 status; + long flags; int rc = SUCCESS; - if (test_bit(FLAG_LOCKED, &ai->flags) == 0) { - dolock = 1; - if (down_interruptible(&ai->sem)) - return ERROR; - } + spin_lock_irqsave(&ai->main_lock, flags); if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS) { rc = status; goto done; @@ -2605,8 +2505,7 @@ // read remainder of the rid rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1); done: - if (dolock) - up(&ai->sem); + spin_unlock_irqrestore(&ai->main_lock, flags); return rc; } @@ -2615,14 +2514,11 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, const void *pBuf, int len) { - u16 status, dolock = 0; + u16 status; + long flags; int rc = SUCCESS; - if (test_bit(FLAG_LOCKED, &ai->flags) == 0) { - dolock = 1; - if (down_interruptible(&ai->sem)) - return ERROR; - } + 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 +2532,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 +2541,7 @@ one for now. */ static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw) { + long flags; Cmd cmd; Resp rsp; u16 txFid; @@ -2653,8 +2549,7 @@ cmd.cmd = CMD_ALLOCATETX; cmd.parm0 = lenPayload; - if (down_interruptible(&ai->sem)) - return ERROR; + spin_lock_irqsave(&ai->main_lock, flags); if (issuecommand(ai, &cmd, &rsp) != SUCCESS) { txFid = 0; goto done; @@ -2688,7 +2583,7 @@ bap_write(ai, &txControl, sizeof(txControl), BAP1); done: - up(&ai->sem); + spin_unlock_irqrestore(&ai->main_lock, flags); return txFid; } @@ -2696,17 +2591,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; @@ -2742,7 +2634,7 @@ 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 +2645,6 @@ u16 gaplen; u8 gap[6]; } gap; - u16 txFid = len; - len >>= 16; gap.gaplen = 6; fc = le16_to_cpu(*(const u16*)pPacket); @@ -3865,10 +3755,7 @@ memset(&cmd, 0, sizeof(cmd)); cmd.cmd=CMD_LISTBSS; - if (down_interruptible(&ai->sem)) - return -ERESTARTSYS; - issuecommand(ai, &cmd, &rsp); - up(&ai->sem); + lock_issuecommand(ai, &cmd, &rsp); data->readlen = 0; return 0; } @@ -3932,13 +3819,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 +3844,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); @@ -4255,11 +4133,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; - issuecommand(local, &cmd, &rsp); - up(&local->sem); + cmd.cmd = CMD_LOSE_SYNC; + lock_issuecommand(local, &cmd, &rsp); } else { memset(&APList_rid, 0, sizeof(APList_rid)); APList_rid.len = sizeof(APList_rid); @@ -5141,11 +5016,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); + lock_issuecommand(ai, &cmd, &rsp); ai->scan_timestamp = jiffies; - up(&ai->sem); /* At this point, just return to the user. */