Merge branch 'QCA8K'
John Crispin says: ==================== net-next: dsa: add QCA8K support This series is based on the AR8xxx series posted by Matthieu Olivari in may 2015. The following changes were made since then * fixed the nitpicks from the previous review * updated to latest API * turned it into an mdio device * added callbacks for fdb, bridge offloading, stp, eee, port status * fixed several minor issues to the port setup and arp learning * changed the namespacing as this driver to qca8k The driver has so far only been tested on qca8337/N. It should work on other QCA switches such as the qca8327 with minor changes. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
84ce3da1bf
89
Documentation/devicetree/bindings/net/dsa/qca8k.txt
Normal file
89
Documentation/devicetree/bindings/net/dsa/qca8k.txt
Normal file
@ -0,0 +1,89 @@
|
||||
* Qualcomm Atheros QCA8xxx switch family
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be "qca,qca8337"
|
||||
- #size-cells: must be 0
|
||||
- #address-cells: must be 1
|
||||
|
||||
Subnodes:
|
||||
|
||||
The integrated switch subnode should be specified according to the binding
|
||||
described in dsa/dsa.txt. As the QCA8K switches do not have a N:N mapping of
|
||||
port and PHY id, each subnode describing a port needs to have a valid phandle
|
||||
referencing the internal PHY connected to it. The CPU port of this switch is
|
||||
always port 0.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
&mdio0 {
|
||||
phy_port1: phy@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
phy_port2: phy@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
phy_port3: phy@2 {
|
||||
reg = <2>;
|
||||
};
|
||||
|
||||
phy_port4: phy@3 {
|
||||
reg = <3>;
|
||||
};
|
||||
|
||||
phy_port5: phy@4 {
|
||||
reg = <4>;
|
||||
};
|
||||
|
||||
switch0@0 {
|
||||
compatible = "qca,qca8337";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
reg = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "cpu";
|
||||
ethernet = <&gmac1>;
|
||||
phy-mode = "rgmii";
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "lan1";
|
||||
phy-handle = <&phy_port1>;
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan2";
|
||||
phy-handle = <&phy_port2>;
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "lan3";
|
||||
phy-handle = <&phy_port3>;
|
||||
};
|
||||
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
label = "lan4";
|
||||
phy-handle = <&phy_port4>;
|
||||
};
|
||||
|
||||
port@5 {
|
||||
reg = <5>;
|
||||
label = "wan";
|
||||
phy-handle = <&phy_port5>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -25,4 +25,13 @@ source "drivers/net/dsa/b53/Kconfig"
|
||||
|
||||
source "drivers/net/dsa/mv88e6xxx/Kconfig"
|
||||
|
||||
config NET_DSA_QCA8K
|
||||
tristate "Qualcomm Atheros QCA8K Ethernet switch family support"
|
||||
depends on NET_DSA
|
||||
select NET_DSA_TAG_QCA
|
||||
select REGMAP
|
||||
---help---
|
||||
This enables support for the Qualcomm Atheros QCA8K Ethernet
|
||||
switch chips.
|
||||
|
||||
endmenu
|
||||
|
@ -1,5 +1,6 @@
|
||||
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
|
||||
obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm_sf2.o
|
||||
obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
|
||||
|
||||
obj-y += b53/
|
||||
obj-y += mv88e6xxx/
|
||||
|
1060
drivers/net/dsa/qca8k.c
Normal file
1060
drivers/net/dsa/qca8k.c
Normal file
File diff suppressed because it is too large
Load Diff
185
drivers/net/dsa/qca8k.h
Normal file
185
drivers/net/dsa/qca8k.h
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
|
||||
* Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __QCA8K_H
|
||||
#define __QCA8K_H
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define QCA8K_NUM_PORTS 7
|
||||
|
||||
#define PHY_ID_QCA8337 0x004dd036
|
||||
#define QCA8K_ID_QCA8337 0x13
|
||||
|
||||
#define QCA8K_NUM_FDB_RECORDS 2048
|
||||
|
||||
#define QCA8K_CPU_PORT 0
|
||||
|
||||
/* Global control registers */
|
||||
#define QCA8K_REG_MASK_CTRL 0x000
|
||||
#define QCA8K_MASK_CTRL_ID_M 0xff
|
||||
#define QCA8K_MASK_CTRL_ID_S 8
|
||||
#define QCA8K_REG_PORT0_PAD_CTRL 0x004
|
||||
#define QCA8K_REG_PORT5_PAD_CTRL 0x008
|
||||
#define QCA8K_REG_PORT6_PAD_CTRL 0x00c
|
||||
#define QCA8K_PORT_PAD_RGMII_EN BIT(26)
|
||||
#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) \
|
||||
((0x8 + (x & 0x3)) << 22)
|
||||
#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) \
|
||||
((0x10 + (x & 0x3)) << 20)
|
||||
#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24)
|
||||
#define QCA8K_PORT_PAD_SGMII_EN BIT(7)
|
||||
#define QCA8K_REG_MODULE_EN 0x030
|
||||
#define QCA8K_MODULE_EN_MIB BIT(0)
|
||||
#define QCA8K_REG_MIB 0x034
|
||||
#define QCA8K_MIB_FLUSH BIT(24)
|
||||
#define QCA8K_MIB_CPU_KEEP BIT(20)
|
||||
#define QCA8K_MIB_BUSY BIT(17)
|
||||
#define QCA8K_GOL_MAC_ADDR0 0x60
|
||||
#define QCA8K_GOL_MAC_ADDR1 0x64
|
||||
#define QCA8K_REG_PORT_STATUS(_i) (0x07c + (_i) * 4)
|
||||
#define QCA8K_PORT_STATUS_SPEED GENMASK(2, 0)
|
||||
#define QCA8K_PORT_STATUS_SPEED_S 0
|
||||
#define QCA8K_PORT_STATUS_TXMAC BIT(2)
|
||||
#define QCA8K_PORT_STATUS_RXMAC BIT(3)
|
||||
#define QCA8K_PORT_STATUS_TXFLOW BIT(4)
|
||||
#define QCA8K_PORT_STATUS_RXFLOW BIT(5)
|
||||
#define QCA8K_PORT_STATUS_DUPLEX BIT(6)
|
||||
#define QCA8K_PORT_STATUS_LINK_UP BIT(8)
|
||||
#define QCA8K_PORT_STATUS_LINK_AUTO BIT(9)
|
||||
#define QCA8K_PORT_STATUS_LINK_PAUSE BIT(10)
|
||||
#define QCA8K_REG_PORT_HDR_CTRL(_i) (0x9c + (_i * 4))
|
||||
#define QCA8K_PORT_HDR_CTRL_RX_MASK GENMASK(3, 2)
|
||||
#define QCA8K_PORT_HDR_CTRL_RX_S 2
|
||||
#define QCA8K_PORT_HDR_CTRL_TX_MASK GENMASK(1, 0)
|
||||
#define QCA8K_PORT_HDR_CTRL_TX_S 0
|
||||
#define QCA8K_PORT_HDR_CTRL_ALL 2
|
||||
#define QCA8K_PORT_HDR_CTRL_MGMT 1
|
||||
#define QCA8K_PORT_HDR_CTRL_NONE 0
|
||||
|
||||
/* EEE control registers */
|
||||
#define QCA8K_REG_EEE_CTRL 0x100
|
||||
#define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2)
|
||||
|
||||
/* ACL registers */
|
||||
#define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8))
|
||||
#define QCA8K_PORT_VLAN_CVID(x) (x << 16)
|
||||
#define QCA8K_PORT_VLAN_SVID(x) x
|
||||
#define QCA8K_REG_PORT_VLAN_CTRL1(_i) (0x424 + (_i * 8))
|
||||
#define QCA8K_REG_IPV4_PRI_BASE_ADDR 0x470
|
||||
#define QCA8K_REG_IPV4_PRI_ADDR_MASK 0x474
|
||||
|
||||
/* Lookup registers */
|
||||
#define QCA8K_REG_ATU_DATA0 0x600
|
||||
#define QCA8K_ATU_ADDR2_S 24
|
||||
#define QCA8K_ATU_ADDR3_S 16
|
||||
#define QCA8K_ATU_ADDR4_S 8
|
||||
#define QCA8K_REG_ATU_DATA1 0x604
|
||||
#define QCA8K_ATU_PORT_M 0x7f
|
||||
#define QCA8K_ATU_PORT_S 16
|
||||
#define QCA8K_ATU_ADDR0_S 8
|
||||
#define QCA8K_REG_ATU_DATA2 0x608
|
||||
#define QCA8K_ATU_VID_M 0xfff
|
||||
#define QCA8K_ATU_VID_S 8
|
||||
#define QCA8K_ATU_STATUS_M 0xf
|
||||
#define QCA8K_ATU_STATUS_STATIC 0xf
|
||||
#define QCA8K_REG_ATU_FUNC 0x60c
|
||||
#define QCA8K_ATU_FUNC_BUSY BIT(31)
|
||||
#define QCA8K_ATU_FUNC_PORT_EN BIT(14)
|
||||
#define QCA8K_ATU_FUNC_MULTI_EN BIT(13)
|
||||
#define QCA8K_ATU_FUNC_FULL BIT(12)
|
||||
#define QCA8K_ATU_FUNC_PORT_M 0xf
|
||||
#define QCA8K_ATU_FUNC_PORT_S 8
|
||||
#define QCA8K_REG_GLOBAL_FW_CTRL0 0x620
|
||||
#define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10)
|
||||
#define QCA8K_REG_GLOBAL_FW_CTRL1 0x624
|
||||
#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S 24
|
||||
#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_S 16
|
||||
#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_S 8
|
||||
#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_S 0
|
||||
#define QCA8K_PORT_LOOKUP_CTRL(_i) (0x660 + (_i) * 0xc)
|
||||
#define QCA8K_PORT_LOOKUP_MEMBER GENMASK(6, 0)
|
||||
#define QCA8K_PORT_LOOKUP_STATE_MASK GENMASK(18, 16)
|
||||
#define QCA8K_PORT_LOOKUP_STATE_DISABLED (0 << 16)
|
||||
#define QCA8K_PORT_LOOKUP_STATE_BLOCKING (1 << 16)
|
||||
#define QCA8K_PORT_LOOKUP_STATE_LISTENING (2 << 16)
|
||||
#define QCA8K_PORT_LOOKUP_STATE_LEARNING (3 << 16)
|
||||
#define QCA8K_PORT_LOOKUP_STATE_FORWARD (4 << 16)
|
||||
#define QCA8K_PORT_LOOKUP_STATE GENMASK(18, 16)
|
||||
#define QCA8K_PORT_LOOKUP_LEARN BIT(20)
|
||||
|
||||
/* Pkt edit registers */
|
||||
#define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2)))
|
||||
|
||||
/* L3 registers */
|
||||
#define QCA8K_HROUTER_CONTROL 0xe00
|
||||
#define QCA8K_HROUTER_CONTROL_GLB_LOCKTIME_M GENMASK(17, 16)
|
||||
#define QCA8K_HROUTER_CONTROL_GLB_LOCKTIME_S 16
|
||||
#define QCA8K_HROUTER_CONTROL_ARP_AGE_MODE 1
|
||||
#define QCA8K_HROUTER_PBASED_CONTROL1 0xe08
|
||||
#define QCA8K_HROUTER_PBASED_CONTROL2 0xe0c
|
||||
#define QCA8K_HNAT_CONTROL 0xe38
|
||||
|
||||
/* MIB registers */
|
||||
#define QCA8K_PORT_MIB_COUNTER(_i) (0x1000 + (_i) * 0x100)
|
||||
|
||||
/* QCA specific MII registers */
|
||||
#define MII_ATH_MMD_ADDR 0x0d
|
||||
#define MII_ATH_MMD_DATA 0x0e
|
||||
|
||||
enum {
|
||||
QCA8K_PORT_SPEED_10M = 0,
|
||||
QCA8K_PORT_SPEED_100M = 1,
|
||||
QCA8K_PORT_SPEED_1000M = 2,
|
||||
QCA8K_PORT_SPEED_ERR = 3,
|
||||
};
|
||||
|
||||
enum qca8k_fdb_cmd {
|
||||
QCA8K_FDB_FLUSH = 1,
|
||||
QCA8K_FDB_LOAD = 2,
|
||||
QCA8K_FDB_PURGE = 3,
|
||||
QCA8K_FDB_NEXT = 6,
|
||||
QCA8K_FDB_SEARCH = 7,
|
||||
};
|
||||
|
||||
struct ar8xxx_port_status {
|
||||
struct ethtool_eee eee;
|
||||
struct net_device *bridge_dev;
|
||||
int enabled;
|
||||
};
|
||||
|
||||
struct qca8k_priv {
|
||||
struct regmap *regmap;
|
||||
struct mii_bus *bus;
|
||||
struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
|
||||
struct dsa_switch *ds;
|
||||
struct mutex reg_mutex;
|
||||
};
|
||||
|
||||
struct qca8k_mib_desc {
|
||||
unsigned int size;
|
||||
unsigned int offset;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct qca8k_fdb {
|
||||
u16 vid;
|
||||
u8 port_mask;
|
||||
u8 aging;
|
||||
u8 mac[6];
|
||||
};
|
||||
|
||||
#endif /* __QCA8K_H */
|
@ -26,6 +26,7 @@ enum dsa_tag_protocol {
|
||||
DSA_TAG_PROTO_TRAILER,
|
||||
DSA_TAG_PROTO_EDSA,
|
||||
DSA_TAG_PROTO_BRCM,
|
||||
DSA_TAG_PROTO_QCA,
|
||||
DSA_TAG_LAST, /* MUST BE LAST */
|
||||
};
|
||||
|
||||
|
@ -38,4 +38,7 @@ config NET_DSA_TAG_EDSA
|
||||
config NET_DSA_TAG_TRAILER
|
||||
bool
|
||||
|
||||
config NET_DSA_TAG_QCA
|
||||
bool
|
||||
|
||||
endif
|
||||
|
@ -7,3 +7,4 @@ dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
|
||||
dsa_core-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
|
||||
|
@ -53,6 +53,9 @@ const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = {
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_BRCM
|
||||
[DSA_TAG_PROTO_BRCM] = &brcm_netdev_ops,
|
||||
#endif
|
||||
#ifdef CONFIG_NET_DSA_TAG_QCA
|
||||
[DSA_TAG_PROTO_QCA] = &qca_netdev_ops,
|
||||
#endif
|
||||
[DSA_TAG_PROTO_NONE] = &none_ops,
|
||||
};
|
||||
|
@ -81,5 +81,7 @@ extern const struct dsa_device_ops trailer_netdev_ops;
|
||||
/* tag_brcm.c */
|
||||
extern const struct dsa_device_ops brcm_netdev_ops;
|
||||
|
||||
/* tag_qca.c */
|
||||
extern const struct dsa_device_ops qca_netdev_ops;
|
||||
|
||||
#endif
|
||||
|
138
net/dsa/tag_qca.c
Normal file
138
net/dsa/tag_qca.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include "dsa_priv.h"
|
||||
|
||||
#define QCA_HDR_LEN 2
|
||||
#define QCA_HDR_VERSION 0x2
|
||||
|
||||
#define QCA_HDR_RECV_VERSION_MASK GENMASK(15, 14)
|
||||
#define QCA_HDR_RECV_VERSION_S 14
|
||||
#define QCA_HDR_RECV_PRIORITY_MASK GENMASK(13, 11)
|
||||
#define QCA_HDR_RECV_PRIORITY_S 11
|
||||
#define QCA_HDR_RECV_TYPE_MASK GENMASK(10, 6)
|
||||
#define QCA_HDR_RECV_TYPE_S 6
|
||||
#define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3)
|
||||
#define QCA_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0)
|
||||
|
||||
#define QCA_HDR_XMIT_VERSION_MASK GENMASK(15, 14)
|
||||
#define QCA_HDR_XMIT_VERSION_S 14
|
||||
#define QCA_HDR_XMIT_PRIORITY_MASK GENMASK(13, 11)
|
||||
#define QCA_HDR_XMIT_PRIORITY_S 11
|
||||
#define QCA_HDR_XMIT_CONTROL_MASK GENMASK(10, 8)
|
||||
#define QCA_HDR_XMIT_CONTROL_S 8
|
||||
#define QCA_HDR_XMIT_FROM_CPU BIT(7)
|
||||
#define QCA_HDR_XMIT_DP_BIT_MASK GENMASK(6, 0)
|
||||
|
||||
static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct dsa_slave_priv *p = netdev_priv(dev);
|
||||
u16 *phdr, hdr;
|
||||
|
||||
dev->stats.tx_packets++;
|
||||
dev->stats.tx_bytes += skb->len;
|
||||
|
||||
if (skb_cow_head(skb, 0) < 0)
|
||||
goto out_free;
|
||||
|
||||
skb_push(skb, QCA_HDR_LEN);
|
||||
|
||||
memmove(skb->data, skb->data + QCA_HDR_LEN, 2 * ETH_ALEN);
|
||||
phdr = (u16 *)(skb->data + 2 * ETH_ALEN);
|
||||
|
||||
/* Set the version field, and set destination port information */
|
||||
hdr = QCA_HDR_VERSION << QCA_HDR_XMIT_VERSION_S |
|
||||
QCA_HDR_XMIT_FROM_CPU |
|
||||
BIT(p->port);
|
||||
|
||||
*phdr = htons(hdr);
|
||||
|
||||
return skb;
|
||||
|
||||
out_free:
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int qca_tag_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *orig_dev)
|
||||
{
|
||||
struct dsa_switch_tree *dst = dev->dsa_ptr;
|
||||
struct dsa_switch *ds;
|
||||
u8 ver;
|
||||
int port;
|
||||
__be16 *phdr, hdr;
|
||||
|
||||
if (unlikely(!dst))
|
||||
goto out_drop;
|
||||
|
||||
skb = skb_unshare(skb, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN)))
|
||||
goto out_drop;
|
||||
|
||||
/* The QCA header is added by the switch between src addr and Ethertype
|
||||
* At this point, skb->data points to ethertype so header should be
|
||||
* right before
|
||||
*/
|
||||
phdr = (__be16 *)(skb->data - 2);
|
||||
hdr = ntohs(*phdr);
|
||||
|
||||
/* Make sure the version is correct */
|
||||
ver = (hdr & QCA_HDR_RECV_VERSION_MASK) >> QCA_HDR_RECV_VERSION_S;
|
||||
if (unlikely(ver != QCA_HDR_VERSION))
|
||||
goto out_drop;
|
||||
|
||||
/* Remove QCA tag and recalculate checksum */
|
||||
skb_pull_rcsum(skb, QCA_HDR_LEN);
|
||||
memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - QCA_HDR_LEN,
|
||||
ETH_HLEN - QCA_HDR_LEN);
|
||||
|
||||
/* This protocol doesn't support cascading multiple switches so it's
|
||||
* safe to assume the switch is first in the tree
|
||||
*/
|
||||
ds = dst->ds[0];
|
||||
if (!ds)
|
||||
goto out_drop;
|
||||
|
||||
/* Get source port information */
|
||||
port = (hdr & QCA_HDR_RECV_SOURCE_PORT_MASK);
|
||||
if (!ds->ports[port].netdev)
|
||||
goto out_drop;
|
||||
|
||||
/* Update skb & forward the frame accordingly */
|
||||
skb_push(skb, ETH_HLEN);
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
skb->dev = ds->ports[port].netdev;
|
||||
skb->protocol = eth_type_trans(skb, skb->dev);
|
||||
|
||||
skb->dev->stats.rx_packets++;
|
||||
skb->dev->stats.rx_bytes += skb->len;
|
||||
|
||||
netif_receive_skb(skb);
|
||||
|
||||
return 0;
|
||||
|
||||
out_drop:
|
||||
kfree_skb(skb);
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct dsa_device_ops qca_netdev_ops = {
|
||||
.xmit = qca_tag_xmit,
|
||||
.rcv = qca_tag_rcv,
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user