diff options
author | Santiago Leon <santil@linux.vnet.ibm.com> | 2010-09-03 14:28:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-09-06 21:21:48 -0400 |
commit | 6e8ab30ec677925e8999a9f5bdb028736d22d48c (patch) | |
tree | 23738f9382f6d0f1b1cd6dba62394ac53aeeb12e | |
parent | f89e49e79f839dbe79364ec6cd7e2274ad11b120 (diff) |
ibmveth: Add scatter-gather support
ibmveth can scatter gather up to 6 segments. If we go over this then
we have no option but to call skb_linearize, like other drivers with
similar limitations do.
Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Santiago Leon <santil@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ibmveth.c | 184 |
1 files changed, 124 insertions, 60 deletions
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index aedcb1802182..d8a89846c6a8 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c | |||
@@ -897,6 +897,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { | |||
897 | .get_strings = ibmveth_get_strings, | 897 | .get_strings = ibmveth_get_strings, |
898 | .get_sset_count = ibmveth_get_sset_count, | 898 | .get_sset_count = ibmveth_get_sset_count, |
899 | .get_ethtool_stats = ibmveth_get_ethtool_stats, | 899 | .get_ethtool_stats = ibmveth_get_ethtool_stats, |
900 | .set_sg = ethtool_op_set_sg, | ||
900 | }; | 901 | }; |
901 | 902 | ||
902 | static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 903 | static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
@@ -906,96 +907,158 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
906 | 907 | ||
907 | #define page_offset(v) ((unsigned long)(v) & ((1 << 12) - 1)) | 908 | #define page_offset(v) ((unsigned long)(v) & ((1 << 12) - 1)) |
908 | 909 | ||
909 | static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, | 910 | static int ibmveth_send(struct ibmveth_adapter *adapter, |
910 | struct net_device *netdev) | 911 | union ibmveth_buf_desc *descs) |
911 | { | 912 | { |
912 | struct ibmveth_adapter *adapter = netdev_priv(netdev); | ||
913 | union ibmveth_buf_desc desc; | ||
914 | unsigned long lpar_rc; | ||
915 | unsigned long correlator; | 913 | unsigned long correlator; |
916 | unsigned int retry_count; | 914 | unsigned int retry_count; |
917 | unsigned int tx_dropped = 0; | 915 | unsigned long ret; |
918 | unsigned int tx_bytes = 0; | 916 | |
919 | unsigned int tx_packets = 0; | 917 | /* |
920 | unsigned int tx_send_failed = 0; | 918 | * The retry count sets a maximum for the number of broadcast and |
921 | unsigned int tx_map_failed = 0; | 919 | * multicast destinations within the system. |
922 | int used_bounce = 0; | 920 | */ |
923 | unsigned long data_dma_addr; | 921 | retry_count = 1024; |
922 | correlator = 0; | ||
923 | do { | ||
924 | ret = h_send_logical_lan(adapter->vdev->unit_address, | ||
925 | descs[0].desc, descs[1].desc, | ||
926 | descs[2].desc, descs[3].desc, | ||
927 | descs[4].desc, descs[5].desc, | ||
928 | correlator, &correlator); | ||
929 | } while ((ret == H_BUSY) && (retry_count--)); | ||
930 | |||
931 | if (ret != H_SUCCESS && ret != H_DROPPED) { | ||
932 | ibmveth_error_printk("tx: h_send_logical_lan failed with " | ||
933 | "rc=%ld\n", ret); | ||
934 | return 1; | ||
935 | } | ||
936 | |||
937 | return 0; | ||
938 | } | ||
924 | 939 | ||
925 | desc.fields.flags_len = IBMVETH_BUF_VALID | skb->len; | 940 | static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, |
941 | struct net_device *netdev) | ||
942 | { | ||
943 | struct ibmveth_adapter *adapter = netdev_priv(netdev); | ||
944 | unsigned int desc_flags; | ||
945 | union ibmveth_buf_desc descs[6]; | ||
946 | int last, i; | ||
947 | int force_bounce = 0; | ||
948 | |||
949 | /* | ||
950 | * veth handles a maximum of 6 segments including the header, so | ||
951 | * we have to linearize the skb if there are more than this. | ||
952 | */ | ||
953 | if (skb_shinfo(skb)->nr_frags > 5 && __skb_linearize(skb)) { | ||
954 | netdev->stats.tx_dropped++; | ||
955 | goto out; | ||
956 | } | ||
926 | 957 | ||
958 | /* veth can't checksum offload UDP */ | ||
927 | if (skb->ip_summed == CHECKSUM_PARTIAL && | 959 | if (skb->ip_summed == CHECKSUM_PARTIAL && |
928 | ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) { | 960 | ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) { |
929 | ibmveth_error_printk("tx: failed to checksum packet\n"); | 961 | ibmveth_error_printk("tx: failed to checksum packet\n"); |
930 | tx_dropped++; | 962 | netdev->stats.tx_dropped++; |
931 | goto out; | 963 | goto out; |
932 | } | 964 | } |
933 | 965 | ||
966 | desc_flags = IBMVETH_BUF_VALID; | ||
967 | |||
934 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 968 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
935 | unsigned char *buf = skb_transport_header(skb) + skb->csum_offset; | 969 | unsigned char *buf = skb_transport_header(skb) + |
970 | skb->csum_offset; | ||
936 | 971 | ||
937 | desc.fields.flags_len |= (IBMVETH_BUF_NO_CSUM | IBMVETH_BUF_CSUM_GOOD); | 972 | desc_flags |= (IBMVETH_BUF_NO_CSUM | IBMVETH_BUF_CSUM_GOOD); |
938 | 973 | ||
939 | /* Need to zero out the checksum */ | 974 | /* Need to zero out the checksum */ |
940 | buf[0] = 0; | 975 | buf[0] = 0; |
941 | buf[1] = 0; | 976 | buf[1] = 0; |
942 | } | 977 | } |
943 | 978 | ||
944 | if (skb->len < tx_copybreak) { | 979 | retry_bounce: |
945 | used_bounce = 1; | 980 | memset(descs, 0, sizeof(descs)); |
946 | } else { | ||
947 | data_dma_addr = dma_map_single(&adapter->vdev->dev, skb->data, | ||
948 | skb->len, DMA_TO_DEVICE); | ||
949 | if (dma_mapping_error(&adapter->vdev->dev, data_dma_addr)) { | ||
950 | if (!firmware_has_feature(FW_FEATURE_CMO)) | ||
951 | ibmveth_error_printk("tx: unable to map " | ||
952 | "xmit buffer\n"); | ||
953 | tx_map_failed++; | ||
954 | used_bounce = 1; | ||
955 | } | ||
956 | } | ||
957 | 981 | ||
958 | if (used_bounce) { | 982 | /* |
983 | * If a linear packet is below the rx threshold then | ||
984 | * copy it into the static bounce buffer. This avoids the | ||
985 | * cost of a TCE insert and remove. | ||
986 | */ | ||
987 | if (force_bounce || (!skb_is_nonlinear(skb) && | ||
988 | (skb->len < tx_copybreak))) { | ||
959 | skb_copy_from_linear_data(skb, adapter->bounce_buffer, | 989 | skb_copy_from_linear_data(skb, adapter->bounce_buffer, |
960 | skb->len); | 990 | skb->len); |
961 | desc.fields.address = adapter->bounce_buffer_dma; | ||
962 | } else | ||
963 | desc.fields.address = data_dma_addr; | ||
964 | 991 | ||
965 | /* send the frame. Arbitrarily set retrycount to 1024 */ | 992 | descs[0].fields.flags_len = desc_flags | skb->len; |
966 | correlator = 0; | 993 | descs[0].fields.address = adapter->bounce_buffer_dma; |
967 | retry_count = 1024; | 994 | |
968 | do { | 995 | if (ibmveth_send(adapter, descs)) { |
969 | lpar_rc = h_send_logical_lan(adapter->vdev->unit_address, | 996 | adapter->tx_send_failed++; |
970 | desc.desc, 0, 0, 0, 0, 0, | 997 | netdev->stats.tx_dropped++; |
971 | correlator, &correlator); | 998 | } else { |
972 | } while ((lpar_rc == H_BUSY) && (retry_count--)); | 999 | netdev->stats.tx_packets++; |
973 | 1000 | netdev->stats.tx_bytes += skb->len; | |
974 | if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) { | 1001 | } |
975 | ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc); | 1002 | |
976 | ibmveth_error_printk("tx: valid=%d, len=%d, address=0x%08x\n", | 1003 | goto out; |
977 | (desc.fields.flags_len & IBMVETH_BUF_VALID) ? 1 : 0, | 1004 | } |
978 | skb->len, desc.fields.address); | 1005 | |
979 | tx_send_failed++; | 1006 | /* Map the header */ |
980 | tx_dropped++; | 1007 | descs[0].fields.address = dma_map_single(&adapter->vdev->dev, skb->data, |
1008 | skb_headlen(skb), | ||
1009 | DMA_TO_DEVICE); | ||
1010 | if (dma_mapping_error(&adapter->vdev->dev, descs[0].fields.address)) | ||
1011 | goto map_failed; | ||
1012 | |||
1013 | descs[0].fields.flags_len = desc_flags | skb_headlen(skb); | ||
1014 | |||
1015 | /* Map the frags */ | ||
1016 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | ||
1017 | unsigned long dma_addr; | ||
1018 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; | ||
1019 | |||
1020 | dma_addr = dma_map_page(&adapter->vdev->dev, frag->page, | ||
1021 | frag->page_offset, frag->size, | ||
1022 | DMA_TO_DEVICE); | ||
1023 | |||
1024 | if (dma_mapping_error(&adapter->vdev->dev, dma_addr)) | ||
1025 | goto map_failed_frags; | ||
1026 | |||
1027 | descs[i+1].fields.flags_len = desc_flags | frag->size; | ||
1028 | descs[i+1].fields.address = dma_addr; | ||
1029 | } | ||
1030 | |||
1031 | if (ibmveth_send(adapter, descs)) { | ||
1032 | adapter->tx_send_failed++; | ||
1033 | netdev->stats.tx_dropped++; | ||
981 | } else { | 1034 | } else { |
982 | tx_packets++; | 1035 | netdev->stats.tx_packets++; |
983 | tx_bytes += skb->len; | 1036 | netdev->stats.tx_bytes += skb->len; |
984 | } | 1037 | } |
985 | 1038 | ||
986 | if (!used_bounce) | 1039 | for (i = 0; i < skb_shinfo(skb)->nr_frags + 1; i++) |
987 | dma_unmap_single(&adapter->vdev->dev, data_dma_addr, | 1040 | dma_unmap_page(&adapter->vdev->dev, descs[i].fields.address, |
988 | skb->len, DMA_TO_DEVICE); | 1041 | descs[i].fields.flags_len & IBMVETH_BUF_LEN_MASK, |
1042 | DMA_TO_DEVICE); | ||
989 | 1043 | ||
990 | out: | 1044 | out: |
991 | netdev->stats.tx_dropped += tx_dropped; | ||
992 | netdev->stats.tx_bytes += tx_bytes; | ||
993 | netdev->stats.tx_packets += tx_packets; | ||
994 | adapter->tx_send_failed += tx_send_failed; | ||
995 | adapter->tx_map_failed += tx_map_failed; | ||
996 | |||
997 | dev_kfree_skb(skb); | 1045 | dev_kfree_skb(skb); |
998 | return NETDEV_TX_OK; | 1046 | return NETDEV_TX_OK; |
1047 | |||
1048 | map_failed_frags: | ||
1049 | last = i+1; | ||
1050 | for (i = 0; i < last; i++) | ||
1051 | dma_unmap_page(&adapter->vdev->dev, descs[i].fields.address, | ||
1052 | descs[i].fields.flags_len & IBMVETH_BUF_LEN_MASK, | ||
1053 | DMA_TO_DEVICE); | ||
1054 | |||
1055 | map_failed: | ||
1056 | if (!firmware_has_feature(FW_FEATURE_CMO)) | ||
1057 | ibmveth_error_printk("tx: unable to map xmit buffer\n"); | ||
1058 | adapter->tx_map_failed++; | ||
1059 | skb_linearize(skb); | ||
1060 | force_bounce = 1; | ||
1061 | goto retry_bounce; | ||
999 | } | 1062 | } |
1000 | 1063 | ||
1001 | static int ibmveth_poll(struct napi_struct *napi, int budget) | 1064 | static int ibmveth_poll(struct napi_struct *napi, int budget) |
@@ -1316,6 +1379,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ | |||
1316 | netdev->netdev_ops = &ibmveth_netdev_ops; | 1379 | netdev->netdev_ops = &ibmveth_netdev_ops; |
1317 | netdev->ethtool_ops = &netdev_ethtool_ops; | 1380 | netdev->ethtool_ops = &netdev_ethtool_ops; |
1318 | SET_NETDEV_DEV(netdev, &dev->dev); | 1381 | SET_NETDEV_DEV(netdev, &dev->dev); |
1382 | netdev->features |= NETIF_F_SG; | ||
1319 | 1383 | ||
1320 | memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); | 1384 | memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); |
1321 | 1385 | ||