aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/mellanox/mlx4
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx4')
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cq.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_clock.c35
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c28
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c36
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_port.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h11
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h5
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/port.c170
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c59
14 files changed, 272 insertions, 108 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
index 6b8635378f1f..fa6d2354a0e9 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
@@ -81,8 +81,9 @@ void mlx4_cq_tasklet_cb(unsigned long data)
static void mlx4_add_cq_to_tasklet(struct mlx4_cq *cq)
{
- unsigned long flags;
struct mlx4_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv;
+ unsigned long flags;
+ bool kick;
spin_lock_irqsave(&tasklet_ctx->lock, flags);
/* When migrating CQs between EQs will be implemented, please note
@@ -92,7 +93,10 @@ static void mlx4_add_cq_to_tasklet(struct mlx4_cq *cq)
*/
if (list_empty_careful(&cq->tasklet_ctx.list)) {
atomic_inc(&cq->refcount);
+ kick = list_empty(&tasklet_ctx->list);
list_add_tail(&cq->tasklet_ctx.list, &tasklet_ctx->list);
+ if (kick)
+ tasklet_schedule(&tasklet_ctx->task);
}
spin_unlock_irqrestore(&tasklet_ctx->lock, flags);
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
index 504461a464c5..e7b81a305469 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
@@ -62,12 +62,13 @@ void mlx4_en_fill_hwtstamps(struct mlx4_en_dev *mdev,
struct skb_shared_hwtstamps *hwts,
u64 timestamp)
{
- unsigned long flags;
+ unsigned int seq;
u64 nsec;
- read_lock_irqsave(&mdev->clock_lock, flags);
- nsec = timecounter_cyc2time(&mdev->clock, timestamp);
- read_unlock_irqrestore(&mdev->clock_lock, flags);
+ do {
+ seq = read_seqbegin(&mdev->clock_lock);
+ nsec = timecounter_cyc2time(&mdev->clock, timestamp);
+ } while (read_seqretry(&mdev->clock_lock, seq));
memset(hwts, 0, sizeof(struct skb_shared_hwtstamps));
hwts->hwtstamp = ns_to_ktime(nsec);
@@ -95,9 +96,9 @@ void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev)
unsigned long flags;
if (timeout) {
- write_lock_irqsave(&mdev->clock_lock, flags);
+ write_seqlock_irqsave(&mdev->clock_lock, flags);
timecounter_read(&mdev->clock);
- write_unlock_irqrestore(&mdev->clock_lock, flags);
+ write_sequnlock_irqrestore(&mdev->clock_lock, flags);
mdev->last_overflow_check = jiffies;
}
}
@@ -128,10 +129,10 @@ static int mlx4_en_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
adj *= delta;
diff = div_u64(adj, 1000000000ULL);
- write_lock_irqsave(&mdev->clock_lock, flags);
+ write_seqlock_irqsave(&mdev->clock_lock, flags);
timecounter_read(&mdev->clock);
mdev->cycles.mult = neg_adj ? mult - diff : mult + diff;
- write_unlock_irqrestore(&mdev->clock_lock, flags);
+ write_sequnlock_irqrestore(&mdev->clock_lock, flags);
return 0;
}
@@ -149,9 +150,9 @@ static int mlx4_en_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
ptp_clock_info);
unsigned long flags;
- write_lock_irqsave(&mdev->clock_lock, flags);
+ write_seqlock_irqsave(&mdev->clock_lock, flags);
timecounter_adjtime(&mdev->clock, delta);
- write_unlock_irqrestore(&mdev->clock_lock, flags);
+ write_sequnlock_irqrestore(&mdev->clock_lock, flags);
return 0;
}
@@ -172,9 +173,9 @@ static int mlx4_en_phc_gettime(struct ptp_clock_info *ptp,
unsigned long flags;
u64 ns;
- write_lock_irqsave(&mdev->clock_lock, flags);
+ write_seqlock_irqsave(&mdev->clock_lock, flags);
ns = timecounter_read(&mdev->clock);
- write_unlock_irqrestore(&mdev->clock_lock, flags);
+ write_sequnlock_irqrestore(&mdev->clock_lock, flags);
*ts = ns_to_timespec64(ns);
@@ -198,9 +199,9 @@ static int mlx4_en_phc_settime(struct ptp_clock_info *ptp,
unsigned long flags;
/* reset the timecounter */
- write_lock_irqsave(&mdev->clock_lock, flags);
+ write_seqlock_irqsave(&mdev->clock_lock, flags);
timecounter_init(&mdev->clock, &mdev->cycles, ns);
- write_unlock_irqrestore(&mdev->clock_lock, flags);
+ write_sequnlock_irqrestore(&mdev->clock_lock, flags);
return 0;
}
@@ -266,7 +267,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
if (mdev->ptp_clock)
return;
- rwlock_init(&mdev->clock_lock);
+ seqlock_init(&mdev->clock_lock);
memset(&mdev->cycles, 0, sizeof(mdev->cycles));
mdev->cycles.read = mlx4_en_read_clock;
@@ -276,10 +277,10 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift);
mdev->nominal_c_mult = mdev->cycles.mult;
- write_lock_irqsave(&mdev->clock_lock, flags);
+ write_seqlock_irqsave(&mdev->clock_lock, flags);
timecounter_init(&mdev->clock, &mdev->cycles,
ktime_to_ns(ktime_get_real()));
- write_unlock_irqrestore(&mdev->clock_lock, flags);
+ write_sequnlock_irqrestore(&mdev->clock_lock, flags);
/* Calculate period in seconds to call the overflow watchdog - to make
* sure counter is checked at least once every wrap around.
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 9aa422691954..c4d714fcc7da 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -902,6 +902,7 @@ mlx4_en_set_link_ksettings(struct net_device *dev,
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_ptys_reg ptys_reg;
__be32 proto_admin;
+ u8 cur_autoneg;
int ret;
u32 ptys_adv = ethtool2ptys_link_modes(
@@ -931,10 +932,21 @@ mlx4_en_set_link_ksettings(struct net_device *dev,
return 0;
}
- proto_admin = link_ksettings->base.autoneg == AUTONEG_ENABLE ?
- cpu_to_be32(ptys_adv) :
- speed_set_ptys_admin(priv, speed,
- ptys_reg.eth_proto_cap);
+ cur_autoneg = ptys_reg.flags & MLX4_PTYS_AN_DISABLE_ADMIN ?
+ AUTONEG_DISABLE : AUTONEG_ENABLE;
+
+ if (link_ksettings->base.autoneg == AUTONEG_DISABLE) {
+ proto_admin = speed_set_ptys_admin(priv, speed,
+ ptys_reg.eth_proto_cap);
+ if ((be32_to_cpu(proto_admin) &
+ (MLX4_PROT_MASK(MLX4_1000BASE_CX_SGMII) |
+ MLX4_PROT_MASK(MLX4_1000BASE_KX))) &&
+ (ptys_reg.flags & MLX4_PTYS_AN_DISABLE_CAP))
+ ptys_reg.flags |= MLX4_PTYS_AN_DISABLE_ADMIN;
+ } else {
+ proto_admin = cpu_to_be32(ptys_adv);
+ ptys_reg.flags &= ~MLX4_PTYS_AN_DISABLE_ADMIN;
+ }
proto_admin &= ptys_reg.eth_proto_cap;
if (!proto_admin) {
@@ -942,7 +954,9 @@ mlx4_en_set_link_ksettings(struct net_device *dev,
return -EINVAL; /* nothing to change due to bad input */
}
- if (proto_admin == ptys_reg.eth_proto_admin)
+ if ((proto_admin == ptys_reg.eth_proto_admin) &&
+ ((ptys_reg.flags & MLX4_PTYS_AN_DISABLE_CAP) &&
+ (link_ksettings->base.autoneg == cur_autoneg)))
return 0; /* Nothing to change */
en_dbg(DRV, priv, "mlx4_ACCESS_PTYS_REG SET: ptys_reg.eth_proto_admin = 0x%x\n",
@@ -1788,7 +1802,7 @@ static int mlx4_en_set_channels(struct net_device *dev,
netif_set_real_num_tx_queues(dev, priv->tx_ring_num[TX]);
netif_set_real_num_rx_queues(dev, priv->rx_ring_num);
- if (dev->num_tc)
+ if (netdev_get_num_tc(dev))
mlx4_en_setup_tc(dev, MLX4_EN_NUM_UP);
en_warn(priv, "Using %d TX rings\n", priv->tx_ring_num[TX]);
@@ -1980,7 +1994,7 @@ static int mlx4_en_get_module_info(struct net_device *dev,
modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
break;
default:
- return -ENOSYS;
+ return -EINVAL;
}
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 3b4961a8e8e4..afe4444e5434 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1321,7 +1321,7 @@ static void mlx4_en_tx_timeout(struct net_device *dev)
}
-static struct rtnl_link_stats64 *
+static void
mlx4_en_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
@@ -1330,8 +1330,6 @@ mlx4_en_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
mlx4_en_fold_software_stats(dev);
netdev_stats_to_stats64(stats, &dev->stats);
spin_unlock_bh(&priv->stats_lock);
-
- return stats;
}
static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
@@ -1384,6 +1382,7 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
{
unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies);
+ u32 pkt_rate_high, pkt_rate_low;
struct mlx4_en_cq *cq;
unsigned long packets;
unsigned long rate;
@@ -1397,37 +1396,40 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
if (!priv->adaptive_rx_coal || period < priv->sample_interval * HZ)
return;
+ pkt_rate_low = READ_ONCE(priv->pkt_rate_low);
+ pkt_rate_high = READ_ONCE(priv->pkt_rate_high);
+
for (ring = 0; ring < priv->rx_ring_num; ring++) {
rx_packets = READ_ONCE(priv->rx_ring[ring]->packets);
rx_bytes = READ_ONCE(priv->rx_ring[ring]->bytes);
- rx_pkt_diff = ((unsigned long) (rx_packets -
- priv->last_moder_packets[ring]));
+ rx_pkt_diff = rx_packets - priv->last_moder_packets[ring];
packets = rx_pkt_diff;
rate = packets * HZ / period;
- avg_pkt_size = packets ? ((unsigned long) (rx_bytes -
- priv->last_moder_bytes[ring])) / packets : 0;
+ avg_pkt_size = packets ? (rx_bytes -
+ priv->last_moder_bytes[ring]) / packets : 0;
/* Apply auto-moderation only when packet rate
* exceeds a rate that it matters */
if (rate > (MLX4_EN_RX_RATE_THRESH / priv->rx_ring_num) &&
avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) {
- if (rate < priv->pkt_rate_low)
+ if (rate <= pkt_rate_low)
moder_time = priv->rx_usecs_low;
- else if (rate > priv->pkt_rate_high)
+ else if (rate >= pkt_rate_high)
moder_time = priv->rx_usecs_high;
else
- moder_time = (rate - priv->pkt_rate_low) *
+ moder_time = (rate - pkt_rate_low) *
(priv->rx_usecs_high - priv->rx_usecs_low) /
- (priv->pkt_rate_high - priv->pkt_rate_low) +
+ (pkt_rate_high - pkt_rate_low) +
priv->rx_usecs_low;
} else {
moder_time = priv->rx_usecs_low;
}
- if (moder_time != priv->last_moder_time[ring]) {
+ cq = priv->rx_cq[ring];
+ if (moder_time != priv->last_moder_time[ring] ||
+ cq->moder_cnt != priv->rx_frames) {
priv->last_moder_time[ring] = moder_time;
- cq = priv->rx_cq[ring];
cq->moder_time = moder_time;
cq->moder_cnt = priv->rx_frames;
err = mlx4_en_set_cq_moder(priv, cq);
@@ -1697,6 +1699,14 @@ int mlx4_en_start_port(struct net_device *dev)
priv->port, err);
goto tx_err;
}
+
+ err = mlx4_SET_PORT_user_mtu(mdev->dev, priv->port, dev->mtu);
+ if (err) {
+ en_err(priv, "Failed to pass user MTU(%d) to Firmware for port %d, with error %d\n",
+ dev->mtu, priv->port, err);
+ goto tx_err;
+ }
+
/* Set default qp number */
err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0);
if (err) {
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.h b/drivers/net/ethernet/mellanox/mlx4/en_port.h
index 040da4b16b1c..930f961fee42 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_port.h
+++ b/drivers/net/ethernet/mellanox/mlx4/en_port.h
@@ -35,7 +35,6 @@
#define _MLX4_EN_PORT_H_
-#define SET_PORT_GEN_ALL_VALID 0x7
#define SET_PORT_PROMISC_SHIFT 31
#define SET_PORT_MC_PROMISC_SHIFT 30
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index cc003fdf0ed9..d85e6446f9d9 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -33,6 +33,7 @@
#include <net/busy_poll.h>
#include <linux/bpf.h>
+#include <linux/bpf_trace.h>
#include <linux/mlx4/cq.h>
#include <linux/slab.h>
#include <linux/mlx4/qp.h>
@@ -709,7 +710,8 @@ static bool mlx4_en_refill_rx_buffers(struct mlx4_en_priv *priv,
do {
if (mlx4_en_prepare_rx_desc(priv, ring,
ring->prod & ring->size_mask,
- GFP_ATOMIC | __GFP_COLD))
+ GFP_ATOMIC | __GFP_COLD |
+ __GFP_MEMALLOC))
break;
ring->prod++;
} while (--missing);
@@ -928,10 +930,12 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
length, cq->ring,
&doorbell_pending)))
goto consumed;
+ trace_xdp_exception(dev, xdp_prog, act);
goto xdp_drop_no_cnt; /* Drop on xmit failure */
default:
bpf_warn_invalid_xdp_action(act);
case XDP_ABORTED:
+ trace_xdp_exception(dev, xdp_prog, act);
case XDP_DROP:
ring->xdp_drop++;
xdp_drop_no_cnt:
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 5886ad78058f..3ed42199d3f1 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -710,7 +710,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
u16 rings_p_up = priv->num_tx_rings_p_up;
u8 up = 0;
- if (dev->num_tc)
+ if (netdev_get_num_tc(dev))
return skb_tx_hash(dev, skb);
if (skb_vlan_tag_present(skb))
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
index 0509996957d9..39232b6a974f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
@@ -494,7 +494,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_eqe *eqe;
- int cqn = -1;
+ int cqn;
int eqes_found = 0;
int set_ci = 0;
int port;
@@ -840,13 +840,6 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
eq_set_ci(eq, 1);
- /* cqn is 24bit wide but is initialized such that its higher bits
- * are ones too. Thus, if we got any event, cqn's high bits should be off
- * and we need to schedule the tasklet.
- */
- if (!(cqn & ~0xffffff))
- tasklet_schedule(&eq->tasklet_ctx.task);
-
return eqes_found;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index 84bab9f0732e..3fe885ce1902 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -672,7 +672,7 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port,
MLX4_GET(field, outbox, QUERY_FUNC_CAP_PHYS_PORT_OFFSET);
func_cap->physical_port = field;
if (func_cap->physical_port != gen_or_port) {
- err = -ENOSYS;
+ err = -EINVAL;
goto out;
}
@@ -1875,7 +1875,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
*((u8 *) mailbox->buf + INIT_HCA_VERSION_OFFSET) = INIT_HCA_VERSION;
*((u8 *) mailbox->buf + INIT_HCA_CACHELINE_SZ_OFFSET) =
- (ilog2(cache_line_size()) - 4) << 5;
+ ((ilog2(cache_line_size()) - 4) << 5) | (1 << 4);
#if defined(__LITTLE_ENDIAN)
*(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
@@ -2983,7 +2983,7 @@ static int mlx4_SET_PORT_phv_bit(struct mlx4_dev *dev, u8 port, u8 phv_bit)
return PTR_ERR(mailbox);
context = mailbox->buf;
- context->v_ignore_fcs |= SET_PORT_GEN_PHV_VALID;
+ context->flags2 |= SET_PORT_GEN_PHV_VALID;
if (phv_bit)
context->phv_en |= SET_PORT_GEN_PHV_EN;
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index bffa6f345f2f..15ef787e71ba 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -838,7 +838,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
*/
if (hca_param.global_caps) {
mlx4_err(dev, "Unknown hca global capabilities\n");
- return -ENOSYS;
+ return -EINVAL;
}
mlx4_log_num_mgm_entry_size = hca_param.log_mc_entry_sz;
@@ -896,7 +896,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
PF_CONTEXT_BEHAVIOUR_MASK) {
mlx4_err(dev, "Unknown pf context behaviour %x known flags %x\n",
func_cap.pf_context_behaviour, PF_CONTEXT_BEHAVIOUR_MASK);
- return -ENOSYS;
+ return -EINVAL;
}
dev->caps.num_ports = func_cap.num_ports;
@@ -3492,7 +3492,7 @@ slave_start:
mlx4_enable_msi_x(dev);
if ((mlx4_is_mfunc(dev)) &&
!(dev->flags & MLX4_FLAG_MSI_X)) {
- err = -ENOSYS;
+ err = -EOPNOTSUPP;
mlx4_err(dev, "INTx is not supported in multi-function mode, aborting\n");
goto err_free_eq;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 086920b615af..b4f1bc56cc68 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -487,6 +487,7 @@ struct mlx4_slave_state {
bool vst_qinq_supported;
u8 function;
dma_addr_t vhcr_dma;
+ u16 user_mtu[MLX4_MAX_PORTS + 1];
u16 mtu[MLX4_MAX_PORTS + 1];
__be32 ib_cap_mask[MLX4_MAX_PORTS + 1];
struct mlx4_slave_eqe eq[MLX4_MFUNC_MAX_EQES];
@@ -590,6 +591,7 @@ struct mlx4_mfunc_master_ctx {
struct mlx4_master_qp0_state qp0_state[MLX4_MAX_PORTS + 1];
int init_port_ref[MLX4_MAX_PORTS + 1];
u16 max_mtu[MLX4_MAX_PORTS + 1];
+ u16 max_user_mtu[MLX4_MAX_PORTS + 1];
u8 pptx;
u8 pprx;
int disable_mcast_ref[MLX4_MAX_PORTS + 1];
@@ -774,7 +776,9 @@ struct mlx4_vlan_table {
int max;
};
-#define SET_PORT_GEN_ALL_VALID 0x7
+#define SET_PORT_GEN_ALL_VALID (MLX4_FLAG_V_MTU_MASK | \
+ MLX4_FLAG_V_PPRX_MASK | \
+ MLX4_FLAG_V_PPTX_MASK)
#define SET_PORT_PROMISC_SHIFT 31
#define SET_PORT_MC_PROMISC_SHIFT 30
@@ -787,7 +791,7 @@ enum {
struct mlx4_set_port_general_context {
u16 reserved1;
- u8 v_ignore_fcs;
+ u8 flags2;
u8 flags;
union {
u8 ignore_fcs;
@@ -803,7 +807,8 @@ struct mlx4_set_port_general_context {
u16 reserved4;
u32 reserved5;
u8 phv_en;
- u8 reserved6[3];
+ u8 reserved6[5];
+ __be16 user_mtu;
};
struct mlx4_set_port_rqp_calc_context {
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index cec59bc264c9..4941b692e947 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -102,7 +102,8 @@
/* Use the maximum between 16384 and a single page */
#define MLX4_EN_ALLOC_SIZE PAGE_ALIGN(16384)
-#define MLX4_EN_ALLOC_PREFER_ORDER PAGE_ALLOC_COSTLY_ORDER
+#define MLX4_EN_ALLOC_PREFER_ORDER min_t(int, get_order(32768), \
+ PAGE_ALLOC_COSTLY_ORDER)
/* Receive fragment sizes; we use at most 3 fragments (for 9600 byte MTU
* and 4K allocations) */
@@ -424,9 +425,9 @@ struct mlx4_en_dev {
u32 priv_pdn;
spinlock_t uar_lock;
u8 mac_removed[MLX4_MAX_PORTS + 1];
- rwlock_t clock_lock;
u32 nominal_c_mult;
struct cyclecounter cycles;
+ seqlock_t clock_lock;
struct timecounter clock;
unsigned long last_overflow_check;
unsigned long overflow_period;
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index b656dd5772e5..4e36e287d605 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -50,7 +50,11 @@
#define MLX4_STATS_ERROR_COUNTERS_MASK 0x1ffc30ULL
#define MLX4_STATS_PORT_COUNTERS_MASK 0x1fe00000ULL
-#define MLX4_FLAG_V_IGNORE_FCS_MASK 0x2
+#define MLX4_FLAG2_V_IGNORE_FCS_MASK BIT(1)
+#define MLX4_FLAG2_V_USER_MTU_MASK BIT(5)
+#define MLX4_FLAG_V_MTU_MASK BIT(0)
+#define MLX4_FLAG_V_PPRX_MASK BIT(1)
+#define MLX4_FLAG_V_PPTX_MASK BIT(2)
#define MLX4_IGNORE_FCS_MASK 0x1
#define MLX4_TC_MAX_NUMBER 8
@@ -1239,13 +1243,96 @@ void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave)
return;
}
+static void
+mlx4_en_set_port_mtu(struct mlx4_dev *dev, int slave, int port,
+ struct mlx4_set_port_general_context *gen_context)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
+ struct mlx4_slave_state *slave_st = &master->slave_state[slave];
+ u16 mtu, prev_mtu;
+
+ /* Mtu is configured as the max USER_MTU among all
+ * the functions on the port.
+ */
+ mtu = be16_to_cpu(gen_context->mtu);
+ mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] +
+ ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
+ prev_mtu = slave_st->mtu[port];
+ slave_st->mtu[port] = mtu;
+ if (mtu > master->max_mtu[port])
+ master->max_mtu[port] = mtu;
+ if (mtu < prev_mtu && prev_mtu == master->max_mtu[port]) {
+ int i;
+
+ slave_st->mtu[port] = mtu;
+ master->max_mtu[port] = mtu;
+ for (i = 0; i < dev->num_slaves; i++)
+ master->max_mtu[port] =
+ max_t(u16, master->max_mtu[port],
+ master->slave_state[i].mtu[port]);
+ }
+ gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
+}
+
+static void
+mlx4_en_set_port_user_mtu(struct mlx4_dev *dev, int slave, int port,
+ struct mlx4_set_port_general_context *gen_context)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
+ struct mlx4_slave_state *slave_st = &master->slave_state[slave];
+ u16 user_mtu, prev_user_mtu;
+
+ /* User Mtu is configured as the max USER_MTU among all
+ * the functions on the port.
+ */
+ user_mtu = be16_to_cpu(gen_context->user_mtu);
+ user_mtu = min_t(int, user_mtu, dev->caps.eth_mtu_cap[port]);
+ prev_user_mtu = slave_st->user_mtu[port];
+ slave_st->user_mtu[port] = user_mtu;
+ if (user_mtu > master->max_user_mtu[port])
+ master->max_user_mtu[port] = user_mtu;
+ if (user_mtu < prev_user_mtu &&
+ prev_user_mtu == master->max_user_mtu[port]) {
+ int i;
+
+ slave_st->user_mtu[port] = user_mtu;
+ master->max_user_mtu[port] = user_mtu;
+ for (i = 0; i < dev->num_slaves; i++)
+ master->max_user_mtu[port] =
+ max_t(u16, master->max_user_mtu[port],
+ master->slave_state[i].user_mtu[port]);
+ }
+ gen_context->user_mtu = cpu_to_be16(master->max_user_mtu[port]);
+}
+
+static void
+mlx4_en_set_port_global_pause(struct mlx4_dev *dev, int slave,
+ struct mlx4_set_port_general_context *gen_context)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
+
+ /* Slave cannot change Global Pause configuration */
+ if (slave != mlx4_master_func_num(dev) &&
+ (gen_context->pptx != master->pptx ||
+ gen_context->pprx != master->pprx)) {
+ gen_context->pptx = master->pptx;
+ gen_context->pprx = master->pprx;
+ mlx4_warn(dev, "denying Global Pause change for slave:%d\n",
+ slave);
+ } else {
+ master->pptx = gen_context->pptx;
+ master->pprx = gen_context->pprx;
+ }
+}
+
static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
u8 op_mod, struct mlx4_cmd_mailbox *inbox)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_port_info *port_info;
- struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
- struct mlx4_slave_state *slave_st = &master->slave_state[slave];
struct mlx4_set_port_rqp_calc_context *qpn_context;
struct mlx4_set_port_general_context *gen_context;
struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1;
@@ -1256,7 +1343,6 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
int base;
u32 in_modifier;
u32 promisc;
- u16 mtu, prev_mtu;
int err;
int i, j;
int offset;
@@ -1269,7 +1355,9 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
is_eth = op_mod;
port_info = &priv->port[port];
- /* Slaves cannot perform SET_PORT operations except changing MTU */
+ /* Slaves cannot perform SET_PORT operations,
+ * except for changing MTU and USER_MTU.
+ */
if (is_eth) {
if (slave != dev->caps.function &&
in_modifier != MLX4_SET_PORT_GENERAL &&
@@ -1297,40 +1385,20 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
break;
case MLX4_SET_PORT_GENERAL:
gen_context = inbox->buf;
- /* Mtu is configured as the max MTU among all the
- * the functions on the port. */
- mtu = be16_to_cpu(gen_context->mtu);
- mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] +
- ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
- prev_mtu = slave_st->mtu[port];
- slave_st->mtu[port] = mtu;
- if (mtu > master->max_mtu[port])
- master->max_mtu[port] = mtu;
- if (mtu < prev_mtu && prev_mtu ==
- master->max_mtu[port]) {
- slave_st->mtu[port] = mtu;
- master->max_mtu[port] = mtu;
- for (i = 0; i < dev->num_slaves; i++) {
- master->max_mtu[port] =
- max(master->max_mtu[port],
- master->slave_state[i].mtu[port]);
- }
- }
- gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
- /* Slave cannot change Global Pause configuration */
- if (slave != mlx4_master_func_num(dev) &&
- ((gen_context->pptx != master->pptx) ||
- (gen_context->pprx != master->pprx))) {
- gen_context->pptx = master->pptx;
- gen_context->pprx = master->pprx;
- mlx4_warn(dev,
- "denying Global Pause change for slave:%d\n",
- slave);
- } else {
- master->pptx = gen_context->pptx;
- master->pprx = gen_context->pprx;
- }
+ if (gen_context->flags & MLX4_FLAG_V_MTU_MASK)
+ mlx4_en_set_port_mtu(dev, slave, port,
+ gen_context);
+
+ if (gen_context->flags2 & MLX4_FLAG2_V_USER_MTU_MASK)
+ mlx4_en_set_port_user_mtu(dev, slave, port,
+ gen_context);
+
+ if (gen_context->flags &
+ (MLX4_FLAG_V_PPRX_MASK | MLX4_FLAG_V_PPTX_MASK))
+ mlx4_en_set_port_global_pause(dev, slave,
+ gen_context);
+
break;
case MLX4_SET_PORT_GID_TABLE:
/* change to MULTIPLE entries: number of guest's gids
@@ -1608,6 +1676,30 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
}
EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc);
+int mlx4_SET_PORT_user_mtu(struct mlx4_dev *dev, u8 port, u16 user_mtu)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_set_port_general_context *context;
+ u32 in_mod;
+ int err;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ context = mailbox->buf;
+ context->flags2 |= MLX4_FLAG2_V_USER_MTU_MASK;
+ context->user_mtu = cpu_to_be16(user_mtu);
+
+ in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
+ err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
+ MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
+ MLX4_CMD_WRAPPED);
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+EXPORT_SYMBOL(mlx4_SET_PORT_user_mtu);
+
int mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value)
{
struct mlx4_cmd_mailbox *mailbox;
@@ -1619,7 +1711,7 @@ int mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value)
if (IS_ERR(mailbox))
return PTR_ERR(mailbox);
context = mailbox->buf;
- context->v_ignore_fcs |= MLX4_FLAG_V_IGNORE_FCS_MASK;
+ context->flags2 |= MLX4_FLAG2_V_IGNORE_FCS_MASK;
if (ignore_fcs_value)
context->ignore_fcs |= MLX4_IGNORE_FCS_MASK;
else
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 1822382212ee..6fe9f76ae656 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -77,6 +77,7 @@ struct res_common {
int from_state;
int to_state;
int removing;
+ const char *func_name;
};
enum {
@@ -236,8 +237,8 @@ static void *res_tracker_lookup(struct rb_root *root, u64 res_id)
struct rb_node *node = root->rb_node;
while (node) {
- struct res_common *res = container_of(node, struct res_common,
- node);
+ struct res_common *res = rb_entry(node, struct res_common,
+ node);
if (res_id < res->res_id)
node = node->rb_left;
@@ -255,8 +256,8 @@ static int res_tracker_insert(struct rb_root *root, struct res_common *res)
/* Figure out where to put new node */
while (*new) {
- struct res_common *this = container_of(*new, struct res_common,
- node);
+ struct res_common *this = rb_entry(*new, struct res_common,
+ node);
parent = *new;
if (res->res_id < this->res_id)
@@ -837,6 +838,36 @@ static int mpt_mask(struct mlx4_dev *dev)
return dev->caps.num_mpts - 1;
}
+static const char *mlx4_resource_type_to_str(enum mlx4_resource t)
+{
+ switch (t) {
+ case RES_QP:
+ return "QP";
+ case RES_CQ:
+ return "CQ";
+ case RES_SRQ:
+ return "SRQ";
+ case RES_XRCD:
+ return "XRCD";
+ case RES_MPT:
+ return "MPT";
+ case RES_MTT:
+ return "MTT";
+ case RES_MAC:
+ return "MAC";
+ case RES_VLAN:
+ return "VLAN";
+ case RES_COUNTER:
+ return "COUNTER";
+ case RES_FS_RULE:
+ return "FS_RULE";
+ case RES_EQ:
+ return "EQ";
+ default:
+ return "INVALID RESOURCE";
+ }
+}
+
static void *find_res(struct mlx4_dev *dev, u64 res_id,
enum mlx4_resource type)
{
@@ -846,9 +877,9 @@ static void *find_res(struct mlx4_dev *dev, u64 res_id,
res_id);
}
-static int get_res(struct mlx4_dev *dev, int slave, u64 res_id,
- enum mlx4_resource type,
- void *res)
+static int _get_res(struct mlx4_dev *dev, int slave, u64 res_id,
+ enum mlx4_resource type,
+ void *res, const char *func_name)
{
struct res_common *r;
int err = 0;
@@ -861,6 +892,10 @@ static int get_res(struct mlx4_dev *dev, int slave, u64 res_id,
}
if (r->state == RES_ANY_BUSY) {
+ mlx4_warn(dev,
+ "%s(%d) trying to get resource %llx of type %s, but it's already taken by %s\n",
+ func_name, slave, res_id, mlx4_resource_type_to_str(type),
+ r->func_name);
err = -EBUSY;
goto exit;
}
@@ -872,6 +907,7 @@ static int get_res(struct mlx4_dev *dev, int slave, u64 res_id,
r->from_state = r->state;
r->state = RES_ANY_BUSY;
+ r->func_name = func_name;
if (res)
*((struct res_common **)res) = r;
@@ -881,6 +917,9 @@ exit:
return err;
}
+#define get_res(dev, slave, res_id, type, res) \
+ _get_res((dev), (slave), (res_id), (type), (res), __func__)
+
int mlx4_get_slave_from_resource_id(struct mlx4_dev *dev,
enum mlx4_resource type,
u64 res_id, int *slave)
@@ -911,8 +950,10 @@ static void put_res(struct mlx4_dev *dev, int slave, u64 res_id,
spin_lock_irq(mlx4_tlock(dev));
r = find_res(dev, res_id, type);
- if (r)
+ if (r) {
r->state = r->from_state;
+ r->func_name = "";
+ }
spin_unlock_irq(mlx4_tlock(dev));
}
@@ -1396,7 +1437,7 @@ static int remove_ok(struct res_common *res, enum mlx4_resource type, int extra)
case RES_MTT:
return remove_mtt_ok((struct res_mtt *)res, extra);
case RES_MAC:
- return -ENOSYS;
+ return -EOPNOTSUPP;
case RES_EQ:
return remove_eq_ok((struct res_eq *)res);
case RES_COUNTER: