Merge branch 'bnxt_en-next'

Michael Chan says:

====================
bnxt_en: Updates for net-next.

First, we upgrade the firmware interface spec.  Due to a change in
the toolchains, the auto-generated bnxt_hsi.h does not match the
old bnxt_hsi.h and the patch is really big.  This should be just
one-time.  Going forward, changes should be incremental.

The next 10 patches implement a new scheme for the PF and VF drivers
to allocate and reserve resources.  The new scheme is more flexible
and allows dynamic and asymmetric distribution of resources, whereas
the old scheme is static and even distribution.

The last few patches add cacheline size setting, a couple of PCI IDs,
better management of VF MAC address, and a better parent switchdev ID
for dual-port devices.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2018-01-17 14:48:27 -05:00
commit c9a824210f
7 changed files with 6289 additions and 5954 deletions

View File

@ -1,7 +1,7 @@
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2016 Broadcom Corporation
* Copyright (c) 2016-2017 Broadcom Limited
* Copyright (c) 2016-2018 Broadcom Limited
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -107,6 +107,7 @@ enum board_idx {
BCM57416_NPAR,
BCM57452,
BCM57454,
BCM5745x_NPAR,
BCM58802,
BCM58804,
BCM58808,
@ -147,6 +148,7 @@ static const struct {
[BCM57416_NPAR] = { "Broadcom BCM57416 NetXtreme-E Ethernet Partition" },
[BCM57452] = { "Broadcom BCM57452 NetXtreme-E 10Gb/25Gb/40Gb/50Gb Ethernet" },
[BCM57454] = { "Broadcom BCM57454 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet" },
[BCM5745x_NPAR] = { "Broadcom BCM5745x NetXtreme-E Ethernet Partition" },
[BCM58802] = { "Broadcom BCM58802 NetXtreme-S 10Gb/25Gb/40Gb/50Gb Ethernet" },
[BCM58804] = { "Broadcom BCM58804 NetXtreme-S 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet" },
[BCM58808] = { "Broadcom BCM58808 NetXtreme-S 10Gb/25Gb/40Gb/50Gb/100Gb Ethernet" },
@ -156,6 +158,8 @@ static const struct {
};
static const struct pci_device_id bnxt_pci_tbl[] = {
{ PCI_VDEVICE(BROADCOM, 0x1604), .driver_data = BCM5745x_NPAR },
{ PCI_VDEVICE(BROADCOM, 0x1605), .driver_data = BCM5745x_NPAR },
{ PCI_VDEVICE(BROADCOM, 0x1614), .driver_data = BCM57454 },
{ PCI_VDEVICE(BROADCOM, 0x16c0), .driver_data = BCM57417_NPAR },
{ PCI_VDEVICE(BROADCOM, 0x16c8), .driver_data = BCM57301 },
@ -209,6 +213,7 @@ MODULE_DEVICE_TABLE(pci, bnxt_pci_tbl);
static const u16 bnxt_vf_req_snif[] = {
HWRM_FUNC_CFG,
HWRM_FUNC_VF_CFG,
HWRM_PORT_PHY_QCFG,
HWRM_CFA_L2_FILTER_ALLOC,
};
@ -4498,6 +4503,42 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
}
}
static int bnxt_hwrm_get_rings(struct bnxt *bp)
{
struct hwrm_func_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
struct hwrm_func_qcfg_input req = {0};
int rc;
if (bp->hwrm_spec_code < 0x10601)
return 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCFG, -1, -1);
req.fid = cpu_to_le16(0xffff);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc) {
mutex_unlock(&bp->hwrm_cmd_lock);
return -EIO;
}
hw_resc->resv_tx_rings = le16_to_cpu(resp->alloc_tx_rings);
if (bp->flags & BNXT_FLAG_NEW_RM) {
u16 cp, stats;
hw_resc->resv_rx_rings = le16_to_cpu(resp->alloc_rx_rings);
hw_resc->resv_hw_ring_grps =
le32_to_cpu(resp->alloc_hw_ring_grps);
hw_resc->resv_vnics = le16_to_cpu(resp->alloc_vnics);
cp = le16_to_cpu(resp->alloc_cmpl_rings);
stats = le16_to_cpu(resp->alloc_stat_ctx);
cp = min_t(u16, cp, stats);
hw_resc->resv_cp_rings = cp;
}
mutex_unlock(&bp->hwrm_cmd_lock);
return 0;
}
/* Caller must hold bp->hwrm_cmd_lock */
int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings)
{
@ -4517,55 +4558,283 @@ int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings)
return rc;
}
static int bnxt_hwrm_reserve_tx_rings(struct bnxt *bp, int *tx_rings)
static int
bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
int ring_grps, int cp_rings, int vnics)
{
struct hwrm_func_cfg_input req = {0};
u32 enables = 0;
int rc;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.fid = cpu_to_le16(0xffff);
enables |= tx_rings ? FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS : 0;
req.num_tx_rings = cpu_to_le16(tx_rings);
if (bp->flags & BNXT_FLAG_NEW_RM) {
enables |= rx_rings ? FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS : 0;
enables |= cp_rings ? FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
enables |= ring_grps ?
FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0;
enables |= vnics ? FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS : 0;
req.num_rx_rings = cpu_to_le16(rx_rings);
req.num_hw_ring_grps = cpu_to_le16(ring_grps);
req.num_cmpl_rings = cpu_to_le16(cp_rings);
req.num_stat_ctxs = req.num_cmpl_rings;
req.num_vnics = cpu_to_le16(vnics);
}
if (!enables)
return 0;
req.enables = cpu_to_le32(enables);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc)
return -ENOMEM;
if (bp->hwrm_spec_code < 0x10601)
bp->hw_resc.resv_tx_rings = tx_rings;
rc = bnxt_hwrm_get_rings(bp);
return rc;
}
static int
bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
int ring_grps, int cp_rings, int vnics)
{
struct hwrm_func_vf_cfg_input req = {0};
u32 enables = 0;
int rc;
if (!(bp->flags & BNXT_FLAG_NEW_RM)) {
bp->hw_resc.resv_tx_rings = tx_rings;
return 0;
}
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_CFG, -1, -1);
enables |= tx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_TX_RINGS : 0;
enables |= rx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS : 0;
enables |= cp_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
enables |= ring_grps ? FUNC_VF_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0;
enables |= vnics ? FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS : 0;
req.num_tx_rings = cpu_to_le16(tx_rings);
req.num_rx_rings = cpu_to_le16(rx_rings);
req.num_hw_ring_grps = cpu_to_le16(ring_grps);
req.num_cmpl_rings = cpu_to_le16(cp_rings);
req.num_stat_ctxs = req.num_cmpl_rings;
req.num_vnics = cpu_to_le16(vnics);
req.enables = cpu_to_le32(enables);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc)
return -ENOMEM;
rc = bnxt_hwrm_get_rings(bp);
return rc;
}
static int bnxt_hwrm_reserve_rings(struct bnxt *bp, int tx, int rx, int grp,
int cp, int vnic)
{
if (BNXT_PF(bp))
return bnxt_hwrm_reserve_pf_rings(bp, tx, rx, grp, cp, vnic);
else
return bnxt_hwrm_reserve_vf_rings(bp, tx, rx, grp, cp, vnic);
}
static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max,
bool shared);
static int __bnxt_reserve_rings(struct bnxt *bp)
{
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
int tx = bp->tx_nr_rings;
int rx = bp->rx_nr_rings;
int cp = bp->cp_nr_rings;
int grp, rx_rings, rc;
bool sh = false;
int vnic = 1;
if (bp->hwrm_spec_code < 0x10601)
return 0;
if (BNXT_VF(bp))
if (bp->flags & BNXT_FLAG_SHARED_RINGS)
sh = true;
if (bp->flags & BNXT_FLAG_RFS)
vnic = rx + 1;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
rx <<= 1;
grp = bp->rx_nr_rings;
if (tx == hw_resc->resv_tx_rings &&
(!(bp->flags & BNXT_FLAG_NEW_RM) ||
(rx == hw_resc->resv_rx_rings &&
grp == hw_resc->resv_hw_ring_grps &&
cp == hw_resc->resv_cp_rings && vnic == hw_resc->resv_vnics)))
return 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.fid = cpu_to_le16(0xffff);
req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS);
req.num_tx_rings = cpu_to_le16(*tx_rings);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
rc = bnxt_hwrm_reserve_rings(bp, tx, rx, grp, cp, vnic);
if (rc)
return rc;
mutex_lock(&bp->hwrm_cmd_lock);
rc = __bnxt_hwrm_get_tx_rings(bp, 0xffff, tx_rings);
mutex_unlock(&bp->hwrm_cmd_lock);
if (!rc)
bp->tx_reserved_rings = *tx_rings;
tx = hw_resc->resv_tx_rings;
if (bp->flags & BNXT_FLAG_NEW_RM) {
rx = hw_resc->resv_rx_rings;
cp = hw_resc->resv_cp_rings;
grp = hw_resc->resv_hw_ring_grps;
vnic = hw_resc->resv_vnics;
}
rx_rings = rx;
if (bp->flags & BNXT_FLAG_AGG_RINGS) {
if (rx >= 2) {
rx_rings = rx >> 1;
} else {
if (netif_running(bp->dev))
return -ENOMEM;
bp->flags &= ~BNXT_FLAG_AGG_RINGS;
bp->flags |= BNXT_FLAG_NO_AGG_RINGS;
bp->dev->hw_features &= ~NETIF_F_LRO;
bp->dev->features &= ~NETIF_F_LRO;
bnxt_set_ring_params(bp);
}
}
rx_rings = min_t(int, rx_rings, grp);
rc = bnxt_trim_rings(bp, &rx_rings, &tx, cp, sh);
if (bp->flags & BNXT_FLAG_AGG_RINGS)
rx = rx_rings << 1;
cp = sh ? max_t(int, tx, rx_rings) : tx + rx_rings;
bp->tx_nr_rings = tx;
bp->rx_nr_rings = rx_rings;
bp->cp_nr_rings = cp;
if (!tx || !rx || !cp || !grp || !vnic)
return -ENOMEM;
return rc;
}
static int bnxt_hwrm_check_tx_rings(struct bnxt *bp, int tx_rings)
static bool bnxt_need_reserve_rings(struct bnxt *bp)
{
struct hwrm_func_cfg_input req = {0};
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
int rx = bp->rx_nr_rings;
int vnic = 1;
if (bp->hwrm_spec_code < 0x10601)
return false;
if (hw_resc->resv_tx_rings != bp->tx_nr_rings)
return true;
if (bp->flags & BNXT_FLAG_RFS)
vnic = rx + 1;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
rx <<= 1;
if ((bp->flags & BNXT_FLAG_NEW_RM) &&
(hw_resc->resv_rx_rings != rx ||
hw_resc->resv_cp_rings != bp->cp_nr_rings ||
hw_resc->resv_vnics != vnic))
return true;
return false;
}
static int bnxt_hwrm_check_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
int ring_grps, int cp_rings)
{
struct hwrm_func_vf_cfg_input req = {0};
u32 flags, enables;
int rc;
if (bp->hwrm_spec_code < 0x10801)
if (!(bp->flags & BNXT_FLAG_NEW_RM))
return 0;
if (BNXT_VF(bp))
return 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_CFG, -1, -1);
flags = FUNC_VF_CFG_REQ_FLAGS_TX_ASSETS_TEST |
FUNC_VF_CFG_REQ_FLAGS_RX_ASSETS_TEST |
FUNC_VF_CFG_REQ_FLAGS_CMPL_ASSETS_TEST |
FUNC_VF_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST |
FUNC_VF_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST |
FUNC_VF_CFG_REQ_FLAGS_VNIC_ASSETS_TEST;
enables = FUNC_VF_CFG_REQ_ENABLES_NUM_TX_RINGS |
FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS |
FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
FUNC_VF_CFG_REQ_ENABLES_NUM_HW_RING_GRPS |
FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS |
FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.fid = cpu_to_le16(0xffff);
req.flags = cpu_to_le32(FUNC_CFG_REQ_FLAGS_TX_ASSETS_TEST);
req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS);
req.flags = cpu_to_le32(flags);
req.enables = cpu_to_le32(enables);
req.num_tx_rings = cpu_to_le16(tx_rings);
req.num_rx_rings = cpu_to_le16(rx_rings);
req.num_cmpl_rings = cpu_to_le16(cp_rings);
req.num_hw_ring_grps = cpu_to_le16(ring_grps);
req.num_stat_ctxs = cpu_to_le16(cp_rings);
req.num_vnics = cpu_to_le16(1);
if (bp->flags & BNXT_FLAG_RFS)
req.num_vnics = cpu_to_le16(rx_rings + 1);
rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc)
return -ENOMEM;
return 0;
}
static int bnxt_hwrm_check_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
int ring_grps, int cp_rings)
{
struct hwrm_func_cfg_input req = {0};
u32 flags, enables;
int rc;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.fid = cpu_to_le16(0xffff);
flags = FUNC_CFG_REQ_FLAGS_TX_ASSETS_TEST;
enables = FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS;
req.num_tx_rings = cpu_to_le16(tx_rings);
if (bp->flags & BNXT_FLAG_NEW_RM) {
flags |= FUNC_CFG_REQ_FLAGS_RX_ASSETS_TEST |
FUNC_CFG_REQ_FLAGS_CMPL_ASSETS_TEST |
FUNC_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST |
FUNC_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST |
FUNC_CFG_REQ_FLAGS_VNIC_ASSETS_TEST;
enables |= FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS |
FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS |
FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS |
FUNC_CFG_REQ_ENABLES_NUM_VNICS;
req.num_rx_rings = cpu_to_le16(rx_rings);
req.num_cmpl_rings = cpu_to_le16(cp_rings);
req.num_hw_ring_grps = cpu_to_le16(ring_grps);
req.num_stat_ctxs = cpu_to_le16(cp_rings);
req.num_vnics = cpu_to_le16(1);
if (bp->flags & BNXT_FLAG_RFS)
req.num_vnics = cpu_to_le16(rx_rings + 1);
}
req.flags = cpu_to_le32(flags);
req.enables = cpu_to_le32(enables);
rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc)
return -ENOMEM;
return 0;
}
static int bnxt_hwrm_check_rings(struct bnxt *bp, int tx_rings, int rx_rings,
int ring_grps, int cp_rings)
{
if (bp->hwrm_spec_code < 0x10801)
return 0;
if (BNXT_PF(bp))
return bnxt_hwrm_check_pf_rings(bp, tx_rings, rx_rings,
ring_grps, cp_rings);
return bnxt_hwrm_check_vf_rings(bp, tx_rings, rx_rings, ring_grps,
cp_rings);
}
static void bnxt_hwrm_set_coal_params(struct bnxt_coal *hw_coal,
struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req)
{
@ -4791,11 +5060,60 @@ func_qcfg_exit:
return rc;
}
static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
static int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp)
{
struct hwrm_func_resource_qcaps_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_func_resource_qcaps_input req = {0};
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
int rc;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_RESOURCE_QCAPS, -1, -1);
req.fid = cpu_to_le16(0xffff);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc) {
rc = -EIO;
goto hwrm_func_resc_qcaps_exit;
}
hw_resc->min_rsscos_ctxs = le16_to_cpu(resp->min_rsscos_ctx);
hw_resc->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx);
hw_resc->min_cp_rings = le16_to_cpu(resp->min_cmpl_rings);
hw_resc->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings);
hw_resc->min_tx_rings = le16_to_cpu(resp->min_tx_rings);
hw_resc->max_tx_rings = le16_to_cpu(resp->max_tx_rings);
hw_resc->min_rx_rings = le16_to_cpu(resp->min_rx_rings);
hw_resc->max_rx_rings = le16_to_cpu(resp->max_rx_rings);
hw_resc->min_hw_ring_grps = le16_to_cpu(resp->min_hw_ring_grps);
hw_resc->max_hw_ring_grps = le16_to_cpu(resp->max_hw_ring_grps);
hw_resc->min_l2_ctxs = le16_to_cpu(resp->min_l2_ctxs);
hw_resc->max_l2_ctxs = le16_to_cpu(resp->max_l2_ctxs);
hw_resc->min_vnics = le16_to_cpu(resp->min_vnics);
hw_resc->max_vnics = le16_to_cpu(resp->max_vnics);
hw_resc->min_stat_ctxs = le16_to_cpu(resp->min_stat_ctx);
hw_resc->max_stat_ctxs = le16_to_cpu(resp->max_stat_ctx);
if (BNXT_PF(bp)) {
struct bnxt_pf_info *pf = &bp->pf;
pf->vf_resv_strategy =
le16_to_cpu(resp->vf_reservation_strategy);
if (pf->vf_resv_strategy > BNXT_VF_RESV_STRATEGY_MINIMAL)
pf->vf_resv_strategy = BNXT_VF_RESV_STRATEGY_MAXIMAL;
}
hwrm_func_resc_qcaps_exit:
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
{
int rc = 0;
struct hwrm_func_qcaps_input req = {0};
struct hwrm_func_qcaps_output *resp = bp->hwrm_cmd_resp_addr;
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
u32 flags;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCAPS, -1, -1);
req.fid = cpu_to_le16(0xffff);
@ -4805,16 +5123,27 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
if (rc)
goto hwrm_func_qcaps_exit;
if (resp->flags & cpu_to_le32(FUNC_QCAPS_RESP_FLAGS_ROCE_V1_SUPPORTED))
flags = le32_to_cpu(resp->flags);
if (flags & FUNC_QCAPS_RESP_FLAGS_ROCE_V1_SUPPORTED)
bp->flags |= BNXT_FLAG_ROCEV1_CAP;
if (resp->flags & cpu_to_le32(FUNC_QCAPS_RESP_FLAGS_ROCE_V2_SUPPORTED))
if (flags & FUNC_QCAPS_RESP_FLAGS_ROCE_V2_SUPPORTED)
bp->flags |= BNXT_FLAG_ROCEV2_CAP;
bp->tx_push_thresh = 0;
if (resp->flags &
cpu_to_le32(FUNC_QCAPS_RESP_FLAGS_PUSH_MODE_SUPPORTED))
if (flags & FUNC_QCAPS_RESP_FLAGS_PUSH_MODE_SUPPORTED)
bp->tx_push_thresh = BNXT_TX_PUSH_THRESH;
hw_resc->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx);
hw_resc->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings);
hw_resc->max_tx_rings = le16_to_cpu(resp->max_tx_rings);
hw_resc->max_rx_rings = le16_to_cpu(resp->max_rx_rings);
hw_resc->max_hw_ring_grps = le32_to_cpu(resp->max_hw_ring_grps);
if (!hw_resc->max_hw_ring_grps)
hw_resc->max_hw_ring_grps = hw_resc->max_tx_rings;
hw_resc->max_l2_ctxs = le16_to_cpu(resp->max_l2_ctxs);
hw_resc->max_vnics = le16_to_cpu(resp->max_vnics);
hw_resc->max_stat_ctxs = le16_to_cpu(resp->max_stat_ctx);
if (BNXT_PF(bp)) {
struct bnxt_pf_info *pf = &bp->pf;
@ -4822,16 +5151,6 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
pf->port_id = le16_to_cpu(resp->port_id);
bp->dev->dev_port = pf->port_id;
memcpy(pf->mac_addr, resp->mac_address, ETH_ALEN);
pf->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx);
pf->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings);
pf->max_tx_rings = le16_to_cpu(resp->max_tx_rings);
pf->max_rx_rings = le16_to_cpu(resp->max_rx_rings);
pf->max_hw_ring_grps = le32_to_cpu(resp->max_hw_ring_grps);
if (!pf->max_hw_ring_grps)
pf->max_hw_ring_grps = pf->max_tx_rings;
pf->max_l2_ctxs = le16_to_cpu(resp->max_l2_ctxs);
pf->max_vnics = le16_to_cpu(resp->max_vnics);
pf->max_stat_ctxs = le16_to_cpu(resp->max_stat_ctx);
pf->first_vf_id = le16_to_cpu(resp->first_vf_id);
pf->max_vfs = le16_to_cpu(resp->max_vfs);
pf->max_encap_records = le32_to_cpu(resp->max_encap_records);
@ -4840,26 +5159,13 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
pf->max_tx_wm_flows = le32_to_cpu(resp->max_tx_wm_flows);
pf->max_rx_em_flows = le32_to_cpu(resp->max_rx_em_flows);
pf->max_rx_wm_flows = le32_to_cpu(resp->max_rx_wm_flows);
if (resp->flags &
cpu_to_le32(FUNC_QCAPS_RESP_FLAGS_WOL_MAGICPKT_SUPPORTED))
if (flags & FUNC_QCAPS_RESP_FLAGS_WOL_MAGICPKT_SUPPORTED)
bp->flags |= BNXT_FLAG_WOL_CAP;
} else {
#ifdef CONFIG_BNXT_SRIOV
struct bnxt_vf_info *vf = &bp->vf;
vf->fw_fid = le16_to_cpu(resp->fid);
vf->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx);
vf->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings);
vf->max_tx_rings = le16_to_cpu(resp->max_tx_rings);
vf->max_rx_rings = le16_to_cpu(resp->max_rx_rings);
vf->max_hw_ring_grps = le32_to_cpu(resp->max_hw_ring_grps);
if (!vf->max_hw_ring_grps)
vf->max_hw_ring_grps = vf->max_tx_rings;
vf->max_l2_ctxs = le16_to_cpu(resp->max_l2_ctxs);
vf->max_vnics = le16_to_cpu(resp->max_vnics);
vf->max_stat_ctxs = le16_to_cpu(resp->max_stat_ctx);
memcpy(vf->mac_addr, resp->mac_address, ETH_ALEN);
#endif
}
@ -4869,6 +5175,21 @@ hwrm_func_qcaps_exit:
return rc;
}
static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
{
int rc;
rc = __bnxt_hwrm_func_qcaps(bp);
if (rc)
return rc;
if (bp->hwrm_spec_code >= 0x10803) {
rc = bnxt_hwrm_func_resc_qcaps(bp);
if (!rc)
bp->flags |= BNXT_FLAG_NEW_RM;
}
return 0;
}
static int bnxt_hwrm_func_reset(struct bnxt *bp)
{
struct hwrm_func_reset_input req = {0};
@ -4938,23 +5259,24 @@ static int bnxt_hwrm_ver_get(struct bnxt *bp)
memcpy(&bp->ver_resp, resp, sizeof(struct hwrm_ver_get_output));
bp->hwrm_spec_code = resp->hwrm_intf_maj << 16 |
resp->hwrm_intf_min << 8 | resp->hwrm_intf_upd;
if (resp->hwrm_intf_maj < 1) {
bp->hwrm_spec_code = resp->hwrm_intf_maj_8b << 16 |
resp->hwrm_intf_min_8b << 8 |
resp->hwrm_intf_upd_8b;
if (resp->hwrm_intf_maj_8b < 1) {
netdev_warn(bp->dev, "HWRM interface %d.%d.%d is older than 1.0.0.\n",
resp->hwrm_intf_maj, resp->hwrm_intf_min,
resp->hwrm_intf_upd);
resp->hwrm_intf_maj_8b, resp->hwrm_intf_min_8b,
resp->hwrm_intf_upd_8b);
netdev_warn(bp->dev, "Please update firmware with HWRM interface 1.0.0 or newer.\n");
}
snprintf(bp->fw_ver_str, BC_HWRM_STR_LEN, "%d.%d.%d.%d",
resp->hwrm_fw_maj, resp->hwrm_fw_min, resp->hwrm_fw_bld,
resp->hwrm_fw_rsvd);
resp->hwrm_fw_maj_8b, resp->hwrm_fw_min_8b,
resp->hwrm_fw_bld_8b, resp->hwrm_fw_rsvd_8b);
bp->hwrm_cmd_timeout = le16_to_cpu(resp->def_req_timeout);
if (!bp->hwrm_cmd_timeout)
bp->hwrm_cmd_timeout = DFLT_HWRM_CMD_TIMEOUT;
if (resp->hwrm_intf_maj >= 1)
if (resp->hwrm_intf_maj_8b >= 1)
bp->hwrm_max_req_len = le16_to_cpu(resp->max_req_win_len);
bp->chip_num = le16_to_cpu(resp->chip_num);
@ -5090,6 +5412,28 @@ static int bnxt_hwrm_set_br_mode(struct bnxt *bp, u16 br_mode)
return rc;
}
static int bnxt_hwrm_set_cache_line_size(struct bnxt *bp, int size)
{
struct hwrm_func_cfg_input req = {0};
int rc;
if (BNXT_VF(bp) || bp->hwrm_spec_code < 0x10803)
return 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.fid = cpu_to_le16(0xffff);
req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_CACHE_LINESIZE);
req.cache_linesize = FUNC_QCFG_RESP_CACHE_LINESIZE_CACHE_LINESIZE_64;
if (size == 128)
req.cache_linesize =
FUNC_QCFG_RESP_CACHE_LINESIZE_CACHE_LINESIZE_128;
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc)
rc = -EIO;
return rc;
}
static int bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id)
{
struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id];
@ -5225,15 +5569,6 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
rc);
goto err_out;
}
if (bp->tx_reserved_rings != bp->tx_nr_rings) {
int tx = bp->tx_nr_rings;
if (bnxt_hwrm_reserve_tx_rings(bp, &tx) ||
tx < bp->tx_nr_rings) {
rc = -ENOMEM;
goto err_out;
}
}
}
rc = bnxt_hwrm_ring_alloc(bp);
@ -5453,79 +5788,45 @@ static int bnxt_setup_int_mode(struct bnxt *bp)
#ifdef CONFIG_RFS_ACCEL
static unsigned int bnxt_get_max_func_rss_ctxs(struct bnxt *bp)
{
#if defined(CONFIG_BNXT_SRIOV)
if (BNXT_VF(bp))
return bp->vf.max_rsscos_ctxs;
#endif
return bp->pf.max_rsscos_ctxs;
return bp->hw_resc.max_rsscos_ctxs;
}
static unsigned int bnxt_get_max_func_vnics(struct bnxt *bp)
{
#if defined(CONFIG_BNXT_SRIOV)
if (BNXT_VF(bp))
return bp->vf.max_vnics;
#endif
return bp->pf.max_vnics;
return bp->hw_resc.max_vnics;
}
#endif
unsigned int bnxt_get_max_func_stat_ctxs(struct bnxt *bp)
{
#if defined(CONFIG_BNXT_SRIOV)
if (BNXT_VF(bp))
return bp->vf.max_stat_ctxs;
#endif
return bp->pf.max_stat_ctxs;
return bp->hw_resc.max_stat_ctxs;
}
void bnxt_set_max_func_stat_ctxs(struct bnxt *bp, unsigned int max)
{
#if defined(CONFIG_BNXT_SRIOV)
if (BNXT_VF(bp))
bp->vf.max_stat_ctxs = max;
else
#endif
bp->pf.max_stat_ctxs = max;
bp->hw_resc.max_stat_ctxs = max;
}
unsigned int bnxt_get_max_func_cp_rings(struct bnxt *bp)
{
#if defined(CONFIG_BNXT_SRIOV)
if (BNXT_VF(bp))
return bp->vf.max_cp_rings;
#endif
return bp->pf.max_cp_rings;
return bp->hw_resc.max_cp_rings;
}
void bnxt_set_max_func_cp_rings(struct bnxt *bp, unsigned int max)
{
#if defined(CONFIG_BNXT_SRIOV)
if (BNXT_VF(bp))
bp->vf.max_cp_rings = max;
else
#endif
bp->pf.max_cp_rings = max;
bp->hw_resc.max_cp_rings = max;
}
static unsigned int bnxt_get_max_func_irqs(struct bnxt *bp)
{
#if defined(CONFIG_BNXT_SRIOV)
if (BNXT_VF(bp))
return min_t(unsigned int, bp->vf.max_irqs,
bp->vf.max_cp_rings);
#endif
return min_t(unsigned int, bp->pf.max_irqs, bp->pf.max_cp_rings);
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
return min_t(unsigned int, hw_resc->max_irqs, hw_resc->max_cp_rings);
}
void bnxt_set_max_func_irqs(struct bnxt *bp, unsigned int max_irqs)
{
#if defined(CONFIG_BNXT_SRIOV)
if (BNXT_VF(bp))
bp->vf.max_irqs = max_irqs;
else
#endif
bp->pf.max_irqs = max_irqs;
bp->hw_resc.max_irqs = max_irqs;
}
static int bnxt_init_msix(struct bnxt *bp)
@ -5626,6 +5927,36 @@ static void bnxt_clear_int_mode(struct bnxt *bp)
bp->flags &= ~BNXT_FLAG_USING_MSIX;
}
static int bnxt_reserve_rings(struct bnxt *bp)
{
int orig_cp = bp->hw_resc.resv_cp_rings;
int tcs = netdev_get_num_tc(bp->dev);
int rc;
if (!bnxt_need_reserve_rings(bp))
return 0;
rc = __bnxt_reserve_rings(bp);
if (rc) {
netdev_err(bp->dev, "ring reservation failure rc: %d\n", rc);
return rc;
}
if ((bp->flags & BNXT_FLAG_NEW_RM) && bp->cp_nr_rings > orig_cp) {
bnxt_clear_int_mode(bp);
rc = bnxt_init_int_mode(bp);
if (rc)
return rc;
}
if (tcs && (bp->tx_nr_rings_per_tc * tcs != bp->tx_nr_rings)) {
netdev_err(bp->dev, "tx ring reservation failure\n");
netdev_reset_tc(bp->dev);
bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
return -ENOMEM;
}
bp->num_stat_ctxs = bp->cp_nr_rings;
return 0;
}
static void bnxt_free_irq(struct bnxt *bp)
{
struct bnxt_irq *irq;
@ -6376,6 +6707,10 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
bnxt_preset_reg_win(bp);
netif_carrier_off(bp->dev);
if (irq_re_init) {
rc = bnxt_reserve_rings(bp);
if (rc)
return rc;
rc = bnxt_setup_int_mode(bp);
if (rc) {
netdev_err(bp->dev, "bnxt_setup_int_mode err: %x\n",
@ -6511,23 +6846,13 @@ static bool bnxt_drv_busy(struct bnxt *bp)
test_bit(BNXT_STATE_READ_STATS, &bp->state));
}
int bnxt_close_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
static void __bnxt_close_nic(struct bnxt *bp, bool irq_re_init,
bool link_re_init)
{
int rc = 0;
#ifdef CONFIG_BNXT_SRIOV
if (bp->sriov_cfg) {
rc = wait_event_interruptible_timeout(bp->sriov_cfg_wait,
!bp->sriov_cfg,
BNXT_SRIOV_CFG_WAIT_TMO);
if (rc)
netdev_warn(bp->dev, "timeout waiting for SRIOV config operation to complete!\n");
}
/* Close the VF-reps before closing PF */
if (BNXT_PF(bp))
bnxt_vf_reps_close(bp);
#endif
/* Change device state to avoid TX queue wake up's */
bnxt_tx_disable(bp);
@ -6550,6 +6875,22 @@ int bnxt_close_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
bnxt_del_napi(bp);
}
bnxt_free_mem(bp, irq_re_init);
}
int bnxt_close_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
{
int rc = 0;
#ifdef CONFIG_BNXT_SRIOV
if (bp->sriov_cfg) {
rc = wait_event_interruptible_timeout(bp->sriov_cfg_wait,
!bp->sriov_cfg,
BNXT_SRIOV_CFG_WAIT_TMO);
if (rc)
netdev_warn(bp->dev, "timeout waiting for SRIOV config operation to complete!\n");
}
#endif
__bnxt_close_nic(bp, irq_re_init, link_re_init);
return rc;
}
@ -6829,13 +7170,26 @@ static bool bnxt_rfs_capable(struct bnxt *bp)
if (bp->flags & BNXT_FLAG_NEW_RSS_CAP)
max_rss_ctxs = max_vnics;
if (vnics > max_vnics || vnics > max_rss_ctxs) {
netdev_warn(bp->dev,
"Not enough resources to support NTUPLE filters, enough resources for up to %d rx rings\n",
min(max_rss_ctxs - 1, max_vnics - 1));
if (bp->rx_nr_rings > 1)
netdev_warn(bp->dev,
"Not enough resources to support NTUPLE filters, enough resources for up to %d rx rings\n",
min(max_rss_ctxs - 1, max_vnics - 1));
return false;
}
return true;
if (!(bp->flags & BNXT_FLAG_NEW_RM))
return true;
if (vnics == bp->hw_resc.resv_vnics)
return true;
bnxt_hwrm_reserve_rings(bp, 0, 0, 0, 0, vnics);
if (vnics <= bp->hw_resc.resv_vnics)
return true;
netdev_warn(bp->dev, "Unable to reserve resources to support NTUPLE filters.\n");
bnxt_hwrm_reserve_rings(bp, 0, 0, 0, 0, 1);
return false;
#else
return false;
#endif
@ -7170,7 +7524,8 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
{
int max_rx, max_tx, tx_sets = 1;
int tx_rings_needed;
int rc;
int rx_rings = rx;
int cp, rc;
if (tcs)
tx_sets = tcs;
@ -7186,7 +7541,10 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
if (max_tx < tx_rings_needed)
return -ENOMEM;
return bnxt_hwrm_check_tx_rings(bp, tx_rings_needed);
if (bp->flags & BNXT_FLAG_AGG_RINGS)
rx_rings <<= 1;
cp = sh ? max_t(int, tx_rings_needed, rx) : tx_rings_needed + rx;
return bnxt_hwrm_check_rings(bp, tx_rings_needed, rx_rings, rx, cp);
}
static void bnxt_unmap_bars(struct bnxt *bp, struct pci_dev *pdev)
@ -7791,12 +8149,8 @@ int bnxt_port_attr_get(struct bnxt *bp, struct switchdev_attr *attr)
switch (attr->id) {
case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
/* In SRIOV each PF-pool (PF + child VFs) serves as a
* switching domain, the PF's perm mac-addr can be used
* as the unique parent-id
*/
attr->u.ppid.id_len = ETH_ALEN;
ether_addr_copy(attr->u.ppid.id, bp->pf.mac_addr);
attr->u.ppid.id_len = sizeof(bp->switch_id);
memcpy(attr->u.ppid.id, bp->switch_id, attr->u.ppid.id_len);
break;
default:
return -EOPNOTSUPP;
@ -7941,24 +8295,14 @@ static int bnxt_get_max_irq(struct pci_dev *pdev)
static void _bnxt_get_max_rings(struct bnxt *bp, int *max_rx, int *max_tx,
int *max_cp)
{
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
int max_ring_grps = 0;
#ifdef CONFIG_BNXT_SRIOV
if (!BNXT_PF(bp)) {
*max_tx = bp->vf.max_tx_rings;
*max_rx = bp->vf.max_rx_rings;
*max_cp = min_t(int, bp->vf.max_irqs, bp->vf.max_cp_rings);
*max_cp = min_t(int, *max_cp, bp->vf.max_stat_ctxs);
max_ring_grps = bp->vf.max_hw_ring_grps;
} else
#endif
{
*max_tx = bp->pf.max_tx_rings;
*max_rx = bp->pf.max_rx_rings;
*max_cp = min_t(int, bp->pf.max_irqs, bp->pf.max_cp_rings);
*max_cp = min_t(int, *max_cp, bp->pf.max_stat_ctxs);
max_ring_grps = bp->pf.max_hw_ring_grps;
}
*max_tx = hw_resc->max_tx_rings;
*max_rx = hw_resc->max_rx_rings;
*max_cp = min_t(int, hw_resc->max_irqs, hw_resc->max_cp_rings);
*max_cp = min_t(int, *max_cp, hw_resc->max_stat_ctxs);
max_ring_grps = hw_resc->max_hw_ring_grps;
if (BNXT_CHIP_TYPE_NITRO_A0(bp) && BNXT_PF(bp)) {
*max_cp -= 1;
*max_rx -= 2;
@ -8023,6 +8367,17 @@ static int bnxt_get_dflt_rings(struct bnxt *bp, int *max_rx, int *max_tx,
return rc;
}
/* In initial default shared ring setting, each shared ring must have a
* RX/TX ring pair.
*/
static void bnxt_trim_dflt_sh_rings(struct bnxt *bp)
{
bp->cp_nr_rings = min_t(int, bp->tx_nr_rings_per_tc, bp->rx_nr_rings);
bp->rx_nr_rings = bp->cp_nr_rings;
bp->tx_nr_rings_per_tc = bp->cp_nr_rings;
bp->tx_nr_rings = bp->tx_nr_rings_per_tc;
}
static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
{
int dflt_rings, max_rx_rings, max_tx_rings, rc;
@ -8038,14 +8393,26 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
return rc;
bp->rx_nr_rings = min_t(int, dflt_rings, max_rx_rings);
bp->tx_nr_rings_per_tc = min_t(int, dflt_rings, max_tx_rings);
if (sh)
bnxt_trim_dflt_sh_rings(bp);
else
bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings;
bp->tx_nr_rings = bp->tx_nr_rings_per_tc;
rc = bnxt_hwrm_reserve_tx_rings(bp, &bp->tx_nr_rings_per_tc);
rc = __bnxt_reserve_rings(bp);
if (rc)
netdev_warn(bp->dev, "Unable to reserve tx rings\n");
bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
if (sh)
bnxt_trim_dflt_sh_rings(bp);
bp->tx_nr_rings = bp->tx_nr_rings_per_tc;
bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) :
bp->tx_nr_rings + bp->rx_nr_rings;
/* Rings may have been trimmed, re-reserve the trimmed rings. */
if (bnxt_need_reserve_rings(bp)) {
rc = __bnxt_reserve_rings(bp);
if (rc)
netdev_warn(bp->dev, "2nd rings reservation failed.\n");
bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
}
bp->num_stat_ctxs = bp->cp_nr_rings;
if (BNXT_CHIP_TYPE_NITRO_A0(bp)) {
bp->rx_nr_rings++;
@ -8054,11 +8421,23 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
return rc;
}
void bnxt_restore_pf_fw_resources(struct bnxt *bp)
int bnxt_restore_pf_fw_resources(struct bnxt *bp)
{
int rc;
ASSERT_RTNL();
if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP))
return 0;
bnxt_hwrm_func_qcaps(bp);
bnxt_subtract_ulp_resources(bp, BNXT_ROCE_ULP);
__bnxt_close_nic(bp, true, false);
bnxt_clear_int_mode(bp);
rc = bnxt_init_int_mode(bp);
if (rc)
dev_close(bp->dev);
else
rc = bnxt_open_nic(bp, true, false);
return rc;
}
static int bnxt_init_mac_addr(struct bnxt *bp)
@ -8072,7 +8451,7 @@ static int bnxt_init_mac_addr(struct bnxt *bp)
struct bnxt_vf_info *vf = &bp->vf;
if (is_valid_ether_addr(vf->mac_addr)) {
/* overwrite netdev dev_adr with admin VF MAC */
/* overwrite netdev dev_addr with admin VF MAC */
memcpy(bp->dev->dev_addr, vf->mac_addr, ETH_ALEN);
} else {
eth_hw_addr_random(bp->dev);
@ -8284,6 +8663,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
else
device_set_wakeup_capable(&pdev->dev, false);
bnxt_hwrm_set_cache_line_size(bp, cache_line_size());
if (BNXT_PF(bp)) {
if (!bnxt_pf_wq) {
bnxt_pf_wq =

View File

@ -1,7 +1,7 @@
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2016 Broadcom Corporation
* Copyright (c) 2016-2017 Broadcom Limited
* Copyright (c) 2016-2018 Broadcom Limited
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -12,10 +12,10 @@
#define BNXT_H
#define DRV_MODULE_NAME "bnxt_en"
#define DRV_MODULE_VERSION "1.8.0"
#define DRV_MODULE_VERSION "1.9.0"
#define DRV_VER_MAJ 1
#define DRV_VER_MIN 8
#define DRV_VER_MIN 9
#define DRV_VER_UPD 0
#include <linux/interrupt.h>
@ -776,19 +776,38 @@ struct bnxt_vnic_info {
#define BNXT_VNIC_RFS_NEW_RSS_FLAG 0x10
};
struct bnxt_hw_resc {
u16 min_rsscos_ctxs;
u16 max_rsscos_ctxs;
u16 min_cp_rings;
u16 max_cp_rings;
u16 resv_cp_rings;
u16 min_tx_rings;
u16 max_tx_rings;
u16 resv_tx_rings;
u16 min_rx_rings;
u16 max_rx_rings;
u16 resv_rx_rings;
u16 min_hw_ring_grps;
u16 max_hw_ring_grps;
u16 resv_hw_ring_grps;
u16 min_l2_ctxs;
u16 max_l2_ctxs;
u16 min_vnics;
u16 max_vnics;
u16 resv_vnics;
u16 min_stat_ctxs;
u16 max_stat_ctxs;
u16 max_irqs;
};
#if defined(CONFIG_BNXT_SRIOV)
struct bnxt_vf_info {
u16 fw_fid;
u8 mac_addr[ETH_ALEN];
u16 max_rsscos_ctxs;
u16 max_cp_rings;
u16 max_tx_rings;
u16 max_rx_rings;
u16 max_hw_ring_grps;
u16 max_l2_ctxs;
u16 max_irqs;
u16 max_vnics;
u16 max_stat_ctxs;
u8 mac_addr[ETH_ALEN]; /* PF assigned MAC Address */
u8 vf_mac_addr[ETH_ALEN]; /* VF assigned MAC address, only
* stored by PF.
*/
u16 vlan;
u32 flags;
#define BNXT_VF_QOS 0x1
@ -809,15 +828,6 @@ struct bnxt_pf_info {
u16 fw_fid;
u16 port_id;
u8 mac_addr[ETH_ALEN];
u16 max_rsscos_ctxs;
u16 max_cp_rings;
u16 max_tx_rings; /* HW assigned max tx rings for this PF */
u16 max_rx_rings; /* HW assigned max rx rings for this PF */
u16 max_hw_ring_grps;
u16 max_irqs;
u16 max_l2_ctxs;
u16 max_vnics;
u16 max_stat_ctxs;
u32 first_vf_id;
u16 active_vfs;
u16 max_vfs;
@ -829,6 +839,9 @@ struct bnxt_pf_info {
u32 max_rx_wm_flows;
unsigned long *vf_event_bmap;
u16 hwrm_cmd_req_pages;
u8 vf_resv_strategy;
#define BNXT_VF_RESV_STRATEGY_MAXIMAL 0
#define BNXT_VF_RESV_STRATEGY_MINIMAL 1
void *hwrm_cmd_req_addr[4];
dma_addr_t hwrm_cmd_req_dma_addr[4];
struct bnxt_vf_info *vf;
@ -1137,6 +1150,7 @@ struct bnxt {
#define BNXT_FLAG_FW_DCBX_AGENT 0x800000
#define BNXT_FLAG_CHIP_NITRO_A0 0x1000000
#define BNXT_FLAG_DIM 0x2000000
#define BNXT_FLAG_NEW_RM 0x8000000
#define BNXT_FLAG_ALL_CONFIG_FEATS (BNXT_FLAG_TPA | \
BNXT_FLAG_RFS | \
@ -1196,7 +1210,6 @@ struct bnxt {
int tx_nr_rings;
int tx_nr_rings_per_tc;
int tx_nr_rings_xdp;
int tx_reserved_rings;
int tx_wake_thresh;
int tx_push_thresh;
@ -1308,6 +1321,7 @@ struct bnxt {
#define BNXT_LINK_SPEED_CHNG_SP_EVENT 14
#define BNXT_FLOW_STATS_SP_EVENT 15
struct bnxt_hw_resc hw_resc;
struct bnxt_pf_info pf;
#ifdef CONFIG_BNXT_SRIOV
int nr_vfs;
@ -1357,6 +1371,7 @@ struct bnxt {
enum devlink_eswitch_mode eswitch_mode;
struct bnxt_vf_rep **vf_reps; /* array of vf-rep ptrs */
u16 *cfa_code_map; /* cfa_code -> vf_idx map */
u8 switch_id[8];
struct bnxt_tc_info *tc_info;
};
@ -1432,7 +1447,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
int tx_xdp);
int bnxt_setup_mq_tc(struct net_device *dev, u8 tc);
int bnxt_get_max_rings(struct bnxt *, int *, int *, bool);
void bnxt_restore_pf_fw_resources(struct bnxt *bp);
int bnxt_restore_pf_fw_resources(struct bnxt *bp);
int bnxt_port_attr_get(struct bnxt *bp, struct switchdev_attr *attr);
void bnxt_dim_work(struct work_struct *work);
int bnxt_hwrm_set_ring_coal(struct bnxt *bp, struct bnxt_napi *bnapi);

File diff suppressed because it is too large Load Diff

View File

@ -135,7 +135,10 @@ int bnxt_get_vf_config(struct net_device *dev, int vf_id,
ivi->vf = vf_id;
vf = &bp->pf.vf[vf_id];
memcpy(&ivi->mac, vf->mac_addr, ETH_ALEN);
if (is_valid_ether_addr(vf->mac_addr))
memcpy(&ivi->mac, vf->mac_addr, ETH_ALEN);
else
memcpy(&ivi->mac, vf->vf_mac_addr, ETH_ALEN);
ivi->max_tx_rate = vf->max_tx_rate;
ivi->min_tx_rate = vf->min_tx_rate;
ivi->vlan = vf->vlan;
@ -416,29 +419,126 @@ static int bnxt_hwrm_func_buf_rgtr(struct bnxt *bp)
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
/* only call by PF to reserve resources for VF */
/* Only called by PF to reserve resources for VFs, returns actual number of
* VFs configured, or < 0 on error.
*/
static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs)
{
struct hwrm_func_vf_resource_cfg_input req = {0};
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
u16 vf_tx_rings, vf_rx_rings, vf_cp_rings;
u16 vf_stat_ctx, vf_vnics, vf_ring_grps;
struct bnxt_pf_info *pf = &bp->pf;
int i, rc = 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_RESOURCE_CFG, -1, -1);
vf_cp_rings = hw_resc->max_cp_rings - bp->cp_nr_rings;
vf_stat_ctx = hw_resc->max_stat_ctxs - bp->num_stat_ctxs;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
vf_rx_rings = hw_resc->max_rx_rings - bp->rx_nr_rings * 2;
else
vf_rx_rings = hw_resc->max_rx_rings - bp->rx_nr_rings;
vf_ring_grps = hw_resc->max_hw_ring_grps - bp->rx_nr_rings;
vf_tx_rings = hw_resc->max_tx_rings - bp->tx_nr_rings;
vf_vnics = hw_resc->max_vnics - bp->nr_vnics;
vf_vnics = min_t(u16, vf_vnics, vf_rx_rings);
req.min_rsscos_ctx = cpu_to_le16(1);
req.max_rsscos_ctx = cpu_to_le16(1);
if (pf->vf_resv_strategy == BNXT_VF_RESV_STRATEGY_MINIMAL) {
req.min_cmpl_rings = cpu_to_le16(1);
req.min_tx_rings = cpu_to_le16(1);
req.min_rx_rings = cpu_to_le16(1);
req.min_l2_ctxs = cpu_to_le16(1);
req.min_vnics = cpu_to_le16(1);
req.min_stat_ctx = cpu_to_le16(1);
req.min_hw_ring_grps = cpu_to_le16(1);
} else {
vf_cp_rings /= num_vfs;
vf_tx_rings /= num_vfs;
vf_rx_rings /= num_vfs;
vf_vnics /= num_vfs;
vf_stat_ctx /= num_vfs;
vf_ring_grps /= num_vfs;
req.min_cmpl_rings = cpu_to_le16(vf_cp_rings);
req.min_tx_rings = cpu_to_le16(vf_tx_rings);
req.min_rx_rings = cpu_to_le16(vf_rx_rings);
req.min_l2_ctxs = cpu_to_le16(4);
req.min_vnics = cpu_to_le16(vf_vnics);
req.min_stat_ctx = cpu_to_le16(vf_stat_ctx);
req.min_hw_ring_grps = cpu_to_le16(vf_ring_grps);
}
req.max_cmpl_rings = cpu_to_le16(vf_cp_rings);
req.max_tx_rings = cpu_to_le16(vf_tx_rings);
req.max_rx_rings = cpu_to_le16(vf_rx_rings);
req.max_l2_ctxs = cpu_to_le16(4);
req.max_vnics = cpu_to_le16(vf_vnics);
req.max_stat_ctx = cpu_to_le16(vf_stat_ctx);
req.max_hw_ring_grps = cpu_to_le16(vf_ring_grps);
mutex_lock(&bp->hwrm_cmd_lock);
for (i = 0; i < num_vfs; i++) {
req.vf_id = cpu_to_le16(pf->first_vf_id + i);
rc = _hwrm_send_message(bp, &req, sizeof(req),
HWRM_CMD_TIMEOUT);
if (rc) {
rc = -ENOMEM;
break;
}
pf->active_vfs = i + 1;
pf->vf[i].fw_fid = pf->first_vf_id + i;
}
mutex_unlock(&bp->hwrm_cmd_lock);
if (pf->active_vfs) {
u16 n = 1;
if (pf->vf_resv_strategy != BNXT_VF_RESV_STRATEGY_MINIMAL)
n = pf->active_vfs;
hw_resc->max_tx_rings -= vf_tx_rings * n;
hw_resc->max_rx_rings -= vf_rx_rings * n;
hw_resc->max_hw_ring_grps -= vf_ring_grps * n;
hw_resc->max_cp_rings -= vf_cp_rings * n;
hw_resc->max_rsscos_ctxs -= pf->active_vfs;
hw_resc->max_stat_ctxs -= vf_stat_ctx * n;
hw_resc->max_vnics -= vf_vnics * n;
rc = pf->active_vfs;
}
return rc;
}
/* Only called by PF to reserve resources for VFs, returns actual number of
* VFs configured, or < 0 on error.
*/
static int bnxt_hwrm_func_cfg(struct bnxt *bp, int num_vfs)
{
u32 rc = 0, mtu, i;
u16 vf_tx_rings, vf_rx_rings, vf_cp_rings, vf_stat_ctx, vf_vnics;
u16 vf_ring_grps;
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
u16 vf_ring_grps, max_stat_ctxs;
struct hwrm_func_cfg_input req = {0};
struct bnxt_pf_info *pf = &bp->pf;
int total_vf_tx_rings = 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
max_stat_ctxs = hw_resc->max_stat_ctxs;
/* Remaining rings are distributed equally amongs VF's for now */
vf_cp_rings = (pf->max_cp_rings - bp->cp_nr_rings) / num_vfs;
vf_stat_ctx = (pf->max_stat_ctxs - bp->num_stat_ctxs) / num_vfs;
vf_cp_rings = (hw_resc->max_cp_rings - bp->cp_nr_rings) / num_vfs;
vf_stat_ctx = (max_stat_ctxs - bp->num_stat_ctxs) / num_vfs;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
vf_rx_rings = (pf->max_rx_rings - bp->rx_nr_rings * 2) /
vf_rx_rings = (hw_resc->max_rx_rings - bp->rx_nr_rings * 2) /
num_vfs;
else
vf_rx_rings = (pf->max_rx_rings - bp->rx_nr_rings) / num_vfs;
vf_ring_grps = (bp->pf.max_hw_ring_grps - bp->rx_nr_rings) / num_vfs;
vf_tx_rings = (pf->max_tx_rings - bp->tx_nr_rings) / num_vfs;
vf_vnics = (pf->max_vnics - bp->nr_vnics) / num_vfs;
vf_rx_rings = (hw_resc->max_rx_rings - bp->rx_nr_rings) /
num_vfs;
vf_ring_grps = (hw_resc->max_hw_ring_grps - bp->rx_nr_rings) / num_vfs;
vf_tx_rings = (hw_resc->max_tx_rings - bp->tx_nr_rings) / num_vfs;
vf_vnics = (hw_resc->max_vnics - bp->nr_vnics) / num_vfs;
vf_vnics = min_t(u16, vf_vnics, vf_rx_rings);
req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_MTU |
@ -485,22 +585,34 @@ static int bnxt_hwrm_func_cfg(struct bnxt *bp, int num_vfs)
total_vf_tx_rings += vf_tx_rsvd;
}
mutex_unlock(&bp->hwrm_cmd_lock);
if (!rc) {
pf->max_tx_rings -= total_vf_tx_rings;
pf->max_rx_rings -= vf_rx_rings * num_vfs;
pf->max_hw_ring_grps -= vf_ring_grps * num_vfs;
pf->max_cp_rings -= vf_cp_rings * num_vfs;
pf->max_rsscos_ctxs -= num_vfs;
pf->max_stat_ctxs -= vf_stat_ctx * num_vfs;
pf->max_vnics -= vf_vnics * num_vfs;
if (rc)
rc = -ENOMEM;
if (pf->active_vfs) {
hw_resc->max_tx_rings -= total_vf_tx_rings;
hw_resc->max_rx_rings -= vf_rx_rings * num_vfs;
hw_resc->max_hw_ring_grps -= vf_ring_grps * num_vfs;
hw_resc->max_cp_rings -= vf_cp_rings * num_vfs;
hw_resc->max_rsscos_ctxs -= num_vfs;
hw_resc->max_stat_ctxs -= vf_stat_ctx * num_vfs;
hw_resc->max_vnics -= vf_vnics * num_vfs;
rc = pf->active_vfs;
}
return rc;
}
static int bnxt_func_cfg(struct bnxt *bp, int num_vfs)
{
if (bp->flags & BNXT_FLAG_NEW_RM)
return bnxt_hwrm_func_vf_resc_cfg(bp, num_vfs);
else
return bnxt_hwrm_func_cfg(bp, num_vfs);
}
static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
{
int rc = 0, vfs_supported;
int min_rx_rings, min_tx_rings, min_rss_ctxs;
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
int tx_ok = 0, rx_ok = 0, rss_ok = 0;
int avail_cp, avail_stat;
@ -510,8 +622,8 @@ static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
*/
vfs_supported = *num_vfs;
avail_cp = bp->pf.max_cp_rings - bp->cp_nr_rings;
avail_stat = bp->pf.max_stat_ctxs - bp->num_stat_ctxs;
avail_cp = hw_resc->max_cp_rings - bp->cp_nr_rings;
avail_stat = hw_resc->max_stat_ctxs - bp->num_stat_ctxs;
avail_cp = min_t(int, avail_cp, avail_stat);
while (vfs_supported) {
@ -520,23 +632,24 @@ static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
min_rss_ctxs = vfs_supported;
if (bp->flags & BNXT_FLAG_AGG_RINGS) {
if (bp->pf.max_rx_rings - bp->rx_nr_rings * 2 >=
if (hw_resc->max_rx_rings - bp->rx_nr_rings * 2 >=
min_rx_rings)
rx_ok = 1;
} else {
if (bp->pf.max_rx_rings - bp->rx_nr_rings >=
if (hw_resc->max_rx_rings - bp->rx_nr_rings >=
min_rx_rings)
rx_ok = 1;
}
if (bp->pf.max_vnics - bp->nr_vnics < min_rx_rings ||
if (hw_resc->max_vnics - bp->nr_vnics < min_rx_rings ||
avail_cp < min_rx_rings)
rx_ok = 0;
if (bp->pf.max_tx_rings - bp->tx_nr_rings >= min_tx_rings &&
if (hw_resc->max_tx_rings - bp->tx_nr_rings >= min_tx_rings &&
avail_cp >= min_tx_rings)
tx_ok = 1;
if (bp->pf.max_rsscos_ctxs - bp->rsscos_nr_ctxs >= min_rss_ctxs)
if (hw_resc->max_rsscos_ctxs - bp->rsscos_nr_ctxs >=
min_rss_ctxs)
rss_ok = 1;
if (tx_ok && rx_ok && rss_ok)
@ -561,9 +674,16 @@ static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
goto err_out1;
/* Reserve resources for VFs */
rc = bnxt_hwrm_func_cfg(bp, *num_vfs);
if (rc)
goto err_out2;
rc = bnxt_func_cfg(bp, *num_vfs);
if (rc != *num_vfs) {
if (rc <= 0) {
netdev_warn(bp->dev, "Unable to reserve resources for SRIOV.\n");
*num_vfs = 0;
goto err_out2;
}
netdev_warn(bp->dev, "Only able to reserve resources for %d VFs.\n", rc);
*num_vfs = rc;
}
/* Register buffers for VFs */
rc = bnxt_hwrm_func_buf_rgtr(bp);
@ -766,17 +886,51 @@ exec_fwd_resp_exit:
return rc;
}
static int bnxt_vf_store_mac(struct bnxt *bp, struct bnxt_vf_info *vf)
{
u32 msg_size = sizeof(struct hwrm_func_vf_cfg_input);
struct hwrm_func_vf_cfg_input *req =
(struct hwrm_func_vf_cfg_input *)vf->hwrm_cmd_req_addr;
/* Only allow VF to set a valid MAC address if the PF assigned MAC
* address is zero
*/
if (req->enables & cpu_to_le32(FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR)) {
if (is_valid_ether_addr(req->dflt_mac_addr) &&
!is_valid_ether_addr(vf->mac_addr)) {
ether_addr_copy(vf->vf_mac_addr, req->dflt_mac_addr);
return bnxt_hwrm_exec_fwd_resp(bp, vf, msg_size);
}
return bnxt_hwrm_fwd_err_resp(bp, vf, msg_size);
}
return bnxt_hwrm_exec_fwd_resp(bp, vf, msg_size);
}
static int bnxt_vf_validate_set_mac(struct bnxt *bp, struct bnxt_vf_info *vf)
{
u32 msg_size = sizeof(struct hwrm_cfa_l2_filter_alloc_input);
struct hwrm_cfa_l2_filter_alloc_input *req =
(struct hwrm_cfa_l2_filter_alloc_input *)vf->hwrm_cmd_req_addr;
bool mac_ok = false;
if (!is_valid_ether_addr(vf->mac_addr) ||
ether_addr_equal((const u8 *)req->l2_addr, vf->mac_addr))
/* VF MAC address must first match PF MAC address, if it is valid.
* Otherwise, it must match the VF MAC address if firmware spec >=
* 1.2.2
*/
if (is_valid_ether_addr(vf->mac_addr)) {
if (ether_addr_equal((const u8 *)req->l2_addr, vf->mac_addr))
mac_ok = true;
} else if (is_valid_ether_addr(vf->vf_mac_addr)) {
if (ether_addr_equal((const u8 *)req->l2_addr, vf->vf_mac_addr))
mac_ok = true;
} else if (bp->hwrm_spec_code < 0x10202) {
mac_ok = true;
} else {
mac_ok = true;
}
if (mac_ok)
return bnxt_hwrm_exec_fwd_resp(bp, vf, msg_size);
else
return bnxt_hwrm_fwd_err_resp(bp, vf, msg_size);
return bnxt_hwrm_fwd_err_resp(bp, vf, msg_size);
}
static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf)
@ -838,6 +992,9 @@ static int bnxt_vf_req_validate_snd(struct bnxt *bp, struct bnxt_vf_info *vf)
u32 req_type = le16_to_cpu(encap_req->req_type);
switch (req_type) {
case HWRM_FUNC_VF_CFG:
rc = bnxt_vf_store_mac(bp, vf);
break;
case HWRM_CFA_L2_FILTER_ALLOC:
rc = bnxt_vf_validate_set_mac(bp, vf);
break;

View File

@ -43,7 +43,7 @@ static u16 bnxt_flow_get_dst_fid(struct bnxt *pf_bp, struct net_device *dev)
}
/* Is dev a VF-rep? */
if (dev != pf_bp->dev)
if (bnxt_dev_is_vf_rep(dev))
return bnxt_vf_rep_get_fid(dev);
bp = netdev_priv(dev);

View File

@ -241,6 +241,11 @@ static const struct net_device_ops bnxt_vf_rep_netdev_ops = {
.ndo_get_phys_port_name = bnxt_vf_rep_get_phys_port_name
};
bool bnxt_dev_is_vf_rep(struct net_device *dev)
{
return dev->netdev_ops == &bnxt_vf_rep_netdev_ops;
}
/* Called when the parent PF interface is closed:
* As the mode transition from SWITCHDEV to LEGACY
* happens under the rtnl_lock() this routine is safe
@ -376,6 +381,26 @@ static void bnxt_vf_rep_netdev_init(struct bnxt *bp, struct bnxt_vf_rep *vf_rep,
ether_addr_copy(dev->dev_addr, dev->perm_addr);
}
static int bnxt_pcie_dsn_get(struct bnxt *bp, u8 dsn[])
{
struct pci_dev *pdev = bp->pdev;
int pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DSN);
u32 dw;
if (!pos) {
netdev_info(bp->dev, "Unable do read adapter's DSN");
return -EOPNOTSUPP;
}
/* DSN (two dw) is at an offset of 4 from the cap pos */
pos += 4;
pci_read_config_dword(pdev, pos, &dw);
put_unaligned_le32(dw, &dsn[0]);
pci_read_config_dword(pdev, pos + 4, &dw);
put_unaligned_le32(dw, &dsn[4]);
return 0;
}
static int bnxt_vf_reps_create(struct bnxt *bp)
{
u16 *cfa_code_map = NULL, num_vfs = pci_num_vf(bp->pdev);
@ -440,6 +465,11 @@ static int bnxt_vf_reps_create(struct bnxt *bp)
}
}
/* Read the adapter's DSN to use as the eswitch switch_id */
rc = bnxt_pcie_dsn_get(bp, bp->switch_id);
if (rc)
goto err;
/* publish cfa_code_map only after all VF-reps have been initialized */
bp->cfa_code_map = cfa_code_map;
bp->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;

View File

@ -28,6 +28,7 @@ static inline u16 bnxt_vf_rep_get_fid(struct net_device *dev)
return bp->pf.vf[vf_rep->vf_idx].fw_fid;
}
bool bnxt_dev_is_vf_rep(struct net_device *dev);
int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode);
int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode);
@ -54,5 +55,10 @@ static inline u16 bnxt_vf_rep_get_fid(struct net_device *dev)
{
return 0;
}
static inline bool bnxt_dev_is_vf_rep(struct net_device *dev)
{
return false;
}
#endif /* CONFIG_BNXT_SRIOV */
#endif /* BNXT_VFR_H */