X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fmv643xx_eth.c;h=b62e61d4ca3e82d40500d73b6b762b12264d7600;hb=37c4fd8c7551c7419a5faf87a76ff6949c5adaf3;hp=9f3ee7d6a5bcaeb737a8380dee14a41f895115ac;hpb=66e63ffbc04706568d8789cbb00eaa8ddbcae648;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 9f3ee7d..b62e61d 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -53,7 +53,9 @@ #include #include #include +#include #include +#include static char mv643xx_eth_driver_name[] = "mv643xx_eth"; static char mv643xx_eth_driver_version[] = "1.4"; @@ -87,7 +89,24 @@ static char mv643xx_eth_driver_version[] = "1.4"; #define MAC_ADDR_LOW 0x0014 #define MAC_ADDR_HIGH 0x0018 #define SDMA_CONFIG 0x001c +#define TX_BURST_SIZE_16_64BIT 0x01000000 +#define TX_BURST_SIZE_4_64BIT 0x00800000 +#define BLM_TX_NO_SWAP 0x00000020 +#define BLM_RX_NO_SWAP 0x00000010 +#define RX_BURST_SIZE_16_64BIT 0x00000008 +#define RX_BURST_SIZE_4_64BIT 0x00000004 #define PORT_SERIAL_CONTROL 0x003c +#define SET_MII_SPEED_TO_100 0x01000000 +#define SET_GMII_SPEED_TO_1000 0x00800000 +#define SET_FULL_DUPLEX_MODE 0x00200000 +#define MAX_RX_PACKET_9700BYTE 0x000a0000 +#define DISABLE_AUTO_NEG_SPEED_GMII 0x00002000 +#define DO_NOT_FORCE_LINK_FAIL 0x00000400 +#define SERIAL_PORT_CONTROL_RESERVED 0x00000200 +#define DISABLE_AUTO_NEG_FOR_FLOW_CTRL 0x00000008 +#define DISABLE_AUTO_NEG_FOR_DUPLEX 0x00000004 +#define FORCE_LINK_PASS 0x00000002 +#define SERIAL_PORT_ENABLE 0x00000001 #define PORT_STATUS 0x0044 #define TX_FIFO_EMPTY 0x00000400 #define TX_IN_PROGRESS 0x00000080 @@ -105,7 +124,9 @@ static char mv643xx_eth_driver_version[] = "1.4"; #define TX_BW_BURST 0x005c #define INT_CAUSE 0x0060 #define INT_TX_END 0x07f80000 +#define INT_TX_END_0 0x00080000 #define INT_RX 0x000003fc +#define INT_RX_0 0x00000004 #define INT_EXT 0x00000002 #define INT_CAUSE_EXT 0x0064 #define INT_EXT_LINK_PHY 0x00110000 @@ -134,45 +155,29 @@ static char mv643xx_eth_driver_version[] = "1.4"; /* - * SDMA configuration register. + * SDMA configuration register default value. */ -#define RX_BURST_SIZE_16_64BIT (4 << 1) -#define BLM_RX_NO_SWAP (1 << 4) -#define BLM_TX_NO_SWAP (1 << 5) -#define TX_BURST_SIZE_16_64BIT (4 << 22) - #if defined(__BIG_ENDIAN) #define PORT_SDMA_CONFIG_DEFAULT_VALUE \ - (RX_BURST_SIZE_16_64BIT | \ - TX_BURST_SIZE_16_64BIT) + (RX_BURST_SIZE_4_64BIT | \ + TX_BURST_SIZE_4_64BIT) #elif defined(__LITTLE_ENDIAN) #define PORT_SDMA_CONFIG_DEFAULT_VALUE \ - (RX_BURST_SIZE_16_64BIT | \ - BLM_RX_NO_SWAP | \ - BLM_TX_NO_SWAP | \ - TX_BURST_SIZE_16_64BIT) + (RX_BURST_SIZE_4_64BIT | \ + BLM_RX_NO_SWAP | \ + BLM_TX_NO_SWAP | \ + TX_BURST_SIZE_4_64BIT) #else #error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined #endif /* - * Port serial control register. + * Misc definitions. */ -#define SET_MII_SPEED_TO_100 (1 << 24) -#define SET_GMII_SPEED_TO_1000 (1 << 23) -#define SET_FULL_DUPLEX_MODE (1 << 21) -#define MAX_RX_PACKET_9700BYTE (5 << 17) -#define DISABLE_AUTO_NEG_SPEED_GMII (1 << 13) -#define DO_NOT_FORCE_LINK_FAIL (1 << 10) -#define SERIAL_PORT_CONTROL_RESERVED (1 << 9) -#define DISABLE_AUTO_NEG_FOR_FLOW_CTRL (1 << 3) -#define DISABLE_AUTO_NEG_FOR_DUPLEX (1 << 2) -#define FORCE_LINK_PASS (1 << 1) -#define SERIAL_PORT_ENABLE (1 << 0) - -#define DEFAULT_RX_QUEUE_SIZE 128 -#define DEFAULT_TX_QUEUE_SIZE 256 +#define DEFAULT_RX_QUEUE_SIZE 128 +#define DEFAULT_TX_QUEUE_SIZE 256 +#define SKB_DMA_REALIGN ((PAGE_SIZE - NET_SKB_PAD) % SMP_CACHE_BYTES) /* @@ -225,6 +230,12 @@ struct tx_desc { #define RX_ENABLE_INTERRUPT 0x20000000 #define RX_FIRST_DESC 0x08000000 #define RX_LAST_DESC 0x04000000 +#define RX_IP_HDR_OK 0x02000000 +#define RX_PKT_IS_IPV4 0x01000000 +#define RX_PKT_IS_ETHERNETV2 0x00800000 +#define RX_PKT_LAYER4_TYPE_MASK 0x00600000 +#define RX_PKT_LAYER4_TYPE_TCP_IPV4 0x00000000 +#define RX_PKT_IS_VLAN_TAGGED 0x00080000 /* TX descriptor command */ #define TX_ENABLE_INTERRUPT 0x00800000 @@ -284,6 +295,9 @@ struct mv643xx_eth_shared_private { #define TX_BW_CONTROL_OLD_LAYOUT 1 #define TX_BW_CONTROL_NEW_LAYOUT 2 +static int mv643xx_eth_open(struct net_device *dev); +static int mv643xx_eth_stop(struct net_device *dev); + /* per-port *****************************************************************/ struct mib_counters { @@ -319,6 +333,12 @@ struct mib_counters { u32 late_collision; }; +struct lro_counters { + u32 lro_aggregated; + u32 lro_flushed; + u32 lro_no_desc; +}; + struct rx_queue { int index; @@ -332,6 +352,9 @@ struct rx_queue { dma_addr_t rx_desc_dma; int rx_desc_area_size; struct sk_buff **rx_skb; + + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_arr[8]; }; struct tx_queue { @@ -367,15 +390,18 @@ struct mv643xx_eth_private { spinlock_t mib_counters_lock; struct mib_counters mib_counters; + struct lro_counters lro_counters; + struct work_struct tx_timeout_task; struct napi_struct napi; + u32 int_mask; + u8 oom; u8 work_link; u8 work_tx; u8 work_tx_end; u8 work_rx; u8 work_rx_refill; - u8 work_rx_oom; int skb_size; struct sk_buff_head rx_recycle; @@ -383,7 +409,7 @@ struct mv643xx_eth_private { /* * RX state. */ - int default_rx_ring_size; + int rx_ring_size; unsigned long rx_desc_sram_addr; int rx_desc_sram_size; int rxq_count; @@ -393,7 +419,7 @@ struct mv643xx_eth_private { /* * TX state. */ - int default_tx_ring_size; + int tx_ring_size; unsigned long tx_desc_sram_addr; int tx_desc_sram_size; int txq_count; @@ -491,12 +517,40 @@ static void txq_maybe_wake(struct tx_queue *txq) /* rx napi ******************************************************************/ +static int +mv643xx_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph, + u64 *hdr_flags, void *priv) +{ + unsigned long cmd_sts = (unsigned long)priv; + + /* + * Make sure that this packet is Ethernet II, is not VLAN + * tagged, is IPv4, has a valid IP header, and is TCP. + */ + if ((cmd_sts & (RX_IP_HDR_OK | RX_PKT_IS_IPV4 | + RX_PKT_IS_ETHERNETV2 | RX_PKT_LAYER4_TYPE_MASK | + RX_PKT_IS_VLAN_TAGGED)) != + (RX_IP_HDR_OK | RX_PKT_IS_IPV4 | + RX_PKT_IS_ETHERNETV2 | RX_PKT_LAYER4_TYPE_TCP_IPV4)) + return -1; + + skb_reset_network_header(skb); + skb_set_transport_header(skb, ip_hdrlen(skb)); + *iphdr = ip_hdr(skb); + *tcph = tcp_hdr(skb); + *hdr_flags = LRO_IPV4 | LRO_TCP; + + return 0; +} + static int rxq_process(struct rx_queue *rxq, int budget) { struct mv643xx_eth_private *mp = rxq_to_mp(rxq); struct net_device_stats *stats = &mp->dev->stats; + int lro_flush_needed; int rx; + lro_flush_needed = 0; rx = 0; while (rx < budget && rxq->rx_desc_count) { struct rx_desc *rx_desc; @@ -518,7 +572,7 @@ static int rxq_process(struct rx_queue *rxq, int budget) if (rxq->rx_curr_desc == rxq->rx_ring_size) rxq->rx_curr_desc = 0; - dma_unmap_single(NULL, rx_desc->buf_ptr, + dma_unmap_single(mp->dev->dev.parent, rx_desc->buf_ptr, rx_desc->buf_size, DMA_FROM_DEVICE); rxq->rx_desc_count--; rx++; @@ -543,37 +597,49 @@ static int rxq_process(struct rx_queue *rxq, int budget) * on, or the error summary bit is set, the packet needs * to be dropped. */ - if (((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != - (RX_FIRST_DESC | RX_LAST_DESC)) - || (cmd_sts & ERROR_SUMMARY)) { - stats->rx_dropped++; - - if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != - (RX_FIRST_DESC | RX_LAST_DESC)) { - if (net_ratelimit()) - dev_printk(KERN_ERR, &mp->dev->dev, - "received packet spanning " - "multiple descriptors\n"); - } + if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC | ERROR_SUMMARY)) + != (RX_FIRST_DESC | RX_LAST_DESC)) + goto err; + + /* + * The -4 is for the CRC in the trailer of the + * received packet + */ + skb_put(skb, byte_cnt - 2 - 4); - if (cmd_sts & ERROR_SUMMARY) - stats->rx_errors++; + if (cmd_sts & LAYER_4_CHECKSUM_OK) + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->protocol = eth_type_trans(skb, mp->dev); - dev_kfree_skb(skb); - } else { - /* - * The -4 is for the CRC in the trailer of the - * received packet - */ - skb_put(skb, byte_cnt - 2 - 4); - - if (cmd_sts & LAYER_4_CHECKSUM_OK) - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->protocol = eth_type_trans(skb, mp->dev); + if (skb->dev->features & NETIF_F_LRO && + skb->ip_summed == CHECKSUM_UNNECESSARY) { + lro_receive_skb(&rxq->lro_mgr, skb, (void *)cmd_sts); + lro_flush_needed = 1; + } else netif_receive_skb(skb); + + continue; + +err: + stats->rx_dropped++; + + if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != + (RX_FIRST_DESC | RX_LAST_DESC)) { + if (net_ratelimit()) + dev_printk(KERN_ERR, &mp->dev->dev, + "received packet spanning " + "multiple descriptors\n"); } + + if (cmd_sts & ERROR_SUMMARY) + stats->rx_errors++; + + dev_kfree_skb(skb); } + if (lro_flush_needed) + lro_flush_all(&rxq->lro_mgr); + if (rx < budget) mp->work_rx &= ~(1 << rxq->index); @@ -588,22 +654,20 @@ static int rxq_refill(struct rx_queue *rxq, int budget) refilled = 0; while (refilled < budget && rxq->rx_desc_count < rxq->rx_ring_size) { struct sk_buff *skb; - int unaligned; int rx; + struct rx_desc *rx_desc; skb = __skb_dequeue(&mp->rx_recycle); if (skb == NULL) - skb = dev_alloc_skb(mp->skb_size + - dma_get_cache_alignment() - 1); + skb = dev_alloc_skb(mp->skb_size); if (skb == NULL) { - mp->work_rx_oom |= 1 << rxq->index; + mp->oom = 1; goto oom; } - unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1); - if (unaligned) - skb_reserve(skb, dma_get_cache_alignment() - unaligned); + if (SKB_DMA_REALIGN) + skb_reserve(skb, SKB_DMA_REALIGN); refilled++; rxq->rx_desc_count++; @@ -612,13 +676,15 @@ static int rxq_refill(struct rx_queue *rxq, int budget) if (rxq->rx_used_desc == rxq->rx_ring_size) rxq->rx_used_desc = 0; - rxq->rx_desc_area[rx].buf_ptr = dma_map_single(NULL, skb->data, - mp->skb_size, DMA_FROM_DEVICE); - rxq->rx_desc_area[rx].buf_size = mp->skb_size; + rx_desc = rxq->rx_desc_area + rx; + + rx_desc->buf_ptr = dma_map_single(mp->dev->dev.parent, + skb->data, mp->skb_size, + DMA_FROM_DEVICE); + rx_desc->buf_size = mp->skb_size; rxq->rx_skb[rx] = skb; wmb(); - rxq->rx_desc_area[rx].cmd_sts = BUFFER_OWNED_BY_DMA | - RX_ENABLE_INTERRUPT; + rx_desc->cmd_sts = BUFFER_OWNED_BY_DMA | RX_ENABLE_INTERRUPT; wmb(); /* @@ -653,6 +719,7 @@ static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb) static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb) { + struct mv643xx_eth_private *mp = txq_to_mp(txq); int nr_frags = skb_shinfo(skb)->nr_frags; int frag; @@ -681,10 +748,10 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb) desc->l4i_chk = 0; desc->byte_cnt = this_frag->size; - desc->buf_ptr = dma_map_page(NULL, this_frag->page, - this_frag->page_offset, - this_frag->size, - DMA_TO_DEVICE); + desc->buf_ptr = dma_map_page(mp->dev->dev.parent, + this_frag->page, + this_frag->page_offset, + this_frag->size, DMA_TO_DEVICE); } } @@ -761,7 +828,8 @@ no_csum: desc->l4i_chk = l4i_chk; desc->byte_cnt = length; - desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); + desc->buf_ptr = dma_map_single(mp->dev->dev.parent, skb->data, + length, DMA_TO_DEVICE); __skb_queue_tail(&txq->tx_skb, skb); @@ -891,16 +959,16 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force) } if (cmd_sts & TX_FIRST_DESC) { - dma_unmap_single(NULL, desc->buf_ptr, + dma_unmap_single(mp->dev->dev.parent, desc->buf_ptr, desc->byte_cnt, DMA_TO_DEVICE); } else { - dma_unmap_page(NULL, desc->buf_ptr, + dma_unmap_page(mp->dev->dev.parent, desc->buf_ptr, desc->byte_cnt, DMA_TO_DEVICE); } if (skb != NULL) { if (skb_queue_len(&mp->rx_recycle) < - mp->default_rx_ring_size && + mp->rx_ring_size && skb_recycle_check(skb, mp->skb_size)) __skb_queue_head(&mp->rx_recycle, skb); else @@ -998,40 +1066,6 @@ static void txq_set_fixed_prio_mode(struct tx_queue *txq) } } -static void txq_set_wrr(struct tx_queue *txq, int weight) -{ - struct mv643xx_eth_private *mp = txq_to_mp(txq); - int off; - u32 val; - - /* - * Turn off fixed priority mode. - */ - off = 0; - switch (mp->shared->tx_bw_control) { - case TX_BW_CONTROL_OLD_LAYOUT: - off = TXQ_FIX_PRIO_CONF; - break; - case TX_BW_CONTROL_NEW_LAYOUT: - off = TXQ_FIX_PRIO_CONF_MOVED; - break; - } - - if (off) { - val = rdlp(mp, off); - val &= ~(1 << txq->index); - wrlp(mp, off, val); - - /* - * Configure WRR weight for this queue. - */ - - val = rdlp(mp, off); - val = (val & ~0xff) | (weight & 0xff); - wrlp(mp, TXQ_BW_WRR_CONF(txq->index), val); - } -} - /* mii management interface *************************************************/ static irqreturn_t mv643xx_eth_err_irq(int irq, void *dev_id) @@ -1150,6 +1184,26 @@ static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev) return stats; } +static void mv643xx_eth_grab_lro_stats(struct mv643xx_eth_private *mp) +{ + u32 lro_aggregated = 0; + u32 lro_flushed = 0; + u32 lro_no_desc = 0; + int i; + + for (i = 0; i < mp->rxq_count; i++) { + struct rx_queue *rxq = mp->rxq + i; + + lro_aggregated += rxq->lro_mgr.stats.aggregated; + lro_flushed += rxq->lro_mgr.stats.flushed; + lro_no_desc += rxq->lro_mgr.stats.no_desc; + } + + mp->lro_counters.lro_aggregated = lro_aggregated; + mp->lro_counters.lro_flushed = lro_flushed; + mp->lro_counters.lro_no_desc = lro_no_desc; +} + static inline u32 mib_read(struct mv643xx_eth_private *mp, int offset) { return rdl(mp, MIB_COUNTERS(mp->port_num) + offset); @@ -1167,9 +1221,8 @@ static void mib_counters_update(struct mv643xx_eth_private *mp) { struct mib_counters *p = &mp->mib_counters; - spin_lock(&mp->mib_counters_lock); + spin_lock_bh(&mp->mib_counters_lock); p->good_octets_received += mib_read(mp, 0x00); - p->good_octets_received += (u64)mib_read(mp, 0x04) << 32; p->bad_octets_received += mib_read(mp, 0x08); p->internal_mac_transmit_err += mib_read(mp, 0x0c); p->good_frames_received += mib_read(mp, 0x10); @@ -1183,7 +1236,6 @@ static void mib_counters_update(struct mv643xx_eth_private *mp) p->frames_512_to_1023_octets += mib_read(mp, 0x30); p->frames_1024_to_max_octets += mib_read(mp, 0x34); p->good_octets_sent += mib_read(mp, 0x38); - p->good_octets_sent += (u64)mib_read(mp, 0x3c) << 32; p->good_frames_sent += mib_read(mp, 0x40); p->excessive_collision += mib_read(mp, 0x44); p->multicast_frames_sent += mib_read(mp, 0x48); @@ -1200,7 +1252,7 @@ static void mib_counters_update(struct mv643xx_eth_private *mp) p->bad_crc_event += mib_read(mp, 0x74); p->collision += mib_read(mp, 0x78); p->late_collision += mib_read(mp, 0x7c); - spin_unlock(&mp->mib_counters_lock); + spin_unlock_bh(&mp->mib_counters_lock); mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ); } @@ -1213,6 +1265,85 @@ static void mib_counters_timer_wrapper(unsigned long _mp) } +/* interrupt coalescing *****************************************************/ +/* + * Hardware coalescing parameters are set in units of 64 t_clk + * cycles. I.e.: + * + * coal_delay_in_usec = 64000000 * register_value / t_clk_rate + * + * register_value = coal_delay_in_usec * t_clk_rate / 64000000 + * + * In the ->set*() methods, we round the computed register value + * to the nearest integer. + */ +static unsigned int get_rx_coal(struct mv643xx_eth_private *mp) +{ + u32 val = rdlp(mp, SDMA_CONFIG); + u64 temp; + + if (mp->shared->extended_rx_coal_limit) + temp = ((val & 0x02000000) >> 10) | ((val & 0x003fff80) >> 7); + else + temp = (val & 0x003fff00) >> 8; + + temp *= 64000000; + do_div(temp, mp->shared->t_clk); + + return (unsigned int)temp; +} + +static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int usec) +{ + u64 temp; + u32 val; + + temp = (u64)usec * mp->shared->t_clk; + temp += 31999999; + do_div(temp, 64000000); + + val = rdlp(mp, SDMA_CONFIG); + if (mp->shared->extended_rx_coal_limit) { + if (temp > 0xffff) + temp = 0xffff; + val &= ~0x023fff80; + val |= (temp & 0x8000) << 10; + val |= (temp & 0x7fff) << 7; + } else { + if (temp > 0x3fff) + temp = 0x3fff; + val &= ~0x003fff00; + val |= (temp & 0x3fff) << 8; + } + wrlp(mp, SDMA_CONFIG, val); +} + +static unsigned int get_tx_coal(struct mv643xx_eth_private *mp) +{ + u64 temp; + + temp = (rdlp(mp, TX_FIFO_URGENT_THRESHOLD) & 0x3fff0) >> 4; + temp *= 64000000; + do_div(temp, mp->shared->t_clk); + + return (unsigned int)temp; +} + +static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int usec) +{ + u64 temp; + + temp = (u64)usec * mp->shared->t_clk; + temp += 31999999; + do_div(temp, 64000000); + + if (temp > 0x3fff) + temp = 0x3fff; + + wrlp(mp, TX_FIFO_URGENT_THRESHOLD, temp << 4); +} + + /* ethtool ******************************************************************/ struct mv643xx_eth_stats { char stat_string[ETH_GSTRING_LEN]; @@ -1229,6 +1360,10 @@ struct mv643xx_eth_stats { { #m, FIELD_SIZEOF(struct mib_counters, m), \ -1, offsetof(struct mv643xx_eth_private, mib_counters.m) } +#define LROSTAT(m) \ + { #m, FIELD_SIZEOF(struct lro_counters, m), \ + -1, offsetof(struct mv643xx_eth_private, lro_counters.m) } + static const struct mv643xx_eth_stats mv643xx_eth_stats[] = { SSTAT(rx_packets), SSTAT(tx_packets), @@ -1268,12 +1403,15 @@ static const struct mv643xx_eth_stats mv643xx_eth_stats[] = { MIBSTAT(bad_crc_event), MIBSTAT(collision), MIBSTAT(late_collision), + LROSTAT(lro_aggregated), + LROSTAT(lro_flushed), + LROSTAT(lro_no_desc), }; static int -mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +mv643xx_eth_get_settings_phy(struct mv643xx_eth_private *mp, + struct ethtool_cmd *cmd) { - struct mv643xx_eth_private *mp = netdev_priv(dev); int err; err = phy_read_status(mp->phy); @@ -1290,10 +1428,9 @@ mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) } static int -mv643xx_eth_get_settings_phyless(struct net_device *dev, +mv643xx_eth_get_settings_phyless(struct mv643xx_eth_private *mp, struct ethtool_cmd *cmd) { - struct mv643xx_eth_private *mp = netdev_priv(dev); u32 port_status; port_status = rdlp(mp, PORT_STATUS); @@ -1326,10 +1463,24 @@ mv643xx_eth_get_settings_phyless(struct net_device *dev, } static int +mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct mv643xx_eth_private *mp = netdev_priv(dev); + + if (mp->phy != NULL) + return mv643xx_eth_get_settings_phy(mp, cmd); + else + return mv643xx_eth_get_settings_phyless(mp, cmd); +} + +static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct mv643xx_eth_private *mp = netdev_priv(dev); + if (mp->phy == NULL) + return -EINVAL; + /* * The MAC does not support 1000baseT_Half. */ @@ -1338,13 +1489,6 @@ mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return phy_ethtool_sset(mp->phy, cmd); } -static int -mv643xx_eth_set_settings_phyless(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - return -EINVAL; -} - static void mv643xx_eth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { @@ -1359,17 +1503,95 @@ static int mv643xx_eth_nway_reset(struct net_device *dev) { struct mv643xx_eth_private *mp = netdev_priv(dev); + if (mp->phy == NULL) + return -EINVAL; + return genphy_restart_aneg(mp->phy); } -static int mv643xx_eth_nway_reset_phyless(struct net_device *dev) +static u32 mv643xx_eth_get_link(struct net_device *dev) { - return -EINVAL; + return !!netif_carrier_ok(dev); } -static u32 mv643xx_eth_get_link(struct net_device *dev) +static int +mv643xx_eth_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) { - return !!netif_carrier_ok(dev); + struct mv643xx_eth_private *mp = netdev_priv(dev); + + ec->rx_coalesce_usecs = get_rx_coal(mp); + ec->tx_coalesce_usecs = get_tx_coal(mp); + + return 0; +} + +static int +mv643xx_eth_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) +{ + struct mv643xx_eth_private *mp = netdev_priv(dev); + + set_rx_coal(mp, ec->rx_coalesce_usecs); + set_tx_coal(mp, ec->tx_coalesce_usecs); + + return 0; +} + +static void +mv643xx_eth_get_ringparam(struct net_device *dev, struct ethtool_ringparam *er) +{ + struct mv643xx_eth_private *mp = netdev_priv(dev); + + er->rx_max_pending = 4096; + er->tx_max_pending = 4096; + er->rx_mini_max_pending = 0; + er->rx_jumbo_max_pending = 0; + + er->rx_pending = mp->rx_ring_size; + er->tx_pending = mp->tx_ring_size; + er->rx_mini_pending = 0; + er->rx_jumbo_pending = 0; +} + +static int +mv643xx_eth_set_ringparam(struct net_device *dev, struct ethtool_ringparam *er) +{ + struct mv643xx_eth_private *mp = netdev_priv(dev); + + if (er->rx_mini_pending || er->rx_jumbo_pending) + return -EINVAL; + + mp->rx_ring_size = er->rx_pending < 4096 ? er->rx_pending : 4096; + mp->tx_ring_size = er->tx_pending < 4096 ? er->tx_pending : 4096; + + if (netif_running(dev)) { + mv643xx_eth_stop(dev); + if (mv643xx_eth_open(dev)) { + dev_printk(KERN_ERR, &dev->dev, + "fatal error on re-opening device after " + "ring param change\n"); + return -ENOMEM; + } + } + + return 0; +} + +static u32 +mv643xx_eth_get_rx_csum(struct net_device *dev) +{ + struct mv643xx_eth_private *mp = netdev_priv(dev); + + return !!(rdlp(mp, PORT_CONFIG) & 0x02000000); +} + +static int +mv643xx_eth_set_rx_csum(struct net_device *dev, u32 rx_csum) +{ + struct mv643xx_eth_private *mp = netdev_priv(dev); + + wrlp(mp, PORT_CONFIG, rx_csum ? 0x02000000 : 0x00000000); + + return 0; } static void mv643xx_eth_get_strings(struct net_device *dev, @@ -1395,6 +1617,7 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *dev, mv643xx_eth_get_stats(dev); mib_counters_update(mp); + mv643xx_eth_grab_lro_stats(mp); for (i = 0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) { const struct mv643xx_eth_stats *stat; @@ -1426,21 +1649,18 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { .get_drvinfo = mv643xx_eth_get_drvinfo, .nway_reset = mv643xx_eth_nway_reset, .get_link = mv643xx_eth_get_link, + .get_coalesce = mv643xx_eth_get_coalesce, + .set_coalesce = mv643xx_eth_set_coalesce, + .get_ringparam = mv643xx_eth_get_ringparam, + .set_ringparam = mv643xx_eth_set_ringparam, + .get_rx_csum = mv643xx_eth_get_rx_csum, + .set_rx_csum = mv643xx_eth_set_rx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, .set_sg = ethtool_op_set_sg, .get_strings = mv643xx_eth_get_strings, .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, - .get_sset_count = mv643xx_eth_get_sset_count, -}; - -static const struct ethtool_ops mv643xx_eth_ethtool_ops_phyless = { - .get_settings = mv643xx_eth_get_settings_phyless, - .set_settings = mv643xx_eth_set_settings_phyless, - .get_drvinfo = mv643xx_eth_get_drvinfo, - .nway_reset = mv643xx_eth_nway_reset_phyless, - .get_link = mv643xx_eth_get_link, - .set_sg = ethtool_op_set_sg, - .get_strings = mv643xx_eth_get_strings, - .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags, .get_sset_count = mv643xx_eth_get_sset_count, }; @@ -1468,20 +1688,20 @@ static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr) static u32 uc_addr_filter_mask(struct net_device *dev) { - struct dev_addr_list *uc_ptr; + struct netdev_hw_addr *ha; u32 nibbles; if (dev->flags & IFF_PROMISC) return 0; nibbles = 1 << (dev->dev_addr[5] & 0x0f); - for (uc_ptr = dev->uc_list; uc_ptr != NULL; uc_ptr = uc_ptr->next) { - if (memcmp(dev->dev_addr, uc_ptr->da_addr, 5)) + list_for_each_entry(ha, &dev->uc.list, list) { + if (memcmp(dev->dev_addr, ha->addr, 5)) return 0; - if ((dev->dev_addr[5] ^ uc_ptr->da_addr[5]) & 0xf0) + if ((dev->dev_addr[5] ^ ha->addr[5]) & 0xf0) return 0; - nibbles |= 1 << (uc_ptr->da_addr[5] & 0x0f); + nibbles |= 1 << (ha->addr[5] & 0x0f); } return nibbles; @@ -1496,12 +1716,12 @@ static void mv643xx_eth_program_unicast_filter(struct net_device *dev) uc_addr_set(mp, dev->dev_addr); - port_config = rdlp(mp, PORT_CONFIG); + port_config = rdlp(mp, PORT_CONFIG) & ~UNICAST_PROMISCUOUS_MODE; + nibbles = uc_addr_filter_mask(dev); if (!nibbles) { port_config |= UNICAST_PROMISCUOUS_MODE; - wrlp(mp, PORT_CONFIG, port_config); - return; + nibbles = 0xffff; } for (i = 0; i < 16; i += 4) { @@ -1522,7 +1742,6 @@ static void mv643xx_eth_program_unicast_filter(struct net_device *dev) wrl(mp, off, v); } - port_config &= ~UNICAST_PROMISCUOUS_MODE; wrlp(mp, PORT_CONFIG, port_config); } @@ -1555,7 +1774,6 @@ static void mv643xx_eth_program_multicast_filter(struct net_device *dev) if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { int port_num; u32 accept; - int i; oom: port_num = mp->port_num; @@ -1567,7 +1785,7 @@ oom: return; } - mc_spec = kmalloc(0x200, GFP_KERNEL); + mc_spec = kmalloc(0x200, GFP_ATOMIC); if (mc_spec == NULL) goto oom; mc_other = mc_spec + (0x100 >> 2); @@ -1588,7 +1806,7 @@ oom: entry = addr_crc(a); } - table[entry >> 2] |= 1 << (entry & 3); + table[entry >> 2] |= 1 << (8 * (entry & 3)); } for (i = 0; i < 0x100; i += 4) { @@ -1629,7 +1847,7 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index) rxq->index = index; - rxq->rx_ring_size = mp->default_rx_ring_size; + rxq->rx_ring_size = mp->rx_ring_size; rxq->rx_desc_count = 0; rxq->rx_curr_desc = 0; @@ -1642,9 +1860,9 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index) mp->rx_desc_sram_size); rxq->rx_desc_dma = mp->rx_desc_sram_addr; } else { - rxq->rx_desc_area = dma_alloc_coherent(NULL, size, - &rxq->rx_desc_dma, - GFP_KERNEL); + rxq->rx_desc_area = dma_alloc_coherent(mp->dev->dev.parent, + size, &rxq->rx_desc_dma, + GFP_KERNEL); } if (rxq->rx_desc_area == NULL) { @@ -1675,6 +1893,19 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index) nexti * sizeof(struct rx_desc); } + rxq->lro_mgr.dev = mp->dev; + memset(&rxq->lro_mgr.stats, 0, sizeof(rxq->lro_mgr.stats)); + rxq->lro_mgr.features = LRO_F_NAPI; + rxq->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; + rxq->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; + rxq->lro_mgr.max_desc = ARRAY_SIZE(rxq->lro_arr); + rxq->lro_mgr.max_aggr = 32; + rxq->lro_mgr.frag_align_pad = 0; + rxq->lro_mgr.lro_arr = rxq->lro_arr; + rxq->lro_mgr.get_skb_header = mv643xx_get_skb_header; + + memset(&rxq->lro_arr, 0, sizeof(rxq->lro_arr)); + return 0; @@ -1682,7 +1913,7 @@ out_free: if (index == 0 && size <= mp->rx_desc_sram_size) iounmap(rxq->rx_desc_area); else - dma_free_coherent(NULL, size, + dma_free_coherent(mp->dev->dev.parent, size, rxq->rx_desc_area, rxq->rx_desc_dma); @@ -1714,7 +1945,7 @@ static void rxq_deinit(struct rx_queue *rxq) rxq->rx_desc_area_size <= mp->rx_desc_sram_size) iounmap(rxq->rx_desc_area); else - dma_free_coherent(NULL, rxq->rx_desc_area_size, + dma_free_coherent(mp->dev->dev.parent, rxq->rx_desc_area_size, rxq->rx_desc_area, rxq->rx_desc_dma); kfree(rxq->rx_skb); @@ -1729,7 +1960,7 @@ static int txq_init(struct mv643xx_eth_private *mp, int index) txq->index = index; - txq->tx_ring_size = mp->default_tx_ring_size; + txq->tx_ring_size = mp->tx_ring_size; txq->tx_desc_count = 0; txq->tx_curr_desc = 0; @@ -1742,9 +1973,9 @@ static int txq_init(struct mv643xx_eth_private *mp, int index) mp->tx_desc_sram_size); txq->tx_desc_dma = mp->tx_desc_sram_addr; } else { - txq->tx_desc_area = dma_alloc_coherent(NULL, size, - &txq->tx_desc_dma, - GFP_KERNEL); + txq->tx_desc_area = dma_alloc_coherent(mp->dev->dev.parent, + size, &txq->tx_desc_dma, + GFP_KERNEL); } if (txq->tx_desc_area == NULL) { @@ -1788,7 +2019,7 @@ static void txq_deinit(struct tx_queue *txq) txq->tx_desc_area_size <= mp->tx_desc_sram_size) iounmap(txq->tx_desc_area); else - dma_free_coherent(NULL, txq->tx_desc_area_size, + dma_free_coherent(mp->dev->dev.parent, txq->tx_desc_area_size, txq->tx_desc_area, txq->tx_desc_dma); } @@ -1799,15 +2030,16 @@ static int mv643xx_eth_collect_events(struct mv643xx_eth_private *mp) u32 int_cause; u32 int_cause_ext; - int_cause = rdlp(mp, INT_CAUSE) & (INT_TX_END | INT_RX | INT_EXT); + int_cause = rdlp(mp, INT_CAUSE) & mp->int_mask; if (int_cause == 0) return 0; int_cause_ext = 0; - if (int_cause & INT_EXT) + if (int_cause & INT_EXT) { + int_cause &= ~INT_EXT; int_cause_ext = rdlp(mp, INT_CAUSE_EXT); + } - int_cause &= INT_TX_END | INT_RX; if (int_cause) { wrlp(mp, INT_CAUSE, ~int_cause); mp->work_tx_end |= ((int_cause & INT_TX_END) >> 19) & @@ -1900,8 +2132,10 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget) mp = container_of(napi, struct mv643xx_eth_private, napi); - mp->work_rx_refill |= mp->work_rx_oom; - mp->work_rx_oom = 0; + if (unlikely(mp->oom)) { + mp->oom = 0; + del_timer(&mp->rx_oom); + } work_done = 0; while (work_done < budget) { @@ -1912,11 +2146,14 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget) if (mp->work_link) { mp->work_link = 0; handle_link_event(mp); + work_done++; continue; } - queue_mask = mp->work_tx | mp->work_tx_end | - mp->work_rx | mp->work_rx_refill; + queue_mask = mp->work_tx | mp->work_tx_end | mp->work_rx; + if (likely(!mp->oom)) + queue_mask |= mp->work_rx_refill; + if (!queue_mask) { if (mv643xx_eth_collect_events(mp)) continue; @@ -1937,7 +2174,7 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget) txq_maybe_wake(mp->txq + queue); } else if (mp->work_rx & queue_mask) { work_done += rxq_process(mp->rxq + queue, work_tbd); - } else if (mp->work_rx_refill & queue_mask) { + } else if (!mp->oom && (mp->work_rx_refill & queue_mask)) { work_done += rxq_refill(mp->rxq + queue, work_tbd); } else { BUG(); @@ -1945,10 +2182,10 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget) } if (work_done < budget) { - if (mp->work_rx_oom) + if (mp->oom) mod_timer(&mp->rx_oom, jiffies + (HZ / 10)); napi_complete(napi); - wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, mp->int_mask); } return work_done; @@ -2007,8 +2244,6 @@ static void port_start(struct mv643xx_eth_private *mp) pscr |= FORCE_LINK_PASS; wrlp(mp, PORT_SERIAL_CONTROL, pscr); - wrlp(mp, SDMA_CONFIG, PORT_SDMA_CONFIG_DEFAULT_VALUE); - /* * Configure TX path and queues. */ @@ -2022,11 +2257,6 @@ static void port_start(struct mv643xx_eth_private *mp) } /* - * Add configured unicast address to address filter table. - */ - mv643xx_eth_program_unicast_filter(mp->dev); - - /* * Receive all unmatched unicast, TCP, UDP, BPDU and broadcast * frames to RX queue #0, and include the pseudo-header when * calculating receive checksums. @@ -2039,6 +2269,11 @@ static void port_start(struct mv643xx_eth_private *mp) wrlp(mp, PORT_CONFIG_EXT, 0x00000000); /* + * Add configured unicast addresses to address filter table. + */ + mv643xx_eth_program_unicast_filter(mp->dev); + + /* * Enable the receive queues. */ for (i = 0; i < mp->rxq_count; i++) { @@ -2053,36 +2288,6 @@ static void port_start(struct mv643xx_eth_private *mp) } } -static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int delay) -{ - unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; - u32 val; - - val = rdlp(mp, SDMA_CONFIG); - if (mp->shared->extended_rx_coal_limit) { - if (coal > 0xffff) - coal = 0xffff; - val &= ~0x023fff80; - val |= (coal & 0x8000) << 10; - val |= (coal & 0x7fff) << 7; - } else { - if (coal > 0x3fff) - coal = 0x3fff; - val &= ~0x003fff00; - val |= (coal & 0x3fff) << 8; - } - wrlp(mp, SDMA_CONFIG, val); -} - -static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int delay) -{ - unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; - - if (coal > 0x3fff) - coal = 0x3fff; - wrlp(mp, TX_FIFO_URGENT_THRESHOLD, (coal & 0x3fff) << 4); -} - static void mv643xx_eth_recalc_skb_size(struct mv643xx_eth_private *mp) { int skb_size; @@ -2101,6 +2306,14 @@ static void mv643xx_eth_recalc_skb_size(struct mv643xx_eth_private *mp) * size field are ignored by the hardware. */ mp->skb_size = (skb_size + 7) & ~7; + + /* + * If NET_SKB_PAD is smaller than a cache line, + * netdev_alloc_skb() will cause skb->data to be misaligned + * to a cache line boundary. If this is the case, include + * some extra space to allow re-aligning the data area. + */ + mp->skb_size += SKB_DMA_REALIGN; } static int mv643xx_eth_open(struct net_device *dev) @@ -2126,6 +2339,8 @@ static int mv643xx_eth_open(struct net_device *dev) skb_queue_head_init(&mp->rx_recycle); + mp->int_mask = INT_EXT; + for (i = 0; i < mp->rxq_count; i++) { err = rxq_init(mp, i); if (err) { @@ -2135,9 +2350,10 @@ static int mv643xx_eth_open(struct net_device *dev) } rxq_refill(mp->rxq + i, INT_MAX); + mp->int_mask |= INT_RX_0 << i; } - if (mp->work_rx_oom) { + if (mp->oom) { mp->rx_oom.expires = jiffies + (HZ / 10); add_timer(&mp->rx_oom); } @@ -2149,17 +2365,13 @@ static int mv643xx_eth_open(struct net_device *dev) txq_deinit(mp->txq + i); goto out_free; } + mp->int_mask |= INT_TX_END_0 << i; } - netif_carrier_off(dev); - port_start(mp); - set_rx_coal(mp, 0); - set_tx_coal(mp, 0); - wrlp(mp, INT_MASK_EXT, INT_EXT_LINK_PHY | INT_EXT_TX); - wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, mp->int_mask); return 0; @@ -2204,11 +2416,10 @@ static int mv643xx_eth_stop(struct net_device *dev) struct mv643xx_eth_private *mp = netdev_priv(dev); int i; + wrlp(mp, INT_MASK_EXT, 0x00000000); wrlp(mp, INT_MASK, 0x00000000); rdlp(mp, INT_MASK); - del_timer_sync(&mp->mib_counters_timer); - napi_disable(&mp->napi); del_timer_sync(&mp->rx_oom); @@ -2220,6 +2431,7 @@ static int mv643xx_eth_stop(struct net_device *dev) port_reset(mp); mv643xx_eth_get_stats(dev); mib_counters_update(mp); + del_timer_sync(&mp->mib_counters_timer); skb_queue_purge(&mp->rx_recycle); @@ -2303,7 +2515,7 @@ static void mv643xx_eth_netpoll(struct net_device *dev) mv643xx_eth_irq(dev->irq, dev); - wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, mp->int_mask); } #endif @@ -2473,8 +2685,8 @@ static int mv643xx_eth_shared_remove(struct platform_device *pdev) struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data; if (pd == NULL || pd->shared_smi == NULL) { - mdiobus_free(msp->smi_bus); mdiobus_unregister(msp->smi_bus); + mdiobus_free(msp->smi_bus); } if (msp->err_interrupt != NO_IRQ) free_irq(msp->err_interrupt, msp); @@ -2523,17 +2735,17 @@ static void set_params(struct mv643xx_eth_private *mp, else uc_addr_get(mp, dev->dev_addr); - mp->default_rx_ring_size = DEFAULT_RX_QUEUE_SIZE; + mp->rx_ring_size = DEFAULT_RX_QUEUE_SIZE; if (pd->rx_queue_size) - mp->default_rx_ring_size = pd->rx_queue_size; + mp->rx_ring_size = pd->rx_queue_size; mp->rx_desc_sram_addr = pd->rx_sram_addr; mp->rx_desc_sram_size = pd->rx_sram_size; mp->rxq_count = pd->rx_queue_count ? : 1; - mp->default_tx_ring_size = DEFAULT_TX_QUEUE_SIZE; + mp->tx_ring_size = DEFAULT_TX_QUEUE_SIZE; if (pd->tx_queue_size) - mp->default_tx_ring_size = pd->tx_queue_size; + mp->tx_ring_size = pd->tx_queue_size; mp->tx_desc_sram_addr = pd->tx_sram_addr; mp->tx_desc_sram_size = pd->tx_sram_size; @@ -2580,7 +2792,7 @@ static void phy_init(struct mv643xx_eth_private *mp, int speed, int duplex) phy_reset(mp); - phy_attach(mp->dev, phy->dev.bus_id, 0, PHY_INTERFACE_MODE_GMII); + phy_attach(mp->dev, dev_name(&phy->dev), 0, PHY_INTERFACE_MODE_GMII); if (speed == 0) { phy->autoneg = AUTONEG_ENABLE; @@ -2624,6 +2836,21 @@ static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex) wrlp(mp, PORT_SERIAL_CONTROL, pscr); } +static const struct net_device_ops mv643xx_eth_netdev_ops = { + .ndo_open = mv643xx_eth_open, + .ndo_stop = mv643xx_eth_stop, + .ndo_start_xmit = mv643xx_eth_xmit, + .ndo_set_rx_mode = mv643xx_eth_set_rx_mode, + .ndo_set_mac_address = mv643xx_eth_set_mac_address, + .ndo_do_ioctl = mv643xx_eth_ioctl, + .ndo_change_mtu = mv643xx_eth_change_mtu, + .ndo_tx_timeout = mv643xx_eth_tx_timeout, + .ndo_get_stats = mv643xx_eth_get_stats, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = mv643xx_eth_netpoll, +#endif +}; + static int mv643xx_eth_probe(struct platform_device *pdev) { struct mv643xx_eth_platform_data *pd; @@ -2664,12 +2891,10 @@ static int mv643xx_eth_probe(struct platform_device *pdev) if (pd->phy_addr != MV643XX_ETH_PHY_NONE) mp->phy = phy_scan(mp, pd->phy_addr); - if (mp->phy != NULL) { + if (mp->phy != NULL) phy_init(mp, pd->speed, pd->duplex); - SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops); - } else { - SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops_phyless); - } + + SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops); init_pscr(mp, pd->speed, pd->duplex); @@ -2697,18 +2922,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev) BUG_ON(!res); dev->irq = res->start; - dev->get_stats = mv643xx_eth_get_stats; - dev->hard_start_xmit = mv643xx_eth_xmit; - dev->open = mv643xx_eth_open; - dev->stop = mv643xx_eth_stop; - dev->set_rx_mode = mv643xx_eth_set_rx_mode; - dev->set_mac_address = mv643xx_eth_set_mac_address; - dev->do_ioctl = mv643xx_eth_ioctl; - dev->change_mtu = mv643xx_eth_change_mtu; - dev->tx_timeout = mv643xx_eth_tx_timeout; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = mv643xx_eth_netpoll; -#endif + dev->netdev_ops = &mv643xx_eth_netdev_ops; + dev->watchdog_timeo = 2 * HZ; dev->base_addr = 0; @@ -2720,6 +2935,13 @@ static int mv643xx_eth_probe(struct platform_device *pdev) if (mp->shared->win_protect) wrl(mp, WINDOW_PROTECT(mp->port_num), mp->shared->win_protect); + netif_carrier_off(dev); + + wrlp(mp, SDMA_CONFIG, PORT_SDMA_CONFIG_DEFAULT_VALUE); + + set_rx_coal(mp, 250); + set_tx_coal(mp, 0); + err = register_netdev(dev); if (err) goto out;