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>
This commit is contained in:
parent
bc2bebe8de
commit
cdffcf1bc7
2 changed files with 55 additions and 10 deletions
|
@ -203,6 +203,9 @@ struct bufdesc_ex {
|
||||||
#define BD_ENET_RX_CL ((ushort)0x0001)
|
#define BD_ENET_RX_CL ((ushort)0x0001)
|
||||||
#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */
|
#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */
|
||||||
|
|
||||||
|
/* Enhanced buffer descriptor control/status used by Ethernet receive */
|
||||||
|
#define BD_ENET_RX_VLAN 0x00000004
|
||||||
|
|
||||||
/* Buffer descriptor control/status used by Ethernet transmit.
|
/* Buffer descriptor control/status used by Ethernet transmit.
|
||||||
*/
|
*/
|
||||||
#define BD_ENET_TX_READY ((ushort)0x8000)
|
#define BD_ENET_TX_READY ((ushort)0x8000)
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
#include <linux/of_gpio.h>
|
#include <linux/of_gpio.h>
|
||||||
#include <linux/of_net.h>
|
#include <linux/of_net.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/if_vlan.h>
|
||||||
|
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
|
|
||||||
|
@ -90,6 +91,8 @@ static void set_multicast_list(struct net_device *ndev);
|
||||||
#define FEC_QUIRK_HAS_BUFDESC_EX (1 << 4)
|
#define FEC_QUIRK_HAS_BUFDESC_EX (1 << 4)
|
||||||
/* Controller has hardware checksum support */
|
/* Controller has hardware checksum support */
|
||||||
#define FEC_QUIRK_HAS_CSUM (1 << 5)
|
#define FEC_QUIRK_HAS_CSUM (1 << 5)
|
||||||
|
/* Controller has hardware vlan support */
|
||||||
|
#define FEC_QUIRK_HAS_VLAN (1 << 6)
|
||||||
|
|
||||||
static struct platform_device_id fec_devtype[] = {
|
static struct platform_device_id fec_devtype[] = {
|
||||||
{
|
{
|
||||||
|
@ -108,7 +111,8 @@ static struct platform_device_id fec_devtype[] = {
|
||||||
}, {
|
}, {
|
||||||
.name = "imx6q-fec",
|
.name = "imx6q-fec",
|
||||||
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
|
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
|
||||||
FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM,
|
FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
|
||||||
|
FEC_QUIRK_HAS_VLAN,
|
||||||
}, {
|
}, {
|
||||||
.name = "mvf600-fec",
|
.name = "mvf600-fec",
|
||||||
.driver_data = FEC_QUIRK_ENET_MAC,
|
.driver_data = FEC_QUIRK_ENET_MAC,
|
||||||
|
@ -179,11 +183,11 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
|
||||||
#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
|
#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
|
||||||
#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
|
#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
|
||||||
|
|
||||||
/* The FEC stores dest/src/type, data, and checksum for receive packets.
|
/* The FEC stores dest/src/type/vlan, data, and checksum for receive packets.
|
||||||
*/
|
*/
|
||||||
#define PKT_MAXBUF_SIZE 1518
|
#define PKT_MAXBUF_SIZE 1522
|
||||||
#define PKT_MINBUF_SIZE 64
|
#define PKT_MINBUF_SIZE 64
|
||||||
#define PKT_MAXBLR_SIZE 1520
|
#define PKT_MAXBLR_SIZE 1536
|
||||||
|
|
||||||
/* FEC receive acceleration */
|
/* FEC receive acceleration */
|
||||||
#define FEC_RACC_IPDIS (1 << 1)
|
#define FEC_RACC_IPDIS (1 << 1)
|
||||||
|
@ -806,6 +810,9 @@ fec_enet_rx(struct net_device *ndev, int budget)
|
||||||
ushort pkt_len;
|
ushort pkt_len;
|
||||||
__u8 *data;
|
__u8 *data;
|
||||||
int pkt_received = 0;
|
int pkt_received = 0;
|
||||||
|
struct bufdesc_ex *ebdp = NULL;
|
||||||
|
bool vlan_packet_rcvd = false;
|
||||||
|
u16 vlan_tag;
|
||||||
|
|
||||||
#ifdef CONFIG_M532x
|
#ifdef CONFIG_M532x
|
||||||
flush_cache_all();
|
flush_cache_all();
|
||||||
|
@ -869,6 +876,24 @@ fec_enet_rx(struct net_device *ndev, int budget)
|
||||||
if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
|
if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
|
||||||
swap_buffer(data, pkt_len);
|
swap_buffer(data, pkt_len);
|
||||||
|
|
||||||
|
/* Extract the enhanced buffer descriptor */
|
||||||
|
ebdp = NULL;
|
||||||
|
if (fep->bufdesc_ex)
|
||||||
|
ebdp = (struct bufdesc_ex *)bdp;
|
||||||
|
|
||||||
|
/* If this is a VLAN packet remove the VLAN Tag */
|
||||||
|
vlan_packet_rcvd = false;
|
||||||
|
if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
|
||||||
|
fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) {
|
||||||
|
/* Push and remove the vlan tag */
|
||||||
|
struct vlan_hdr *vlan_header =
|
||||||
|
(struct vlan_hdr *) (data + ETH_HLEN);
|
||||||
|
vlan_tag = ntohs(vlan_header->h_vlan_TCI);
|
||||||
|
pkt_len -= VLAN_HLEN;
|
||||||
|
|
||||||
|
vlan_packet_rcvd = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* This does 16 byte alignment, exactly what we need.
|
/* This does 16 byte alignment, exactly what we need.
|
||||||
* The packet length includes FCS, but we don't want to
|
* The packet length includes FCS, but we don't want to
|
||||||
* include that when passing upstream as it messes up
|
* include that when passing upstream as it messes up
|
||||||
|
@ -879,9 +904,18 @@ fec_enet_rx(struct net_device *ndev, int budget)
|
||||||
if (unlikely(!skb)) {
|
if (unlikely(!skb)) {
|
||||||
ndev->stats.rx_dropped++;
|
ndev->stats.rx_dropped++;
|
||||||
} else {
|
} else {
|
||||||
|
int payload_offset = (2 * ETH_ALEN);
|
||||||
skb_reserve(skb, NET_IP_ALIGN);
|
skb_reserve(skb, NET_IP_ALIGN);
|
||||||
skb_put(skb, pkt_len - 4); /* Make room */
|
skb_put(skb, pkt_len - 4); /* Make room */
|
||||||
skb_copy_to_linear_data(skb, data, pkt_len - 4);
|
|
||||||
|
/* Extract the frame data without the VLAN header. */
|
||||||
|
skb_copy_to_linear_data(skb, data, (2 * ETH_ALEN));
|
||||||
|
if (vlan_packet_rcvd)
|
||||||
|
payload_offset = (2 * ETH_ALEN) + VLAN_HLEN;
|
||||||
|
skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN),
|
||||||
|
data + payload_offset,
|
||||||
|
pkt_len - 4 - (2 * ETH_ALEN));
|
||||||
|
|
||||||
skb->protocol = eth_type_trans(skb, ndev);
|
skb->protocol = eth_type_trans(skb, ndev);
|
||||||
|
|
||||||
/* Get receive timestamp from the skb */
|
/* Get receive timestamp from the skb */
|
||||||
|
@ -889,8 +923,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
|
||||||
struct skb_shared_hwtstamps *shhwtstamps =
|
struct skb_shared_hwtstamps *shhwtstamps =
|
||||||
skb_hwtstamps(skb);
|
skb_hwtstamps(skb);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct bufdesc_ex *ebdp =
|
|
||||||
(struct bufdesc_ex *)bdp;
|
|
||||||
|
|
||||||
memset(shhwtstamps, 0, sizeof(*shhwtstamps));
|
memset(shhwtstamps, 0, sizeof(*shhwtstamps));
|
||||||
|
|
||||||
|
@ -901,9 +933,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fep->bufdesc_ex &&
|
if (fep->bufdesc_ex &&
|
||||||
(fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
|
(fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
|
||||||
struct bufdesc_ex *ebdp =
|
|
||||||
(struct bufdesc_ex *)bdp;
|
|
||||||
if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) {
|
if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) {
|
||||||
/* don't check it */
|
/* don't check it */
|
||||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||||
|
@ -912,6 +942,12 @@ fec_enet_rx(struct net_device *ndev, int budget)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle received VLAN packets */
|
||||||
|
if (vlan_packet_rcvd)
|
||||||
|
__vlan_hwaccel_put_tag(skb,
|
||||||
|
htons(ETH_P_8021Q),
|
||||||
|
vlan_tag);
|
||||||
|
|
||||||
if (!skb_defer_rx_timestamp(skb))
|
if (!skb_defer_rx_timestamp(skb))
|
||||||
napi_gro_receive(&fep->napi, skb);
|
napi_gro_receive(&fep->napi, skb);
|
||||||
}
|
}
|
||||||
|
@ -1924,6 +1960,12 @@ static int fec_enet_init(struct net_device *ndev)
|
||||||
writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
|
writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
|
||||||
netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
|
netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
|
||||||
|
|
||||||
|
if (id_entry->driver_data & FEC_QUIRK_HAS_VLAN) {
|
||||||
|
/* enable hw VLAN support */
|
||||||
|
ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
|
||||||
|
ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
|
||||||
|
}
|
||||||
|
|
||||||
if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) {
|
if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) {
|
||||||
/* enable hw accelerator */
|
/* enable hw accelerator */
|
||||||
ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
|
ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
|
||||||
|
|
Loading…
Reference in a new issue