int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu)
{
u16 frame_size;
if (!dsa_is_cpu_port(dev->ds, port)) return0;
frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
switch (dev->chip_id) { case KSZ8795_CHIP_ID: case KSZ8794_CHIP_ID: case KSZ8765_CHIP_ID: return ksz8795_change_mtu(dev, frame_size); case KSZ8463_CHIP_ID: case KSZ88X3_CHIP_ID: case KSZ8864_CHIP_ID: case KSZ8895_CHIP_ID: return ksz8863_change_mtu(dev, frame_size);
}
return -EOPNOTSUPP;
}
staticint ksz8_port_queue_split(struct ksz_device *dev, int port, int queues)
{
u8 mask_4q, mask_2q;
u8 reg_4q, reg_2q;
u8 data_4q = 0;
u8 data_2q = 0; int ret;
/* TODO: this is legacy from initial KSZ8795 driver, should be *movedtoappropriateplaceinthefuture.
*/
ret = ksz_rmw8(dev, REG_SW_CTRL_19,
SW_OUT_RATE_LIMIT_QUEUE_BASED,
SW_OUT_RATE_LIMIT_QUEUE_BASED); if (ret) return ret;
}
/* It is almost guaranteed to always read the valid bit because of *slowSPIspeed.
*/ for (loop = 2; loop > 0; loop--) {
ksz_read8(dev, regs[REG_IND_MIB_CHECK], &check);
if (check & masks[MIB_COUNTER_VALID]) {
ksz_read32(dev, regs[REG_IND_DATA_LO], &data); if (check & masks[MIB_COUNTER_OVERFLOW])
*cnt += MIB_COUNTER_VALUE + 1;
*cnt += data & MIB_COUNTER_VALUE; break;
}
}
mutex_unlock(&dev->alu_mutex);
}
/* It is almost guaranteed to always read the valid bit because of *slowSPIspeed.
*/ for (loop = 2; loop > 0; loop--) {
ksz_read8(dev, regs[REG_IND_MIB_CHECK], &check);
if (check & masks[MIB_COUNTER_VALID]) {
ksz_read32(dev, regs[REG_IND_DATA_LO], &data); if (addr < 2) {
u64 total;
total = check & MIB_TOTAL_BYTES_H;
total <<= 32;
*cnt += total;
*cnt += data; if (check & masks[MIB_COUNTER_OVERFLOW]) {
total = MIB_TOTAL_BYTES_H + 1;
total <<= 32;
*cnt += total;
}
} else { if (check & masks[MIB_COUNTER_OVERFLOW])
*cnt += MIB_PACKET_DROPPED + 1;
*cnt += data & MIB_PACKET_DROPPED;
} break;
}
}
mutex_unlock(&dev->alu_mutex);
}
void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
{ if (is_ksz88xx(dev)) return;
/* enable the port for flush/freeze function */ if (freeze)
ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true);
ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FREEZE, freeze);
/* disable the port after freeze is done */ if (!freeze)
ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false);
}
/* For KSZ8795 family. */ if (ksz_is_ksz87xx(dev)) { /* flush all enabled port MIB counters */
ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true);
ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FLUSH, true);
ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false);
}
mib->cnt_ptr = 0;
/* Some ports may not have MIB counters before SWITCH_COUNTER_NUM. */ while (mib->cnt_ptr < dev->info->reg_mib_cnt) {
dev->dev_ops->r_mib_cnt(dev, port, mib->cnt_ptr,
&mib->counters[mib->cnt_ptr]);
++mib->cnt_ptr;
}
/* last one in storage */
dropped = &mib->counters[dev->info->mib_cnt];
/* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */ while (mib->cnt_ptr < dev->info->mib_cnt) {
dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr,
dropped, &mib->counters[mib->cnt_ptr]);
++mib->cnt_ptr;
}
}
staticint ksz8_r_table(struct ksz_device *dev, int table, u16 addr, u64 *data)
{ const u16 *regs;
u16 ctrl_addr; int ret;
ret = ksz_pread8(dev, port, regs[P_NEG_RESTART_CTRL], &restart); if (ret) return ret;
ret = ksz_pread8(dev, port, regs[P_SPEED_STATUS], &speed); if (ret) return ret;
ret = ksz_pread8(dev, port, regs[P_FORCE_CTRL], &ctrl); if (ret) return ret;
if (ctrl & PORT_FORCE_100_MBIT)
*val |= BMCR_SPEED100;
if (ksz_is_ksz88x3(dev)) { if (restart & KSZ8873_PORT_PHY_LOOPBACK)
*val |= BMCR_LOOPBACK;
if ((ctrl & PORT_AUTO_NEG_ENABLE))
*val |= BMCR_ANENABLE;
} else {
ret = ksz879x_get_loopback(dev, port, val); if (ret) return ret;
if (!(ctrl & PORT_AUTO_NEG_DISABLE))
*val |= BMCR_ANENABLE;
}
if (restart & PORT_POWER_DOWN)
*val |= BMCR_PDOWN;
if (restart & PORT_AUTO_NEG_RESTART)
*val |= BMCR_ANRESTART;
if (ctrl & PORT_FORCE_FULL_DUPLEX)
*val |= BMCR_FULLDPLX;
if (speed & PORT_HP_MDIX)
*val |= KSZ886X_BMCR_HP_MDIX;
if (restart & PORT_FORCE_MDIX)
*val |= KSZ886X_BMCR_FORCE_MDI;
if (restart & PORT_AUTO_MDIX_DISABLE)
*val |= KSZ886X_BMCR_DISABLE_AUTO_MDIX;
if (restart & PORT_TX_DISABLE)
*val |= KSZ886X_BMCR_DISABLE_TRANSMIT;
if (restart & PORT_LED_OFF)
*val |= KSZ886X_BMCR_DISABLE_LED;
return0;
}
int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
{
u8 ctrl, link, val1, val2; int processed = true; const u16 *regs;
u16 data = 0;
u16 p = phy; int ret;
regs = dev->info->regs;
switch (reg) { case MII_BMCR:
ret = ksz8_r_phy_bmcr(dev, p, &data); if (ret) return ret; break; case MII_BMSR:
ret = ksz_pread8(dev, p, regs[P_LINK_STATUS], &link); if (ret) return ret;
data = BMSR_100FULL |
BMSR_100HALF |
BMSR_10FULL |
BMSR_10HALF |
BMSR_ANEGCAPABLE; if (link & PORT_AUTO_NEG_COMPLETE)
data |= BMSR_ANEGCOMPLETE; if (link & PORT_STAT_LINK_GOOD)
data |= BMSR_LSTATUS; break; case MII_PHYSID1:
data = KSZ8795_ID_HI; break; case MII_PHYSID2: if (ksz_is_ksz88x3(dev))
data = KSZ8863_ID_LO; else
data = KSZ8795_ID_LO; break; case MII_ADVERTISE:
ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl); if (ret) return ret;
data = ADVERTISE_CSMA; if (ctrl & PORT_AUTO_NEG_SYM_PAUSE)
data |= ADVERTISE_PAUSE_CAP; if (ctrl & PORT_AUTO_NEG_100BTX_FD)
data |= ADVERTISE_100FULL; if (ctrl & PORT_AUTO_NEG_100BTX)
data |= ADVERTISE_100HALF; if (ctrl & PORT_AUTO_NEG_10BT_FD)
data |= ADVERTISE_10FULL; if (ctrl & PORT_AUTO_NEG_10BT)
data |= ADVERTISE_10HALF; break; case MII_LPA:
ret = ksz_pread8(dev, p, regs[P_REMOTE_STATUS], &link); if (ret) return ret;
data = LPA_SLCT; if (link & PORT_REMOTE_SYM_PAUSE)
data |= LPA_PAUSE_CAP; if (link & PORT_REMOTE_100BTX_FD)
data |= LPA_100FULL; if (link & PORT_REMOTE_100BTX)
data |= LPA_100HALF; if (link & PORT_REMOTE_10BT_FD)
data |= LPA_10FULL; if (link & PORT_REMOTE_10BT)
data |= LPA_10HALF; if (data & ~LPA_SLCT)
data |= LPA_LPACK; break; case PHY_REG_LINK_MD:
ret = ksz_pread8(dev, p, REG_PORT_LINK_MD_CTRL, &val1); if (ret) return ret;
ret = ksz_pread8(dev, p, REG_PORT_LINK_MD_RESULT, &val2); if (ret) return ret;
if (val1 & PORT_START_CABLE_DIAG)
data |= PHY_START_CABLE_DIAG;
if (val1 & PORT_CABLE_10M_SHORT)
data |= PHY_CABLE_10M_SHORT;
data |= FIELD_PREP(PHY_CABLE_DIAG_RESULT_M,
FIELD_GET(PORT_CABLE_DIAG_RESULT_M, val1));
data |= FIELD_PREP(PHY_CABLE_FAULT_COUNTER_M,
(FIELD_GET(PORT_CABLE_FAULT_COUNTER_H, val1) << 8) |
FIELD_GET(PORT_CABLE_FAULT_COUNTER_L, val2)); break; case PHY_REG_PHY_CTRL:
ret = ksz8_r_phy_ctrl(dev, p, &data); if (ret) return ret;
/* Do not support PHY reset function. */ if (val & BMCR_RESET) return0;
speed = 0; if (val & KSZ886X_BMCR_HP_MDIX)
speed |= PORT_HP_MDIX;
ret = ksz_prmw8(dev, port, regs[P_SPEED_STATUS], PORT_HP_MDIX, speed); if (ret) return ret;
ctrl = 0; if (ksz_is_ksz88x3(dev)) { if ((val & BMCR_ANENABLE))
ctrl |= PORT_AUTO_NEG_ENABLE;
} else { if (!(val & BMCR_ANENABLE))
ctrl |= PORT_AUTO_NEG_DISABLE;
/* Fiber port does not support auto-negotiation. */ if (dev->ports[port].fiber)
ctrl |= PORT_AUTO_NEG_DISABLE;
}
if (val & BMCR_SPEED100)
ctrl |= PORT_FORCE_100_MBIT;
if (val & BMCR_FULLDPLX)
ctrl |= PORT_FORCE_FULL_DUPLEX;
ret = ksz_prmw8(dev, port, regs[P_FORCE_CTRL], PORT_FORCE_100_MBIT | /* PORT_AUTO_NEG_ENABLE and PORT_AUTO_NEG_DISABLE are the same *bits
*/
PORT_FORCE_FULL_DUPLEX | PORT_AUTO_NEG_ENABLE, ctrl); if (ret) return ret;
int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
{ const u16 *regs;
u8 ctrl, data;
u16 p = phy; int ret;
regs = dev->info->regs;
switch (reg) { case MII_BMCR:
ret = ksz8_w_phy_bmcr(dev, p, val); if (ret) return ret; break; case MII_ADVERTISE:
ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl); if (ret) return ret;
data = ctrl;
data &= ~(PORT_AUTO_NEG_SYM_PAUSE |
PORT_AUTO_NEG_100BTX_FD |
PORT_AUTO_NEG_100BTX |
PORT_AUTO_NEG_10BT_FD |
PORT_AUTO_NEG_10BT); if (val & ADVERTISE_PAUSE_CAP)
data |= PORT_AUTO_NEG_SYM_PAUSE; if (val & ADVERTISE_100FULL)
data |= PORT_AUTO_NEG_100BTX_FD; if (val & ADVERTISE_100HALF)
data |= PORT_AUTO_NEG_100BTX; if (val & ADVERTISE_10FULL)
data |= PORT_AUTO_NEG_10BT_FD; if (val & ADVERTISE_10HALF)
data |= PORT_AUTO_NEG_10BT;
if (data != ctrl) {
ret = ksz_pwrite8(dev, p, regs[P_LOCAL_CTRL], data); if (ret) return ret;
} break; case PHY_REG_LINK_MD: if (val & PHY_START_CABLE_DIAG)
ksz_port_cfg(dev, p, REG_PORT_LINK_MD_CTRL, PORT_START_CABLE_DIAG, true); break;
case PHY_REG_PHY_CTRL:
ret = ksz8_w_phy_ctrl(dev, p, val); if (ret) return ret; break; default: break;
}
return0;
}
void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member)
{ int offset = P_MIRROR_CTRL;
u8 data;
if (ksz_is_ksz8463(dev))
offset = P1CR2;
ksz_pread8(dev, port, offset, &data);
data &= ~dev->port_mask;
data |= (member & dev->port_mask);
ksz_pwrite8(dev, port, offset, data);
}
void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
{
u8 learn[DSA_MAX_PORTS]; int first, index, cnt; const u16 *regs; int reg = S_FLUSH_TABLE_CTRL; int mask = SW_FLUSH_DYN_MAC_TABLE;
regs = dev->info->regs;
if ((uint)port < dev->info->port_cnt) {
first = port;
cnt = port + 1;
} else { /* Flush all ports. */
first = 0;
cnt = dev->info->port_cnt;
} for (index = first; index < cnt; index++) {
ksz_pread8(dev, index, regs[P_STP_CTRL], &learn[index]); if (!(learn[index] & PORT_LEARN_DISABLE))
ksz_pwrite8(dev, index, regs[P_STP_CTRL],
learn[index] | PORT_LEARN_DISABLE);
} if (ksz_is_ksz8463(dev)) {
reg = KSZ8463_FLUSH_TABLE_CTRL;
mask = KSZ8463_FLUSH_DYN_MAC_TABLE;
}
ksz_cfg(dev, reg, mask, true); for (index = first; index < cnt; index++) { if (!(learn[index] & PORT_LEARN_DISABLE))
ksz_pwrite8(dev, index, regs[P_STP_CTRL], learn[index]);
}
}
int ksz8_fdb_dump(struct ksz_device *dev, int port,
dsa_fdb_dump_cb_t *cb, void *data)
{
u8 mac[ETH_ALEN];
u8 src_port, fid;
u16 entries = 0; int ret, i;
for (i = 0; i < KSZ8_DYN_MAC_ENTRIES; i++) {
ret = ksz8_r_dyn_mac_table(dev, i, mac, &fid, &src_port,
&entries); if (ret) return ret;
if (i >= entries) return0;
if (port == src_port) {
ret = cb(mac, fid, false, data); if (ret) return ret;
}
}
return0;
}
staticint ksz8_add_sta_mac(struct ksz_device *dev, int port, constunsignedchar *addr, u16 vid)
{ struct alu_struct alu; int index, ret; int empty = 0;
alu.port_forward = 0; for (index = 0; index < dev->info->num_statics; index++) { bool valid;
ret = ksz8_r_sta_mac_table(dev, index, &alu, &valid); if (ret) return ret; if (!valid) { /* Remember the first empty entry. */ if (!empty)
empty = index + 1; continue;
}
if (!memcmp(alu.mac, addr, ETH_ALEN) && alu.fid == vid) break;
}
/* no available entry */ if (index == dev->info->num_statics && !empty) return -ENOSPC;
/* Need a way to map VID to FID. */
alu.fid = vid;
}
return ksz8_w_sta_mac_table(dev, index, &alu);
}
staticint ksz8_del_sta_mac(struct ksz_device *dev, int port, constunsignedchar *addr, u16 vid)
{ struct alu_struct alu; int index, ret;
for (index = 0; index < dev->info->num_statics; index++) { bool valid;
ret = ksz8_r_sta_mac_table(dev, index, &alu, &valid); if (ret) return ret; if (!valid) continue;
if (!memcmp(alu.mac, addr, ETH_ALEN) && alu.fid == vid) break;
}
/* no available entry */ if (index == dev->info->num_statics) return0;
/* clear port */
alu.port_forward &= ~BIT(port); if (!alu.port_forward)
alu.is_static = false;
return ksz8_w_sta_mac_table(dev, index, &alu);
}
int ksz8_mdb_add(struct ksz_device *dev, int port, conststruct switchdev_obj_port_mdb *mdb, struct dsa_db db)
{ return ksz8_add_sta_mac(dev, port, mdb->addr, mdb->vid);
}
int ksz8_mdb_del(struct ksz_device *dev, int port, conststruct switchdev_obj_port_mdb *mdb, struct dsa_db db)
{ return ksz8_del_sta_mac(dev, port, mdb->addr, mdb->vid);
}
int ksz8_fdb_add(struct ksz_device *dev, int port, constunsignedchar *addr,
u16 vid, struct dsa_db db)
{ return ksz8_add_sta_mac(dev, port, addr, vid);
}
int ksz8_fdb_del(struct ksz_device *dev, int port, constunsignedchar *addr,
u16 vid, struct dsa_db db)
{ return ksz8_del_sta_mac(dev, port, addr, vid);
}
int ksz8_port_vlan_filtering(struct ksz_device *dev, int port, bool flag, struct netlink_ext_ack *extack)
{ if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev)) return -ENOTSUPP;
/* Discard packets with VID not enabled on the switch */
ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag);
/* Discard packets with VID not enabled on the ingress port */ for (port = 0; port < dev->phy_port_cnt; ++port)
ksz_port_cfg(dev, port, REG_PORT_CTRL_2, PORT_INGRESS_FILTER,
flag);
return0;
}
staticvoid ksz8_port_enable_pvid(struct ksz_device *dev, int port, bool state)
{ if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev)) { int reg = REG_SW_INSERT_SRC_PVID;
if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev)) return -ENOTSUPP;
/* If a VLAN is added with untagged flag different from the *port'sRemoveTagflag,weneedtochangethelatter. *IgnoreVID0,whichisalwaysuntagged. *IgnoreCPUport,whichwillalwaysbetagged.
*/ if (untagged != p->remove_tag && vlan->vid != 0 &&
port != dev->cpu_port) { unsignedint vid;
/* Reject attempts to add a VLAN that requires the *RemoveTagflagtobechanged,unlessthereareno *otherVLANscurrentlyconfigured.
*/ for (vid = 1; vid < dev->info->num_vlans; ++vid) { /* Skip the VID we are going to add or reconfigure */ if (vid == vlan->vid) continue;
if (!p->interface && dev->compat_interface) {
dev_warn(dev->dev, "Using legacy switch \"phy-mode\" property, because it is missing on port %d node. " "Please update your device tree.\n",
port);
p->interface = dev->compat_interface;
}
}
if (cpu_port)
member = dsa_user_ports(ds); else
member = BIT(dsa_upstream_port(ds, port));
ksz8_cfg_port_member(dev, port, member);
/* Disable all WoL options by default. Otherwise *ksz_switch_macaddr_get/putlogicwillnotworkproperly. *CPUport4hasnoWoLfunctionality.
*/ if (ksz_is_ksz87xx(dev) && !cpu_port)
ksz8_pme_pwrite8(dev, port, regs[REG_PORT_PME_CTRL], 0);
}
for (i = 0; i < dev->phy_port_cnt; i++) {
ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED);
} for (i = 0; i < dev->phy_port_cnt; i++) {
p = &dev->ports[i];
/* For KSZ8795 family. */ if (ksz_is_ksz87xx(dev)) {
ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote); if (remote & KSZ8_PORT_FIBER_MODE)
p->fiber = 1;
} if (p->fiber)
ksz_port_cfg(dev, i, regs[P_STP_CTRL],
PORT_FORCE_FLOW_CTRL, true); else
ksz_port_cfg(dev, i, regs[P_STP_CTRL],
PORT_FORCE_FLOW_CTRL, false); if (p->fiber)
fiber_ports |= (1 << i);
} if (ksz_is_ksz8463(dev)) { /* Setup fiber ports. */ if (fiber_ports) {
fiber_ports &= 3;
regmap_update_bits(ksz_regmap_16(dev),
KSZ8463_REG_CFG_CTRL,
fiber_ports << PORT_COPPER_MODE_S, 0);
regmap_update_bits(ksz_regmap_16(dev),
KSZ8463_REG_DSP_CTRL_6,
COPPER_RECEIVE_ADJUSTMENT, 0);
}
/* Turn off PTP function as the switch's proprietary way of *handlingtimestampisnotsupportedincurrentLinuxPTP *stackimplementation.
*/
regmap_update_bits(ksz_regmap_16(dev),
KSZ8463_PTP_MSG_CONF1,
PTP_ENABLE, 0);
regmap_update_bits(ksz_regmap_16(dev),
KSZ8463_PTP_CLK_CTRL,
PTP_CLK_ENABLE, 0);
}
}
/* SW_FLOW_CTRL, SW_HALF_DUPLEX, and SW_10_MBIT bits are bootstrappable *atleastonKSZ8873.Theycanhavedifferentvaluesdependingonyour *boardsetup.
*/ if (tx_pause || rx_pause)
ctrl |= SW_FLOW_CTRL;
if (duplex == DUPLEX_HALF)
ctrl |= SW_HALF_DUPLEX;
/* This hardware only supports SPEED_10 and SPEED_100. For SPEED_10 *weneedtosettheSW_10_MBITbit.Otherwise,wecanleaveit0.
*/ if (speed == SPEED_10)
ctrl |= SW_10_MBIT;
void ksz8_phylink_mac_link_up(struct phylink_config *config, struct phy_device *phydev, unsignedint mode,
phy_interface_t interface, int speed, int duplex, bool tx_pause, bool rx_pause)
{ struct dsa_port *dp = dsa_phylink_to_port(config); struct ksz_device *dev = dp->ds->priv; int port = dp->index;
/* If the port is the CPU port, apply special handling. Only the CPU *portisconfiguredviaglobalregisters.
*/ if (dev->cpu_port == port)
ksz8_cpu_port_link_up(dev, speed, duplex, tx_pause, rx_pause); elseif (dev->info->internal_phy[port])
ksz8_phy_port_link_up(dev, port, duplex, tx_pause, rx_pause);
}
staticint ksz8_handle_global_errata(struct dsa_switch *ds)
{ struct ksz_device *dev = ds->priv; int ret = 0;
/* KSZ87xx Errata DS80000687C. *Module2:LinkdropswithsomeEEElinkpartners. *AnissuewiththeEEEnextpageexchangebetweenthe *KSZ879x/KSZ877x/KSZ876xandsomeEEElinkpartnersmayresultin *thelinkdropping.
*/ if (dev->info->ksz87xx_eee_link_erratum)
ret = ksz8_ind_write8(dev, TABLE_EEE, REG_IND_EEE_GLOB2_HI, 0);
return ret;
}
int ksz8_enable_stp_addr(struct ksz_device *dev)
{ struct alu_struct alu;
int ksz8_setup(struct dsa_switch *ds)
{ struct ksz_device *dev = ds->priv; const u16 *regs = dev->info->regs; int i, ret = 0;
ds->mtu_enforcement_ingress = true;
/* We rely on software untagging on the CPU port, so that we *cansupportbothtaggedanduntaggedVLANs
*/
ds->untag_bridge_pvid = true;
/* VLAN filtering is partly controlled by the global VLAN *Enableflag
*/
ds->vlan_filtering_is_global = true;
/* Enable automatic fast aging when link changed detected. */
ksz_cfg(dev, S_LINK_AGING_CTRL, SW_LINK_AUTO_AGING, true);
/* Enable aggressive back off algorithm in half duplex mode. */
ret = ksz_rmw8(dev, REG_SW_CTRL_1, SW_AGGR_BACKOFF, SW_AGGR_BACKOFF); if (ret) return ret;
/* *MakesureunicastVLANboundaryissetasdefaultand *enablenoexcessivecollisiondrop.
*/
ret = ksz_rmw8(dev, REG_SW_CTRL_2,
UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP,
UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP); if (ret) return ret;
if (!ksz_is_ksz88x3(dev) && !ksz_is_ksz8463(dev))
ksz_cfg(dev, REG_SW_CTRL_19, SW_INS_TAG_ENABLE, true);
for (i = 0; i < (dev->info->num_vlans / 4); i++)
ksz8_r_vlan_entries(dev, i);
/* Make sure PME (WoL) is not enabled. If requested, it will *beenabledbyksz_wol_pre_shutdown().Otherwise,somePMICs *donotlikePMEeventschangesbeforeshutdown.PMEonly *availableonKSZ87xxfamily.
*/ if (ksz_is_ksz87xx(dev)) {
ret = ksz8_pme_write8(dev, regs[REG_SW_PME_CTRL], 0); if (!ret)
ret = ksz_rmw8(dev, REG_INT_ENABLE, INT_PME, 0);
}
if (!ret) return ksz8_handle_global_errata(ds); else return ret;
}
int ksz8463_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
{
u16 sw_reg = 0;
u16 data = 0; int ret;
if (phy > 1) return -ENOSPC; switch (reg) { case MII_PHYSID1:
sw_reg = ksz8463_get_phy_addr(phy, 0, PHY1IHR); break; case MII_PHYSID2:
sw_reg = ksz8463_get_phy_addr(phy, 0, PHY1ILR); break; case MII_BMCR: case MII_BMSR: case MII_ADVERTISE: case MII_LPA:
sw_reg = ksz8463_get_phy_addr(phy, reg, P1MBCR); break; case MII_TPISTATUS: /* This register holds the PHY interrupt status for simulated *MicrelKSZPHY.
*/
data = 0x0505; break; default: break;
} if (sw_reg) {
ret = ksz_read16(dev, sw_reg, &data); if (ret) return ret;
}
*val = data;
return0;
}
int ksz8463_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
{
u16 sw_reg = 0; int ret;
if (phy > 1) return -ENOSPC;
/* No write to fiber port. */ if (dev->ports[phy].fiber) return0; switch (reg) { case MII_BMCR: case MII_ADVERTISE:
sw_reg = ksz8463_get_phy_addr(phy, reg, P1MBCR); break; default: break;
} if (sw_reg) {
ret = ksz_write16(dev, sw_reg, val); if (ret) return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.