summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/mscc
diff options
context:
space:
mode:
authorVladimir Oltean <vladimir.oltean@nxp.com>2020-06-20 18:43:44 +0300
committerDavid S. Miller <davem@davemloft.net>2020-06-20 17:25:23 -0700
commit9c90eea310f80460b81a7afe27064c7f0200d1d1 (patch)
tree79721b9dcd50c6bd53c3771189d4d1cf1efafe49 /drivers/net/ethernet/mscc
parentd9feb9049973332de0242a08248e069113bf5761 (diff)
net: mscc: ocelot: move net_device related functions to ocelot_net.c
The ocelot hardware library shouldn't contain too much net_device specific code, since it is shared with DSA which abstracts that structure away. So much as much of this code as possible into the mscc_ocelot driver and outside of the common library. We're making an exception for MDB and LAG code. That is not yet exported to DSA, but when it will, most of the code that's already in ocelot.c will remain there. So, there's no point in moving code to ocelot_net.c just to move it back later. We could have moved all net_device code to ocelot_vsc7514.c directly, but let's operate under the assumption that if a new switchdev ocelot driver gets added, it'll define its SoC-specific stuff in a new ocelot_vsc*.c file and it'll reuse the rest of the code. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/mscc')
-rw-r--r--drivers/net/ethernet/mscc/Makefile5
-rw-r--r--drivers/net/ethernet/mscc/ocelot.c909
-rw-r--r--drivers/net/ethernet/mscc/ocelot.h45
-rw-r--r--drivers/net/ethernet/mscc/ocelot_ace.c24
-rw-r--r--drivers/net/ethernet/mscc/ocelot_flower.c22
-rw-r--r--drivers/net/ethernet/mscc/ocelot_net.c1031
-rw-r--r--drivers/net/ethernet/mscc/ocelot_police.c49
-rw-r--r--drivers/net/ethernet/mscc/ocelot_police.h24
-rw-r--r--drivers/net/ethernet/mscc/ocelot_tc.c179
-rw-r--r--drivers/net/ethernet/mscc/ocelot_tc.h22
10 files changed, 1151 insertions, 1159 deletions
diff --git a/drivers/net/ethernet/mscc/Makefile b/drivers/net/ethernet/mscc/Makefile
index 5d0b6c1da3a0..7ab3bc25ed27 100644
--- a/drivers/net/ethernet/mscc/Makefile
+++ b/drivers/net/ethernet/mscc/Makefile
@@ -3,10 +3,11 @@ obj-$(CONFIG_MSCC_OCELOT_SWITCH_LIB) += mscc_ocelot_switch_lib.o
mscc_ocelot_switch_lib-y := \
ocelot.o \
ocelot_io.o \
- ocelot_tc.o \
ocelot_police.o \
ocelot_ace.o \
ocelot_flower.o \
ocelot_ptp.o
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot.o
-mscc_ocelot-y := ocelot_vsc7514.o
+mscc_ocelot-y := \
+ ocelot_vsc7514.o \
+ ocelot_net.o
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 9cfe1fd98c30..5c2b5a2e8608 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -4,42 +4,13 @@
*
* Copyright (c) 2017 Microsemi Corporation
*/
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
#include <linux/if_bridge.h>
-#include <linux/if_ether.h>
-#include <linux/if_vlan.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/phy.h>
-#include <linux/skbuff.h>
-#include <linux/iopoll.h>
-#include <net/arp.h>
-#include <net/netevent.h>
-#include <net/rtnetlink.h>
-#include <net/switchdev.h>
-
#include "ocelot.h"
#include "ocelot_ace.h"
#define TABLE_UPDATE_SLEEP_US 10
#define TABLE_UPDATE_TIMEOUT_US 100000
-/* MAC table entry types.
- * ENTRYTYPE_NORMAL is subject to aging.
- * ENTRYTYPE_LOCKED is not subject to aging.
- * ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast.
- * ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast.
- */
-enum macaccess_entry_type {
- ENTRYTYPE_NORMAL = 0,
- ENTRYTYPE_LOCKED,
- ENTRYTYPE_MACv4,
- ENTRYTYPE_MACv6,
-};
-
struct ocelot_mact_entry {
u8 mac[ETH_ALEN];
u16 vid;
@@ -84,10 +55,9 @@ static void ocelot_mact_select(struct ocelot *ocelot,
}
-static int ocelot_mact_learn(struct ocelot *ocelot, int port,
- const unsigned char mac[ETH_ALEN],
- unsigned int vid,
- enum macaccess_entry_type type)
+int ocelot_mact_learn(struct ocelot *ocelot, int port,
+ const unsigned char mac[ETH_ALEN],
+ unsigned int vid, enum macaccess_entry_type type)
{
ocelot_mact_select(ocelot, mac, vid);
@@ -100,10 +70,10 @@ static int ocelot_mact_learn(struct ocelot *ocelot, int port,
return ocelot_mact_wait_for_completion(ocelot);
}
+EXPORT_SYMBOL(ocelot_mact_learn);
-static int ocelot_mact_forget(struct ocelot *ocelot,
- const unsigned char mac[ETH_ALEN],
- unsigned int vid)
+int ocelot_mact_forget(struct ocelot *ocelot,
+ const unsigned char mac[ETH_ALEN], unsigned int vid)
{
ocelot_mact_select(ocelot, mac, vid);
@@ -114,6 +84,7 @@ static int ocelot_mact_forget(struct ocelot *ocelot,
return ocelot_mact_wait_for_completion(ocelot);
}
+EXPORT_SYMBOL(ocelot_mact_forget);
static void ocelot_mact_init(struct ocelot *ocelot)
{
@@ -168,20 +139,6 @@ static int ocelot_vlant_set_mask(struct ocelot *ocelot, u16 vid, u32 mask)
return ocelot_vlant_wait_for_completion(ocelot);
}
-static void ocelot_vlan_mode(struct ocelot *ocelot, int port,
- netdev_features_t features)
-{
- u32 val;
-
- /* Filtering */
- val = ocelot_read(ocelot, ANA_VLANMASK);
- if (features & NETIF_F_HW_VLAN_CTAG_FILTER)
- val |= BIT(port);
- else
- val &= ~BIT(port);
- ocelot_write(ocelot, val, ANA_VLANMASK);
-}
-
static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
u16 vid)
{
@@ -295,26 +252,6 @@ int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
}
EXPORT_SYMBOL(ocelot_vlan_add);
-static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid,
- bool untagged)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot_port *ocelot_port = &priv->port;
- struct ocelot *ocelot = ocelot_port->ocelot;
- int port = priv->chip_port;
- int ret;
-
- ret = ocelot_vlan_add(ocelot, port, vid, pvid, untagged);
- if (ret)
- return ret;
-
- /* Add the port MAC address to with the right VLAN information */
- ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, vid,
- ENTRYTYPE_LOCKED);
-
- return 0;
-}
-
int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
@@ -338,30 +275,6 @@ int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid)
}
EXPORT_SYMBOL(ocelot_vlan_del);
-static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
- int ret;
-
- /* 8021q removes VID 0 on module unload for all interfaces
- * with VLAN filtering feature. We need to keep it to receive
- * untagged traffic.
- */
- if (vid == 0)
- return 0;
-
- ret = ocelot_vlan_del(ocelot, port, vid);
- if (ret)
- return ret;
-
- /* Del the port MAC address to with the right VLAN information */
- ocelot_mact_forget(ocelot, dev->dev_addr, vid);
-
- return 0;
-}
-
static void ocelot_vlan_init(struct ocelot *ocelot)
{
u16 port, vid;
@@ -492,15 +405,6 @@ void ocelot_adjust_link(struct ocelot *ocelot, int port,
}
EXPORT_SYMBOL(ocelot_adjust_link);
-static void ocelot_port_adjust_link(struct net_device *dev)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
-
- ocelot_adjust_link(ocelot, port, dev->phydev);
-}
-
void ocelot_port_enable(struct ocelot *ocelot, int port,
struct phy_device *phy)
{
@@ -514,40 +418,6 @@ void ocelot_port_enable(struct ocelot *ocelot, int port,
}
EXPORT_SYMBOL(ocelot_port_enable);
-static int ocelot_port_open(struct net_device *dev)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot_port *ocelot_port = &priv->port;
- struct ocelot *ocelot = ocelot_port->ocelot;
- int port = priv->chip_port;
- int err;
-
- if (priv->serdes) {
- err = phy_set_mode_ext(priv->serdes, PHY_MODE_ETHERNET,
- ocelot_port->phy_mode);
- if (err) {
- netdev_err(dev, "Could not set mode of SerDes\n");
- return err;
- }
- }
-
- err = phy_connect_direct(dev, priv->phy, &ocelot_port_adjust_link,
- ocelot_port->phy_mode);
- if (err) {
- netdev_err(dev, "Could not attach to PHY\n");
- return err;
- }
-
- dev->phydev = priv->phy;
-
- phy_attached_info(priv->phy);
- phy_start(priv->phy);
-
- ocelot_port_enable(ocelot, port, priv->phy);
-
- return 0;
-}
-
void ocelot_port_disable(struct ocelot *ocelot, int port)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
@@ -558,41 +428,6 @@ void ocelot_port_disable(struct ocelot *ocelot, int port)
}
EXPORT_SYMBOL(ocelot_port_disable);
-static int ocelot_port_stop(struct net_device *dev)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
-
- phy_disconnect(priv->phy);
-
- dev->phydev = NULL;
-
- ocelot_port_disable(ocelot, port);
-
- return 0;
-}
-
-/* Generate the IFH for frame injection
- *
- * The IFH is a 128bit-value
- * bit 127: bypass the analyzer processing
- * bit 56-67: destination mask
- * bit 28-29: pop_cnt: 3 disables all rewriting of the frame
- * bit 20-27: cpu extraction queue mask
- * bit 16: tag type 0: C-tag, 1: S-tag
- * bit 0-11: VID
- */
-static int ocelot_gen_ifh(u32 *ifh, struct frame_info *info)
-{
- ifh[0] = IFH_INJ_BYPASS | ((0x1ff & info->rew_op) << 21);
- ifh[1] = (0xf00 & info->port) >> 8;
- ifh[2] = (0xff & info->port) << 24;
- ifh[3] = (info->tag_type << 16) | info->vid;
-
- return 0;
-}
-
int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port,
struct sk_buff *skb)
{
@@ -611,77 +446,6 @@ int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port,
}
EXPORT_SYMBOL(ocelot_port_add_txtstamp_skb);
-static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- struct ocelot_port *ocelot_port = &priv->port;
- struct ocelot *ocelot = ocelot_port->ocelot;
- u32 val, ifh[OCELOT_TAG_LEN / 4];
- struct frame_info info = {};
- u8 grp = 0; /* Send everything on CPU group 0 */
- unsigned int i, count, last;
- int port = priv->chip_port;
-
- val = ocelot_read(ocelot, QS_INJ_STATUS);
- if (!(val & QS_INJ_STATUS_FIFO_RDY(BIT(grp))) ||
- (val & QS_INJ_STATUS_WMARK_REACHED(BIT(grp))))
- return NETDEV_TX_BUSY;
-
- ocelot_write_rix(ocelot, QS_INJ_CTRL_GAP_SIZE(1) |
- QS_INJ_CTRL_SOF, QS_INJ_CTRL, grp);
-
- info.port = BIT(port);
- info.tag_type = IFH_TAG_TYPE_C;
- info.vid = skb_vlan_tag_get(skb);
-
- /* Check if timestamping is needed */
- if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP) {
- info.rew_op = ocelot_port->ptp_cmd;
- if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP)
- info.rew_op |= (ocelot_port->ts_id % 4) << 3;
- }
-
- ocelot_gen_ifh(ifh, &info);
-
- for (i = 0; i < OCELOT_TAG_LEN / 4; i++)
- ocelot_write_rix(ocelot, (__force u32)cpu_to_be32(ifh[i]),
- QS_INJ_WR, grp);
-
- count = (skb->len + 3) / 4;
- last = skb->len % 4;
- for (i = 0; i < count; i++) {
- ocelot_write_rix(ocelot, ((u32 *)skb->data)[i], QS_INJ_WR, grp);
- }
-
- /* Add padding */
- while (i < (OCELOT_BUFFER_CELL_SZ / 4)) {
- ocelot_write_rix(ocelot, 0, QS_INJ_WR, grp);
- i++;
- }
-
- /* Indicate EOF and valid bytes in last word */
- ocelot_write_rix(ocelot, QS_INJ_CTRL_GAP_SIZE(1) |
- QS_INJ_CTRL_VLD_BYTES(skb->len < OCELOT_BUFFER_CELL_SZ ? 0 : last) |
- QS_INJ_CTRL_EOF,
- QS_INJ_CTRL, grp);
-
- /* Add dummy CRC */
- ocelot_write_rix(ocelot, 0, QS_INJ_WR, grp);
- skb_tx_timestamp(skb);
-
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
-
- if (!ocelot_port_add_txtstamp_skb(ocelot_port, skb)) {
- ocelot_port->ts_id++;
- return NETDEV_TX_OK;
- }
-
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
-}
-
static void ocelot_get_hwtimestamp(struct ocelot *ocelot,
struct timespec64 *ts)
{
@@ -767,113 +531,6 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
}
EXPORT_SYMBOL(ocelot_get_txtstamp);
-static int ocelot_mc_unsync(struct net_device *dev, const unsigned char *addr)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot_port *ocelot_port = &priv->port;
- struct ocelot *ocelot = ocelot_port->ocelot;
-
- return ocelot_mact_forget(ocelot, addr, ocelot_port->pvid);
-}
-
-static int ocelot_mc_sync(struct net_device *dev, const unsigned char *addr)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot_port *ocelot_port = &priv->port;
- struct ocelot *ocelot = ocelot_port->ocelot;
-
- return ocelot_mact_learn(ocelot, PGID_CPU, addr, ocelot_port->pvid,
- ENTRYTYPE_LOCKED);
-}
-
-static void ocelot_set_rx_mode(struct net_device *dev)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- u32 val;
- int i;
-
- /* This doesn't handle promiscuous mode because the bridge core is
- * setting IFF_PROMISC on all slave interfaces and all frames would be
- * forwarded to the CPU port.
- */
- val = GENMASK(ocelot->num_phys_ports - 1, 0);
- for (i = ocelot->num_phys_ports + 1; i < PGID_CPU; i++)
- ocelot_write_rix(ocelot, val, ANA_PGID_PGID, i);
-
- __dev_mc_sync(dev, ocelot_mc_sync, ocelot_mc_unsync);
-}
-
-static int ocelot_port_get_phys_port_name(struct net_device *dev,
- char *buf, size_t len)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- int port = priv->chip_port;
- int ret;
-
- ret = snprintf(buf, len, "p%d", port);
- if (ret >= len)
- return -EINVAL;
-
- return 0;
-}
-
-static int ocelot_port_set_mac_address(struct net_device *dev, void *p)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot_port *ocelot_port = &priv->port;
- struct ocelot *ocelot = ocelot_port->ocelot;
- const struct sockaddr *addr = p;
-
- /* Learn the new net device MAC address in the mac table. */
- ocelot_mact_learn(ocelot, PGID_CPU, addr->sa_data, ocelot_port->pvid,
- ENTRYTYPE_LOCKED);
- /* Then forget the previous one. */
- ocelot_mact_forget(ocelot, dev->dev_addr, ocelot_port->pvid);
-
- ether_addr_copy(dev->dev_addr, addr->sa_data);
- return 0;
-}
-
-static void ocelot_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *stats)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
-
- /* Configure the port to read the stats from */
- ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port),
- SYS_STAT_CFG);
-
- /* Get Rx stats */
- stats->rx_bytes = ocelot_read(ocelot, SYS_COUNT_RX_OCTETS);
- stats->rx_packets = ocelot_read(ocelot, SYS_COUNT_RX_SHORTS) +
- ocelot_read(ocelot, SYS_COUNT_RX_FRAGMENTS) +
- ocelot_read(ocelot, SYS_COUNT_RX_JABBERS) +
- ocelot_read(ocelot, SYS_COUNT_RX_LONGS) +
- ocelot_read(ocelot, SYS_COUNT_RX_64) +
- ocelot_read(ocelot, SYS_COUNT_RX_65_127) +
- ocelot_read(ocelot, SYS_COUNT_RX_128_255) +
- ocelot_read(ocelot, SYS_COUNT_RX_256_1023) +
- ocelot_read(ocelot, SYS_COUNT_RX_1024_1526) +
- ocelot_read(ocelot, SYS_COUNT_RX_1527_MAX);
- stats->multicast = ocelot_read(ocelot, SYS_COUNT_RX_MULTICAST);
- stats->rx_dropped = dev->stats.rx_dropped;
-
- /* Get Tx stats */
- stats->tx_bytes = ocelot_read(ocelot, SYS_COUNT_TX_OCTETS);
- stats->tx_packets = ocelot_read(ocelot, SYS_COUNT_TX_64) +
- ocelot_read(ocelot, SYS_COUNT_TX_65_127) +
- ocelot_read(ocelot, SYS_COUNT_TX_128_511) +
- ocelot_read(ocelot, SYS_COUNT_TX_512_1023) +
- ocelot_read(ocelot, SYS_COUNT_TX_1024_1526) +
- ocelot_read(ocelot, SYS_COUNT_TX_1527_MAX);
- stats->tx_dropped = ocelot_read(ocelot, SYS_COUNT_TX_DROPS) +
- ocelot_read(ocelot, SYS_COUNT_TX_AGING);
- stats->collisions = ocelot_read(ocelot, SYS_COUNT_TX_COLLISION);
-}
-
int ocelot_fdb_add(struct ocelot *ocelot, int port,
const unsigned char *addr, u16 vid)
{
@@ -897,19 +554,6 @@ int ocelot_fdb_add(struct ocelot *ocelot, int port,
}
EXPORT_SYMBOL(ocelot_fdb_add);
-static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
- struct net_device *dev,
- const unsigned char *addr,
- u16 vid, u16 flags,
- struct netlink_ext_ack *extack)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
-
- return ocelot_fdb_add(ocelot, port, addr, vid);
-}
-
int ocelot_fdb_del(struct ocelot *ocelot, int port,
const unsigned char *addr, u16 vid)
{
@@ -917,26 +561,8 @@ int ocelot_fdb_del(struct ocelot *ocelot, int port,
}
EXPORT_SYMBOL(ocelot_fdb_del);
-static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
- struct net_device *dev,
- const unsigned char *addr, u16 vid)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
-
- return ocelot_fdb_del(ocelot, port, addr, vid);
-}
-
-struct ocelot_dump_ctx {
- struct net_device *dev;
- struct sk_buff *skb;
- struct netlink_callback *cb;
- int idx;
-};
-
-static int ocelot_port_fdb_do_dump(const unsigned char *addr, u16 vid,
- bool is_static, void *data)
+int ocelot_port_fdb_do_dump(const unsigned char *addr, u16 vid,
+ bool is_static, void *data)
{
struct ocelot_dump_ctx *dump = data;
u32 portid = NETLINK_CB(dump->cb->skb).portid;
@@ -977,6 +603,7 @@ nla_put_failure:
nlmsg_cancel(dump->skb, nlh);
return -EMSGSIZE;
}
+EXPORT_SYMBOL(ocelot_port_fdb_do_dump);
static int ocelot_mact_read(struct ocelot *ocelot, int port, int row, int col,
struct ocelot_mact_entry *entry)
@@ -1058,74 +685,6 @@ int ocelot_fdb_dump(struct ocelot *ocelot, int port,
}
EXPORT_SYMBOL(ocelot_fdb_dump);
-static int ocelot_port_fdb_dump(struct sk_buff *skb,
- struct netlink_callback *cb,
- struct net_device *dev,
- struct net_device *filter_dev, int *idx)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- struct ocelot_dump_ctx dump = {
- .dev = dev,
- .skb = skb,
- .cb = cb,
- .idx = *idx,
- };
- int port = priv->chip_port;
- int ret;
-
- ret = ocelot_fdb_dump(ocelot, port, ocelot_port_fdb_do_dump, &dump);
-
- *idx = dump.idx;
-
- return ret;
-}
-
-static int ocelot_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
- u16 vid)
-{
- return ocelot_vlan_vid_add(dev, vid, false, false);
-}
-
-static int ocelot_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
- u16 vid)
-{
- return ocelot_vlan_vid_del(dev, vid);
-}
-
-static int ocelot_set_features(struct net_device *dev,
- netdev_features_t features)
-{
- netdev_features_t changed = dev->features ^ features;
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
-
- if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) &&
- priv->tc.offload_cnt) {
- netdev_err(dev,
- "Cannot disable HW TC offload while offloads active\n");
- return -EBUSY;
- }
-
- if (changed & NETIF_F_HW_VLAN_CTAG_FILTER)
- ocelot_vlan_mode(ocelot, port, features);
-
- return 0;
-}
-
-static int ocelot_get_port_parent_id(struct net_device *dev,
- struct netdev_phys_item_id *ppid)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
-
- ppid->id_len = sizeof(ocelot->base_mac);
- memcpy(&ppid->id, &ocelot->base_mac, ppid->id_len);
-
- return 0;
-}
-
int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr)
{
return copy_to_user(ifr->ifr_data, &ocelot->hwtstamp_config,
@@ -1198,46 +757,6 @@ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
}
EXPORT_SYMBOL(ocelot_hwstamp_set);
-static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
-
- /* If the attached PHY device isn't capable of timestamping operations,
- * use our own (when possible).
- */
- if (!phy_has_hwtstamp(dev->phydev) && ocelot->ptp) {
- switch (cmd) {
- case SIOCSHWTSTAMP:
- return ocelot_hwstamp_set(ocelot, port, ifr);
- case SIOCGHWTSTAMP:
- return ocelot_hwstamp_get(ocelot, port, ifr);
- }
- }
-
- return phy_mii_ioctl(dev->phydev, ifr, cmd);
-}
-
-static const struct net_device_ops ocelot_port_netdev_ops = {
- .ndo_open = ocelot_port_open,
- .ndo_stop = ocelot_port_stop,
- .ndo_start_xmit = ocelot_port_xmit,
- .ndo_set_rx_mode = ocelot_set_rx_mode,
- .ndo_get_phys_port_name = ocelot_port_get_phys_port_name,
- .ndo_set_mac_address = ocelot_port_set_mac_address,
- .ndo_get_stats64 = ocelot_get_stats64,
- .ndo_fdb_add = ocelot_port_fdb_add,
- .ndo_fdb_del = ocelot_port_fdb_del,
- .ndo_fdb_dump = ocelot_port_fdb_dump,
- .ndo_vlan_rx_add_vid = ocelot_vlan_rx_add_vid,
- .ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid,
- .ndo_set_features = ocelot_set_features,
- .ndo_get_port_parent_id = ocelot_get_port_parent_id,
- .ndo_setup_tc = ocelot_setup_tc,
- .ndo_do_ioctl = ocelot_ioctl,
-};
-
void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
{
int i;
@@ -1251,16 +770,6 @@ void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
}
EXPORT_SYMBOL(ocelot_get_strings);
-static void ocelot_port_get_strings(struct net_device *netdev, u32 sset,
- u8 *data)
-{
- struct ocelot_port_private *priv = netdev_priv(netdev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
-
- ocelot_get_strings(ocelot, port, sset, data);
-}
-
static void ocelot_update_stats(struct ocelot *ocelot)
{
int i, j;
@@ -1314,17 +823,6 @@ void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
}
EXPORT_SYMBOL(ocelot_get_ethtool_stats);
-static void ocelot_port_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *stats,
- u64 *data)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
-
- ocelot_get_ethtool_stats(ocelot, port, data);
-}
-
int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
{
if (sset != ETH_SS_STATS)
@@ -1334,15 +832,6 @@ int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
}
EXPORT_SYMBOL(ocelot_get_sset_count);
-static int ocelot_port_get_sset_count(struct net_device *dev, int sset)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
-
- return ocelot_get_sset_count(ocelot, port, sset);
-}
-
int ocelot_get_ts_info(struct ocelot *ocelot, int port,
struct ethtool_ts_info *info)
{
@@ -1368,28 +857,6 @@ int ocelot_get_ts_info(struct ocelot *ocelot, int port,
}
EXPORT_SYMBOL(ocelot_get_ts_info);
-static int ocelot_port_get_ts_info(struct net_device *dev,
- struct ethtool_ts_info *info)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
-
- if (!ocelot->ptp)
- return ethtool_op_get_ts_info(dev, info);
-
- return ocelot_get_ts_info(ocelot, port, info);
-}
-
-static const struct ethtool_ops ocelot_ethtool_ops = {
- .get_strings = ocelot_port_get_strings,
- .get_ethtool_stats = ocelot_port_get_ethtool_stats,
- .get_sset_count = ocelot_port_get_sset_count,
- .get_link_ksettings = phy_ethtool_get_link_ksettings,
- .set_link_ksettings = phy_ethtool_set_link_ksettings,
- .get_ts_info = ocelot_port_get_ts_info,
-};
-
void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state)
{
u32 port_cfg;
@@ -1445,16 +912,6 @@ void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state)
}
EXPORT_SYMBOL(ocelot_bridge_stp_state_set);
-static void ocelot_port_attr_stp_state_set(struct ocelot *ocelot, int port,
- struct switchdev_trans *trans,
- u8 state)
-{
- if (switchdev_trans_ph_prepare(trans))
- return;
-
- ocelot_bridge_stp_state_set(ocelot, port, state);
-}
-
void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs)
{
unsigned int age_period = ANA_AUTOAGE_AGE_PERIOD(msecs / 2000);
@@ -1469,95 +926,6 @@ void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs)
}
EXPORT_SYMBOL(ocelot_set_ageing_time);
-static void ocelot_port_attr_ageing_set(struct ocelot *ocelot, int port,
- unsigned long ageing_clock_t)
-{
- unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
- u32 ageing_time = jiffies_to_msecs(ageing_jiffies);
-
- ocelot_set_ageing_time(ocelot, ageing_time);
-}
-
-static void ocelot_port_attr_mc_set(struct ocelot *ocelot, int port, bool mc)
-{
- u32 cpu_fwd_mcast = ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA |
- ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA |
- ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA;
- u32 val = 0;
-
- if (mc)
- val = cpu_fwd_mcast;
-
- ocelot_rmw_gix(ocelot, val, cpu_fwd_mcast,
- ANA_PORT_CPU_FWD_CFG, port);
-}
-
-static int ocelot_port_attr_set(struct net_device *dev,
- const struct switchdev_attr *attr,
- struct switchdev_trans *trans)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot *ocelot = priv->port.ocelot;
- int port = priv->chip_port;
- int err = 0;
-
- switch (attr->id) {
- case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
- ocelot_port_attr_stp_state_set(ocelot, port, trans,
- attr->u.stp_state);
- break;
- case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
- ocelot_port_attr_ageing_set(ocelot, port, attr->u.ageing_time);
- break;
- case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
- ocelot_port_vlan_filtering(ocelot, port,
- attr->u.vlan_filtering);
- break;
- case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
- ocelot_port_attr_mc_set(ocelot, port, !attr->u.mc_disabled);
- break;
- default:
- err = -EOPNOTSUPP;
- break;
- }
-
- return err;
-}
-
-static int ocelot_port_obj_add_vlan(struct net_device *dev,
- const struct switchdev_obj_port_vlan *vlan,
- struct switchdev_trans *trans)
-{
- int ret;
- u16 vid;
-
- for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
- ret = ocelot_vlan_vid_add(dev, vid,
- vlan->flags & BRIDGE_VLAN_INFO_PVID,
- vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int ocelot_port_vlan_del_vlan(struct net_device *dev,
- const struct switchdev_obj_port_vlan *vlan)
-{
- int ret;
- u16 vid;
-
- for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
- ret = ocelot_vlan_vid_del(dev, vid);
-
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
static struct ocelot_multicast *ocelot_multicast_get(struct ocelot *ocelot,
const unsigned char *addr,
u16 vid)
@@ -1572,9 +940,9 @@ static struct ocelot_multicast *ocelot_multicast_get(struct ocelot *ocelot,
return NULL;
}
-static int ocelot_port_obj_add_mdb(struct net_device *dev,
- const struct switchdev_obj_port_mdb *mdb,
- struct switchdev_trans *trans)
+int ocelot_port_obj_add_mdb(struct net_device *dev,
+ const struct switchdev_obj_port_mdb *mdb,
+ struct switchdev_trans *trans)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot_port *ocelot_port = &priv->port;
@@ -1616,9 +984,10 @@ static int ocelot_port_obj_add_mdb(struct net_device *dev,
return ocelot_mact_learn(ocelot, 0, addr, vid, ENTRYTYPE_MACv4);
}
+EXPORT_SYMBOL(ocelot_port_obj_add_mdb);
-static int ocelot_port_obj_del_mdb(struct net_device *dev,
- const struct switchdev_obj_port_mdb *mdb)
+int ocelot_port_obj_del_mdb(struct net_device *dev,
+ const struct switchdev_obj_port_mdb *mdb)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot_port *ocelot_port = &priv->port;
@@ -1653,50 +1022,7 @@ static int ocelot_port_obj_del_mdb(struct net_device *dev,
return ocelot_mact_learn(ocelot, 0, addr, vid, ENTRYTYPE_MACv4);
}
-
-static int ocelot_port_obj_add(struct net_device *dev,
- const struct switchdev_obj *obj,
- struct switchdev_trans *trans,
- struct netlink_ext_ack *extack)
-{
- int ret = 0;
-
- switch (obj->id) {
- case SWITCHDEV_OBJ_ID_PORT_VLAN:
- ret = ocelot_port_obj_add_vlan(dev,
- SWITCHDEV_OBJ_PORT_VLAN(obj),
- trans);
- break;
- case SWITCHDEV_OBJ_ID_PORT_MDB:
- ret = ocelot_port_obj_add_mdb(dev, SWITCHDEV_OBJ_PORT_MDB(obj),
- trans);
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return ret;
-}
-
-static int ocelot_port_obj_del(struct net_device *dev,
- const struct switchdev_obj *obj)
-{
- int ret = 0;
-
- switch (obj->id) {
- case SWITCHDEV_OBJ_ID_PORT_VLAN:
- ret = ocelot_port_vlan_del_vlan(dev,
- SWITCHDEV_OBJ_PORT_VLAN(obj));
- break;
- case SWITCHDEV_OBJ_ID_PORT_MDB:
- ret = ocelot_port_obj_del_mdb(dev, SWITCHDEV_OBJ_PORT_MDB(obj));
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return ret;
-}
+EXPORT_SYMBOL(ocelot_port_obj_del_mdb);
int ocelot_port_bridge_join(struct ocelot *ocelot, int port,
struct net_device *bridge)
@@ -1788,8 +1114,8 @@ static void ocelot_setup_lag(struct ocelot *ocelot, int lag)
}
}
-static int ocelot_port_lag_join(struct ocelot *ocelot, int port,
- struct net_device *bond)
+int ocelot_port_lag_join(struct ocelot *ocelot, int port,
+ struct net_device *bond)
{
struct net_device *ndev;
u32 bond_mask = 0;
@@ -1826,9 +1152,10 @@ static int ocelot_port_lag_join(struct ocelot *ocelot, int port,
return 0;
}
+EXPORT_SYMBOL(ocelot_port_lag_join);
-static void ocelot_port_lag_leave(struct ocelot *ocelot, int port,
- struct net_device *bond)
+void ocelot_port_lag_leave(struct ocelot *ocelot, int port,
+ struct net_device *bond)
{
u32 port_cfg;
int i;
@@ -1856,151 +1183,7 @@ static void ocelot_port_lag_leave(struct ocelot *ocelot, int port,
ocelot_set_aggr_pgids(ocelot);
}
-
-/* Checks if the net_device instance given to us originate from our driver. */
-static bool ocelot_netdevice_dev_check(const struct net_device *dev)
-{
- return dev->netdev_ops == &ocelot_port_netdev_ops;
-}
-
-static int ocelot_netdevice_port_event(struct net_device *dev,
- unsigned long event,
- struct netdev_notifier_changeupper_info *info)
-{
- struct ocelot_port_private *priv = netdev_priv(dev);
- struct ocelot_port *ocelot_port = &priv->port;
- struct ocelot *ocelot = ocelot_port->ocelot;
- int port = priv->chip_port;
- int err = 0;
-
- switch (event) {
- case NETDEV_CHANGEUPPER:
- if (netif_is_bridge_master(info->upper_dev)) {
- if (info->linking) {
- err = ocelot_port_bridge_join(ocelot, port,
- info->upper_dev);
- } else {
- err = ocelot_port_bridge_leave(ocelot, port,
- info->upper_dev);
- }
- }
- if (netif_is_lag_master(info->upper_dev)) {
- if (info->linking)
- err = ocelot_port_lag_join(ocelot, port,
- info->upper_dev);
- else
- ocelot_port_lag_leave(ocelot, port,
- info->upper_dev);
- }
- break;
- default:
- break;
- }
-
- return err;
-}
-
-static int ocelot_netdevice_event(struct notifier_block *unused,
- unsigned long event, void *ptr)
-{
- struct netdev_notifier_changeupper_info *info = ptr;
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- int ret = 0;
-
- if (!ocelot_netdevice_dev_check(dev))
- return 0;
-
- if (event == NETDEV_PRECHANGEUPPER &&
- netif_is_lag_master(info->upper_dev)) {
- struct netdev_lag_upper_info *lag_upper_info = info->upper_info;
- struct netlink_ext_ack *extack;
-
- if (lag_upper_info &&
- lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
- extack = netdev_notifier_info_to_extack(&info->info);
- NL_SET_ERR_MSG_MOD(extack, "LAG device using unsupported Tx type");
-
- ret = -EINVAL;
- goto notify;
- }
- }
-
- if (netif_is_lag_master(dev)) {
- struct net_device *slave;
- struct list_head *iter;
-
- netdev_for_each_lower_dev(dev, slave, iter) {
- ret = ocelot_netdevice_port_event(slave, event, info);
- if (ret)
- goto notify;