Skip to content

Commit e18aba8

Browse files
HoratiuVulturdavem330
authored andcommitted
net: lan966x: add mactable support
This patch adds support for MAC table operations like add and forget. Also add the functionality to read the MAC address from DT, if there is no MAC set in DT it would use a random one. Signed-off-by: Horatiu Vultur <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d28d6d2 commit e18aba8

File tree

4 files changed

+208
-1
lines changed

4 files changed

+208
-1
lines changed

drivers/net/ethernet/microchip/lan966x/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55

66
obj-$(CONFIG_LAN966X_SWITCH) += lan966x-switch.o
77

8-
lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o
8+
lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \
9+
lan966x_mac.o
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
3+
#include "lan966x_main.h"
4+
5+
#define LAN966X_MAC_COLUMNS 4
6+
#define MACACCESS_CMD_IDLE 0
7+
#define MACACCESS_CMD_LEARN 1
8+
#define MACACCESS_CMD_FORGET 2
9+
#define MACACCESS_CMD_AGE 3
10+
#define MACACCESS_CMD_GET_NEXT 4
11+
#define MACACCESS_CMD_INIT 5
12+
#define MACACCESS_CMD_READ 6
13+
#define MACACCESS_CMD_WRITE 7
14+
#define MACACCESS_CMD_SYNC_GET_NEXT 8
15+
16+
static int lan966x_mac_get_status(struct lan966x *lan966x)
17+
{
18+
return lan_rd(lan966x, ANA_MACACCESS);
19+
}
20+
21+
static int lan966x_mac_wait_for_completion(struct lan966x *lan966x)
22+
{
23+
u32 val;
24+
25+
return readx_poll_timeout(lan966x_mac_get_status,
26+
lan966x, val,
27+
(ANA_MACACCESS_MAC_TABLE_CMD_GET(val)) ==
28+
MACACCESS_CMD_IDLE,
29+
TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US);
30+
}
31+
32+
static void lan966x_mac_select(struct lan966x *lan966x,
33+
const unsigned char mac[ETH_ALEN],
34+
unsigned int vid)
35+
{
36+
u32 macl = 0, mach = 0;
37+
38+
/* Set the MAC address to handle and the vlan associated in a format
39+
* understood by the hardware.
40+
*/
41+
mach |= vid << 16;
42+
mach |= mac[0] << 8;
43+
mach |= mac[1] << 0;
44+
macl |= mac[2] << 24;
45+
macl |= mac[3] << 16;
46+
macl |= mac[4] << 8;
47+
macl |= mac[5] << 0;
48+
49+
lan_wr(macl, lan966x, ANA_MACLDATA);
50+
lan_wr(mach, lan966x, ANA_MACHDATA);
51+
}
52+
53+
int lan966x_mac_learn(struct lan966x *lan966x, int port,
54+
const unsigned char mac[ETH_ALEN],
55+
unsigned int vid,
56+
enum macaccess_entry_type type)
57+
{
58+
lan966x_mac_select(lan966x, mac, vid);
59+
60+
/* Issue a write command */
61+
lan_wr(ANA_MACACCESS_VALID_SET(1) |
62+
ANA_MACACCESS_CHANGE2SW_SET(0) |
63+
ANA_MACACCESS_DEST_IDX_SET(port) |
64+
ANA_MACACCESS_ENTRYTYPE_SET(type) |
65+
ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_LEARN),
66+
lan966x, ANA_MACACCESS);
67+
68+
return lan966x_mac_wait_for_completion(lan966x);
69+
}
70+
71+
int lan966x_mac_forget(struct lan966x *lan966x,
72+
const unsigned char mac[ETH_ALEN],
73+
unsigned int vid,
74+
enum macaccess_entry_type type)
75+
{
76+
lan966x_mac_select(lan966x, mac, vid);
77+
78+
/* Issue a forget command */
79+
lan_wr(ANA_MACACCESS_ENTRYTYPE_SET(type) |
80+
ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_FORGET),
81+
lan966x, ANA_MACACCESS);
82+
83+
return lan966x_mac_wait_for_completion(lan966x);
84+
}
85+
86+
int lan966x_mac_cpu_learn(struct lan966x *lan966x, const char *addr, u16 vid)
87+
{
88+
return lan966x_mac_learn(lan966x, PGID_CPU, addr, vid, ENTRYTYPE_LOCKED);
89+
}
90+
91+
int lan966x_mac_cpu_forget(struct lan966x *lan966x, const char *addr, u16 vid)
92+
{
93+
return lan966x_mac_forget(lan966x, addr, vid, ENTRYTYPE_LOCKED);
94+
}
95+
96+
void lan966x_mac_init(struct lan966x *lan966x)
97+
{
98+
/* Clear the MAC table */
99+
lan_wr(MACACCESS_CMD_INIT, lan966x, ANA_MACACCESS);
100+
lan966x_mac_wait_for_completion(lan966x);
101+
}

