Commit 12717dec authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: enetc: implement software lockstep for port MAC registers

Currently the enetc driver duplicates its writes to the PM0 registers
also to PM1, but it doesn't do this consistently - for example we write
to ENETC_PM0_MAXFRM but not to ENETC_PM1_MAXFRM.

Create enetc_port_mac_wr() which writes both the PM0 and PM1 register
with the same value (if frame preemption is supported on this port).
Also create enetc_port_mac_rd() which reads from PM0 - the assumption
being that PM1 contains just the same value.

This will be necessary when we enable the MAC Merge layer properly, and
the pMAC becomes operational.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 219355f1
...@@ -11,6 +11,20 @@ ...@@ -11,6 +11,20 @@
#include <net/pkt_sched.h> #include <net/pkt_sched.h>
#include <net/tso.h> #include <net/tso.h>
u32 enetc_port_mac_rd(struct enetc_si *si, u32 reg)
{
return enetc_port_rd(&si->hw, reg);
}
EXPORT_SYMBOL_GPL(enetc_port_mac_rd);
void enetc_port_mac_wr(struct enetc_si *si, u32 reg, u32 val)
{
enetc_port_wr(&si->hw, reg, val);
if (si->hw_features & ENETC_SI_F_QBU)
enetc_port_wr(&si->hw, reg + ENETC_PMAC_OFFSET, val);
}
EXPORT_SYMBOL_GPL(enetc_port_mac_wr);
static int enetc_num_stack_tx_queues(struct enetc_ndev_priv *priv) static int enetc_num_stack_tx_queues(struct enetc_ndev_priv *priv)
{ {
int num_tx_rings = priv->num_tx_rings; int num_tx_rings = priv->num_tx_rings;
...@@ -243,8 +257,8 @@ static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb) ...@@ -243,8 +257,8 @@ static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb)
if (udp) if (udp)
val |= ENETC_PM0_SINGLE_STEP_CH; val |= ENETC_PM0_SINGLE_STEP_CH;
enetc_port_wr(hw, ENETC_PM0_SINGLE_STEP, val); enetc_port_mac_wr(priv->si, ENETC_PM0_SINGLE_STEP,
enetc_port_wr(hw, ENETC_PM1_SINGLE_STEP, val); val);
} else if (do_twostep_tstamp) { } else if (do_twostep_tstamp) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
e_flags |= ENETC_TXBD_E_FLAGS_TWO_STEP_PTP; e_flags |= ENETC_TXBD_E_FLAGS_TWO_STEP_PTP;
......
...@@ -397,6 +397,8 @@ struct enetc_msg_cmd_set_primary_mac { ...@@ -397,6 +397,8 @@ struct enetc_msg_cmd_set_primary_mac {
extern int enetc_phc_index; extern int enetc_phc_index;
/* SI common */ /* SI common */
u32 enetc_port_mac_rd(struct enetc_si *si, u32 reg);
void enetc_port_mac_wr(struct enetc_si *si, u32 reg, u32 val);
int enetc_pci_probe(struct pci_dev *pdev, const char *name, int sizeof_priv); int enetc_pci_probe(struct pci_dev *pdev, const char *name, int sizeof_priv);
void enetc_pci_remove(struct pci_dev *pdev); void enetc_pci_remove(struct pci_dev *pdev);
int enetc_alloc_msix(struct enetc_ndev_priv *priv); int enetc_alloc_msix(struct enetc_ndev_priv *priv);
......
...@@ -228,7 +228,6 @@ enum enetc_bdr_type {TX, RX}; ...@@ -228,7 +228,6 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PMAC_OFFSET 0x1000 #define ENETC_PMAC_OFFSET 0x1000
#define ENETC_PM0_CMD_CFG 0x8008 #define ENETC_PM0_CMD_CFG 0x8008
#define ENETC_PM1_CMD_CFG 0x9008
#define ENETC_PM0_TX_EN BIT(0) #define ENETC_PM0_TX_EN BIT(0)
#define ENETC_PM0_RX_EN BIT(1) #define ENETC_PM0_RX_EN BIT(1)
#define ENETC_PM0_PROMISC BIT(4) #define ENETC_PM0_PROMISC BIT(4)
...@@ -247,11 +246,8 @@ enum enetc_bdr_type {TX, RX}; ...@@ -247,11 +246,8 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PM0_PAUSE_QUANTA 0x8054 #define ENETC_PM0_PAUSE_QUANTA 0x8054
#define ENETC_PM0_PAUSE_THRESH 0x8064 #define ENETC_PM0_PAUSE_THRESH 0x8064
#define ENETC_PM1_PAUSE_QUANTA 0x9054
#define ENETC_PM1_PAUSE_THRESH 0x9064
#define ENETC_PM0_SINGLE_STEP 0x80c0 #define ENETC_PM0_SINGLE_STEP 0x80c0
#define ENETC_PM1_SINGLE_STEP 0x90c0
#define ENETC_PM0_SINGLE_STEP_CH BIT(7) #define ENETC_PM0_SINGLE_STEP_CH BIT(7)
#define ENETC_PM0_SINGLE_STEP_EN BIT(31) #define ENETC_PM0_SINGLE_STEP_EN BIT(31)
#define ENETC_SET_SINGLE_STEP_OFFSET(v) (((v) & 0xff) << 8) #define ENETC_SET_SINGLE_STEP_OFFSET(v) (((v) & 0xff) << 8)
......
...@@ -319,24 +319,23 @@ static int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid) ...@@ -319,24 +319,23 @@ static int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid)
static void enetc_set_loopback(struct net_device *ndev, bool en) static void enetc_set_loopback(struct net_device *ndev, bool en)
{ {
struct enetc_ndev_priv *priv = netdev_priv(ndev); struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct enetc_hw *hw = &priv->si->hw; struct enetc_si *si = priv->si;
u32 reg; u32 reg;
reg = enetc_port_rd(hw, ENETC_PM0_IF_MODE); reg = enetc_port_mac_rd(si, ENETC_PM0_IF_MODE);
if (reg & ENETC_PM0_IFM_RG) { if (reg & ENETC_PM0_IFM_RG) {
/* RGMII mode */ /* RGMII mode */
reg = (reg & ~ENETC_PM0_IFM_RLP) | reg = (reg & ~ENETC_PM0_IFM_RLP) |
(en ? ENETC_PM0_IFM_RLP : 0); (en ? ENETC_PM0_IFM_RLP : 0);
enetc_port_wr(hw, ENETC_PM0_IF_MODE, reg); enetc_port_mac_wr(si, ENETC_PM0_IF_MODE, reg);
} else { } else {
/* assume SGMII mode */ /* assume SGMII mode */
reg = enetc_port_rd(hw, ENETC_PM0_CMD_CFG); reg = enetc_port_mac_rd(si, ENETC_PM0_CMD_CFG);
reg = (reg & ~ENETC_PM0_CMD_XGLP) | reg = (reg & ~ENETC_PM0_CMD_XGLP) |
(en ? ENETC_PM0_CMD_XGLP : 0); (en ? ENETC_PM0_CMD_XGLP : 0);
reg = (reg & ~ENETC_PM0_CMD_PHY_TX_EN) | reg = (reg & ~ENETC_PM0_CMD_PHY_TX_EN) |
(en ? ENETC_PM0_CMD_PHY_TX_EN : 0); (en ? ENETC_PM0_CMD_PHY_TX_EN : 0);
enetc_port_wr(hw, ENETC_PM0_CMD_CFG, reg); enetc_port_mac_wr(si, ENETC_PM0_CMD_CFG, reg);
enetc_port_wr(hw, ENETC_PM1_CMD_CFG, reg);
} }
} }
...@@ -538,52 +537,50 @@ void enetc_reset_ptcmsdur(struct enetc_hw *hw) ...@@ -538,52 +537,50 @@ void enetc_reset_ptcmsdur(struct enetc_hw *hw)
enetc_port_wr(hw, ENETC_PTCMSDUR(tc), ENETC_MAC_MAXFRM_SIZE); enetc_port_wr(hw, ENETC_PTCMSDUR(tc), ENETC_MAC_MAXFRM_SIZE);
} }
static void enetc_configure_port_mac(struct enetc_hw *hw) static void enetc_configure_port_mac(struct enetc_si *si)
{ {
enetc_port_wr(hw, ENETC_PM0_MAXFRM, struct enetc_hw *hw = &si->hw;
ENETC_SET_MAXFRM(ENETC_RX_MAXFRM_SIZE));
enetc_reset_ptcmsdur(hw); enetc_port_mac_wr(si, ENETC_PM0_MAXFRM,
ENETC_SET_MAXFRM(ENETC_RX_MAXFRM_SIZE));
enetc_port_wr(hw, ENETC_PM0_CMD_CFG, ENETC_PM0_CMD_PHY_TX_EN | enetc_reset_ptcmsdur(hw);
ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC);
enetc_port_wr(hw, ENETC_PM1_CMD_CFG, ENETC_PM0_CMD_PHY_TX_EN | enetc_port_mac_wr(si, ENETC_PM0_CMD_CFG, ENETC_PM0_CMD_PHY_TX_EN |
ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC); ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC);
/* On LS1028A, the MAC RX FIFO defaults to 2, which is too high /* On LS1028A, the MAC RX FIFO defaults to 2, which is too high
* and may lead to RX lock-up under traffic. Set it to 1 instead, * and may lead to RX lock-up under traffic. Set it to 1 instead,
* as recommended by the hardware team. * as recommended by the hardware team.
*/ */
enetc_port_wr(hw, ENETC_PM0_RX_FIFO, ENETC_PM0_RX_FIFO_VAL); enetc_port_mac_wr(si, ENETC_PM0_RX_FIFO, ENETC_PM0_RX_FIFO_VAL);
} }
static void enetc_mac_config(struct enetc_hw *hw, phy_interface_t phy_mode) static void enetc_mac_config(struct enetc_si *si, phy_interface_t phy_mode)
{ {
u32 val; u32 val;
if (phy_interface_mode_is_rgmii(phy_mode)) { if (phy_interface_mode_is_rgmii(phy_mode)) {
val = enetc_port_rd(hw, ENETC_PM0_IF_MODE); val = enetc_port_mac_rd(si, ENETC_PM0_IF_MODE);
val &= ~(ENETC_PM0_IFM_EN_AUTO | ENETC_PM0_IFM_IFMODE_MASK); val &= ~(ENETC_PM0_IFM_EN_AUTO | ENETC_PM0_IFM_IFMODE_MASK);
val |= ENETC_PM0_IFM_IFMODE_GMII | ENETC_PM0_IFM_RG; val |= ENETC_PM0_IFM_IFMODE_GMII | ENETC_PM0_IFM_RG;
enetc_port_wr(hw, ENETC_PM0_IF_MODE, val); enetc_port_mac_wr(si, ENETC_PM0_IF_MODE, val);
} }
if (phy_mode == PHY_INTERFACE_MODE_USXGMII) { if (phy_mode == PHY_INTERFACE_MODE_USXGMII) {
val = ENETC_PM0_IFM_FULL_DPX | ENETC_PM0_IFM_IFMODE_XGMII; val = ENETC_PM0_IFM_FULL_DPX | ENETC_PM0_IFM_IFMODE_XGMII;
enetc_port_wr(hw, ENETC_PM0_IF_MODE, val); enetc_port_mac_wr(si, ENETC_PM0_IF_MODE, val);
} }
} }
static void enetc_mac_enable(struct enetc_hw *hw, bool en) static void enetc_mac_enable(struct enetc_si *si, bool en)
{ {
u32 val = enetc_port_rd(hw, ENETC_PM0_CMD_CFG); u32 val = enetc_port_mac_rd(si, ENETC_PM0_CMD_CFG);
val &= ~(ENETC_PM0_TX_EN | ENETC_PM0_RX_EN); val &= ~(ENETC_PM0_TX_EN | ENETC_PM0_RX_EN);
val |= en ? (ENETC_PM0_TX_EN | ENETC_PM0_RX_EN) : 0; val |= en ? (ENETC_PM0_TX_EN | ENETC_PM0_RX_EN) : 0;
enetc_port_wr(hw, ENETC_PM0_CMD_CFG, val); enetc_port_mac_wr(si, ENETC_PM0_CMD_CFG, val);
enetc_port_wr(hw, ENETC_PM1_CMD_CFG, val);
} }
static void enetc_configure_port_pmac(struct enetc_hw *hw) static void enetc_configure_port_pmac(struct enetc_hw *hw)
...@@ -604,7 +601,7 @@ static void enetc_configure_port(struct enetc_pf *pf) ...@@ -604,7 +601,7 @@ static void enetc_configure_port(struct enetc_pf *pf)
enetc_configure_port_pmac(hw); enetc_configure_port_pmac(hw);
enetc_configure_port_mac(hw); enetc_configure_port_mac(pf->si);
enetc_port_si_configure(pf->si); enetc_port_si_configure(pf->si);
...@@ -996,14 +993,14 @@ static void enetc_pl_mac_config(struct phylink_config *config, ...@@ -996,14 +993,14 @@ static void enetc_pl_mac_config(struct phylink_config *config,
{ {
struct enetc_pf *pf = phylink_to_enetc_pf(config); struct enetc_pf *pf = phylink_to_enetc_pf(config);
enetc_mac_config(&pf->si->hw, state->interface); enetc_mac_config(pf->si, state->interface);
} }
static void enetc_force_rgmii_mac(struct enetc_hw *hw, int speed, int duplex) static void enetc_force_rgmii_mac(struct enetc_si *si, int speed, int duplex)
{ {
u32 old_val, val; u32 old_val, val;
old_val = val = enetc_port_rd(hw, ENETC_PM0_IF_MODE); old_val = val = enetc_port_mac_rd(si, ENETC_PM0_IF_MODE);
if (speed == SPEED_1000) { if (speed == SPEED_1000) {
val &= ~ENETC_PM0_IFM_SSP_MASK; val &= ~ENETC_PM0_IFM_SSP_MASK;
...@@ -1024,7 +1021,7 @@ static void enetc_force_rgmii_mac(struct enetc_hw *hw, int speed, int duplex) ...@@ -1024,7 +1021,7 @@ static void enetc_force_rgmii_mac(struct enetc_hw *hw, int speed, int duplex)
if (val == old_val) if (val == old_val)
return; return;
enetc_port_wr(hw, ENETC_PM0_IF_MODE, val); enetc_port_mac_wr(si, ENETC_PM0_IF_MODE, val);
} }
static void enetc_pl_mac_link_up(struct phylink_config *config, static void enetc_pl_mac_link_up(struct phylink_config *config,
...@@ -1036,6 +1033,7 @@ static void enetc_pl_mac_link_up(struct phylink_config *config, ...@@ -1036,6 +1033,7 @@ static void enetc_pl_mac_link_up(struct phylink_config *config,
u32 pause_off_thresh = 0, pause_on_thresh = 0; u32 pause_off_thresh = 0, pause_on_thresh = 0;
u32 init_quanta = 0, refresh_quanta = 0; u32 init_quanta = 0, refresh_quanta = 0;
struct enetc_hw *hw = &pf->si->hw; struct enetc_hw *hw = &pf->si->hw;
struct enetc_si *si = pf->si;
struct enetc_ndev_priv *priv; struct enetc_ndev_priv *priv;
u32 rbmr, cmd_cfg; u32 rbmr, cmd_cfg;
int idx; int idx;
...@@ -1047,7 +1045,7 @@ static void enetc_pl_mac_link_up(struct phylink_config *config, ...@@ -1047,7 +1045,7 @@ static void enetc_pl_mac_link_up(struct phylink_config *config,
if (!phylink_autoneg_inband(mode) && if (!phylink_autoneg_inband(mode) &&
phy_interface_mode_is_rgmii(interface)) phy_interface_mode_is_rgmii(interface))
enetc_force_rgmii_mac(hw, speed, duplex); enetc_force_rgmii_mac(si, speed, duplex);
/* Flow control */ /* Flow control */
for (idx = 0; idx < priv->num_rx_rings; idx++) { for (idx = 0; idx < priv->num_rx_rings; idx++) {
...@@ -1083,24 +1081,21 @@ static void enetc_pl_mac_link_up(struct phylink_config *config, ...@@ -1083,24 +1081,21 @@ static void enetc_pl_mac_link_up(struct phylink_config *config,
pause_off_thresh = 1 * ENETC_MAC_MAXFRM_SIZE; pause_off_thresh = 1 * ENETC_MAC_MAXFRM_SIZE;
} }
enetc_port_wr(hw, ENETC_PM0_PAUSE_QUANTA, init_quanta); enetc_port_mac_wr(si, ENETC_PM0_PAUSE_QUANTA, init_quanta);
enetc_port_wr(hw, ENETC_PM1_PAUSE_QUANTA, init_quanta); enetc_port_mac_wr(si, ENETC_PM0_PAUSE_THRESH, refresh_quanta);
enetc_port_wr(hw, ENETC_PM0_PAUSE_THRESH, refresh_quanta);
enetc_port_wr(hw, ENETC_PM1_PAUSE_THRESH, refresh_quanta);
enetc_port_wr(hw, ENETC_PPAUONTR, pause_on_thresh); enetc_port_wr(hw, ENETC_PPAUONTR, pause_on_thresh);
enetc_port_wr(hw, ENETC_PPAUOFFTR, pause_off_thresh); enetc_port_wr(hw, ENETC_PPAUOFFTR, pause_off_thresh);
cmd_cfg = enetc_port_rd(hw, ENETC_PM0_CMD_CFG); cmd_cfg = enetc_port_mac_rd(si, ENETC_PM0_CMD_CFG);
if (rx_pause) if (rx_pause)
cmd_cfg &= ~ENETC_PM0_PAUSE_IGN; cmd_cfg &= ~ENETC_PM0_PAUSE_IGN;
else else
cmd_cfg |= ENETC_PM0_PAUSE_IGN; cmd_cfg |= ENETC_PM0_PAUSE_IGN;
enetc_port_wr(hw, ENETC_PM0_CMD_CFG, cmd_cfg); enetc_port_mac_wr(si, ENETC_PM0_CMD_CFG, cmd_cfg);
enetc_port_wr(hw, ENETC_PM1_CMD_CFG, cmd_cfg);
enetc_mac_enable(hw, true); enetc_mac_enable(si, true);
} }
static void enetc_pl_mac_link_down(struct phylink_config *config, static void enetc_pl_mac_link_down(struct phylink_config *config,
...@@ -1109,7 +1104,7 @@ static void enetc_pl_mac_link_down(struct phylink_config *config, ...@@ -1109,7 +1104,7 @@ static void enetc_pl_mac_link_down(struct phylink_config *config,
{ {
struct enetc_pf *pf = phylink_to_enetc_pf(config); struct enetc_pf *pf = phylink_to_enetc_pf(config);
enetc_mac_enable(&pf->si->hw, false); enetc_mac_enable(pf->si, false);
} }
static const struct phylink_mac_ops enetc_mac_phylink_ops = { static const struct phylink_mac_ops enetc_mac_phylink_ops = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment