#include <linux/etherdevice.h>
#include "rtl8365mb_l2.h"
#include "rtl8365mb_table.h"
#include <linux/regmap.h>
#define RTL8365MB_L2_ENTRY_SIZE 6
#define RTL8365MB_L2_UC_D0_MAC5_MSK GENMASK(7, 0)
#define RTL8365MB_L2_UC_D0_MAC4_MSK GENMASK(15, 8)
#define RTL8365MB_L2_UC_D1_MAC3_MSK GENMASK(7, 0)
#define RTL8365MB_L2_UC_D1_MAC2_MSK GENMASK(15, 8)
#define RTL8365MB_L2_UC_D2_MAC1_MSK GENMASK(7, 0)
#define RTL8365MB_L2_UC_D2_MAC0_MSK GENMASK(15, 8)
#define RTL8365MB_L2_UC_D3_VID_MSK GENMASK(11, 0)
#define RTL8365MB_L2_UC_D3_IVL_MSK GENMASK(13, 13)
#define RTL8365MB_L2_UC_D3_PORT_EXT_MSK GENMASK(15, 15)
#define RTL8365MB_L2_UC_PORT_HI_MSK GENMASK(3, 3)
#define RTL8365MB_L2_UC_D4_EFID_MSK GENMASK(2, 0)
#define RTL8365MB_L2_UC_D4_FID_MSK GENMASK(6, 3)
#define RTL8365MB_L2_UC_D4_SA_PRI_MSK GENMASK(7, 7)
#define RTL8365MB_L2_UC_D4_PORT_MSK GENMASK(10, 8)
#define RTL8365MB_L2_UC_PORT_LO_MSK GENMASK(2, 0)
#define RTL8365MB_L2_UC_D4_AGE_MSK GENMASK(13, 11)
#define RTL8365MB_L2_UC_D4_AUTH_MSK GENMASK(14, 14)
#define RTL8365MB_L2_UC_D4_SA_BLOCK_MSK GENMASK(15, 15)
#define RTL8365MB_L2_UC_D5_DA_BLOCK_MSK GENMASK(0, 0)
#define RTL8365MB_L2_UC_D5_PRIORITY_MSK GENMASK(3, 1)
#define RTL8365MB_L2_UC_D5_FWD_PRI_MSK GENMASK(4, 4)
#define RTL8365MB_L2_UC_D5_STATIC_MSK GENMASK(5, 5)
#define RTL8365MB_L2_MC_D0_MAC5_MSK GENMASK(7, 0)
#define RTL8365MB_L2_MC_D0_MAC4_MSK GENMASK(15, 8)
#define RTL8365MB_L2_MC_D1_MAC3_MSK GENMASK(7, 0)
#define RTL8365MB_L2_MC_D1_MAC2_MSK GENMASK(15, 8)
#define RTL8365MB_L2_MC_D2_MAC1_MSK GENMASK(7, 0)
#define RTL8365MB_L2_MC_D2_MAC0_MSK GENMASK(15, 8)
#define RTL8365MB_L2_MC_D3_VID_MSK GENMASK(11, 0)
#define RTL8365MB_L2_MC_D3_IVL_MSK GENMASK(13, 13)
#define RTL8365MB_L2_MC_D3_MBR_HI1_MSK GENMASK(15, 14)
#define RTL8365MB_L2_MC_MBR_HI1_MSK GENMASK(9, 8)
#define RTL8365MB_L2_MC_D4_MBR_MSK GENMASK(7, 0)
#define RTL8365MB_L2_MC_MBR_LO_MSK GENMASK(7, 0)
#define RTL8365MB_L2_MC_D4_IGMPIDX_MSK GENMASK(15, 8)
#define RTL8365MB_L2_MC_D5_IGMP_ASIC_MSK GENMASK(0, 0)
#define RTL8365MB_L2_MC_D5_PRIORITY_MSK GENMASK(3, 1)
#define RTL8365MB_L2_MC_D5_FWD_PRI_MSK GENMASK(4, 4)
#define RTL8365MB_L2_MC_D5_STATIC_MSK GENMASK(5, 5)
#define RTL8365MB_L2_MC_D5_MBR_HI2_MSK GENMASK(7, 7)
#define RTL8365MB_L2_MC_MBR_HI2_MSK GENMASK(10, 10)
#define RTL8365MB_L2_FLUSH_PORT_REG 0x0A36
#define RTL8365MB_L2_FLUSH_PORT_MSK_MSK GENMASK(7, 0)
#define RTL8365MB_L2_FLUSH_PORT_BUSY_MSK GENMASK(15, 8)
#define RTL8365MB_L2_FLUSH_PORT_EXT_REG 0x0A35
#define RTL8365MB_L2_FLUSH_PORT_EXT_MSK_MSK GENMASK(2, 0)
#define RTL8365MB_L2_FLUSH_PORT_EXT_BUSY_MSK GENMASK(5, 3)
#define RTL8365MB_L2_FLUSH_CTRL1_REG 0x0A37
#define RTL8365MB_L2_FLUSH_CTRL1_VID_MSK GENMASK(11, 0)
#define RTL8365MB_L2_FLUSH_CTRL1_FID_MSK GENMASK(15, 12)
#define RTL8365MB_L2_FLUSH_CTRL2_REG 0x0A38
#define RTL8365MB_L2_FLUSH_CTRL2_MODE_MSK GENMASK(1, 0)
#define RTL8365MB_L2_FLUSH_CTRL2_MODE_PORT 0
#define RTL8365MB_L2_FLUSH_CTRL2_MODE_PORT_VID 1
#define RTL8365MB_L2_FLUSH_CTRL2_MODE_PORT_FID 2
#define RTL8365MB_L2_FLUSH_CTRL2_TYPE_MSK GENMASK(2, 2)
#define RTL8365MB_L2_FLUSH_CTRL2_TYPE_DYNAMIC 0
#define RTL8365MB_L2_FLUSH_CTRL2_TYPE_BOTH 1
#define RTL8365MB_L2_FLUSH_CTRL3_REG 0x0A39
#define RTL8365MB_L2_FLUSH_CTRL3_MSK GENMASK(0, 0)
struct rtl8365mb_l2_uc_key {
u8 mac_addr[ETH_ALEN];
u16 vid;
u16 fid;
bool ivl;
u16 efid;
};
struct rtl8365mb_l2_uc {
struct rtl8365mb_l2_uc_key key;
u8 port;
u8 age;
u8 priority;
bool sa_block;
bool da_block;
bool auth;
bool is_static;
bool sa_pri;
bool fwd_pri;
};
struct rtl8365mb_l2_mc_key {
u8 mac_addr[ETH_ALEN];
union {
u16 vid;
u16 fid;
};
bool ivl;
};
struct rtl8365mb_l2_mc {
struct rtl8365mb_l2_mc_key key;
u16 member;
u8 priority;
u8 igmpidx;
bool is_static;
bool fwd_pri;
bool igmp_asic;
};
static void rtl8365mb_l2_data_to_uc(const u16 *data, struct rtl8365mb_l2_uc *uc)
{
u32 val;
uc->key.mac_addr[5] = FIELD_GET(RTL8365MB_L2_UC_D0_MAC5_MSK, data[0]);
uc->key.mac_addr[4] = FIELD_GET(RTL8365MB_L2_UC_D0_MAC4_MSK, data[0]);
uc->key.mac_addr[3] = FIELD_GET(RTL8365MB_L2_UC_D1_MAC3_MSK, data[1]);
uc->key.mac_addr[2] = FIELD_GET(RTL8365MB_L2_UC_D1_MAC2_MSK, data[1]);
uc->key.mac_addr[1] = FIELD_GET(RTL8365MB_L2_UC_D2_MAC1_MSK, data[2]);
uc->key.mac_addr[0] = FIELD_GET(RTL8365MB_L2_UC_D2_MAC0_MSK, data[2]);
uc->key.efid = FIELD_GET(RTL8365MB_L2_UC_D4_EFID_MSK, data[4]);
uc->key.vid = FIELD_GET(RTL8365MB_L2_UC_D3_VID_MSK, data[3]);
uc->key.ivl = FIELD_GET(RTL8365MB_L2_UC_D3_IVL_MSK, data[3]);
uc->key.fid = FIELD_GET(RTL8365MB_L2_UC_D4_FID_MSK, data[4]);
uc->age = FIELD_GET(RTL8365MB_L2_UC_D4_AGE_MSK, data[4]);
uc->auth = FIELD_GET(RTL8365MB_L2_UC_D4_AUTH_MSK, data[4]);
val = FIELD_GET(RTL8365MB_L2_UC_D4_PORT_MSK, data[4]);
uc->port = FIELD_PREP(RTL8365MB_L2_UC_PORT_LO_MSK, val);
val = FIELD_GET(RTL8365MB_L2_UC_D3_PORT_EXT_MSK, data[3]);
uc->port |= FIELD_PREP(RTL8365MB_L2_UC_PORT_HI_MSK, val);
uc->sa_pri = FIELD_GET(RTL8365MB_L2_UC_D4_SA_PRI_MSK, data[4]);
uc->fwd_pri = FIELD_GET(RTL8365MB_L2_UC_D5_FWD_PRI_MSK, data[5]);
uc->sa_block = FIELD_GET(RTL8365MB_L2_UC_D4_SA_BLOCK_MSK, data[4]);
uc->da_block = FIELD_GET(RTL8365MB_L2_UC_D5_DA_BLOCK_MSK, data[5]);
uc->priority = FIELD_GET(RTL8365MB_L2_UC_D5_PRIORITY_MSK, data[5]);
uc->is_static = FIELD_GET(RTL8365MB_L2_UC_D5_STATIC_MSK, data[5]);
}
static void rtl8365mb_l2_uc_to_data(const struct rtl8365mb_l2_uc *uc, u16 *data)
{
u32 val;
memset(data, 0, RTL8365MB_L2_ENTRY_SIZE * 2);
data[0] |=
FIELD_PREP(RTL8365MB_L2_UC_D0_MAC5_MSK, uc->key.mac_addr[5]);
data[0] |=
FIELD_PREP(RTL8365MB_L2_UC_D0_MAC4_MSK, uc->key.mac_addr[4]);
data[1] |=
FIELD_PREP(RTL8365MB_L2_UC_D1_MAC3_MSK, uc->key.mac_addr[3]);
data[1] |=
FIELD_PREP(RTL8365MB_L2_UC_D1_MAC2_MSK, uc->key.mac_addr[2]);
data[2] |=
FIELD_PREP(RTL8365MB_L2_UC_D2_MAC1_MSK, uc->key.mac_addr[1]);
data[2] |=
FIELD_PREP(RTL8365MB_L2_UC_D2_MAC0_MSK, uc->key.mac_addr[0]);
data[3] |= FIELD_PREP(RTL8365MB_L2_UC_D3_VID_MSK, uc->key.vid);
data[3] |= FIELD_PREP(RTL8365MB_L2_UC_D3_IVL_MSK, uc->key.ivl);
val = FIELD_GET(RTL8365MB_L2_UC_PORT_HI_MSK, uc->port);
data[3] |= FIELD_PREP(RTL8365MB_L2_UC_D3_PORT_EXT_MSK, val);
data[4] |= FIELD_PREP(RTL8365MB_L2_UC_D4_FID_MSK, uc->key.fid);
data[4] |= FIELD_PREP(RTL8365MB_L2_UC_D4_EFID_MSK, uc->key.efid);
data[4] |= FIELD_PREP(RTL8365MB_L2_UC_D4_AGE_MSK, uc->age);
data[4] |= FIELD_PREP(RTL8365MB_L2_UC_D4_AUTH_MSK, uc->auth);
val = FIELD_GET(RTL8365MB_L2_UC_PORT_LO_MSK, uc->port);
data[4] |= FIELD_PREP(RTL8365MB_L2_UC_D4_PORT_MSK, val);
data[4] |= FIELD_PREP(RTL8365MB_L2_UC_D4_SA_PRI_MSK, uc->sa_pri);
data[4] |= FIELD_PREP(RTL8365MB_L2_UC_D4_SA_BLOCK_MSK, uc->sa_block);
data[5] |= FIELD_PREP(RTL8365MB_L2_UC_D5_FWD_PRI_MSK, uc->fwd_pri);
data[5] |= FIELD_PREP(RTL8365MB_L2_UC_D5_DA_BLOCK_MSK, uc->da_block);
data[5] |= FIELD_PREP(RTL8365MB_L2_UC_D5_PRIORITY_MSK, uc->priority);
data[5] |= FIELD_PREP(RTL8365MB_L2_UC_D5_STATIC_MSK, uc->is_static);
}
static void rtl8365mb_l2_data_to_mc(const u16 *data, struct rtl8365mb_l2_mc *mc)
{
u32 val;
mc->key.mac_addr[5] = FIELD_GET(RTL8365MB_L2_MC_D0_MAC5_MSK, data[0]);
mc->key.mac_addr[4] = FIELD_GET(RTL8365MB_L2_MC_D0_MAC4_MSK, data[0]);
mc->key.mac_addr[3] = FIELD_GET(RTL8365MB_L2_MC_D1_MAC3_MSK, data[1]);
mc->key.mac_addr[2] = FIELD_GET(RTL8365MB_L2_MC_D1_MAC2_MSK, data[1]);
mc->key.mac_addr[1] = FIELD_GET(RTL8365MB_L2_MC_D2_MAC1_MSK, data[2]);
mc->key.mac_addr[0] = FIELD_GET(RTL8365MB_L2_MC_D2_MAC0_MSK, data[2]);
mc->key.vid = FIELD_GET(RTL8365MB_L2_MC_D3_VID_MSK, data[3]);
mc->key.ivl = FIELD_GET(RTL8365MB_L2_MC_D3_IVL_MSK, data[3]);
mc->priority = FIELD_GET(RTL8365MB_L2_MC_D5_PRIORITY_MSK, data[5]);
mc->fwd_pri = FIELD_GET(RTL8365MB_L2_MC_D5_FWD_PRI_MSK, data[5]);
mc->is_static = FIELD_GET(RTL8365MB_L2_MC_D5_STATIC_MSK, data[5]);
val = FIELD_GET(RTL8365MB_L2_MC_D4_MBR_MSK, data[4]);
mc->member = FIELD_PREP(RTL8365MB_L2_MC_MBR_LO_MSK, val);
val = FIELD_GET(RTL8365MB_L2_MC_D3_MBR_HI1_MSK, data[3]);
mc->member |= FIELD_PREP(RTL8365MB_L2_MC_MBR_HI1_MSK, val);
val = FIELD_GET(RTL8365MB_L2_MC_D5_MBR_HI2_MSK, data[5]);
mc->member |= FIELD_PREP(RTL8365MB_L2_MC_MBR_HI2_MSK, val);
mc->igmpidx = FIELD_GET(RTL8365MB_L2_MC_D4_IGMPIDX_MSK, data[4]);
mc->igmp_asic = FIELD_GET(RTL8365MB_L2_MC_D5_IGMP_ASIC_MSK, data[5]);
}
static void rtl8365mb_l2_mc_to_data(const struct rtl8365mb_l2_mc *mc, u16 *data)
{
u32 val;
memset(data, 0, RTL8365MB_L2_ENTRY_SIZE * 2);
data[0] |= FIELD_PREP(RTL8365MB_L2_MC_D0_MAC5_MSK, mc->key.mac_addr[5]);
data[0] |= FIELD_PREP(RTL8365MB_L2_MC_D0_MAC4_MSK, mc->key.mac_addr[4]);
data[1] |= FIELD_PREP(RTL8365MB_L2_MC_D1_MAC3_MSK, mc->key.mac_addr[3]);
data[1] |= FIELD_PREP(RTL8365MB_L2_MC_D1_MAC2_MSK, mc->key.mac_addr[2]);
data[2] |= FIELD_PREP(RTL8365MB_L2_MC_D2_MAC1_MSK, mc->key.mac_addr[1]);
data[2] |= FIELD_PREP(RTL8365MB_L2_MC_D2_MAC0_MSK, mc->key.mac_addr[0]);
data[3] |= FIELD_PREP(RTL8365MB_L2_MC_D3_VID_MSK, mc->key.vid);
data[3] |= FIELD_PREP(RTL8365MB_L2_MC_D3_IVL_MSK, mc->key.ivl);
val = FIELD_GET(RTL8365MB_L2_MC_MBR_HI1_MSK, mc->member);
data[3] |= FIELD_PREP(RTL8365MB_L2_MC_D3_MBR_HI1_MSK, val);
val = FIELD_GET(RTL8365MB_L2_MC_MBR_LO_MSK, mc->member);
data[4] |= FIELD_PREP(RTL8365MB_L2_MC_D4_MBR_MSK, val);
data[4] |= FIELD_PREP(RTL8365MB_L2_MC_D4_IGMPIDX_MSK, mc->igmpidx);
data[5] |= FIELD_PREP(RTL8365MB_L2_MC_D5_IGMP_ASIC_MSK, mc->igmp_asic);
data[5] |= FIELD_PREP(RTL8365MB_L2_MC_D5_PRIORITY_MSK, mc->priority);
data[5] |= FIELD_PREP(RTL8365MB_L2_MC_D5_FWD_PRI_MSK, mc->fwd_pri);
data[5] |= FIELD_PREP(RTL8365MB_L2_MC_D5_STATIC_MSK, mc->is_static);
val = FIELD_GET(RTL8365MB_L2_MC_MBR_HI2_MSK, mc->member);
data[5] |= FIELD_PREP(RTL8365MB_L2_MC_D5_MBR_HI2_MSK, val);
}
int rtl8365mb_l2_get_next_uc(struct realtek_priv *priv, u16 *addr, int port,
struct realtek_fdb_entry *entry)
{
u16 data[RTL8365MB_L2_ENTRY_SIZE] = { 0 };
struct rtl8365mb_l2_uc uc;
int ret;
ret = rtl8365mb_table_query(priv, RTL8365MB_TABLE_L2,
RTL8365MB_TABLE_OP_READ, addr,
RTL8365MB_TABLE_L2_METHOD_ADDR_NEXT_UC_PORT,
port, data, RTL8365MB_L2_ENTRY_SIZE);
if (ret)
return ret;
rtl8365mb_l2_data_to_uc(data, &uc);
ether_addr_copy(entry->mac_addr, uc.key.mac_addr);
entry->vid = uc.key.vid;
entry->is_static = uc.is_static;
return 0;
}
int rtl8365mb_l2_add_uc(struct realtek_priv *priv, int port,
const unsigned char mac_addr[static ETH_ALEN],
u16 efid, u16 vid)
{
u16 data[RTL8365MB_L2_ENTRY_SIZE] = { 0 };
struct rtl8365mb_l2_uc uc = { 0 };
u16 addr;
int ret;
memcpy(uc.key.mac_addr, mac_addr, ETH_ALEN);
uc.key.efid = efid;
uc.key.fid = 0;
uc.key.ivl = true;
uc.key.vid = vid;
uc.port = port;
uc.is_static = true;
uc.age = 1;
rtl8365mb_l2_uc_to_data(&uc, data);
ret = rtl8365mb_table_query(priv, RTL8365MB_TABLE_L2,
RTL8365MB_TABLE_OP_WRITE, &addr,
0, 0,
data, RTL8365MB_L2_ENTRY_SIZE);
if (ret == -ENOENT)
return -ENOSPC;
return ret;
}
int rtl8365mb_l2_del_uc(struct realtek_priv *priv, int port,
const unsigned char mac_addr[static ETH_ALEN],
u16 efid, u16 vid)
{
u16 data[RTL8365MB_L2_ENTRY_SIZE] = { 0 };
struct rtl8365mb_l2_uc uc = { 0 };
u16 addr;
int ret;
memcpy(uc.key.mac_addr, mac_addr, ETH_ALEN);
uc.key.efid = efid;
uc.key.fid = 0;
uc.key.ivl = true;
uc.key.vid = vid;
uc.age = 0;
rtl8365mb_l2_uc_to_data(&uc, data);
ret = rtl8365mb_table_query(priv, RTL8365MB_TABLE_L2,
RTL8365MB_TABLE_OP_WRITE, &addr,
0, 0,
data, RTL8365MB_L2_ENTRY_SIZE);
if (ret == -ENOENT) {
dev_dbg(priv->dev, "%s: %pM vid=%d efid=%d missing\n",
__func__, mac_addr, vid, efid);
return 0;
}
return ret;
}
int rtl8365mb_l2_flush(struct realtek_priv *priv, int port, u16 vid)
{
int mode = vid ? RTL8365MB_L2_FLUSH_CTRL2_MODE_PORT_VID :
RTL8365MB_L2_FLUSH_CTRL2_MODE_PORT;
u32 val, mask;
int ret;
mutex_lock(&priv->map_lock);
ret = regmap_write(priv->map_nolock, RTL8365MB_L2_FLUSH_CTRL2_REG,
FIELD_PREP(RTL8365MB_L2_FLUSH_CTRL2_MODE_MSK,
mode) |
FIELD_PREP(RTL8365MB_L2_FLUSH_CTRL2_TYPE_MSK,
RTL8365MB_L2_FLUSH_CTRL2_TYPE_DYNAMIC));
if (ret)
goto out;
ret = regmap_write(priv->map_nolock, RTL8365MB_L2_FLUSH_CTRL1_REG,
FIELD_PREP(RTL8365MB_L2_FLUSH_CTRL1_VID_MSK, vid));
if (ret)
goto out;
if (port < 8) {
val = FIELD_PREP(RTL8365MB_L2_FLUSH_PORT_MSK_MSK,
BIT(port) & 0xFF);
ret = regmap_write(priv->map_nolock,
RTL8365MB_L2_FLUSH_PORT_REG, val);
if (ret)
goto out;
mask = FIELD_PREP(RTL8365MB_L2_FLUSH_PORT_BUSY_MSK,
BIT(port) & 0xFF);
ret = regmap_read_poll_timeout(priv->map_nolock,
RTL8365MB_L2_FLUSH_PORT_REG,
val, !(val & mask), 10, 10000);
if (ret)
goto out;
} else {
val = FIELD_PREP(RTL8365MB_L2_FLUSH_PORT_EXT_MSK_MSK,
BIT(port) >> 8);
ret = regmap_write(priv->map_nolock,
RTL8365MB_L2_FLUSH_PORT_EXT_REG, val);
if (ret)
goto out;
mask = FIELD_PREP(RTL8365MB_L2_FLUSH_PORT_EXT_BUSY_MSK,
BIT(port) >> 8);
ret = regmap_read_poll_timeout(priv->map_nolock,
RTL8365MB_L2_FLUSH_PORT_EXT_REG,
val, !(val & mask), 10, 10000);
if (ret)
goto out;
}
out:
mutex_unlock(&priv->map_lock);
return ret;
}
int rtl8365mb_l2_add_mc(struct realtek_priv *priv, int port,
const unsigned char mac_addr[static ETH_ALEN],
u16 vid)
{
u16 data[RTL8365MB_L2_ENTRY_SIZE] = { 0 };
struct rtl8365mb_l2_mc mc = { 0 };
u16 addr;
int ret;
memcpy(mc.key.mac_addr, mac_addr, ETH_ALEN);
mc.key.vid = vid;
mc.key.ivl = true;
mc.member |= BIT(port);
mc.is_static = 1;
rtl8365mb_l2_mc_to_data(&mc, data);
ret = rtl8365mb_table_query(priv, RTL8365MB_TABLE_L2,
RTL8365MB_TABLE_OP_READ, &addr,
RTL8365MB_TABLE_L2_METHOD_MAC, 0,
data, RTL8365MB_L2_ENTRY_SIZE);
if (!ret) {
rtl8365mb_l2_data_to_mc(data, &mc);
dev_dbg(priv->dev,
"%s: found %pM addr=%d member=0x%x igmpidx=0x%x %s\n",
__func__, mac_addr, addr, mc.member, mc.igmpidx,
mc.is_static ? "static" : "dynamic");
mc.member |= BIT(port);
if (!mc.is_static) {
dev_dbg(priv->dev,
"%s: promoting addr=%d group to static\n",
__func__, addr);
mc.is_static = 1;
}
rtl8365mb_l2_mc_to_data(&mc, data);
} else if (ret == -ENOENT) {
} else {
return ret;
}
ret = rtl8365mb_table_query(priv, RTL8365MB_TABLE_L2,
RTL8365MB_TABLE_OP_WRITE, &addr,
0, 0,
data, RTL8365MB_L2_ENTRY_SIZE);
if (ret == -ENOENT)
return -ENOSPC;
return ret;
}
int rtl8365mb_l2_del_mc(struct realtek_priv *priv, int port,
const unsigned char mac_addr[static ETH_ALEN],
u16 vid)
{
u16 data[RTL8365MB_L2_ENTRY_SIZE] = { 0 };
struct rtl8365mb_l2_mc mc = { 0 };
u16 addr;
int ret;
memcpy(mc.key.mac_addr, mac_addr, ETH_ALEN);
mc.key.vid = vid;
mc.key.ivl = true;
rtl8365mb_l2_mc_to_data(&mc, data);
ret = rtl8365mb_table_query(priv, RTL8365MB_TABLE_L2,
RTL8365MB_TABLE_OP_READ, &addr,
RTL8365MB_TABLE_L2_METHOD_MAC, 0,
data, RTL8365MB_L2_ENTRY_SIZE);
if (ret == -ENOENT) {
dev_dbg(priv->dev, "%s: %pM vid=%d missing\n",
__func__, mac_addr, vid);
return 0;
}
if (ret)
return ret;
rtl8365mb_l2_data_to_mc(data, &mc);
dev_dbg(priv->dev,
"%s: found %pM addr=%d member=0x%x igmpidx=0x%x %s\n",
__func__, mac_addr, addr, mc.member, mc.igmpidx,
mc.is_static ? "static" : "dynamic");
mc.member &= ~BIT(port);
if (!mc.member) {
mc.is_static = 0;
mc.igmpidx = 0;
mc.priority = 0;
mc.fwd_pri = 0;
mc.igmp_asic = 0;
}
rtl8365mb_l2_mc_to_data(&mc, data);
ret = rtl8365mb_table_query(priv, RTL8365MB_TABLE_L2,
RTL8365MB_TABLE_OP_WRITE, &addr,
0, 0,
data, RTL8365MB_L2_ENTRY_SIZE);
return ret;
}