diff options
author | hayeswang <hayeswang@realtek.com> | 2014-03-06 22:04:39 -0500 |
---|---|---|
committer | Vladislav Zhurba <vzhurba@nvidia.com> | 2018-02-01 16:58:00 -0500 |
commit | 871e3a05e91237501cfc91af7d24c17ab363c740 (patch) | |
tree | 81b2041a5d04c7c066bcb8e920064b81cbf9d81e /drivers/net/usb/r8152_shield.c | |
parent | 2fdab93e71896e888891e87efc2048c7adda74ec (diff) |
r8152: support TSO
Support scatter gather and TSO.
Adjust the tx checksum function and set the max gso size to fix the
size of the tx aggregation buffer.
Change-Id: Iff3dde25a2329fb47de6a5b6bfce92f260276992
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Aly Hirani <ahirani@nvidia.com>
Reviewed-on: http://git-master/r/390297
(cherry picked from commit 5af199861e22e25c0454676b992298ddfe4d6111)
Reviewed-on: http://git-master/r/396899
Reviewed-by: Preetham Chandru <pchandru@nvidia.com>
Tested-by: Preetham Chandru <pchandru@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Diffstat (limited to 'drivers/net/usb/r8152_shield.c')
-rw-r--r-- | drivers/net/usb/r8152_shield.c | 117 |
1 files changed, 87 insertions, 30 deletions
diff --git a/drivers/net/usb/r8152_shield.c b/drivers/net/usb/r8152_shield.c index 571a2af3c..6d86f5943 100644 --- a/drivers/net/usb/r8152_shield.c +++ b/drivers/net/usb/r8152_shield.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/ipv6.h> | 24 | #include <linux/ipv6.h> |
25 | 25 | ||
26 | /* Version Information */ | 26 | /* Version Information */ |
27 | #define DRIVER_VERSION "v1.05.0 (2014/02/18)" | 27 | #define DRIVER_VERSION "v1.06.0 (2014/03/03)" |
28 | #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" | 28 | #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" |
29 | #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" | 29 | #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" |
30 | #define MODULENAME "r8152" | 30 | #define MODULENAME "r8152" |
@@ -485,13 +485,18 @@ struct tx_desc { | |||
485 | __le32 opts1; | 485 | __le32 opts1; |
486 | #define TX_FS (1 << 31) /* First segment of a packet */ | 486 | #define TX_FS (1 << 31) /* First segment of a packet */ |
487 | #define TX_LS (1 << 30) /* Final segment of a packet */ | 487 | #define TX_LS (1 << 30) /* Final segment of a packet */ |
488 | #define TX_LEN_MASK 0x3ffff | 488 | #define GTSENDV4 (1 << 28) |
489 | #define GTTCPHO_SHIFT 18 | ||
490 | #define TX_LEN_MAX 0x3ffffU | ||
489 | 491 | ||
490 | __le32 opts2; | 492 | __le32 opts2; |
491 | #define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */ | 493 | #define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */ |
492 | #define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */ | 494 | #define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */ |
493 | #define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */ | 495 | #define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */ |
494 | #define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */ | 496 | #define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */ |
497 | #define MSS_SHIFT 17 | ||
498 | #define MSS_MAX 0x7ffU | ||
499 | #define TCPHO_SHIFT 17 | ||
495 | }; | 500 | }; |
496 | 501 | ||
497 | struct r8152; | 502 | struct r8152; |
@@ -558,12 +563,21 @@ enum rtl_version { | |||
558 | RTL_VER_MAX | 563 | RTL_VER_MAX |
559 | }; | 564 | }; |
560 | 565 | ||
566 | enum tx_csum_stat { | ||
567 | TX_CSUM_SUCCESS = 0, | ||
568 | TX_CSUM_TSO, | ||
569 | TX_CSUM_NONE | ||
570 | }; | ||
571 | |||
561 | /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). | 572 | /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). |
562 | * The RTL chips use a 64 element hash table based on the Ethernet CRC. | 573 | * The RTL chips use a 64 element hash table based on the Ethernet CRC. |
563 | */ | 574 | */ |
564 | static const int multicast_filter_limit = 32; | 575 | static const int multicast_filter_limit = 32; |
565 | static unsigned int rx_buf_sz = 16384; | 576 | static unsigned int rx_buf_sz = 16384; |
566 | 577 | ||
578 | #define RTL_LIMITED_TSO_SIZE (rx_buf_sz - sizeof(struct tx_desc) - \ | ||
579 | VLAN_ETH_HLEN - VLAN_HLEN) | ||
580 | |||
567 | static | 581 | static |
568 | int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) | 582 | int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) |
569 | { | 583 | { |
@@ -1290,24 +1304,46 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp) | |||
1290 | return agg; | 1304 | return agg; |
1291 | } | 1305 | } |
1292 | 1306 | ||
1293 | static void | 1307 | static inline __be16 get_protocol(struct sk_buff *skb) |
1294 | r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb) | ||
1295 | { | 1308 | { |
1296 | memset(desc, 0, sizeof(*desc)); | 1309 | __be16 protocol; |
1297 | 1310 | ||
1298 | desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS | TX_LS); | 1311 | if (skb->protocol == htons(ETH_P_8021Q)) |
1312 | protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; | ||
1313 | else | ||
1314 | protocol = skb->protocol; | ||
1299 | 1315 | ||
1300 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 1316 | return protocol; |
1301 | __be16 protocol; | 1317 | } |
1302 | u8 ip_protocol; | ||
1303 | u32 opts2 = 0; | ||
1304 | 1318 | ||
1305 | if (skb->protocol == htons(ETH_P_8021Q)) | 1319 | static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, |
1306 | protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; | 1320 | struct sk_buff *skb, u32 len, u32 transport_offset) |
1307 | else | 1321 | { |
1308 | protocol = skb->protocol; | 1322 | u32 mss = skb_shinfo(skb)->gso_size; |
1323 | u32 opts1, opts2 = 0; | ||
1324 | int ret = TX_CSUM_SUCCESS; | ||
1325 | |||
1326 | WARN_ON_ONCE(len > TX_LEN_MAX); | ||
1327 | |||
1328 | opts1 = len | TX_FS | TX_LS; | ||
1329 | |||
1330 | if (mss) { | ||
1331 | switch (get_protocol(skb)) { | ||
1332 | case htons(ETH_P_IP): | ||
1333 | opts1 |= GTSENDV4; | ||
1334 | break; | ||
1335 | |||
1336 | default: | ||
1337 | WARN_ON_ONCE(1); | ||
1338 | break; | ||
1339 | } | ||
1340 | |||
1341 | opts1 |= transport_offset << GTTCPHO_SHIFT; | ||
1342 | opts2 |= min(mss, MSS_MAX) << MSS_SHIFT; | ||
1343 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
1344 | u8 ip_protocol; | ||
1309 | 1345 | ||
1310 | switch (protocol) { | 1346 | switch (get_protocol(skb)) { |
1311 | case htons(ETH_P_IP): | 1347 | case htons(ETH_P_IP): |
1312 | opts2 |= IPV4_CS; | 1348 | opts2 |= IPV4_CS; |
1313 | ip_protocol = ip_hdr(skb)->protocol; | 1349 | ip_protocol = ip_hdr(skb)->protocol; |
@@ -1323,17 +1359,20 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb) | |||
1323 | break; | 1359 | break; |
1324 | } | 1360 | } |
1325 | 1361 | ||
1326 | if (ip_protocol == IPPROTO_TCP) { | 1362 | if (ip_protocol == IPPROTO_TCP) |
1327 | opts2 |= TCP_CS; | 1363 | opts2 |= TCP_CS; |
1328 | opts2 |= (skb_transport_offset(skb) & 0x7fff) << 17; | 1364 | else if (ip_protocol == IPPROTO_UDP) |
1329 | } else if (ip_protocol == IPPROTO_UDP) { | ||
1330 | opts2 |= UDP_CS; | 1365 | opts2 |= UDP_CS; |
1331 | } else { | 1366 | else |
1332 | WARN_ON_ONCE(1); | 1367 | WARN_ON_ONCE(1); |
1333 | } | ||
1334 | 1368 | ||
1335 | desc->opts2 = cpu_to_le32(opts2); | 1369 | opts2 |= transport_offset << TCPHO_SHIFT; |
1336 | } | 1370 | } |
1371 | |||
1372 | desc->opts2 = cpu_to_le32(opts2); | ||
1373 | desc->opts1 = cpu_to_le32(opts1); | ||
1374 | |||
1375 | return ret; | ||
1337 | } | 1376 | } |
1338 | 1377 | ||
1339 | static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) | 1378 | static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) |
@@ -1355,29 +1394,44 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) | |||
1355 | struct tx_desc *tx_desc; | 1394 | struct tx_desc *tx_desc; |
1356 | struct sk_buff *skb; | 1395 | struct sk_buff *skb; |
1357 | unsigned int len; | 1396 | unsigned int len; |
1397 | u32 offset; | ||
1358 | 1398 | ||
1359 | skb = __skb_dequeue(&skb_head); | 1399 | skb = __skb_dequeue(&skb_head); |
1360 | if (!skb) | 1400 | if (!skb) |
1361 | break; | 1401 | break; |
1362 | 1402 | ||
1363 | remain -= sizeof(*tx_desc); | 1403 | len = skb->len + sizeof(*tx_desc); |
1364 | len = skb->len; | 1404 | |
1365 | if (remain < len) { | 1405 | if (len > remain) { |
1366 | __skb_queue_head(&skb_head, skb); | 1406 | __skb_queue_head(&skb_head, skb); |
1367 | break; | 1407 | break; |
1368 | } | 1408 | } |
1369 | 1409 | ||
1370 | tx_data = tx_agg_align(tx_data); | 1410 | tx_data = tx_agg_align(tx_data); |
1371 | tx_desc = (struct tx_desc *)tx_data; | 1411 | tx_desc = (struct tx_desc *)tx_data; |
1412 | |||
1413 | offset = (u32)skb_transport_offset(skb); | ||
1414 | |||
1415 | r8152_tx_csum(tp, tx_desc, skb, skb->len, offset); | ||
1416 | |||
1372 | tx_data += sizeof(*tx_desc); | 1417 | tx_data += sizeof(*tx_desc); |
1373 | 1418 | ||
1374 | r8152_tx_csum(tp, tx_desc, skb); | 1419 | len = skb->len; |
1375 | memcpy(tx_data, skb->data, len); | 1420 | if (skb_copy_bits(skb, 0, tx_data, len) < 0) { |
1376 | agg->skb_num++; | 1421 | struct net_device_stats *stats = &tp->netdev->stats; |
1422 | |||
1423 | stats->tx_dropped++; | ||
1424 | dev_kfree_skb_any(skb); | ||
1425 | tx_data -= sizeof(*tx_desc); | ||
1426 | continue; | ||
1427 | } | ||
1428 | |||
1429 | tx_data += len; | ||
1377 | agg->skb_len += len; | 1430 | agg->skb_len += len; |
1431 | agg->skb_num++; | ||
1432 | |||
1378 | dev_kfree_skb_any(skb); | 1433 | dev_kfree_skb_any(skb); |
1379 | 1434 | ||
1380 | tx_data += len; | ||
1381 | remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head); | 1435 | remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head); |
1382 | } | 1436 | } |
1383 | 1437 | ||
@@ -3143,10 +3197,13 @@ static int rtl8152_probe(struct usb_interface *intf, | |||
3143 | netdev->netdev_ops = &rtl8152_netdev_ops; | 3197 | netdev->netdev_ops = &rtl8152_netdev_ops; |
3144 | netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; | 3198 | netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; |
3145 | 3199 | ||
3146 | netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM; | 3200 | netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | |
3147 | netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM; | 3201 | NETIF_F_TSO | NETIF_F_FRAGLIST; |
3202 | netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | | ||
3203 | NETIF_F_TSO | NETIF_F_FRAGLIST; | ||
3148 | 3204 | ||
3149 | SET_ETHTOOL_OPS(netdev, &ops); | 3205 | SET_ETHTOOL_OPS(netdev, &ops); |
3206 | netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE); | ||
3150 | 3207 | ||
3151 | tp->mii.dev = netdev; | 3208 | tp->mii.dev = netdev; |
3152 | tp->mii.mdio_read = read_mii_word; | 3209 | tp->mii.mdio_read = read_mii_word; |