477 lines
12 KiB
C
477 lines
12 KiB
C
|
// SPDX-License-Identifier: GPL-2.0-only
|
||
|
|
||
|
#include <asm/mach-rtl838x/mach-rtl83xx.h>
|
||
|
#include "rtl83xx.h"
|
||
|
|
||
|
extern struct mutex smi_lock;
|
||
|
|
||
|
|
||
|
static inline void rtl838x_mask_port_reg(u64 clear, u64 set, int reg)
|
||
|
{
|
||
|
sw_w32_mask((u32)clear, (u32)set, reg);
|
||
|
}
|
||
|
|
||
|
static inline void rtl838x_set_port_reg(u64 set, int reg)
|
||
|
{
|
||
|
sw_w32(set, reg);
|
||
|
}
|
||
|
|
||
|
static inline u64 rtl838x_get_port_reg(int reg)
|
||
|
{
|
||
|
return ((u64) sw_r32(reg));
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_stat_port_std_mib(int p)
|
||
|
{
|
||
|
return RTL838X_STAT_PORT_STD_MIB + (p << 8);
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_port_iso_ctrl(int p)
|
||
|
{
|
||
|
return RTL838X_PORT_ISO_CTRL(p);
|
||
|
}
|
||
|
|
||
|
static inline void rtl838x_exec_tbl0_cmd(u32 cmd)
|
||
|
{
|
||
|
sw_w32(cmd, RTL838X_TBL_ACCESS_CTRL_0);
|
||
|
do { } while (sw_r32(RTL838X_TBL_ACCESS_CTRL_0) & BIT(15));
|
||
|
}
|
||
|
|
||
|
static inline void rtl838x_exec_tbl1_cmd(u32 cmd)
|
||
|
{
|
||
|
sw_w32(cmd, RTL838X_TBL_ACCESS_CTRL_1);
|
||
|
do { } while (sw_r32(RTL838X_TBL_ACCESS_CTRL_1) & BIT(15));
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_tbl_access_data_0(int i)
|
||
|
{
|
||
|
return RTL838X_TBL_ACCESS_DATA_0(i);
|
||
|
}
|
||
|
|
||
|
static void rtl838x_vlan_tables_read(u32 vlan, struct rtl838x_vlan_info *info)
|
||
|
{
|
||
|
u32 cmd, v;
|
||
|
|
||
|
cmd = BIT(15) /* Execute cmd */
|
||
|
| BIT(14) /* Read */
|
||
|
| 0 << 12 /* Table type 0b00 */
|
||
|
| (vlan & 0xfff);
|
||
|
rtl838x_exec_tbl0_cmd(cmd);
|
||
|
info->tagged_ports = sw_r32(RTL838X_TBL_ACCESS_DATA_0(0));
|
||
|
v = sw_r32(RTL838X_TBL_ACCESS_DATA_0(1));
|
||
|
info->profile_id = v & 0x7;
|
||
|
info->hash_mc_fid = !!(v & 0x8);
|
||
|
info->hash_uc_fid = !!(v & 0x10);
|
||
|
info->fid = (v >> 5) & 0x3f;
|
||
|
|
||
|
|
||
|
cmd = BIT(15) /* Execute cmd */
|
||
|
| BIT(14) /* Read */
|
||
|
| 0 << 12 /* Table type 0b00 */
|
||
|
| (vlan & 0xfff);
|
||
|
rtl838x_exec_tbl1_cmd(cmd);
|
||
|
info->untagged_ports = sw_r32(RTL838X_TBL_ACCESS_DATA_1(0));
|
||
|
}
|
||
|
|
||
|
static void rtl838x_vlan_set_tagged(u32 vlan, struct rtl838x_vlan_info *info)
|
||
|
{
|
||
|
u32 cmd = BIT(15) /* Execute cmd */
|
||
|
| 0 << 14 /* Write */
|
||
|
| 0 << 12 /* Table type 0b00 */
|
||
|
| (vlan & 0xfff);
|
||
|
u32 v;
|
||
|
|
||
|
sw_w32(info->tagged_ports, RTL838X_TBL_ACCESS_DATA_0(0));
|
||
|
|
||
|
v = info->profile_id;
|
||
|
v |= info->hash_mc_fid ? 0x8 : 0;
|
||
|
v |= info->hash_uc_fid ? 0x10 : 0;
|
||
|
v |= ((u32)info->fid) << 5;
|
||
|
|
||
|
sw_w32(v, RTL838X_TBL_ACCESS_DATA_0(1));
|
||
|
rtl838x_exec_tbl0_cmd(cmd);
|
||
|
}
|
||
|
|
||
|
static void rtl838x_vlan_set_untagged(u32 vlan, u64 portmask)
|
||
|
{
|
||
|
u32 cmd = BIT(15) /* Execute cmd */
|
||
|
| 0 << 14 /* Write */
|
||
|
| 0 << 12 /* Table type 0b00 */
|
||
|
| (vlan & 0xfff);
|
||
|
sw_w32(portmask & 0x1fffffff, RTL838X_TBL_ACCESS_DATA_1(0));
|
||
|
rtl838x_exec_tbl1_cmd(cmd);
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_mac_force_mode_ctrl(int p)
|
||
|
{
|
||
|
return RTL838X_MAC_FORCE_MODE_CTRL + (p << 2);
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_mac_port_ctrl(int p)
|
||
|
{
|
||
|
return RTL838X_MAC_PORT_CTRL(p);
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_l2_port_new_salrn(int p)
|
||
|
{
|
||
|
return RTL838X_L2_PORT_NEW_SALRN(p);
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_l2_port_new_sa_fwd(int p)
|
||
|
{
|
||
|
return RTL838X_L2_PORT_NEW_SA_FWD(p);
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_mir_ctrl(int group)
|
||
|
{
|
||
|
return RTL838X_MIR_CTRL(group);
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_mir_dpm(int group)
|
||
|
{
|
||
|
return RTL838X_MIR_DPM_CTRL(group);
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_mir_spm(int group)
|
||
|
{
|
||
|
return RTL838X_MIR_SPM_CTRL(group);
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_mac_link_spd_sts(int p)
|
||
|
{
|
||
|
return RTL838X_MAC_LINK_SPD_STS(p);
|
||
|
}
|
||
|
|
||
|
static u64 rtl838x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl838x_l2_entry *e)
|
||
|
{
|
||
|
u64 entry;
|
||
|
u32 r[3];
|
||
|
|
||
|
/* Search in SRAM, with hash and at position in hash bucket (0-3) */
|
||
|
u32 idx = (0 << 14) | (hash << 2) | position;
|
||
|
|
||
|
u32 cmd = BIT(16) /* Execute cmd */
|
||
|
| BIT(15) /* Read */
|
||
|
| 0 << 13 /* Table type 0b00 */
|
||
|
| (idx & 0x1fff);
|
||
|
|
||
|
sw_w32(cmd, RTL838X_TBL_ACCESS_L2_CTRL);
|
||
|
do { } while (sw_r32(RTL838X_TBL_ACCESS_L2_CTRL) & BIT(16));
|
||
|
r[0] = sw_r32(RTL838X_TBL_ACCESS_L2_DATA(0));
|
||
|
r[1] = sw_r32(RTL838X_TBL_ACCESS_L2_DATA(1));
|
||
|
r[2] = sw_r32(RTL838X_TBL_ACCESS_L2_DATA(2));
|
||
|
|
||
|
e->mac[0] = (r[1] >> 20);
|
||
|
e->mac[1] = (r[1] >> 12);
|
||
|
e->mac[2] = (r[1] >> 4);
|
||
|
e->mac[3] = (r[1] & 0xf) << 4 | (r[2] >> 28);
|
||
|
e->mac[4] = (r[2] >> 20);
|
||
|
e->mac[5] = (r[2] >> 12);
|
||
|
e->is_static = !!((r[0] >> 19) & 1);
|
||
|
e->vid = r[0] & 0xfff;
|
||
|
e->rvid = r[2] & 0xfff;
|
||
|
e->port = (r[0] >> 12) & 0x1f;
|
||
|
|
||
|
e->valid = true;
|
||
|
if (!(r[0] >> 17)) /* Check for invalid entry */
|
||
|
e->valid = false;
|
||
|
|
||
|
if (e->valid)
|
||
|
pr_debug("Found in Hash: R1 %x R2 %x R3 %x\n", r[0], r[1], r[2]);
|
||
|
|
||
|
entry = (((u64) r[1]) << 32) | (r[2] & 0xfffff000) | (r[0] & 0xfff);
|
||
|
return entry;
|
||
|
}
|
||
|
|
||
|
static u64 rtl838x_read_cam(int idx, struct rtl838x_l2_entry *e)
|
||
|
{
|
||
|
u64 entry;
|
||
|
u32 r[3];
|
||
|
|
||
|
u32 cmd = BIT(16) /* Execute cmd */
|
||
|
| BIT(15) /* Read */
|
||
|
| BIT(13) /* Table type 0b01 */
|
||
|
| (idx & 0x3f);
|
||
|
sw_w32(cmd, RTL838X_TBL_ACCESS_L2_CTRL);
|
||
|
do { } while (sw_r32(RTL838X_TBL_ACCESS_L2_CTRL) & BIT(16));
|
||
|
r[0] = sw_r32(RTL838X_TBL_ACCESS_L2_DATA(0));
|
||
|
r[1] = sw_r32(RTL838X_TBL_ACCESS_L2_DATA(1));
|
||
|
r[2] = sw_r32(RTL838X_TBL_ACCESS_L2_DATA(2));
|
||
|
|
||
|
e->mac[0] = (r[1] >> 20);
|
||
|
e->mac[1] = (r[1] >> 12);
|
||
|
e->mac[2] = (r[1] >> 4);
|
||
|
e->mac[3] = (r[1] & 0xf) << 4 | (r[2] >> 28);
|
||
|
e->mac[4] = (r[2] >> 20);
|
||
|
e->mac[5] = (r[2] >> 12);
|
||
|
e->is_static = !!((r[0] >> 19) & 1);
|
||
|
e->vid = r[0] & 0xfff;
|
||
|
e->rvid = r[2] & 0xfff;
|
||
|
e->port = (r[0] >> 12) & 0x1f;
|
||
|
|
||
|
e->valid = true;
|
||
|
if (!(r[0] >> 17)) /* Check for invalid entry */
|
||
|
e->valid = false;
|
||
|
|
||
|
if (e->valid)
|
||
|
pr_debug("Found in CAM: R1 %x R2 %x R3 %x\n", r[0], r[1], r[2]);
|
||
|
|
||
|
entry = (((u64) r[1]) << 32) | (r[2] & 0xfffff000) | (r[0] & 0xfff);
|
||
|
return entry;
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_vlan_profile(int profile)
|
||
|
{
|
||
|
return RTL838X_VLAN_PROFILE(profile);
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_vlan_port_egr_filter(int port)
|
||
|
{
|
||
|
return RTL838X_VLAN_PORT_EGR_FLTR;
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_vlan_port_igr_filter(int port)
|
||
|
{
|
||
|
return RTL838X_VLAN_PORT_IGR_FLTR(port);
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_vlan_port_pb(int port)
|
||
|
{
|
||
|
return RTL838X_VLAN_PORT_PB_VLAN(port);
|
||
|
}
|
||
|
|
||
|
static inline int rtl838x_vlan_port_tag_sts_ctrl(int port)
|
||
|
{
|
||
|
return RTL838X_VLAN_PORT_TAG_STS_CTRL(port);
|
||
|
}
|
||
|
|
||
|
const struct rtl838x_reg rtl838x_reg = {
|
||
|
.mask_port_reg_be = rtl838x_mask_port_reg,
|
||
|
.set_port_reg_be = rtl838x_set_port_reg,
|
||
|
.get_port_reg_be = rtl838x_get_port_reg,
|
||
|
.mask_port_reg_le = rtl838x_mask_port_reg,
|
||
|
.set_port_reg_le = rtl838x_set_port_reg,
|
||
|
.get_port_reg_le = rtl838x_get_port_reg,
|
||
|
.stat_port_rst = RTL838X_STAT_PORT_RST,
|
||
|
.stat_rst = RTL838X_STAT_RST,
|
||
|
.stat_port_std_mib = rtl838x_stat_port_std_mib,
|
||
|
.port_iso_ctrl = rtl838x_port_iso_ctrl,
|
||
|
.l2_ctrl_0 = RTL838X_L2_CTRL_0,
|
||
|
.l2_ctrl_1 = RTL838X_L2_CTRL_1,
|
||
|
.l2_port_aging_out = RTL838X_L2_PORT_AGING_OUT,
|
||
|
.smi_poll_ctrl = RTL838X_SMI_POLL_CTRL,
|
||
|
.l2_tbl_flush_ctrl = RTL838X_L2_TBL_FLUSH_CTRL,
|
||
|
.exec_tbl0_cmd = rtl838x_exec_tbl0_cmd,
|
||
|
.exec_tbl1_cmd = rtl838x_exec_tbl1_cmd,
|
||
|
.tbl_access_data_0 = rtl838x_tbl_access_data_0,
|
||
|
.isr_glb_src = RTL838X_ISR_GLB_SRC,
|
||
|
.isr_port_link_sts_chg = RTL838X_ISR_PORT_LINK_STS_CHG,
|
||
|
.imr_port_link_sts_chg = RTL838X_IMR_PORT_LINK_STS_CHG,
|
||
|
.imr_glb = RTL838X_IMR_GLB,
|
||
|
.vlan_tables_read = rtl838x_vlan_tables_read,
|
||
|
.vlan_set_tagged = rtl838x_vlan_set_tagged,
|
||
|
.vlan_set_untagged = rtl838x_vlan_set_untagged,
|
||
|
.mac_force_mode_ctrl = rtl838x_mac_force_mode_ctrl,
|
||
|
.mac_port_ctrl = rtl838x_mac_port_ctrl,
|
||
|
.l2_port_new_salrn = rtl838x_l2_port_new_salrn,
|
||
|
.l2_port_new_sa_fwd = rtl838x_l2_port_new_sa_fwd,
|
||
|
.mir_ctrl = rtl838x_mir_ctrl,
|
||
|
.mir_dpm = rtl838x_mir_dpm,
|
||
|
.mir_spm = rtl838x_mir_spm,
|
||
|
.mac_link_sts = RTL838X_MAC_LINK_STS,
|
||
|
.mac_link_dup_sts = RTL838X_MAC_LINK_DUP_STS,
|
||
|
.mac_link_spd_sts = rtl838x_mac_link_spd_sts,
|
||
|
.mac_rx_pause_sts = RTL838X_MAC_RX_PAUSE_STS,
|
||
|
.mac_tx_pause_sts = RTL838X_MAC_TX_PAUSE_STS,
|
||
|
.read_l2_entry_using_hash = rtl838x_read_l2_entry_using_hash,
|
||
|
.read_cam = rtl838x_read_cam,
|
||
|
.vlan_profile = rtl838x_vlan_profile,
|
||
|
.vlan_port_egr_filter = rtl838x_vlan_port_egr_filter,
|
||
|
.vlan_port_igr_filter = rtl838x_vlan_port_igr_filter,
|
||
|
.vlan_port_pb = rtl838x_vlan_port_pb,
|
||
|
.vlan_port_tag_sts_ctrl = rtl838x_vlan_port_tag_sts_ctrl,
|
||
|
};
|
||
|
|
||
|
irqreturn_t rtl838x_switch_irq(int irq, void *dev_id)
|
||
|
{
|
||
|
struct dsa_switch *ds = dev_id;
|
||
|
u32 status = sw_r32(RTL838X_ISR_GLB_SRC);
|
||
|
u32 ports = sw_r32(RTL838X_ISR_PORT_LINK_STS_CHG);
|
||
|
u32 link;
|
||
|
int i;
|
||
|
|
||
|
/* Clear status */
|
||
|
sw_w32(ports, RTL838X_ISR_PORT_LINK_STS_CHG);
|
||
|
pr_debug("RTL8380 Link change: status: %x, ports %x\n", status, ports);
|
||
|
|
||
|
for (i = 0; i < 28; i++) {
|
||
|
if (ports & BIT(i)) {
|
||
|
link = sw_r32(RTL838X_MAC_LINK_STS);
|
||
|
if (link & BIT(i))
|
||
|
dsa_port_phylink_mac_change(ds, i, true);
|
||
|
else
|
||
|
dsa_port_phylink_mac_change(ds, i, false);
|
||
|
}
|
||
|
}
|
||
|
return IRQ_HANDLED;
|
||
|
}
|
||
|
|
||
|
int rtl838x_smi_wait_op(int timeout)
|
||
|
{
|
||
|
do {
|
||
|
timeout--;
|
||
|
udelay(10);
|
||
|
} while ((sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_1) & 0x1) && (timeout >= 0));
|
||
|
if (timeout <= 0)
|
||
|
return -1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Reads a register in a page from the PHY
|
||
|
*/
|
||
|
int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
|
||
|
{
|
||
|
u32 v;
|
||
|
u32 park_page;
|
||
|
|
||
|
if (port > 31) {
|
||
|
*val = 0xffff;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (page > 4095 || reg > 31)
|
||
|
return -ENOTSUPP;
|
||
|
|
||
|
mutex_lock(&smi_lock);
|
||
|
|
||
|
if (rtl838x_smi_wait_op(10000))
|
||
|
goto timeout;
|
||
|
|
||
|
sw_w32_mask(0xffff0000, port << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
|
||
|
|
||
|
park_page = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_1) & ((0x1f << 15) | 0x2);
|
||
|
v = reg << 20 | page << 3;
|
||
|
sw_w32(v | park_page, RTL838X_SMI_ACCESS_PHY_CTRL_1);
|
||
|
sw_w32_mask(0, 1, RTL838X_SMI_ACCESS_PHY_CTRL_1);
|
||
|
|
||
|
if (rtl838x_smi_wait_op(10000))
|
||
|
goto timeout;
|
||
|
|
||
|
*val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff;
|
||
|
|
||
|
mutex_unlock(&smi_lock);
|
||
|
return 0;
|
||
|
|
||
|
timeout:
|
||
|
mutex_unlock(&smi_lock);
|
||
|
return -ETIMEDOUT;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Write to a register in a page of the PHY
|
||
|
*/
|
||
|
int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val)
|
||
|
{
|
||
|
u32 v;
|
||
|
u32 park_page;
|
||
|
|
||
|
val &= 0xffff;
|
||
|
if (port > 31 || page > 4095 || reg > 31)
|
||
|
return -ENOTSUPP;
|
||
|
|
||
|
mutex_lock(&smi_lock);
|
||
|
if (rtl838x_smi_wait_op(10000))
|
||
|
goto timeout;
|
||
|
|
||
|
sw_w32(BIT(port), RTL838X_SMI_ACCESS_PHY_CTRL_0);
|
||
|
mdelay(10);
|
||
|
|
||
|
sw_w32_mask(0xffff0000, val << 16, RTL838X_SMI_ACCESS_PHY_CTRL_2);
|
||
|
|
||
|
park_page = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_1) & ((0x1f << 15) | 0x2);
|
||
|
v = reg << 20 | page << 3 | 0x4;
|
||
|
sw_w32(v | park_page, RTL838X_SMI_ACCESS_PHY_CTRL_1);
|
||
|
sw_w32_mask(0, 1, RTL838X_SMI_ACCESS_PHY_CTRL_1);
|
||
|
|
||
|
if (rtl838x_smi_wait_op(10000))
|
||
|
goto timeout;
|
||
|
|
||
|
mutex_unlock(&smi_lock);
|
||
|
return 0;
|
||
|
|
||
|
timeout:
|
||
|
mutex_unlock(&smi_lock);
|
||
|
return -ETIMEDOUT;
|
||
|
}
|
||
|
|
||
|
void rtl8380_get_version(struct rtl838x_switch_priv *priv)
|
||
|
{
|
||
|
u32 rw_save, info_save;
|
||
|
u32 info;
|
||
|
|
||
|
rw_save = sw_r32(RTL838X_INT_RW_CTRL);
|
||
|
sw_w32(rw_save | 0x3, RTL838X_INT_RW_CTRL);
|
||
|
|
||
|
info_save = sw_r32(RTL838X_CHIP_INFO);
|
||
|
sw_w32(info_save | 0xA0000000, RTL838X_CHIP_INFO);
|
||
|
|
||
|
info = sw_r32(RTL838X_CHIP_INFO);
|
||
|
sw_w32(info_save, RTL838X_CHIP_INFO);
|
||
|
sw_w32(rw_save, RTL838X_INT_RW_CTRL);
|
||
|
|
||
|
if ((info & 0xFFFF) == 0x6275) {
|
||
|
if (((info >> 16) & 0x1F) == 0x1)
|
||
|
priv->version = RTL8380_VERSION_A;
|
||
|
else if (((info >> 16) & 0x1F) == 0x2)
|
||
|
priv->version = RTL8380_VERSION_B;
|
||
|
else
|
||
|
priv->version = RTL8380_VERSION_B;
|
||
|
} else {
|
||
|
priv->version = '-';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Applies the same hash algorithm as the one used currently by the ASIC
|
||
|
*/
|
||
|
u32 rtl838x_hash(struct rtl838x_switch_priv *priv, u64 seed)
|
||
|
{
|
||
|
u32 h1, h2, h3, h;
|
||
|
|
||
|
if (sw_r32(priv->r->l2_ctrl_0) & 1) {
|
||
|
h1 = (seed >> 11) & 0x7ff;
|
||
|
h1 = ((h1 & 0x1f) << 6) | ((h1 >> 5) & 0x3f);
|
||
|
|
||
|
h2 = (seed >> 33) & 0x7ff;
|
||
|
h2 = ((h2 & 0x3f) << 5) | ((h2 >> 6) & 0x1f);
|
||
|
|
||
|
h3 = (seed >> 44) & 0x7ff;
|
||
|
h3 = ((h3 & 0x7f) << 4) | ((h3 >> 7) & 0xf);
|
||
|
|
||
|
h = h1 ^ h2 ^ h3 ^ ((seed >> 55) & 0x1ff);
|
||
|
h ^= ((seed >> 22) & 0x7ff) ^ (seed & 0x7ff);
|
||
|
} else {
|
||
|
h = ((seed >> 55) & 0x1ff) ^ ((seed >> 44) & 0x7ff)
|
||
|
^ ((seed >> 33) & 0x7ff) ^ ((seed >> 22) & 0x7ff)
|
||
|
^ ((seed >> 11) & 0x7ff) ^ (seed & 0x7ff);
|
||
|
}
|
||
|
|
||
|
return h;
|
||
|
}
|
||
|
|
||
|
void rtl838x_vlan_profile_dump(int index)
|
||
|
{
|
||
|
u32 profile;
|
||
|
|
||
|
if (index < 0 || index > 7)
|
||
|
return;
|
||
|
|
||
|
profile = sw_r32(RTL838X_VLAN_PROFILE(index));
|
||
|
|
||
|
pr_debug("VLAN %d: L2 learning: %d, L2 Unknown MultiCast Field %x, \
|
||
|
IPv4 Unknown MultiCast Field %x, IPv6 Unknown MultiCast Field: %x",
|
||
|
index, profile & 1, (profile >> 1) & 0x1ff, (profile >> 10) & 0x1ff,
|
||
|
(profile >> 19) & 0x1ff);
|
||
|
}
|