From db1d7bf70f42124f73675fca62fe32f3ab1111b4 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 26 Jan 2009 21:12:58 -0800 Subject: net: struct device - replace bus_id with dev_name(), dev_set_name() Signed-off-by: Kay Sievers Acked-by: Greg Kroah-Hartman Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 5f31bbb614af..8fab31f631a0 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2589,7 +2589,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; -- cgit v1.2.3-59-g8ed1b From 6bdf576e4b068e86381280c58393cad42ffc8cc8 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 12 Feb 2009 14:06:46 +0000 Subject: mv643xx_eth: unify ethtool ops for phy'd and phy-less interfaces It's a waste having two different versions of this structure around when the differences between ethtool ops for phy'd and phy-less interfaces are so minor. Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 56 +++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 8fab31f631a0..e8fbc0badf7e 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1279,9 +1279,9 @@ static const struct mv643xx_eth_stats mv643xx_eth_stats[] = { }; 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); @@ -1298,10 +1298,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); @@ -1333,11 +1332,25 @@ mv643xx_eth_get_settings_phyless(struct net_device *dev, return 0; } +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. */ @@ -1346,13 +1359,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) { @@ -1367,12 +1373,10 @@ static int mv643xx_eth_nway_reset(struct net_device *dev) { struct mv643xx_eth_private *mp = netdev_priv(dev); - return genphy_restart_aneg(mp->phy); -} + if (mp->phy == NULL) + return -EINVAL; -static int mv643xx_eth_nway_reset_phyless(struct net_device *dev) -{ - return -EINVAL; + return genphy_restart_aneg(mp->phy); } static u32 mv643xx_eth_get_link(struct net_device *dev) @@ -1440,18 +1444,6 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { .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_sset_count = mv643xx_eth_get_sset_count, -}; - /* address handling *********************************************************/ static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) @@ -2673,12 +2665,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); -- cgit v1.2.3-59-g8ed1b From 3e5080344e95c0861a7ca494288593023ee383c6 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 12 Feb 2009 14:07:09 +0000 Subject: mv643xx_eth: rework interrupt coalescing, and export via ethtool This patch: - increases the precision of the receive/transmit interrupt coalescing register value computations by using 64bit temporaries; - adds functions to read the current hardware coalescing register values and convert them back to usecs; - exports the {get,set} {rx,tx} coal methods via the standard ethtool coalescing interface. Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 133 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 30 deletions(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index e8fbc0badf7e..c32d623061d9 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1221,6 +1221,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]; @@ -1384,6 +1463,28 @@ static u32 mv643xx_eth_get_link(struct net_device *dev) return !!netif_carrier_ok(dev); } +static int +mv643xx_eth_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) +{ + 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_strings(struct net_device *dev, uint32_t stringset, uint8_t *data) { @@ -1438,6 +1539,8 @@ 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, .set_sg = ethtool_op_set_sg, .get_strings = mv643xx_eth_get_strings, .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, @@ -2053,36 +2156,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; -- cgit v1.2.3-59-g8ed1b From e7d2f4dbd9224ba50d6d5331bb0538d2ce9027f8 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 12 Feb 2009 14:07:37 +0000 Subject: mv643xx_eth: implement ethtool rx/tx ring size query and resizing Rename the mp->default_[rt]x_ring_size variables to ->[rt]x_ring_size, allow them to be read via the standard ethtool ->get_ringparam() op, and add a ->set_ringparam() op to allow resizing them at run time. Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 63 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 9 deletions(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index c32d623061d9..89eaf3b3c760 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -286,6 +286,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 { @@ -385,7 +388,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; @@ -395,7 +398,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; @@ -907,7 +910,7 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force) 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 + dma_get_cache_alignment() - 1)) __skb_queue_head(&mp->rx_recycle, skb); @@ -1485,6 +1488,46 @@ mv643xx_eth_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) 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 void mv643xx_eth_get_strings(struct net_device *dev, uint32_t stringset, uint8_t *data) { @@ -1541,6 +1584,8 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { .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, .set_sg = ethtool_op_set_sg, .get_strings = mv643xx_eth_get_strings, .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, @@ -1732,7 +1777,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; @@ -1832,7 +1877,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; @@ -2597,17 +2642,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; -- cgit v1.2.3-59-g8ed1b From d888b3738eba7ebc5844d5977c30e290dfbe435b Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 12 Feb 2009 14:07:56 +0000 Subject: mv643xx_eth: export rx csum get/set methods via ethtool Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 89eaf3b3c760..3bbbd9410c9c 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1528,6 +1528,24 @@ mv643xx_eth_set_ringparam(struct net_device *dev, struct ethtool_ringparam *er) 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, uint32_t stringset, uint8_t *data) { @@ -1586,6 +1604,8 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { .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_sg = ethtool_op_set_sg, .get_strings = mv643xx_eth_get_strings, .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, -- cgit v1.2.3-59-g8ed1b From b8df184f88f06f985ae58248305ddc257dc016b8 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 12 Feb 2009 14:08:07 +0000 Subject: mv643xx_eth: allow enabling/disabling tx checksumming via ethtool Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 3bbbd9410c9c..a99e5d3f2e46 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1606,6 +1606,7 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { .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, -- cgit v1.2.3-59-g8ed1b From eaf5d59092dbed853bfab956ce123293832998f5 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 12 Feb 2009 14:08:39 +0000 Subject: mv643xx_eth: implement Large Receive Offload Controlled by a compile-time (Kconfig) option for now, since it isn't a win in all cases. Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/Kconfig | 10 +++++ drivers/net/mv643xx_eth.c | 112 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 121 insertions(+), 1 deletion(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 62bc0223a8ed..3fed3347f4b3 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2318,6 +2318,16 @@ config MV643XX_ETH Some boards that use the Discovery chipset are the Momenco Ocelot C and Jaguar ATX and Pegasos II. +config MV643XX_ETH_LRO + tristate "Marvell 643XX ethernet driver LRO support" + depends on MV643XX_ETH + select INET_LRO + help + Say y here if you want to use Large Receive Offload for the + mv643xx_eth driver. + + If in doubt, say N. + config QLA3XXX tristate "QLogic QLA3XXX Network Driver Support" depends on PCI diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index a99e5d3f2e46..bb9693195242 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -53,6 +53,7 @@ #include #include #include +#include #include static char mv643xx_eth_driver_name[] = "mv643xx_eth"; @@ -227,6 +228,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 @@ -324,6 +331,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; @@ -337,6 +350,11 @@ struct rx_queue { dma_addr_t rx_desc_dma; int rx_desc_area_size; struct sk_buff **rx_skb; + +#ifdef CONFIG_MV643XX_ETH_LRO + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_arr[8]; +#endif }; struct tx_queue { @@ -372,6 +390,8 @@ 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; @@ -496,12 +516,42 @@ static void txq_maybe_wake(struct tx_queue *txq) /* rx napi ******************************************************************/ +#ifdef CONFIG_MV643XX_ETH_LRO +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; +} +#endif + 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; @@ -561,7 +611,15 @@ static int rxq_process(struct rx_queue *rxq, int budget) if (cmd_sts & LAYER_4_CHECKSUM_OK) skb->ip_summed = CHECKSUM_UNNECESSARY; skb->protocol = eth_type_trans(skb, mp->dev); - netif_receive_skb(skb); + +#ifdef CONFIG_MV643XX_ETH_LRO + 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 +#endif + netif_receive_skb(skb); continue; @@ -582,6 +640,11 @@ err: dev_kfree_skb(skb); } +#ifdef CONFIG_MV643XX_ETH_LRO + if (lro_flush_needed) + lro_flush_all(&rxq->lro_mgr); +#endif + if (rx < budget) mp->work_rx &= ~(1 << rxq->index); @@ -1161,6 +1224,28 @@ 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; + +#ifdef CONFIG_MV643XX_ETH_LRO + 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; + } +#endif + + 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); @@ -1319,6 +1404,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), @@ -1358,6 +1447,9 @@ 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 @@ -1569,6 +1661,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; @@ -1610,6 +1703,8 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { .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, }; @@ -1844,6 +1939,21 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index) nexti * sizeof(struct rx_desc); } +#ifdef CONFIG_MV643XX_ETH_LRO + 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)); +#endif + return 0; -- cgit v1.2.3-59-g8ed1b From ab307a3983a7fa28f260f3123293c7b91d5d629e Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 24 Feb 2009 15:41:32 +0000 Subject: mv643xx_eth: make LRO unconditional Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/Kconfig | 11 +---------- drivers/net/mv643xx_eth.c | 12 ------------ 2 files changed, 1 insertion(+), 22 deletions(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 7159a39aa2b9..45403e67e351 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2301,6 +2301,7 @@ config UGETH_TX_ON_DEMAND config MV643XX_ETH tristate "Marvell Discovery (643XX) and Orion ethernet support" depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION + select INET_LRO select PHYLIB help This driver supports the gigabit ethernet MACs in the @@ -2310,16 +2311,6 @@ config MV643XX_ETH Some boards that use the Discovery chipset are the Momenco Ocelot C and Jaguar ATX and Pegasos II. -config MV643XX_ETH_LRO - tristate "Marvell 643XX ethernet driver LRO support" - depends on MV643XX_ETH - select INET_LRO - help - Say y here if you want to use Large Receive Offload for the - mv643xx_eth driver. - - If in doubt, say N. - config QLA3XXX tristate "QLogic QLA3XXX Network Driver Support" depends on PCI diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 56912add8b13..d4d5a5690d89 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -351,10 +351,8 @@ struct rx_queue { int rx_desc_area_size; struct sk_buff **rx_skb; -#ifdef CONFIG_MV643XX_ETH_LRO struct net_lro_mgr lro_mgr; struct net_lro_desc lro_arr[8]; -#endif }; struct tx_queue { @@ -516,7 +514,6 @@ static void txq_maybe_wake(struct tx_queue *txq) /* rx napi ******************************************************************/ -#ifdef CONFIG_MV643XX_ETH_LRO static int mv643xx_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph, u64 *hdr_flags, void *priv) @@ -542,7 +539,6 @@ mv643xx_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph, return 0; } -#endif static int rxq_process(struct rx_queue *rxq, int budget) { @@ -612,13 +608,11 @@ static int rxq_process(struct rx_queue *rxq, int budget) skb->ip_summed = CHECKSUM_UNNECESSARY; skb->protocol = eth_type_trans(skb, mp->dev); -#ifdef CONFIG_MV643XX_ETH_LRO 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 -#endif netif_receive_skb(skb); continue; @@ -640,10 +634,8 @@ err: dev_kfree_skb(skb); } -#ifdef CONFIG_MV643XX_ETH_LRO if (lro_flush_needed) lro_flush_all(&rxq->lro_mgr); -#endif if (rx < budget) mp->work_rx &= ~(1 << rxq->index); @@ -1231,7 +1223,6 @@ static void mv643xx_eth_grab_lro_stats(struct mv643xx_eth_private *mp) u32 lro_no_desc = 0; int i; -#ifdef CONFIG_MV643XX_ETH_LRO for (i = 0; i < mp->rxq_count; i++) { struct rx_queue *rxq = mp->rxq + i; @@ -1239,7 +1230,6 @@ static void mv643xx_eth_grab_lro_stats(struct mv643xx_eth_private *mp) lro_flushed += rxq->lro_mgr.stats.flushed; lro_no_desc += rxq->lro_mgr.stats.no_desc; } -#endif mp->lro_counters.lro_aggregated = lro_aggregated; mp->lro_counters.lro_flushed = lro_flushed; @@ -1939,7 +1929,6 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index) nexti * sizeof(struct rx_desc); } -#ifdef CONFIG_MV643XX_ETH_LRO rxq->lro_mgr.dev = mp->dev; memset(&rxq->lro_mgr.stats, 0, sizeof(rxq->lro_mgr.stats)); rxq->lro_mgr.features = LRO_F_NAPI; @@ -1952,7 +1941,6 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index) rxq->lro_mgr.get_skb_header = mv643xx_get_skb_header; memset(&rxq->lro_arr, 0, sizeof(rxq->lro_arr)); -#endif return 0; -- cgit v1.2.3-59-g8ed1b From ea8a8642636b905c79aed104a0755b3fa2e65e8e Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 24 Feb 2009 15:41:40 +0000 Subject: mv643xx_eth: convert to net_device_ops Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index d4d5a5690d89..7d10897dcc85 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2861,6 +2861,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; @@ -2932,18 +2947,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; -- cgit v1.2.3-59-g8ed1b From a5fe36165339c57b341250e8252d833e91317c70 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 24 Feb 2009 15:41:47 +0000 Subject: mv643xx_eth: move a couple of init actions from ->open() to port probe Move the netif_carrier_off() call in ->open() to port probe, so that ethtool doesn't report the link as being up before we have up'd the interface. Move initialisation of the rx/tx coalescing timers from ->open() to port probe, so that we don't reset the coalescing timers every time the interface is up'd. Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 7d10897dcc85..e1a18e3540ad 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2388,13 +2388,8 @@ static int mv643xx_eth_open(struct net_device *dev) } } - 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); @@ -2960,6 +2955,11 @@ 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); + + set_rx_coal(mp, 0); + set_tx_coal(mp, 0); + err = register_netdev(dev); if (err) goto out; -- cgit v1.2.3-59-g8ed1b From 4fb0a54a55d34c28dc53c39567ce171166572699 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 24 Feb 2009 15:42:05 +0000 Subject: mv643xx_eth: set sane default receive coalescing timeout A receive coalescing timeout of 250 usec appears to strike a good balance between allowing enough received frames to be aggregated for LRO to do its job and not allowing the connection to stall due to delaying ACKs to the remote end for too long. Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index e1a18e3540ad..e1f7706c15cd 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2957,7 +2957,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) netif_carrier_off(dev); - set_rx_coal(mp, 0); + set_rx_coal(mp, 250); set_tx_coal(mp, 0); err = register_netdev(dev); -- cgit v1.2.3-59-g8ed1b