Commit d7c52fc8 authored by David S. Miller's avatar David S. Miller

Merge tag 'mlx5e-updates-2018-05-19' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux

Saeed Mahameed says:

====================
mlx5e-updates-2018-05-19

This series contains updates for mlx5e netdevice driver with one subject,
DSCP to priority mapping, in the first patch Huy adds the needed API in
dcbnl, the second patch adds the needed mlx5 core capability bits for the
feature, and all other patches are mlx5e (netdev) only changes to add
support for the feature.

From: Huy Nguyen

Dscp to priority mapping for Ethernet packet:

These patches enable differentiated services code point (dscp) to
priority mapping for Ethernet packet. Once this feature is
enabled, the packet is routed to the corresponding priority based on its
dscp. User can combine this feature with priority flow control (pfc)
feature to have priority flow control based on the dscp.

Firmware interface:
Mellanox firmware provides two control knobs for this feature:
  QPTS register allow changing the trust state between dscp and
  pcp mode. The default is pcp mode. Once in dscp mode, firmware will
  route the packet based on its dscp value if the dscp field exists.

  QPDPM register allow mapping a specific dscp (0 to 63) to a
  specific priority (0 to 7). By default, all the dscps are mapped to
  priority zero.

Software interface:
This feature is controlled via application priority TLV. IEEE
specification P802.1Qcd/D2.1 defines priority selector id 5 for
application priority TLV. This APP TLV selector defines DSCP to priority
map. This APP TLV can be sent by the switch or can be set locally using
software such as lldptool. In mlx5 drivers, we add the support for net
dcb's getapp and setapp call back. Mlx5 driver only handles the selector
id 5 application entry (dscp application priority application entry).
If user sends multiple dscp to priority APP TLV entries on the same
dscp, the last sent one will take effect. All the previous sent will be
deleted.

This attribute combined with pfc attribute allows advanced user to
fine tune the qos setting for specific priority queue. For example,
user can give dedicated buffer for one or more priorities or user
can give large buffer to certain priorities.

The dcb buffer configuration will be controlled by lldptool.
>> lldptool -T -i eth2 -V BUFFER prio 0,2,5,7,1,2,3,6
      maps priorities 0,1,2,3,4,5,6,7 to receive buffer 0,2,5,7,1,2,3,6
>> lldptool -T -i eth2 -V BUFFER size 87296,87296,0,87296,0,0,0,0
      sets receive buffer size for buffer 0,1,2,3,4,5,6,7 respectively

After discussion on mailing list with Jakub, Jiri, Ido and John, we agreed to
choose dcbnl over devlink interface since this feature is intended to set
port attributes which are governed by the netdev instance of that port, where
devlink API is more suitable for global ASIC configurations.

The firmware trust state (in QPTS register) is changed based on the
number of dscp to priority application entries. When the first dscp to
priority application entry is added by the user, the trust state is
changed to dscp. When the last dscp to priority application entry is
deleted by the user, the trust state is changed to pcp.

When the port is in DSCP trust state, the transmit queue is selected
based on the dscp of the skb.

When the port is in DSCP trust state and vport inline mode is not NONE,
firmware requires mlx5 driver to copy the IP header to the
wqe ethernet segment inline header if the skb has it.
This is done by changing the transmit queue sq's min inline mode to L3.
Note that the min inline mode of sqs that belong to other features
such as xdpsq, icosq are not modified.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a4567579 ecdf2dad
...@@ -15,13 +15,13 @@ mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \ ...@@ -15,13 +15,13 @@ mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
en_tx.o en_rx.o en_dim.o en_txrx.o en_stats.o vxlan.o \ en_tx.o en_rx.o en_dim.o en_txrx.o en_stats.o vxlan.o \
en_arfs.o en_fs_ethtool.o en_selftest.o en_arfs.o en_fs_ethtool.o en_selftest.o en/port.o
mlx5_core-$(CONFIG_MLX5_MPFS) += lib/mpfs.o mlx5_core-$(CONFIG_MLX5_MPFS) += lib/mpfs.o
mlx5_core-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o en_rep.o en_tc.o mlx5_core-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o en_rep.o en_tc.o
mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
......
...@@ -65,6 +65,7 @@ struct page_pool; ...@@ -65,6 +65,7 @@ struct page_pool;
#define MLX5E_HW2SW_MTU(params, hwmtu) ((hwmtu) - ((params)->hard_mtu)) #define MLX5E_HW2SW_MTU(params, hwmtu) ((hwmtu) - ((params)->hard_mtu))
#define MLX5E_SW2HW_MTU(params, swmtu) ((swmtu) + ((params)->hard_mtu)) #define MLX5E_SW2HW_MTU(params, swmtu) ((swmtu) + ((params)->hard_mtu))
#define MLX5E_MAX_PRIORITY 8
#define MLX5E_MAX_DSCP 64 #define MLX5E_MAX_DSCP 64
#define MLX5E_MAX_NUM_TC 8 #define MLX5E_MAX_NUM_TC 8
...@@ -275,6 +276,11 @@ struct mlx5e_dcbx { ...@@ -275,6 +276,11 @@ struct mlx5e_dcbx {
/* The only setting that cannot be read from FW */ /* The only setting that cannot be read from FW */
u8 tc_tsa[IEEE_8021QAZ_MAX_TCS]; u8 tc_tsa[IEEE_8021QAZ_MAX_TCS];
u8 cap; u8 cap;
/* Buffer configuration */
bool manual_buffer;
u32 cable_len;
u32 xoff;
}; };
struct mlx5e_dcbx_dp { struct mlx5e_dcbx_dp {
...@@ -932,8 +938,6 @@ void mlx5e_deactivate_priv_channels(struct mlx5e_priv *priv); ...@@ -932,8 +938,6 @@ void mlx5e_deactivate_priv_channels(struct mlx5e_priv *priv);
void mlx5e_build_default_indir_rqt(u32 *indirection_rqt, int len, void mlx5e_build_default_indir_rqt(u32 *indirection_rqt, int len,
int num_channels); int num_channels);
int mlx5e_get_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
void mlx5e_set_tx_cq_mode_params(struct mlx5e_params *params, void mlx5e_set_tx_cq_mode_params(struct mlx5e_params *params,
u8 cq_period_mode); u8 cq_period_mode);
void mlx5e_set_rx_cq_mode_params(struct mlx5e_params *params, void mlx5e_set_rx_cq_mode_params(struct mlx5e_params *params,
......
/*
* Copyright (c) 2018, Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "port.h"
/* speed in units of 1Mb */
static const u32 mlx5e_link_speed[MLX5E_LINK_MODES_NUMBER] = {
[MLX5E_1000BASE_CX_SGMII] = 1000,
[MLX5E_1000BASE_KX] = 1000,
[MLX5E_10GBASE_CX4] = 10000,
[MLX5E_10GBASE_KX4] = 10000,
[MLX5E_10GBASE_KR] = 10000,
[MLX5E_20GBASE_KR2] = 20000,
[MLX5E_40GBASE_CR4] = 40000,
[MLX5E_40GBASE_KR4] = 40000,
[MLX5E_56GBASE_R4] = 56000,
[MLX5E_10GBASE_CR] = 10000,
[MLX5E_10GBASE_SR] = 10000,
[MLX5E_10GBASE_ER] = 10000,
[MLX5E_40GBASE_SR4] = 40000,
[MLX5E_40GBASE_LR4] = 40000,
[MLX5E_50GBASE_SR2] = 50000,
[MLX5E_100GBASE_CR4] = 100000,
[MLX5E_100GBASE_SR4] = 100000,
[MLX5E_100GBASE_KR4] = 100000,
[MLX5E_100GBASE_LR4] = 100000,
[MLX5E_100BASE_TX] = 100,
[MLX5E_1000BASE_T] = 1000,
[MLX5E_10GBASE_T] = 10000,
[MLX5E_25GBASE_CR] = 25000,
[MLX5E_25GBASE_KR] = 25000,
[MLX5E_25GBASE_SR] = 25000,
[MLX5E_50GBASE_CR2] = 50000,
[MLX5E_50GBASE_KR2] = 50000,
};
u32 mlx5e_port_ptys2speed(u32 eth_proto_oper)
{
unsigned long temp = eth_proto_oper;
u32 speed = 0;
int i;
i = find_first_bit(&temp, MLX5E_LINK_MODES_NUMBER);
if (i < MLX5E_LINK_MODES_NUMBER)
speed = mlx5e_link_speed[i];
return speed;
}
int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
{
u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {};
u32 eth_proto_oper;
int err;
err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1);
if (err)
return err;
eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
*speed = mlx5e_port_ptys2speed(eth_proto_oper);
if (!(*speed)) {
mlx5_core_warn(mdev, "cannot get port speed\n");
err = -EINVAL;
}
return err;
}
int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
{
u32 max_speed = 0;
u32 proto_cap;
int err;
int i;
err = mlx5_query_port_proto_cap(mdev, &proto_cap, MLX5_PTYS_EN);
if (err)
return err;
for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i)
if (proto_cap & MLX5E_PROT_MASK(i))
max_speed = max(max_speed, mlx5e_link_speed[i]);
*speed = max_speed;
return 0;
}
u32 mlx5e_port_speed2linkmodes(u32 speed)
{
u32 link_modes = 0;
int i;
for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) {
if (mlx5e_link_speed[i] == speed)
link_modes |= MLX5E_PROT_MASK(i);
}
return link_modes;
}
int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out)
{
int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
void *in;
int err;
in = kzalloc(sz, GFP_KERNEL);
if (!in)
return -ENOMEM;
MLX5_SET(pbmc_reg, in, local_port, 1);
err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0);
kfree(in);
return err;
}
int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in)
{
int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
void *out;
int err;
out = kzalloc(sz, GFP_KERNEL);
if (!out)
return -ENOMEM;
MLX5_SET(pbmc_reg, in, local_port, 1);
err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1);
kfree(out);
return err;
}
/* buffer[i]: buffer that priority i mapped to */
int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
{
int sz = MLX5_ST_SZ_BYTES(pptb_reg);
u32 prio_x_buff;
void *out;
void *in;
int prio;
int err;
in = kzalloc(sz, GFP_KERNEL);
out = kzalloc(sz, GFP_KERNEL);
if (!in || !out) {
err = -ENOMEM;
goto out;
}
MLX5_SET(pptb_reg, in, local_port, 1);
err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
if (err)
goto out;
prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff);
for (prio = 0; prio < 8; prio++) {
buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF;
mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]);
}
out:
kfree(in);
kfree(out);
return err;
}
int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
{
int sz = MLX5_ST_SZ_BYTES(pptb_reg);
u32 prio_x_buff;
void *out;
void *in;
int prio;
int err;
in = kzalloc(sz, GFP_KERNEL);
out = kzalloc(sz, GFP_KERNEL);
if (!in || !out) {
err = -ENOMEM;
goto out;
}
/* First query the pptb register */
MLX5_SET(pptb_reg, in, local_port, 1);
err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
if (err)
goto out;
memcpy(in, out, sz);
MLX5_SET(pptb_reg, in, local_port, 1);
/* Update the pm and prio_x_buff */
MLX5_SET(pptb_reg, in, pm, 0xFF);
prio_x_buff = 0;
for (prio = 0; prio < 8; prio++)
prio_x_buff |= (buffer[prio] << (4 * prio));
MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff);
err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1);
out:
kfree(in);
kfree(out);
return err;
}
/*
* Copyright (c) 2018, Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __MLX5E_EN_PORT_H
#define __MLX5E_EN_PORT_H
#include <linux/mlx5/driver.h>
#include "en.h"
u32 mlx5e_port_ptys2speed(u32 eth_proto_oper);
int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
u32 mlx5e_port_speed2linkmodes(u32 speed);
int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out);
int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in);
int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer);
int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer);
#endif
/*
* Copyright (c) 2018, Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "port_buffer.h"
int mlx5e_port_query_buffer(struct mlx5e_priv *priv,
struct mlx5e_port_buffer *port_buffer)
{
struct mlx5_core_dev *mdev = priv->mdev;
int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
u32 total_used = 0;
void *buffer;
void *out;
int err;
int i;
out = kzalloc(sz, GFP_KERNEL);
if (!out)
return -ENOMEM;
err = mlx5e_port_query_pbmc(mdev, out);
if (err)
goto out;
for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
buffer = MLX5_ADDR_OF(pbmc_reg, out, buffer[i]);
port_buffer->buffer[i].lossy =
MLX5_GET(bufferx_reg, buffer, lossy);
port_buffer->buffer[i].epsb =
MLX5_GET(bufferx_reg, buffer, epsb);
port_buffer->buffer[i].size =
MLX5_GET(bufferx_reg, buffer, size) << MLX5E_BUFFER_CELL_SHIFT;
port_buffer->buffer[i].xon =
MLX5_GET(bufferx_reg, buffer, xon_threshold) << MLX5E_BUFFER_CELL_SHIFT;
port_buffer->buffer[i].xoff =
MLX5_GET(bufferx_reg, buffer, xoff_threshold) << MLX5E_BUFFER_CELL_SHIFT;
total_used += port_buffer->buffer[i].size;
mlx5e_dbg(HW, priv, "buffer %d: size=%d, xon=%d, xoff=%d, epsb=%d, lossy=%d\n", i,
port_buffer->buffer[i].size,
port_buffer->buffer[i].xon,
port_buffer->buffer[i].xoff,
port_buffer->buffer[i].epsb,
port_buffer->buffer[i].lossy);
}
port_buffer->port_buffer_size =
MLX5_GET(pbmc_reg, out, port_buffer_size) << MLX5E_BUFFER_CELL_SHIFT;
port_buffer->spare_buffer_size =
port_buffer->port_buffer_size - total_used;
mlx5e_dbg(HW, priv, "total buffer size=%d, spare buffer size=%d\n",
port_buffer->port_buffer_size,
port_buffer->spare_buffer_size);
out:
kfree(out);
return err;
}
static int port_set_buffer(struct mlx5e_priv *priv,
struct mlx5e_port_buffer *port_buffer)
{
struct mlx5_core_dev *mdev = priv->mdev;
int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
void *buffer;
void *in;
int err;
int i;
in = kzalloc(sz, GFP_KERNEL);
if (!in)
return -ENOMEM;
err = mlx5e_port_query_pbmc(mdev, in);
if (err)
goto out;
for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
buffer = MLX5_ADDR_OF(pbmc_reg, in, buffer[i]);
MLX5_SET(bufferx_reg, buffer, size,
port_buffer->buffer[i].size >> MLX5E_BUFFER_CELL_SHIFT);
MLX5_SET(bufferx_reg, buffer, lossy,
port_buffer->buffer[i].lossy);
MLX5_SET(bufferx_reg, buffer, xoff_threshold,
port_buffer->buffer[i].xoff >> MLX5E_BUFFER_CELL_SHIFT);
MLX5_SET(bufferx_reg, buffer, xon_threshold,
port_buffer->buffer[i].xon >> MLX5E_BUFFER_CELL_SHIFT);
}
err = mlx5e_port_set_pbmc(mdev, in);
out:
kfree(in);
return err;
}
/* xoff = ((301+2.16 * len [m]) * speed [Gbps] + 2.72 MTU [B]) */
static u32 calculate_xoff(struct mlx5e_priv *priv, unsigned int mtu)
{
u32 speed;
u32 xoff;
int err;
err = mlx5e_port_linkspeed(priv->mdev, &speed);
if (err)
return 0;
xoff = (301 + 216 * priv->dcbx.cable_len / 100) * speed / 1000 + 272 * mtu / 100;
mlx5e_dbg(HW, priv, "%s: xoff=%d\n", __func__, xoff);
return xoff;
}
static int update_xoff_threshold(struct mlx5e_port_buffer *port_buffer,
u32 xoff, unsigned int mtu)
{
int i;
for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
if (port_buffer->buffer[i].lossy) {
port_buffer->buffer[i].xoff = 0;
port_buffer->buffer[i].xon = 0;
continue;
}
if (port_buffer->buffer[i].size <
(xoff + mtu + (1 << MLX5E_BUFFER_CELL_SHIFT)))
return -ENOMEM;
port_buffer->buffer[i].xoff = port_buffer->buffer[i].size - xoff;
port_buffer->buffer[i].xon = port_buffer->buffer[i].xoff - mtu;
}
return 0;
}
/**
* update_buffer_lossy()
* mtu: device's MTU
* pfc_en: <input> current pfc configuration
* buffer: <input> current prio to buffer mapping
* xoff: <input> xoff value
* port_buffer: <output> port receive buffer configuration
* change: <output>
*
* Update buffer configuration based on pfc configuraiton and priority
* to buffer mapping.
* Buffer's lossy bit is changed to:
* lossless if there is at least one PFC enabled priority mapped to this buffer
* lossy if all priorities mapped to this buffer are PFC disabled
*
* Return:
* Return 0 if no error.
* Set change to true if buffer configuration is modified.
*/
static int update_buffer_lossy(unsigned int mtu,
u8 pfc_en, u8 *buffer, u32 xoff,
struct mlx5e_port_buffer *port_buffer,
bool *change)
{
bool changed = false;
u8 lossy_count;
u8 prio_count;
u8 lossy;
int prio;
int err;
int i;
for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
prio_count = 0;
lossy_count = 0;
for (prio = 0; prio < MLX5E_MAX_PRIORITY; prio++) {
if (buffer[prio] != i)
continue;
prio_count++;
lossy_count += !(pfc_en & (1 << prio));
}
if (lossy_count == prio_count)
lossy = 1;
else /* lossy_count < prio_count */
lossy = 0;
if (lossy != port_buffer->buffer[i].lossy) {
port_buffer->buffer[i].lossy = lossy;
changed = true;
}
}
if (changed) {
err = update_xoff_threshold(port_buffer, xoff, mtu);
if (err)
return err;
*change = true;
}
return 0;
}
int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
u32 change, unsigned int mtu,
struct ieee_pfc *pfc,
u32 *buffer_size,
u8 *prio2buffer)
{
struct mlx5e_port_buffer port_buffer;
u32 xoff = calculate_xoff(priv, mtu);
bool update_prio2buffer = false;
u8 buffer[MLX5E_MAX_PRIORITY];
bool update_buffer = false;
u32 total_used = 0;
u8 curr_pfc_en;
int err;
int i;
mlx5e_dbg(HW, priv, "%s: change=%x\n", __func__, change);
err = mlx5e_port_query_buffer(priv, &port_buffer);
if (err)
return err;
if (change & MLX5E_PORT_BUFFER_CABLE_LEN) {
update_buffer = true;
err = update_xoff_threshold(&port_buffer, xoff, mtu);
if (err)
return err;
}
if (change & MLX5E_PORT_BUFFER_PFC) {
err = mlx5e_port_query_priority2buffer(priv->mdev, buffer);
if (err)
return err;
err = update_buffer_lossy(mtu, pfc->pfc_en, buffer, xoff,
&port_buffer, &update_buffer);
if (err)
return err;
}
if (change & MLX5E_PORT_BUFFER_PRIO2BUFFER) {
update_prio2buffer = true;
err = mlx5_query_port_pfc(priv->mdev, &curr_pfc_en, NULL);
if (err)
return err;
err = update_buffer_lossy(mtu, curr_pfc_en, prio2buffer, xoff,
&port_buffer, &update_buffer);
if (err)
return err;
}
if (change & MLX5E_PORT_BUFFER_SIZE) {
for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
mlx5e_dbg(HW, priv, "%s: buffer[%d]=%d\n", __func__, i, buffer_size[i]);
if (!port_buffer.buffer[i].lossy && !buffer_size[i]) {
mlx5e_dbg(HW, priv, "%s: lossless buffer[%d] size cannot be zero\n",
__func__, i);
return -EINVAL;
}
port_buffer.buffer[i].size = buffer_size[i];
total_used += buffer_size[i];
}
mlx5e_dbg(HW, priv, "%s: total buffer requested=%d\n", __func__, total_used);
if (total_used > port_buffer.port_buffer_size)
return -EINVAL;
update_buffer = true;
err = update_xoff_threshold(&port_buffer, xoff, mtu);
if (err)
return err;
}
/* Need to update buffer configuration if xoff value is changed */
if (!update_buffer && xoff != priv->dcbx.xoff) {
update_buffer = true;
err = update_xoff_threshold(&port_buffer, xoff, mtu);
if (err)
return err;
}
priv->dcbx.xoff = xoff;
/* Apply the settings */
if (update_buffer) {
err = port_set_buffer(priv, &port_buffer);
if (err)
return err;
}
if (update_prio2buffer)
err = mlx5e_port_set_priority2buffer(priv->mdev, prio2buffer);
return err;
}
/*
* Copyright (c) 2018, Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __MLX5_EN_PORT_BUFFER_H__
#define __MLX5_EN_PORT_BUFFER_H__
#include "en.h"
#include "port.h"
#define MLX5E_MAX_BUFFER 8
#define MLX5E_BUFFER_CELL_SHIFT 7
#define MLX5E_DEFAULT_CABLE_LEN 7 /* 7 meters */
#define MLX5_BUFFER_SUPPORTED(mdev) (MLX5_CAP_GEN(mdev, pcam_reg) && \
MLX5_CAP_PCAM_REG(mdev, pbmc) && \
MLX5_CAP_PCAM_REG(mdev, pptb))
enum {
MLX5E_PORT_BUFFER_CABLE_LEN = BIT(0),
MLX5E_PORT_BUFFER_PFC = BIT(1),
MLX5E_PORT_BUFFER_PRIO2BUFFER = BIT(2),
MLX5E_PORT_BUFFER_SIZE = BIT(3),
};
struct mlx5e_bufferx_reg {
u8 lossy;
u8 epsb;
u32 size;
u32 xoff;
u32 xon;
};
struct mlx5e_port_buffer {
u32 port_buffer_size;
u32 spare_buffer_size;
struct mlx5e_bufferx_reg buffer[MLX5E_MAX_BUFFER];
};
int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
u32 change, unsigned int mtu,
struct ieee_pfc *pfc,
u32 *buffer_size,
u8 *prio2buffer);
int mlx5e_port_query_buffer(struct mlx5e_priv *priv,
struct mlx5e_port_buffer *port_buffer);
#endif
...@@ -32,8 +32,8 @@ ...@@ -32,8 +32,8 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include "en.h" #include "en.h"
#include "en/port.h"
#define MLX5E_MAX_PRIORITY 8 #include "en/port_buffer.h"
#define MLX5E_100MB (100000) #define MLX5E_100MB (100000)
#define MLX5E_1GB (1000000) #define MLX5E_1GB (1000000)
...@@ -41,6 +41,9 @@ ...@@ -41,6 +41,9 @@
#define MLX5E_CEE_STATE_UP 1 #define MLX5E_CEE_STATE_UP 1
#define MLX5E_CEE_STATE_DOWN 0 #define MLX5E_CEE_STATE_DOWN 0
/* Max supported cable length is 1000 meters */
#define MLX5E_MAX_CABLE_LENGTH 1000
enum { enum {
MLX5E_VENDOR_TC_GROUP_NUM = 7, MLX5E_VENDOR_TC_GROUP_NUM = 7,
MLX5E_LOWEST_PRIO_GROUP = 0, MLX5E_LOWEST_PRIO_GROUP = 0,
...@@ -338,6 +341,9 @@ static int mlx5e_dcbnl_ieee_getpfc(struct net_device *dev, ...@@ -338,6 +341,9 @@ static int mlx5e_dcbnl_ieee_getpfc(struct net_device *dev,
pfc->indications[i] = PPORT_PER_PRIO_GET(pstats, i, rx_pause); pfc->indications[i] = PPORT_PER_PRIO_GET(pstats, i, rx_pause);
} }
if (MLX5_BUFFER_SUPPORTED(mdev))
pfc->delay = priv->dcbx.cable_len;
return mlx5_query_port_pfc(mdev, &pfc->pfc_en, NULL); return mlx5_query_port_pfc(mdev, &pfc->pfc_en, NULL);
} }
...@@ -346,16 +352,39 @@ static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev, ...@@ -346,16 +352,39 @@ static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev,
{ {
struct mlx5e_priv *priv = netdev_priv(dev); struct mlx5e_priv *priv = netdev_priv(dev);
struct mlx5_core_dev *mdev = priv->mdev; struct mlx5_core_dev *mdev = priv->mdev;
u32 old_cable_len = priv->dcbx.cable_len;
struct ieee_pfc pfc_new;
u32 changed = 0;
u8 curr_pfc_en; u8 curr_pfc_en;
int ret; int ret = 0;
/* pfc_en */
mlx5_query_port_pfc(mdev, &curr_pfc_en, NULL); mlx5_query_port_pfc(mdev, &curr_pfc_en, NULL);
if (pfc->pfc_en != curr_pfc_en) {
ret = mlx5_set_port_pfc(mdev, pfc->pfc_en, pfc->pfc_en);
if (ret)
return ret;
mlx5_toggle_port_link(mdev);
changed |= MLX5E_PORT_BUFFER_PFC;
}
if (pfc->pfc_en == curr_pfc_en) if (pfc->delay &&
return 0; pfc->delay < MLX5E_MAX_CABLE_LENGTH &&
pfc->delay != priv->dcbx.cable_len) {
priv->dcbx.cable_len = pfc->delay;
changed |= MLX5E_PORT_BUFFER_CABLE_LEN;
}
ret = mlx5_set_port_pfc(mdev, pfc->pfc_en, pfc->pfc_en); if (MLX5_BUFFER_SUPPORTED(mdev)) {
mlx5_toggle_port_link(mdev); pfc_new.pfc_en = (changed & MLX5E_PORT_BUFFER_PFC) ? pfc->pfc_en : curr_pfc_en;
if (priv->dcbx.manual_buffer)
ret = mlx5e_port_manual_buffer_config(priv, changed,
dev->mtu, &pfc_new,
NULL, NULL);
if (ret && (changed & MLX5E_PORT_BUFFER_CABLE_LEN))
priv->dcbx.cable_len = old_cable_len;
}
if (!ret) { if (!ret) {
mlx5e_dbg(HW, priv, mlx5e_dbg(HW, priv,
...@@ -873,6 +902,90 @@ static void mlx5e_dcbnl_setpfcstate(struct net_device *netdev, u8 state) ...@@ -873,6 +902,90 @@ static void mlx5e_dcbnl_setpfcstate(struct net_device *netdev, u8 state)
cee_cfg->pfc_enable = state; cee_cfg->pfc_enable = state;
} }
static int mlx5e_dcbnl_getbuffer(struct net_device *dev,
struct dcbnl_buffer *dcb_buffer)
{
struct mlx5e_priv *priv = netdev_priv(dev);
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5e_port_buffer port_buffer;
u8 buffer[MLX5E_MAX_PRIORITY];
int i, err;
if (!MLX5_BUFFER_SUPPORTED(mdev))
return -EOPNOTSUPP;
err = mlx5e_port_query_priority2buffer(mdev, buffer);
if (err)
return err;
for (i = 0; i < MLX5E_MAX_PRIORITY; i++)
dcb_buffer->prio2buffer[i] = buffer[i];
err = mlx5e_port_query_buffer(priv, &port_buffer);
if (err)
return err;
for (i = 0; i < MLX5E_MAX_BUFFER; i++)
dcb_buffer->buffer_size[i] = port_buffer.buffer[i].size;
dcb_buffer->total_size = port_buffer.port_buffer_size;
return 0;
}
static int mlx5e_dcbnl_setbuffer(struct net_device *dev,
struct dcbnl_buffer *dcb_buffer)
{
struct mlx5e_priv *priv = netdev_priv(dev);
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5e_port_buffer port_buffer;
u8 old_prio2buffer[MLX5E_MAX_PRIORITY];
u32 *buffer_size = NULL;
u8 *prio2buffer = NULL;
u32 changed = 0;
int i, err;
if (!MLX5_BUFFER_SUPPORTED(mdev))
return -EOPNOTSUPP;
for (i = 0; i < DCBX_MAX_BUFFERS; i++)
mlx5_core_dbg(mdev, "buffer[%d]=%d\n", i, dcb_buffer->buffer_size[i]);
for (i = 0; i < MLX5E_MAX_PRIORITY; i++)
mlx5_core_dbg(mdev, "priority %d buffer%d\n", i, dcb_buffer->prio2buffer[i]);
err = mlx5e_port_query_priority2buffer(mdev, old_prio2buffer);
if (err)
return err;
for (i = 0; i < MLX5E_MAX_PRIORITY; i++) {
if (dcb_buffer->prio2buffer[i] != old_prio2buffer[i]) {
changed |= MLX5E_PORT_BUFFER_PRIO2BUFFER;
prio2buffer = dcb_buffer->prio2buffer;
break;
}
}
err = mlx5e_port_query_buffer(priv, &port_buffer);
if (err)
return err;
for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
if (port_buffer.buffer[i].size != dcb_buffer->buffer_size[i]) {
changed |= MLX5E_PORT_BUFFER_SIZE;
buffer_size = dcb_buffer->buffer_size;
break;
}
}
if (!changed)
return 0;
priv->dcbx.manual_buffer = true;
err = mlx5e_port_manual_buffer_config(priv, changed, dev->mtu, NULL,
buffer_size, prio2buffer);
return err;
}
const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops = { const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops = {
.ieee_getets = mlx5e_dcbnl_ieee_getets, .ieee_getets = mlx5e_dcbnl_ieee_getets,
.ieee_setets = mlx5e_dcbnl_ieee_setets, .ieee_setets = mlx5e_dcbnl_ieee_setets,
...@@ -884,6 +997,8 @@ const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops = { ...@@ -884,6 +997,8 @@ const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops = {
.ieee_delapp = mlx5e_dcbnl_ieee_delapp, .ieee_delapp = mlx5e_dcbnl_ieee_delapp,
.getdcbx = mlx5e_dcbnl_getdcbx, .getdcbx = mlx5e_dcbnl_getdcbx,
.setdcbx = mlx5e_dcbnl_setdcbx, .setdcbx = mlx5e_dcbnl_setdcbx,
.dcbnl_getbuffer = mlx5e_dcbnl_getbuffer,
.dcbnl_setbuffer = mlx5e_dcbnl_setbuffer,
/* CEE interfaces */ /* CEE interfaces */
.setall = mlx5e_dcbnl_setall, .setall = mlx5e_dcbnl_setall,
...@@ -1091,5 +1206,8 @@ void mlx5e_dcbnl_initialize(struct mlx5e_priv *priv) ...@@ -1091,5 +1206,8 @@ void mlx5e_dcbnl_initialize(struct mlx5e_priv *priv)
if (priv->dcbx.mode == MLX5E_DCBX_PARAM_VER_OPER_HOST) if (priv->dcbx.mode == MLX5E_DCBX_PARAM_VER_OPER_HOST)
priv->dcbx.cap |= DCB_CAP_DCBX_HOST; priv->dcbx.cap |= DCB_CAP_DCBX_HOST;
priv->dcbx.manual_buffer = false;
priv->dcbx.cable_len = MLX5E_DEFAULT_CABLE_LEN;
mlx5e_ets_init(priv); mlx5e_ets_init(priv);
} }
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
*/ */
#include "en.h" #include "en.h"
#include "en/port.h"
void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv, void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv,
struct ethtool_drvinfo *drvinfo) struct ethtool_drvinfo *drvinfo)
...@@ -59,18 +60,16 @@ static void mlx5e_get_drvinfo(struct net_device *dev, ...@@ -59,18 +60,16 @@ static void mlx5e_get_drvinfo(struct net_device *dev,
struct ptys2ethtool_config { struct ptys2ethtool_config {
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported); __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertised); __ETHTOOL_DECLARE_LINK_MODE_MASK(advertised);
u32 speed;
}; };
static struct ptys2ethtool_config ptys2ethtool_table[MLX5E_LINK_MODES_NUMBER]; static struct ptys2ethtool_config ptys2ethtool_table[MLX5E_LINK_MODES_NUMBER];
#define MLX5_BUILD_PTYS2ETHTOOL_CONFIG(reg_, speed_, ...) \ #define MLX5_BUILD_PTYS2ETHTOOL_CONFIG(reg_, ...) \
({ \ ({ \
struct ptys2ethtool_config *cfg; \ struct ptys2ethtool_config *cfg; \
const unsigned int modes[] = { __VA_ARGS__ }; \ const unsigned int modes[] = { __VA_ARGS__ }; \
unsigned int i; \ unsigned int i; \
cfg = &ptys2ethtool_table[reg_]; \ cfg = &ptys2ethtool_table[reg_]; \
cfg->speed = speed_; \
bitmap_zero(cfg->supported, \ bitmap_zero(cfg->supported, \
__ETHTOOL_LINK_MODE_MASK_NBITS); \ __ETHTOOL_LINK_MODE_MASK_NBITS); \
bitmap_zero(cfg->advertised, \ bitmap_zero(cfg->advertised, \
...@@ -83,55 +82,55 @@ static struct ptys2ethtool_config ptys2ethtool_table[MLX5E_LINK_MODES_NUMBER]; ...@@ -83,55 +82,55 @@ static struct ptys2ethtool_config ptys2ethtool_table[MLX5E_LINK_MODES_NUMBER];
void mlx5e_build_ptys2ethtool_map(void) void mlx5e_build_ptys2ethtool_map(void)
{ {
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_1000BASE_CX_SGMII, SPEED_1000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_1000BASE_CX_SGMII,
ETHTOOL_LINK_MODE_1000baseKX_Full_BIT); ETHTOOL_LINK_MODE_1000baseKX_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_1000BASE_KX, SPEED_1000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_1000BASE_KX,
ETHTOOL_LINK_MODE_1000baseKX_Full_BIT); ETHTOOL_LINK_MODE_1000baseKX_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_CX4, SPEED_10000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_CX4,
ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT); ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_KX4, SPEED_10000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_KX4,
ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT); ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_KR, SPEED_10000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_KR,
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_20GBASE_KR2, SPEED_20000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_20GBASE_KR2,
ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT); ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_CR4, SPEED_40000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_CR4,
ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT); ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_KR4, SPEED_40000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_KR4,
ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT); ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_56GBASE_R4, SPEED_56000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_56GBASE_R4,
ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT); ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_CR, SPEED_10000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_CR,
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_SR, SPEED_10000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_SR,
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_ER, SPEED_10000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_ER,
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_SR4, SPEED_40000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_SR4,
ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT); ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_LR4, SPEED_40000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_LR4,
ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT); ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_SR2, SPEED_50000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_SR2,
ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT); ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_CR4, SPEED_100000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_CR4,
ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT); ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_SR4, SPEED_100000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_SR4,
ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT); ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_KR4, SPEED_100000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_KR4,
ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT); ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_LR4, SPEED_100000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_LR4,
ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT); ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_T, SPEED_10000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_T,
ETHTOOL_LINK_MODE_10000baseT_Full_BIT); ETHTOOL_LINK_MODE_10000baseT_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_CR, SPEED_25000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_CR,
ETHTOOL_LINK_MODE_25000baseCR_Full_BIT); ETHTOOL_LINK_MODE_25000baseCR_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_KR, SPEED_25000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_KR,
ETHTOOL_LINK_MODE_25000baseKR_Full_BIT); ETHTOOL_LINK_MODE_25000baseKR_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_SR, SPEED_25000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_SR,
ETHTOOL_LINK_MODE_25000baseSR_Full_BIT); ETHTOOL_LINK_MODE_25000baseSR_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_CR2, SPEED_50000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_CR2,
ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT); ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT);
MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_KR2, SPEED_50000, MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_KR2,
ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT); ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT);
} }
...@@ -617,43 +616,24 @@ static void ptys2ethtool_supported_advertised_port(struct ethtool_link_ksettings ...@@ -617,43 +616,24 @@ static void ptys2ethtool_supported_advertised_port(struct ethtool_link_ksettings
} }
} }
int mlx5e_get_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
{
u32 max_speed = 0;
u32 proto_cap;
int err;
int i;
err = mlx5_query_port_proto_cap(mdev, &proto_cap, MLX5_PTYS_EN);
if (err)
return err;
for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i)
if (proto_cap & MLX5E_PROT_MASK(i))
max_speed = max(max_speed, ptys2ethtool_table[i].speed);
*speed = max_speed;
return 0;
}
static void get_speed_duplex(struct net_device *netdev, static void get_speed_duplex(struct net_device *netdev,
u32 eth_proto_oper, u32 eth_proto_oper,
struct ethtool_link_ksettings *link_ksettings) struct ethtool_link_ksettings *link_ksettings)
{ {
int i;
u32 speed = SPEED_UNKNOWN; u32 speed = SPEED_UNKNOWN;
u8 duplex = DUPLEX_UNKNOWN; u8 duplex = DUPLEX_UNKNOWN;
if (!netif_carrier_ok(netdev)) if (!netif_carrier_ok(netdev))
goto out; goto out;
for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { speed = mlx5e_port_ptys2speed(eth_proto_oper);
if (eth_proto_oper & MLX5E_PROT_MASK(i)) { if (!speed) {
speed = ptys2ethtool_table[i].speed; speed = SPEED_UNKNOWN;
duplex = DUPLEX_FULL; goto out;
break;
}
} }
duplex = DUPLEX_FULL;
out: out:
link_ksettings->base.speed = speed; link_ksettings->base.speed = speed;
link_ksettings->base.duplex = duplex; link_ksettings->base.duplex = duplex;
...@@ -811,18 +791,6 @@ static u32 mlx5e_ethtool2ptys_adver_link(const unsigned long *link_modes) ...@@ -811,18 +791,6 @@ static u32 mlx5e_ethtool2ptys_adver_link(const unsigned long *link_modes)
return ptys_modes; return ptys_modes;
} }
static u32 mlx5e_ethtool2ptys_speed_link(u32 speed)
{
u32 i, speed_links = 0;
for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) {
if (ptys2ethtool_table[i].speed == speed)
speed_links |= MLX5E_PROT_MASK(i);
}
return speed_links;
}
static int mlx5e_set_link_ksettings(struct net_device *netdev, static int mlx5e_set_link_ksettings(struct net_device *netdev,
const struct ethtool_link_ksettings *link_ksettings) const struct ethtool_link_ksettings *link_ksettings)
{ {
...@@ -842,7 +810,7 @@ static int mlx5e_set_link_ksettings(struct net_device *netdev, ...@@ -842,7 +810,7 @@ static int mlx5e_set_link_ksettings(struct net_device *netdev,
link_modes = link_ksettings->base.autoneg == AUTONEG_ENABLE ? link_modes = link_ksettings->base.autoneg == AUTONEG_ENABLE ?
mlx5e_ethtool2ptys_adver_link(link_ksettings->link_modes.advertising) : mlx5e_ethtool2ptys_adver_link(link_ksettings->link_modes.advertising) :
mlx5e_ethtool2ptys_speed_link(speed); mlx5e_port_speed2linkmodes(speed);
err = mlx5_query_port_proto_cap(mdev, &eth_proto_cap, MLX5_PTYS_EN); err = mlx5_query_port_proto_cap(mdev, &eth_proto_cap, MLX5_PTYS_EN);
if (err) { if (err) {
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include "accel/ipsec.h" #include "accel/ipsec.h"
#include "accel/tls.h" #include "accel/tls.h"
#include "vxlan.h" #include "vxlan.h"
#include "en/port.h"
struct mlx5e_rq_param { struct mlx5e_rq_param {
u32 rqc[MLX5_ST_SZ_DW(rqc)]; u32 rqc[MLX5_ST_SZ_DW(rqc)];
...@@ -4082,7 +4083,7 @@ static bool slow_pci_heuristic(struct mlx5_core_dev *mdev) ...@@ -4082,7 +4083,7 @@ static bool slow_pci_heuristic(struct mlx5_core_dev *mdev)
u32 link_speed = 0; u32 link_speed = 0;
u32 pci_bw = 0; u32 pci_bw = 0;
mlx5e_get_max_linkspeed(mdev, &link_speed); mlx5e_port_max_linkspeed(mdev, &link_speed);
pci_bw = pcie_bandwidth_available(mdev->pdev, NULL, NULL, NULL); pci_bw = pcie_bandwidth_available(mdev->pdev, NULL, NULL, NULL);
mlx5_core_dbg_once(mdev, "Max link speed = %d, PCI BW = %d\n", mlx5_core_dbg_once(mdev, "Max link speed = %d, PCI BW = %d\n",
link_speed, pci_bw); link_speed, pci_bw);
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include "eswitch.h" #include "eswitch.h"
#include "vxlan.h" #include "vxlan.h"
#include "fs_core.h" #include "fs_core.h"
#include "en/port.h"
struct mlx5_nic_flow_attr { struct mlx5_nic_flow_attr {
u32 action; u32 action;
...@@ -613,7 +614,7 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv, ...@@ -613,7 +614,7 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
params.q_counter = priv->q_counter; params.q_counter = priv->q_counter;
/* set hairpin pair per each 50Gbs share of the link */ /* set hairpin pair per each 50Gbs share of the link */
mlx5e_get_max_linkspeed(priv->mdev, &link_speed); mlx5e_port_max_linkspeed(priv->mdev, &link_speed);
link_speed = max_t(u32, link_speed, 50000); link_speed = max_t(u32, link_speed, 50000);
link_speed64 = link_speed; link_speed64 = link_speed;
do_div(link_speed64, 50000); do_div(link_speed64, 50000);
......
...@@ -1152,6 +1152,9 @@ enum mlx5_qcam_feature_groups { ...@@ -1152,6 +1152,9 @@ enum mlx5_qcam_feature_groups {
#define MLX5_CAP_PCAM_FEATURE(mdev, fld) \ #define MLX5_CAP_PCAM_FEATURE(mdev, fld) \
MLX5_GET(pcam_reg, (mdev)->caps.pcam, feature_cap_mask.enhanced_features.fld) MLX5_GET(pcam_reg, (mdev)->caps.pcam, feature_cap_mask.enhanced_features.fld)
#define MLX5_CAP_PCAM_REG(mdev, reg) \
MLX5_GET(pcam_reg, (mdev)->caps.pcam, port_access_reg_cap_mask.regs_5000_to_507f.reg)
#define MLX5_CAP_MCAM_REG(mdev, reg) \ #define MLX5_CAP_MCAM_REG(mdev, reg) \
MLX5_GET(mcam_reg, (mdev)->caps.mcam, mng_access_reg_cap_mask.access_regs.reg) MLX5_GET(mcam_reg, (mdev)->caps.mcam, mng_access_reg_cap_mask.access_regs.reg)
......
...@@ -124,6 +124,8 @@ enum { ...@@ -124,6 +124,8 @@ enum {
MLX5_REG_PAOS = 0x5006, MLX5_REG_PAOS = 0x5006,
MLX5_REG_PFCC = 0x5007, MLX5_REG_PFCC = 0x5007,
MLX5_REG_PPCNT = 0x5008, MLX5_REG_PPCNT = 0x5008,
MLX5_REG_PPTB = 0x500b,
MLX5_REG_PBMC = 0x500c,
MLX5_REG_PMAOS = 0x5012, MLX5_REG_PMAOS = 0x5012,
MLX5_REG_PUDE = 0x5009, MLX5_REG_PUDE = 0x5009,
MLX5_REG_PMPE = 0x5010, MLX5_REG_PMPE = 0x5010,
......
...@@ -8003,6 +8003,17 @@ struct mlx5_ifc_pcam_enhanced_features_bits { ...@@ -8003,6 +8003,17 @@ struct mlx5_ifc_pcam_enhanced_features_bits {
u8 ppcnt_statistical_group[0x1]; u8 ppcnt_statistical_group[0x1];
}; };
struct mlx5_ifc_pcam_regs_5000_to_507f_bits {
u8 port_access_reg_cap_mask_127_to_96[0x20];
u8 port_access_reg_cap_mask_95_to_64[0x20];
u8 port_access_reg_cap_mask_63_to_32[0x20];
u8 port_access_reg_cap_mask_31_to_13[0x13];
u8 pbmc[0x1];
u8 pptb[0x1];
u8 port_access_reg_cap_mask_10_to_0[0xb];
};
struct mlx5_ifc_pcam_reg_bits { struct mlx5_ifc_pcam_reg_bits {
u8 reserved_at_0[0x8]; u8 reserved_at_0[0x8];
u8 feature_group[0x8]; u8 feature_group[0x8];
...@@ -8012,6 +8023,7 @@ struct mlx5_ifc_pcam_reg_bits { ...@@ -8012,6 +8023,7 @@ struct mlx5_ifc_pcam_reg_bits {
u8 reserved_at_20[0x20]; u8 reserved_at_20[0x20];
union { union {
struct mlx5_ifc_pcam_regs_5000_to_507f_bits regs_5000_to_507f;
u8 reserved_at_0[0x80]; u8 reserved_at_0[0x80];
} port_access_reg_cap_mask; } port_access_reg_cap_mask;
...@@ -8776,6 +8788,41 @@ struct mlx5_ifc_qpts_reg_bits { ...@@ -8776,6 +8788,41 @@ struct mlx5_ifc_qpts_reg_bits {
u8 trust_state[0x3]; u8 trust_state[0x3];
}; };
struct mlx5_ifc_pptb_reg_bits {
u8 reserved_at_0[0x2];
u8 mm[0x2];
u8 reserved_at_4[0x4];
u8 local_port[0x8];
u8 reserved_at_10[0x6];
u8 cm[0x1];
u8 um[0x1];
u8 pm[0x8];
u8 prio_x_buff[0x20];
u8 pm_msb[0x8];
u8 reserved_at_48[0x10];
u8 ctrl_buff[0x4];
u8 untagged_buff[0x4];
};
struct mlx5_ifc_pbmc_reg_bits {
u8 reserved_at_0[0x8];
u8 local_port[0x8];
u8 reserved_at_10[0x10];
u8 xoff_timer_value[0x10];
u8 xoff_refresh[0x10];
u8 reserved_at_40[0x9];
u8 fullness_threshold[0x7];
u8 port_buffer_size[0x10];
struct mlx5_ifc_bufferx_reg_bits buffer[10];
u8 reserved_at_2e0[0x40];
};
struct mlx5_ifc_qtct_reg_bits { struct mlx5_ifc_qtct_reg_bits {
u8 reserved_at_0[0x8]; u8 reserved_at_0[0x8];
u8 port_number[0x8]; u8 port_number[0x8];
......
...@@ -101,6 +101,10 @@ struct dcbnl_rtnl_ops { ...@@ -101,6 +101,10 @@ struct dcbnl_rtnl_ops {
/* CEE peer */ /* CEE peer */
int (*cee_peer_getpg) (struct net_device *, struct cee_pg *); int (*cee_peer_getpg) (struct net_device *, struct cee_pg *);
int (*cee_peer_getpfc) (struct net_device *, struct cee_pfc *); int (*cee_peer_getpfc) (struct net_device *, struct cee_pfc *);
/* buffer settings */
int (*dcbnl_getbuffer)(struct net_device *, struct dcbnl_buffer *);
int (*dcbnl_setbuffer)(struct net_device *, struct dcbnl_buffer *);
}; };
#endif /* __NET_DCBNL_H__ */ #endif /* __NET_DCBNL_H__ */
...@@ -163,6 +163,16 @@ struct ieee_pfc { ...@@ -163,6 +163,16 @@ struct ieee_pfc {
__u64 indications[IEEE_8021QAZ_MAX_TCS]; __u64 indications[IEEE_8021QAZ_MAX_TCS];
}; };
#define IEEE_8021Q_MAX_PRIORITIES 8
#define DCBX_MAX_BUFFERS 8
struct dcbnl_buffer {
/* priority to buffer mapping */
__u8 prio2buffer[IEEE_8021Q_MAX_PRIORITIES];
/* buffer size in Bytes */
__u32 buffer_size[DCBX_MAX_BUFFERS];
__u32 total_size;
};
/* CEE DCBX std supported values */ /* CEE DCBX std supported values */
#define CEE_DCBX_MAX_PGS 8 #define CEE_DCBX_MAX_PGS 8
#define CEE_DCBX_MAX_PRIO 8 #define CEE_DCBX_MAX_PRIO 8
...@@ -406,6 +416,7 @@ enum ieee_attrs { ...@@ -406,6 +416,7 @@ enum ieee_attrs {
DCB_ATTR_IEEE_MAXRATE, DCB_ATTR_IEEE_MAXRATE,
DCB_ATTR_IEEE_QCN, DCB_ATTR_IEEE_QCN,
DCB_ATTR_IEEE_QCN_STATS, DCB_ATTR_IEEE_QCN_STATS,
DCB_ATTR_DCB_BUFFER,
__DCB_ATTR_IEEE_MAX __DCB_ATTR_IEEE_MAX
}; };
#define DCB_ATTR_IEEE_MAX (__DCB_ATTR_IEEE_MAX - 1) #define DCB_ATTR_IEEE_MAX (__DCB_ATTR_IEEE_MAX - 1)
......
...@@ -176,6 +176,7 @@ static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = { ...@@ -176,6 +176,7 @@ static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = {
[DCB_ATTR_IEEE_MAXRATE] = {.len = sizeof(struct ieee_maxrate)}, [DCB_ATTR_IEEE_MAXRATE] = {.len = sizeof(struct ieee_maxrate)},
[DCB_ATTR_IEEE_QCN] = {.len = sizeof(struct ieee_qcn)}, [DCB_ATTR_IEEE_QCN] = {.len = sizeof(struct ieee_qcn)},
[DCB_ATTR_IEEE_QCN_STATS] = {.len = sizeof(struct ieee_qcn_stats)}, [DCB_ATTR_IEEE_QCN_STATS] = {.len = sizeof(struct ieee_qcn_stats)},
[DCB_ATTR_DCB_BUFFER] = {.len = sizeof(struct dcbnl_buffer)},
}; };
/* DCB number of traffic classes nested attributes. */ /* DCB number of traffic classes nested attributes. */
...@@ -1094,6 +1095,16 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev) ...@@ -1094,6 +1095,16 @@ static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
return -EMSGSIZE; return -EMSGSIZE;
} }
if (ops->dcbnl_getbuffer) {
struct dcbnl_buffer buffer;
memset(&buffer, 0, sizeof(buffer));
err = ops->dcbnl_getbuffer(netdev, &buffer);
if (!err &&
nla_put(skb, DCB_ATTR_DCB_BUFFER, sizeof(buffer), &buffer))
return -EMSGSIZE;
}
app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE); app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE);
if (!app) if (!app)
return -EMSGSIZE; return -EMSGSIZE;
...@@ -1453,6 +1464,15 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh, ...@@ -1453,6 +1464,15 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh,
goto err; goto err;
} }
if (ieee[DCB_ATTR_DCB_BUFFER] && ops->dcbnl_setbuffer) {
struct dcbnl_buffer *buffer =
nla_data(ieee[DCB_ATTR_DCB_BUFFER]);
err = ops->dcbnl_setbuffer(netdev, buffer);
if (err)
goto err;
}
if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
struct nlattr *attr; struct nlattr *attr;
int rem; int rem;
......
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