From a4e2b347848bf626b822599329933887dc90e50f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 26 Oct 2005 15:46:52 -0700 Subject: [PATCH] tg3: add 5714/5715 support Add complete support for 5714/5715. These chips are very similar to 5780 so the changes are very trivial. A TG3_FLG2_5780_CLASS flag is added to identify these chips. Signed-off-by: Michael Chan Signed-off-by: Jeff Garzik --- drivers/net/tg3.c | 39 +++++++++++++++++++++++++-------------- drivers/net/tg3.h | 11 +++++++++-- 2 files changed, 34 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 1802c3b4879..cf2204f5b7f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -219,6 +219,10 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S, @@ -570,7 +574,7 @@ static void tg3_switch_clocks(struct tg3 *tp) u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); u32 orig_clock_ctrl; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) return; orig_clock_ctrl = clock_ctrl; @@ -1210,7 +1214,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state) CLOCK_CTRL_ALTCLK | CLOCK_CTRL_PWRDOWN_PLL133); udelay(40); - } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { + } else if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { /* do nothing */ } else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) { @@ -3712,14 +3716,14 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, dev->mtu = new_mtu; if (new_mtu > ETH_DATA_LEN) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; ethtool_op_set_tso(dev, 0); } else tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; } else { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; tp->tg3_flags &= ~TG3_FLAG_JUMBO_RING_ENABLE; } @@ -3850,7 +3854,7 @@ static void tg3_init_rings(struct tg3 *tp) memset(tp->tx_ring, 0, TG3_TX_RING_BYTES); tp->rx_pkt_buf_sz = RX_PKT_BUF_SZ; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) && + if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && (tp->dev->mtu > ETH_DATA_LEN)) tp->rx_pkt_buf_sz = RX_JUMBO_PKT_BUF_SZ; @@ -4347,7 +4351,7 @@ static int tg3_chip_reset(struct tg3 *tp) val &= ~PCIX_CAPS_RELAXED_ORDERING; pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { u32 val; /* Chip reset on 5780 will reset MSI enable bit, @@ -6003,7 +6007,7 @@ static int tg3_reset_hw(struct tg3 *tp) tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK); if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780)) + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) limit = 8; else limit = 16; @@ -7237,7 +7241,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported |= (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); - if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) + if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) cmd->supported |= (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_10baseT_Half | @@ -8380,7 +8384,7 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) } if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)) { + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; @@ -8980,7 +8984,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->phy_id = eeprom_phy_id; if (eeprom_phy_serdes) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) tp->tg3_flags2 |= TG3_FLG2_MII_SERDES; else tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; @@ -9393,8 +9397,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } /* Find msi capability. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { + tp->tg3_flags2 |= TG3_FLG2_5780_CLASS; tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI); + } /* Initialize misc host control in PCI block. */ tp->misc_host_ctrl |= (misc_ctrl_reg & @@ -9412,7 +9419,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || @@ -9607,7 +9614,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * ether_setup() via the alloc_etherdev() call */ if (tp->dev->mtu > ETH_DATA_LEN && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780) + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; /* Determine WakeOnLan speed to use. */ @@ -9830,7 +9837,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) mac_offset = 0x7c; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && !(tp->tg3_flags & TG3_FLG2_SUN_570X)) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) mac_offset = 0xcc; if (tg3_nvram_lock(tp)) @@ -10148,6 +10155,9 @@ static int __devinit tg3_test_dma(struct tg3 *tp) } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) { /* 5780 always in PCIX mode */ tp->dma_rwctrl |= 0x00144000; + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { + /* 5714 always in PCIX mode */ + tp->dma_rwctrl |= 0x00148000; } else { tp->dma_rwctrl |= 0x001b000f; } @@ -10347,6 +10357,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5705: return "5705"; case PHY_ID_BCM5750: return "5750"; case PHY_ID_BCM5752: return "5752"; + case PHY_ID_BCM5714: return "5714"; case PHY_ID_BCM5780: return "5780"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 2e733c60bfa..456ef2b3d0e 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -137,6 +137,7 @@ #define ASIC_REV_5750 0x04 #define ASIC_REV_5752 0x06 #define ASIC_REV_5780 0x08 +#define ASIC_REV_5714 0x09 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -531,6 +532,8 @@ #define MAC_SERDES_CFG_EDGE_SELECT 0x00001000 #define MAC_SERDES_STAT 0x00000594 /* 0x598 --> 0x5b0 unused */ +#define SERDES_RX_CTRL 0x000005b0 /* 5780/5714 only */ +#define SERDES_RX_SIG_DETECT 0x00000400 #define SG_DIG_CTRL 0x000005b0 #define SG_DIG_USING_HW_AUTONEG 0x80000000 #define SG_DIG_SOFT_RESET 0x40000000 @@ -1329,6 +1332,8 @@ #define GRC_LCLCTRL_CLEARINT 0x00000002 #define GRC_LCLCTRL_SETINT 0x00000004 #define GRC_LCLCTRL_INT_ON_ATTN 0x00000008 +#define GRC_LCLCTRL_USE_SIG_DETECT 0x00000010 /* 5714/5780 only */ +#define GRC_LCLCTRL_USE_EXT_SIG_DETECT 0x00000020 /* 5714/5780 only */ #define GRC_LCLCTRL_GPIO_INPUT3 0x00000020 #define GRC_LCLCTRL_GPIO_OE3 0x00000040 #define GRC_LCLCTRL_GPIO_OUTPUT3 0x00000080 @@ -2175,6 +2180,7 @@ struct tg3 { TG3_FLG2_MII_SERDES) #define TG3_FLG2_PARALLEL_DETECT 0x01000000 #define TG3_FLG2_ICH_WORKAROUND 0x02000000 +#define TG3_FLG2_5780_CLASS 0x04000000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 @@ -2222,6 +2228,7 @@ struct tg3 { #define PHY_ID_BCM5705 0x600081a0 #define PHY_ID_BCM5750 0x60008180 #define PHY_ID_BCM5752 0x60008100 +#define PHY_ID_BCM5714 0x60008340 #define PHY_ID_BCM5780 0x60008350 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff @@ -2246,8 +2253,8 @@ struct tg3 { (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \ (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \ (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \ - (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5780 || \ - (X) == PHY_ID_BCM8002) + (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \ + (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; -- cgit v1.2.3-18-g5258 From 28fbef78a420acdea20570d31f3bdcbfa0cac0d2 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 26 Oct 2005 15:48:35 -0700 Subject: [PATCH] tg3: fix ASF heartbeat Change the ASF heart beat to 5 seconds for faster detection of system crash. The driver sends the heartbeat every 2 seconds and the ASF firmware will timeout and reset the device if no heartbeat is received after 5 seconds. The old scheme of 2 minutes is ineffective. tg3_write_mem_fast() is added to speed up the IO to send the heartbeat. When no workaround is needed, it will use direct MMIO to memory space to write to memory. Signed-off-by: Michael Chan Signed-off-by: Jeff Garzik --- drivers/net/tg3.c | 21 ++++++++++++++++----- drivers/net/tg3.h | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index cf2204f5b7f..479be21425f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -470,6 +470,15 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) spin_unlock_irqrestore(&tp->indirect_lock, flags); } +static void tg3_write_mem_fast(struct tg3 *tp, u32 off, u32 val) +{ + /* If no workaround is needed, write to mem space directly */ + if (tp->write32 != tg3_write_indirect_reg32) + tw32(NIC_SRAM_WIN_BASE + off, val); + else + tg3_write_mem(tp, off, val); +} + static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) { unsigned long flags; @@ -6195,14 +6204,16 @@ static void tg3_timer(unsigned long __opaque) tp->timer_counter = tp->timer_multiplier; } - /* Heartbeat is only sent once every 120 seconds. */ + /* Heartbeat is only sent once every 2 seconds. */ if (!--tp->asf_counter) { if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { u32 val; - tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_ALIVE); - tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 3); + tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX, + FWCMD_NICDRV_ALIVE2); + tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); + /* 5 seconds timeout */ + tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); val = tr32(GRC_RX_CPU_EVENT); val |= (1 << 14); tw32(GRC_RX_CPU_EVENT, val); @@ -6413,7 +6424,7 @@ static int tg3_open(struct net_device *dev) tp->timer_counter = tp->timer_multiplier = (HZ / tp->timer_offset); tp->asf_counter = tp->asf_multiplier = - ((HZ / tp->timer_offset) * 120); + ((HZ / tp->timer_offset) * 2); init_timer(&tp->timer); tp->timer.expires = jiffies + tp->timer_offset; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 456ef2b3d0e..fb7e2a5f4a0 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1512,6 +1512,7 @@ #define FWCMD_NICDRV_IPV6ADDR_CHG 0x00000004 #define FWCMD_NICDRV_FIX_DMAR 0x00000005 #define FWCMD_NICDRV_FIX_DMAW 0x00000006 +#define FWCMD_NICDRV_ALIVE2 0x0000000d #define NIC_SRAM_FW_CMD_LEN_MBOX 0x00000b7c #define NIC_SRAM_FW_CMD_DATA_MBOX 0x00000b80 #define NIC_SRAM_FW_ASF_STATUS_MBOX 0x00000c00 -- cgit v1.2.3-18-g5258 From 37ff238d68683d42e7363eee3303773906c336d9 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 26 Oct 2005 15:49:51 -0700 Subject: [PATCH] tg3: update version and minor fixes Update version and reldate and add more sanity checking to tg3_set_settings(). Signed-off-by: Gary Zambrano Signed-off-by: Michael Chan Signed-off-by: Jeff Garzik --- drivers/net/tg3.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 479be21425f..551c9449322 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -67,8 +67,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.42" -#define DRV_MODULE_RELDATE "Oct 3, 2005" +#define DRV_MODULE_VERSION "3.43" +#define DRV_MODULE_RELDATE "Oct 24, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -7279,7 +7279,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct tg3 *tp = netdev_priv(dev); - if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { + if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) { /* These are the only valid advertisement bits allowed. */ if (cmd->autoneg == AUTONEG_ENABLE && (cmd->advertising & ~(ADVERTISED_1000baseT_Half | @@ -7287,7 +7287,17 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ADVERTISED_Autoneg | ADVERTISED_FIBRE))) return -EINVAL; - } + /* Fiber can only do SPEED_1000. */ + else if ((cmd->autoneg != AUTONEG_ENABLE) && + (cmd->speed != SPEED_1000)) + return -EINVAL; + /* Copper cannot force SPEED_1000. */ + } else if ((cmd->autoneg != AUTONEG_ENABLE) && + (cmd->speed == SPEED_1000)) + return -EINVAL; + else if ((cmd->speed == SPEED_1000) && + (tp->tg3_flags2 & TG3_FLAG_10_100_ONLY)) + return -EINVAL; tg3_full_lock(tp, 0); -- cgit v1.2.3-18-g5258 From 0abe791e94033b727f2b55670c2966f3d3d3cf70 Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Wed, 26 Oct 2005 10:46:53 -0600 Subject: [PATCH] ibmveth fix bonding This patch updates dev->trans_start and dev->last_rx so that the ibmveth driver can be used with the ARP monitor in the bonding driver. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index a2c4dd4fb22..5617bec7fd5 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -725,6 +725,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) } else { adapter->stats.tx_packets++; adapter->stats.tx_bytes += skb->len; + netdev->trans_start = jiffies; } do { @@ -776,6 +777,7 @@ static int ibmveth_poll(struct net_device *netdev, int *budget) adapter->stats.rx_packets++; adapter->stats.rx_bytes += length; frames_processed++; + netdev->last_rx = jiffies; } } else { more_work = 0; -- cgit v1.2.3-18-g5258 From b6d35182fe62e57d368062adcc880ca35119d88e Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Wed, 26 Oct 2005 10:47:01 -0600 Subject: [PATCH] ibmveth fix buffer pool management This patch changes the way the ibmveth driver handles the receive buffers. The old code mallocs and maps all the buffers in the pools regardless of MTU size and it also limits the number of buffer pools to three. This patch makes the driver malloc and map the buffers necessary to support the current MTU. It also changes the hardcoded names of the buffer pool number, size, and elements to arrays to make it easier to change (with the hope of making them runtime parameters in the future). Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 102 ++++++++++++++++++++++++++++++++++++-------------- drivers/net/ibmveth.h | 18 +++++---- 2 files changed, 85 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 5617bec7fd5..d985b804a76 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -97,6 +97,7 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter*); +static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); #ifdef CONFIG_PROC_FS #define IBMVETH_PROC_DIR "net/ibmveth" @@ -181,6 +182,7 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool) atomic_set(&pool->available, 0); pool->producer_index = 0; pool->consumer_index = 0; + pool->active = 0; return 0; } @@ -258,9 +260,14 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc /* check if replenishing is needed. */ static inline int ibmveth_is_replenishing_needed(struct ibmveth_adapter *adapter) { - return ((atomic_read(&adapter->rx_buff_pool[0].available) < adapter->rx_buff_pool[0].threshold) || - (atomic_read(&adapter->rx_buff_pool[1].available) < adapter->rx_buff_pool[1].threshold) || - (atomic_read(&adapter->rx_buff_pool[2].available) < adapter->rx_buff_pool[2].threshold)); + int i; + + for(i = 0; i < IbmVethNumBufferPools; i++) + if(adapter->rx_buff_pool[i].active && + (atomic_read(&adapter->rx_buff_pool[i].available) < + adapter->rx_buff_pool[i].threshold)) + return 1; + return 0; } /* kick the replenish tasklet if we need replenishing and it isn't already running */ @@ -275,11 +282,14 @@ static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter *adapter /* replenish tasklet routine */ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) { + int i; + adapter->replenish_task_cycles++; - ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[0]); - ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[1]); - ibmveth_replenish_buffer_pool(adapter, &adapter->rx_buff_pool[2]); + for(i = 0; i < IbmVethNumBufferPools; i++) + if(adapter->rx_buff_pool[i].active) + ibmveth_replenish_buffer_pool(adapter, + &adapter->rx_buff_pool[i]); adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8); @@ -321,6 +331,7 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm kfree(pool->skbuff); pool->skbuff = NULL; } + pool->active = 0; } /* remove a buffer from a pool */ @@ -379,6 +390,12 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) ibmveth_assert(pool < IbmVethNumBufferPools); ibmveth_assert(index < adapter->rx_buff_pool[pool].size); + if(!adapter->rx_buff_pool[pool].active) { + ibmveth_rxq_harvest_buffer(adapter); + ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[pool]); + return; + } + desc.desc = 0; desc.fields.valid = 1; desc.fields.length = adapter->rx_buff_pool[pool].buff_size; @@ -409,6 +426,8 @@ static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter) static void ibmveth_cleanup(struct ibmveth_adapter *adapter) { + int i; + if(adapter->buffer_list_addr != NULL) { if(!dma_mapping_error(adapter->buffer_list_dma)) { dma_unmap_single(&adapter->vdev->dev, @@ -443,26 +462,24 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) adapter->rx_queue.queue_addr = NULL; } - ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[0]); - ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[1]); - ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[2]); + for(i = 0; irx_buff_pool[i]); } static int ibmveth_open(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev->priv; u64 mac_address = 0; - int rxq_entries; + int rxq_entries = 1; unsigned long lpar_rc; int rc; union ibmveth_buf_desc rxq_desc; + int i; ibmveth_debug_printk("open starting\n"); - rxq_entries = - adapter->rx_buff_pool[0].size + - adapter->rx_buff_pool[1].size + - adapter->rx_buff_pool[2].size + 1; + for(i = 0; irx_buff_pool[i].size; adapter->buffer_list_addr = (void*) get_zeroed_page(GFP_KERNEL); adapter->filter_list_addr = (void*) get_zeroed_page(GFP_KERNEL); @@ -502,14 +519,8 @@ static int ibmveth_open(struct net_device *netdev) adapter->rx_queue.num_slots = rxq_entries; adapter->rx_queue.toggle = 1; - if(ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[0]) || - ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[1]) || - ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[2])) - { - ibmveth_error_printk("unable to allocate buffer pools\n"); - ibmveth_cleanup(adapter); - return -ENOMEM; - } + /* call change_mtu to init the buffer pools based in initial mtu */ + ibmveth_change_mtu(netdev, netdev->mtu); memcpy(&mac_address, netdev->dev_addr, netdev->addr_len); mac_address = mac_address >> 16; @@ -885,17 +896,52 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) { - if ((new_mtu < 68) || (new_mtu > (1<<20))) + struct ibmveth_adapter *adapter = dev->priv; + int i; + int prev_smaller = 1; + + if ((new_mtu < 68) || + (new_mtu > (pool_size[IbmVethNumBufferPools-1]) - IBMVETH_BUFF_OH)) return -EINVAL; + + for(i = 0; i (pool_size[i] - IBMVETH_BUFF_OH)) { + activate = 1; + prev_smaller= 1; + } else { + if (prev_smaller) + activate = 1; + prev_smaller= 0; + } + + if (activate && !adapter->rx_buff_pool[i].active) { + struct ibmveth_buff_pool *pool = + &adapter->rx_buff_pool[i]; + if(ibmveth_alloc_buffer_pool(pool)) { + ibmveth_error_printk("unable to alloc pool\n"); + return -ENOMEM; + } + adapter->rx_buff_pool[i].active = 1; + } else if (!activate && adapter->rx_buff_pool[i].active) { + adapter->rx_buff_pool[i].active = 0; + h_free_logical_lan_buffer(adapter->vdev->unit_address, + (u64)pool_size[i]); + } + + } + + + ibmveth_schedule_replenishing(adapter); dev->mtu = new_mtu; return 0; } static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) { - int rc; + int rc, i; struct net_device *netdev; - struct ibmveth_adapter *adapter; + struct ibmveth_adapter *adapter = NULL; unsigned char *mac_addr_p; unsigned int *mcastFilterSize_p; @@ -965,9 +1011,9 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); - ibmveth_init_buffer_pool(&adapter->rx_buff_pool[0], 0, IbmVethPool0DftCnt, IbmVethPool0DftSize); - ibmveth_init_buffer_pool(&adapter->rx_buff_pool[1], 1, IbmVethPool1DftCnt, IbmVethPool1DftSize); - ibmveth_init_buffer_pool(&adapter->rx_buff_pool[2], 2, IbmVethPool2DftCnt, IbmVethPool2DftSize); + for(i = 0; irx_buff_pool[i], i, + pool_count[i], pool_size[i]); ibmveth_debug_printk("adapter @ 0x%p\n", adapter); diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 51a470da968..a5d27a9cdf1 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -49,6 +49,7 @@ #define H_SEND_LOGICAL_LAN 0x120 #define H_MULTICAST_CTRL 0x130 #define H_CHANGE_LOGICAL_LAN_MAC 0x14C +#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4 /* hcall macros */ #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \ @@ -69,13 +70,15 @@ #define h_change_logical_lan_mac(ua, mac) \ plpar_hcall_norets(H_CHANGE_LOGICAL_LAN_MAC, ua, mac) -#define IbmVethNumBufferPools 3 -#define IbmVethPool0DftSize (1024 * 2) -#define IbmVethPool1DftSize (1024 * 4) -#define IbmVethPool2DftSize (1024 * 10) -#define IbmVethPool0DftCnt 256 -#define IbmVethPool1DftCnt 256 -#define IbmVethPool2DftCnt 256 +#define h_free_logical_lan_buffer(ua, bufsize) \ + plpar_hcall_norets(H_FREE_LOGICAL_LAN_BUFFER, ua, bufsize) + +#define IbmVethNumBufferPools 5 +#define IBMVETH_BUFF_OH 22 /* Overhead: 14 ethernet header + 8 opaque handle */ + +/* pool_size should be sorted */ +static int pool_size[] = { 512, 1024 * 2, 1024 * 16, 1024 * 32, 1024 * 64 }; +static int pool_count[] = { 256, 768, 256, 256, 256 }; #define IBM_VETH_INVALID_MAP ((u16)0xffff) @@ -90,6 +93,7 @@ struct ibmveth_buff_pool { u16 *free_map; dma_addr_t *dma_addr; struct sk_buff **skbuff; + int active; }; struct ibmveth_rx_q { -- cgit v1.2.3-18-g5258 From e2adbcb480992de8a01acf9218e8bbd9b507fc6f Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Wed, 26 Oct 2005 10:47:08 -0600 Subject: [PATCH] ibmveth fix buffer replenishing This patch removes the allocation of RX skb's buffers from a workqueue to be called directly at RX processing time. This change was suggested by Dave Miller when the driver was starving the RX buffers and deadlocking under heavy traffic: > Allocating RX SKBs via tasklet is, IMHO, the worst way to > do it. It is no surprise that there are starvation cases. > > If tasklets or work queues get delayed in any way, you lose, > and it's very easy for a card to catch up with the driver RX'ing > packets very fast, no matter how aggressive you make the > replenishing. By the time you detect that you need to be > "more aggressive" it is already too late. > The only pseudo-reliable way is to allocate at RX processing time. > Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 48 ++++++++---------------------------------------- drivers/net/ibmveth.h | 4 ---- 2 files changed, 8 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index d985b804a76..aea1598b225 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -96,7 +96,6 @@ static void ibmveth_proc_unregister_driver(void); static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter*); static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); #ifdef CONFIG_PROC_FS @@ -257,29 +256,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc atomic_add(buffers_added, &(pool->available)); } -/* check if replenishing is needed. */ -static inline int ibmveth_is_replenishing_needed(struct ibmveth_adapter *adapter) -{ - int i; - - for(i = 0; i < IbmVethNumBufferPools; i++) - if(adapter->rx_buff_pool[i].active && - (atomic_read(&adapter->rx_buff_pool[i].available) < - adapter->rx_buff_pool[i].threshold)) - return 1; - return 0; -} - -/* kick the replenish tasklet if we need replenishing and it isn't already running */ -static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter *adapter) -{ - if(ibmveth_is_replenishing_needed(adapter) && - (atomic_dec_if_positive(&adapter->not_replenishing) == 0)) { - schedule_work(&adapter->replenish_task); - } -} - -/* replenish tasklet routine */ +/* replenish routine */ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) { int i; @@ -292,10 +269,6 @@ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) &adapter->rx_buff_pool[i]); adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8); - - atomic_inc(&adapter->not_replenishing); - - ibmveth_schedule_replenishing(adapter); } /* empty and free ana buffer pool - also used to do cleanup in error paths */ @@ -563,10 +536,10 @@ static int ibmveth_open(struct net_device *netdev) return rc; } - netif_start_queue(netdev); + ibmveth_debug_printk("initial replenish cycle\n"); + ibmveth_replenish_task(adapter); - ibmveth_debug_printk("scheduling initial replenish cycle\n"); - ibmveth_schedule_replenishing(adapter); + netif_start_queue(netdev); ibmveth_debug_printk("open complete\n"); @@ -584,9 +557,6 @@ static int ibmveth_close(struct net_device *netdev) free_irq(netdev->irq, netdev); - cancel_delayed_work(&adapter->replenish_task); - flush_scheduled_work(); - do { lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); } while (H_isLongBusy(lpar_rc) || (lpar_rc == H_Busy)); @@ -795,7 +765,7 @@ static int ibmveth_poll(struct net_device *netdev, int *budget) } } while(more_work && (frames_processed < max_frames_to_process)); - ibmveth_schedule_replenishing(adapter); + ibmveth_replenish_task(adapter); if(more_work) { /* more work to do - return that we are not done yet */ @@ -931,8 +901,10 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) } + /* kick the interrupt handler so that the new buffer pools get + replenished or deallocated */ + ibmveth_interrupt(dev->irq, dev, NULL); - ibmveth_schedule_replenishing(adapter); dev->mtu = new_mtu; return 0; } @@ -1017,14 +989,10 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ ibmveth_debug_printk("adapter @ 0x%p\n", adapter); - INIT_WORK(&adapter->replenish_task, (void*)ibmveth_replenish_task, (void*)adapter); - adapter->buffer_list_dma = DMA_ERROR_CODE; adapter->filter_list_dma = DMA_ERROR_CODE; adapter->rx_queue.queue_dma = DMA_ERROR_CODE; - atomic_set(&adapter->not_replenishing, 1); - ibmveth_debug_printk("registering netdev...\n"); rc = register_netdev(netdev); diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index a5d27a9cdf1..a3ea02937d6 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -118,10 +118,6 @@ struct ibmveth_adapter { dma_addr_t filter_list_dma; struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools]; struct ibmveth_rx_q rx_queue; - atomic_t not_replenishing; - - /* helper tasks */ - struct work_struct replenish_task; /* adapter specific stats */ u64 replenish_task_cycles; -- cgit v1.2.3-18-g5258 From 60296d9e4be1cd9e096f7804ce6e839e0cbd97cf Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Wed, 26 Oct 2005 10:47:16 -0600 Subject: [PATCH] ibmveth lockless TX This patch adds the lockless TX feature to the ibmveth driver. The hypervisor has its own locking so the only change that is necessary is to protect the statistics counters. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 44 +++++++++++++++++++++++++++++--------------- drivers/net/ibmveth.h | 1 + 2 files changed, 30 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index aea1598b225..987bcba0188 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -621,12 +621,18 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned long lpar_rc; int nfrags = 0, curfrag; unsigned long correlator; + unsigned long flags; unsigned int retry_count; + unsigned int tx_dropped = 0; + unsigned int tx_bytes = 0; + unsigned int tx_packets = 0; + unsigned int tx_send_failed = 0; + unsigned int tx_map_failed = 0; + if ((skb_shinfo(skb)->nr_frags + 1) > IbmVethMaxSendFrags) { - adapter->stats.tx_dropped++; - dev_kfree_skb(skb); - return 0; + tx_dropped++; + goto out; } memset(&desc, 0, sizeof(desc)); @@ -645,10 +651,9 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if(dma_mapping_error(desc[0].fields.address)) { ibmveth_error_printk("tx: unable to map initial fragment\n"); - adapter->tx_map_failed++; - adapter->stats.tx_dropped++; - dev_kfree_skb(skb); - return 0; + tx_map_failed++; + tx_dropped++; + goto out; } curfrag = nfrags; @@ -665,8 +670,8 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) if(dma_mapping_error(desc[curfrag+1].fields.address)) { ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag); - adapter->tx_map_failed++; - adapter->stats.tx_dropped++; + tx_map_failed++; + tx_dropped++; /* Free all the mappings we just created */ while(curfrag < nfrags) { dma_unmap_single(&adapter->vdev->dev, @@ -675,8 +680,7 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) DMA_TO_DEVICE); curfrag++; } - dev_kfree_skb(skb); - return 0; + goto out; } } @@ -701,11 +705,11 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) ibmveth_error_printk("tx: desc[%i] valid=%d, len=%d, address=0x%d\n", i, desc[i].fields.valid, desc[i].fields.length, desc[i].fields.address); } - adapter->tx_send_failed++; - adapter->stats.tx_dropped++; + tx_send_failed++; + tx_dropped++; } else { - adapter->stats.tx_packets++; - adapter->stats.tx_bytes += skb->len; + tx_packets++; + tx_bytes += skb->len; netdev->trans_start = jiffies; } @@ -715,6 +719,14 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) desc[nfrags].fields.length, DMA_TO_DEVICE); } while(--nfrags >= 0); +out: spin_lock_irqsave(&adapter->stats_lock, flags); + adapter->stats.tx_dropped += tx_dropped; + adapter->stats.tx_bytes += tx_bytes; + adapter->stats.tx_packets += tx_packets; + adapter->tx_send_failed += tx_send_failed; + adapter->tx_map_failed += tx_map_failed; + spin_unlock_irqrestore(&adapter->stats_lock, flags); + dev_kfree_skb(skb); return 0; } @@ -980,6 +992,8 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->ethtool_ops = &netdev_ethtool_ops; netdev->change_mtu = ibmveth_change_mtu; SET_NETDEV_DEV(netdev, &dev->dev); + netdev->features |= NETIF_F_LLTX; + spin_lock_init(&adapter->stats_lock); memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index a3ea02937d6..46919a814fc 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -131,6 +131,7 @@ struct ibmveth_adapter { u64 tx_linearize_failed; u64 tx_map_failed; u64 tx_send_failed; + spinlock_t stats_lock; }; struct ibmveth_buf_desc_fields { -- cgit v1.2.3-18-g5258 From 82702d37a559cf94fe238cd3f8ef63cf7fa699a9 Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Wed, 26 Oct 2005 10:47:23 -0600 Subject: [PATCH] ibmveth fix failed addbuf This patch fixes a bug that happens when the hypervisor can't add a buffer. The old code wrote IBM_VETH_INVALID_MAP into the free_map array, so next time the index was used, a ibmveth_assert() caught it and called BUG(). The patch writes the right value into the free_map array so that the index can be reused. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 987bcba0188..f5819527ec9 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -237,7 +237,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); if(lpar_rc != H_Success) { - pool->free_map[free_index] = IBM_VETH_INVALID_MAP; + pool->free_map[free_index] = index; pool->skbuff[index] = NULL; pool->consumer_index--; dma_unmap_single(&adapter->vdev->dev, -- cgit v1.2.3-18-g5258 From d89a64bedf956ef0b406018a7cb76e027fe3e751 Mon Sep 17 00:00:00 2001 From: Komuro Date: Fri, 28 Oct 2005 16:09:54 -0400 Subject: pcnet_cs: fix mii init code for older DL10019 based cards Some older DL10019 based cards need to setup the auto-negotiation-advertisement register to advertise 100Full,100Half,10Full and 10Half. Signed-off-by: Signed-off-by: Jeff Garzik --- drivers/net/pcmcia/pcnet_cs.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 9f22d138e3a..818c185d643 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1020,6 +1020,12 @@ static void set_misc_reg(struct net_device *dev) } else { outb(full_duplex ? 4 : 0, nic_base + DLINK_DIAG); } + } else if (info->flags & IS_DL10019) { + /* Advertise 100F, 100H, 10F, 10H */ + mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1); + /* Restart MII autonegotiation */ + mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000); + mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200); } } -- cgit v1.2.3-18-g5258 From 008d55903a1e9e179ff1d366dfcfa9b72abd116d Mon Sep 17 00:00:00 2001 From: Roger While Date: Fri, 28 Oct 2005 16:11:49 -0400 Subject: [wireless prism54] Fix frame length prism54 is leaking information when passing transmits to the firmware. There is no requirement to adjust the length to >= ETH_ZLEN. Just pass the skb length (after possible adjustment). Signed-off-by: Roger While Signed-off-by: Jeff Garzik --- drivers/net/wireless/prism54/islpci_eth.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 5952e996049..0975dd4ed77 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -97,12 +97,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) /* lock the driver code */ spin_lock_irqsave(&priv->slock, flags); - /* determine the amount of fragments needed to store the frame */ - - frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; - if (init_wds) - frame_size += 6; - /* check whether the destination queue has enough fragments for the frame */ curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]); if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) { @@ -213,6 +207,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) /* store the skb address for future freeing */ priv->data_low_tx[index] = skb; /* set the proper fragment start address and size information */ + frame_size = skb->len; fragment->size = cpu_to_le16(frame_size); fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */ fragment->address = cpu_to_le32(pci_map_address); -- cgit v1.2.3-18-g5258 From 9eb343aeb3e106c1e4c07e2863f45b2c121b3b78 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 21 Oct 2005 19:06:42 +0900 Subject: [PATCH] s2io: kconfig help fix The documentation about s2io is available at Documentation/networking/s2io.txt. Signed-off-by: Akinobu Mita Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5148d47492a..8fa0e26fa80 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2201,8 +2201,8 @@ config S2IO depends on PCI ---help--- This driver supports the 10Gbe XFrame NIC of S2IO. - For help regarding driver compilation, installation and - tuning please look into ~/drivers/net/s2io/README.txt. + More specific information on configuring the driver is in + . config S2IO_NAPI bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" -- cgit v1.2.3-18-g5258 From adf6e00064ebcd3d82009ba6ef66f489f0885ebd Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 4 Oct 2005 11:25:17 -0600 Subject: [PATCH] b44 reports wrong advertised flags Looks like someone used the MII constants instead of the ethtool constants. Signed-off-by: Matthew Wilcox Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 282ebd15f01..225d14fd923 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1619,14 +1619,14 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = 0; if (bp->flags & B44_FLAG_ADV_10HALF) - cmd->advertising |= ADVERTISE_10HALF; + cmd->advertising |= ADVERTISED_10baseT_Half; if (bp->flags & B44_FLAG_ADV_10FULL) - cmd->advertising |= ADVERTISE_10FULL; + cmd->advertising |= ADVERTISED_10baseT_Full; if (bp->flags & B44_FLAG_ADV_100HALF) - cmd->advertising |= ADVERTISE_100HALF; + cmd->advertising |= ADVERTISED_100baseT_Half; if (bp->flags & B44_FLAG_ADV_100FULL) - cmd->advertising |= ADVERTISE_100FULL; - cmd->advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + cmd->advertising |= ADVERTISED_100baseT_Full; + cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; cmd->speed = (bp->flags & B44_FLAG_100_BASE_T) ? SPEED_100 : SPEED_10; cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? -- cgit v1.2.3-18-g5258 From 8fee5f51a56aa7a67d955993572a2ae05d31a2c6 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 5 Oct 2005 23:29:58 +0200 Subject: [PATCH] sis190.c: fix multicast MAC filter Here is a patch that changes the way the MAC filter is computed for the multicast addresses. The computation is taken from the SiS GPL driver. This patch is necessary to get IPv6 working. Signed-off-by: Aurelien Jarno Signed-off-by: Jeff Garzik --- drivers/net/sis190.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 92f75529eff..478791e09bf 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -842,7 +842,7 @@ static void sis190_set_rx_mode(struct net_device *dev) for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { int bit_nr = - ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f; mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); rx_mode |= AcceptMulticast; } -- cgit v1.2.3-18-g5258 From 99e1baf869cf20791e66e38facd51d14b28551f8 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 5 Oct 2005 11:10:24 -0400 Subject: [PATCH] smc91x: shut down power after probing If the interface is not used right away after being probed it wastes power needlessly. Noted by Holger Schurig. Signed-off-by: Nicolas Pitre Signed-off-by: Jeff Garzik --- drivers/net/smc91x.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 1438fdd2082..c5bc8ae84dd 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1983,6 +1983,10 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) if (lp->version >= (CHIP_91100 << 4)) smc_phy_detect(dev); + /* then shut everything down to save power */ + smc_shutdown(dev); + smc_phy_powerdown(dev); + /* Set default parameters */ lp->msg_enable = NETIF_MSG_LINK; lp->ctl_rfduplx = 0; -- cgit v1.2.3-18-g5258 From 712cb1ebb1653538527500165d8382ca48a7fca1 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Sun, 23 Oct 2005 13:41:35 -0700 Subject: [PATCH] Fix CS89x0 KConfig for IXDP2X01 IXDP2x01 systems can be built without PCI network cards, so we should not require NET_PCI to build CS89x0 on these systems. Signed-off-by: Deepak Saxena Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8fa0e26fa80..814a93b8c90 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1338,7 +1338,7 @@ config FORCEDETH config CS89x0 tristate "CS89x0 support" - depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105 + depends on (NET_PCI && ISA) || ARCH_PNX0105 || ARCH_IXDP2X01 ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the -- cgit v1.2.3-18-g5258 From d8840ac907c7943bc7e196b11812adfa95cb28ef Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 7 Oct 2005 02:05:23 +0400 Subject: [PATCH] starfire: free_irq() on error path of netdev_open() Signed-off-by: Alexey Dobriyan Signed-off-by: Jeff Garzik --- drivers/net/starfire.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index efdb179ecc8..38b2b0a3ce9 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1091,8 +1091,10 @@ static int netdev_open(struct net_device *dev) rx_ring_size = sizeof(struct starfire_rx_desc) * RX_RING_SIZE; np->queue_mem_size = tx_done_q_size + rx_done_q_size + tx_ring_size + rx_ring_size; np->queue_mem = pci_alloc_consistent(np->pci_dev, np->queue_mem_size, &np->queue_mem_dma); - if (np->queue_mem == 0) + if (np->queue_mem == NULL) { + free_irq(dev->irq, dev); return -ENOMEM; + } np->tx_done_q = np->queue_mem; np->tx_done_q_dma = np->queue_mem_dma; -- cgit v1.2.3-18-g5258 From 48257c4f168e5d040394aeca4d37b59f68e0d36b Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Fri, 28 Oct 2005 16:25:58 -0400 Subject: Add fs_enet ethernet network driver, for several embedded platforms. --- drivers/net/Kconfig | 1 + drivers/net/Makefile | 3 + drivers/net/fs_enet/Kconfig | 20 + drivers/net/fs_enet/Makefile | 10 + drivers/net/fs_enet/fs_enet-main.c | 1226 ++++++++++++++++++++++++++++++++++++ drivers/net/fs_enet/fs_enet-mii.c | 507 +++++++++++++++ drivers/net/fs_enet/fs_enet.h | 245 +++++++ drivers/net/fs_enet/mac-fcc.c | 578 +++++++++++++++++ drivers/net/fs_enet/mac-fec.c | 653 +++++++++++++++++++ drivers/net/fs_enet/mac-scc.c | 524 +++++++++++++++ drivers/net/fs_enet/mii-bitbang.c | 405 ++++++++++++ drivers/net/fs_enet/mii-fixed.c | 92 +++ 12 files changed, 4264 insertions(+) create mode 100644 drivers/net/fs_enet/Kconfig create mode 100644 drivers/net/fs_enet/Makefile create mode 100644 drivers/net/fs_enet/fs_enet-main.c create mode 100644 drivers/net/fs_enet/fs_enet-mii.c create mode 100644 drivers/net/fs_enet/fs_enet.h create mode 100644 drivers/net/fs_enet/mac-fcc.c create mode 100644 drivers/net/fs_enet/mac-fec.c create mode 100644 drivers/net/fs_enet/mac-scc.c create mode 100644 drivers/net/fs_enet/mii-bitbang.c create mode 100644 drivers/net/fs_enet/mii-fixed.c (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 814a93b8c90..27732fdeeea 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1775,6 +1775,7 @@ config NE_H8300 controller on the Renesas H8/300 processor. source "drivers/net/fec_8xx/Kconfig" +source "drivers/net/fs_enet/Kconfig" endmenu diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 1a84e0435f6..7c313cb341b 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -203,3 +203,6 @@ obj-$(CONFIG_IRDA) += irda/ obj-$(CONFIG_ETRAX_ETHERNET) += cris/ obj-$(CONFIG_NETCONSOLE) += netconsole.o + +obj-$(CONFIG_FS_ENET) += fs_enet/ + diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig new file mode 100644 index 00000000000..6aaee67dd4b --- /dev/null +++ b/drivers/net/fs_enet/Kconfig @@ -0,0 +1,20 @@ +config FS_ENET + tristate "Freescale Ethernet Driver" + depends on NET_ETHERNET && (CPM1 || CPM2) + select MII + +config FS_ENET_HAS_SCC + bool "Chip has an SCC usable for ethernet" + depends on FS_ENET && (CPM1 || CPM2) + default y + +config FS_ENET_HAS_FCC + bool "Chip has an FCC usable for ethernet" + depends on FS_ENET && CPM2 + default y + +config FS_ENET_HAS_FEC + bool "Chip has an FEC usable for ethernet" + depends on FS_ENET && CPM1 + default y + diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/fs_enet/Makefile new file mode 100644 index 00000000000..d6dd3f2fb43 --- /dev/null +++ b/drivers/net/fs_enet/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the Freescale Ethernet controllers +# + +obj-$(CONFIG_FS_ENET) += fs_enet.o + +obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o +obj-$(CONFIG_8260) += mac-fcc.o + +fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c new file mode 100644 index 00000000000..44fac737328 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -0,0 +1,1226 @@ +/* + * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * Heavily based on original FEC driver by Dan Malek + * and modifications by Joakim Tjernlund + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "fs_enet.h" + +/*************************************************/ + +static char version[] __devinitdata = + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n"; + +MODULE_AUTHOR("Pantelis Antoniou "); +MODULE_DESCRIPTION("Freescale Ethernet Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); + +MODULE_PARM(fs_enet_debug, "i"); +MODULE_PARM_DESC(fs_enet_debug, + "Freescale bitmapped debugging message enable value"); + +int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ + +static void fs_set_multicast_list(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + + (*fep->ops->set_multicast_list)(dev); +} + +/* NAPI receive function */ +static int fs_enet_rx_napi(struct net_device *dev, int *budget) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + cbd_t *bdp; + struct sk_buff *skb, *skbn, *skbt; + int received = 0; + u16 pkt_len, sc; + int curidx; + int rx_work_limit = 0; /* pacify gcc */ + + rx_work_limit = min(dev->quota, *budget); + + if (!netif_running(dev)) + return 0; + + /* + * First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = fep->cur_rx; + + /* clear RX status bits for napi*/ + (*fep->ops->napi_clear_rx_event)(dev); + + while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { + + curidx = bdp - fep->rx_bd_base; + + /* + * Since we have allocated space to hold a complete frame, + * the last indicator should be set. + */ + if ((sc & BD_ENET_RX_LAST) == 0) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s rcv is not +last\n", + dev->name); + + /* + * Check for errors. + */ + if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | + BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { + fep->stats.rx_errors++; + /* Frame too long or too short. */ + if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) + fep->stats.rx_length_errors++; + /* Frame alignment */ + if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) + fep->stats.rx_frame_errors++; + /* CRC Error */ + if (sc & BD_ENET_RX_CR) + fep->stats.rx_crc_errors++; + /* FIFO overrun */ + if (sc & BD_ENET_RX_OV) + fep->stats.rx_crc_errors++; + + skb = fep->rx_skbuff[curidx]; + + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + skbn = skb; + + } else { + + /* napi, got packet but no quota */ + if (--rx_work_limit < 0) + break; + + skb = fep->rx_skbuff[curidx]; + + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + /* + * Process the incoming frame. + */ + fep->stats.rx_packets++; + pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ + fep->stats.rx_bytes += pkt_len + 4; + + if (pkt_len <= fpi->rx_copybreak) { + /* +2 to make IP header L1 cache aligned */ + skbn = dev_alloc_skb(pkt_len + 2); + if (skbn != NULL) { + skb_reserve(skbn, 2); /* align IP header */ + memcpy(skbn->data, skb->data, pkt_len); + /* swap */ + skbt = skb; + skb = skbn; + skbn = skbt; + } + } else + skbn = dev_alloc_skb(ENET_RX_FRSIZE); + + if (skbn != NULL) { + skb->dev = dev; + skb_put(skb, pkt_len); /* Make room */ + skb->protocol = eth_type_trans(skb, dev); + received++; + netif_receive_skb(skb); + } else { + printk(KERN_WARNING DRV_MODULE_NAME + ": %s Memory squeeze, dropping packet.\n", + dev->name); + fep->stats.rx_dropped++; + skbn = skb; + } + } + + fep->rx_skbuff[curidx] = skbn; + CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE)); + CBDW_DATLEN(bdp, 0); + CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); + + /* + * Update BD pointer to next entry. + */ + if ((sc & BD_ENET_RX_WRAP) == 0) + bdp++; + else + bdp = fep->rx_bd_base; + + (*fep->ops->rx_bd_done)(dev); + } + + fep->cur_rx = bdp; + + dev->quota -= received; + *budget -= received; + + if (rx_work_limit < 0) + return 1; /* not done */ + + /* done */ + netif_rx_complete(dev); + + (*fep->ops->napi_enable_rx)(dev); + + return 0; +} + +/* non NAPI receive function */ +static int fs_enet_rx_non_napi(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; + cbd_t *bdp; + struct sk_buff *skb, *skbn, *skbt; + int received = 0; + u16 pkt_len, sc; + int curidx; + /* + * First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = fep->cur_rx; + + while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { + + curidx = bdp - fep->rx_bd_base; + + /* + * Since we have allocated space to hold a complete frame, + * the last indicator should be set. + */ + if ((sc & BD_ENET_RX_LAST) == 0) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s rcv is not +last\n", + dev->name); + + /* + * Check for errors. + */ + if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | + BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { + fep->stats.rx_errors++; + /* Frame too long or too short. */ + if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) + fep->stats.rx_length_errors++; + /* Frame alignment */ + if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) + fep->stats.rx_frame_errors++; + /* CRC Error */ + if (sc & BD_ENET_RX_CR) + fep->stats.rx_crc_errors++; + /* FIFO overrun */ + if (sc & BD_ENET_RX_OV) + fep->stats.rx_crc_errors++; + + skb = fep->rx_skbuff[curidx]; + + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + skbn = skb; + + } else { + + skb = fep->rx_skbuff[curidx]; + + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + /* + * Process the incoming frame. + */ + fep->stats.rx_packets++; + pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ + fep->stats.rx_bytes += pkt_len + 4; + + if (pkt_len <= fpi->rx_copybreak) { + /* +2 to make IP header L1 cache aligned */ + skbn = dev_alloc_skb(pkt_len + 2); + if (skbn != NULL) { + skb_reserve(skbn, 2); /* align IP header */ + memcpy(skbn->data, skb->data, pkt_len); + /* swap */ + skbt = skb; + skb = skbn; + skbn = skbt; + } + } else + skbn = dev_alloc_skb(ENET_RX_FRSIZE); + + if (skbn != NULL) { + skb->dev = dev; + skb_put(skb, pkt_len); /* Make room */ + skb->protocol = eth_type_trans(skb, dev); + received++; + netif_rx(skb); + } else { + printk(KERN_WARNING DRV_MODULE_NAME + ": %s Memory squeeze, dropping packet.\n", + dev->name); + fep->stats.rx_dropped++; + skbn = skb; + } + } + + fep->rx_skbuff[curidx] = skbn; + CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE)); + CBDW_DATLEN(bdp, 0); + CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); + + /* + * Update BD pointer to next entry. + */ + if ((sc & BD_ENET_RX_WRAP) == 0) + bdp++; + else + bdp = fep->rx_bd_base; + + (*fep->ops->rx_bd_done)(dev); + } + + fep->cur_rx = bdp; + + return 0; +} + +static void fs_enet_tx(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; + struct sk_buff *skb; + int dirtyidx, do_wake, do_restart; + u16 sc; + + spin_lock(&fep->lock); + bdp = fep->dirty_tx; + + do_wake = do_restart = 0; + while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { + + dirtyidx = bdp - fep->tx_bd_base; + + if (fep->tx_free == fep->tx_ring) + break; + + skb = fep->tx_skbuff[dirtyidx]; + + /* + * Check for errors. + */ + if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | + BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { + + if (sc & BD_ENET_TX_HB) /* No heartbeat */ + fep->stats.tx_heartbeat_errors++; + if (sc & BD_ENET_TX_LC) /* Late collision */ + fep->stats.tx_window_errors++; + if (sc & BD_ENET_TX_RL) /* Retrans limit */ + fep->stats.tx_aborted_errors++; + if (sc & BD_ENET_TX_UN) /* Underrun */ + fep->stats.tx_fifo_errors++; + if (sc & BD_ENET_TX_CSL) /* Carrier lost */ + fep->stats.tx_carrier_errors++; + + if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { + fep->stats.tx_errors++; + do_restart = 1; + } + } else + fep->stats.tx_packets++; + + if (sc & BD_ENET_TX_READY) + printk(KERN_WARNING DRV_MODULE_NAME + ": %s HEY! Enet xmit interrupt and TX_READY.\n", + dev->name); + + /* + * Deferred means some collisions occurred during transmit, + * but we eventually sent the packet OK. + */ + if (sc & BD_ENET_TX_DEF) + fep->stats.collisions++; + + /* unmap */ + dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE); + + /* + * Free the sk buffer associated with this last transmit. + */ + dev_kfree_skb_irq(skb); + fep->tx_skbuff[dirtyidx] = NULL; + + /* + * Update pointer to next buffer descriptor to be transmitted. + */ + if ((sc & BD_ENET_TX_WRAP) == 0) + bdp++; + else + bdp = fep->tx_bd_base; + + /* + * Since we have freed up a buffer, the ring is no longer + * full. + */ + if (!fep->tx_free++) + do_wake = 1; + } + + fep->dirty_tx = bdp; + + if (do_restart) + (*fep->ops->tx_restart)(dev); + + spin_unlock(&fep->lock); + + if (do_wake) + netif_wake_queue(dev); +} + +/* + * The interrupt handler. + * This is called from the MPC core interrupt. + */ +static irqreturn_t +fs_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct fs_enet_private *fep; + const struct fs_platform_info *fpi; + u32 int_events; + u32 int_clr_events; + int nr, napi_ok; + int handled; + + fep = netdev_priv(dev); + fpi = fep->fpi; + + nr = 0; + while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) { + + nr++; + + int_clr_events = int_events; + if (fpi->use_napi) + int_clr_events &= ~fep->ev_napi_rx; + + (*fep->ops->clear_int_events)(dev, int_clr_events); + + if (int_events & fep->ev_err) + (*fep->ops->ev_error)(dev, int_events); + + if (int_events & fep->ev_rx) { + if (!fpi->use_napi) + fs_enet_rx_non_napi(dev); + else { + napi_ok = netif_rx_schedule_prep(dev); + + (*fep->ops->napi_disable_rx)(dev); + (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx); + + /* NOTE: it is possible for FCCs in NAPI mode */ + /* to submit a spurious interrupt while in poll */ + if (napi_ok) + __netif_rx_schedule(dev); + } + } + + if (int_events & fep->ev_tx) + fs_enet_tx(dev); + } + + handled = nr > 0; + return IRQ_RETVAL(handled); +} + +void fs_init_bds(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; + struct sk_buff *skb; + int i; + + fs_cleanup_bds(dev); + + fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; + fep->tx_free = fep->tx_ring; + fep->cur_rx = fep->rx_bd_base; + + /* + * Initialize the receive buffer descriptors. + */ + for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { + skb = dev_alloc_skb(ENET_RX_FRSIZE); + if (skb == NULL) { + printk(KERN_WARNING DRV_MODULE_NAME + ": %s Memory squeeze, unable to allocate skb\n", + dev->name); + break; + } + fep->rx_skbuff[i] = skb; + skb->dev = dev; + CBDW_BUFADDR(bdp, + dma_map_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE)); + CBDW_DATLEN(bdp, 0); /* zero */ + CBDW_SC(bdp, BD_ENET_RX_EMPTY | + ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); + } + /* + * if we failed, fillup remainder + */ + for (; i < fep->rx_ring; i++, bdp++) { + fep->rx_skbuff[i] = NULL; + CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP); + } + + /* + * ...and the same for transmit. + */ + for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { + fep->tx_skbuff[i] = NULL; + CBDW_BUFADDR(bdp, 0); + CBDW_DATLEN(bdp, 0); + CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP); + } +} + +void fs_cleanup_bds(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct sk_buff *skb; + int i; + + /* + * Reset SKB transmit buffers. + */ + for (i = 0; i < fep->tx_ring; i++) { + if ((skb = fep->tx_skbuff[i]) == NULL) + continue; + + /* unmap */ + dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE); + + fep->tx_skbuff[i] = NULL; + dev_kfree_skb(skb); + } + + /* + * Reset SKB receive buffers + */ + for (i = 0; i < fep->rx_ring; i++) { + if ((skb = fep->rx_skbuff[i]) == NULL) + continue; + + /* unmap */ + dma_unmap_single(fep->dev, skb->data, + L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), + DMA_FROM_DEVICE); + + fep->rx_skbuff[i] = NULL; + + dev_kfree_skb(skb); + } +} + +/**********************************************************************************/ + +static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + cbd_t *bdp; + int curidx; + u16 sc; + unsigned long flags; + + spin_lock_irqsave(&fep->tx_lock, flags); + + /* + * Fill in a Tx ring entry + */ + bdp = fep->cur_tx; + + if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { + netif_stop_queue(dev); + spin_unlock_irqrestore(&fep->tx_lock, flags); + + /* + * Ooops. All transmit buffers are full. Bail out. + * This should not happen, since the tx queue should be stopped. + */ + printk(KERN_WARNING DRV_MODULE_NAME + ": %s tx queue full!.\n", dev->name); + return NETDEV_TX_BUSY; + } + + curi