| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) | |
| /* | |
| * Copyright (c) 2018 Microsemi Corporation | |
| */ | |
| #include <errno.h> | |
| #include <linux/bitops.h> | |
| #include <linux/io.h> | |
| #include "mscc_mac_table.h" | |
| #define ANA_TABLES_MACACCESS_VALID BIT(11) | |
| #define ANA_TABLES_MACACCESS_ENTRYTYPE(x) ((x) << 9) | |
| #define ANA_TABLES_MACACCESS_DEST_IDX(x) ((x) << 3) | |
| #define ANA_TABLES_MACACCESS_MAC_TABLE_CMD(x) (x) | |
| #define ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M GENMASK(2, 0) | |
| #define MACACCESS_CMD_IDLE 0 | |
| #define MACACCESS_CMD_LEARN 1 | |
| /* MAC table entry types. | |
| * ENTRYTYPE_NORMAL is subject to aging. | |
| * ENTRYTYPE_LOCKED is not subject to aging. | |
| */ | |
| enum macaccess_entry_type { | |
| ENTRYTYPE_NORMAL = 0, | |
| ENTRYTYPE_LOCKED, | |
| }; | |
| static int vlan_wait_for_completion(void __iomem *regs, | |
| const unsigned long *mscc_mac_table_offset) | |
| { | |
| unsigned int val, timeout = 10; | |
| /* Wait for the issued mac table command to be completed, or timeout. | |
| * When the command read from ANA_TABLES_MACACCESS is | |
| * MACACCESS_CMD_IDLE, the issued command completed successfully. | |
| */ | |
| do { | |
| val = readl(regs + | |
| mscc_mac_table_offset[MSCC_ANA_TABLES_MACACCESS]); | |
| val &= ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M; | |
| } while (val != MACACCESS_CMD_IDLE && timeout--); | |
| if (!timeout) | |
| return -ETIMEDOUT; | |
| return 0; | |
| } | |
| int mscc_mac_table_add(void __iomem *regs, | |
| const unsigned long *mscc_mac_table_offset, | |
| const unsigned char mac[ETH_LEN], int pgid) | |
| { | |
| u32 macl = 0, mach = 0; | |
| /* Set the MAC address to handle and the vlan associated in a format | |
| * understood by the hardware. | |
| */ | |
| mach |= MAC_VID << 16; | |
| mach |= ((u32)mac[0]) << 8; | |
| mach |= ((u32)mac[1]) << 0; | |
| macl |= ((u32)mac[2]) << 24; | |
| macl |= ((u32)mac[3]) << 16; | |
| macl |= ((u32)mac[4]) << 8; | |
| macl |= ((u32)mac[5]) << 0; | |
| writel(macl, regs + mscc_mac_table_offset[MSCC_ANA_TABLES_MACLDATA]); | |
| writel(mach, regs + mscc_mac_table_offset[MSCC_ANA_TABLES_MACHDATA]); | |
| writel(ANA_TABLES_MACACCESS_VALID | | |
| ANA_TABLES_MACACCESS_DEST_IDX(pgid) | | |
| ANA_TABLES_MACACCESS_ENTRYTYPE(ENTRYTYPE_LOCKED) | | |
| ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN), | |
| regs + mscc_mac_table_offset[MSCC_ANA_TABLES_MACACCESS]); | |
| return vlan_wait_for_completion(regs, mscc_mac_table_offset); | |
| } |