1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2 /*
3  * Copyright (c) 2018 Microsemi Corporation
4  */
5 
6 #include <errno.h>
7 #include <linux/bitops.h>
8 #include <linux/io.h>
9 #include "mscc_mac_table.h"
10 
11 #define ANA_TABLES_MACACCESS_VALID		BIT(11)
12 #define ANA_TABLES_MACACCESS_ENTRYTYPE(x)	((x) << 9)
13 #define ANA_TABLES_MACACCESS_DEST_IDX(x)	((x) << 3)
14 #define ANA_TABLES_MACACCESS_MAC_TABLE_CMD(x)	(x)
15 #define ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M	GENMASK(2, 0)
16 #define MACACCESS_CMD_IDLE			0
17 #define MACACCESS_CMD_LEARN			1
18 
19 /* MAC table entry types.
20  * ENTRYTYPE_NORMAL is subject to aging.
21  * ENTRYTYPE_LOCKED is not subject to aging.
22  */
23 enum macaccess_entry_type {
24 	ENTRYTYPE_NORMAL = 0,
25 	ENTRYTYPE_LOCKED,
26 };
27 
vlan_wait_for_completion(void __iomem * regs,const unsigned long * mscc_mac_table_offset)28 static int vlan_wait_for_completion(void __iomem *regs,
29 				    const unsigned long *mscc_mac_table_offset)
30 {
31 	unsigned int val, timeout = 10;
32 
33 	/* Wait for the issued mac table command to be completed, or timeout.
34 	 * When the command read from ANA_TABLES_MACACCESS is
35 	 * MACACCESS_CMD_IDLE, the issued command completed successfully.
36 	 */
37 	do {
38 		val = readl(regs +
39 			    mscc_mac_table_offset[MSCC_ANA_TABLES_MACACCESS]);
40 		val &= ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M;
41 	} while (val != MACACCESS_CMD_IDLE && timeout--);
42 
43 	if (!timeout)
44 		return -ETIMEDOUT;
45 
46 	return 0;
47 }
48 
mscc_mac_table_add(void __iomem * regs,const unsigned long * mscc_mac_table_offset,const unsigned char mac[ETH_LEN],int pgid)49 int mscc_mac_table_add(void __iomem *regs,
50 		       const unsigned long *mscc_mac_table_offset,
51 		       const unsigned char mac[ETH_LEN], int pgid)
52 {
53 	u32 macl = 0, mach = 0;
54 
55 	/* Set the MAC address to handle and the vlan associated in a format
56 	 * understood by the hardware.
57 	 */
58 	mach |= MAC_VID << 16;
59 	mach |= ((u32)mac[0]) << 8;
60 	mach |= ((u32)mac[1]) << 0;
61 	macl |= ((u32)mac[2]) << 24;
62 	macl |= ((u32)mac[3]) << 16;
63 	macl |= ((u32)mac[4]) << 8;
64 	macl |= ((u32)mac[5]) << 0;
65 
66 	writel(macl, regs + mscc_mac_table_offset[MSCC_ANA_TABLES_MACLDATA]);
67 	writel(mach, regs + mscc_mac_table_offset[MSCC_ANA_TABLES_MACHDATA]);
68 
69 	writel(ANA_TABLES_MACACCESS_VALID |
70 	       ANA_TABLES_MACACCESS_DEST_IDX(pgid) |
71 	       ANA_TABLES_MACACCESS_ENTRYTYPE(ENTRYTYPE_LOCKED) |
72 	       ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN),
73 	       regs + mscc_mac_table_offset[MSCC_ANA_TABLES_MACACCESS]);
74 
75 	return vlan_wait_for_completion(regs, mscc_mac_table_offset);
76 }
77