Fixes ipw2100 and ipw2200 after ieee80211 xmit improvements. Signed-off-by: Jiri Benc Signed-off-by: Jirka Bohac Index: netdev/drivers/net/wireless/ipw2200.c =================================================================== --- netdev.orig/drivers/net/wireless/ipw2200.c 2005-09-17 15:09:21.000000000 +0200 +++ netdev/drivers/net/wireless/ipw2200.c 2005-09-17 15:13:01.000000000 +0200 @@ -75,6 +75,8 @@ static int ipw_config(struct ipw_priv *) static int init_supported_rates(struct ipw_priv *priv, struct ipw_supported_rates *prates); +static void ipw_txb_free(struct ipw_txb *txb); + static u8 band_b_active_channel[MAX_B_CHANNELS] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0 }; @@ -1070,7 +1072,7 @@ static void ipw_irq_tasklet(struct ipw_p priv->status |= STATUS_RF_KILL_HW; wake_up_interruptible(&priv->wait_command_queue); netif_carrier_off(priv->net_dev); - netif_stop_queue(priv->net_dev); + ieee80211_stop_queue(priv->ieee); cancel_delayed_work(&priv->request_scan); queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); handled |= CX2_INTA_BIT_RF_KILL_DONE; @@ -2766,7 +2768,7 @@ static void ipw_queue_tx_free_tfd(struct pci_unmap_single(dev, bd->u.data.chunk_ptr[i], bd->u.data.chunk_len[i], PCI_DMA_TODEVICE); if (txq->txb[txq->q.last_used]) { - ieee80211_txb_free(txq->txb[txq->q.last_used]); + ipw_txb_free(txq->txb[txq->q.last_used]); txq->txb[txq->q.last_used] = NULL; } } @@ -2831,7 +2833,7 @@ static void inline __maybe_wake_tx(struc return; } } - netif_wake_queue(priv->net_dev); + ieee80211_wake_queue(priv->ieee); } } @@ -3336,14 +3338,14 @@ static inline void ipw_rx_notification(s priv->status |= STATUS_ASSOCIATED; netif_carrier_on(priv->net_dev); - if (netif_queue_stopped(priv->net_dev)) { + if (ieee80211_queue_stopped(priv->net_dev)) { IPW_DEBUG_NOTIF ("waking queue\n"); - netif_wake_queue(priv->net_dev); + ieee80211_wake_queue(priv->net_dev); } else { IPW_DEBUG_NOTIF ("starting queue\n"); - netif_start_queue(priv-> + ieee80211_start_queue(priv-> net_dev); } @@ -3392,7 +3394,7 @@ static inline void ipw_rx_notification(s netif_carrier_off(priv-> net_dev); - netif_stop_queue(priv->net_dev); + ieee80211_stop_queue(priv->net_dev); queue_work(priv->workqueue, &priv->request_scan); notify_wx_assoc_event(priv); @@ -3423,7 +3425,7 @@ static inline void ipw_rx_notification(s STATUS_ASSOCIATING | STATUS_ASSOCIATED | STATUS_AUTH); - netif_stop_queue(priv->net_dev); + ieee80211_stop_queue(priv->net_dev); if (!(priv->status & STATUS_ROAMING)) { netif_carrier_off(priv-> net_dev); @@ -3494,7 +3496,7 @@ static inline void ipw_rx_notification(s STATUS_ASSOCIATED); netif_carrier_off(priv->net_dev); - netif_stop_queue(priv->net_dev); + ieee80211_stop_queue(priv->net_dev); queue_work(priv->workqueue, &priv->request_scan); notify_wx_assoc_event(priv); @@ -6300,14 +6302,14 @@ static int ipw_net_open(struct net_devic /* we should be verifying the device is ready to be opened */ if (!(priv->status & STATUS_RF_KILL_MASK) && (priv->status & STATUS_ASSOCIATED)) - netif_start_queue(dev); + ieee80211_start_queue(ieee80211_dev_to_ieee(dev)); return 0; } static int ipw_net_stop(struct net_device *dev) { IPW_DEBUG_INFO("dev->close\n"); - netif_stop_queue(dev); + ieee80211_stop_queue(ieee80211_dev_to_ieee(dev)); return 0; } @@ -6318,7 +6320,7 @@ modify to send one tfd per fragment inst we need to heavily modify the ieee80211_skb_to_txb. */ -static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) +static inline void ipw_tx_skb(struct ipw_priv *priv, struct ipw_txb *txb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) txb->fragments[0]->data; @@ -6433,38 +6435,87 @@ static inline void ipw_tx_skb(struct ipw ipw_write32(priv, q->reg_w, q->first_empty); if (ipw_queue_space(q) < q->high_mark) - netif_stop_queue(priv->net_dev); + ieee80211_stop_queue(priv->net_dev); return; drop: IPW_DEBUG_DROP("Silently dropping Tx packet.\n"); - ieee80211_txb_free(txb); + ipw_txb_free(txb); } -static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, +static struct ipw_txb *ipw_txb_new(struct sk_buff *skb, + struct ieee80211_xmit_info *info) +{ + struct ipw_txb *txb; + int i; + + txb = kmalloc( + sizeof(struct ipw_txb) + (sizeof(u8*) * info->nr_frags), + GFP_ATOMIC); + if (!txb) + return NULL; + + memset(txb, 0, sizeof(struct ipw_txb)); + txb->nr_frags = info->nr_frags; + txb->frag_size = info->frag_size; + txb->payload_size = info->payload_size; + txb->encrypted = info->encryption; + + for (i = 0; i < info->nr_frags; i++) { + txb->fragments[i] = skb; + if (unlikely(!txb->fragments[i])) { + kfree(txb); + return NULL; + } + skb = skb->next; + } + return txb; +} + +static void ipw_txb_free(struct ipw_txb *txb) +{ + int i; + + if (unlikely(!txb)) + return; + for (i = 0; i < txb->nr_frags; i++) + if (txb->fragments[i]) + dev_kfree_skb_any(txb->fragments[i]); + kfree(txb); +} + +static int ipw_net_hard_start_xmit(struct sk_buff *skb, + struct ieee80211_xmit_info *info, struct ieee80211_device *ieee) { struct ipw_priv *priv = ieee80211_priv(ieee); + struct ipw_txb *txb; unsigned long flags; - IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size); + IPW_DEBUG_TX("dev->xmit(%d bytes)\n", info->payload_size); spin_lock_irqsave(&priv->lock, flags); if (!(priv->status & STATUS_ASSOCIATED)) { IPW_DEBUG_INFO("Tx attempt while not associated.\n"); priv->ieee->stats.tx_carrier_errors++; - netif_stop_queue(ieee80211_dev(ieee)); goto fail_unlock; } + txb = ipw_txb_new(skb, info); + if (unlikely(!txb)) { + printk(KERN_WARNING "%s: Could not allocate TXB\n", + ieee80211_dev(ieee)->name); + goto fail_unlock; + } ipw_tx_skb(priv, txb); spin_unlock_irqrestore(&priv->lock, flags); return 0; fail_unlock: + ieee80211_stop_queue(ieee); spin_unlock_irqrestore(&priv->lock, flags); return 1; } @@ -6866,7 +6917,7 @@ static int ipw_up(struct ipw_priv *priv) if (!rc) { IPW_DEBUG_INFO("Configured device on count %i\n", i); priv->notif_missed_beacons = 0; - netif_start_queue(priv->net_dev); + ieee80211_start_queue(priv->ieee); return 0; } else { IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", @@ -6901,7 +6952,7 @@ static void ipw_down(struct ipw_priv *pr priv->status &= STATUS_RF_KILL_MASK; netif_carrier_off(priv->net_dev); - netif_stop_queue(priv->net_dev); + ieee80211_stop_queue(priv->ieee); ipw_stop_nic(priv); } Index: netdev/drivers/net/wireless/ipw2100.c =================================================================== --- netdev.orig/drivers/net/wireless/ipw2100.c 2005-09-17 15:06:10.000000000 +0200 +++ netdev/drivers/net/wireless/ipw2100.c 2005-09-17 15:13:01.000000000 +0200 @@ -298,6 +298,8 @@ static const char *command_types[] = { }; #endif +static void ipw_txb_free(struct ipw_txb *txb); + /* Pre-decl until we get the code solid and then we can clean it up */ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv); @@ -683,7 +685,7 @@ static inline void schedule_reset(struct IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n", priv->net_dev->name, priv->reset_backoff); netif_carrier_off(priv->net_dev); - netif_stop_queue(priv->net_dev); + ieee80211_stop_queue(priv->ieee); priv->status |= STATUS_RESET_PENDING; if (priv->reset_backoff) queue_delayed_work(priv->workqueue, &priv->reset_work, @@ -1854,7 +1856,7 @@ static void ipw2100_down(struct ipw2100_ priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); netif_carrier_off(priv->net_dev); - netif_stop_queue(priv->net_dev); + ieee80211_stop_queue(priv->ieee); } static void ipw2100_reset_adapter(struct ipw2100_priv *priv) @@ -2057,7 +2059,7 @@ static void isr_indicate_association_los memset(priv->ieee->bssid, 0, ETH_ALEN); netif_carrier_off(priv->net_dev); - netif_stop_queue(priv->net_dev); + ieee80211_stop_queue(priv->ieee); if (!(priv->status & STATUS_RUNNING)) return; @@ -2797,7 +2799,7 @@ static inline int __ipw2100_tx_process(s } priv->ieee->stats.tx_bytes += packet->info.d_struct.txb->payload_size; - ieee80211_txb_free(packet->info.d_struct.txb); + ipw_txb_free(packet->info.d_struct.txb); packet->info.d_struct.txb = NULL; list_add_tail(element, &priv->tx_free_list); @@ -2806,11 +2808,11 @@ static inline int __ipw2100_tx_process(s /* We have a free slot in the Tx queue, so wake up the * transmit layer if it is stopped. */ if (priv->status & STATUS_ASSOCIATED && - netif_queue_stopped(priv->net_dev)) { + ieee80211_queue_stopped(priv->ieee)) { IPW_DEBUG_INFO(KERN_INFO "%s: Waking net queue.\n", priv->net_dev->name); - netif_wake_queue(priv->net_dev); + ieee80211_wake_queue(priv->ieee); } /* A packet was processed by the hardware, so update the @@ -3270,7 +3272,50 @@ static irqreturn_t ipw2100_interrupt(int return IRQ_NONE; } -static int ipw2100_tx(struct ieee80211_txb *txb, struct ieee80211_device *ieee) +static struct ipw_txb *ipw_txb_new(struct sk_buff *skb, + struct ieee80211_xmit_info *info) +{ + struct ipw_txb *txb; + int i; + + txb = kmalloc( + sizeof(struct ipw_txb) + (sizeof(u8*) * info->nr_frags), + GFP_ATOMIC); + if (!txb) + return NULL; + + memset(txb, 0, sizeof(struct ipw_txb)); + txb->nr_frags = info->nr_frags; + txb->frag_size = info->frag_size; + txb->payload_size = info->payload_size; + txb->encrypted = info->encryption; + + for (i = 0; i < info->nr_frags; i++) { + txb->fragments[i] = skb; + if (unlikely(!txb->fragments[i])) { + kfree(txb); + return NULL; + } + skb = skb->next; + } + return txb; +} + +static void ipw_txb_free(struct ipw_txb *txb) +{ + int i; + + if (unlikely(!txb)) + return; + for (i = 0; i < txb->nr_frags; i++) + if (txb->fragments[i]) + dev_kfree_skb_any(txb->fragments[i]); + kfree(txb); +} + +static int ipw2100_tx(struct sk_buff *skb, + struct ieee80211_xmit_info *info, + struct ieee80211_device *ieee) { struct ipw2100_priv *priv = ieee80211_priv(ieee); struct list_head *element; @@ -3282,7 +3327,6 @@ static int ipw2100_tx(struct ieee80211_t if (!(priv->status & STATUS_ASSOCIATED)) { IPW_DEBUG_INFO("Can not transmit when not connected.\n"); priv->ieee->stats.tx_carrier_errors++; - netif_stop_queue(ieee80211_dev(ieee)); goto fail_unlock; } @@ -3292,12 +3336,17 @@ static int ipw2100_tx(struct ieee80211_t element = priv->tx_free_list.next; packet = list_entry(element, struct ipw2100_tx_packet, list); - packet->info.d_struct.txb = txb; + packet->info.d_struct.txb = ipw_txb_new(skb, info); + if (unlikely(!packet->info.d_struct.txb)) { + printk(KERN_WARNING "%s: Could not allocate TXB\n", + ieee80211_dev(ieee)->name); + goto fail_unlock; + } IPW_DEBUG_TX("Sending fragment (%d bytes):\n", - txb->fragments[0]->len - IEEE80211_FCS_LEN); - printk_buf(IPW_DL_TX, txb->fragments[0]->data, - txb->fragments[0]->len - IEEE80211_FCS_LEN); + packet->info.d_struct.txb->fragments[0]->len - IEEE80211_FCS_LEN); + printk_buf(IPW_DL_TX, packet->info.d_struct.txb->fragments[0]->data, + packet->info.d_struct.txb->fragments[0]->len - IEEE80211_FCS_LEN); packet->jiffy_start = jiffies; @@ -3313,7 +3362,7 @@ static int ipw2100_tx(struct ieee80211_t return 0; fail_unlock: - netif_stop_queue(ieee80211_dev(ieee)); + ieee80211_stop_queue(ieee); spin_unlock_irqrestore(&priv->low_lock, flags); return 1; } @@ -4356,7 +4405,7 @@ static void ipw2100_tx_initialize(struct /* We simply drop any SKBs that have been queued for * transmit */ if (priv->tx_buffers[i].info.d_struct.txb) { - ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb); + ipw_txb_free(priv->tx_buffers[i].info.d_struct.txb); priv->tx_buffers[i].info.d_struct.txb = NULL; } @@ -4394,7 +4443,7 @@ static void ipw2100_tx_free(struct ipw21 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { if (priv->tx_buffers[i].info.d_struct.txb) { - ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb); + ipw_txb_free(priv->tx_buffers[i].info.d_struct.txb); priv->tx_buffers[i].info.d_struct.txb = NULL; } if (priv->tx_buffers[i].info.d_struct.data) @@ -5683,7 +5732,7 @@ static int ipw2100_open(struct net_devic spin_lock_irqsave(&priv->low_lock, flags); if (priv->status & STATUS_ASSOCIATED) { netif_carrier_on(dev); - netif_start_queue(dev); + ieee80211_start_queue(ieee80211_dev_to_ieee(dev)); } spin_unlock_irqrestore(&priv->low_lock, flags); @@ -5703,7 +5752,7 @@ static int ipw2100_close(struct net_devi if (priv->status & STATUS_ASSOCIATED) netif_carrier_off(dev); - netif_stop_queue(dev); + ieee80211_stop_queue(ieee80211_dev_to_ieee(dev)); /* Flush the TX queue ... */ while (!list_empty(&priv->tx_pend_list)) { @@ -5713,7 +5762,7 @@ static int ipw2100_close(struct net_devi list_del(element); DEC_STAT(&priv->tx_pend_stat); - ieee80211_txb_free(packet->info.d_struct.txb); + ipw_txb_free(packet->info.d_struct.txb); packet->info.d_struct.txb = NULL; list_add_tail(element, &priv->tx_free_list); @@ -8343,12 +8392,12 @@ static void ipw2100_wx_event_work(struct priv->status &= ~STATUS_ASSOCIATING; priv->status |= STATUS_ASSOCIATED; netif_carrier_on(priv->net_dev); - if (netif_queue_stopped(priv->net_dev)) { + if (ieee80211_queue_stopped(priv->ieee)) { IPW_DEBUG_INFO("Waking net queue.\n"); - netif_wake_queue(priv->net_dev); + ieee80211_wake_queue(priv->ieee); } else { IPW_DEBUG_INFO("Starting net queue.\n"); - netif_start_queue(priv->net_dev); + ieee80211_start_queue(priv->ieee); } } Index: netdev/drivers/net/wireless/ipw2100.h =================================================================== --- netdev.orig/drivers/net/wireless/ipw2100.h 2005-09-07 11:20:19.000000000 +0200 +++ netdev/drivers/net/wireless/ipw2100.h 2005-09-17 15:13:01.000000000 +0200 @@ -340,7 +340,7 @@ struct ipw2100_tx_packet { struct { /* DATA */ struct ipw2100_data_header* data; dma_addr_t data_phys; - struct ieee80211_txb *txb; + struct ipw_txb *txb; } d_struct; } info; int jiffy_start; @@ -600,6 +600,16 @@ struct ipw2100_priv { }; +struct ipw_txb { + u8 nr_frags; + u8 encrypted; + u16 reserved; + u16 frag_size; + u16 payload_size; + struct sk_buff *fragments[0]; +}; + + /********************************************************* * Host Command -> From Driver to FW *********************************************************/ Index: netdev/drivers/net/wireless/ipw2200.h =================================================================== --- netdev.orig/drivers/net/wireless/ipw2200.h 2005-09-17 15:06:10.000000000 +0200 +++ netdev/drivers/net/wireless/ipw2200.h 2005-09-17 15:13:01.000000000 +0200 @@ -428,7 +428,7 @@ typedef void destructor_func(const void struct clx2_tx_queue { struct clx2_queue q; struct tfd_frame *bd; - struct ieee80211_txb **txb; + struct ipw_txb **txb; }; /* @@ -1105,6 +1105,15 @@ struct ipw_priv { u32 indirect_byte; }; /*ipw_priv */ +struct ipw_txb { + u8 nr_frags; + u8 encrypted; + u16 reserved; + u16 frag_size; + u16 payload_size; + struct sk_buff *fragments[0]; +}; + /* debug macros */ #ifdef CONFIG_IPW_DEBUG