aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorJim Baxter <jim_baxter@mentor.com>2013-07-02 17:52:56 -0400
committerDavid S. Miller <davem@davemloft.net>2013-07-03 19:45:34 -0400
commitcdffcf1bc721032d261a7a9da353b41f0d830410 (patch)
tree4746033333eae7eb588f2eca7eb7770eb38f563f /drivers/net
parentbc2bebe8de8ed4ba6482c9cc370b0dd72ffe8cd2 (diff)
net: fec: Add VLAN receive HW support.
This enables the driver to take advantage of the FEC VLAN indicator to improve performance. Signed-off-by: Jim Baxter <jim_baxter@mentor.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/freescale/fec.h3
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c62
2 files changed, 55 insertions, 10 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 8362a0399afb..2b0a0ea4f8e7 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -203,6 +203,9 @@ struct bufdesc_ex {
203#define BD_ENET_RX_CL ((ushort)0x0001) 203#define BD_ENET_RX_CL ((ushort)0x0001)
204#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ 204#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */
205 205
206/* Enhanced buffer descriptor control/status used by Ethernet receive */
207#define BD_ENET_RX_VLAN 0x00000004
208
206/* Buffer descriptor control/status used by Ethernet transmit. 209/* Buffer descriptor control/status used by Ethernet transmit.
207*/ 210*/
208#define BD_ENET_TX_READY ((ushort)0x8000) 211#define BD_ENET_TX_READY ((ushort)0x8000)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 1f7ff2268bd0..d3ad5ea711d3 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -54,6 +54,7 @@
54#include <linux/of_gpio.h> 54#include <linux/of_gpio.h>
55#include <linux/of_net.h> 55#include <linux/of_net.h>
56#include <linux/regulator/consumer.h> 56#include <linux/regulator/consumer.h>
57#include <linux/if_vlan.h>
57 58
58#include <asm/cacheflush.h> 59#include <asm/cacheflush.h>
59 60
@@ -90,6 +91,8 @@ static void set_multicast_list(struct net_device *ndev);
90#define FEC_QUIRK_HAS_BUFDESC_EX (1 << 4) 91#define FEC_QUIRK_HAS_BUFDESC_EX (1 << 4)
91/* Controller has hardware checksum support */ 92/* Controller has hardware checksum support */
92#define FEC_QUIRK_HAS_CSUM (1 << 5) 93#define FEC_QUIRK_HAS_CSUM (1 << 5)
94/* Controller has hardware vlan support */
95#define FEC_QUIRK_HAS_VLAN (1 << 6)
93 96
94static struct platform_device_id fec_devtype[] = { 97static struct platform_device_id fec_devtype[] = {
95 { 98 {
@@ -108,7 +111,8 @@ static struct platform_device_id fec_devtype[] = {
108 }, { 111 }, {
109 .name = "imx6q-fec", 112 .name = "imx6q-fec",
110 .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | 113 .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
111 FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM, 114 FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
115 FEC_QUIRK_HAS_VLAN,
112 }, { 116 }, {
113 .name = "mvf600-fec", 117 .name = "mvf600-fec",
114 .driver_data = FEC_QUIRK_ENET_MAC, 118 .driver_data = FEC_QUIRK_ENET_MAC,
@@ -179,11 +183,11 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
179#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII) 183#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
180#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF)) 184#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
181 185
182/* The FEC stores dest/src/type, data, and checksum for receive packets. 186/* The FEC stores dest/src/type/vlan, data, and checksum for receive packets.
183 */ 187 */
184#define PKT_MAXBUF_SIZE 1518 188#define PKT_MAXBUF_SIZE 1522
185#define PKT_MINBUF_SIZE 64 189#define PKT_MINBUF_SIZE 64
186#define PKT_MAXBLR_SIZE 1520 190#define PKT_MAXBLR_SIZE 1536
187 191
188/* FEC receive acceleration */ 192/* FEC receive acceleration */
189#define FEC_RACC_IPDIS (1 << 1) 193#define FEC_RACC_IPDIS (1 << 1)
@@ -806,6 +810,9 @@ fec_enet_rx(struct net_device *ndev, int budget)
806 ushort pkt_len; 810 ushort pkt_len;
807 __u8 *data; 811 __u8 *data;
808 int pkt_received = 0; 812 int pkt_received = 0;
813 struct bufdesc_ex *ebdp = NULL;
814 bool vlan_packet_rcvd = false;
815 u16 vlan_tag;
809 816
810#ifdef CONFIG_M532x 817#ifdef CONFIG_M532x
811 flush_cache_all(); 818 flush_cache_all();
@@ -869,6 +876,24 @@ fec_enet_rx(struct net_device *ndev, int budget)
869 if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) 876 if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
870 swap_buffer(data, pkt_len); 877 swap_buffer(data, pkt_len);
871 878
879 /* Extract the enhanced buffer descriptor */
880 ebdp = NULL;
881 if (fep->bufdesc_ex)
882 ebdp = (struct bufdesc_ex *)bdp;
883
884 /* If this is a VLAN packet remove the VLAN Tag */
885 vlan_packet_rcvd = false;
886 if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
887 fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) {
888 /* Push and remove the vlan tag */
889 struct vlan_hdr *vlan_header =
890 (struct vlan_hdr *) (data + ETH_HLEN);
891 vlan_tag = ntohs(vlan_header->h_vlan_TCI);
892 pkt_len -= VLAN_HLEN;
893
894 vlan_packet_rcvd = true;
895 }
896
872 /* This does 16 byte alignment, exactly what we need. 897 /* This does 16 byte alignment, exactly what we need.
873 * The packet length includes FCS, but we don't want to 898 * The packet length includes FCS, but we don't want to
874 * include that when passing upstream as it messes up 899 * include that when passing upstream as it messes up
@@ -879,9 +904,18 @@ fec_enet_rx(struct net_device *ndev, int budget)
879 if (unlikely(!skb)) { 904 if (unlikely(!skb)) {
880 ndev->stats.rx_dropped++; 905 ndev->stats.rx_dropped++;
881 } else { 906 } else {
907 int payload_offset = (2 * ETH_ALEN);
882 skb_reserve(skb, NET_IP_ALIGN); 908 skb_reserve(skb, NET_IP_ALIGN);
883 skb_put(skb, pkt_len - 4); /* Make room */ 909 skb_put(skb, pkt_len - 4); /* Make room */
884 skb_copy_to_linear_data(skb, data, pkt_len - 4); 910
911 /* Extract the frame data without the VLAN header. */
912 skb_copy_to_linear_data(skb, data, (2 * ETH_ALEN));
913 if (vlan_packet_rcvd)
914 payload_offset = (2 * ETH_ALEN) + VLAN_HLEN;
915 skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN),
916 data + payload_offset,
917 pkt_len - 4 - (2 * ETH_ALEN));
918
885 skb->protocol = eth_type_trans(skb, ndev); 919 skb->protocol = eth_type_trans(skb, ndev);
886 920
887 /* Get receive timestamp from the skb */ 921 /* Get receive timestamp from the skb */
@@ -889,8 +923,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
889 struct skb_shared_hwtstamps *shhwtstamps = 923 struct skb_shared_hwtstamps *shhwtstamps =
890 skb_hwtstamps(skb); 924 skb_hwtstamps(skb);
891 unsigned long flags; 925 unsigned long flags;
892 struct bufdesc_ex *ebdp =
893 (struct bufdesc_ex *)bdp;
894 926
895 memset(shhwtstamps, 0, sizeof(*shhwtstamps)); 927 memset(shhwtstamps, 0, sizeof(*shhwtstamps));
896 928
@@ -901,9 +933,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
901 } 933 }
902 934
903 if (fep->bufdesc_ex && 935 if (fep->bufdesc_ex &&
904 (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { 936 (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
905 struct bufdesc_ex *ebdp =
906 (struct bufdesc_ex *)bdp;
907 if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) { 937 if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) {
908 /* don't check it */ 938 /* don't check it */
909 skb->ip_summed = CHECKSUM_UNNECESSARY; 939 skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -912,6 +942,12 @@ fec_enet_rx(struct net_device *ndev, int budget)
912 } 942 }
913 } 943 }
914 944
945 /* Handle received VLAN packets */
946 if (vlan_packet_rcvd)
947 __vlan_hwaccel_put_tag(skb,
948 htons(ETH_P_8021Q),
949 vlan_tag);
950
915 if (!skb_defer_rx_timestamp(skb)) 951 if (!skb_defer_rx_timestamp(skb))
916 napi_gro_receive(&fep->napi, skb); 952 napi_gro_receive(&fep->napi, skb);
917 } 953 }
@@ -1924,6 +1960,12 @@ static int fec_enet_init(struct net_device *ndev)
1924 writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK); 1960 writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
1925 netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT); 1961 netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
1926 1962
1963 if (id_entry->driver_data & FEC_QUIRK_HAS_VLAN) {
1964 /* enable hw VLAN support */
1965 ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
1966 ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
1967 }
1968
1927 if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) { 1969 if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) {
1928 /* enable hw accelerator */ 1970 /* enable hw accelerator */
1929 ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM 1971 ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM