diff options
author | Fugang Duan <B38611@freescale.com> | 2014-03-30 22:30:12 -0400 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:58:19 -0400 |
commit | eb57d56ada1cda08b3c621861c84c72b90fa06fc (patch) | |
tree | ca7e9773089ad936c58e172a1e07d45904dc8741 | |
parent | b6affa9ca096abc11d842ecb9c06f55885d0ba61 (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.h | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 89 |
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); | |||
73 | static void fec_reset_phy(struct platform_device *pdev); | 73 | static void fec_reset_phy(struct platform_device *pdev); |
74 | static void fec_enet_itr_coal_init(struct net_device *ndev); | 74 | static 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 | ||
934 | static int | ||
935 | fec_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"); | ||
1119 | rx_processing_done: | 1130 | rx_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; |