net: netcp: Fixes SGMII reset on network interface shutdown
This patch asserts SGMII RTRESET, i.e. resetting the SGMII Tx/Rx logic, during network interface shutdown to avoid having the hardware wedge when shutting down with high incoming traffic rates. This is cleared (brought out of RTRESET) when the interface is brought back up. Signed-off-by: WingMan Kwok <w-kwok2@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
54109da31f
commit
7025e88a79
@ -223,6 +223,7 @@ void *netcp_device_find_module(struct netcp_device *netcp_device,
|
||||
|
||||
/* SGMII functions */
|
||||
int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port);
|
||||
bool netcp_sgmii_rtreset(void __iomem *sgmii_ofs, int port, bool set);
|
||||
int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port);
|
||||
int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface);
|
||||
|
||||
|
@ -1901,11 +1901,28 @@ static void gbe_port_config(struct gbe_priv *gbe_dev, struct gbe_slave *slave,
|
||||
writel(slave->mac_control, GBE_REG_ADDR(slave, emac_regs, mac_control));
|
||||
}
|
||||
|
||||
static void gbe_sgmii_rtreset(struct gbe_priv *priv,
|
||||
struct gbe_slave *slave, bool set)
|
||||
{
|
||||
void __iomem *sgmii_port_regs;
|
||||
|
||||
if (SLAVE_LINK_IS_XGMII(slave))
|
||||
return;
|
||||
|
||||
if ((priv->ss_version == GBE_SS_VERSION_14) && (slave->slave_num >= 2))
|
||||
sgmii_port_regs = priv->sgmii_port34_regs;
|
||||
else
|
||||
sgmii_port_regs = priv->sgmii_port_regs;
|
||||
|
||||
netcp_sgmii_rtreset(sgmii_port_regs, slave->slave_num, set);
|
||||
}
|
||||
|
||||
static void gbe_slave_stop(struct gbe_intf *intf)
|
||||
{
|
||||
struct gbe_priv *gbe_dev = intf->gbe_dev;
|
||||
struct gbe_slave *slave = intf->slave;
|
||||
|
||||
gbe_sgmii_rtreset(gbe_dev, slave, true);
|
||||
gbe_port_reset(slave);
|
||||
/* Disable forwarding */
|
||||
cpsw_ale_control_set(gbe_dev->ale, slave->port_num,
|
||||
@ -1947,6 +1964,7 @@ static int gbe_slave_open(struct gbe_intf *gbe_intf)
|
||||
|
||||
gbe_sgmii_config(priv, slave);
|
||||
gbe_port_reset(slave);
|
||||
gbe_sgmii_rtreset(priv, slave, false);
|
||||
gbe_port_config(priv, slave, priv->rx_packet_max);
|
||||
gbe_set_slave_mac(slave, gbe_intf);
|
||||
/* enable forwarding */
|
||||
|
@ -18,6 +18,9 @@
|
||||
|
||||
#include "netcp.h"
|
||||
|
||||
#define SGMII_SRESET_RESET BIT(0)
|
||||
#define SGMII_SRESET_RTRESET BIT(1)
|
||||
|
||||
#define SGMII_REG_STATUS_LOCK BIT(4)
|
||||
#define SGMII_REG_STATUS_LINK BIT(0)
|
||||
#define SGMII_REG_STATUS_AUTONEG BIT(2)
|
||||
@ -51,12 +54,35 @@ static void sgmii_write_reg_bit(void __iomem *base, int reg, u32 val)
|
||||
int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port)
|
||||
{
|
||||
/* Soft reset */
|
||||
sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port), 0x1);
|
||||
while (sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) != 0x0)
|
||||
sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port),
|
||||
SGMII_SRESET_RESET);
|
||||
|
||||
while ((sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) &
|
||||
SGMII_SRESET_RESET) != 0x0)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* port is 0 based */
|
||||
bool netcp_sgmii_rtreset(void __iomem *sgmii_ofs, int port, bool set)
|
||||
{
|
||||
u32 reg;
|
||||
bool oldval;
|
||||
|
||||
/* Initiate a soft reset */
|
||||
reg = sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port));
|
||||
oldval = (reg & SGMII_SRESET_RTRESET) != 0x0;
|
||||
if (set)
|
||||
reg |= SGMII_SRESET_RTRESET;
|
||||
else
|
||||
reg &= ~SGMII_SRESET_RTRESET;
|
||||
sgmii_write_reg(sgmii_ofs, SGMII_SRESET_REG(port), reg);
|
||||
wmb();
|
||||
|
||||
return oldval;
|
||||
}
|
||||
|
||||
int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port)
|
||||
{
|
||||
u32 status = 0, link = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user