aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFugang Duan <B38611@freescale.com>2014-03-30 22:30:12 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:58:19 -0400
commiteb57d56ada1cda08b3c621861c84c72b90fa06fc (patch)
treeca7e9773089ad936c58e172a1e07d45904dc8741
parentb6affa9ca096abc11d842ecb9c06f55885d0ba61 (diff)
ENGR00305366-03 net: fec: remove memory copy for rx path
Re-allocate skb instead of memory copy skb in rx path to improve imx6sx enet rx performance. After the patch, rx performance can reach at 940Mbps (cpu loading is near to 100%) with below interrupt coalescing setting and cpu frequency is 996Mhz. enet reg 0x021880F0=C4000B00 enet reg 0x02188100=C5000900 Signed-off-by: Fugang Duan <B38611@freescale.com>
-rw-r--r--drivers/net/ethernet/freescale/fec.h11
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c89
2 files changed, 55 insertions, 45 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 95fecfeb2e88..7190f171d02e 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -251,6 +251,11 @@ struct bufdesc_ex {
251#define BD_ENET_TX_PINS 0x10000000 251#define BD_ENET_TX_PINS 0x10000000
252#define BD_ENET_TX_IINS 0x08000000 252#define BD_ENET_TX_IINS 0x08000000
253 253
254#if defined(CONFIG_ARM)
255#define FEC_ALIGNMENT 0x3f
256#else
257#define FEC_ALIGNMENT 0x3
258#endif
254 259
255/* This device has up to three irqs on some platforms */ 260/* This device has up to three irqs on some platforms */
256#define FEC_IRQ_NUM 3 261#define FEC_IRQ_NUM 3
@@ -270,10 +275,8 @@ struct bufdesc_ex {
270 * the skbuffer directly. 275 * the skbuffer directly.
271 */ 276 */
272 277
273#define FEC_ENET_RX_PAGES 256 278#define FEC_ENET_RX_FRSIZE (1522 + FEC_ALIGNMENT)
274#define FEC_ENET_RX_FRSIZE 2048 279#define RX_RING_SIZE 256
275#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE)
276#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
277#define FEC_ENET_TX_FRSIZE 2048 280#define FEC_ENET_TX_FRSIZE 2048
278#define FEC_ENET_TX_FRPPG (PAGE_SIZE / FEC_ENET_TX_FRSIZE) 281#define FEC_ENET_TX_FRPPG (PAGE_SIZE / FEC_ENET_TX_FRSIZE)
279#define TX_RING_SIZE 512 /* Must be power of two */ 282#define TX_RING_SIZE 512 /* Must be power of two */
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index f5178a9b30c5..c337e26cde9c 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -73,12 +73,6 @@ static void set_multicast_list(struct net_device *ndev);
73static void fec_reset_phy(struct platform_device *pdev); 73static void fec_reset_phy(struct platform_device *pdev);
74static void fec_enet_itr_coal_init(struct net_device *ndev); 74static void fec_enet_itr_coal_init(struct net_device *ndev);
75 75
76#if defined(CONFIG_ARM)
77#define FEC_ALIGNMENT 0x3f
78#else
79#define FEC_ALIGNMENT 0x3
80#endif
81
82#define DRIVER_NAME "fec" 76#define DRIVER_NAME "fec"
83#define FEC_NAPI_WEIGHT 64 77#define FEC_NAPI_WEIGHT 64
84#define FEC_ENET_GET_QUQUE(_x) ((_x == 0) ? 1 : ((_x == 1) ? 2 : 0)) 78#define FEC_ENET_GET_QUQUE(_x) ((_x == 0) ? 1 : ((_x == 1) ? 2 : 0))
@@ -937,6 +931,25 @@ fec_enet_tx(struct net_device *ndev)
937 return; 931 return;
938} 932}
939 933
934static int
935fec_new_rxbdp(struct net_device *ndev, struct bufdesc *bdp, struct sk_buff *skb)
936{
937 struct fec_enet_private *fep = netdev_priv(ndev);
938 int off;
939
940 off = ((unsigned long)skb->data) & FEC_ALIGNMENT;
941 if (off)
942 skb_reserve(skb, FEC_ALIGNMENT + 1 - off);
943
944 bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data,
945 FEC_ENET_RX_FRSIZE - FEC_ALIGNMENT, DMA_FROM_DEVICE);
946 if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) {
947 netdev_err(ndev, "Rx DMA memory map failed\n");
948 return -ENOMEM;
949 }
950
951 return 0;
952}
940 953
941/* During a receive, the cur_rx points to the current incoming buffer. 954/* During a receive, the cur_rx points to the current incoming buffer.
942 * When we update through the ring, if the next incoming buffer has 955 * When we update through the ring, if the next incoming buffer has
@@ -952,7 +965,8 @@ fec_enet_rx(struct net_device *ndev, int budget)
952 struct fec_enet_priv_rx_q *rxq; 965 struct fec_enet_priv_rx_q *rxq;
953 struct bufdesc *bdp; 966 struct bufdesc *bdp;
954 unsigned short status; 967 unsigned short status;
955 struct sk_buff *skb; 968 struct sk_buff *skb_new = NULL;
969 struct sk_buff *skb_cur;
956 ushort pkt_len; 970 ushort pkt_len;
957 __u8 *data; 971 __u8 *data;
958 int pkt_received = 0; 972 int pkt_received = 0;
@@ -960,6 +974,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
960 bool vlan_packet_rcvd = false; 974 bool vlan_packet_rcvd = false;
961 u16 vlan_tag = 0; 975 u16 vlan_tag = 0;
962 u16 queue_id; 976 u16 queue_id;
977 int index = 0;
963 978
964#ifdef CONFIG_M532x 979#ifdef CONFIG_M532x
965 flush_cache_all(); 980 flush_cache_all();
@@ -981,6 +996,12 @@ fec_enet_rx(struct net_device *ndev, int budget)
981 break; 996 break;
982 pkt_received++; 997 pkt_received++;
983 998
999 if (fep->bufdesc_ex)
1000 index = (struct bufdesc_ex *)bdp -
1001 (struct bufdesc_ex *)rxq->rx_bd_base;
1002 else
1003 index = bdp - rxq->rx_bd_base;
1004
984 /* Since we have allocated space to hold a complete frame, 1005 /* Since we have allocated space to hold a complete frame,
985 * the last indicator should be set. 1006 * the last indicator should be set.
986 */ 1007 */
@@ -1021,6 +1042,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
1021 pkt_len = bdp->cbd_datlen; 1042 pkt_len = bdp->cbd_datlen;
1022 ndev->stats.rx_bytes += pkt_len; 1043 ndev->stats.rx_bytes += pkt_len;
1023 data = (__u8 *)__va(bdp->cbd_bufaddr); 1044 data = (__u8 *)__va(bdp->cbd_bufaddr);
1045 skb_cur = rxq->rx_skbuff[index];
1024 1046
1025 dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, 1047 dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
1026 FEC_ENET_RX_FRSIZE - FEC_ALIGNMENT, 1048 FEC_ENET_RX_FRSIZE - FEC_ALIGNMENT,
@@ -1052,31 +1074,26 @@ fec_enet_rx(struct net_device *ndev, int budget)
1052 * include that when passing upstream as it messes up 1074 * include that when passing upstream as it messes up
1053 * bridging applications. 1075 * bridging applications.
1054 */ 1076 */
1055 skb = __netdev_alloc_skb_ip_align(ndev, pkt_len - 4, 1077 skb_new = __netdev_alloc_skb_ip_align(ndev, FEC_ENET_RX_FRSIZE,
1056 GFP_ATOMIC | __GFP_NOWARN); 1078 GFP_ATOMIC | __GFP_NOWARN);
1057 1079
1058 if (unlikely(!skb)) { 1080 if (unlikely(!skb_new)) {
1059 ndev->stats.rx_dropped++; 1081 ndev->stats.rx_dropped++;
1060 } else { 1082 } else {
1061 int payload_offset = (2 * ETH_ALEN); 1083 skb_put(skb_cur, pkt_len - 4); /* Make room */
1062 skb_put(skb, pkt_len - 4); /* Make room */
1063 1084
1064 /* Extract the frame data without the VLAN header. */ 1085 /* Extract the frame data without the VLAN header. */
1065 if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX && 1086 if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX &&
1066 vlan_packet_rcvd) { 1087 vlan_packet_rcvd) {
1067 skb_copy_to_linear_data(skb, data, (2 * ETH_ALEN)); 1088 skb_copy_to_linear_data_offset(skb_cur, VLAN_HLEN,
1068 payload_offset = (2 * ETH_ALEN) + VLAN_HLEN; 1089 data, (2 * ETH_ALEN));
1069 skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN), 1090 skb_pull(skb_cur, VLAN_HLEN);
1070 data + payload_offset,
1071 pkt_len - 4 - (2 * ETH_ALEN));
1072 } else {
1073 skb_copy_to_linear_data(skb, data, pkt_len - 4);
1074 } 1091 }
1075 1092
1076 /* Get receive timestamp from the skb */ 1093 /* Get receive timestamp from the skb */
1077 if (fep->hwts_rx_en && fep->bufdesc_ex) { 1094 if (fep->hwts_rx_en && fep->bufdesc_ex) {
1078 struct skb_shared_hwtstamps *shhwtstamps = 1095 struct skb_shared_hwtstamps *shhwtstamps =
1079 skb_hwtstamps(skb); 1096 skb_hwtstamps(skb_cur);
1080 unsigned long flags; 1097 unsigned long flags;
1081 1098
1082 memset(shhwtstamps, 0, sizeof(*shhwtstamps)); 1099 memset(shhwtstamps, 0, sizeof(*shhwtstamps));
@@ -1087,36 +1104,34 @@ fec_enet_rx(struct net_device *ndev, int budget)
1087 spin_unlock_irqrestore(&fep->tmreg_lock, flags); 1104 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
1088 } else if (unlikely(fep->hwts_rx_en_ioctl) && 1105 } else if (unlikely(fep->hwts_rx_en_ioctl) &&
1089 fep->bufdesc_ex) 1106 fep->bufdesc_ex)
1090 fec_ptp_store_rxstamp(fep, skb, bdp); 1107 fec_ptp_store_rxstamp(fep, skb_cur, bdp);
1091 1108
1092 skb->protocol = eth_type_trans(skb, ndev); 1109 skb_cur->protocol = eth_type_trans(skb_cur, ndev);
1093 if (fep->bufdesc_ex && 1110 if (fep->bufdesc_ex &&
1094 (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { 1111 (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
1095 if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) { 1112 if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) {
1096 /* don't check it */ 1113 /* don't check it */
1097 skb->ip_summed = CHECKSUM_UNNECESSARY; 1114 skb_cur->ip_summed = CHECKSUM_UNNECESSARY;
1098 } else { 1115 } else {
1099 skb_checksum_none_assert(skb); 1116 skb_checksum_none_assert(skb_cur);
1100 } 1117 }
1101 } 1118 }
1102 1119
1103 /* Handle received VLAN packets */ 1120 /* Handle received VLAN packets */
1104 if (vlan_packet_rcvd) 1121 if (vlan_packet_rcvd)
1105 __vlan_hwaccel_put_tag(skb, 1122 __vlan_hwaccel_put_tag(skb_cur,
1106 htons(ETH_P_8021Q), 1123 htons(ETH_P_8021Q),
1107 vlan_tag); 1124 vlan_tag);
1108 1125
1109 if (!skb_defer_rx_timestamp(skb)) 1126 if (!skb_defer_rx_timestamp(skb_cur))
1110 napi_gro_receive(&fep->napi, skb); 1127 napi_gro_receive(&fep->napi, skb_cur);
1111 } 1128 }
1112 1129
1113 bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data,
1114 FEC_ENET_RX_FRSIZE - FEC_ALIGNMENT,
1115 DMA_FROM_DEVICE);
1116 /* here dma mapping shouldn't be error, just avoid kernel dump */
1117 if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr))
1118 netdev_err(ndev, "Rx DMA memory map failed\n");
1119rx_processing_done: 1130rx_processing_done:
1131 /* set the new skb */
1132 rxq->rx_skbuff[index] = skb_new;
1133 fec_new_rxbdp(ndev, bdp, skb_new);
1134
1120 /* Clear the status flags for this buffer */ 1135 /* Clear the status flags for this buffer */
1121 status &= ~BD_ENET_RX_STATS; 1136 status &= ~BD_ENET_RX_STATS;
1122 1137
@@ -2019,7 +2034,6 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
2019 unsigned int i, j; 2034 unsigned int i, j;
2020 struct sk_buff *skb; 2035 struct sk_buff *skb;
2021 struct bufdesc *bdp; 2036 struct bufdesc *bdp;
2022 int off;
2023 2037
2024 for (j = 0; j < fep->num_rx_queues; j++) { 2038 for (j = 0; j < fep->num_rx_queues; j++) {
2025 rx_queue = fep->rx_queue[j]; 2039 rx_queue = fep->rx_queue[j];
@@ -2033,15 +2047,8 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
2033 } 2047 }
2034 rx_queue->rx_skbuff[i] = skb; 2048 rx_queue->rx_skbuff[i] = skb;
2035 2049
2036 off = ((unsigned long)skb->data) & FEC_ALIGNMENT; 2050 if (fec_new_rxbdp(ndev, bdp, skb)) {
2037 if (off)
2038 skb_reserve(skb, FEC_ALIGNMENT + 1 - off);
2039
2040 bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data,
2041 FEC_ENET_RX_FRSIZE - FEC_ALIGNMENT, DMA_FROM_DEVICE);
2042 if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) {
2043 fec_enet_free_buffers(ndev); 2051 fec_enet_free_buffers(ndev);
2044 netdev_err(ndev, "Rx DMA memory map failed\n");
2045 return -ENOMEM; 2052 return -ENOMEM;
2046 } 2053 }
2047 bdp->cbd_sc = BD_ENET_RX_EMPTY; 2054 bdp->cbd_sc = BD_ENET_RX_EMPTY;