|
|
|
@@ -1439,6 +1439,127 @@ void ksz8_config_cpu_port(struct dsa_switch *ds)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ksz8_phy_port_link_up - Configures ports with integrated PHYs
|
|
|
|
|
* @dev: The KSZ device instance.
|
|
|
|
|
* @port: The port number to configure.
|
|
|
|
|
* @duplex: The desired duplex mode.
|
|
|
|
|
* @tx_pause: If true, enables transmit pause.
|
|
|
|
|
* @rx_pause: If true, enables receive pause.
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* The function configures flow control settings for a given port based on the
|
|
|
|
|
* desired settings and current duplex mode.
|
|
|
|
|
*
|
|
|
|
|
* According to the KSZ8873 datasheet, the PORT_FORCE_FLOW_CTRL bit in the
|
|
|
|
|
* Port Control 2 register (0x1A for Port 1, 0x22 for Port 2, 0x32 for Port 3)
|
|
|
|
|
* determines how flow control is handled on the port:
|
|
|
|
|
* "1 = will always enable full-duplex flow control on the port, regardless
|
|
|
|
|
* of AN result.
|
|
|
|
|
* 0 = full-duplex flow control is enabled based on AN result."
|
|
|
|
|
*
|
|
|
|
|
* This means that the flow control behavior depends on the state of this bit:
|
|
|
|
|
* - If PORT_FORCE_FLOW_CTRL is set to 1, the switch will ignore AN results and
|
|
|
|
|
* force flow control on the port.
|
|
|
|
|
* - If PORT_FORCE_FLOW_CTRL is set to 0, the switch will enable or disable
|
|
|
|
|
* flow control based on the AN results.
|
|
|
|
|
*
|
|
|
|
|
* However, there is a potential limitation in this configuration. It is
|
|
|
|
|
* currently not possible to force disable flow control on a port if we still
|
|
|
|
|
* advertise pause support. While such a configuration is not currently
|
|
|
|
|
* supported by Linux, and may not make practical sense, it's important to be
|
|
|
|
|
* aware of this limitation when working with the KSZ8873 and similar devices.
|
|
|
|
|
*/
|
|
|
|
|
static void ksz8_phy_port_link_up(struct ksz_device *dev, int port, int duplex,
|
|
|
|
|
bool tx_pause, bool rx_pause)
|
|
|
|
|
{
|
|
|
|
|
const u16 *regs = dev->info->regs;
|
|
|
|
|
u8 sctrl = 0;
|
|
|
|
|
|
|
|
|
|
/* The KSZ8795 switch differs from the KSZ8873 by supporting
|
|
|
|
|
* asymmetric pause control. However, since a single bit is used to
|
|
|
|
|
* control both RX and TX pause, we can't enforce asymmetric pause
|
|
|
|
|
* control - both TX and RX pause will be either enabled or disabled
|
|
|
|
|
* together.
|
|
|
|
|
*
|
|
|
|
|
* If auto-negotiation is enabled, we usually allow the flow control to
|
|
|
|
|
* be determined by the auto-negotiation process based on the
|
|
|
|
|
* capabilities of both link partners. However, for KSZ8873, the
|
|
|
|
|
* PORT_FORCE_FLOW_CTRL bit may be set by the hardware bootstrap,
|
|
|
|
|
* ignoring the auto-negotiation result. Thus, even in auto-negotiation
|
|
|
|
|
* mode, we need to ensure that the PORT_FORCE_FLOW_CTRL bit is
|
|
|
|
|
* properly cleared.
|
|
|
|
|
*
|
|
|
|
|
* In the absence of pause auto-negotiation, we will enforce symmetric
|
|
|
|
|
* pause control for both variants of switches - KSZ8873 and KSZ8795.
|
|
|
|
|
*
|
|
|
|
|
* Autoneg Pause Autoneg rx,tx PORT_FORCE_FLOW_CTRL
|
|
|
|
|
* 1 1 x 0
|
|
|
|
|
* 0 1 x 0 (flow control probably disabled)
|
|
|
|
|
* x 0 1 1 (flow control force enabled)
|
|
|
|
|
* 1 0 0 0 (flow control still depends on
|
|
|
|
|
* aneg result due to hardware)
|
|
|
|
|
* 0 0 0 0 (flow control probably disabled)
|
|
|
|
|
*/
|
|
|
|
|
if (dev->ports[port].manual_flow && tx_pause)
|
|
|
|
|
sctrl |= PORT_FORCE_FLOW_CTRL;
|
|
|
|
|
|
|
|
|
|
ksz_prmw8(dev, port, regs[P_STP_CTRL], PORT_FORCE_FLOW_CTRL, sctrl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ksz8_cpu_port_link_up - Configures the CPU port of the switch.
|
|
|
|
|
* @dev: The KSZ device instance.
|
|
|
|
|
* @speed: The desired link speed.
|
|
|
|
|
* @duplex: The desired duplex mode.
|
|
|
|
|
* @tx_pause: If true, enables transmit pause.
|
|
|
|
|
* @rx_pause: If true, enables receive pause.
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* The function configures flow control and speed settings for the CPU
|
|
|
|
|
* port of the switch based on the desired settings, current duplex mode, and
|
|
|
|
|
* speed.
|
|
|
|
|
*/
|
|
|
|
|
static void ksz8_cpu_port_link_up(struct ksz_device *dev, int speed, int duplex,
|
|
|
|
|
bool tx_pause, bool rx_pause)
|
|
|
|
|
{
|
|
|
|
|
const u16 *regs = dev->info->regs;
|
|
|
|
|
u8 ctrl = 0;
|
|
|
|
|
|
|
|
|
|
/* SW_FLOW_CTRL, SW_HALF_DUPLEX, and SW_10_MBIT bits are bootstrappable
|
|
|
|
|
* at least on KSZ8873. They can have different values depending on your
|
|
|
|
|
* board setup.
|
|
|
|
|
*/
|
|
|
|
|
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
|
|
|
|
|
* we need to set the SW_10_MBIT bit. Otherwise, we can leave it 0.
|
|
|
|
|
*/
|
|
|
|
|
if (speed == SPEED_10)
|
|
|
|
|
ctrl |= SW_10_MBIT;
|
|
|
|
|
|
|
|
|
|
ksz_rmw8(dev, regs[S_BROADCAST_CTRL], SW_HALF_DUPLEX | SW_FLOW_CTRL |
|
|
|
|
|
SW_10_MBIT, ctrl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ksz8_phylink_mac_link_up(struct ksz_device *dev, int port,
|
|
|
|
|
unsigned int mode, phy_interface_t interface,
|
|
|
|
|
struct phy_device *phydev, int speed, int duplex,
|
|
|
|
|
bool tx_pause, bool rx_pause)
|
|
|
|
|
{
|
|
|
|
|
/* If the port is the CPU port, apply special handling. Only the CPU
|
|
|
|
|
* port is configured via global registers.
|
|
|
|
|
*/
|
|
|
|
|
if (dev->cpu_port == port)
|
|
|
|
|
ksz8_cpu_port_link_up(dev, speed, duplex, tx_pause, rx_pause);
|
|
|
|
|
else if (dev->info->internal_phy[port])
|
|
|
|
|
ksz8_phy_port_link_up(dev, port, duplex, tx_pause, rx_pause);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ksz8_handle_global_errata(struct dsa_switch *ds)
|
|
|
|
|
{
|
|
|
|
|
struct ksz_device *dev = ds->priv;
|
|
|
|
@@ -1487,8 +1608,6 @@ int ksz8_setup(struct dsa_switch *ds)
|
|
|
|
|
*/
|
|
|
|
|
ds->vlan_filtering_is_global = true;
|
|
|
|
|
|
|
|
|
|
ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_FLOW_CTRL, true);
|
|
|
|
|
|
|
|
|
|
/* Enable automatic fast aging when link changed detected. */
|
|
|
|
|
ksz_cfg(dev, S_LINK_AGING_CTRL, SW_LINK_AUTO_AGING, true);
|
|
|
|
|
|
|
|
|
|