diff options
author | Govindarajulu Varadarajan <_govind@gmx.com> | 2014-09-02 17:47:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-05 15:12:20 -0400 |
commit | a03bb56e67c357980dae886683733dab5583dc14 (patch) | |
tree | 787611409812bc85e37ebdbd09a86aa309b61f7b /drivers/net | |
parent | e020836d953eb1ce5b9221b32f4613646a4d5772 (diff) |
enic: implement rx_copybreak
Calling dma_map_single()/dma_unmap_single() is quite expensive compared
to copying a small packet. So let's copy short frames and keep the buffers
mapped.
Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/cisco/enic/enic.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/cisco/enic/enic_main.c | 50 |
2 files changed, 48 insertions, 3 deletions
diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index 962510f391df..5ba5ad071bb6 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h | |||
@@ -186,6 +186,7 @@ struct enic { | |||
186 | ____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX]; | 186 | ____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX]; |
187 | unsigned int cq_count; | 187 | unsigned int cq_count; |
188 | struct enic_rfs_flw_tbl rfs_h; | 188 | struct enic_rfs_flw_tbl rfs_h; |
189 | u32 rx_copybreak; | ||
189 | }; | 190 | }; |
190 | 191 | ||
191 | static inline struct device *enic_get_dev(struct enic *enic) | 192 | static inline struct device *enic_get_dev(struct enic *enic) |
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index c8832bc1c5f7..929bfe70080a 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c | |||
@@ -66,6 +66,8 @@ | |||
66 | #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN 0x0044 /* enet dynamic vnic */ | 66 | #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN 0x0044 /* enet dynamic vnic */ |
67 | #define PCI_DEVICE_ID_CISCO_VIC_ENET_VF 0x0071 /* enet SRIOV VF */ | 67 | #define PCI_DEVICE_ID_CISCO_VIC_ENET_VF 0x0071 /* enet SRIOV VF */ |
68 | 68 | ||
69 | #define RX_COPYBREAK_DEFAULT 256 | ||
70 | |||
69 | /* Supported devices */ | 71 | /* Supported devices */ |
70 | static const struct pci_device_id enic_id_table[] = { | 72 | static const struct pci_device_id enic_id_table[] = { |
71 | { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, | 73 | { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, |
@@ -924,6 +926,7 @@ static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) | |||
924 | pci_unmap_single(enic->pdev, buf->dma_addr, | 926 | pci_unmap_single(enic->pdev, buf->dma_addr, |
925 | buf->len, PCI_DMA_FROMDEVICE); | 927 | buf->len, PCI_DMA_FROMDEVICE); |
926 | dev_kfree_skb_any(buf->os_buf); | 928 | dev_kfree_skb_any(buf->os_buf); |
929 | buf->os_buf = NULL; | ||
927 | } | 930 | } |
928 | 931 | ||
929 | static int enic_rq_alloc_buf(struct vnic_rq *rq) | 932 | static int enic_rq_alloc_buf(struct vnic_rq *rq) |
@@ -934,7 +937,24 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq) | |||
934 | unsigned int len = netdev->mtu + VLAN_ETH_HLEN; | 937 | unsigned int len = netdev->mtu + VLAN_ETH_HLEN; |
935 | unsigned int os_buf_index = 0; | 938 | unsigned int os_buf_index = 0; |
936 | dma_addr_t dma_addr; | 939 | dma_addr_t dma_addr; |
940 | struct vnic_rq_buf *buf = rq->to_use; | ||
941 | |||
942 | if (buf->os_buf) { | ||
943 | buf = buf->next; | ||
944 | rq->to_use = buf; | ||
945 | rq->ring.desc_avail--; | ||
946 | if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) { | ||
947 | /* Adding write memory barrier prevents compiler and/or | ||
948 | * CPU reordering, thus avoiding descriptor posting | ||
949 | * before descriptor is initialized. Otherwise, hardware | ||
950 | * can read stale descriptor fields. | ||
951 | */ | ||
952 | wmb(); | ||
953 | iowrite32(buf->index, &rq->ctrl->posted_index); | ||
954 | } | ||
937 | 955 | ||
956 | return 0; | ||
957 | } | ||
938 | skb = netdev_alloc_skb_ip_align(netdev, len); | 958 | skb = netdev_alloc_skb_ip_align(netdev, len); |
939 | if (!skb) | 959 | if (!skb) |
940 | return -ENOMEM; | 960 | return -ENOMEM; |
@@ -957,6 +977,25 @@ static void enic_intr_update_pkt_size(struct vnic_rx_bytes_counter *pkt_size, | |||
957 | pkt_size->small_pkt_bytes_cnt += pkt_len; | 977 | pkt_size->small_pkt_bytes_cnt += pkt_len; |
958 | } | 978 | } |
959 | 979 | ||
980 | static bool enic_rxcopybreak(struct net_device *netdev, struct sk_buff **skb, | ||
981 | struct vnic_rq_buf *buf, u16 len) | ||
982 | { | ||
983 | struct enic *enic = netdev_priv(netdev); | ||
984 | struct sk_buff *new_skb; | ||
985 | |||
986 | if (len > enic->rx_copybreak) | ||
987 | return false; | ||
988 | new_skb = netdev_alloc_skb_ip_align(netdev, len); | ||
989 | if (!new_skb) | ||
990 | return false; | ||
991 | pci_dma_sync_single_for_cpu(enic->pdev, buf->dma_addr, len, | ||
992 | DMA_FROM_DEVICE); | ||
993 | memcpy(new_skb->data, (*skb)->data, len); | ||
994 | *skb = new_skb; | ||
995 | |||
996 | return true; | ||
997 | } | ||
998 | |||
960 | static void enic_rq_indicate_buf(struct vnic_rq *rq, | 999 | static void enic_rq_indicate_buf(struct vnic_rq *rq, |
961 | struct cq_desc *cq_desc, struct vnic_rq_buf *buf, | 1000 | struct cq_desc *cq_desc, struct vnic_rq_buf *buf, |
962 | int skipped, void *opaque) | 1001 | int skipped, void *opaque) |
@@ -978,9 +1017,6 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, | |||
978 | return; | 1017 | return; |
979 | 1018 | ||
980 | skb = buf->os_buf; | 1019 | skb = buf->os_buf; |
981 | prefetch(skb->data - NET_IP_ALIGN); | ||
982 | pci_unmap_single(enic->pdev, buf->dma_addr, | ||
983 | buf->len, PCI_DMA_FROMDEVICE); | ||
984 | 1020 | ||
985 | cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc, | 1021 | cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc, |
986 | &type, &color, &q_number, &completed_index, | 1022 | &type, &color, &q_number, &completed_index, |
@@ -1011,6 +1047,13 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, | |||
1011 | /* Good receive | 1047 | /* Good receive |
1012 | */ | 1048 | */ |
1013 | 1049 | ||
1050 | if (!enic_rxcopybreak(netdev, &skb, buf, bytes_written)) { | ||
1051 | buf->os_buf = NULL; | ||
1052 | pci_unmap_single(enic->pdev, buf->dma_addr, buf->len, | ||
1053 | PCI_DMA_FROMDEVICE); | ||
1054 | } | ||
1055 | prefetch(skb->data - NET_IP_ALIGN); | ||
1056 | |||
1014 | skb_put(skb, bytes_written); | 1057 | skb_put(skb, bytes_written); |
1015 | skb->protocol = eth_type_trans(skb, netdev); | 1058 | skb->protocol = eth_type_trans(skb, netdev); |
1016 | skb_record_rx_queue(skb, q_number); | 1059 | skb_record_rx_queue(skb, q_number); |
@@ -2531,6 +2574,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2531 | dev_err(dev, "Cannot register net device, aborting\n"); | 2574 | dev_err(dev, "Cannot register net device, aborting\n"); |
2532 | goto err_out_dev_deinit; | 2575 | goto err_out_dev_deinit; |
2533 | } | 2576 | } |
2577 | enic->rx_copybreak = RX_COPYBREAK_DEFAULT; | ||
2534 | 2578 | ||
2535 | return 0; | 2579 | return 0; |
2536 | 2580 | ||