ocelot.c (8fd1a4affbdafda592f80cd01bf7a382a5ff2fe8) ocelot.c (639c1b2625af66501b24c8082231a83d4f5ad56b)
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
2/*
3 * Microsemi Ocelot Switch driver
4 *
5 * Copyright (c) 2017 Microsemi Corporation
6 */
7#include <linux/etherdevice.h>
8#include <linux/ethtool.h>
9#include <linux/if_bridge.h>
10#include <linux/if_ether.h>
11#include <linux/if_vlan.h>
12#include <linux/interrupt.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/netdevice.h>
16#include <linux/phy.h>
17#include <linux/skbuff.h>
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
2/*
3 * Microsemi Ocelot Switch driver
4 *
5 * Copyright (c) 2017 Microsemi Corporation
6 */
7#include <linux/etherdevice.h>
8#include <linux/ethtool.h>
9#include <linux/if_bridge.h>
10#include <linux/if_ether.h>
11#include <linux/if_vlan.h>
12#include <linux/interrupt.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/netdevice.h>
16#include <linux/phy.h>
17#include <linux/skbuff.h>
18#include <linux/iopoll.h>
18#include <net/arp.h>
19#include <net/netevent.h>
20#include <net/rtnetlink.h>
21#include <net/switchdev.h>
22
23#include "ocelot.h"
24
19#include <net/arp.h>
20#include <net/netevent.h>
21#include <net/rtnetlink.h>
22#include <net/switchdev.h>
23
24#include "ocelot.h"
25
26#define TABLE_UPDATE_SLEEP_US 10
27#define TABLE_UPDATE_TIMEOUT_US 100000
28
25/* MAC table entry types.
26 * ENTRYTYPE_NORMAL is subject to aging.
27 * ENTRYTYPE_LOCKED is not subject to aging.
28 * ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast.
29 * ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast.
30 */
31enum macaccess_entry_type {
32 ENTRYTYPE_NORMAL = 0,
33 ENTRYTYPE_LOCKED,
34 ENTRYTYPE_MACv4,
35 ENTRYTYPE_MACv6,
36};
37
38struct ocelot_mact_entry {
39 u8 mac[ETH_ALEN];
40 u16 vid;
41 enum macaccess_entry_type type;
42};
43
29/* MAC table entry types.
30 * ENTRYTYPE_NORMAL is subject to aging.
31 * ENTRYTYPE_LOCKED is not subject to aging.
32 * ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast.
33 * ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast.
34 */
35enum macaccess_entry_type {
36 ENTRYTYPE_NORMAL = 0,
37 ENTRYTYPE_LOCKED,
38 ENTRYTYPE_MACv4,
39 ENTRYTYPE_MACv6,
40};
41
42struct ocelot_mact_entry {
43 u8 mac[ETH_ALEN];
44 u16 vid;
45 enum macaccess_entry_type type;
46};
47
48static inline u32 ocelot_mact_read_macaccess(struct ocelot *ocelot)
49{
50 return ocelot_read(ocelot, ANA_TABLES_MACACCESS);
51}
52
44static inline int ocelot_mact_wait_for_completion(struct ocelot *ocelot)
45{
53static inline int ocelot_mact_wait_for_completion(struct ocelot *ocelot)
54{
46 unsigned int val, timeout = 10;
55 u32 val;
47
56
48 /* Wait for the issued mac table command to be completed, or timeout.
49 * When the command read from ANA_TABLES_MACACCESS is
50 * MACACCESS_CMD_IDLE, the issued command completed successfully.
51 */
52 do {
53 val = ocelot_read(ocelot, ANA_TABLES_MACACCESS);
54 val &= ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M;
55 } while (val != MACACCESS_CMD_IDLE && timeout--);
56
57 if (!timeout)
58 return -ETIMEDOUT;
59
60 return 0;
57 return readx_poll_timeout(ocelot_mact_read_macaccess,
58 ocelot, val,
59 (val & ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M) ==
60 MACACCESS_CMD_IDLE,
61 TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US);
61}
62
63static void ocelot_mact_select(struct ocelot *ocelot,
64 const unsigned char mac[ETH_ALEN],
65 unsigned int vid)
66{
67 u32 macl = 0, mach = 0;
68

--- 55 unchanged lines hidden (view full) ---

124 | ANA_AGENCTRL_LEARN_FWD_KILL
125 | ANA_AGENCTRL_LEARN_IGNORE_VLAN,
126 ANA_AGENCTRL);
127
128 /* Clear the MAC table */
129 ocelot_write(ocelot, MACACCESS_CMD_INIT, ANA_TABLES_MACACCESS);
130}
131
62}
63
64static void ocelot_mact_select(struct ocelot *ocelot,
65 const unsigned char mac[ETH_ALEN],
66 unsigned int vid)
67{
68 u32 macl = 0, mach = 0;
69

--- 55 unchanged lines hidden (view full) ---

125 | ANA_AGENCTRL_LEARN_FWD_KILL
126 | ANA_AGENCTRL_LEARN_IGNORE_VLAN,
127 ANA_AGENCTRL);
128
129 /* Clear the MAC table */
130 ocelot_write(ocelot, MACACCESS_CMD_INIT, ANA_TABLES_MACACCESS);
131}
132
133static inline u32 ocelot_vlant_read_vlanaccess(struct ocelot *ocelot)
134{
135 return ocelot_read(ocelot, ANA_TABLES_VLANACCESS);
136}
137
132static inline int ocelot_vlant_wait_for_completion(struct ocelot *ocelot)
133{
138static inline int ocelot_vlant_wait_for_completion(struct ocelot *ocelot)
139{
134 unsigned int val, timeout = 10;
140 u32 val;
135
141
136 /* Wait for the issued vlan table command to be completed, or timeout.
137 * When the command read from ANA_TABLES_VLANACCESS is
138 * VLANACCESS_CMD_IDLE, the issued command completed successfully.
139 */
140 do {
141 val = ocelot_read(ocelot, ANA_TABLES_VLANACCESS);
142 val &= ANA_TABLES_VLANACCESS_VLAN_TBL_CMD_M;
143 } while (val != ANA_TABLES_VLANACCESS_CMD_IDLE && timeout--);
144
145 if (!timeout)
146 return -ETIMEDOUT;
147
148 return 0;
142 return readx_poll_timeout(ocelot_vlant_read_vlanaccess,
143 ocelot,
144 val,
145 (val & ANA_TABLES_VLANACCESS_VLAN_TBL_CMD_M) ==
146 ANA_TABLES_VLANACCESS_CMD_IDLE,
147 TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US);
149}
150
151static int ocelot_vlant_set_mask(struct ocelot *ocelot, u16 vid, u32 mask)
152{
153 /* Select the VID to configure */
154 ocelot_write(ocelot, ANA_TABLES_VLANTIDX_V_INDEX(vid),
155 ANA_TABLES_VLANTIDX);
156 /* Set the vlan port members mask and issue a write command */

--- 585 unchanged lines hidden (view full) ---

742 else
743 /* If the bridge is VLAN aware a VID must be provided as
744 * otherwise the learnt entry wouldn't match any frame.
745 */
746 return -EINVAL;
747 }
748
749 return ocelot_mact_learn(ocelot, port->chip_port, addr, vid,
148}
149
150static int ocelot_vlant_set_mask(struct ocelot *ocelot, u16 vid, u32 mask)
151{
152 /* Select the VID to configure */
153 ocelot_write(ocelot, ANA_TABLES_VLANTIDX_V_INDEX(vid),
154 ANA_TABLES_VLANTIDX);
155 /* Set the vlan port members mask and issue a write command */

--- 585 unchanged lines hidden (view full) ---

741 else
742 /* If the bridge is VLAN aware a VID must be provided as
743 * otherwise the learnt entry wouldn't match any frame.
744 */
745 return -EINVAL;
746 }
747
748 return ocelot_mact_learn(ocelot, port->chip_port, addr, vid,
750 ENTRYTYPE_LOCKED);
749 ENTRYTYPE_NORMAL);
751}
752
753static int ocelot_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
754 struct net_device *dev,
755 const unsigned char *addr, u16 vid)
756{
757 struct ocelot_port *port = netdev_priv(dev);
758 struct ocelot *ocelot = port->ocelot;

--- 529 unchanged lines hidden (view full) ---

1288 addr[2] = mc->ports << 0;
1289 addr[1] = mc->ports << 8;
1290
1291 return ocelot_mact_learn(ocelot, 0, addr, vid, ENTRYTYPE_MACv4);
1292}
1293
1294static int ocelot_port_obj_add(struct net_device *dev,
1295 const struct switchdev_obj *obj,
750}
751
752static int ocelot_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
753 struct net_device *dev,
754 const unsigned char *addr, u16 vid)
755{
756 struct ocelot_port *port = netdev_priv(dev);
757 struct ocelot *ocelot = port->ocelot;

--- 529 unchanged lines hidden (view full) ---

1287 addr[2] = mc->ports << 0;
1288 addr[1] = mc->ports << 8;
1289
1290 return ocelot_mact_learn(ocelot, 0, addr, vid, ENTRYTYPE_MACv4);
1291}
1292
1293static int ocelot_port_obj_add(struct net_device *dev,
1294 const struct switchdev_obj *obj,
1296 struct switchdev_trans *trans)
1295 struct switchdev_trans *trans,
1296 struct netlink_ext_ack *extack)
1297{
1298 int ret = 0;
1299
1300 switch (obj->id) {
1301 case SWITCHDEV_OBJ_ID_PORT_VLAN:
1302 ret = ocelot_port_obj_add_vlan(dev,
1303 SWITCHDEV_OBJ_PORT_VLAN(obj),
1304 trans);

--- 27 unchanged lines hidden (view full) ---

1332 }
1333
1334 return ret;
1335}
1336
1337static const struct switchdev_ops ocelot_port_switchdev_ops = {
1338 .switchdev_port_attr_get = ocelot_port_attr_get,
1339 .switchdev_port_attr_set = ocelot_port_attr_set,
1297{
1298 int ret = 0;
1299
1300 switch (obj->id) {
1301 case SWITCHDEV_OBJ_ID_PORT_VLAN:
1302 ret = ocelot_port_obj_add_vlan(dev,
1303 SWITCHDEV_OBJ_PORT_VLAN(obj),
1304 trans);

--- 27 unchanged lines hidden (view full) ---

1332 }
1333
1334 return ret;
1335}
1336
1337static const struct switchdev_ops ocelot_port_switchdev_ops = {
1338 .switchdev_port_attr_get = ocelot_port_attr_get,
1339 .switchdev_port_attr_set = ocelot_port_attr_set,
1340 .switchdev_port_obj_add = ocelot_port_obj_add,
1341 .switchdev_port_obj_del = ocelot_port_obj_del,
1342};
1343
1344static int ocelot_port_bridge_join(struct ocelot_port *ocelot_port,
1345 struct net_device *bridge)
1346{
1347 struct ocelot *ocelot = ocelot_port->ocelot;
1348
1349 if (!ocelot->bridge_mask) {

--- 240 unchanged lines hidden (view full) ---

1590 return notifier_from_errno(ret);
1591}
1592
1593struct notifier_block ocelot_netdevice_nb __read_mostly = {
1594 .notifier_call = ocelot_netdevice_event,
1595};
1596EXPORT_SYMBOL(ocelot_netdevice_nb);
1597
1340};
1341
1342static int ocelot_port_bridge_join(struct ocelot_port *ocelot_port,
1343 struct net_device *bridge)
1344{
1345 struct ocelot *ocelot = ocelot_port->ocelot;
1346
1347 if (!ocelot->bridge_mask) {

--- 240 unchanged lines hidden (view full) ---

1588 return notifier_from_errno(ret);
1589}
1590
1591struct notifier_block ocelot_netdevice_nb __read_mostly = {
1592 .notifier_call = ocelot_netdevice_event,
1593};
1594EXPORT_SYMBOL(ocelot_netdevice_nb);
1595
1596static int ocelot_switchdev_blocking_event(struct notifier_block *unused,
1597 unsigned long event, void *ptr)
1598{
1599 struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
1600 int err;
1601
1602 switch (event) {
1603 /* Blocking events. */
1604 case SWITCHDEV_PORT_OBJ_ADD:
1605 err = switchdev_handle_port_obj_add(dev, ptr,
1606 ocelot_netdevice_dev_check,
1607 ocelot_port_obj_add);
1608 return notifier_from_errno(err);
1609 case SWITCHDEV_PORT_OBJ_DEL:
1610 err = switchdev_handle_port_obj_del(dev, ptr,
1611 ocelot_netdevice_dev_check,
1612 ocelot_port_obj_del);
1613 return notifier_from_errno(err);
1614 }
1615
1616 return NOTIFY_DONE;
1617}
1618
1619struct notifier_block ocelot_switchdev_blocking_nb __read_mostly = {
1620 .notifier_call = ocelot_switchdev_blocking_event,
1621};
1622EXPORT_SYMBOL(ocelot_switchdev_blocking_nb);
1623
1598int ocelot_probe_port(struct ocelot *ocelot, u8 port,
1599 void __iomem *regs,
1600 struct phy_device *phy)
1601{
1602 struct ocelot_port *ocelot_port;
1603 struct net_device *dev;
1604 int err;
1605

--- 184 unchanged lines hidden ---
1624int ocelot_probe_port(struct ocelot *ocelot, u8 port,
1625 void __iomem *regs,
1626 struct phy_device *phy)
1627{
1628 struct ocelot_port *ocelot_port;
1629 struct net_device *dev;
1630 int err;
1631

--- 184 unchanged lines hidden ---