drivers/net/ethernet/microchip/lan966x/lan966x_main.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,27 @@ static int lan966x_create_targets(struct platform_device *pdev,
100100
return 0;
101101
}
102102

103+
static int lan966x_port_set_mac_address(struct net_device *dev, void *p)
104+
{
105+
struct lan966x_port *port = netdev_priv(dev);
106+
struct lan966x *lan966x = port->lan966x;
107+
const struct sockaddr *addr = p;
108+
int ret;
109+
110+
/* Learn the new net device MAC address in the mac table. */
111+
ret = lan966x_mac_cpu_learn(lan966x, addr->sa_data, port->pvid);
112+
if (ret)
113+
return ret;
114+
115+
/* Then forget the previous one. */
116+
ret = lan966x_mac_cpu_forget(lan966x, dev->dev_addr, port->pvid);
117+
if (ret)
118+
return ret;
119+
120+
eth_hw_addr_set(dev, addr->sa_data);
121+
return ret;
122+
}
123+
103124
static int lan966x_port_get_phys_port_name(struct net_device *dev,
104125
char *buf, size_t len)
105126
{
@@ -311,13 +332,49 @@ static int lan966x_port_change_mtu(struct net_device *dev, int new_mtu)
311332
return 0;
312333
}
313334

335+
static int lan966x_mc_unsync(struct net_device *dev, const unsigned char *addr)
336+
{
337+
struct lan966x_port *port = netdev_priv(dev);
338+
struct lan966x *lan966x = port->lan966x;
339+
340+
return lan966x_mac_forget(lan966x, addr, port->pvid, ENTRYTYPE_LOCKED);
341+
}
342+
343+
static int lan966x_mc_sync(struct net_device *dev, const unsigned char *addr)
344+
{
345+
struct lan966x_port *port = netdev_priv(dev);
346+
struct lan966x *lan966x = port->lan966x;
347+
348+
return lan966x_mac_cpu_learn(lan966x, addr, port->pvid);
349+
}
350+
351+
static void lan966x_port_set_rx_mode(struct net_device *dev)
352+
{
353+
__dev_mc_sync(dev, lan966x_mc_sync, lan966x_mc_unsync);
354+
}
355+
356+
static int lan966x_port_get_parent_id(struct net_device *dev,
357+
struct netdev_phys_item_id *ppid)
358+
{
359+
struct lan966x_port *port = netdev_priv(dev);
360+
struct lan966x *lan966x = port->lan966x;
361+
362+
ppid->id_len = sizeof(lan966x->base_mac);
363+
memcpy(&ppid->id, &lan966x->base_mac, ppid->id_len);
364+
365+
return 0;
366+
}
367+
314368
static const struct net_device_ops lan966x_port_netdev_ops = {
315369
.ndo_open = lan966x_port_open,
316370
.ndo_stop = lan966x_port_stop,
317371
.ndo_start_xmit = lan966x_port_xmit,
318372
.ndo_change_rx_flags = lan966x_port_change_rx_flags,
319373
.ndo_change_mtu = lan966x_port_change_mtu,
374+
.ndo_set_rx_mode = lan966x_port_set_rx_mode,
320375
.ndo_get_phys_port_name = lan966x_port_get_phys_port_name,
376+
.ndo_set_mac_address = lan966x_port_set_mac_address,
377+
.ndo_get_port_parent_id = lan966x_port_get_parent_id,
321378
};
322379

323380
static int lan966x_port_xtr_status(struct lan966x *lan966x, u8 grp)
@@ -533,6 +590,11 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p,
533590
dev->netdev_ops = &lan966x_port_netdev_ops;
534591
dev->needed_headroom = IFH_LEN * sizeof(u32);
535592

