diff options
| -rw-r--r-- | drivers/net/myri10ge/myri10ge.c | 87 |
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 | ||
| 313 | static void myri10ge_set_multicast_list(struct net_device *dev); | 315 | static void myri10ge_set_multicast_list(struct net_device *dev); |
| 316 | static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev); | ||
| 314 | 317 | ||
| 315 | static inline void put_be32(__be32 val, __be32 __iomem * p) | 318 | static 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 | ||
| 1399 | static 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 | |||
| 1387 | static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = { | 1411 | static 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 | ||
| 2428 | static 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 | |||
| 2457 | drop: | ||
| 2458 | dev_kfree_skb_any(skb); | ||
| 2459 | mgp->stats.tx_dropped += 1; | ||
| 2460 | return 0; | ||
| 2461 | } | ||
| 2462 | |||
| 2392 | static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) | 2463 | static 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 | ||
