summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/freescale/enetc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/freescale/enetc')
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.c72
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.h9
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc4_pf.c16
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_pf.c14
4 files changed, 72 insertions, 39 deletions
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 8e3f345dd9aa..80f0082f6c63 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -81,6 +81,33 @@ void enetc_reset_mac_addr_filter(struct enetc_mac_filter *filter)
}
EXPORT_SYMBOL_GPL(enetc_reset_mac_addr_filter);
+void enetc_set_congestion_mode(struct enetc_ndev_priv *priv, bool enable)
+{
+ struct enetc_si *si = priv->si;
+ struct enetc_hw *hw = &si->hw;
+
+ spin_lock(&si->gen_lock);
+
+ if (enable)
+ set_bit(ENETC_RXBDR_CM, &priv->flags);
+ else
+ clear_bit(ENETC_RXBDR_CM, &priv->flags);
+
+ for (int i = 0; i < priv->num_rx_rings; i++) {
+ u32 old_rbmr = enetc_rxbdr_rd(hw, i, ENETC_RBMR);
+ u32 rbmr;
+
+ rbmr = u32_replace_bits(old_rbmr, enable, ENETC_RBMR_CM);
+ if (rbmr == old_rbmr)
+ continue;
+
+ enetc_rxbdr_wr(hw, i, ENETC_RBMR, rbmr);
+ }
+
+ spin_unlock(&si->gen_lock);
+}
+EXPORT_SYMBOL_GPL(enetc_set_congestion_mode);
+
static int enetc_num_stack_tx_queues(struct enetc_ndev_priv *priv)
{
int num_tx_rings = priv->num_tx_rings;
@@ -2632,7 +2659,6 @@ static void enetc_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring,
bool extended)
{
int idx = rx_ring->index;
- u32 rbmr = 0;
enetc_rxbdr_wr(hw, idx, ENETC_RBBAR0,
lower_32_bits(rx_ring->bd_dma_base));
@@ -2660,12 +2686,6 @@ static void enetc_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring,
enetc_rxbdr_wr(hw, idx, ENETC_RBICR0, ENETC_RBICR0_ICEN | 0x1);
rx_ring->ext_en = extended;
- if (rx_ring->ext_en)
- rbmr |= ENETC_RBMR_BDS;
-
- if (rx_ring->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
- rbmr |= ENETC_RBMR_VTE;
-
rx_ring->rcir = hw->reg + ENETC_BDR(RX, idx, ENETC_RBCIR);
rx_ring->idr = hw->reg + ENETC_SIRXIDR;
@@ -2676,8 +2696,6 @@ static void enetc_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring,
enetc_lock_mdio();
enetc_refill_rx_ring(rx_ring, enetc_bd_unused(rx_ring));
enetc_unlock_mdio();
-
- enetc_rxbdr_wr(hw, idx, ENETC_RBMR, rbmr);
}
static void enetc_setup_bdrs(struct enetc_ndev_priv *priv, bool extended)
@@ -2704,21 +2722,34 @@ static void enetc_enable_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
static void enetc_enable_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring)
{
+ struct enetc_ndev_priv *priv = netdev_priv(rx_ring->ndev);
int idx = rx_ring->index;
- u32 rbmr;
+ u32 rbmr = ENETC_RBMR_EN;
+
+ if (rx_ring->ext_en)
+ rbmr |= ENETC_RBMR_BDS;
+
+ if (rx_ring->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
+ rbmr |= ENETC_RBMR_VTE;
+
+ if (test_bit(ENETC_RXBDR_CM, &priv->flags))
+ rbmr |= ENETC_RBMR_CM;
- rbmr = enetc_rxbdr_rd(hw, idx, ENETC_RBMR);
- rbmr |= ENETC_RBMR_EN;
enetc_rxbdr_wr(hw, idx, ENETC_RBMR, rbmr);
}
static void enetc_enable_rx_bdrs(struct enetc_ndev_priv *priv)
{
- struct enetc_hw *hw = &priv->si->hw;
+ struct enetc_si *si = priv->si;
+ struct enetc_hw *hw = &si->hw;
int i;
+ spin_lock(&si->gen_lock);
+
for (i = 0; i < priv->num_rx_rings; i++)
enetc_enable_rxbdr(hw, priv->rx_ring[i]);
+
+ spin_unlock(&si->gen_lock);
}
static void enetc_enable_tx_bdrs(struct enetc_ndev_priv *priv)
@@ -2748,11 +2779,16 @@ static void enetc_disable_txbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring)
static void enetc_disable_rx_bdrs(struct enetc_ndev_priv *priv)
{
- struct enetc_hw *hw = &priv->si->hw;
+ struct enetc_si *si = priv->si;
+ struct enetc_hw *hw = &si->hw;
int i;
+ spin_lock(&si->gen_lock);
+
for (i = 0; i < priv->num_rx_rings; i++)
enetc_disable_rxbdr(hw, priv->rx_ring[i]);
+
+ spin_unlock(&si->gen_lock);
}
static void enetc_disable_tx_bdrs(struct enetc_ndev_priv *priv)
@@ -3344,11 +3380,16 @@ EXPORT_SYMBOL_GPL(enetc_get_stats);
static void enetc_enable_rxvlan(struct net_device *ndev, bool en)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
- struct enetc_hw *hw = &priv->si->hw;
+ struct enetc_si *si = priv->si;
+ struct enetc_hw *hw = &si->hw;
int i;
+ spin_lock(&si->gen_lock);
+
for (i = 0; i < priv->num_rx_rings; i++)
enetc_bdr_enable_rxvlan(hw, i, en);
+
+ spin_unlock(&si->gen_lock);
}
static void enetc_enable_txvlan(struct net_device *ndev, bool en)
@@ -3679,6 +3720,7 @@ int enetc_pci_probe(struct pci_dev *pdev, const char *name, int sizeof_priv)
si = PTR_ALIGN(p, ENETC_SI_ALIGN);
si->pad = (char *)si - (char *)p;
+ spin_lock_init(&si->gen_lock);
pci_set_drvdata(pdev, si);
si->pdev = pdev;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 8839cfb49bcf..d1e9d9130057 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -309,6 +309,13 @@ struct enetc_si {
struct net_device *ndev; /* back ref. */
+ /* General-purpose lock serializing updates that must not race,
+ * e.g. read-modify-write of shared hardware registers and of
+ * selected priv->flags bits between the phylink link callbacks
+ * and the ring (re)configuration path.
+ */
+ spinlock_t gen_lock;
+
union {
struct enetc_cbdr cbd_ring; /* Only ENETC 1.0 */
struct ntmp_user ntmp_user; /* ENETC 4.1 and later */
@@ -417,6 +424,7 @@ enum enetc_active_offloads {
enum enetc_flags_bit {
ENETC_TX_ONESTEP_TSTAMP_IN_PROGRESS = 0,
ENETC_TX_DOWN,
+ ENETC_RXBDR_CM,
};
/* interrupt coalescing modes */
@@ -505,6 +513,7 @@ int enetc_get_driver_data(struct enetc_si *si);
void enetc_add_mac_addr_ht_filter(struct enetc_mac_filter *filter,
const unsigned char *addr);
void enetc_reset_mac_addr_filter(struct enetc_mac_filter *filter);
+void enetc_set_congestion_mode(struct enetc_ndev_priv *priv, bool enable);
int enetc_open(struct net_device *ndev);
int enetc_close(struct net_device *ndev);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index fcfbabb29d22..9bb1004548ab 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -718,22 +718,14 @@ static void enetc4_set_rx_pause(struct enetc_pf *pf, bool rx_pause)
enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
}
-static void enetc4_set_tx_pause(struct enetc_pf *pf, int num_rxbdr, bool tx_pause)
+static void enetc4_set_tx_pause(struct enetc_pf *pf, bool tx_pause)
{
+ struct enetc_ndev_priv *priv = netdev_priv(pf->si->ndev);
u32 pause_off_thresh = 0, pause_on_thresh = 0;
u32 init_quanta = 0, refresh_quanta = 0;
struct enetc_hw *hw = &pf->si->hw;
- u32 rbmr, old_rbmr;
- int i;
- for (i = 0; i < num_rxbdr; i++) {
- old_rbmr = enetc_rxbdr_rd(hw, i, ENETC_RBMR);
- rbmr = u32_replace_bits(old_rbmr, tx_pause ? 1 : 0, ENETC_RBMR_CM);
- if (rbmr == old_rbmr)
- continue;
-
- enetc_rxbdr_wr(hw, i, ENETC_RBMR, rbmr);
- }
+ enetc_set_congestion_mode(priv, tx_pause);
if (tx_pause) {
/* When the port first enters congestion, send a PAUSE request
@@ -898,7 +890,7 @@ static void enetc4_pl_mac_link_up(struct phylink_config *config,
tx_pause = false;
}
- enetc4_set_tx_pause(pf, priv->num_rx_rings, tx_pause);
+ enetc4_set_tx_pause(pf, tx_pause);
enetc4_set_rx_pause(pf, rx_pause);
enetc4_mac_tx_enable(pf);
enetc4_mac_rx_enable(pf);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index a509929f89f2..55c07c528f22 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -556,8 +556,7 @@ static void enetc_pl_mac_link_up(struct phylink_config *config,
struct enetc_hw *hw = &pf->si->hw;
struct enetc_si *si = pf->si;
struct enetc_ndev_priv *priv;
- u32 rbmr, cmd_cfg;
- int idx;
+ u32 cmd_cfg;
priv = netdev_priv(pf->si->ndev);
@@ -569,16 +568,7 @@ static void enetc_pl_mac_link_up(struct phylink_config *config,
enetc_force_rgmii_mac(si, speed, duplex);
/* Flow control */
- for (idx = 0; idx < priv->num_rx_rings; idx++) {
- rbmr = enetc_rxbdr_rd(hw, idx, ENETC_RBMR);
-
- if (tx_pause)
- rbmr |= ENETC_RBMR_CM;
- else
- rbmr &= ~ENETC_RBMR_CM;
-
- enetc_rxbdr_wr(hw, idx, ENETC_RBMR, rbmr);
- }
+ enetc_set_congestion_mode(priv, tx_pause);
if (tx_pause) {
/* When the port first enters congestion, send a PAUSE request