593+
eth_hw_addr_gen(dev, lan966x->base_mac, p + 1);
594+
595+
lan966x_mac_learn(lan966x, PGID_CPU, dev->dev_addr, port->pvid,
596+
ENTRYTYPE_LOCKED);
597+
536598
port->phylink_config.dev = &port->dev->dev;
537599
port->phylink_config.type = PHYLINK_NETDEV;
538600
port->phylink_pcs.poll = true;
@@ -579,6 +641,9 @@ static void lan966x_init(struct lan966x *lan966x)
579641
{
580642
u32 p, i;
581643

644+
/* MAC table initialization */
645+
lan966x_mac_init(lan966x);
646+
582647
/* Flush queues */
583648
lan_wr(lan_rd(lan966x, QS_XTR_FLUSH) |
584649
GENMASK(1, 0),
@@ -749,6 +814,7 @@ static int lan966x_probe(struct platform_device *pdev)
749814
{
750815
struct fwnode_handle *ports, *portnp;
751816
struct lan966x *lan966x;
817+
u8 mac_addr[ETH_ALEN];
752818
int err, i;
753819

754820
lan966x = devm_kzalloc(&pdev->dev, sizeof(*lan966x), GFP_KERNEL);
@@ -758,6 +824,14 @@ static int lan966x_probe(struct platform_device *pdev)
758824
platform_set_drvdata(pdev, lan966x);
759825
lan966x->dev = &pdev->dev;
760826

827+
if (!device_get_mac_address(&pdev->dev, mac_addr)) {
828+
ether_addr_copy(lan966x->base_mac, mac_addr);
829+
} else {
830+
pr_info("MAC addr was not set, use random MAC\n");
831+
eth_random_addr(lan966x->base_mac);
832+
lan966x->base_mac[5] &= 0xf0;
833+
}
834+
761835
ports = device_get_named_child_node(&pdev->dev, "ethernet-ports");
762836
if (!ports)
763837
return dev_err_probe(&pdev->dev, -ENODEV,

drivers/net/ethernet/microchip/lan966x/lan966x_main.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
#define __LAN966X_MAIN_H__
55

66
#include <linux/etherdevice.h>
7+
#include <linux/jiffies.h>
78
#include <linux/phy.h>
89
#include <linux/phylink.h>
910

1011
#include "lan966x_regs.h"
1112
#include "lan966x_ifh.h"
1213

14+
#define TABLE_UPDATE_SLEEP_US 10
15+
#define TABLE_UPDATE_TIMEOUT_US 100000
16+
1317
#define LAN966X_BUFFER_CELL_SZ 64
1418
#define LAN966X_BUFFER_MEMORY (160 * 1024)
1519
#define LAN966X_BUFFER_MIN_SZ 60
@@ -39,6 +43,19 @@
3943

4044
#define CPU_PORT 8
4145

46+
/* MAC table entry types.
47+
* ENTRYTYPE_NORMAL is subject to aging.
48+
* ENTRYTYPE_LOCKED is not subject to aging.
49+
* ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast.
50+
* ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast.
51+
*/
52+
enum macaccess_entry_type {
53+
ENTRYTYPE_NORMAL = 0,
54+
ENTRYTYPE_LOCKED,
55+
ENTRYTYPE_MACV4,
56+
ENTRYTYPE_MACV6,
57+
};
58+
4259
struct lan966x_port;
4360

4461
struct lan966x {
@@ -51,6 +68,8 @@ struct lan966x {
5168

5269
int shared_queue_sz;
5370

71+
u8 base_mac[ETH_ALEN];
72+
5473
/* interrupts */
5574
int xtr_irq;
5675
};
@@ -91,6 +110,18 @@ int lan966x_port_pcs_set(struct lan966x_port *port,
91110
struct lan966x_port_config *config);
92111
void lan966x_port_init(struct lan966x_port *port);
93112

113+
int lan966x_mac_learn(struct lan966x *lan966x, int port,
114+
const unsigned char mac[ETH_ALEN],
115+
unsigned int vid,
116+
enum macaccess_entry_type type);
117+
int lan966x_mac_forget(struct lan966x *lan966x,
118+
const unsigned char mac[ETH_ALEN],
119+
unsigned int vid,
120+
enum macaccess_entry_type type);
121+
int lan966x_mac_cpu_learn(struct lan966x *lan966x, const char *addr, u16 vid);
122+
int lan966x_mac_cpu_forget(struct lan966x *lan966x, const char *addr, u16 vid);
123+
void lan966x_mac_init(struct lan966x *lan966x);
124+
94125
static inline void __iomem *lan_addr(void __iomem *base[],
95126
int id, int tinst, int tcnt,
96127
int gbase, int ginst,

0 commit comments

Comments
 (0)