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 --- |