aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/myri10ge
diff options
context:
space:
mode:
authorBrice Goglin <brice@myri.com>2007-10-13 06:34:01 -0400
committerJeff Garzik <jeff@garzik.org>2007-10-15 14:24:07 -0400
commit4f93fde06b0623319bc1cd6c9adad8d730813433 (patch)
tree5e80f5b57da6a0b9003b1d4ce73ab1c81e705839 /drivers/net/myri10ge
parenteabd7e35c0061dc250fcb8b77c472cb66d770774 (diff)
myri10ge: add IPv6 TSO support
Add support for IPv6 TSO to the myri10ge driver. Signed-off-by: Brice Goglin <brice@myri.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/myri10ge')
-rw-r--r--drivers/net/myri10ge/myri10ge.c87
1 files changed, 79 insertions, 8 deletions
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 5c103128e248..6d5af080d7d5 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -214,6 +214,8 @@ struct myri10ge_priv {
214 unsigned long serial_number; 214 unsigned long serial_number;
215 int vendor_specific_offset; 215 int vendor_specific_offset;
216 int fw_multicast_support; 216 int fw_multicast_support;
217 unsigned long features;
218 u32 max_tso6;
217 u32 read_dma; 219 u32 read_dma;
218 u32 write_dma; 220 u32 write_dma;
219 u32 read_write_dma; 221 u32 read_write_dma;
@@ -311,6 +313,7 @@ MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n");
311#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8) 313#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
312 314
313static void myri10ge_set_multicast_list(struct net_device *dev); 315static void myri10ge_set_multicast_list(struct net_device *dev);
316static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev);
314 317
315static inline void put_be32(__be32 val, __be32 __iomem * p) 318static inline void put_be32(__be32 val, __be32 __iomem * p)
316{ 319{
@@ -612,6 +615,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
612 __be32 buf[16]; 615 __be32 buf[16];
613 u32 dma_low, dma_high, size; 616 u32 dma_low, dma_high, size;
614 int status, i; 617 int status, i;
618 struct myri10ge_cmd cmd;
615 619
616 size = 0; 620 size = 0;
617 status = myri10ge_load_hotplug_firmware(mgp, &size); 621 status = myri10ge_load_hotplug_firmware(mgp, &size);
@@ -688,6 +692,14 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
688 dev_info(&mgp->pdev->dev, "handoff confirmed\n"); 692 dev_info(&mgp->pdev->dev, "handoff confirmed\n");
689 myri10ge_dummy_rdma(mgp, 1); 693 myri10ge_dummy_rdma(mgp, 1);
690 694
695 /* probe for IPv6 TSO support */
696 mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
697 status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
698 &cmd, 0);
699 if (status == 0) {
700 mgp->max_tso6 = cmd.data0;
701 mgp->features |= NETIF_F_TSO6;
702 }
691 return 0; 703 return 0;
692} 704}
693 705
@@ -1384,6 +1396,18 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
1384 return 0; 1396 return 0;
1385} 1397}
1386 1398
1399static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled)
1400{
1401 struct myri10ge_priv *mgp = netdev_priv(netdev);
1402 unsigned long flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO);
1403
1404 if (tso_enabled)
1405 netdev->features |= flags;
1406 else
1407 netdev->features &= ~flags;
1408 return 0;
1409}
1410
1387static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = { 1411static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
1388 "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", 1412 "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
1389 "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", 1413 "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
@@ -1508,7 +1532,7 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
1508 .set_rx_csum = myri10ge_set_rx_csum, 1532 .set_rx_csum = myri10ge_set_rx_csum,
1509 .set_tx_csum = ethtool_op_set_tx_hw_csum, 1533 .set_tx_csum = ethtool_op_set_tx_hw_csum,
1510 .set_sg = ethtool_op_set_sg, 1534 .set_sg = ethtool_op_set_sg,
1511 .set_tso = ethtool_op_set_tso, 1535 .set_tso = myri10ge_set_tso,
1512 .get_link = ethtool_op_get_link, 1536 .get_link = ethtool_op_get_link,
1513 .get_strings = myri10ge_get_strings, 1537 .get_strings = myri10ge_get_strings,
1514 .get_sset_count = myri10ge_get_sset_count, 1538 .get_sset_count = myri10ge_get_sset_count,
@@ -2166,7 +2190,8 @@ again:
2166 pseudo_hdr_offset = cksum_offset + skb->csum_offset; 2190 pseudo_hdr_offset = cksum_offset + skb->csum_offset;
2167 /* If the headers are excessively large, then we must 2191 /* If the headers are excessively large, then we must
2168 * fall back to a software checksum */ 2192 * fall back to a software checksum */
2169 if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) { 2193 if (unlikely(!mss && (cksum_offset > 255 ||
2194 pseudo_hdr_offset > 127))) {
2170 if (skb_checksum_help(skb)) 2195 if (skb_checksum_help(skb))
2171 goto drop; 2196 goto drop;
2172 cksum_offset = 0; 2197 cksum_offset = 0;
@@ -2186,9 +2211,18 @@ again:
2186 /* negative cum_len signifies to the 2211 /* negative cum_len signifies to the
2187 * send loop that we are still in the 2212 * send loop that we are still in the
2188 * header portion of the TSO packet. 2213 * header portion of the TSO packet.
2189 * TSO header must be at most 134 bytes long */ 2214 * TSO header can be at most 1KB long */
2190 cum_len = -(skb_transport_offset(skb) + tcp_hdrlen(skb)); 2215 cum_len = -(skb_transport_offset(skb) + tcp_hdrlen(skb));
2191 2216
2217 /* for IPv6 TSO, the checksum offset stores the
2218 * TCP header length, to save the firmware from
2219 * the need to parse the headers */
2220 if (skb_is_gso_v6(skb)) {
2221 cksum_offset = tcp_hdrlen(skb);
2222 /* Can only handle headers <= max_tso6 long */
2223 if (unlikely(-cum_len > mgp->max_tso6))
2224 return myri10ge_sw_tso(skb, dev);
2225 }
2192 /* for TSO, pseudo_hdr_offset holds mss. 2226 /* for TSO, pseudo_hdr_offset holds mss.
2193 * The firmware figures out where to put 2227 * The firmware figures out where to put
2194 * the checksum by parsing the header. */ 2228 * the checksum by parsing the header. */
@@ -2303,10 +2337,12 @@ again:
2303 req++; 2337 req++;
2304 count++; 2338 count++;
2305 rdma_count++; 2339 rdma_count++;
2306 if (unlikely(cksum_offset > seglen)) 2340 if (cksum_offset != 0 && !(mss && skb_is_gso_v6(skb))) {
2307 cksum_offset -= seglen; 2341 if (unlikely(cksum_offset > seglen))
2308 else 2342 cksum_offset -= seglen;
2309 cksum_offset = 0; 2343 else
2344 cksum_offset = 0;
2345 }
2310 } 2346 }
2311 if (frag_idx == frag_cnt) 2347 if (frag_idx == frag_cnt)
2312 break; 2348 break;
@@ -2389,6 +2425,41 @@ drop:
2389 2425
2390} 2426}
2391 2427
2428static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev)
2429{
2430 struct sk_buff *segs, *curr;
2431 struct myri10ge_priv *mgp = dev->priv;
2432 int status;
2433
2434 segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6);
2435 if (unlikely(IS_ERR(segs)))
2436 goto drop;
2437
2438 while (segs) {
2439 curr = segs;
2440 segs = segs->next;
2441 curr->next = NULL;
2442 status = myri10ge_xmit(curr, dev);
2443 if (status != 0) {
2444 dev_kfree_skb_any(curr);
2445 if (segs != NULL) {
2446 curr = segs;
2447 segs = segs->next;
2448 curr->next = NULL;
2449 dev_kfree_skb_any(segs);
2450 }
2451 goto drop;
2452 }
2453 }
2454 dev_kfree_skb_any(skb);
2455 return 0;
2456
2457drop:
2458 dev_kfree_skb_any(skb);
2459 mgp->stats.tx_dropped += 1;
2460 return 0;
2461}
2462
2392static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) 2463static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
2393{ 2464{
2394 struct myri10ge_priv *mgp = netdev_priv(dev); 2465 struct myri10ge_priv *mgp = netdev_priv(dev);
@@ -3076,7 +3147,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
3076 netdev->change_mtu = myri10ge_change_mtu; 3147 netdev->change_mtu = myri10ge_change_mtu;
3077 netdev->set_multicast_list = myri10ge_set_multicast_list; 3148 netdev->set_multicast_list = myri10ge_set_multicast_list;
3078 netdev->set_mac_address = myri10ge_set_mac_address; 3149 netdev->set_mac_address = myri10ge_set_mac_address;
3079 netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO; 3150 netdev->features = mgp->features;
3080 if (dac_enabled) 3151 if (dac_enabled)
3081 netdev->features |= NETIF_F_HIGHDMA; 3152 netdev->features |= NETIF_F_HIGHDMA;
3082 3153