From 57f78ab3b0e9338a9241aeff6ee92aecc8f8bcbb Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 5 Feb 2008 14:19:40 +1100 Subject: iSeries: fix section mismatch in iseries_veth WARNING: vmlinux.o(.text+0x25dca0): Section mismatch in reference from the function .veth_probe() to the function .init.text:.veth_probe_one() Signed-off-by: Stephen Rothwell Signed-off-by: Jeff Garzik --- drivers/net/iseries_veth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 419861cbc65..58d3bb622da 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1020,7 +1020,7 @@ static const struct ethtool_ops ops = { .get_link = veth_get_link, }; -static struct net_device * __init veth_probe_one(int vlan, +static struct net_device *veth_probe_one(int vlan, struct vio_dev *vio_dev) { struct net_device *dev; -- cgit v1.2.3 From 39dbd9587bebedbd72be9a8a30a8c4783f3ef7eb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 4 Feb 2008 19:45:13 -0800 Subject: sky2: fix for Yukon FE (regression in 2.6.25) The Yukon FE chip has a ram buffer therefore it needs the alignment restriction and hang check workarounds. Therefore: * Autodetect the prescence/absence of ram buffer * Rename the flag value to reflect this * Use it consistently (ie don't reread register) Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 17 +++++++---------- drivers/net/sky2.h | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index dc062367a1c..9a6295909e4 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -857,7 +857,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); /* On chips without ram buffer, pause is controled by MAC level */ - if (sky2_read8(hw, B2_E_0) == 0) { + if (!(hw->flags & SKY2_HW_RAM_BUFFER)) { sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8); sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8); @@ -1194,7 +1194,7 @@ static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2) struct sk_buff *skb; int i; - if (sky2->hw->flags & SKY2_HW_FIFO_HANG_CHECK) { + if (sky2->hw->flags & SKY2_HW_RAM_BUFFER) { unsigned char *start; /* * Workaround for a bug in FIFO that cause hang @@ -1387,6 +1387,7 @@ static int sky2_up(struct net_device *dev) if (ramsize > 0) { u32 rxspace; + hw->flags |= SKY2_HW_RAM_BUFFER; pr_debug(PFX "%s: ram buffer %dK\n", dev->name, ramsize); if (ramsize < 16) rxspace = ramsize / 2; @@ -2026,7 +2027,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) synchronize_irq(hw->pdev->irq); - if (sky2_read8(hw, B2_E_0) == 0) + if (!(hw->flags & SKY2_HW_RAM_BUFFER)) sky2_set_tx_stfwd(hw, port); ctl = gma_read16(hw, port, GM_GP_CTRL); @@ -2566,7 +2567,7 @@ static void sky2_watchdog(unsigned long arg) ++active; /* For chips with Rx FIFO, check if stuck */ - if ((hw->flags & SKY2_HW_FIFO_HANG_CHECK) && + if ((hw->flags & SKY2_HW_RAM_BUFFER) && sky2_rx_hung(dev)) { pr_info(PFX "%s: receiver hang detected\n", dev->name); @@ -2722,11 +2723,7 @@ static int __devinit sky2_init(struct sky2_hw *hw) switch(hw->chip_id) { case CHIP_ID_YUKON_XL: - hw->flags = SKY2_HW_GIGABIT - | SKY2_HW_NEWER_PHY; - if (hw->chip_rev < 3) - hw->flags |= SKY2_HW_FIFO_HANG_CHECK; - + hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY; break; case CHIP_ID_YUKON_EC_U: @@ -2752,7 +2749,7 @@ static int __devinit sky2_init(struct sky2_hw *hw) dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n"); return -EOPNOTSUPP; } - hw->flags = SKY2_HW_GIGABIT | SKY2_HW_FIFO_HANG_CHECK; + hw->flags = SKY2_HW_GIGABIT; break; case CHIP_ID_YUKON_FE: diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 2bced1a0898..5ab5c1c7c5a 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2045,7 +2045,7 @@ struct sky2_hw { #define SKY2_HW_FIBRE_PHY 0x00000002 #define SKY2_HW_GIGABIT 0x00000004 #define SKY2_HW_NEWER_PHY 0x00000008 -#define SKY2_HW_FIFO_HANG_CHECK 0x00000010 +#define SKY2_HW_RAM_BUFFER 0x00000010 #define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */ #define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */ #define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */ -- cgit v1.2.3 From 324ff2c1793b6d3d5c377cf6de2ada9b49af227a Mon Sep 17 00:00:00 2001 From: Byron Bradley Date: Mon, 4 Feb 2008 23:47:15 -0800 Subject: mv643xx_eth: fix byte order when checksum offload is enabled The Marvell Orion system on chips have an integrated mv643xx MAC. On these little endian ARM devices mv643xx will oops when checksum offload is enabled. Swapping the byte order of the protocol and checksum solves this problem. Signed-off-by: Byron Bradley Cc: Dale Farnsworth Cc: Manish Lachwani Cc: Jeff Garzik Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 651c2699d5e..b528ce77c40 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1652,6 +1652,11 @@ static void eth_tx_fill_frag_descs(struct mv643xx_private *mp, } } +static inline __be16 sum16_as_be(__sum16 sum) +{ + return (__force __be16)sum; +} + /** * eth_tx_submit_descs_for_skb - submit data from an skb to the tx hw * @@ -1689,7 +1694,7 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); if (skb->ip_summed == CHECKSUM_PARTIAL) { - BUG_ON(skb->protocol != ETH_P_IP); + BUG_ON(skb->protocol != htons(ETH_P_IP)); cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM | ETH_GEN_IP_V_4_CHECKSUM | @@ -1698,10 +1703,10 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, switch (ip_hdr(skb)->protocol) { case IPPROTO_UDP: cmd_sts |= ETH_UDP_FRAME; - desc->l4i_chk = udp_hdr(skb)->check; + desc->l4i_chk = ntohs(sum16_as_be(udp_hdr(skb)->check)); break; case IPPROTO_TCP: - desc->l4i_chk = tcp_hdr(skb)->check; + desc->l4i_chk = ntohs(sum16_as_be(tcp_hdr(skb)->check)); break; default: BUG(); -- cgit v1.2.3 From 6c04a515085e6b94266db3e0e05c2700eeffa469 Mon Sep 17 00:00:00 2001 From: Leonardo Potenza Date: Mon, 4 Feb 2008 23:47:16 -0800 Subject: drivers/net/tlan.c: compilation warning fix Add a check for the pci_register_driver() return value. Removed unused variable pad_allocated. The aim of this patch is to remove the following warning messages: drivers/net/tlan.c: In function 'tlan_probe': drivers/net/tlan.c:486: warning: ignoring return value of 'pci_register_driver', declared with attribute warn_unused_result Signed-off-by: Leonardo Potenza Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/tlan.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index c99ce74a7af..3af5b92b48c 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -465,7 +465,7 @@ static struct pci_driver tlan_driver = { static int __init tlan_probe(void) { - static int pad_allocated; + int rc = -ENODEV; printk(KERN_INFO "%s", tlan_banner); @@ -473,17 +473,22 @@ static int __init tlan_probe(void) if (TLanPadBuffer == NULL) { printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n"); - return -ENOMEM; + rc = -ENOMEM; + goto err_out; } memset(TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE); - pad_allocated = 1; TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n"); /* Use new style PCI probing. Now the kernel will do most of this for us */ - pci_register_driver(&tlan_driver); + rc = pci_register_driver(&tlan_driver); + + if (rc != 0) { + printk(KERN_ERR "TLAN: Could not register pci driver.\n"); + goto err_out_pci_free; + } TLAN_DBG(TLAN_DEBUG_PROBE, "Starting EISA Probe....\n"); TLan_EisaProbe(); @@ -493,11 +498,17 @@ static int __init tlan_probe(void) tlan_have_pci, tlan_have_eisa); if (TLanDevicesInstalled == 0) { - pci_unregister_driver(&tlan_driver); - pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA); - return -ENODEV; + rc = -ENODEV; + goto err_out_pci_unreg; } return 0; + +err_out_pci_unreg: + pci_unregister_driver(&tlan_driver); +err_out_pci_free: + pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA); +err_out: + return rc; } -- cgit v1.2.3 From 06f7525be463ef95bfdba001484bda04d00ec74e Mon Sep 17 00:00:00 2001 From: Erik Mouw Date: Mon, 4 Feb 2008 18:56:54 +0100 Subject: xircom_cb should return NETDEV_TX_BUSY when no descriptors available Changes in other networking paths uncovered a bug in the xircom_cb driver which made the kernel spew lots of the following error messages: BUG eth1 code -5 qlen 0 It turned out that the driver returned -EIO when there was no descriptor available for sending packets. It should return NETDEV_TX_BUSY instead. This was discussed on the netdev list before, see http://thread.gmane.org/gmane.linux.network/84603 . Signed-off-by: Erik Mouw Signed-off-by: Jeff Garzik --- drivers/net/tulip/xircom_cb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 8fc7274642e..6b93d016911 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -441,7 +441,7 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&card->lock,flags); trigger_transmit(card); - return -EIO; + return NETDEV_TX_BUSY; } -- cgit v1.2.3 From d4f80882ee7bdc721230b9ac209ddd3a837e4545 Mon Sep 17 00:00:00 2001 From: Ayyappan Veeraiyan Date: Fri, 1 Feb 2008 15:58:41 -0800 Subject: ixgbe: remove obsolete irq_sem, add driver state checking code After testing we confirmed that the irq_sem can safely be removed from ixgbe. Add strict state checking code to various ethtool parts to properly protect against races between various driver reset paths. Signed-off-by: Ayyappan Veeraiyan Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/ixgbe/ixgbe.h | 2 +- drivers/net/ixgbe/ixgbe_ethtool.c | 29 +++++++++---------- drivers/net/ixgbe/ixgbe_main.c | 60 +++++++++++++++++++++++---------------- 3 files changed, 49 insertions(+), 42 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index a021a6e7264..7dd9a03650d 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -174,7 +174,6 @@ struct ixgbe_adapter { struct vlan_group *vlgrp; u16 bd_number; u16 rx_buf_len; - atomic_t irq_sem; struct work_struct reset_task; /* TX */ @@ -244,6 +243,7 @@ extern const char ixgbe_driver_version[]; extern int ixgbe_up(struct ixgbe_adapter *adapter); extern void ixgbe_down(struct ixgbe_adapter *adapter); +extern void ixgbe_reinit_locked(struct ixgbe_adapter *adapter); extern void ixgbe_reset(struct ixgbe_adapter *adapter); extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); extern void ixgbe_set_ethtool_ops(struct net_device *netdev); diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 36353447716..9f3cdb87300 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -179,12 +179,10 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, hw->fc.original_type = hw->fc.type; - if (netif_running(adapter->netdev)) { - ixgbe_down(adapter); - ixgbe_up(adapter); - } else { + if (netif_running(netdev)) + ixgbe_reinit_locked(adapter); + else ixgbe_reset(adapter); - } return 0; } @@ -203,12 +201,10 @@ static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data) else adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED; - if (netif_running(netdev)) { - ixgbe_down(adapter); - ixgbe_up(adapter); - } else { + if (netif_running(netdev)) + ixgbe_reinit_locked(adapter); + else ixgbe_reset(adapter); - } return 0; } @@ -662,7 +658,10 @@ static int ixgbe_set_ringparam(struct net_device *netdev, return 0; } - if (netif_running(adapter->netdev)) + while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) + msleep(1); + + if (netif_running(netdev)) ixgbe_down(adapter); /* @@ -733,6 +732,7 @@ err_setup: if (netif_running(adapter->netdev)) ixgbe_up(adapter); + clear_bit(__IXGBE_RESETTING, &adapter->state); return err; } @@ -820,11 +820,8 @@ static int ixgbe_nway_reset(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - if (netif_running(netdev)) { - ixgbe_down(adapter); - ixgbe_reset(adapter); - ixgbe_up(adapter); - } + if (netif_running(netdev)) + ixgbe_reinit_locked(adapter); return 0; } diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 3732dd6c4b2..28bb20330de 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -535,7 +535,9 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) if (!test_bit(__IXGBE_DOWN, &adapter->state)) mod_timer(&adapter->watchdog_timer, jiffies); } - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); + + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); return IRQ_HANDLED; } @@ -713,7 +715,6 @@ static irqreturn_t ixgbe_intr(int irq, void *data) if (netif_rx_schedule_prep(netdev, &adapter->napi)) { /* Disable interrupts and register for poll. The flush of the * posted write is intentionally left out. */ - atomic_inc(&adapter->irq_sem); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); __netif_rx_schedule(netdev, &adapter->napi); } @@ -801,7 +802,6 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter) **/ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter) { - atomic_inc(&adapter->irq_sem); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); IXGBE_WRITE_FLUSH(&adapter->hw); synchronize_irq(adapter->pdev->irq); @@ -813,15 +813,13 @@ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter) **/ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) { - if (atomic_dec_and_test(&adapter->irq_sem)) { - if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, - (IXGBE_EIMS_ENABLE_MASK & - ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC))); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, - IXGBE_EIMS_ENABLE_MASK); - IXGBE_WRITE_FLUSH(&adapter->hw); - } + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, + (IXGBE_EIMS_ENABLE_MASK & + ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC))); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, + IXGBE_EIMS_ENABLE_MASK); + IXGBE_WRITE_FLUSH(&adapter->hw); } /** @@ -1040,7 +1038,8 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); u32 ctrl; - ixgbe_irq_disable(adapter); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + ixgbe_irq_disable(adapter); adapter->vlgrp = grp; if (grp) { @@ -1051,7 +1050,8 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev, IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl); } - ixgbe_irq_enable(adapter); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + ixgbe_irq_enable(adapter); } static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid) @@ -1066,9 +1066,13 @@ static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - ixgbe_irq_disable(adapter); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + ixgbe_irq_disable(adapter); + vlan_group_set_device(adapter->vlgrp, vid, NULL); - ixgbe_irq_enable(adapter); + + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + ixgbe_irq_enable(adapter); /* remove VID from filter table */ ixgbe_set_vfta(&adapter->hw, vid, 0, false); @@ -1224,6 +1228,16 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) return 0; } +void ixgbe_reinit_locked(struct ixgbe_adapter *adapter) +{ + WARN_ON(in_interrupt()); + while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) + msleep(1); + ixgbe_down(adapter); + ixgbe_up(adapter); + clear_bit(__IXGBE_RESETTING, &adapter->state); +} + int ixgbe_up(struct ixgbe_adapter *adapter) { /* hardware has been reset, we need to reload some things */ @@ -1408,7 +1422,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter) msleep(10); napi_disable(&adapter->napi); - atomic_set(&adapter->irq_sem, 0); ixgbe_irq_disable(adapter); @@ -1481,7 +1494,8 @@ static int ixgbe_clean(struct napi_struct *napi, int budget) /* If budget not fully consumed, exit the polling mode */ if (work_done < budget) { netif_rx_complete(netdev, napi); - ixgbe_irq_enable(adapter); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + ixgbe_irq_enable(adapter); } return work_done; @@ -1506,8 +1520,7 @@ static void ixgbe_reset_task(struct work_struct *work) adapter->tx_timeout_count++; - ixgbe_down(adapter); - ixgbe_up(adapter); + ixgbe_reinit_locked(adapter); } /** @@ -1590,7 +1603,6 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) return -ENOMEM; } - atomic_set(&adapter->irq_sem, 1); set_bit(__IXGBE_DOWN, &adapter->state); return 0; @@ -1828,10 +1840,8 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu) netdev->mtu = new_mtu; - if (netif_running(netdev)) { - ixgbe_down(adapter); - ixgbe_up(adapter); - } + if (netif_running(netdev)) + ixgbe_reinit_locked(adapter); return 0; } -- cgit v1.2.3 From e092be60b2292af91c55f085151d58dc8a76820a Mon Sep 17 00:00:00 2001 From: Ayyappan Veeraiyan Date: Fri, 1 Feb 2008 15:58:49 -0800 Subject: ixbge: remove TX lock and redo TX accounting. This ports Herbert Xu's "maybe_stop_tx" code and removes the tx_lock which is not needed. Signed-off-by: Ayyappan Veeraiyan Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/ixgbe/ixgbe.h | 2 - drivers/net/ixgbe/ixgbe_main.c | 110 ++++++++++++++++++++++++++++------------- 2 files changed, 76 insertions(+), 36 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 7dd9a03650d..d0bf206632c 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -136,8 +136,6 @@ struct ixgbe_ring { u16 head; u16 tail; - /* To protect race between sender and clean_tx_irq */ - spinlock_t tx_lock; struct ixgbe_queue_stats stats; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 28bb20330de..b4c9c77c09d 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -165,6 +165,15 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter, return false; } +#define IXGBE_MAX_TXD_PWR 14 +#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR) + +/* Tx Descriptors needed, worst case */ +#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \ + (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0)) +#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \ + MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ + /** * ixgbe_clean_tx_irq - Reclaim resources after transmit completes * @adapter: board private structure @@ -177,18 +186,34 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, struct ixgbe_tx_buffer *tx_buffer_info; unsigned int i, eop; bool cleaned = false; - int count = 0; + unsigned int total_tx_bytes = 0, total_tx_packets = 0; i = tx_ring->next_to_clean; eop = tx_ring->tx_buffer_info[i].next_to_watch; eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); while (eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) { - for (cleaned = false; !cleaned;) { + cleaned = false; + while (!cleaned) { tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); tx_buffer_info = &tx_ring->tx_buffer_info[i]; cleaned = (i == eop); tx_ring->stats.bytes += tx_buffer_info->length; + if (cleaned) { + struct sk_buff *skb = tx_buffer_info->skb; +#ifdef NETIF_F_TSO + unsigned int segs, bytecount; + segs = skb_shinfo(skb)->gso_segs ?: 1; + /* multiply data chunks by size of headers */ + bytecount = ((segs - 1) * skb_headlen(skb)) + + skb->len; + total_tx_packets += segs; + total_tx_bytes += bytecount; +#else + total_tx_packets++; + total_tx_bytes += skb->len; +#endif + } ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info); tx_desc->wb.status = 0; @@ -204,29 +229,34 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); /* weight of a sort for tx, avoid endless transmit cleanup */ - if (count++ >= tx_ring->work_limit) + if (total_tx_packets >= tx_ring->work_limit) break; } tx_ring->next_to_clean = i; -#define TX_WAKE_THRESHOLD 32 - spin_lock(&tx_ring->tx_lock); - - if (cleaned && netif_carrier_ok(netdev) && - (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD) && - !test_bit(__IXGBE_DOWN, &adapter->state)) - netif_wake_queue(netdev); - - spin_unlock(&tx_ring->tx_lock); +#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2) + if (total_tx_packets && netif_carrier_ok(netdev) && + (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) { + /* Make sure that anybody stopping the queue after this + * sees the new next_to_clean. + */ + smp_mb(); + if (netif_queue_stopped(netdev) && + !test_bit(__IXGBE_DOWN, &adapter->state)) { + netif_wake_queue(netdev); + adapter->restart_queue++; + } + } if (adapter->detect_tx_hung) if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc)) netif_stop_queue(netdev); - if (count >= tx_ring->work_limit) + if (total_tx_packets >= tx_ring->work_limit) IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value); + cleaned = total_tx_packets ? true : false; return cleaned; } @@ -1646,7 +1676,6 @@ int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, txdr->next_to_use = 0; txdr->next_to_clean = 0; txdr->work_limit = txdr->count; - spin_lock_init(&txdr->tx_lock); return 0; } @@ -2086,15 +2115,6 @@ static void ixgbe_watchdog(unsigned long data) round_jiffies(jiffies + 2 * HZ)); } -#define IXGBE_MAX_TXD_PWR 14 -#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR) - -/* Tx Descriptors needed, worst case */ -#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \ - (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0)) -#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \ - MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ - static int ixgbe_tso(struct ixgbe_adapter *adapter, struct ixgbe_ring *tx_ring, struct sk_buff *skb, u32 tx_flags, u8 *hdr_len) @@ -2366,6 +2386,37 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, writel(i, adapter->hw.hw_addr + tx_ring->tail); } +static int __ixgbe_maybe_stop_tx(struct net_device *netdev, + struct ixgbe_ring *tx_ring, int size) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + netif_stop_queue(netdev); + /* Herbert's original patch had: + * smp_mb__after_netif_stop_queue(); + * but since that doesn't exist yet, just open code it. */ + smp_mb(); + + /* We need to check again in a case another CPU has just + * made room available. */ + if (likely(IXGBE_DESC_UNUSED(tx_ring) < size)) + return -EBUSY; + + /* A reprieve! - use start_queue because it doesn't call schedule */ + netif_wake_queue(netdev); + ++adapter->restart_queue; + return 0; +} + +static int ixgbe_maybe_stop_tx(struct net_device *netdev, + struct ixgbe_ring *tx_ring, int size) +{ + if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size)) + return 0; + return __ixgbe_maybe_stop_tx(netdev, tx_ring, size); +} + + static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); @@ -2373,7 +2424,6 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int len = skb->len; unsigned int first; unsigned int tx_flags = 0; - unsigned long flags = 0; u8 hdr_len; int tso; unsigned int mss = 0; @@ -2399,14 +2449,10 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) for (f = 0; f < nr_frags; f++) count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size); - spin_lock_irqsave(&tx_ring->tx_lock, flags); - if (IXGBE_DESC_UNUSED(tx_ring) < (count + 2)) { + if (ixgbe_maybe_stop_tx(netdev, tx_ring, count)) { adapter->tx_busy++; - netif_stop_queue(netdev); - spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_BUSY; } - spin_unlock_irqrestore(&tx_ring->tx_lock, flags); if (adapter->vlgrp && vlan_tx_tag_present(skb)) { tx_flags |= IXGBE_TX_FLAGS_VLAN; tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT); @@ -2433,11 +2479,7 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) netdev->trans_start = jiffies; - spin_lock_irqsave(&tx_ring->tx_lock, flags); - /* Make sure there is space in the ring for the next send. */ - if (IXGBE_DESC_UNUSED(tx_ring) < DESC_NEEDED) - netif_stop_queue(netdev); - spin_unlock_irqrestore(&tx_ring->tx_lock, flags); + ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED); return NETDEV_TX_OK; } -- cgit v1.2.3 From 735441fb1a3b213d8cd12f641f5f1706a356b55c Mon Sep 17 00:00:00 2001 From: Ayyappan Veeraiyan Date: Fri, 1 Feb 2008 15:58:54 -0800 Subject: ixbge: Make ethtool code account for media types The i82598 can support various media types but this ethtool code only was coded for fiber just yet. Signed-off-by: Ayyappan Veeraiyan Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/ixgbe/ixgbe_ethtool.c | 52 +++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 9f3cdb87300..b447dd7de34 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -103,21 +103,41 @@ static int ixgbe_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + u32 link_speed = 0; + bool link_up; - ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); - ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); - ecmd->port = PORT_FIBRE; + ecmd->supported = SUPPORTED_10000baseT_Full; + ecmd->autoneg = AUTONEG_ENABLE; ecmd->transceiver = XCVR_EXTERNAL; + if (hw->phy.media_type == ixgbe_media_type_copper) { + ecmd->supported |= (SUPPORTED_1000baseT_Full | + SUPPORTED_TP | SUPPORTED_Autoneg); + + ecmd->advertising = (ADVERTISED_TP | ADVERTISED_Autoneg); + if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) + ecmd->advertising |= ADVERTISED_10000baseT_Full; + if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) + ecmd->advertising |= ADVERTISED_1000baseT_Full; + + ecmd->port = PORT_TP; + } else { + ecmd->supported |= SUPPORTED_FIBRE; + ecmd->advertising = (ADVERTISED_10000baseT_Full | + ADVERTISED_FIBRE); + ecmd->port = PORT_FIBRE; + } - if (netif_carrier_ok(adapter->netdev)) { - ecmd->speed = SPEED_10000; + adapter->hw.mac.ops.check_link(hw, &(link_speed), &link_up); + if (link_up) { + ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? + SPEED_10000 : SPEED_1000; ecmd->duplex = DUPLEX_FULL; } else { ecmd->speed = -1; ecmd->duplex = -1; } - ecmd->autoneg = AUTONEG_DISABLE; return 0; } @@ -125,17 +145,17 @@ static int ixgbe_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; - if (ecmd->autoneg == AUTONEG_ENABLE || - ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL) - return -EINVAL; - - if (netif_running(adapter->netdev)) { - ixgbe_down(adapter); - ixgbe_reset(adapter); - ixgbe_up(adapter); - } else { - ixgbe_reset(adapter); + switch (hw->phy.media_type) { + case ixgbe_media_type_fiber: + if ((ecmd->autoneg == AUTONEG_ENABLE) || + (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) + return -EINVAL; + /* in this case we currently only support 10Gb/FULL */ + break; + default: + break; } return 0; -- cgit v1.2.3 From 9c83b070edd1f76531ba8a7a120e95f786dcbb73 Mon Sep 17 00:00:00 2001 From: Ayyappan Veeraiyan Date: Fri, 1 Feb 2008 15:58:59 -0800 Subject: ixgbe: Fix pause code for ethtool Signed-off-by: Ayyappan Veeraiyan Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/ixgbe/ixgbe_ethtool.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index b447dd7de34..a119cbd8dbb 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -167,7 +167,7 @@ static void ixgbe_get_pauseparam(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; - pause->autoneg = AUTONEG_DISABLE; + pause->autoneg = (hw->fc.type == ixgbe_fc_full ? 1 : 0); if (hw->fc.type == ixgbe_fc_rx_pause) { pause->rx_pause = 1; @@ -185,10 +185,8 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; - if (pause->autoneg == AUTONEG_ENABLE) - return -EINVAL; - - if (pause->rx_pause && pause->tx_pause) + if ((pause->autoneg == AUTONEG_ENABLE) || + (pause->rx_pause && pause->tx_pause)) hw->fc.type = ixgbe_fc_full; else if (pause->rx_pause && !pause->tx_pause) hw->fc.type = ixgbe_fc_rx_pause; @@ -196,6 +194,8 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, hw->fc.type = ixgbe_fc_tx_pause; else if (!pause->rx_pause && !pause->tx_pause) hw->fc.type = ixgbe_fc_none; + else + return -EINVAL; hw->fc.original_type = hw->fc.type; -- cgit v1.2.3 From 5eba3699a3b2e0d7afa0d4594980bafb1e47e2b4 Mon Sep 17 00:00:00 2001 From: Ayyappan Veeraiyan Date: Fri, 1 Feb 2008 15:59:04 -0800 Subject: ixgbe: Fix FW init/release, make this code a function A gap was left in the FW release/grab code in up/down path. Fix it by making the release/grab code a function and calling it in appropriate locations. Signed-off-by: Ayyappan Veeraiyan Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/ixgbe/ixgbe_main.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index b4c9c77c09d..c814d9bfbca 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -87,6 +87,25 @@ MODULE_VERSION(DRV_VERSION); #define DEFAULT_DEBUG_LEVEL_SHIFT 3 +static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter) +{ + u32 ctrl_ext; + + /* Let firmware take over control of h/w */ + ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, + ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD); +} + +static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter) +{ + u32 ctrl_ext; + + /* Let firmware know the driver has taken over */ + ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, + ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD); +} #ifdef DEBUG /** @@ -1204,6 +1223,8 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) u32 txdctl, rxdctl, mhadd; int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + ixgbe_get_hw_control(adapter); + if (adapter->flags & (IXGBE_FLAG_MSIX_ENABLED | IXGBE_FLAG_MSI_ENABLED)) { if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { @@ -1490,6 +1511,8 @@ static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state) pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); + ixgbe_release_hw_control(adapter); + pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); @@ -1891,14 +1914,8 @@ static int ixgbe_open(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); int err; - u32 ctrl_ext; u32 num_rx_queues = adapter->num_rx_queues; - /* Let firmware know the driver has taken over */ - ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, - ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD); - try_intr_reinit: /* allocate transmit descriptors */ err = ixgbe_setup_all_tx_resources(adapter); @@ -1949,6 +1966,7 @@ try_intr_reinit: return 0; err_up: + ixgbe_release_hw_control(adapter); ixgbe_free_irq(adapter); err_req_irq: ixgbe_free_all_rx_resources(adapter); @@ -1974,7 +1992,6 @@ err_setup_tx: static int ixgbe_close(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - u32 ctrl_ext; ixgbe_down(adapter); ixgbe_free_irq(adapter); @@ -1982,9 +1999,7 @@ static int ixgbe_close(struct net_device *netdev) ixgbe_free_all_tx_resources(adapter); ixgbe_free_all_rx_resources(adapter); - ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, - ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD); + ixgbe_release_hw_control(adapter); return 0; } @@ -2749,6 +2764,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, return 0; err_register: + ixgbe_release_hw_control(adapter); err_hw_init: err_sw_init: err_eeprom: @@ -2784,6 +2800,8 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) unregister_netdev(netdev); + ixgbe_release_hw_control(adapter); + kfree(adapter->tx_ring); kfree(adapter->rx_ring); -- cgit v1.2.3 From e59bd25d579c143f1b93a33d3243d67abbb15abe Mon Sep 17 00:00:00 2001 From: Ayyappan Veeraiyan Date: Fri, 1 Feb 2008 15:59:09 -0800 Subject: ixgbe: properly return CHECKSUM_NONE, cleanup csum code We were not returning CHECKSUM_NONE in a lot of cases which is wrong. Move common exit points in this function and error code up before the actual work in this function. Signed-off-by: Ayyappan Veeraiyan Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/ixgbe/ixgbe_main.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index c814d9bfbca..ee5ee10c918 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -304,25 +304,40 @@ static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, } } +/** + * ixgbe_rx_checksum - indicate in skb if hw indicated a good cksum + * @adapter: address of board private structure + * @status_err: hardware indication of status of receive + * @skb: skb currently being received and modified + **/ static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter, u32 status_err, struct sk_buff *skb) { skb->ip_summed = CHECKSUM_NONE; - /* Ignore Checksum bit is set */ + /* Ignore Checksum bit is set, or rx csum disabled */ if ((status_err & IXGBE_RXD_STAT_IXSM) || - !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED)) + !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED)) return; - /* TCP/UDP checksum error bit is set */ - if (status_err & (IXGBE_RXDADV_ERR_TCPE | IXGBE_RXDADV_ERR_IPE)) { - /* let the stack verify checksum errors */ + + /* if IP and error */ + if ((status_err & IXGBE_RXD_STAT_IPCS) && + (status_err & IXGBE_RXDADV_ERR_IPE)) { adapter->hw_csum_rx_error++; return; } + + if (!(status_err & IXGBE_RXD_STAT_L4CS)) + return; + + if (status_err & IXGBE_RXDADV_ERR_TCPE) { + adapter->hw_csum_rx_error++; + return; + } + /* It must be a TCP or UDP packet with a valid checksum */ - if (status_err & (IXGBE_RXD_STAT_L4CS | IXGBE_RXD_STAT_UDPCS)) - skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->ip_summed = CHECKSUM_UNNECESSARY; adapter->hw_csum_rx_good++; } -- cgit v1.2.3 From 6f11eef7790828c33b4f6fc41aed9815ad047e7c Mon Sep 17 00:00:00 2001 From: Ayyappan Veeraiyan Date: Fri, 1 Feb 2008 15:59:14 -0800 Subject: ixgbe: fix several counter register errata Several counters behave differently on 82598 causing them to display incorrect values. Adjust the accounting so the reported numbers make sense and do not double count or represent the wrong item. Signed-off-by: Ayyappan Veeraiyan Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/ixgbe/ixgbe_main.c | 53 ++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index ee5ee10c918..6e7d90e69b5 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2026,22 +2026,26 @@ static int ixgbe_close(struct net_device *netdev) void ixgbe_update_stats(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; - u64 good_rx, missed_rx, bprc; + u64 total_mpc = 0; + u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot; adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); - good_rx = IXGBE_READ_REG(hw, IXGBE_GPRC); - missed_rx = IXGBE_READ_REG(hw, IXGBE_MPC(0)); - missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(1)); - missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(2)); - missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(3)); - missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(4)); - missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(5)); - missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(6)); - missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(7)); - adapter->stats.gprc += (good_rx - missed_rx); - - adapter->stats.mpc[0] += missed_rx; + for (i = 0; i < 8; i++) { + /* for packet buffers not used, the register should read 0 */ + mpc = IXGBE_READ_REG(hw, IXGBE_MPC(i)); + missed_rx += mpc; + adapter->stats.mpc[i] += mpc; + total_mpc += adapter->stats.mpc[i]; + adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i)); + } + adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); + /* work around hardware counting issue */ + adapter->stats.gprc -= missed_rx; + + /* 82598 hardware only has a 32 bit counter in the high register */ adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); + adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); + adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH); bprc = IXGBE_READ_REG(hw, IXGBE_BPRC); adapter->stats.bprc += bprc; adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); @@ -2053,28 +2057,34 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) adapter->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); - adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); - adapter->stats.lxontxc += IXGBE_READ_REG(hw, IXGBE_LXONTXC); adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); - adapter->stats.lxofftxc += IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); + lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC); + adapter->stats.lxontxc += lxon; + lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); + adapter->stats.lxofftxc += lxoff; adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); adapter->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); - adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); - adapter->stats.rnbc[0] += IXGBE_READ_REG(hw, IXGBE_RNBC(0)); + adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); + /* + * 82598 errata - tx of flow control packets is included in tx counters + */ + xon_off_tot = lxon + lxoff; + adapter->stats.gptc -= xon_off_tot; + adapter->stats.mptc -= xon_off_tot; + adapter->stats.gotc -= (xon_off_tot * (ETH_ZLEN + ETH_FCS_LEN)); adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); adapter->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC); adapter->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); - adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH); adapter->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); adapter->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); + adapter->stats.ptc64 -= xon_off_tot; adapter->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); adapter->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); adapter->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); adapter->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); adapter->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); - adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); /* Fill out the OS statistics structure */ @@ -2090,8 +2100,7 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) adapter->net_stats.rx_dropped = 0; adapter->net_stats.rx_length_errors = adapter->stats.rlec; adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; - adapter->net_stats.rx_missed_errors = adapter->stats.mpc[0]; - + adapter->net_stats.rx_missed_errors = total_mpc; } /** -- cgit v1.2.3 From d2f4fbe2982b3b9e46deea8d7288ea8f8d7b5bc4 Mon Sep 17 00:00:00 2001 From: Ayyappan Veeraiyan Date: Fri, 1 Feb 2008 15:59:19 -0800 Subject: ixgbe: add real-time traffic counters Just like our other drivers before we can switch ixgbe to provide real-time packet/byte counters to the stack easily. Signed-off-by: Ayyappan Veeraiyan Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/ixgbe/ixgbe_main.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 6e7d90e69b5..ead49e54f31 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -275,6 +275,8 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, if (total_tx_packets >= tx_ring->work_limit) IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value); + adapter->net_stats.tx_bytes += total_tx_bytes; + adapter->net_stats.tx_packets += total_tx_packets; cleaned = total_tx_packets ? true : false; return cleaned; } @@ -443,6 +445,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, u16 hdr_info, vlan_tag; bool is_vlan, cleaned = false; int cleaned_count = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; i = rx_ring->next_to_clean; upper_len = 0; @@ -522,6 +525,11 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, } ixgbe_rx_checksum(adapter, staterr, skb); + + /* probably a little skewed due to removing CRC */ + total_rx_bytes += skb->len; + total_rx_packets++; + skb->protocol = eth_type_trans(skb, netdev); ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag); netdev->last_rx = jiffies; @@ -550,6 +558,9 @@ next_desc: if (cleaned_count) ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count); + adapter->net_stats.rx_bytes += total_rx_bytes; + adapter->net_stats.rx_packets += total_rx_packets; + return cleaned; } @@ -2088,10 +2099,6 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); /* Fill out the OS statistics structure */ - adapter->net_stats.rx_packets = adapter->stats.gprc; - adapter->net_stats.tx_packets = adapter->stats.gptc; - adapter->net_stats.rx_bytes = adapter->stats.gorc; - adapter->net_stats.tx_bytes = adapter->stats.gotc; adapter->net_stats.multicast = adapter->stats.mprc; /* Rx Errors */ -- cgit v1.2.3 From 983e23041b28abb113862b2935a85cfb9aab4f5a Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Fri, 1 Feb 2008 22:34:30 +0100 Subject: Generic HDLC - fix kernel panic Fixes kernel panic in Frame Relay mode Signed-off-by: Krzysztof Halasa Signed-off-by: Jeff Garzik --- drivers/net/wan/hdlc_fr.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 071a64cacd5..51296c2b8b8 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -136,6 +136,10 @@ typedef struct pvc_device_struct { }state; }pvc_device; +struct pvc_desc { + struct net_device_stats stats; + pvc_device *pvc; +}; struct frad_state { fr_proto settings; @@ -171,17 +175,20 @@ static inline void dlci_to_q922(u8 *hdr, u16 dlci) } -static inline struct frad_state * state(hdlc_device *hdlc) +static inline struct frad_state* state(hdlc_device *hdlc) { return(struct frad_state *)(hdlc->state); } - -static __inline__ pvc_device* dev_to_pvc(struct net_device *dev) +static inline struct pvc_desc* pvcdev_to_desc(struct net_device *dev) { return dev->priv; } +static inline struct net_device_stats* pvc_get_stats(struct net_device *dev) +{ + return &pvcdev_to_desc(dev)->stats; +} static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) { @@ -351,7 +358,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) static int pvc_open(struct net_device *dev) { - pvc_device *pvc = dev_to_pvc(dev); + pvc_device *pvc = pvcdev_to_desc(dev)->pvc; if ((pvc->frad->flags & IFF_UP) == 0) return -EIO; /* Frad must be UP in order to activate PVC */ @@ -371,7 +378,7 @@ static int pvc_open(struct net_device *dev) static int pvc_close(struct net_device *dev) { - pvc_device *pvc = dev_to_pvc(dev); + pvc_device *pvc = pvcdev_to_desc(dev)->pvc; if (--pvc->open_count == 0) { hdlc_device *hdlc = dev_to_hdlc(pvc->frad); @@ -390,7 +397,7 @@ static int pvc_close(struct net_device *dev) static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - pvc_device *pvc = dev_to_pvc(dev); + pvc_device *pvc = pvcdev_to_desc(dev)->pvc; fr_proto_pvc_info info; if (ifr->ifr_settings.type == IF_GET_PROTO) { @@ -416,17 +423,9 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EINVAL; } - -static inline struct net_device_stats *pvc_get_stats(struct net_device *dev) -{ - return &dev_to_desc(dev)->stats; -} - - - static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) { - pvc_device *pvc = dev_to_pvc(dev); + pvc_device *pvc = pvcdev_to_desc(dev)->pvc; struct net_device_stats *stats = pvc_get_stats(dev); if (pvc->state.active) { @@ -1109,11 +1108,10 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) used = pvc_is_used(pvc); if (type == ARPHRD_ETHER) - dev = alloc_netdev(sizeof(struct net_device_stats), - "pvceth%d", ether_setup); + dev = alloc_netdev(sizeof(struct pvc_desc), "pvceth%d", + ether_setup); else - dev = alloc_netdev(sizeof(struct net_device_stats), - "pvc%d", pvc_setup); + dev = alloc_netdev(sizeof(struct pvc_desc), "pvc%d", pvc_setup); if (!dev) { printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n", @@ -1137,7 +1135,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) dev->change_mtu = pvc_change_mtu; dev->mtu = HDLC_MAX_MTU; dev->tx_queue_len = 0; - dev->priv = pvc; + pvcdev_to_desc(dev)->pvc = pvc; result = dev_alloc_name(dev, dev->name); if (result < 0) { -- cgit v1.2.3 From 40d25142f2ef27084fc317ac8bb5bae460c8ea72 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Fri, 1 Feb 2008 22:37:12 +0100 Subject: Generic HDLC - remove now unneeded hdlc_device_desc Removes now unneeded struct hdlc_device_desc Signed-off-by: Krzysztof Halasa Signed-off-by: Jeff Garzik --- drivers/net/wan/hdlc.c | 24 +++++++++--------------- drivers/net/wan/hdlc_cisco.c | 5 +++-- drivers/net/wan/hdlc_fr.c | 7 ++++--- drivers/net/wan/hdlc_ppp.c | 2 +- drivers/net/wan/hdlc_raw.c | 2 +- drivers/net/wan/hdlc_raw_eth.c | 2 +- drivers/net/wan/hdlc_x25.c | 10 +++++----- 7 files changed, 24 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index d553e6f3285..39951d0c34d 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -1,7 +1,7 @@ /* * Generic HDLC support routines for Linux * - * Copyright (C) 1999 - 2006 Krzysztof Halasa + * Copyright (C) 1999 - 2008 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -39,7 +39,7 @@ #include -static const char* version = "HDLC support module revision 1.21"; +static const char* version = "HDLC support module revision 1.22"; #undef DEBUG_LINK @@ -66,19 +66,15 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev) static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev) { - struct hdlc_device_desc *desc = dev_to_desc(dev); + struct hdlc_device *hdlc = dev_to_hdlc(dev); if (dev->nd_net != &init_net) { kfree_skb(skb); return 0; } - if (desc->netif_rx) - return desc->netif_rx(skb); - - desc->stats.rx_dropped++; /* Shouldn't happen */ - dev_kfree_skb(skb); - return NET_RX_DROP; + BUG_ON(!hdlc->proto->netif_rx); + return hdlc->proto->netif_rx(skb); } @@ -87,7 +83,7 @@ static inline void hdlc_proto_start(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); if (hdlc->proto->start) - return hdlc->proto->start(dev); + hdlc->proto->start(dev); } @@ -96,7 +92,7 @@ static inline void hdlc_proto_stop(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); if (hdlc->proto->stop) - return hdlc->proto->stop(dev); + hdlc->proto->stop(dev); } @@ -263,8 +259,7 @@ static void hdlc_setup(struct net_device *dev) struct net_device *alloc_hdlcdev(void *priv) { struct net_device *dev; - dev = alloc_netdev(sizeof(struct hdlc_device_desc) + - sizeof(hdlc_device), "hdlc%d", hdlc_setup); + dev = alloc_netdev(sizeof(struct hdlc_device), "hdlc%d", hdlc_setup); if (dev) dev_to_hdlc(dev)->priv = priv; return dev; @@ -281,7 +276,7 @@ void unregister_hdlc_device(struct net_device *dev) int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto, - int (*rx)(struct sk_buff *skb), size_t size) + size_t size) { detach_hdlc_protocol(dev); @@ -297,7 +292,6 @@ int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto, return -ENOBUFS; } dev_to_hdlc(dev)->proto = proto; - dev_to_desc(dev)->netif_rx = rx; return 0; } diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 038a6e748bb..7133c688cf2 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -250,7 +250,7 @@ static int cisco_rx(struct sk_buff *skb) return NET_RX_DROP; rx_error: - dev_to_desc(dev)->stats.rx_errors++; /* Mark error */ + dev_to_hdlc(dev)->stats.rx_errors++; /* Mark error */ dev_kfree_skb_any(skb); return NET_RX_DROP; } @@ -314,6 +314,7 @@ static struct hdlc_proto proto = { .stop = cisco_stop, .type_trans = cisco_type_trans, .ioctl = cisco_ioctl, + .netif_rx = cisco_rx, .module = THIS_MODULE, }; @@ -360,7 +361,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - result = attach_hdlc_protocol(dev, &proto, cisco_rx, + result = attach_hdlc_protocol(dev, &proto, sizeof(struct cisco_state)); if (result) return result; diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 51296c2b8b8..2bd609c2706 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -956,7 +956,7 @@ static int fr_rx(struct sk_buff *skb) if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - dev_to_desc(frad)->stats.rx_dropped++; + dev_to_hdlc(frad)->stats.rx_dropped++; return NET_RX_DROP; } @@ -1017,7 +1017,7 @@ static int fr_rx(struct sk_buff *skb) } rx_error: - dev_to_desc(frad)->stats.rx_errors++; /* Mark error */ + dev_to_hdlc(frad)->stats.rx_errors++; /* Mark error */ dev_kfree_skb_any(skb); return NET_RX_DROP; } @@ -1217,6 +1217,7 @@ static struct hdlc_proto proto = { .stop = fr_stop, .detach = fr_destroy, .ioctl = fr_ioctl, + .netif_rx = fr_rx, .module = THIS_MODULE, }; @@ -1275,7 +1276,7 @@ static int fr_ioctl(struct net_device *dev, struct ifreq *ifr) return result; if (dev_to_hdlc(dev)->proto != &proto) { /* Different proto */ - result = attach_hdlc_protocol(dev, &proto, fr_rx, + result = attach_hdlc_protocol(dev, &proto, sizeof(struct frad_state)); if (result) return result; diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 519e1550e2e..10396d9686f 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -122,7 +122,7 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - result = attach_hdlc_protocol(dev, &proto, NULL, + result = attach_hdlc_protocol(dev, &proto, sizeof(struct ppp_state)); if (result) return result; diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c index e23bc665626..bbbb819d764 100644 --- a/drivers/net/wan/hdlc_raw.c +++ b/drivers/net/wan/hdlc_raw.c @@ -82,7 +82,7 @@ static int raw_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - result = attach_hdlc_protocol(dev, &proto, NULL, + result = attach_hdlc_protocol(dev, &proto, sizeof(raw_hdlc_proto)); if (result) return result; diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index 8895394e600..11b16bdfe6a 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -96,7 +96,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - result = attach_hdlc_protocol(dev, &proto, NULL, + result = attach_hdlc_protocol(dev, &proto, sizeof(raw_hdlc_proto)); if (result) return result; diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c index cd7b22f50ed..c15cc11e399 100644 --- a/drivers/net/wan/hdlc_x25.c +++ b/drivers/net/wan/hdlc_x25.c @@ -164,17 +164,17 @@ static void x25_close(struct net_device *dev) static int x25_rx(struct sk_buff *skb) { - struct hdlc_device_desc *desc = dev_to_desc(skb->dev); + struct hdlc_device *hdlc = dev_to_hdlc(skb->dev); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - desc->stats.rx_dropped++; + hdlc->stats.rx_dropped++; return NET_RX_DROP; } if (lapb_data_received(skb->dev, skb) == LAPB_OK) return NET_RX_SUCCESS; - desc->stats.rx_errors++; + hdlc->stats.rx_errors++; dev_kfree_skb_any(skb); return NET_RX_DROP; } @@ -184,6 +184,7 @@ static struct hdlc_proto proto = { .open = x25_open, .close = x25_close, .ioctl = x25_ioctl, + .netif_rx = x25_rx, .module = THIS_MODULE, }; @@ -211,8 +212,7 @@ static int x25_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; - if ((result = attach_hdlc_protocol(dev, &proto, - x25_rx, 0)) != 0) + if ((result = attach_hdlc_protocol(dev, &proto, 0))) return result; dev->hard_start_xmit = x25_xmit; dev->type = ARPHRD_X25; -- cgit v1.2.3 From 47eaa267a5db1729d238f977364e297b8963e115 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Fri, 1 Feb 2008 22:39:50 +0100 Subject: Generic HDLC - use random_ether_addr() Generic HDLC now uses random_ether_addr() for generating MAC addresse for Ethernet-alike interfaces. Signed-off-by: Krzysztof Halasa Signed-off-by: Jeff Garzik --- drivers/net/wan/hdlc_fr.c | 8 +++----- drivers/net/wan/hdlc_raw_eth.c | 4 +--- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 2bd609c2706..c4ab0326f91 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -1120,10 +1119,9 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) return -ENOBUFS; } - if (type == ARPHRD_ETHER) { - memcpy(dev->dev_addr, "\x00\x01", 2); - get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2); - } else { + if (type == ARPHRD_ETHER) + random_ether_addr(dev->dev_addr); + else { *(__be16*)dev->dev_addr = htons(dlci); dlci_to_q922(dev->broadcast, dlci); } diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index 11b16bdfe6a..d20c685f671 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -107,8 +106,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) ether_setup(dev); dev->change_mtu = old_ch_mtu; dev->tx_queue_len = old_qlen; - memcpy(dev->dev_addr, "\x00\x01", 2); - get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2); + random_ether_addr(dev->dev_addr); netif_dormant_off(dev); return 0; } -- cgit v1.2.3 From b2976d23a15aac11e8e77a496108b9f4040fac4d Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Mon, 4 Feb 2008 15:13:59 -0500 Subject: forcedeth: restart tx/rx This patch fixes the issue where the transmitter and receiver must be restarted when applying new changes to certain registers. Signed-off-by: Ayaz Abdulla Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 36342230a6d..6e47b1103cd 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -624,6 +624,9 @@ union ring_type { #define NV_MSI_X_VECTOR_TX 0x1 #define NV_MSI_X_VECTOR_OTHER 0x2 +#define NV_RESTART_TX 0x1 +#define NV_RESTART_RX 0x2 + /* statistics */ struct nv_ethtool_str { char name[ETH_GSTRING_LEN]; @@ -2767,6 +2770,7 @@ static int nv_update_linkspeed(struct net_device *dev) int mii_status; int retval = 0; u32 control_1000, status_1000, phyreg, pause_flags, txreg; + u32 txrxFlags = 0; /* BMSR_LSTATUS is latched, read it twice: * we want the current value. @@ -2862,6 +2866,16 @@ set_speed: np->duplex = newdup; np->linkspeed = newls; + /* The transmitter and receiver must be restarted for safe update */ + if (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_START) { + txrxFlags |= NV_RESTART_TX; + nv_stop_tx(dev); + } + if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) { + txrxFlags |= NV_RESTART_RX; + nv_stop_rx(dev); + } + if (np->gigabit == PHY_GIGABIT) { phyreg = readl(base + NvRegRandomSeed); phyreg &= ~(0x3FF00); @@ -2950,6 +2964,11 @@ set_speed: } nv_update_pause(dev, pause_flags); + if (txrxFlags & NV_RESTART_TX) + nv_start_tx(dev); + if (txrxFlags & NV_RESTART_RX) + nv_start_rx(dev); + return retval; } -- cgit v1.2.3 From eb79842838b6a3860d70be404fbb6e3b8f2a65de Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Mon, 4 Feb 2008 15:14:04 -0500 Subject: forcedeth: phy status fix The driver needs to ack only the phy status bits that it is currently handling and preserve the other bits for the other handlers. For example, when reading/writing from the phy, it should not clear the link change interrupt bit. This will cause a missing link change interrupt. Signed-off-by: Ayaz Abdulla Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 6e47b1103cd..6d5cd94f33a 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -323,8 +323,8 @@ enum { NvRegMIIStatus = 0x180, #define NVREG_MIISTAT_ERROR 0x0001 #define NVREG_MIISTAT_LINKCHANGE 0x0008 -#define NVREG_MIISTAT_MASK 0x000f -#define NVREG_MIISTAT_MASK2 0x000f +#define NVREG_MIISTAT_MASK_RW 0x0007 +#define NVREG_MIISTAT_MASK_ALL 0x000f NvRegMIIMask = 0x184, #define NVREG_MII_LINKCHANGE 0x0008 @@ -1064,7 +1064,7 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value) u32 reg; int retval; - writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); + writel(NVREG_MIISTAT_MASK_RW, base + NvRegMIIStatus); reg = readl(base + NvRegMIIControl); if (reg & NVREG_MIICTL_INUSE) { @@ -2995,7 +2995,7 @@ static void nv_link_irq(struct net_device *dev) u32 miistat; miistat = readl(base + NvRegMIIStatus); - writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); + writel(NVREG_MIISTAT_LINKCHANGE, base + NvRegMIIStatus); dprintk(KERN_INFO "%s: link change irq, status 0x%x.\n", dev->name, miistat); if (miistat & (NVREG_MIISTAT_LINKCHANGE)) @@ -4870,7 +4870,7 @@ static int nv_open(struct net_device *dev) writel(0, base + NvRegMIIMask); writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); - writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); + writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus); writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1); writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); @@ -4908,7 +4908,7 @@ static int nv_open(struct net_device *dev) nv_disable_hw_interrupts(dev, np->irqmask); pci_push(base); - writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); + writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus); writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); pci_push(base); @@ -4931,7 +4931,7 @@ static int nv_open(struct net_device *dev) { u32 miistat; miistat = readl(base + NvRegMIIStatus); - writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); + writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus); dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat); } /* set linkspeed to invalid value, thus force nv_update_linkspeed @@ -5299,7 +5299,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i phystate &= ~NVREG_ADAPTCTL_RUNNING; writel(phystate, base + NvRegAdapterControl); } - writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); + writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus); if (id->driver_data & DEV_HAS_MGMT_UNIT) { /* management unit running on the mac? */ -- cgit v1.2.3 From 4e84f9b10461ad3c869ced4373dd85771dd67d20 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Mon, 4 Feb 2008 15:14:09 -0500 Subject: forcedeth: preserve registers Various registers need to be preserved before resetting the device. Signed-off-by: Ayaz Abdulla Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 6d5cd94f33a..d4843d014bc 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -1435,16 +1435,30 @@ static void nv_mac_reset(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); + u32 temp1, temp2, temp3; dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name); + writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); + + /* save registers since they will be cleared on reset */ + temp1 = readl(base + NvRegMacAddrA); + temp2 = readl(base + NvRegMacAddrB); + temp3 = readl(base + NvRegTransmitPoll); + writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset); pci_push(base); udelay(NV_MAC_RESET_DELAY); writel(0, base + NvRegMacReset); pci_push(base); udelay(NV_MAC_RESET_DELAY); + + /* restore saved registers */ + writel(temp1, base + NvRegMacAddrA); + writel(temp2, base + NvRegMacAddrB); + writel(temp3, base + NvRegTransmitPoll); + writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); } -- cgit v1.2.3 From 15cf6dde99e40bf571a5ca48376650e163fcd30f Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Tue, 5 Feb 2008 16:35:30 -0600 Subject: Fix PHY Lib support for gianfar and ucc_geth The PHY Lib now uses mutexes instead of spin_locks. ucc_geth and gianfar both grab the locks in their mdio_reset functions, so they need to use mutex_(un)lock instead. This was not caught until someone tested it on an SMP system. Signed-off-by: Andy Fleming Signed-off-by: Jeff Garzik --- drivers/net/gianfar_mii.c | 4 ++-- drivers/net/ucc_geth_mii.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index 100bf410bf5..6a647d95e6e 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c @@ -127,7 +127,7 @@ int gfar_mdio_reset(struct mii_bus *bus) struct gfar_mii __iomem *regs = (void __iomem *)bus->priv; unsigned int timeout = PHY_INIT_TIMEOUT; - spin_lock_bh(&bus->mdio_lock); + mutex_lock(&bus->mdio_lock); /* Reset the management interface */ gfar_write(®s->miimcfg, MIIMCFG_RESET); @@ -140,7 +140,7 @@ int gfar_mdio_reset(struct mii_bus *bus) timeout--) cpu_relax(); - spin_unlock_bh(&bus->mdio_lock); + mutex_unlock(&bus->mdio_lock); if(timeout <= 0) { printk(KERN_ERR "%s: The MII Bus is stuck!\n", diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c index e3ba14a1991..c69e654d539 100644 --- a/drivers/net/ucc_geth_mii.c +++ b/drivers/net/ucc_geth_mii.c @@ -109,7 +109,7 @@ int uec_mdio_reset(struct mii_bus *bus) struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; unsigned int timeout = PHY_INIT_TIMEOUT; - spin_lock_bh(&bus->mdio_lock); + mutex_lock(&bus->mdio_lock); /* Reset the management interface */ out_be32(®s->miimcfg, MIIMCFG_RESET_MANAGEMENT); @@ -121,7 +121,7 @@ int uec_mdio_reset(struct mii_bus *bus) while ((in_be32(®s->miimind) & MIIMIND_BUSY) && timeout--) cpu_relax(); - spin_unlock_bh(&bus->mdio_lock); + mutex_unlock(&bus->mdio_lock); if (timeout <= 0) { printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name); -- cgit v1.2.3 From 370076d932ff56a02b9c5328729a69d432cd4b32 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 6 Feb 2008 08:50:11 +0100 Subject: virtio net: fix oops on interface-up I got the following oops during interface ifup. Unfortunately its not easily reproducable so I cant say for sure that my fix fixes this problem, but I am confident and I think its correct anyway: <2>kernel BUG at /space/kvm/drivers/virtio/virtio_ring.c:234! <4>illegal operation: 0001 [#1] PREEMPT SMP <4>Modules linked in: <4>CPU: 0 Not tainted 2.6.24zlive-guest-07293-gf1ca151-dirty #91 <4>Process swapper (pid: 0, task: 0000000000800938, ksp: 000000000084ddb8) <4>Krnl PSW : 0404300180000000 0000000000466374 (vring_disable_cb+0x30/0x34) <4> R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:3 PM:0 EA:3 <4>Krnl GPRS: 0000000000000001 0000000000000001 0000000010003800 0000000000466344 <4> 000000000e980900 00000000008848b0 000000000084e748 0000000000000000 <4> 000000000087b300 0000000000001237 0000000000001237 000000000f85bdd8 <4> 000000000e980920 00000000001137c0 0000000000464754 000000000f85bdd8 <4>Krnl Code: 0000000000466368: e3b0b0700004 lg %r11,112(%r11) <4> 000000000046636e: 07fe bcr 15,%r14 <4> 0000000000466370: a7f40001 brc 15,466372 <4> >0000000000466374: a7f4fff6 brc 15,466360 <4> 0000000000466378: eb7ff0500024 stmg %r7,%r15,80(%r15) <4> 000000000046637e: a7f13e00 tmll %r15,15872 <4> 0000000000466382: b90400ef lgr %r14,%r15 <4> 0000000000466386: a7840001 brc 8,466388 <4>Call Trace: <4>([<000201500f85c000>] 0x201500f85c000) <4> [<0000000000466556>] vring_interrupt+0x72/0x88 <4> [<00000000004801a0>] kvm_extint_handler+0x34/0x44 <4> [<000000000010d22c>] do_extint+0xbc/0xf8 <4> [<0000000000113f98>] ext_no_vtime+0x16/0x1a <4> [<000000000010a182>] cpu_idle+0x216/0x238 <4>([<000000000010a162>] cpu_idle+0x1f6/0x238) <4> [<0000000000568656>] rest_init+0xaa/0xb8 <4> [<000000000084ee2c>] start_kernel+0x3fc/0x490 <4> [<0000000000100020>] _stext+0x20/0x80 <4> <4> <0>Kernel panic - not syncing: Fatal exception in interrupt <4> After looking at the code and the dump I think the following scenario happened: Ifup was running on cpu2 and the interrupt arrived on cpu0. Now virtnet_open on cpu 2 managed to execute napi_enable and disable_cb but did not execute rx_schedule. Meanwhile on cpu 0 skb_recv_done was called by vring_interrupt, executed netif_rx_schedule_prep, which succeeded and therefore called disable_cb. This triggered the BUG_ON, as interrupts were already disabled by cpu 2. I think the proper solution is to make the call to disable_cb depend on the atomic update of NAPI_STATE_SCHED by using netif_rx_schedule_prep in the same way as skb_recv_done. Signed-off-by: Christian Borntraeger Acked-by: Rusty Russell Signed-off-by: Jeff Garzik --- drivers/net/virtio_net.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index e66de0c12fc..fdc23678117 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -302,10 +302,12 @@ static int virtnet_open(struct net_device *dev) /* If all buffers were filled by other side before we napi_enabled, we * won't get another interrupt, so process any outstanding packets - * now. virtnet_poll wants re-enable the queue, so we disable here. */ - vi->rvq->vq_ops->disable_cb(vi->rvq); - netif_rx_schedule(vi->dev, &vi->napi); - + * now. virtnet_poll wants re-enable the queue, so we disable here. + * We synchronize against interrupts via NAPI_STATE_SCHED */ + if (netif_rx_schedule_prep(dev, &vi->napi)) { + vi->rvq->vq_ops->disable_cb(vi->rvq); + __netif_rx_schedule(dev, &vi->napi); + } return 0; } -- cgit v1.2.3