diff --git a/[refs] b/[refs] index ba115fd1a51a..e3970f04105b 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: eaae44d248b151e7257ba551ae589cf343c3fdf6 +refs/heads/master: d510fe70db4c62ac899c486506fdfb7f3b518c86 diff --git a/trunk/Documentation/networking/operstates.txt b/trunk/Documentation/networking/operstates.txt index 1a77a3cfae54..c9074f9b78bb 100644 --- a/trunk/Documentation/networking/operstates.txt +++ b/trunk/Documentation/networking/operstates.txt @@ -38,6 +38,9 @@ ifinfomsg::if_flags & IFF_LOWER_UP: ifinfomsg::if_flags & IFF_DORMANT: Driver has signaled netif_dormant_on() +These interface flags can also be queried without netlink using the +SIOCGIFFLAGS ioctl. + TLV IFLA_OPERSTATE contains RFC2863 state of the interface in numeric representation: diff --git a/trunk/drivers/isdn/i4l/isdn_net.c b/trunk/drivers/isdn/i4l/isdn_net.c index 34d54e7281fd..cb8943da4f12 100644 --- a/trunk/drivers/isdn/i4l/isdn_net.c +++ b/trunk/drivers/isdn/i4l/isdn_net.c @@ -1069,7 +1069,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) lp = isdn_net_get_locked_lp(nd); if (!lp) { printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); - return NETDEV_TX_BUSY; + return 1; } /* we have our lp locked from now on */ @@ -1273,14 +1273,14 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irqrestore(&dev->lock, flags); isdn_net_dial(); /* Initiate dialing */ netif_stop_queue(ndev); - return NETDEV_TX_BUSY; /* let upper layer requeue skb packet */ + return 1; /* let upper layer requeue skb packet */ } #endif /* Initiate dialing */ spin_unlock_irqrestore(&dev->lock, flags); isdn_net_dial(); isdn_net_device_stop_queue(lp); - return NETDEV_TX_BUSY; + return 1; } else { isdn_net_unreachable(ndev, skb, "No phone number"); diff --git a/trunk/drivers/message/fusion/mptlan.c b/trunk/drivers/message/fusion/mptlan.c index a9e48e28b1dc..c2804f26cb44 100644 --- a/trunk/drivers/message/fusion/mptlan.c +++ b/trunk/drivers/message/fusion/mptlan.c @@ -703,7 +703,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) printk (KERN_ERR "%s: no tx context available: %u\n", __func__, priv->mpt_txfidx_tail); - return NETDEV_TX_BUSY; + return 1; } mf = mpt_get_msg_frame(LanCtx, mpt_dev); @@ -713,7 +713,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) printk (KERN_ERR "%s: Unable to alloc request frame\n", __func__); - return NETDEV_TX_BUSY; + return 1; } ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--]; diff --git a/trunk/drivers/misc/sgi-xp/xpnet.c b/trunk/drivers/misc/sgi-xp/xpnet.c index 8d1c60a3f0df..6faefcffcb53 100644 --- a/trunk/drivers/misc/sgi-xp/xpnet.c +++ b/trunk/drivers/misc/sgi-xp/xpnet.c @@ -450,8 +450,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) "packet\n", sizeof(struct xpnet_pending_msg)); dev->stats.tx_errors++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; + return -ENOMEM; } /* get the beginning of the first cacheline and end of last */ diff --git a/trunk/drivers/net/3c505.c b/trunk/drivers/net/3c505.c index f71b35402755..b28499459cd6 100644 --- a/trunk/drivers/net/3c505.c +++ b/trunk/drivers/net/3c505.c @@ -1088,7 +1088,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) pr_debug("%s: failed to transmit packet\n", dev->name); } spin_unlock_irqrestore(&adapter->lock, flags); - return NETDEV_TX_BUSY; + return 1; } if (elp_debug >= 3) pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len); diff --git a/trunk/drivers/net/3c515.c b/trunk/drivers/net/3c515.c index 3e00fa8ea65f..7fd0ff743757 100644 --- a/trunk/drivers/net/3c515.c +++ b/trunk/drivers/net/3c515.c @@ -1014,7 +1014,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb, int i; if (vp->tx_full) /* No room to transmit with */ - return NETDEV_TX_BUSY; + return 1; if (vp->cur_tx != 0) prev_entry = &vp->tx_ring[(vp->cur_tx - 1) % TX_RING_SIZE]; else diff --git a/trunk/drivers/net/3c527.c b/trunk/drivers/net/3c527.c index aaa8a9f405d4..c10ca30458f6 100644 --- a/trunk/drivers/net/3c527.c +++ b/trunk/drivers/net/3c527.c @@ -1030,7 +1030,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); if(atomic_read(&lp->tx_count)==0) { - return NETDEV_TX_BUSY; + return 1; } if (skb_padto(skb, ETH_ZLEN)) { diff --git a/trunk/drivers/net/3c59x.c b/trunk/drivers/net/3c59x.c index c34aee91250b..a6e8a2da3bcd 100644 --- a/trunk/drivers/net/3c59x.c +++ b/trunk/drivers/net/3c59x.c @@ -2107,7 +2107,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) pr_warning("%s: BUG! Tx Ring full, refusing to send buffer.\n", dev->name); netif_stop_queue(dev); - return NETDEV_TX_BUSY; + return 1; } vp->tx_skbuff[entry] = skb; diff --git a/trunk/drivers/net/7990.c b/trunk/drivers/net/7990.c index 69f5b7d298a6..7a331acc34ad 100644 --- a/trunk/drivers/net/7990.c +++ b/trunk/drivers/net/7990.c @@ -541,7 +541,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) unsigned long flags; if (!TX_BUFFS_AVAIL) - return NETDEV_TX_LOCKED; + return -1; netif_stop_queue (dev); diff --git a/trunk/drivers/net/8139cp.c b/trunk/drivers/net/8139cp.c index 50efde11ea6c..c9fc0ff14a4d 100644 --- a/trunk/drivers/net/8139cp.c +++ b/trunk/drivers/net/8139cp.c @@ -756,7 +756,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&cp->lock, intr_flags); pr_err(PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name); - return NETDEV_TX_BUSY; + return 1; } #if CP_VLAN_TAG_USED diff --git a/trunk/drivers/net/a2065.c b/trunk/drivers/net/a2065.c index 85a18175730b..02f64d578641 100644 --- a/trunk/drivers/net/a2065.c +++ b/trunk/drivers/net/a2065.c @@ -564,7 +564,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) if (!TX_BUFFS_AVAIL){ local_irq_restore(flags); - return NETDEV_TX_LOCKED; + return -1; } #ifdef DEBUG_DRIVER diff --git a/trunk/drivers/net/arm/at91_ether.c b/trunk/drivers/net/arm/at91_ether.c index 2e7419a61191..7f4bc8ae5462 100644 --- a/trunk/drivers/net/arm/at91_ether.c +++ b/trunk/drivers/net/arm/at91_ether.c @@ -829,7 +829,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; } else { printk(KERN_ERR "at91_ether.c: at91ether_start_xmit() called, but device is busy!\n"); - return NETDEV_TX_BUSY; /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb) + return 1; /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb) on this skb, he also reports -ENETDOWN and printk's, so either we free and return(0) or don't free and return 1 */ } diff --git a/trunk/drivers/net/arm/ether3.c b/trunk/drivers/net/arm/ether3.c index 455037134aa3..ec8a1ae1e887 100644 --- a/trunk/drivers/net/arm/ether3.c +++ b/trunk/drivers/net/arm/ether3.c @@ -526,7 +526,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) if (priv(dev)->tx_tail == next_ptr) { local_irq_restore(flags); - return NETDEV_TX_BUSY; /* unable to queue */ + return 1; /* unable to queue */ } dev->trans_start = jiffies; diff --git a/trunk/drivers/net/au1000_eth.c b/trunk/drivers/net/au1000_eth.c index d3c734f4d679..d58c105fc779 100644 --- a/trunk/drivers/net/au1000_eth.c +++ b/trunk/drivers/net/au1000_eth.c @@ -957,7 +957,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) /* We've wrapped around and the transmitter is still busy */ netif_stop_queue(dev); aup->tx_full = 1; - return NETDEV_TX_BUSY; + return 1; } else if (buff_stat & TX_T_DONE) { update_tx_stats(dev, ptxd->status); diff --git a/trunk/drivers/net/cassini.c b/trunk/drivers/net/cassini.c index eb066673c2a0..f5222764061c 100644 --- a/trunk/drivers/net/cassini.c +++ b/trunk/drivers/net/cassini.c @@ -2934,7 +2934,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev) * individual queues. */ if (cas_xmit_tx_ringN(cp, ring++ & N_TX_RINGS_MASK, skb)) - return NETDEV_TX_BUSY; + return 1; dev->trans_start = jiffies; return 0; } diff --git a/trunk/drivers/net/cs89x0.c b/trunk/drivers/net/cs89x0.c index 3eee666a9cd2..7433b88eed7e 100644 --- a/trunk/drivers/net/cs89x0.c +++ b/trunk/drivers/net/cs89x0.c @@ -1551,7 +1551,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&lp->lock); if (net_debug) printk("cs89x0: Tx buffer not free!\n"); - return NETDEV_TX_BUSY; + return 1; } /* Write the contents of the packet */ writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1); diff --git a/trunk/drivers/net/de600.c b/trunk/drivers/net/de600.c index e1af089064bc..c866ca99a068 100644 --- a/trunk/drivers/net/de600.c +++ b/trunk/drivers/net/de600.c @@ -168,14 +168,14 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev) if (free_tx_pages <= 0) { /* Do timeouts, to avoid hangs. */ tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) - return NETDEV_TX_BUSY; + return 1; /* else */ printk(KERN_WARNING "%s: transmit timed out (%d), %s?\n", dev->name, tickssofar, "network cable problem"); /* Restart the adapter. */ spin_lock_irqsave(&de600_lock, flags); if (adapter_init(dev)) { spin_unlock_irqrestore(&de600_lock, flags); - return NETDEV_TX_BUSY; + return 1; } spin_unlock_irqrestore(&de600_lock, flags); } @@ -199,7 +199,7 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev) if (was_down || (de600_read_byte(READ_DATA, dev) != 0xde)) { if (adapter_init(dev)) { spin_unlock_irqrestore(&de600_lock, flags); - return NETDEV_TX_BUSY; + return 1; } } } diff --git a/trunk/drivers/net/de620.c b/trunk/drivers/net/de620.c index 55d2bb67cffa..039bc1acadd3 100644 --- a/trunk/drivers/net/de620.c +++ b/trunk/drivers/net/de620.c @@ -531,7 +531,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev) case (TXBF0 | TXBF1): /* NONE!!! */ printk(KERN_WARNING "%s: No tx-buffer available!\n", dev->name); spin_unlock_irqrestore(&de620_lock, flags); - return NETDEV_TX_BUSY; + return 1; } de620_write_block(dev, buffer, skb->len, len-skb->len); diff --git a/trunk/drivers/net/defxx.c b/trunk/drivers/net/defxx.c index 102b8d439714..4ec055dc7174 100644 --- a/trunk/drivers/net/defxx.c +++ b/trunk/drivers/net/defxx.c @@ -3318,7 +3318,7 @@ static int dfx_xmt_queue_pkt( { skb_pull(skb,3); spin_unlock_irqrestore(&bp->lock, flags); - return NETDEV_TX_BUSY; /* requeue packet for later */ + return(1); /* requeue packet for later */ } /* diff --git a/trunk/drivers/net/depca.c b/trunk/drivers/net/depca.c index 97ea2d6d3fe1..9301eb28d9e2 100644 --- a/trunk/drivers/net/depca.c +++ b/trunk/drivers/net/depca.c @@ -957,7 +957,7 @@ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev) if (TX_BUFFS_AVAIL) netif_start_queue(dev); } else - status = NETDEV_TX_LOCKED; + status = -1; out: return status; @@ -1839,7 +1839,7 @@ static int load_packet(struct net_device *dev, struct sk_buff *skb) lp->tx_new = (++end) & lp->txRingMask; /* update current pointers */ } else { - status = NETDEV_TX_LOCKED; + status = -1; } return status; diff --git a/trunk/drivers/net/dm9000.c b/trunk/drivers/net/dm9000.c index dd771dea6ae6..e402e91bf188 100644 --- a/trunk/drivers/net/dm9000.c +++ b/trunk/drivers/net/dm9000.c @@ -756,7 +756,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) dm9000_dbg(db, 3, "%s:\n", __func__); if (db->tx_pkt_cnt > 1) - return NETDEV_TX_BUSY; + return 1; spin_lock_irqsave(&db->lock, flags); diff --git a/trunk/drivers/net/e100.c b/trunk/drivers/net/e100.c index e52a2018e91e..119dc5300f9d 100644 --- a/trunk/drivers/net/e100.c +++ b/trunk/drivers/net/e100.c @@ -1716,7 +1716,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) /* This is a hard error - log it. */ DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n"); netif_stop_queue(netdev); - return NETDEV_TX_BUSY; + return 1; } netdev->trans_start = jiffies; diff --git a/trunk/drivers/net/ethoc.c b/trunk/drivers/net/ethoc.c index ceb6a9c357ad..91a9b1a33764 100644 --- a/trunk/drivers/net/ethoc.c +++ b/trunk/drivers/net/ethoc.c @@ -811,7 +811,7 @@ static int ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len > ETHOC_BUFSIZ)) { priv->stats.tx_errors++; - goto out; + return -EMSGSIZE; } entry = priv->cur_tx % priv->num_tx; @@ -840,9 +840,9 @@ static int ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) } dev->trans_start = jiffies; - spin_unlock_irq(&priv->lock); -out: dev_kfree_skb(skb); + + spin_unlock_irq(&priv->lock); return NETDEV_TX_OK; } diff --git a/trunk/drivers/net/ewrk3.c b/trunk/drivers/net/ewrk3.c index 1e9723281405..1a685a04d4b2 100644 --- a/trunk/drivers/net/ewrk3.c +++ b/trunk/drivers/net/ewrk3.c @@ -873,7 +873,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev) err_out: ENABLE_IRQs; spin_unlock_irq (&lp->hw_lock); - return NETDEV_TX_BUSY; + return 1; } /* diff --git a/trunk/drivers/net/fec.c b/trunk/drivers/net/fec.c index 0f19b743749b..28db6919c526 100644 --- a/trunk/drivers/net/fec.c +++ b/trunk/drivers/net/fec.c @@ -290,7 +290,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!fep->link) { /* Link is down or autonegotiation is in progress. */ - return NETDEV_TX_BUSY; + return 1; } spin_lock_irqsave(&fep->hw_lock, flags); @@ -305,7 +305,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) */ printk("%s: tx queue full!.\n", dev->name); spin_unlock_irqrestore(&fep->hw_lock, flags); - return NETDEV_TX_BUSY; + return 1; } /* Clear all of the status flags */ diff --git a/trunk/drivers/net/hamachi.c b/trunk/drivers/net/hamachi.c index 9d5b62cb30f7..26151fa35df5 100644 --- a/trunk/drivers/net/hamachi.c +++ b/trunk/drivers/net/hamachi.c @@ -1280,7 +1280,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) status=readw(hmp->base + TxStatus); if( !(status & 0x0001) || (status & 0x0002)) writew(0x0001, hmp->base + TxCmd); - return NETDEV_TX_BUSY; + return 1; } /* Caution: the write order is important here, set the field diff --git a/trunk/drivers/net/hamradio/baycom_epp.c b/trunk/drivers/net/hamradio/baycom_epp.c index 5e4b7afd0683..bb78c11559cd 100644 --- a/trunk/drivers/net/hamradio/baycom_epp.c +++ b/trunk/drivers/net/hamradio/baycom_epp.c @@ -777,7 +777,7 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev) return 0; } if (bc->skb) - return NETDEV_TX_LOCKED; + return -1; /* strip KISS byte */ if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) { dev_kfree_skb(skb); diff --git a/trunk/drivers/net/hamradio/bpqether.c b/trunk/drivers/net/hamradio/bpqether.c index 5105548ad50c..d509b371a562 100644 --- a/trunk/drivers/net/hamradio/bpqether.c +++ b/trunk/drivers/net/hamradio/bpqether.c @@ -274,7 +274,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) if ((newskb = skb_realloc_headroom(skb, AX25_BPQ_HEADER_LEN)) == NULL) { printk(KERN_WARNING "bpqether: out of memory\n"); kfree_skb(skb); - return NETDEV_TX_OK; + return -ENOMEM; } if (skb->sk != NULL) @@ -294,7 +294,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev) if ((dev = bpq_get_ether_dev(dev)) == NULL) { dev->stats.tx_dropped++; kfree_skb(skb); - return NETDEV_TX_OK; + return -ENODEV; } skb->protocol = ax25_type_trans(skb, dev); diff --git a/trunk/drivers/net/hamradio/hdlcdrv.c b/trunk/drivers/net/hamradio/hdlcdrv.c index d034f8ca63cb..61de56e45eed 100644 --- a/trunk/drivers/net/hamradio/hdlcdrv.c +++ b/trunk/drivers/net/hamradio/hdlcdrv.c @@ -409,7 +409,7 @@ static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev) return 0; } if (sm->skb) - return NETDEV_TX_LOCKED; + return -1; netif_stop_queue(dev); sm->skb = skb; return 0; diff --git a/trunk/drivers/net/hamradio/mkiss.c b/trunk/drivers/net/hamradio/mkiss.c index fda2fc83e9a1..032c0db4c410 100644 --- a/trunk/drivers/net/hamradio/mkiss.c +++ b/trunk/drivers/net/hamradio/mkiss.c @@ -531,7 +531,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) if (!netif_running(dev)) { printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); - return NETDEV_TX_BUSY; + return 1; } if (netif_queue_stopped(dev)) { @@ -541,7 +541,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) */ if (time_before(jiffies, dev->trans_start + 20 * HZ)) { /* 20 sec timeout not reached */ - return NETDEV_TX_BUSY; + return 1; } printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name, diff --git a/trunk/drivers/net/ibm_newemac/core.c b/trunk/drivers/net/ibm_newemac/core.c index beb84213b671..806533c831c7 100644 --- a/trunk/drivers/net/ibm_newemac/core.c +++ b/trunk/drivers/net/ibm_newemac/core.c @@ -1484,7 +1484,7 @@ static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev) stop_queue: netif_stop_queue(ndev); DBG2(dev, "stopped TX queue" NL); - return NETDEV_TX_BUSY; + return 1; } /* Tx lock BHs */ diff --git a/trunk/drivers/net/ibmlana.c b/trunk/drivers/net/ibmlana.c index 448098d3b39b..c25bc0bc0b25 100644 --- a/trunk/drivers/net/ibmlana.c +++ b/trunk/drivers/net/ibmlana.c @@ -815,7 +815,7 @@ static int ibmlana_close(struct net_device *dev) static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) { ibmlana_priv *priv = netdev_priv(dev); - int tmplen, addr; + int retval = 0, tmplen, addr; unsigned long flags; tda_t tda; int baddr; @@ -824,6 +824,7 @@ static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) the upper layer is in deep desperation and we simply ignore the frame. */ if (priv->txusedcnt >= TXBUFCNT) { + retval = -EIO; dev->stats.tx_dropped++; goto tx_done; } @@ -873,7 +874,7 @@ static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->lock, flags); tx_done: dev_kfree_skb(skb); - return NETDEV_TX_OK; + return retval; } /* switch receiver mode. */ diff --git a/trunk/drivers/net/irda/Kconfig b/trunk/drivers/net/irda/Kconfig index e6317557a531..f76384221422 100644 --- a/trunk/drivers/net/irda/Kconfig +++ b/trunk/drivers/net/irda/Kconfig @@ -17,6 +17,51 @@ config IRTTY_SIR If unsure, say Y. +config BFIN_SIR + tristate "Blackfin SIR on UART" + depends on BLACKFIN && IRDA + default n + help + Say Y here if your want to enable SIR function on Blackfin UART + devices. + + To activate this driver you can start irattach like: + "irattach irda0 -s" + + Saying M, it will be built as a module named bfin_sir. + + Note that you need to turn off one of the serial drivers for SIR + to use that UART. + +config BFIN_SIR0 + bool "Blackfin SIR on UART0" + depends on BFIN_SIR && !SERIAL_BFIN_UART0 + +config BFIN_SIR1 + bool "Blackfin SIR on UART1" + depends on BFIN_SIR && !SERIAL_BFIN_UART1 && (!BF531 && !BF532 && !BF533 && !BF561) + +config BFIN_SIR2 + bool "Blackfin SIR on UART2" + depends on BFIN_SIR && !SERIAL_BFIN_UART2 && (BF54x || BF538 || BF539) + +config BFIN_SIR3 + bool "Blackfin SIR on UART3" + depends on BFIN_SIR && !SERIAL_BFIN_UART3 && (BF54x) + +choice + prompt "SIR Mode" + depends on BFIN_SIR + default SIR_BFIN_DMA + +config SIR_BFIN_DMA + bool "DMA mode" + depends on !DMA_UNCACHED_NONE + +config SIR_BFIN_PIO + bool "PIO mode" +endchoice + comment "Dongle support" config DONGLE diff --git a/trunk/drivers/net/irda/Makefile b/trunk/drivers/net/irda/Makefile index 5d20fde32a24..d82e1e3bd8c8 100644 --- a/trunk/drivers/net/irda/Makefile +++ b/trunk/drivers/net/irda/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_MCS_FIR) += mcs7780.o obj-$(CONFIG_AU1000_FIR) += au1k_ir.o # SIR drivers obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o +obj-$(CONFIG_BFIN_SIR) += bfin_sir.o # dongle drivers for SIR drivers obj-$(CONFIG_ESI_DONGLE) += esi-sir.o obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o diff --git a/trunk/drivers/net/irda/au1k_ir.c b/trunk/drivers/net/irda/au1k_ir.c index c4361d466597..269153eedd26 100644 --- a/trunk/drivers/net/irda/au1k_ir.c +++ b/trunk/drivers/net/irda/au1k_ir.c @@ -512,13 +512,13 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: tx_full\n", dev->name); netif_stop_queue(dev); aup->tx_full = 1; - return NETDEV_TX_BUSY; + return 1; } else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { printk(KERN_DEBUG "%s: tx_full\n", dev->name); netif_stop_queue(dev); aup->tx_full = 1; - return NETDEV_TX_BUSY; + return 1; } pDB = aup->tx_db_inuse[aup->tx_head]; diff --git a/trunk/drivers/net/irda/bfin_sir.c b/trunk/drivers/net/irda/bfin_sir.c new file mode 100644 index 000000000000..f3eed6a8fba5 --- /dev/null +++ b/trunk/drivers/net/irda/bfin_sir.c @@ -0,0 +1,820 @@ +/* + * Blackfin Infra-red Driver + * + * Copyright 2006-2009 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + * + */ +#include "bfin_sir.h" + +#ifdef CONFIG_SIR_BFIN_DMA +#define DMA_SIR_RX_XCNT 10 +#define DMA_SIR_RX_YCNT (PAGE_SIZE / DMA_SIR_RX_XCNT) +#define DMA_SIR_RX_FLUSH_JIFS (HZ * 4 / 250) +#endif + +#if ANOMALY_05000447 +static int max_rate = 57600; +#else +static int max_rate = 115200; +#endif + +static void turnaround_delay(unsigned long last_jif, int mtt) +{ + long ticks; + + mtt = mtt < 10000 ? 10000 : mtt; + ticks = 1 + mtt / (USEC_PER_SEC / HZ); + schedule_timeout_uninterruptible(ticks); +} + +static void __devinit bfin_sir_init_ports(struct bfin_sir_port *sp, struct platform_device *pdev) +{ + int i; + struct resource *res; + + for (i = 0; i < pdev->num_resources; i++) { + res = &pdev->resource[i]; + switch (res->flags) { + case IORESOURCE_MEM: + sp->membase = (void __iomem *)res->start; + break; + case IORESOURCE_IRQ: + sp->irq = res->start; + break; + case IORESOURCE_DMA: + sp->rx_dma_channel = res->start; + sp->tx_dma_channel = res->end; + break; + default: + break; + } + } + + sp->clk = get_sclk(); +#ifdef CONFIG_SIR_BFIN_DMA + sp->tx_done = 1; + init_timer(&(sp->rx_dma_timer)); +#endif +} + +static void bfin_sir_stop_tx(struct bfin_sir_port *port) +{ +#ifdef CONFIG_SIR_BFIN_DMA + disable_dma(port->tx_dma_channel); +#endif + + while (!(SIR_UART_GET_LSR(port) & THRE)) { + cpu_relax(); + continue; + } + + SIR_UART_STOP_TX(port); +} + +static void bfin_sir_enable_tx(struct bfin_sir_port *port) +{ + SIR_UART_ENABLE_TX(port); +} + +static void bfin_sir_stop_rx(struct bfin_sir_port *port) +{ + SIR_UART_STOP_RX(port); +} + +static void bfin_sir_enable_rx(struct bfin_sir_port *port) +{ + SIR_UART_ENABLE_RX(port); +} + +static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed) +{ + int ret = -EINVAL; + unsigned int quot; + unsigned short val, lsr, lcr; + static int utime; + int count = 10; + + lcr = WLS(8); + + switch (speed) { + case 9600: + case 19200: + case 38400: + case 57600: + case 115200: + + quot = (port->clk + (8 * speed)) / (16 * speed)\ + - ANOMALY_05000230; + + do { + udelay(utime); + lsr = SIR_UART_GET_LSR(port); + } while (!(lsr & TEMT) && count--); + + /* The useconds for 1 bits to transmit */ + utime = 1000000 / speed + 1; + + /* Clear UCEN bit to reset the UART state machine + * and control registers + */ + val = SIR_UART_GET_GCTL(port); + val &= ~UCEN; + SIR_UART_PUT_GCTL(port, val); + + /* Set DLAB in LCR to Access THR RBR IER */ + SIR_UART_SET_DLAB(port); + SSYNC(); + + SIR_UART_PUT_DLL(port, quot & 0xFF); + SIR_UART_PUT_DLH(port, (quot >> 8) & 0xFF); + SSYNC(); + + /* Clear DLAB in LCR */ + SIR_UART_CLEAR_DLAB(port); + SSYNC(); + + SIR_UART_PUT_LCR(port, lcr); + + val = SIR_UART_GET_GCTL(port); + val |= UCEN; + SIR_UART_PUT_GCTL(port, val); + + ret = 0; + break; + default: + printk(KERN_WARNING "bfin_sir: Invalid speed %d\n", speed); + break; + } + + val = SIR_UART_GET_GCTL(port); + /* If not add the 'RPOLC', we can't catch the receive interrupt. + * It's related with the HW layout and the IR transiver. + */ + val |= IREN | RPOLC; + SIR_UART_PUT_GCTL(port, val); + return ret; +} + +static int bfin_sir_is_receiving(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + if (!(SIR_UART_GET_IER(port) & ERBFI)) + return 0; + return self->rx_buff.state != OUTSIDE_FRAME; +} + +#ifdef CONFIG_SIR_BFIN_PIO +static void bfin_sir_tx_chars(struct net_device *dev) +{ + unsigned int chr; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + if (self->tx_buff.len != 0) { + chr = *(self->tx_buff.data); + SIR_UART_PUT_CHAR(port, chr); + self->tx_buff.data++; + self->tx_buff.len--; + } else { + self->stats.tx_packets++; + self->stats.tx_bytes += self->tx_buff.data - self->tx_buff.head; + if (self->newspeed) { + bfin_sir_set_speed(port, self->newspeed); + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_stop_tx(port); + bfin_sir_enable_rx(port); + /* I'm hungry! */ + netif_wake_queue(dev); + } +} + +static void bfin_sir_rx_chars(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + unsigned char ch; + + SIR_UART_CLEAR_LSR(port); + ch = SIR_UART_GET_CHAR(port); + async_unwrap_char(dev, &self->stats, &self->rx_buff, ch); + dev->last_rx = jiffies; +} + +static irqreturn_t bfin_sir_rx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + spin_lock(&self->lock); + while ((SIR_UART_GET_LSR(port) & DR)) + bfin_sir_rx_chars(dev); + spin_unlock(&self->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t bfin_sir_tx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + spin_lock(&self->lock); + if (SIR_UART_GET_LSR(port) & THRE) + bfin_sir_tx_chars(dev); + spin_unlock(&self->lock); + + return IRQ_HANDLED; +} +#endif /* CONFIG_SIR_BFIN_PIO */ + +#ifdef CONFIG_SIR_BFIN_DMA +static void bfin_sir_dma_tx_chars(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + if (!port->tx_done) + return; + port->tx_done = 0; + + if (self->tx_buff.len == 0) { + self->stats.tx_packets++; + if (self->newspeed) { + bfin_sir_set_speed(port, self->newspeed); + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_enable_rx(port); + port->tx_done = 1; + netif_wake_queue(dev); + return; + } + + blackfin_dcache_flush_range((unsigned long)(self->tx_buff.data), + (unsigned long)(self->tx_buff.data+self->tx_buff.len)); + set_dma_config(port->tx_dma_channel, + set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, + INTR_ON_BUF, DIMENSION_LINEAR, DATA_SIZE_8, + DMA_SYNC_RESTART)); + set_dma_start_addr(port->tx_dma_channel, + (unsigned long)(self->tx_buff.data)); + set_dma_x_count(port->tx_dma_channel, self->tx_buff.len); + set_dma_x_modify(port->tx_dma_channel, 1); + enable_dma(port->tx_dma_channel); +} + +static irqreturn_t bfin_sir_dma_tx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + + spin_lock(&self->lock); + if (!(get_dma_curr_irqstat(port->tx_dma_channel) & DMA_RUN)) { + clear_dma_irqstat(port->tx_dma_channel); + bfin_sir_stop_tx(port); + + self->stats.tx_packets++; + self->stats.tx_bytes += self->tx_buff.len; + self->tx_buff.len = 0; + if (self->newspeed) { + bfin_sir_set_speed(port, self->newspeed); + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_enable_rx(port); + /* I'm hungry! */ + netif_wake_queue(dev); + port->tx_done = 1; + } + spin_unlock(&self->lock); + + return IRQ_HANDLED; +} + +static void bfin_sir_dma_rx_chars(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int i; + + SIR_UART_CLEAR_LSR(port); + + for (i = port->rx_dma_buf.head; i < port->rx_dma_buf.tail; i++) + async_unwrap_char(dev, &self->stats, &self->rx_buff, port->rx_dma_buf.buf[i]); +} + +void bfin_sir_rx_dma_timeout(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int x_pos, pos; + unsigned long flags; + + spin_lock_irqsave(&self->lock, flags); + x_pos = DMA_SIR_RX_XCNT - get_dma_curr_xcount(port->rx_dma_channel); + if (x_pos == DMA_SIR_RX_XCNT) + x_pos = 0; + + pos = port->rx_dma_nrows * DMA_SIR_RX_XCNT + x_pos; + + if (pos > port->rx_dma_buf.tail) { + port->rx_dma_buf.tail = pos; + bfin_sir_dma_rx_chars(dev); + port->rx_dma_buf.head = port->rx_dma_buf.tail; + } + spin_unlock_irqrestore(&self->lock, flags); +} + +static irqreturn_t bfin_sir_dma_rx_int(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + unsigned short irqstat; + + spin_lock(&self->lock); + + port->rx_dma_nrows++; + port->rx_dma_buf.tail = DMA_SIR_RX_XCNT * port->rx_dma_nrows; + bfin_sir_dma_rx_chars(dev); + if (port->rx_dma_nrows >= DMA_SIR_RX_YCNT) { + port->rx_dma_nrows = 0; + port->rx_dma_buf.tail = 0; + } + port->rx_dma_buf.head = port->rx_dma_buf.tail; + + irqstat = get_dma_curr_irqstat(port->rx_dma_channel); + clear_dma_irqstat(port->rx_dma_channel); + spin_unlock(&self->lock); + + mod_timer(&port->rx_dma_timer, jiffies + DMA_SIR_RX_FLUSH_JIFS); + return IRQ_HANDLED; +} +#endif /* CONFIG_SIR_BFIN_DMA */ + +static int bfin_sir_startup(struct bfin_sir_port *port, struct net_device *dev) +{ +#ifdef CONFIG_SIR_BFIN_DMA + dma_addr_t dma_handle; +#endif /* CONFIG_SIR_BFIN_DMA */ + + if (request_dma(port->rx_dma_channel, "BFIN_UART_RX") < 0) { + dev_warn(&dev->dev, "Unable to attach SIR RX DMA channel\n"); + return -EBUSY; + } + + if (request_dma(port->tx_dma_channel, "BFIN_UART_TX") < 0) { + dev_warn(&dev->dev, "Unable to attach SIR TX DMA channel\n"); + free_dma(port->rx_dma_channel); + return -EBUSY; + } + +#ifdef CONFIG_SIR_BFIN_DMA + + set_dma_callback(port->rx_dma_channel, bfin_sir_dma_rx_int, dev); + set_dma_callback(port->tx_dma_channel, bfin_sir_dma_tx_int, dev); + + port->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA); + port->rx_dma_buf.head = 0; + port->rx_dma_buf.tail = 0; + port->rx_dma_nrows = 0; + + set_dma_config(port->rx_dma_channel, + set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO, + INTR_ON_ROW, DIMENSION_2D, + DATA_SIZE_8, DMA_SYNC_RESTART)); + set_dma_x_count(port->rx_dma_channel, DMA_SIR_RX_XCNT); + set_dma_x_modify(port->rx_dma_channel, 1); + set_dma_y_count(port->rx_dma_channel, DMA_SIR_RX_YCNT); + set_dma_y_modify(port->rx_dma_channel, 1); + set_dma_start_addr(port->rx_dma_channel, (unsigned long)port->rx_dma_buf.buf); + enable_dma(port->rx_dma_channel); + + port->rx_dma_timer.data = (unsigned long)(dev); + port->rx_dma_timer.function = (void *)bfin_sir_rx_dma_timeout; + +#else + + if (request_irq(port->irq, bfin_sir_rx_int, IRQF_DISABLED, "BFIN_SIR_RX", dev)) { + dev_warn(&dev->dev, "Unable to attach SIR RX interrupt\n"); + return -EBUSY; + } + + if (request_irq(port->irq+1, bfin_sir_tx_int, IRQF_DISABLED, "BFIN_SIR_TX", dev)) { + dev_warn(&dev->dev, "Unable to attach SIR TX interrupt\n"); + free_irq(port->irq, dev); + return -EBUSY; + } +#endif + + return 0; +} + +static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev) +{ + unsigned short val; + + bfin_sir_stop_rx(port); + SIR_UART_DISABLE_INTS(port); + + val = SIR_UART_GET_GCTL(port); + val &= ~(UCEN | IREN | RPOLC); + SIR_UART_PUT_GCTL(port, val); + +#ifdef CONFIG_SIR_BFIN_DMA + disable_dma(port->tx_dma_channel); + disable_dma(port->rx_dma_channel); + del_timer(&(port->rx_dma_timer)); + dma_free_coherent(NULL, PAGE_SIZE, port->rx_dma_buf.buf, 0); +#else + free_irq(port->irq+1, dev); + free_irq(port->irq, dev); +#endif + free_dma(port->tx_dma_channel); + free_dma(port->rx_dma_channel); +} + +#ifdef CONFIG_PM +static int bfin_sir_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct bfin_sir_port *sir_port; + struct net_device *dev; + struct bfin_sir_self *self; + + sir_port = platform_get_drvdata(pdev); + if (!sir_port) + return 0; + + dev = sir_port->dev; + self = netdev_priv(dev); + if (self->open) { + flush_work(&self->work); + bfin_sir_shutdown(self->sir_port, dev); + netif_device_detach(dev); + } + + return 0; +} +static int bfin_sir_resume(struct platform_device *pdev) +{ + struct bfin_sir_port *sir_port; + struct net_device *dev; + struct bfin_sir_self *self; + struct bfin_sir_port *port; + + sir_port = platform_get_drvdata(pdev); + if (!sir_port) + return 0; + + dev = sir_port->dev; + self = netdev_priv(dev); + port = self->sir_port; + if (self->open) { + if (self->newspeed) { + self->speed = self->newspeed; + self->newspeed = 0; + } + bfin_sir_startup(port, dev); + bfin_sir_set_speed(port, 9600); + bfin_sir_enable_rx(port); + netif_device_attach(dev); + } + return 0; +} +#else +#define bfin_sir_suspend NULL +#define bfin_sir_resume NULL +#endif + +static void bfin_sir_send_work(struct work_struct *work) +{ + struct bfin_sir_self *self = container_of(work, struct bfin_sir_self, work); + struct net_device *dev = self->sir_port->dev; + struct bfin_sir_port *port = self->sir_port; + unsigned short val; + int tx_cnt = 10; + + while (bfin_sir_is_receiving(dev) && --tx_cnt) + turnaround_delay(dev->last_rx, self->mtt); + + bfin_sir_stop_rx(port); + + /* To avoid losting RX interrupt, we reset IR function before + * sending data. We also can set the speed, which will + * reset all the UART. + */ + val = SIR_UART_GET_GCTL(port); + val &= ~(IREN | RPOLC); + SIR_UART_PUT_GCTL(port, val); + SSYNC(); + val |= IREN | RPOLC; + SIR_UART_PUT_GCTL(port, val); + SSYNC(); + /* bfin_sir_set_speed(port, self->speed); */ + +#ifdef CONFIG_SIR_BFIN_DMA + bfin_sir_dma_tx_chars(dev); +#endif + bfin_sir_enable_tx(port); + dev->trans_start = jiffies; +} + +static int bfin_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + int speed = irda_get_next_speed(skb); + + netif_stop_queue(dev); + + self->mtt = irda_get_mtt(skb); + + if (speed != self->speed && speed != -1) + self->newspeed = speed; + + self->tx_buff.data = self->tx_buff.head; + if (skb->len == 0) + self->tx_buff.len = 0; + else + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); + + schedule_work(&self->work); + dev_kfree_skb(skb); + + return 0; +} + +static int bfin_sir_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int ret = 0; + + switch (cmd) { + case SIOCSBANDWIDTH: + if (capable(CAP_NET_ADMIN)) { + if (self->open) { + ret = bfin_sir_set_speed(port, rq->ifr_baudrate); + bfin_sir_enable_rx(port); + } else { + dev_warn(&dev->dev, "SIOCSBANDWIDTH: !netif_running\n"); + ret = 0; + } + } + break; + + case SIOCSMEDIABUSY: + ret = -EPERM; + if (capable(CAP_NET_ADMIN)) { + irda_device_set_media_busy(dev, TRUE); + ret = 0; + } + break; + + case SIOCGRECEIVING: + rq->ifr_receiving = bfin_sir_is_receiving(dev); + break; + + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static struct net_device_stats *bfin_sir_stats(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + + return &self->stats; +} + +static int bfin_sir_open(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + struct bfin_sir_port *port = self->sir_port; + int err = -ENOMEM; + + self->newspeed = 0; + self->speed = 9600; + + spin_lock_init(&self->lock); + + err = bfin_sir_startup(port, dev); + if (err) + goto err_startup; + + bfin_sir_set_speed(port, 9600); + + self->irlap = irlap_open(dev, &self->qos, DRIVER_NAME); + if (!self->irlap) + goto err_irlap; + + INIT_WORK(&self->work, bfin_sir_send_work); + + /* + * Now enable the interrupt then start the queue + */ + self->open = 1; + bfin_sir_enable_rx(port); + + netif_start_queue(dev); + + return 0; + +err_irlap: + self->open = 0; + bfin_sir_shutdown(port, dev); +err_startup: + return err; +} + +static int bfin_sir_stop(struct net_device *dev) +{ + struct bfin_sir_self *self = netdev_priv(dev); + + flush_work(&self->work); + bfin_sir_shutdown(self->sir_port, dev); + + if (self->rxskb) { + dev_kfree_skb(self->rxskb); + self->rxskb = NULL; + } + + /* Stop IrLAP */ + if (self->irlap) { + irlap_close(self->irlap); + self->irlap = NULL; + } + + netif_stop_queue(dev); + self->open = 0; + + return 0; +} + +static int bfin_sir_init_iobuf(iobuff_t *io, int size) +{ + io->head = kmalloc(size, GFP_KERNEL); + if (!io->head) + return -ENOMEM; + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; + return 0; +} + +static int __devinit bfin_sir_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct bfin_sir_self *self; + unsigned int baudrate_mask; + struct bfin_sir_port *sir_port; + int err; + + if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(per) && \ + per[pdev->id][3] == pdev->id) { + err = peripheral_request_list(per[pdev->id], DRIVER_NAME); + if (err) + return err; + } else { + dev_err(&pdev->dev, "Invalid pdev id, please check board file\n"); + return -ENODEV; + } + + err = -ENOMEM; + sir_port = kmalloc(sizeof(*sir_port), GFP_KERNEL); + if (!sir_port) + goto err_mem_0; + + bfin_sir_init_ports(sir_port, pdev); + + dev = alloc_irdadev(sizeof(*self)); + if (!dev) + goto err_mem_1; + + self = netdev_priv(dev); + self->dev = &pdev->dev; + self->sir_port = sir_port; + sir_port->dev = dev; + + err = bfin_sir_init_iobuf(&self->rx_buff, IRDA_SKB_MAX_MTU); + if (err) + goto err_mem_2; + err = bfin_sir_init_iobuf(&self->tx_buff, IRDA_SIR_MAX_FRAME); + if (err) + goto err_mem_3; + + dev->hard_start_xmit = bfin_sir_hard_xmit; + dev->open = bfin_sir_open; + dev->stop = bfin_sir_stop; + dev->do_ioctl = bfin_sir_ioctl; + dev->get_stats = bfin_sir_stats; + dev->irq = sir_port->irq; + + irda_init_max_qos_capabilies(&self->qos); + + baudrate_mask = IR_9600; + + switch (max_rate) { + case 115200: + baudrate_mask |= IR_115200; + case 57600: + baudrate_mask |= IR_57600; + case 38400: + baudrate_mask |= IR_38400; + case 19200: + baudrate_mask |= IR_19200; + case 9600: + break; + default: + dev_warn(&pdev->dev, "Invalid maximum baud rate, using 9600\n"); + } + + self->qos.baud_rate.bits &= baudrate_mask; + + self->qos.min_turn_time.bits = 1; /* 10 ms or more */ + + irda_qos_bits_to_value(&self->qos); + + err = register_netdev(dev); + + if (err) { + kfree(self->tx_buff.head); +err_mem_3: + kfree(self->rx_buff.head); +err_mem_2: + free_netdev(dev); +err_mem_1: + kfree(sir_port); +err_mem_0: + peripheral_free_list(per[pdev->id]); + } else + platform_set_drvdata(pdev, sir_port); + + return err; +} + +static int __devexit bfin_sir_remove(struct platform_device *pdev) +{ + struct bfin_sir_port *sir_port; + struct net_device *dev = NULL; + struct bfin_sir_self *self; + + sir_port = platform_get_drvdata(pdev); + if (!sir_port) + return 0; + dev = sir_port->dev; + self = netdev_priv(dev); + unregister_netdev(dev); + kfree(self->tx_buff.head); + kfree(self->rx_buff.head); + free_netdev(dev); + kfree(sir_port); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver bfin_ir_driver = { + .probe = bfin_sir_probe, + .remove = __devexit_p(bfin_sir_remove), + .suspend = bfin_sir_suspend, + .resume = bfin_sir_resume, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init bfin_sir_init(void) +{ + return platform_driver_register(&bfin_ir_driver); +} + +static void __exit bfin_sir_exit(void) +{ + platform_driver_unregister(&bfin_ir_driver); +} + +module_init(bfin_sir_init); +module_exit(bfin_sir_exit); + +module_param(max_rate, int, 0); +MODULE_PARM_DESC(max_rate, "Maximum baud rate (115200, 57600, 38400, 19200, 9600)"); + +MODULE_AUTHOR("Graf Yang "); +MODULE_DESCRIPTION("Blackfin IrDA driver"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/irda/bfin_sir.h b/trunk/drivers/net/irda/bfin_sir.h new file mode 100644 index 000000000000..dac71b1f4f9b --- /dev/null +++ b/trunk/drivers/net/irda/bfin_sir.h @@ -0,0 +1,148 @@ +/* + * Blackfin Infra-red Driver + * + * Copyright 2006-2009 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_SIR_BFIN_DMA +struct dma_rx_buf { + char *buf; + int head; + int tail; +}; +#endif + +struct bfin_sir_port { + unsigned char __iomem *membase; + unsigned int irq; + unsigned int lsr; + unsigned long clk; + struct net_device *dev; +#ifdef CONFIG_SIR_BFIN_DMA + int tx_done; + struct dma_rx_buf rx_dma_buf; + struct timer_list rx_dma_timer; + int rx_dma_nrows; +#endif + unsigned int tx_dma_channel; + unsigned int rx_dma_channel; +}; + +struct bfin_sir_port_res { + unsigned long base_addr; + int irq; + unsigned int rx_dma_channel; + unsigned int tx_dma_channel; +}; + +struct bfin_sir_self { + struct bfin_sir_port *sir_port; + spinlock_t lock; + unsigned int open; + int speed; + int newspeed; + + struct sk_buff *txskb; + struct sk_buff *rxskb; + struct net_device_stats stats; + struct device *dev; + struct irlap_cb *irlap; + struct qos_info qos; + + iobuff_t tx_buff; + iobuff_t rx_buff; + + struct work_struct work; + int mtt; +}; + +#define DRIVER_NAME "bfin_sir" + +#define SIR_UART_GET_CHAR(port) bfin_read16((port)->membase + OFFSET_RBR) +#define SIR_UART_GET_DLL(port) bfin_read16((port)->membase + OFFSET_DLL) +#define SIR_UART_GET_DLH(port) bfin_read16((port)->membase + OFFSET_DLH) +#define SIR_UART_GET_LCR(port) bfin_read16((port)->membase + OFFSET_LCR) +#define SIR_UART_GET_GCTL(port) bfin_read16((port)->membase + OFFSET_GCTL) + +#define SIR_UART_PUT_CHAR(port, v) bfin_write16(((port)->membase + OFFSET_THR), v) +#define SIR_UART_PUT_DLL(port, v) bfin_write16(((port)->membase + OFFSET_DLL), v) +#define SIR_UART_PUT_DLH(port, v) bfin_write16(((port)->membase + OFFSET_DLH), v) +#define SIR_UART_PUT_LCR(port, v) bfin_write16(((port)->membase + OFFSET_LCR), v) +#define SIR_UART_PUT_GCTL(port, v) bfin_write16(((port)->membase + OFFSET_GCTL), v) + +#ifdef CONFIG_BF54x +#define SIR_UART_GET_LSR(port) bfin_read16((port)->membase + OFFSET_LSR) +#define SIR_UART_GET_IER(port) bfin_read16((port)->membase + OFFSET_IER_SET) +#define SIR_UART_SET_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER_SET), v) +#define SIR_UART_CLEAR_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER_CLEAR), v) +#define SIR_UART_PUT_LSR(port, v) bfin_write16(((port)->membase + OFFSET_LSR), v) +#define SIR_UART_CLEAR_LSR(port) bfin_write16(((port)->membase + OFFSET_LSR), -1) + +#define SIR_UART_SET_DLAB(port) +#define SIR_UART_CLEAR_DLAB(port) + +#define SIR_UART_ENABLE_INTS(port, v) SIR_UART_SET_IER(port, v) +#define SIR_UART_DISABLE_INTS(port) SIR_UART_CLEAR_IER(port, 0xF) +#define SIR_UART_STOP_TX(port) do { SIR_UART_PUT_LSR(port, TFI); SIR_UART_CLEAR_IER(port, ETBEI); } while (0) +#define SIR_UART_ENABLE_TX(port) do { SIR_UART_SET_IER(port, ETBEI); } while (0) +#define SIR_UART_STOP_RX(port) do { SIR_UART_CLEAR_IER(port, ERBFI); } while (0) +#define SIR_UART_ENABLE_RX(port) do { SIR_UART_SET_IER(port, ERBFI); } while (0) +#else + +#define SIR_UART_GET_IIR(port) bfin_read16((port)->membase + OFFSET_IIR) +#define SIR_UART_GET_IER(port) bfin_read16((port)->membase + OFFSET_IER) +#define SIR_UART_PUT_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER), v) + +#define SIR_UART_SET_DLAB(port) do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) | DLAB); } while (0) +#define SIR_UART_CLEAR_DLAB(port) do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) & ~DLAB); } while (0) + +#define SIR_UART_ENABLE_INTS(port, v) SIR_UART_PUT_IER(port, v) +#define SIR_UART_DISABLE_INTS(port) SIR_UART_PUT_IER(port, 0) +#define SIR_UART_STOP_TX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ETBEI); } while (0) +#define SIR_UART_ENABLE_TX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ETBEI); } while (0) +#define SIR_UART_STOP_RX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ERBFI); } while (0) +#define SIR_UART_ENABLE_RX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ERBFI); } while (0) + +static inline unsigned int SIR_UART_GET_LSR(struct bfin_sir_port *port) +{ + unsigned int lsr = bfin_read16(port->membase + OFFSET_LSR); + port->lsr |= (lsr & (BI|FE|PE|OE)); + return lsr | port->lsr; +} + +static inline void SIR_UART_CLEAR_LSR(struct bfin_sir_port *port) +{ + port->lsr = 0; + bfin_read16(port->membase + OFFSET_LSR); +} +#endif + +static const unsigned short per[][4] = { + /* rx pin tx pin NULL uart_number */ + {P_UART0_RX, P_UART0_TX, 0, 0}, + {P_UART1_RX, P_UART1_TX, 0, 1}, + {P_UART2_RX, P_UART2_TX, 0, 2}, + {P_UART3_RX, P_UART3_TX, 0, 3}, +}; diff --git a/trunk/drivers/net/irda/donauboe.c b/trunk/drivers/net/irda/donauboe.c index 9a0346e751ac..6b6548b9fda0 100644 --- a/trunk/drivers/net/irda/donauboe.c +++ b/trunk/drivers/net/irda/donauboe.c @@ -994,11 +994,11 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) /* change speed pending, wait for its execution */ if (self->new_speed) - return NETDEV_TX_BUSY; + return -EBUSY; /* device stopped (apm) wait for restart */ if (self->stopped) - return NETDEV_TX_BUSY; + return -EBUSY; toshoboe_checkstuck (self); @@ -1049,7 +1049,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) if (self->txpending) { spin_unlock_irqrestore(&self->spinlock, flags); - return NETDEV_TX_BUSY; + return -EBUSY; } /* If in SIR mode we need to generate a string of XBOFs */ @@ -1105,7 +1105,7 @@ dumpbufs(skb->data,skb->len,'>'); ,skb->len, self->ring->tx[self->txs].control, self->txpending); toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); spin_unlock_irqrestore(&self->spinlock, flags); - return NETDEV_TX_BUSY; + return -EBUSY; } if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_SIRON) diff --git a/trunk/drivers/net/irda/irda-usb.c b/trunk/drivers/net/irda/irda-usb.c index 0c0831c03f64..394b2b17075e 100644 --- a/trunk/drivers/net/irda/irda-usb.c +++ b/trunk/drivers/net/irda/irda-usb.c @@ -389,6 +389,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) s32 speed; s16 xbofs; int res, mtt; + int err = 1; /* Failed */ IRDA_DEBUG(4, "%s() on %s\n", __func__, netdev->name); @@ -429,6 +430,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) irda_usb_change_speed_xbofs(self); netdev->trans_start = jiffies; /* Will netif_wake_queue() in callback */ + err = 0; /* No error */ goto drop; } } @@ -540,7 +542,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) /* Drop silently the skb and exit */ dev_kfree_skb(skb); spin_unlock_irqrestore(&self->lock, flags); - return NETDEV_TX_OK; + return err; /* Usually 1 */ } /*------------------------------------------------------------------*/ diff --git a/trunk/drivers/net/irda/kingsun-sir.c b/trunk/drivers/net/irda/kingsun-sir.c index c3e4e2c435ba..9d813bc4502e 100644 --- a/trunk/drivers/net/irda/kingsun-sir.c +++ b/trunk/drivers/net/irda/kingsun-sir.c @@ -156,6 +156,9 @@ static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev) int wraplen; int ret = 0; + if (skb == NULL || netdev == NULL) + return -EINVAL; + netif_stop_queue(netdev); /* the IRDA wrapping routines don't deal with non linear skb */ @@ -194,7 +197,7 @@ static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); spin_unlock(&kingsun->lock); - return NETDEV_TX_OK; + return ret; } /* Receive callback function */ diff --git a/trunk/drivers/net/irda/ks959-sir.c b/trunk/drivers/net/irda/ks959-sir.c index d73b8b64fcb9..b6ffe9715b61 100644 --- a/trunk/drivers/net/irda/ks959-sir.c +++ b/trunk/drivers/net/irda/ks959-sir.c @@ -391,6 +391,9 @@ static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned int wraplen; int ret = 0; + if (skb == NULL || netdev == NULL) + return -EINVAL; + netif_stop_queue(netdev); /* the IRDA wrapping routines don't deal with non linear skb */ @@ -425,7 +428,7 @@ static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); spin_unlock(&kingsun->lock); - return NETDEV_TX_OK; + return ret; } /* Receive callback function */ diff --git a/trunk/drivers/net/irda/ksdazzle-sir.c b/trunk/drivers/net/irda/ksdazzle-sir.c index 1ef45ec74422..64df27f2bfd4 100644 --- a/trunk/drivers/net/irda/ksdazzle-sir.c +++ b/trunk/drivers/net/irda/ksdazzle-sir.c @@ -304,6 +304,9 @@ static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned int wraplen; int ret = 0; + if (skb == NULL || netdev == NULL) + return -EINVAL; + netif_stop_queue(netdev); /* the IRDA wrapping routines don't deal with non linear skb */ @@ -338,7 +341,7 @@ static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev) dev_kfree_skb(skb); spin_unlock(&kingsun->lock); - return NETDEV_TX_OK; + return ret; } /* Receive callback function */ diff --git a/trunk/drivers/net/irda/mcs7780.c b/trunk/drivers/net/irda/mcs7780.c index f4df1001983c..fac504d0cfd8 100644 --- a/trunk/drivers/net/irda/mcs7780.c +++ b/trunk/drivers/net/irda/mcs7780.c @@ -824,6 +824,10 @@ static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev) int wraplen; int ret = 0; + + if (skb == NULL || ndev == NULL) + return -EINVAL; + netif_stop_queue(ndev); mcs = netdev_priv(ndev); @@ -866,7 +870,7 @@ static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev) dev_kfree_skb(skb); spin_unlock_irqrestore(&mcs->lock, flags); - return NETDEV_TX_OK; + return ret; } static const struct net_device_ops mcs_netdev_ops = { diff --git a/trunk/drivers/net/irda/sir_dev.c b/trunk/drivers/net/irda/sir_dev.c index fd0796c3db3c..d940809762ec 100644 --- a/trunk/drivers/net/irda/sir_dev.c +++ b/trunk/drivers/net/irda/sir_dev.c @@ -607,7 +607,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) * stopped so the network layer will retry after the * fsm completes and wakes the queue. */ - return NETDEV_TX_BUSY; + return 1; } else if (unlikely(err)) { /* other fatal error - forget the speed change and diff --git a/trunk/drivers/net/lib8390.c b/trunk/drivers/net/lib8390.c index f28c23343009..789b6cb744b2 100644 --- a/trunk/drivers/net/lib8390.c +++ b/trunk/drivers/net/lib8390.c @@ -370,7 +370,7 @@ static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock(&ei_local->page_lock); enable_irq_lockdep_irqrestore(dev->irq, &flags); dev->stats.tx_errors++; - return NETDEV_TX_BUSY; + return 1; } /* diff --git a/trunk/drivers/net/mac89x0.c b/trunk/drivers/net/mac89x0.c index dab45339d3a8..e24175a39460 100644 --- a/trunk/drivers/net/mac89x0.c +++ b/trunk/drivers/net/mac89x0.c @@ -400,7 +400,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) /* Gasp! It hasn't. But that shouldn't happen since we're waiting for TxOk, so return 1 and requeue this packet. */ local_irq_restore(flags); - return NETDEV_TX_BUSY; + return 1; } /* Write the contents of the packet */ diff --git a/trunk/drivers/net/macb.c b/trunk/drivers/net/macb.c index 5b5c25368d1e..722265920da8 100644 --- a/trunk/drivers/net/macb.c +++ b/trunk/drivers/net/macb.c @@ -645,7 +645,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) "BUG! Tx Ring full when queue awake!\n"); dev_dbg(&bp->pdev->dev, "tx_head = %u, tx_tail = %u\n", bp->tx_head, bp->tx_tail); - return NETDEV_TX_BUSY; + return 1; } entry = bp->tx_head; diff --git a/trunk/drivers/net/mace.c b/trunk/drivers/net/mace.c index 1427755c224d..1ad740bc8878 100644 --- a/trunk/drivers/net/mace.c +++ b/trunk/drivers/net/mace.c @@ -547,7 +547,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); mp->tx_fullup = 1; spin_unlock_irqrestore(&mp->lock, flags); - return NETDEV_TX_BUSY; /* can't take it at the moment */ + return 1; /* can't take it at the moment */ } spin_unlock_irqrestore(&mp->lock, flags); diff --git a/trunk/drivers/net/myri10ge/myri10ge.c b/trunk/drivers/net/myri10ge/myri10ge.c index 1f6e36ea669e..c9a30d3a66fb 100644 --- a/trunk/drivers/net/myri10ge/myri10ge.c +++ b/trunk/drivers/net/myri10ge/myri10ge.c @@ -2687,7 +2687,7 @@ static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev) /* we are out of transmit resources */ tx->stop_queue++; netif_tx_stop_queue(netdev_queue); - return NETDEV_TX_BUSY; + return 1; } /* Setup checksum offloading, if needed */ diff --git a/trunk/drivers/net/myri_sbus.c b/trunk/drivers/net/myri_sbus.c index 5f0758bda6b3..9a802adba9a3 100644 --- a/trunk/drivers/net/myri_sbus.c +++ b/trunk/drivers/net/myri_sbus.c @@ -640,7 +640,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!TX_BUFFS_AVAIL(head, tail)) { DTX(("no buffs available, returning 1\n")); - return NETDEV_TX_BUSY; + return 1; } spin_lock_irqsave(&mp->irq_lock, flags); diff --git a/trunk/drivers/net/ni65.c b/trunk/drivers/net/ni65.c index 1f10ed603e20..6474f02bf783 100644 --- a/trunk/drivers/net/ni65.c +++ b/trunk/drivers/net/ni65.c @@ -1165,7 +1165,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev) if (test_and_set_bit(0, (void*)&p->lock)) { printk(KERN_ERR "%s: Queue was locked.\n", dev->name); - return NETDEV_TX_BUSY; + return 1; } { diff --git a/trunk/drivers/net/ns83820.c b/trunk/drivers/net/ns83820.c index 1576ac07216e..940962ae8f23 100644 --- a/trunk/drivers/net/ns83820.c +++ b/trunk/drivers/net/ns83820.c @@ -1097,7 +1097,7 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (unlikely(dev->CFG_cache & CFG_LNKSTS)) { netif_stop_queue(ndev); if (unlikely(dev->CFG_cache & CFG_LNKSTS)) - return NETDEV_TX_BUSY; + return 1; netif_start_queue(ndev); } @@ -1115,7 +1115,7 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) netif_start_queue(ndev); goto again; } - return NETDEV_TX_BUSY; + return 1; } if (free_idx == dev->tx_intr_idx) { diff --git a/trunk/drivers/net/pcmcia/axnet_cs.c b/trunk/drivers/net/pcmcia/axnet_cs.c index 0e38d80fd255..15b8fe61695b 100644 --- a/trunk/drivers/net/pcmcia/axnet_cs.c +++ b/trunk/drivers/net/pcmcia/axnet_cs.c @@ -1130,7 +1130,7 @@ static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev) outb_p(ENISR_ALL, e8390_base + EN0_IMR); spin_unlock_irqrestore(&ei_local->page_lock, flags); dev->stats.tx_errors++; - return NETDEV_TX_BUSY; + return 1; } /* diff --git a/trunk/drivers/net/pcmcia/fmvj18x_cs.c b/trunk/drivers/net/pcmcia/fmvj18x_cs.c index 479d5b494371..81e6660a433a 100644 --- a/trunk/drivers/net/pcmcia/fmvj18x_cs.c +++ b/trunk/drivers/net/pcmcia/fmvj18x_cs.c @@ -877,7 +877,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) if (length > ETH_FRAME_LEN) { printk(KERN_NOTICE "%s: Attempting to send a large packet" " (%d bytes).\n", dev->name, length); - return NETDEV_TX_BUSY; + return 1; } DEBUG(4, "%s: Transmitting a packet of length %lu.\n", diff --git a/trunk/drivers/net/pcmcia/smc91c92_cs.c b/trunk/drivers/net/pcmcia/smc91c92_cs.c index 37e05d3ab893..48dbb35747d8 100644 --- a/trunk/drivers/net/pcmcia/smc91c92_cs.c +++ b/trunk/drivers/net/pcmcia/smc91c92_cs.c @@ -1388,7 +1388,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_aborted_errors++; printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n", dev->name); - return NETDEV_TX_BUSY; + return 1; } smc->saved_skb = skb; diff --git a/trunk/drivers/net/pcmcia/xirc2ps_cs.c b/trunk/drivers/net/pcmcia/xirc2ps_cs.c index ef37d22c7e1d..a3685c0d22fc 100644 --- a/trunk/drivers/net/pcmcia/xirc2ps_cs.c +++ b/trunk/drivers/net/pcmcia/xirc2ps_cs.c @@ -1399,7 +1399,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) DEBUG(2 + (okay ? 2 : 0), "%s: avail. tx space=%u%s\n", dev->name, freespace, okay ? " (okay)":" (not enough)"); if (!okay) { /* not enough space */ - return NETDEV_TX_BUSY; /* upper layer may decide to requeue this packet */ + return 1; /* upper layer may decide to requeue this packet */ } /* send the packet */ PutWord(XIRCREG_EDP, (u_short)pktlen); diff --git a/trunk/drivers/net/plip.c b/trunk/drivers/net/plip.c index 7a62f781fef2..0be0f0b164f3 100644 --- a/trunk/drivers/net/plip.c +++ b/trunk/drivers/net/plip.c @@ -955,12 +955,12 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev) struct plip_local *snd = &nl->snd_data; if (netif_queue_stopped(dev)) - return NETDEV_TX_BUSY; + return 1; /* We may need to grab the bus */ if (!nl->port_owner) { if (parport_claim(nl->pardev)) - return NETDEV_TX_BUSY; + return 1; nl->port_owner = 1; } @@ -969,7 +969,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev) if (skb->len > dev->mtu + dev->hard_header_len) { printk(KERN_WARNING "%s: packet too big, %d.\n", dev->name, (int)skb->len); netif_start_queue (dev); - return NETDEV_TX_BUSY; + return 1; } if (net_debug > 2) diff --git a/trunk/drivers/net/rrunner.c b/trunk/drivers/net/rrunner.c index 81dbcbb910f4..d890829a9acc 100644 --- a/trunk/drivers/net/rrunner.c +++ b/trunk/drivers/net/rrunner.c @@ -1425,7 +1425,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!(new_skb = dev_alloc_skb(len + 8))) { dev_kfree_skb(skb); netif_wake_queue(dev); - return NETDEV_TX_OK; + return -EBUSY; } skb_reserve(new_skb, 8); skb_put(new_skb, len); diff --git a/trunk/drivers/net/sb1250-mac.c b/trunk/drivers/net/sb1250-mac.c index d8c9cf1b901d..7a4b9fbddbaf 100644 --- a/trunk/drivers/net/sb1250-mac.c +++ b/trunk/drivers/net/sb1250-mac.c @@ -2084,7 +2084,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); spin_unlock_irqrestore(&sc->sbm_lock, flags); - return NETDEV_TX_BUSY; + return 1; } dev->trans_start = jiffies; diff --git a/trunk/drivers/net/sh_eth.c b/trunk/drivers/net/sh_eth.c index 341882f959f3..0709b7512467 100644 --- a/trunk/drivers/net/sh_eth.c +++ b/trunk/drivers/net/sh_eth.c @@ -1108,7 +1108,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (!sh_eth_txfree(ndev)) { netif_stop_queue(ndev); spin_unlock_irqrestore(&mdp->lock, flags); - return NETDEV_TX_BUSY; + return 1; } } spin_unlock_irqrestore(&mdp->lock, flags); diff --git a/trunk/drivers/net/sis900.c b/trunk/drivers/net/sis900.c index a9a897bb42d5..2d4617b3e208 100644 --- a/trunk/drivers/net/sis900.c +++ b/trunk/drivers/net/sis900.c @@ -1584,7 +1584,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) /* Don't transmit data before the complete of auto-negotiation */ if(!sis_priv->autong_complete){ netif_stop_queue(net_dev); - return NETDEV_TX_BUSY; + return 1; } spin_lock_irqsave(&sis_priv->lock, flags); diff --git a/trunk/drivers/net/skfp/skfddi.c b/trunk/drivers/net/skfp/skfddi.c index 088fe26484e7..19d343c42a21 100644 --- a/trunk/drivers/net/skfp/skfddi.c +++ b/trunk/drivers/net/skfp/skfddi.c @@ -1082,7 +1082,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev) if (bp->QueueSkb == 0) { // return with tbusy set: queue full netif_stop_queue(dev); - return NETDEV_TX_BUSY; + return 1; } bp->QueueSkb--; skb_queue_tail(&bp->SendSkbQueue, skb); diff --git a/trunk/drivers/net/smc9194.c b/trunk/drivers/net/smc9194.c index e02471b2f2b5..9a7973a54116 100644 --- a/trunk/drivers/net/smc9194.c +++ b/trunk/drivers/net/smc9194.c @@ -503,7 +503,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de /* THIS SHOULD NEVER HAPPEN. */ dev->stats.tx_aborted_errors++; printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); - return NETDEV_TX_BUSY; + return 1; } lp->saved_skb = skb; diff --git a/trunk/drivers/net/sonic.c b/trunk/drivers/net/sonic.c index e4255d829380..211e805c1223 100644 --- a/trunk/drivers/net/sonic.c +++ b/trunk/drivers/net/sonic.c @@ -223,7 +223,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) if (!laddr) { printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name); dev_kfree_skb(skb); - return NETDEV_TX_BUSY + return 1; } sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */ diff --git a/trunk/drivers/net/starfire.c b/trunk/drivers/net/starfire.c index 838cce8b8fff..fcb943fca4f1 100644 --- a/trunk/drivers/net/starfire.c +++ b/trunk/drivers/net/starfire.c @@ -1236,7 +1236,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) */ if ((np->cur_tx - np->dirty_tx) + skb_num_frags(skb) * 2 > TX_RING_SIZE) { netif_stop_queue(dev); - return NETDEV_TX_BUSY; + return 1; } #if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE) diff --git a/trunk/drivers/net/sun3_82586.c b/trunk/drivers/net/sun3_82586.c index 7bb27426dbd6..a39c0b9ba8b6 100644 --- a/trunk/drivers/net/sun3_82586.c +++ b/trunk/drivers/net/sun3_82586.c @@ -1023,7 +1023,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) #if(NUM_XMIT_BUFFS > 1) if(test_and_set_bit(0,(void *) &p->lock)) { printk("%s: Queue was locked\n",dev->name); - return NETDEV_TX_BUSY; + return 1; } else #endif diff --git a/trunk/drivers/net/sun3lance.c b/trunk/drivers/net/sun3lance.c index 534dfe3eef6f..9bd9dadb8534 100644 --- a/trunk/drivers/net/sun3lance.c +++ b/trunk/drivers/net/sun3lance.c @@ -526,7 +526,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) if (netif_queue_stopped(dev)) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 20) - return NETDEV_TX_BUSY; + return( 1 ); DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n", dev->name, DREG )); @@ -577,7 +577,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) { printk( "%s: tx queue lock!.\n", dev->name); /* don't clear dev->tbusy flag. */ - return NETDEV_TX_BUSY; + return 1; } AREG = CSR0; diff --git a/trunk/drivers/net/sunhme.c b/trunk/drivers/net/sunhme.c index 4ef729198e10..4e9bd380a5c2 100644 --- a/trunk/drivers/net/sunhme.c +++ b/trunk/drivers/net/sunhme.c @@ -2275,7 +2275,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&hp->happy_lock); printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", dev->name); - return NETDEV_TX_BUSY; + return 1; } entry = hp->tx_new; diff --git a/trunk/drivers/net/tlan.c b/trunk/drivers/net/tlan.c index 384cb5e28397..aa6964922d5e 100644 --- a/trunk/drivers/net/tlan.c +++ b/trunk/drivers/net/tlan.c @@ -1111,7 +1111,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) dev->name, priv->txHead, priv->txTail ); netif_stop_queue(dev); priv->txBusyCount++; - return NETDEV_TX_BUSY; + return 1; } tail_list->forward = 0; diff --git a/trunk/drivers/net/tokenring/3c359.c b/trunk/drivers/net/tokenring/3c359.c index 13dbc59bfe42..534c0f38483c 100644 --- a/trunk/drivers/net/tokenring/3c359.c +++ b/trunk/drivers/net/tokenring/3c359.c @@ -1243,7 +1243,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } else { spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; - return NETDEV_TX_BUSY; + return 1; } } diff --git a/trunk/drivers/net/tokenring/lanstreamer.c b/trunk/drivers/net/tokenring/lanstreamer.c index b358bbbce33a..2e70ee8f1459 100644 --- a/trunk/drivers/net/tokenring/lanstreamer.c +++ b/trunk/drivers/net/tokenring/lanstreamer.c @@ -1187,7 +1187,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) } else { netif_stop_queue(dev); spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); - return NETDEV_TX_BUSY; + return 1; } } diff --git a/trunk/drivers/net/tokenring/olympic.c b/trunk/drivers/net/tokenring/olympic.c index c36974925c15..d068a9d36883 100644 --- a/trunk/drivers/net/tokenring/olympic.c +++ b/trunk/drivers/net/tokenring/olympic.c @@ -1055,7 +1055,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } else { spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); - return NETDEV_TX_BUSY; + return 1; } } diff --git a/trunk/drivers/net/tokenring/smctr.c b/trunk/drivers/net/tokenring/smctr.c index 54ad4ed03374..a91d9c55d78e 100644 --- a/trunk/drivers/net/tokenring/smctr.c +++ b/trunk/drivers/net/tokenring/smctr.c @@ -4601,7 +4601,7 @@ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); if(tp->QueueSkb == 0) - return NETDEV_TX_BUSY; /* Return with tbusy set: queue full */ + return (1); /* Return with tbusy set: queue full */ tp->QueueSkb--; skb_queue_tail(&tp->SendSkbQueue, skb); diff --git a/trunk/drivers/net/tokenring/tms380tr.c b/trunk/drivers/net/tokenring/tms380tr.c index a2eab72b507a..b11bb72dc7ab 100644 --- a/trunk/drivers/net/tokenring/tms380tr.c +++ b/trunk/drivers/net/tokenring/tms380tr.c @@ -633,7 +633,7 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device if (tms380tr_debug > 0) printk(KERN_DEBUG "%s: No free TPL\n", dev->name); spin_unlock_irqrestore(&tp->lock, flags); - return NETDEV_TX_BUSY; + return 1; } dmabuf = 0; diff --git a/trunk/drivers/net/tulip/de2104x.c b/trunk/drivers/net/tulip/de2104x.c index 81f054dbb88d..e7609a05032d 100644 --- a/trunk/drivers/net/tulip/de2104x.c +++ b/trunk/drivers/net/tulip/de2104x.c @@ -612,7 +612,7 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) if (tx_free == 0) { netif_stop_queue(dev); spin_unlock_irq(&de->lock); - return NETDEV_TX_BUSY; + return 1; } tx_free--; diff --git a/trunk/drivers/net/tulip/de4x5.c b/trunk/drivers/net/tulip/de4x5.c index eb72d2e9ab3d..32256179a205 100644 --- a/trunk/drivers/net/tulip/de4x5.c +++ b/trunk/drivers/net/tulip/de4x5.c @@ -1461,12 +1461,12 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) { struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; - int status = NETDEV_TX_OK; + int status = 0; u_long flags = 0; netif_stop_queue(dev); if (!lp->tx_enable) { /* Cannot send for now */ - return NETDEV_TX_LOCKED; + return -1; } /* @@ -1480,7 +1480,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) /* Test if cache is already locked - requeue skb if so */ if (test_and_set_bit(0, (void *)&lp->cache.lock) && !lp->interrupt) - return NETDEV_TX_LOCKED; + return -1; /* Transmit descriptor ring full or stale skb */ if (netif_queue_stopped(dev) || (u_long) lp->tx_skb[lp->tx_new] > 1) { diff --git a/trunk/drivers/net/tulip/dmfe.c b/trunk/drivers/net/tulip/dmfe.c index 8e78f003f08f..f2e669974c78 100644 --- a/trunk/drivers/net/tulip/dmfe.c +++ b/trunk/drivers/net/tulip/dmfe.c @@ -686,7 +686,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) spin_unlock_irqrestore(&db->lock, flags); printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_queue_cnt); - return NETDEV_TX_BUSY; + return 1; } /* Disable NIC interrupt */ diff --git a/trunk/drivers/net/tulip/uli526x.c b/trunk/drivers/net/tulip/uli526x.c index 9277ce8febe4..8761a5a5bd79 100644 --- a/trunk/drivers/net/tulip/uli526x.c +++ b/trunk/drivers/net/tulip/uli526x.c @@ -591,7 +591,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) { spin_unlock_irqrestore(&db->lock, flags); printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_packet_cnt); - return NETDEV_TX_BUSY; + return 1; } /* Disable NIC interrupt */ diff --git a/trunk/drivers/net/usb/hso.c b/trunk/drivers/net/usb/hso.c index f8c6d7ea7264..e3580f42c899 100644 --- a/trunk/drivers/net/usb/hso.c +++ b/trunk/drivers/net/usb/hso.c @@ -816,7 +816,7 @@ static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net) } dev_kfree_skb(skb); /* we're done */ - return NETDEV_TX_OK; + return result; } static void hso_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) diff --git a/trunk/drivers/net/wan/cycx_x25.c b/trunk/drivers/net/wan/cycx_x25.c index f525f9fe74db..35dea3bea95d 100644 --- a/trunk/drivers/net/wan/cycx_x25.c +++ b/trunk/drivers/net/wan/cycx_x25.c @@ -615,7 +615,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, case WAN_DISCONNECTED: if (cycx_x25_chan_connect(dev)) { netif_stop_queue(dev); - return NETDEV_TX_BUSY; + return -EBUSY; } /* fall thru */ case WAN_CONNECTED: @@ -624,7 +624,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, netif_stop_queue(dev); if (cycx_x25_chan_send(dev, skb)) - return NETDEV_TX_BUSY; + return -EBUSY; break; default: @@ -656,7 +656,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, if (cycx_x25_chan_send(dev, skb)) { /* prepare for future retransmissions */ skb_push(skb, 1); - return NETDEV_TX_BUSY; + return -EBUSY; } } diff --git a/trunk/drivers/net/wan/dlci.c b/trunk/drivers/net/wan/dlci.c index 2fa275a58f9d..e8d155c3e59f 100644 --- a/trunk/drivers/net/wan/dlci.c +++ b/trunk/drivers/net/wan/dlci.c @@ -205,15 +205,15 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) { case DLCI_RET_OK: dev->stats.tx_packets++; - ret = NETDEV_TX_OK; + ret = 0; break; case DLCI_RET_ERR: dev->stats.tx_errors++; - ret = NETDEV_TX_OK; + ret = 0; break; case DLCI_RET_DROP: dev->stats.tx_dropped++; - ret = NETDEV_TX_BUSY; + ret = 1; break; } /* Alan Cox recommends always returning 0, and always freeing the packet */ diff --git a/trunk/drivers/net/wan/sbni.c b/trunk/drivers/net/wan/sbni.c index 3fb9dbc88a1a..f4211fe0f445 100644 --- a/trunk/drivers/net/wan/sbni.c +++ b/trunk/drivers/net/wan/sbni.c @@ -469,7 +469,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) } } - return NETDEV_TX_BUSY; + return 1; } #else /* CONFIG_SBNI_MULTILINE */ diff --git a/trunk/drivers/net/wan/wanxl.c b/trunk/drivers/net/wan/wanxl.c index e4ad7b6b52eb..8130b79a8a99 100644 --- a/trunk/drivers/net/wan/wanxl.c +++ b/trunk/drivers/net/wan/wanxl.c @@ -283,7 +283,7 @@ static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev) #endif netif_stop_queue(dev); spin_unlock_irq(&port->lock); - return NETDEV_TX_BUSY; /* request packet to be queued */ + return 1; /* request packet to be queued */ } #ifdef DEBUG_PKT diff --git a/trunk/drivers/net/wireless/airo.c b/trunk/drivers/net/wireless/airo.c index c70604f0329e..9eabf4d1f2e7 100644 --- a/trunk/drivers/net/wireless/airo.c +++ b/trunk/drivers/net/wireless/airo.c @@ -1935,7 +1935,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { netif_stop_queue (dev); if (npacks > MAXTXQ) { dev->stats.tx_fifo_errors++; - return NETDEV_TX_BUSY; + return 1; } skb_queue_tail (&ai->txq, skb); return 0; @@ -2139,7 +2139,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { if (i == MAX_FIDS / 2) { dev->stats.tx_fifo_errors++; - return NETDEV_TX_BUSY; + return 1; } } /* check min length*/ @@ -2193,8 +2193,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { if (test_bit(FLAG_MPI, &priv->flags)) { /* Not implemented yet for MPI350 */ netif_stop_queue(dev); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; + return -ENETDOWN; } if ( skb == NULL ) { @@ -2211,7 +2210,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { if (i == MAX_FIDS) { dev->stats.tx_fifo_errors++; - return NETDEV_TX_BUSY; + return 1; } } /* check min length*/ diff --git a/trunk/drivers/net/wireless/arlan-main.c b/trunk/drivers/net/wireless/arlan-main.c index d84caf198a23..a54a67c425c8 100644 --- a/trunk/drivers/net/wireless/arlan-main.c +++ b/trunk/drivers/net/wireless/arlan-main.c @@ -1199,7 +1199,7 @@ static int arlan_tx(struct sk_buff *skb, struct net_device *dev) arlan_process_interrupt(dev); netif_stop_queue (dev); ARLAN_DEBUG_EXIT("arlan_tx"); - return NETDEV_TX_BUSY; + return 1; } diff --git a/trunk/drivers/net/wireless/atmel.c b/trunk/drivers/net/wireless/atmel.c index 291a94bd46fd..27eef8fb7107 100644 --- a/trunk/drivers/net/wireless/atmel.c +++ b/trunk/drivers/net/wireless/atmel.c @@ -818,7 +818,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->irqlock, flags); spin_unlock_bh(&priv->timerlock); netif_stop_queue(dev); - return NETDEV_TX_BUSY; + return 1; } frame_ctl = IEEE80211_FTYPE_DATA; diff --git a/trunk/drivers/net/wireless/hostap/hostap_80211_tx.c b/trunk/drivers/net/wireless/hostap/hostap_80211_tx.c index d313b005114e..6693423f63fe 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/trunk/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -377,7 +377,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct hostap_interface *iface; local_info_t *local; - int ret = NETDEV_TX_BUSY; + int ret = 1; u16 fc; struct hostap_tx_data tx; ap_tx_ret tx_ret; diff --git a/trunk/drivers/net/wireless/ipw2x00/ipw2200.c b/trunk/drivers/net/wireless/ipw2x00/ipw2200.c index 44c29b3f6728..c3b3dfe43d1a 100644 --- a/trunk/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/trunk/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11524,8 +11524,7 @@ static int ipw_prom_stop(struct net_device *dev) static int ipw_prom_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { IPW_DEBUG_INFO("prom dev->xmit\n"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; + return -EOPNOTSUPP; } static const struct net_device_ops ipw_prom_netdev_ops = { diff --git a/trunk/drivers/net/wireless/ipw2x00/libipw_tx.c b/trunk/drivers/net/wireless/ipw2x00/libipw_tx.c index da2ad5437ce5..65a8195b3d90 100644 --- a/trunk/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/trunk/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -539,7 +539,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&ieee->lock, flags); netif_stop_queue(dev); dev->stats.tx_errors++; - return NETDEV_TX_BUSY; + return 1; } EXPORT_SYMBOL(ieee80211_xmit); diff --git a/trunk/drivers/net/wireless/prism54/islpci_eth.c b/trunk/drivers/net/wireless/prism54/islpci_eth.c index 8f6210993448..ef3ef4551b31 100644 --- a/trunk/drivers/net/wireless/prism54/islpci_eth.c +++ b/trunk/drivers/net/wireless/prism54/islpci_eth.c @@ -87,6 +87,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) unsigned long flags; unsigned char wds_mac[6]; u32 curr_frag; + int err = 0; #if VERBOSE > SHOW_ERROR_MESSAGES DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n"); @@ -106,6 +107,8 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE, ISL38XX_DEV_INT_REG); udelay(ISL38XX_WRITEIO_DELAY); + + err = -EBUSY; goto drop_free; } /* Check alignment and WDS frame formatting. The start of the packet should @@ -149,6 +152,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) if (unlikely(newskb == NULL)) { printk(KERN_ERR "%s: Cannot allocate skb\n", ndev->name); + err = -ENOMEM; goto drop_free; } newskb_offset = (4 - (long) newskb->data) & 0x03; @@ -193,6 +197,8 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) if (unlikely(pci_map_address == 0)) { printk(KERN_WARNING "%s: cannot map buffer to PCI\n", ndev->name); + + err = -EIO; goto drop_free; } /* Place the fragment in the control block structure. */ @@ -240,7 +246,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) ndev->stats.tx_dropped++; spin_unlock_irqrestore(&priv->slock, flags); dev_kfree_skb(skb); - return NETDEV_TX_OK; + return err; } static inline int diff --git a/trunk/drivers/net/wireless/ray_cs.c b/trunk/drivers/net/wireless/ray_cs.c index b10b0383dfa5..22e71856aa24 100644 --- a/trunk/drivers/net/wireless/ray_cs.c +++ b/trunk/drivers/net/wireless/ray_cs.c @@ -923,7 +923,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!(pcmcia_dev_present(link))) { DEBUG(2, "ray_dev_start_xmit - device not present\n"); - return NETDEV_TX_LOCKED; + return -1; } DEBUG(3, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev); if (local->authentication_state == NEED_TO_AUTH) { @@ -931,7 +931,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!build_auth_frame(local, local->auth_id, OPEN_AUTH_REQUEST)) { local->authentication_state = AUTHENTICATED; netif_stop_queue(dev); - return NETDEV_TX_BUSY; + return 1; } } @@ -944,7 +944,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) case XMIT_NO_CCS: case XMIT_NEED_AUTH: netif_stop_queue(dev); - return NETDEV_TX_BUSY; + return 1; case XMIT_NO_INTR: case XMIT_MSG_BAD: case XMIT_OK: diff --git a/trunk/drivers/net/wireless/strip.c b/trunk/drivers/net/wireless/strip.c index 38366a56b71f..b7b0c46adb46 100644 --- a/trunk/drivers/net/wireless/strip.c +++ b/trunk/drivers/net/wireless/strip.c @@ -1540,7 +1540,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev) if (!netif_running(dev)) { printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); - return NETDEV_TX_BUSY; + return (1); } netif_stop_queue(dev); diff --git a/trunk/drivers/net/wireless/wavelan.c b/trunk/drivers/net/wireless/wavelan.c index ab7fc5c0c8b4..25d27b64f528 100644 --- a/trunk/drivers/net/wireless/wavelan.c +++ b/trunk/drivers/net/wireless/wavelan.c @@ -2867,7 +2867,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) spin_unlock_irqrestore(&lp->spinlock, flags); /* Check that we can continue */ if (lp->tx_n_in_use == (NTXBLOCKS - 1)) - return NETDEV_TX_BUSY; + return 1; } /* Do we need some padding? */ @@ -2880,10 +2880,10 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) skb_copy_from_linear_data(skb, data, skb->len); /* Write packet on the card */ if(wv_packet_write(dev, data, ETH_ZLEN)) - return NETDEV_TX_BUSY; /* We failed */ + return 1; /* We failed */ } else if(wv_packet_write(dev, skb->data, skb->len)) - return NETDEV_TX_BUSY; /* We failed */ + return 1; /* We failed */ dev_kfree_skb(skb); diff --git a/trunk/drivers/net/wireless/wl3501_cs.c b/trunk/drivers/net/wireless/wl3501_cs.c index e3e96bb2c246..1f64d6033ab5 100644 --- a/trunk/drivers/net/wireless/wl3501_cs.c +++ b/trunk/drivers/net/wireless/wl3501_cs.c @@ -1348,7 +1348,6 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (rc) { ++dev->stats.tx_dropped; netif_stop_queue(dev); - rc = NETDEV_TX_OK; } else { ++dev->stats.tx_packets; dev->stats.tx_bytes += skb->len; diff --git a/trunk/drivers/net/wireless/zd1201.c b/trunk/drivers/net/wireless/zd1201.c index 4430b8d92e21..5fabd9c0f07a 100644 --- a/trunk/drivers/net/wireless/zd1201.c +++ b/trunk/drivers/net/wireless/zd1201.c @@ -819,11 +819,11 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (err) { dev->stats.tx_errors++; netif_start_queue(dev); - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - dev->trans_start = jiffies; + return err; } + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + dev->trans_start = jiffies; kfree_skb(skb); return 0; diff --git a/trunk/drivers/s390/net/claw.c b/trunk/drivers/s390/net/claw.c index 7b6f46ddf3c3..30a43cc79e76 100644 --- a/trunk/drivers/s390/net/claw.c +++ b/trunk/drivers/s390/net/claw.c @@ -338,6 +338,12 @@ claw_tx(struct sk_buff *skb, struct net_device *dev) CLAW_DBF_TEXT(4, trace, "claw_tx"); p_ch=&privptr->channel[WRITE]; + if (skb == NULL) { + privptr->stats.tx_dropped++; + privptr->stats.tx_errors++; + CLAW_DBF_TEXT_(2, trace, "clawtx%d", -EIO); + return -EIO; + } spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags); rc=claw_hw_tx( skb, dev, 1 ); spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags); diff --git a/trunk/drivers/s390/net/netiucv.c b/trunk/drivers/s390/net/netiucv.c index aec9e5d3cf4b..be716e45f7ac 100644 --- a/trunk/drivers/s390/net/netiucv.c +++ b/trunk/drivers/s390/net/netiucv.c @@ -1315,9 +1315,9 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } dev->trans_start = jiffies; - rc = netiucv_transmit_skb(privptr->conn, skb); + rc = netiucv_transmit_skb(privptr->conn, skb) != 0; netiucv_clear_busy(dev); - return rc ? NETDEV_TX_BUSY : NETDEV_TX_OK; + return rc; } /** diff --git a/trunk/drivers/staging/at76_usb/at76_usb.c b/trunk/drivers/staging/at76_usb/at76_usb.c index 3f303ae97b43..c8af9a868d62 100644 --- a/trunk/drivers/staging/at76_usb/at76_usb.c +++ b/trunk/drivers/staging/at76_usb/at76_usb.c @@ -3242,11 +3242,12 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev) "%s: -EINVAL: tx urb %p hcpriv %p complete %p\n", priv->netdev->name, priv->tx_urb, priv->tx_urb->hcpriv, priv->tx_urb->complete); - } else + } else { stats->tx_bytes += skb->len; + dev_kfree_skb(skb); + } - dev_kfree_skb(skb); - return NETDEV_TX_OK; + return ret; } static void at76_tx_timeout(struct net_device *netdev) diff --git a/trunk/drivers/staging/et131x/et131x_netdev.c b/trunk/drivers/staging/et131x/et131x_netdev.c index 59e99cc7786b..951c73d5db20 100644 --- a/trunk/drivers/staging/et131x/et131x_netdev.c +++ b/trunk/drivers/staging/et131x/et131x_netdev.c @@ -585,11 +585,11 @@ int et131x_tx(struct sk_buff *skb, struct net_device *netdev) * available */ netif_stop_queue(netdev); - status = NETDEV_TX_BUSY; + status = 1; } else { DBG_WARNING(et131x_dbginfo, "Misc error; drop packet\n"); - status = NETDEV_TX_OK; + status = 0; } } diff --git a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c index 1294e05fcf13..33a0687252af 100644 --- a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c +++ b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c @@ -814,7 +814,7 @@ int ieee80211_xmit(struct sk_buff *skb, spin_unlock_irqrestore(&ieee->lock, flags); netif_stop_queue(dev); stats->tx_errors++; - return NETDEV_TX_BUSY; + return 1; } diff --git a/trunk/drivers/staging/wlan-ng/p80211netdev.c b/trunk/drivers/staging/wlan-ng/p80211netdev.c index bc0d764d851a..393e4df70dfd 100644 --- a/trunk/drivers/staging/wlan-ng/p80211netdev.c +++ b/trunk/drivers/staging/wlan-ng/p80211netdev.c @@ -432,21 +432,21 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb, /* success and more buf */ /* avail, re: hw_txdata */ netif_wake_queue(wlandev->netdev); - result = NETDEV_TX_OK; + result = 0; } else if (txresult == 1) { /* success, no more avail */ pr_debug("txframe success, no more bufs\n"); /* netdev->tbusy = 1; don't set here, irqhdlr */ /* may have already cleared it */ - result = NETDEV_TX_OK; + result = 0; } else if (txresult == 2) { /* alloc failure, drop frame */ pr_debug("txframe returned alloc_fail\n"); - result = NETDEV_TX_BUSY; + result = 1; } else { /* buffer full or queue busy, drop frame. */ pr_debug("txframe returned full or busy\n"); - result = NETDEV_TX_BUSY; + result = 1; } failed: diff --git a/trunk/drivers/usb/gadget/u_ether.c b/trunk/drivers/usb/gadget/u_ether.c index 016f63b39028..4007770f7ed2 100644 --- a/trunk/drivers/usb/gadget/u_ether.c +++ b/trunk/drivers/usb/gadget/u_ether.c @@ -520,7 +520,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net) */ if (list_empty(&dev->tx_reqs)) { spin_unlock_irqrestore(&dev->req_lock, flags); - return NETDEV_TX_BUSY; + return 1; } req = container_of(dev->tx_reqs.next, struct usb_request, list); diff --git a/trunk/include/linux/list_nulls.h b/trunk/include/linux/list_nulls.h index 5d10ae364b5e..93150ecf3ea4 100644 --- a/trunk/include/linux/list_nulls.h +++ b/trunk/include/linux/list_nulls.h @@ -56,18 +56,6 @@ static inline int hlist_nulls_empty(const struct hlist_nulls_head *h) return is_a_nulls(h->first); } -static inline void hlist_nulls_add_head(struct hlist_nulls_node *n, - struct hlist_nulls_head *h) -{ - struct hlist_nulls_node *first = h->first; - - n->next = first; - n->pprev = &h->first; - h->first = n; - if (!is_a_nulls(first)) - first->pprev = &n->next; -} - static inline void __hlist_nulls_del(struct hlist_nulls_node *n) { struct hlist_nulls_node *next = n->next; @@ -77,12 +65,6 @@ static inline void __hlist_nulls_del(struct hlist_nulls_node *n) next->pprev = pprev; } -static inline void hlist_nulls_del(struct hlist_nulls_node *n) -{ - __hlist_nulls_del(n); - n->pprev = LIST_POISON2; -} - /** * hlist_nulls_for_each_entry - iterate over list of given type * @tpos: the type * to use as a loop cursor. diff --git a/trunk/include/net/netfilter/nf_conntrack.h b/trunk/include/net/netfilter/nf_conntrack.h index a632689b61b4..ecc79f959076 100644 --- a/trunk/include/net/netfilter/nf_conntrack.h +++ b/trunk/include/net/netfilter/nf_conntrack.h @@ -201,8 +201,6 @@ extern struct nf_conntrack_tuple_hash * __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); extern void nf_conntrack_hash_insert(struct nf_conn *ct); -extern void nf_ct_delete_from_lists(struct nf_conn *ct); -extern void nf_ct_insert_dying_list(struct nf_conn *ct); extern void nf_conntrack_flush_report(struct net *net, u32 pid, int report); diff --git a/trunk/include/net/netfilter/nf_conntrack_ecache.h b/trunk/include/net/netfilter/nf_conntrack_ecache.h index 4f20d58e2ab7..1afb907e015a 100644 --- a/trunk/include/net/netfilter/nf_conntrack_ecache.h +++ b/trunk/include/net/netfilter/nf_conntrack_ecache.h @@ -6,54 +6,61 @@ #define _NF_CONNTRACK_ECACHE_H #include +#include #include #include -#include -#include -#include -/* Connection tracking event types */ +/* Connection tracking event bits */ enum ip_conntrack_events { - IPCT_NEW = 0, /* new conntrack */ - IPCT_RELATED = 1, /* related conntrack */ - IPCT_DESTROY = 2, /* destroyed conntrack */ - IPCT_STATUS = 3, /* status has changed */ - IPCT_PROTOINFO = 4, /* protocol information has changed */ - IPCT_HELPER = 5, /* new helper has been set */ - IPCT_MARK = 6, /* new mark has been set */ - IPCT_NATSEQADJ = 7, /* NAT is doing sequence adjustment */ - IPCT_SECMARK = 8, /* new security mark has been set */ -}; + /* New conntrack */ + IPCT_NEW_BIT = 0, + IPCT_NEW = (1 << IPCT_NEW_BIT), -enum ip_conntrack_expect_events { - IPEXP_NEW = 0, /* new expectation */ -}; + /* Expected connection */ + IPCT_RELATED_BIT = 1, + IPCT_RELATED = (1 << IPCT_RELATED_BIT), -struct nf_conntrack_ecache { - unsigned long cache; /* bitops want long */ - unsigned long missed; /* missed events */ - u32 pid; /* netlink pid of destroyer */ -}; + /* Destroyed conntrack */ + IPCT_DESTROY_BIT = 2, + IPCT_DESTROY = (1 << IPCT_DESTROY_BIT), -static inline struct nf_conntrack_ecache * -nf_ct_ecache_find(const struct nf_conn *ct) -{ - return nf_ct_ext_find(ct, NF_CT_EXT_ECACHE); -} + /* Status has changed */ + IPCT_STATUS_BIT = 3, + IPCT_STATUS = (1 << IPCT_STATUS_BIT), -static inline struct nf_conntrack_ecache * -nf_ct_ecache_ext_add(struct nf_conn *ct, gfp_t gfp) -{ - struct net *net = nf_ct_net(ct); + /* Update of protocol info */ + IPCT_PROTOINFO_BIT = 4, + IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT), + + /* New helper for conntrack */ + IPCT_HELPER_BIT = 5, + IPCT_HELPER = (1 << IPCT_HELPER_BIT), - if (!net->ct.sysctl_events) - return NULL; + /* Mark is set */ + IPCT_MARK_BIT = 6, + IPCT_MARK = (1 << IPCT_MARK_BIT), - return nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp); + /* NAT sequence adjustment */ + IPCT_NATSEQADJ_BIT = 7, + IPCT_NATSEQADJ = (1 << IPCT_NATSEQADJ_BIT), + + /* Secmark is set */ + IPCT_SECMARK_BIT = 8, + IPCT_SECMARK = (1 << IPCT_SECMARK_BIT), +}; + +enum ip_conntrack_expect_events { + IPEXP_NEW_BIT = 0, + IPEXP_NEW = (1 << IPEXP_NEW_BIT), }; #ifdef CONFIG_NF_CONNTRACK_EVENTS +struct nf_conntrack_ecache { + struct nf_conn *ct; + unsigned int events; +}; + /* This structure is passed to event handler */ struct nf_ct_event { struct nf_conn *ct; @@ -69,88 +76,53 @@ extern struct nf_ct_event_notifier *nf_conntrack_event_cb; extern int nf_conntrack_register_notifier(struct nf_ct_event_notifier *nb); extern void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *nb); -extern void nf_ct_deliver_cached_events(struct nf_conn *ct); +extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); +extern void __nf_ct_event_cache_init(struct nf_conn *ct); +extern void nf_ct_event_cache_flush(struct net *net); static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) { - struct nf_conntrack_ecache *e; - - if (nf_conntrack_event_cb == NULL) - return; - - e = nf_ct_ecache_find(ct); - if (e == NULL) - return; - - set_bit(event, &e->cache); + struct net *net = nf_ct_net(ct); + struct nf_conntrack_ecache *ecache; + + local_bh_disable(); + ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id()); + if (ct != ecache->ct) + __nf_ct_event_cache_init(ct); + ecache->events |= event; + local_bh_enable(); } -static inline int -nf_conntrack_eventmask_report(unsigned int eventmask, - struct nf_conn *ct, - u32 pid, - int report) +static inline void +nf_conntrack_event_report(enum ip_conntrack_events event, + struct nf_conn *ct, + u32 pid, + int report) { - int ret = 0; - struct net *net = nf_ct_net(ct); struct nf_ct_event_notifier *notify; - struct nf_conntrack_ecache *e; rcu_read_lock(); notify = rcu_dereference(nf_conntrack_event_cb); if (notify == NULL) goto out_unlock; - if (!net->ct.sysctl_events) - goto out_unlock; - - e = nf_ct_ecache_find(ct); - if (e == NULL) - goto out_unlock; - if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) { struct nf_ct_event item = { .ct = ct, - .pid = e->pid ? e->pid : pid, + .pid = pid, .report = report }; - /* This is a resent of a destroy event? If so, skip missed */ - unsigned long missed = e->pid ? 0 : e->missed; - - ret = notify->fcn(eventmask | missed, &item); - if (unlikely(ret < 0 || missed)) { - spin_lock_bh(&ct->lock); - if (ret < 0) { - /* This is a destroy event that has been - * triggered by a process, we store the PID - * to include it in the retransmission. */ - if (eventmask & (1 << IPCT_DESTROY) && - e->pid == 0 && pid != 0) - e->pid = pid; - else - e->missed |= eventmask; - } else - e->missed &= ~missed; - spin_unlock_bh(&ct->lock); - } + notify->fcn(event, &item); } out_unlock: rcu_read_unlock(); - return ret; } -static inline int -nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct, - u32 pid, int report) -{ - return nf_conntrack_eventmask_report(1 << event, ct, pid, report); -} - -static inline int +static inline void nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) { - return nf_conntrack_eventmask_report(1 << event, ct, 0, 0); + nf_conntrack_event_report(event, ct, 0, 0); } struct nf_exp_event { @@ -173,7 +145,6 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event, u32 pid, int report) { - struct net *net = nf_ct_exp_net(exp); struct nf_exp_event_notifier *notify; rcu_read_lock(); @@ -181,16 +152,13 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event, if (notify == NULL) goto out_unlock; - if (!net->ct.sysctl_events) - goto out_unlock; - { struct nf_exp_event item = { .exp = exp, .pid = pid, .report = report }; - notify->fcn(1 << event, &item); + notify->fcn(event, &item); } out_unlock: rcu_read_unlock(); @@ -210,16 +178,12 @@ extern void nf_conntrack_ecache_fini(struct net *net); static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) {} -static inline int nf_conntrack_eventmask_report(unsigned int eventmask, - struct nf_conn *ct, - u32 pid, - int report) { return 0; } -static inline int nf_conntrack_event(enum ip_conntrack_events event, - struct nf_conn *ct) { return 0; } -static inline int nf_conntrack_event_report(enum ip_conntrack_events event, - struct nf_conn *ct, - u32 pid, - int report) { return 0; } +static inline void nf_conntrack_event(enum ip_conntrack_events event, + struct nf_conn *ct) {} +static inline void nf_conntrack_event_report(enum ip_conntrack_events event, + struct nf_conn *ct, + u32 pid, + int report) {} static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {} static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event, struct nf_conntrack_expect *exp) {} @@ -227,6 +191,7 @@ static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e, struct nf_conntrack_expect *exp, u32 pid, int report) {} +static inline void nf_ct_event_cache_flush(struct net *net) {} static inline int nf_conntrack_ecache_init(struct net *net) { diff --git a/trunk/include/net/netfilter/nf_conntrack_extend.h b/trunk/include/net/netfilter/nf_conntrack_extend.h index 7f8fc5d123c5..da8ee52613a5 100644 --- a/trunk/include/net/netfilter/nf_conntrack_extend.h +++ b/trunk/include/net/netfilter/nf_conntrack_extend.h @@ -8,14 +8,12 @@ enum nf_ct_ext_id NF_CT_EXT_HELPER, NF_CT_EXT_NAT, NF_CT_EXT_ACCT, - NF_CT_EXT_ECACHE, NF_CT_EXT_NUM, }; #define NF_CT_EXT_HELPER_TYPE struct nf_conn_help #define NF_CT_EXT_NAT_TYPE struct nf_conn_nat #define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter -#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache /* Extensions: optional stuff which isn't permanently in struct. */ struct nf_ct_ext { diff --git a/trunk/include/net/netfilter/nf_conntrack_helper.h b/trunk/include/net/netfilter/nf_conntrack_helper.h index 1b7068000927..ee2a4b369a04 100644 --- a/trunk/include/net/netfilter/nf_conntrack_helper.h +++ b/trunk/include/net/netfilter/nf_conntrack_helper.h @@ -50,8 +50,6 @@ extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp); extern int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags); -extern void nf_ct_helper_destroy(struct nf_conn *ct); - static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) { return nf_ct_ext_find(ct, NF_CT_EXT_HELPER); diff --git a/trunk/include/net/netns/conntrack.h b/trunk/include/net/netns/conntrack.h index ba1ba0c5efd1..9dc58402bc09 100644 --- a/trunk/include/net/netns/conntrack.h +++ b/trunk/include/net/netns/conntrack.h @@ -14,17 +14,16 @@ struct netns_ct { struct hlist_nulls_head *hash; struct hlist_head *expect_hash; struct hlist_nulls_head unconfirmed; - struct hlist_nulls_head dying; struct ip_conntrack_stat *stat; - int sysctl_events; - unsigned int sysctl_events_retry_timeout; +#ifdef CONFIG_NF_CONNTRACK_EVENTS + struct nf_conntrack_ecache *ecache; +#endif int sysctl_acct; int sysctl_checksum; unsigned int sysctl_log_invalid; /* Log invalid packets */ #ifdef CONFIG_SYSCTL struct ctl_table_header *sysctl_header; struct ctl_table_header *acct_sysctl_header; - struct ctl_table_header *event_sysctl_header; #endif int hash_vmalloc; int expect_vmalloc; diff --git a/trunk/net/atm/lec.c b/trunk/net/atm/lec.c index ff2e594dca9b..199b6bb79f42 100644 --- a/trunk/net/atm/lec.c +++ b/trunk/net/atm/lec.c @@ -34,6 +34,7 @@ /* Proxy LEC knows about bridging */ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) +#include #include "../bridge/br_private.h" static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 }; @@ -270,8 +271,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) printk("%s:No lecd attached\n", dev->name); dev->stats.tx_errors++; netif_stop_queue(dev); - kfree_skb(skb); - return NETDEV_TX_OK; + return -EUNATCH; } pr_debug("skbuff head:%lx data:%lx tail:%lx end:%lx\n", @@ -518,14 +518,18 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) case l_should_bridge: #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) { + struct net_bridge_fdb_entry *f; + pr_debug("%s: bridge zeppelin asks about %pM\n", dev->name, mesg->content.proxy.mac_addr); - if (br_fdb_test_addr_hook == NULL) + if (br_fdb_get_hook == NULL || dev->br_port == NULL) break; - if (br_fdb_test_addr_hook(dev, - mesg->content.proxy.mac_addr)) { + f = br_fdb_get_hook(dev->br_port->br, + mesg->content.proxy.mac_addr); + if (f != NULL && f->dst->dev != dev + && f->dst->state == BR_STATE_FORWARDING) { /* hit from bridge table, send LE_ARP_RESPONSE */ struct sk_buff *skb2; struct sock *sk; @@ -536,8 +540,10 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); - if (skb2 == NULL) + if (skb2 == NULL) { + br_fdb_put_hook(f); break; + } skb2->len = sizeof(struct atmlec_msg); skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg)); @@ -546,6 +552,8 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) skb_queue_tail(&sk->sk_receive_queue, skb2); sk->sk_data_ready(sk, skb2->len); } + if (f != NULL) + br_fdb_put_hook(f); } #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ break; diff --git a/trunk/net/bridge/br.c b/trunk/net/bridge/br.c index 9aac5213105a..4d2c1f1cb524 100644 --- a/trunk/net/bridge/br.c +++ b/trunk/net/bridge/br.c @@ -65,9 +65,8 @@ static int __init br_init(void) brioctl_set(br_ioctl_deviceless_stub); br_handle_frame_hook = br_handle_frame; -#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) - br_fdb_test_addr_hook = br_fdb_test_addr; -#endif + br_fdb_get_hook = br_fdb_get; + br_fdb_put_hook = br_fdb_put; return 0; err_out4: @@ -96,9 +95,8 @@ static void __exit br_deinit(void) synchronize_net(); br_netfilter_fini(); -#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) - br_fdb_test_addr_hook = NULL; -#endif + br_fdb_get_hook = NULL; + br_fdb_put_hook = NULL; br_handle_frame_hook = NULL; br_fdb_fini(); diff --git a/trunk/net/bridge/br_fdb.c b/trunk/net/bridge/br_fdb.c index 57bf05c353bc..cb3e97b93aeb 100644 --- a/trunk/net/bridge/br_fdb.c +++ b/trunk/net/bridge/br_fdb.c @@ -71,17 +71,10 @@ static inline int br_mac_hash(const unsigned char *mac) return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1); } -static void fdb_rcu_free(struct rcu_head *head) -{ - struct net_bridge_fdb_entry *ent - = container_of(head, struct net_bridge_fdb_entry, rcu); - kmem_cache_free(br_fdb_cache, ent); -} - static inline void fdb_delete(struct net_bridge_fdb_entry *f) { hlist_del_rcu(&f->hlist); - call_rcu(&f->rcu, fdb_rcu_free); + br_fdb_put(f); } void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) @@ -233,26 +226,33 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, return NULL; } -#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) -/* Interface used by ATM LANE hook to test - * if an addr is on some other bridge port */ -int br_fdb_test_addr(struct net_device *dev, unsigned char *addr) +/* Interface used by ATM hook that keeps a ref count */ +struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, + unsigned char *addr) { struct net_bridge_fdb_entry *fdb; - int ret; - - if (!dev->br_port) - return 0; rcu_read_lock(); - fdb = __br_fdb_get(dev->br_port->br, addr); - ret = fdb && fdb->dst->dev != dev && - fdb->dst->state == BR_STATE_FORWARDING; + fdb = __br_fdb_get(br, addr); + if (fdb && !atomic_inc_not_zero(&fdb->use_count)) + fdb = NULL; rcu_read_unlock(); + return fdb; +} - return ret; +static void fdb_rcu_free(struct rcu_head *head) +{ + struct net_bridge_fdb_entry *ent + = container_of(head, struct net_bridge_fdb_entry, rcu); + kmem_cache_free(br_fdb_cache, ent); +} + +/* Set entry up for deletion with RCU */ +void br_fdb_put(struct net_bridge_fdb_entry *ent) +{ + if (atomic_dec_and_test(&ent->use_count)) + call_rcu(&ent->rcu, fdb_rcu_free); } -#endif /* CONFIG_ATM_LANE */ /* * Fill buffer with forwarding table records in @@ -326,6 +326,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC); if (fdb) { memcpy(fdb->addr.addr, addr, ETH_ALEN); + atomic_set(&fdb->use_count, 1); hlist_add_head_rcu(&fdb->hlist, head); fdb->dst = source; diff --git a/trunk/net/bridge/br_private.h b/trunk/net/bridge/br_private.h index d5b5537272b4..b6c3b71974dc 100644 --- a/trunk/net/bridge/br_private.h +++ b/trunk/net/bridge/br_private.h @@ -51,6 +51,7 @@ struct net_bridge_fdb_entry struct net_bridge_port *dst; struct rcu_head rcu; + atomic_t use_count; unsigned long ageing_timer; mac_addr addr; unsigned char is_local; @@ -153,7 +154,9 @@ extern void br_fdb_delete_by_port(struct net_bridge *br, const struct net_bridge_port *p, int do_all); extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, const unsigned char *addr); -extern int br_fdb_test_addr(struct net_device *dev, unsigned char *addr); +extern struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, + unsigned char *addr); +extern void br_fdb_put(struct net_bridge_fdb_entry *ent); extern int br_fdb_fillbuf(struct net_bridge *br, void *buf, unsigned long count, unsigned long off); extern int br_fdb_insert(struct net_bridge *br, @@ -239,9 +242,10 @@ extern void br_stp_port_timer_init(struct net_bridge_port *p); extern unsigned long br_timer_value(const struct timer_list *timer); /* br.c */ -#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) -extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr); -#endif +extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, + unsigned char *addr); +extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent); + /* br_netlink.c */ extern int br_netlink_init(void); diff --git a/trunk/net/core/dev.c b/trunk/net/core/dev.c index ea00e36f48e1..11560e3258b5 100644 --- a/trunk/net/core/dev.c +++ b/trunk/net/core/dev.c @@ -2071,13 +2071,11 @@ static inline int deliver_skb(struct sk_buff *skb, } #if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE) - -#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) -/* This hook is defined here for ATM LANE */ -int (*br_fdb_test_addr_hook)(struct net_device *dev, - unsigned char *addr) __read_mostly; -EXPORT_SYMBOL(br_fdb_test_addr_hook); -#endif +/* These hooks defined here for ATM */ +struct net_bridge; +struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, + unsigned char *addr); +void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) __read_mostly; /* * If bridge module is loaded call bridging hook. @@ -2085,8 +2083,6 @@ EXPORT_SYMBOL(br_fdb_test_addr_hook); */ struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff *skb) __read_mostly; -EXPORT_SYMBOL(br_handle_frame_hook); - static inline struct sk_buff *handle_bridge(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, struct net_device *orig_dev) @@ -4213,7 +4209,7 @@ static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cm switch (cmd) { case SIOCGIFFLAGS: /* Get interface flags */ - ifr->ifr_flags = (short) dev_get_flags(dev); + ifr->ifr_flags = dev_get_flags(dev); return 0; case SIOCGIFMETRIC: /* Get the metric on the interface @@ -5669,6 +5665,12 @@ EXPORT_SYMBOL(net_enable_timestamp); EXPORT_SYMBOL(net_disable_timestamp); EXPORT_SYMBOL(dev_get_flags); +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) +EXPORT_SYMBOL(br_handle_frame_hook); +EXPORT_SYMBOL(br_fdb_get_hook); +EXPORT_SYMBOL(br_fdb_put_hook); +#endif + EXPORT_SYMBOL(dev_load); EXPORT_PER_CPU_SYMBOL(softnet_data); diff --git a/trunk/net/mac80211/tx.c b/trunk/net/mac80211/tx.c index d238a8939a09..364222bfb10d 100644 --- a/trunk/net/mac80211/tx.c +++ b/trunk/net/mac80211/tx.c @@ -1615,7 +1615,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; - int ret = NETDEV_TX_BUSY, head_need; + int ret = 1, head_need; u16 ethertype, hdrlen, meshhdrlen = 0; __le16 fc; struct ieee80211_hdr hdr; diff --git a/trunk/net/netfilter/nf_conntrack_core.c b/trunk/net/netfilter/nf_conntrack_core.c index 5f72b94b4918..edf95695e0aa 100644 --- a/trunk/net/netfilter/nf_conntrack_core.c +++ b/trunk/net/netfilter/nf_conntrack_core.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include @@ -183,6 +182,10 @@ destroy_conntrack(struct nf_conntrack *nfct) NF_CT_ASSERT(atomic_read(&nfct->use) == 0); NF_CT_ASSERT(!timer_pending(&ct->timeout)); + if (!test_bit(IPS_DYING_BIT, &ct->status)) + nf_conntrack_event(IPCT_DESTROY, ct); + set_bit(IPS_DYING_BIT, &ct->status); + /* To make sure we don't get any weird locking issues here: * destroy_conntrack() MUST NOT be called with a write lock * to nf_conntrack_lock!!! -HW */ @@ -216,70 +219,27 @@ destroy_conntrack(struct nf_conntrack *nfct) nf_conntrack_free(ct); } -void nf_ct_delete_from_lists(struct nf_conn *ct) +static void death_by_timeout(unsigned long ul_conntrack) { + struct nf_conn *ct = (void *)ul_conntrack; struct net *net = nf_ct_net(ct); + struct nf_conn_help *help = nfct_help(ct); + struct nf_conntrack_helper *helper; + + if (help) { + rcu_read_lock(); + helper = rcu_dereference(help->helper); + if (helper && helper->destroy) + helper->destroy(ct); + rcu_read_unlock(); + } - nf_ct_helper_destroy(ct); spin_lock_bh(&nf_conntrack_lock); /* Inside lock so preempt is disabled on module removal path. * Otherwise we can get spurious warnings. */ NF_CT_STAT_INC(net, delete_list); clean_from_lists(ct); spin_unlock_bh(&nf_conntrack_lock); -} -EXPORT_SYMBOL_GPL(nf_ct_delete_from_lists); - -static void death_by_event(unsigned long ul_conntrack) -{ - struct nf_conn *ct = (void *)ul_conntrack; - struct net *net = nf_ct_net(ct); - - if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) { - /* bad luck, let's retry again */ - ct->timeout.expires = jiffies + - (random32() % net->ct.sysctl_events_retry_timeout); - add_timer(&ct->timeout); - return; - } - /* we've got the event delivered, now it's dying */ - set_bit(IPS_DYING_BIT, &ct->status); - spin_lock(&nf_conntrack_lock); - hlist_nulls_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); - spin_unlock(&nf_conntrack_lock); - nf_ct_put(ct); -} - -void nf_ct_insert_dying_list(struct nf_conn *ct) -{ - struct net *net = nf_ct_net(ct); - - /* add this conntrack to the dying list */ - spin_lock_bh(&nf_conntrack_lock); - hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, - &net->ct.dying); - spin_unlock_bh(&nf_conntrack_lock); - /* set a new timer to retry event delivery */ - setup_timer(&ct->timeout, death_by_event, (unsigned long)ct); - ct->timeout.expires = jiffies + - (random32() % net->ct.sysctl_events_retry_timeout); - add_timer(&ct->timeout); -} -EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list); - -static void death_by_timeout(unsigned long ul_conntrack) -{ - struct nf_conn *ct = (void *)ul_conntrack; - - if (!test_bit(IPS_DYING_BIT, &ct->status) && - unlikely(nf_conntrack_event(IPCT_DESTROY, ct) < 0)) { - /* destroy event was not delivered */ - nf_ct_delete_from_lists(ct); - nf_ct_insert_dying_list(ct); - return; - } - set_bit(IPS_DYING_BIT, &ct->status); - nf_ct_delete_from_lists(ct); nf_ct_put(ct); } @@ -617,7 +577,6 @@ init_conntrack(struct net *net, } nf_ct_acct_ext_add(ct, GFP_ATOMIC); - nf_ct_ecache_ext_add(ct, GFP_ATOMIC); spin_lock_bh(&nf_conntrack_lock); exp = nf_ct_find_expectation(net, tuple); @@ -848,6 +807,8 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); NF_CT_ASSERT(skb); + spin_lock_bh(&nf_conntrack_lock); + /* Only update if this is not a fixed timeout */ if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) goto acct; @@ -861,8 +822,11 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, /* Only update the timeout if the new timeout is at least HZ jiffies from the old timeout. Need del_timer for race avoidance (may already be dying). */ - if (newtime - ct->timeout.expires >= HZ) - mod_timer_pending(&ct->timeout, newtime); + if (newtime - ct->timeout.expires >= HZ + && del_timer(&ct->timeout)) { + ct->timeout.expires = newtime; + add_timer(&ct->timeout); + } } acct: @@ -871,13 +835,13 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, acct = nf_conn_acct_find(ct); if (acct) { - spin_lock_bh(&ct->lock); acct[CTINFO2DIR(ctinfo)].packets++; acct[CTINFO2DIR(ctinfo)].bytes += skb->len - skb_network_offset(skb); - spin_unlock_bh(&ct->lock); } } + + spin_unlock_bh(&nf_conntrack_lock); } EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct); @@ -889,14 +853,14 @@ bool __nf_ct_kill_acct(struct nf_conn *ct, if (do_acct) { struct nf_conn_counter *acct; + spin_lock_bh(&nf_conntrack_lock); acct = nf_conn_acct_find(ct); if (acct) { - spin_lock_bh(&ct->lock); acct[CTINFO2DIR(ctinfo)].packets++; acct[CTINFO2DIR(ctinfo)].bytes += skb->len - skb_network_offset(skb); - spin_unlock_bh(&ct->lock); } + spin_unlock_bh(&nf_conntrack_lock); } if (del_timer(&ct->timeout)) { @@ -1030,13 +994,11 @@ static int kill_report(struct nf_conn *i, void *data) { struct __nf_ct_flush_report *fr = (struct __nf_ct_flush_report *)data; - /* If we fail to deliver the event, death_by_timeout() will retry */ - if (nf_conntrack_event_report(IPCT_DESTROY, i, - fr->pid, fr->report) < 0) - return 1; - - /* Avoid the delivery of the destroy event in death_by_timeout(). */ - set_bit(IPS_DYING_BIT, &i->status); + /* get_next_corpse sets the dying bit for us */ + nf_conntrack_event_report(IPCT_DESTROY, + i, + fr->pid, + fr->report); return 1; } @@ -1065,21 +1027,6 @@ void nf_conntrack_flush_report(struct net *net, u32 pid, int report) } EXPORT_SYMBOL_GPL(nf_conntrack_flush_report); -static void nf_ct_release_dying_list(void) -{ - struct nf_conntrack_tuple_hash *h; - struct nf_conn *ct; - struct hlist_nulls_node *n; - - spin_lock_bh(&nf_conntrack_lock); - hlist_nulls_for_each_entry(h, n, &init_net.ct.dying, hnnode) { - ct = nf_ct_tuplehash_to_ctrack(h); - /* never fails to remove them, no listeners at this point */ - nf_ct_kill(ct); - } - spin_unlock_bh(&nf_conntrack_lock); -} - static void nf_conntrack_cleanup_init_net(void) { nf_conntrack_helper_fini(); @@ -1089,9 +1036,10 @@ static void nf_conntrack_cleanup_init_net(void) static void nf_conntrack_cleanup_net(struct net *net) { + nf_ct_event_cache_flush(net); + nf_conntrack_ecache_fini(net); i_see_dead_people: nf_ct_iterate_cleanup(net, kill_all, NULL); - nf_ct_release_dying_list(); if (atomic_read(&net->ct.count) != 0) { schedule(); goto i_see_dead_people; @@ -1102,7 +1050,6 @@ static void nf_conntrack_cleanup_net(struct net *net) nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, nf_conntrack_htable_size); - nf_conntrack_ecache_fini(net); nf_conntrack_acct_fini(net); nf_conntrack_expect_fini(net); free_percpu(net->ct.stat); @@ -1273,12 +1220,14 @@ static int nf_conntrack_init_net(struct net *net) atomic_set(&net->ct.count, 0); INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, 0); - INIT_HLIST_NULLS_HEAD(&net->ct.dying, 0); net->ct.stat = alloc_percpu(struct ip_conntrack_stat); if (!net->ct.stat) { ret = -ENOMEM; goto err_stat; } + ret = nf_conntrack_ecache_init(net); + if (ret < 0) + goto err_ecache; net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, &net->ct.hash_vmalloc, 1); if (!net->ct.hash) { @@ -1292,9 +1241,6 @@ static int nf_conntrack_init_net(struct net *net) ret = nf_conntrack_acct_init(net); if (ret < 0) goto err_acct; - ret = nf_conntrack_ecache_init(net); - if (ret < 0) - goto err_ecache; /* Set up fake conntrack: - to never be deleted, not in any hashes */ @@ -1307,14 +1253,14 @@ static int nf_conntrack_init_net(struct net *net) return 0; -err_ecache: - nf_conntrack_acct_fini(net); err_acct: nf_conntrack_expect_fini(net); err_expect: nf_ct_free_hashtable(net->ct.hash, net->ct.hash_vmalloc, nf_conntrack_htable_size); err_hash: + nf_conntrack_ecache_fini(net); +err_ecache: free_percpu(net->ct.stat); err_stat: return ret; diff --git a/trunk/net/netfilter/nf_conntrack_ecache.c b/trunk/net/netfilter/nf_conntrack_ecache.c index aee560b4768d..5516b3e64b43 100644 --- a/trunk/net/netfilter/nf_conntrack_ecache.c +++ b/trunk/net/netfilter/nf_conntrack_ecache.c @@ -21,7 +21,6 @@ #include #include -#include static DEFINE_MUTEX(nf_ct_ecache_mutex); @@ -33,51 +32,94 @@ EXPORT_SYMBOL_GPL(nf_expect_event_cb); /* deliver cached events and clear cache entry - must be called with locally * disabled softirqs */ -void nf_ct_deliver_cached_events(struct nf_conn *ct) +static inline void +__nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache) { - unsigned long events; struct nf_ct_event_notifier *notify; - struct nf_conntrack_ecache *e; rcu_read_lock(); notify = rcu_dereference(nf_conntrack_event_cb); if (notify == NULL) goto out_unlock; - e = nf_ct_ecache_find(ct); - if (e == NULL) - goto out_unlock; - - events = xchg(&e->cache, 0); - - if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct) && events) { + if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) + && ecache->events) { struct nf_ct_event item = { - .ct = ct, + .ct = ecache->ct, .pid = 0, .report = 0 }; - int ret; - /* We make a copy of the missed event cache without taking - * the lock, thus we may send missed events twice. However, - * this does not harm and it happens very rarely. */ - unsigned long missed = e->missed; - ret = notify->fcn(events | missed, &item); - if (unlikely(ret < 0 || missed)) { - spin_lock_bh(&ct->lock); - if (ret < 0) - e->missed |= events; - else - e->missed &= ~missed; - spin_unlock_bh(&ct->lock); - } + notify->fcn(ecache->events, &item); } + ecache->events = 0; + nf_ct_put(ecache->ct); + ecache->ct = NULL; + out_unlock: rcu_read_unlock(); } + +/* Deliver all cached events for a particular conntrack. This is called + * by code prior to async packet handling for freeing the skb */ +void nf_ct_deliver_cached_events(const struct nf_conn *ct) +{ + struct net *net = nf_ct_net(ct); + struct nf_conntrack_ecache *ecache; + + local_bh_disable(); + ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id()); + if (ecache->ct == ct) + __nf_ct_deliver_cached_events(ecache); + local_bh_enable(); +} EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); +/* Deliver cached events for old pending events, if current conntrack != old */ +void __nf_ct_event_cache_init(struct nf_conn *ct) +{ + struct net *net = nf_ct_net(ct); + struct nf_conntrack_ecache *ecache; + + /* take care of delivering potentially old events */ + ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id()); + BUG_ON(ecache->ct == ct); + if (ecache->ct) + __nf_ct_deliver_cached_events(ecache); + /* initialize for this conntrack/packet */ + ecache->ct = ct; + nf_conntrack_get(&ct->ct_general); +} +EXPORT_SYMBOL_GPL(__nf_ct_event_cache_init); + +/* flush the event cache - touches other CPU's data and must not be called + * while packets are still passing through the code */ +void nf_ct_event_cache_flush(struct net *net) +{ + struct nf_conntrack_ecache *ecache; + int cpu; + + for_each_possible_cpu(cpu) { + ecache = per_cpu_ptr(net->ct.ecache, cpu); + if (ecache->ct) + nf_ct_put(ecache->ct); + } +} + +int nf_conntrack_ecache_init(struct net *net) +{ + net->ct.ecache = alloc_percpu(struct nf_conntrack_ecache); + if (!net->ct.ecache) + return -ENOMEM; + return 0; +} + +void nf_conntrack_ecache_fini(struct net *net) +{ + free_percpu(net->ct.ecache); +} + int nf_conntrack_register_notifier(struct nf_ct_event_notifier *new) { int ret = 0; @@ -143,118 +185,3 @@ void nf_ct_expect_unregister_notifier(struct nf_exp_event_notifier *new) mutex_unlock(&nf_ct_ecache_mutex); } EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); - -#define NF_CT_EVENTS_DEFAULT 1 -static int nf_ct_events __read_mostly = NF_CT_EVENTS_DEFAULT; -static int nf_ct_events_retry_timeout __read_mostly = 15*HZ; - -#ifdef CONFIG_SYSCTL -static struct ctl_table event_sysctl_table[] = { - { - .ctl_name = CTL_UNNUMBERED, - .procname = "nf_conntrack_events", - .data = &init_net.ct.sysctl_events, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .ctl_name = CTL_UNNUMBERED, - .procname = "nf_conntrack_events_retry_timeout", - .data = &init_net.ct.sysctl_events_retry_timeout, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - {} -}; -#endif /* CONFIG_SYSCTL */ - -static struct nf_ct_ext_type event_extend __read_mostly = { - .len = sizeof(struct nf_conntrack_ecache), - .align = __alignof__(struct nf_conntrack_ecache), - .id = NF_CT_EXT_ECACHE, -}; - -#ifdef CONFIG_SYSCTL -static int nf_conntrack_event_init_sysctl(struct net *net) -{ - struct ctl_table *table; - - table = kmemdup(event_sysctl_table, sizeof(event_sysctl_table), - GFP_KERNEL); - if (!table) - goto out; - - table[0].data = &net->ct.sysctl_events; - table[1].data = &net->ct.sysctl_events_retry_timeout; - - net->ct.event_sysctl_header = - register_net_sysctl_table(net, - nf_net_netfilter_sysctl_path, table); - if (!net->ct.event_sysctl_header) { - printk(KERN_ERR "nf_ct_event: can't register to sysctl.\n"); - goto out_register; - } - return 0; - -out_register: - kfree(table); -out: - return -ENOMEM; -} - -static void nf_conntrack_event_fini_sysctl(struct net *net) -{ - struct ctl_table *table; - - table = net->ct.event_sysctl_header->ctl_table_arg; - unregister_net_sysctl_table(net->ct.event_sysctl_header); - kfree(table); -} -#else -static int nf_conntrack_event_init_sysctl(struct net *net) -{ - return 0; -} - -static void nf_conntrack_event_fini_sysctl(struct net *net) -{ -} -#endif /* CONFIG_SYSCTL */ - -int nf_conntrack_ecache_init(struct net *net) -{ - int ret; - - net->ct.sysctl_events = nf_ct_events; - net->ct.sysctl_events_retry_timeout = nf_ct_events_retry_timeout; - - if (net_eq(net, &init_net)) { - ret = nf_ct_extend_register(&event_extend); - if (ret < 0) { - printk(KERN_ERR "nf_ct_event: Unable to register " - "event extension.\n"); - goto out_extend_register; - } - } - - ret = nf_conntrack_event_init_sysctl(net); - if (ret < 0) - goto out_sysctl; - - return 0; - -out_sysctl: - if (net_eq(net, &init_net)) - nf_ct_extend_unregister(&event_extend); -out_extend_register: - return ret; -} - -void nf_conntrack_ecache_fini(struct net *net) -{ - nf_conntrack_event_fini_sysctl(net); - if (net_eq(net, &init_net)) - nf_ct_extend_unregister(&event_extend); -} diff --git a/trunk/net/netfilter/nf_conntrack_helper.c b/trunk/net/netfilter/nf_conntrack_helper.c index 65c2a7bc3afc..0fa5a422959f 100644 --- a/trunk/net/netfilter/nf_conntrack_helper.c +++ b/trunk/net/netfilter/nf_conntrack_helper.c @@ -136,20 +136,6 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i, return 0; } -void nf_ct_helper_destroy(struct nf_conn *ct) -{ - struct nf_conn_help *help = nfct_help(ct); - struct nf_conntrack_helper *helper; - - if (help) { - rcu_read_lock(); - helper = rcu_dereference(help->helper); - if (helper && helper->destroy) - helper->destroy(ct); - rcu_read_unlock(); - } -} - int nf_conntrack_helper_register(struct nf_conntrack_helper *me) { unsigned int h = helper_hash(&me->tuple); diff --git a/trunk/net/netfilter/nf_conntrack_netlink.c b/trunk/net/netfilter/nf_conntrack_netlink.c index 49479d194570..4e503ada5728 100644 --- a/trunk/net/netfilter/nf_conntrack_netlink.c +++ b/trunk/net/netfilter/nf_conntrack_netlink.c @@ -463,16 +463,15 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) struct sk_buff *skb; unsigned int type; unsigned int flags = 0, group; - int err; /* ignore our fake conntrack entry */ if (ct == &nf_conntrack_untracked) return 0; - if (events & (1 << IPCT_DESTROY)) { + if (events & IPCT_DESTROY) { type = IPCTNL_MSG_CT_DELETE; group = NFNLGRP_CONNTRACK_DESTROY; - } else if (events & ((1 << IPCT_NEW) | (1 << IPCT_RELATED))) { + } else if (events & (IPCT_NEW | IPCT_RELATED)) { type = IPCTNL_MSG_CT_NEW; flags = NLM_F_CREATE|NLM_F_EXCL; group = NFNLGRP_CONNTRACK_NEW; @@ -520,7 +519,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) if (ctnetlink_dump_status(skb, ct) < 0) goto nla_put_failure; - if (events & (1 << IPCT_DESTROY)) { + if (events & IPCT_DESTROY) { if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) goto nla_put_failure; @@ -528,41 +527,38 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) if (ctnetlink_dump_timeout(skb, ct) < 0) goto nla_put_failure; - if (events & (1 << IPCT_PROTOINFO) + if (events & IPCT_PROTOINFO && ctnetlink_dump_protoinfo(skb, ct) < 0) goto nla_put_failure; - if ((events & (1 << IPCT_HELPER) || nfct_help(ct)) + if ((events & IPCT_HELPER || nfct_help(ct)) && ctnetlink_dump_helpinfo(skb, ct) < 0) goto nla_put_failure; #ifdef CONFIG_NF_CONNTRACK_SECMARK - if ((events & (1 << IPCT_SECMARK) || ct->secmark) + if ((events & IPCT_SECMARK || ct->secmark) && ctnetlink_dump_secmark(skb, ct) < 0) goto nla_put_failure; #endif - if (events & (1 << IPCT_RELATED) && + if (events & IPCT_RELATED && ctnetlink_dump_master(skb, ct) < 0) goto nla_put_failure; - if (events & (1 << IPCT_NATSEQADJ) && + if (events & IPCT_NATSEQADJ && ctnetlink_dump_nat_seq_adj(skb, ct) < 0) goto nla_put_failure; } #ifdef CONFIG_NF_CONNTRACK_MARK - if ((events & (1 << IPCT_MARK) || ct->mark) + if ((events & IPCT_MARK || ct->mark) && ctnetlink_dump_mark(skb, ct) < 0) goto nla_put_failure; #endif rcu_read_unlock(); nlmsg_end(skb, nlh); - err = nfnetlink_send(skb, item->pid, group, item->report, GFP_ATOMIC); - if (err == -ENOBUFS || err == -EAGAIN) - return -ENOBUFS; - + nfnetlink_send(skb, item->pid, group, item->report, GFP_ATOMIC); return 0; nla_put_failure: @@ -802,15 +798,10 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, } } - if (nf_conntrack_event_report(IPCT_DESTROY, ct, - NETLINK_CB(skb).pid, - nlmsg_report(nlh)) < 0) { - nf_ct_delete_from_lists(ct); - /* we failed to report the event, try later */ - nf_ct_insert_dying_list(ct); - nf_ct_put(ct); - return 0; - } + nf_conntrack_event_report(IPCT_DESTROY, + ct, + NETLINK_CB(skb).pid, + nlmsg_report(nlh)); /* death_by_timeout would report the event again */ set_bit(IPS_DYING_BIT, &ct->status); @@ -1262,7 +1253,6 @@ ctnetlink_create_conntrack(struct nlattr *cda[], } nf_ct_acct_ext_add(ct, GFP_ATOMIC); - nf_ct_ecache_ext_add(ct, GFP_ATOMIC); #if defined(CONFIG_NF_CONNTRACK_MARK) if (cda[CTA_MARK]) @@ -1350,13 +1340,13 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, else events = IPCT_NEW; - nf_conntrack_eventmask_report((1 << IPCT_STATUS) | - (1 << IPCT_HELPER) | - (1 << IPCT_PROTOINFO) | - (1 << IPCT_NATSEQADJ) | - (1 << IPCT_MARK) | events, - ct, NETLINK_CB(skb).pid, - nlmsg_report(nlh)); + nf_conntrack_event_report(IPCT_STATUS | + IPCT_HELPER | + IPCT_PROTOINFO | + IPCT_NATSEQADJ | + IPCT_MARK | events, + ct, NETLINK_CB(skb).pid, + nlmsg_report(nlh)); nf_ct_put(ct); } else spin_unlock_bh(&nf_conntrack_lock); @@ -1375,13 +1365,13 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, if (err == 0) { nf_conntrack_get(&ct->ct_general); spin_unlock_bh(&nf_conntrack_lock); - nf_conntrack_eventmask_report((1 << IPCT_STATUS) | - (1 << IPCT_HELPER) | - (1 << IPCT_PROTOINFO) | - (1 << IPCT_NATSEQADJ) | - (1 << IPCT_MARK), - ct, NETLINK_CB(skb).pid, - nlmsg_report(nlh)); + nf_conntrack_event_report(IPCT_STATUS | + IPCT_HELPER | + IPCT_PROTOINFO | + IPCT_NATSEQADJ | + IPCT_MARK, + ct, NETLINK_CB(skb).pid, + nlmsg_report(nlh)); nf_ct_put(ct); } else spin_unlock_bh(&nf_conntrack_lock); @@ -1525,7 +1515,7 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item) unsigned int type; int flags = 0; - if (events & (1 << IPEXP_NEW)) { + if (events & IPEXP_NEW) { type = IPCTNL_MSG_EXP_NEW; flags = NLM_F_CREATE|NLM_F_EXCL; } else diff --git a/trunk/net/netfilter/nf_log.c b/trunk/net/netfilter/nf_log.c index 2fefe147750a..beb37311e1a5 100644 --- a/trunk/net/netfilter/nf_log.c +++ b/trunk/net/netfilter/nf_log.c @@ -248,14 +248,14 @@ static int nf_log_proc_dostring(ctl_table *table, int write, struct file *filp, rcu_assign_pointer(nf_loggers[tindex], logger); mutex_unlock(&nf_log_mutex); } else { - mutex_lock(&nf_log_mutex); - logger = nf_loggers[tindex]; + rcu_read_lock(); + logger = rcu_dereference(nf_loggers[tindex]); if (!logger) table->data = "NONE"; else table->data = logger->name; r = proc_dostring(table, write, filp, buffer, lenp, ppos); - mutex_unlock(&nf_log_mutex); + rcu_read_unlock(); } return r; diff --git a/trunk/net/netfilter/x_tables.c b/trunk/net/netfilter/x_tables.c index 025d1a0af78b..46dba5f043d5 100644 --- a/trunk/net/netfilter/x_tables.c +++ b/trunk/net/netfilter/x_tables.c @@ -364,14 +364,14 @@ int xt_check_match(struct xt_mtchk_param *par, * ebt_among is exempt from centralized matchsize checking * because it uses a dynamic-size data set. */ - pr_err("%s_tables: %s match: invalid size %Zu != %u\n", + printk("%s_tables: %s match: invalid size %Zu != %u\n", xt_prefix[par->family], par->match->name, XT_ALIGN(par->match->matchsize), size); return -EINVAL; } if (par->match->table != NULL && strcmp(par->match->table, par->table) != 0) { - pr_err("%s_tables: %s match: only valid in %s table, not %s\n", + printk("%s_tables: %s match: only valid in %s table, not %s\n", xt_prefix[par->family], par->match->name, par->match->table, par->table); return -EINVAL; @@ -379,7 +379,7 @@ int xt_check_match(struct xt_mtchk_param *par, if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) { char used[64], allow[64]; - pr_err("%s_tables: %s match: used from hooks %s, but only " + printk("%s_tables: %s match: used from hooks %s, but only " "valid from %s\n", xt_prefix[par->family], par->match->name, textify_hooks(used, sizeof(used), par->hook_mask), @@ -387,7 +387,7 @@ int xt_check_match(struct xt_mtchk_param *par, return -EINVAL; } if (par->match->proto && (par->match->proto != proto || inv_proto)) { - pr_err("%s_tables: %s match: only valid for protocol %u\n", + printk("%s_tables: %s match: only valid for protocol %u\n", xt_prefix[par->family], par->match->name, par->match->proto); return -EINVAL; @@ -514,14 +514,14 @@ int xt_check_target(struct xt_tgchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { if (XT_ALIGN(par->target->targetsize) != size) { - pr_err("%s_tables: %s target: invalid size %Zu != %u\n", + printk("%s_tables: %s target: invalid size %Zu != %u\n", xt_prefix[par->family], par->target->name, XT_ALIGN(par->target->targetsize), size); return -EINVAL; } if (par->target->table != NULL && strcmp(par->target->table, par->table) != 0) { - pr_err("%s_tables: %s target: only valid in %s table, not %s\n", + printk("%s_tables: %s target: only valid in %s table, not %s\n", xt_prefix[par->family], par->target->name, par->target->table, par->table); return -EINVAL; @@ -529,7 +529,7 @@ int xt_check_target(struct xt_tgchk_param *par, if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) { char used[64], allow[64]; - pr_err("%s_tables: %s target: used from hooks %s, but only " + printk("%s_tables: %s target: used from hooks %s, but only " "usable from %s\n", xt_prefix[par->family], par->target->name, textify_hooks(used, sizeof(used), par->hook_mask), @@ -537,7 +537,7 @@ int xt_check_target(struct xt_tgchk_param *par, return -EINVAL; } if (par->target->proto && (par->target->proto != proto || inv_proto)) { - pr_err("%s_tables: %s target: only valid for protocol %u\n", + printk("%s_tables: %s target: only valid for protocol %u\n", xt_prefix[par->family], par->target->name, par->target->proto); return -EINVAL; diff --git a/trunk/net/rose/rose_dev.c b/trunk/net/rose/rose_dev.c index 389d6e0d7740..7dcf2569613b 100644 --- a/trunk/net/rose/rose_dev.c +++ b/trunk/net/rose/rose_dev.c @@ -137,7 +137,7 @@ static int rose_xmit(struct sk_buff *skb, struct net_device *dev) if (!netif_running(dev)) { printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n"); - return NETDEV_TX_BUSY; + return 1; } dev_kfree_skb(skb); stats->tx_errors++; diff --git a/trunk/net/sched/sch_teql.c b/trunk/net/sched/sch_teql.c index 9c002b6e0533..cb1cb1e76b9a 100644 --- a/trunk/net/sched/sch_teql.c +++ b/trunk/net/sched/sch_teql.c @@ -338,7 +338,7 @@ static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev) if (busy) { netif_stop_queue(dev); - return NETDEV_TX_BUSY; + return 1; } dev->stats.tx_errors++;