Skip to content

Commit

Permalink
bnx2x: VF <-> PF channel 'acquire' at vf probe
Browse files Browse the repository at this point in the history
Add the 'acquire' request to VF <-> PF channel and use it at
VF probe. In the acquire request the VF driver lists the resources
it would like to have. In the response the PF either ratifies the
request, or denies it and supplies the maximum values supported.
The VF may then attempt another acquire request.
This patch adds the bnx2x_vfpf.c file which contains the
implementation of the VF to PF hardware channel.

Signed-off-by: Ariel Elior <ariele@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Ariel Elior authored and David S. Miller committed Jan 2, 2013
1 parent 1ab4434 commit be1f1ff
Show file tree
Hide file tree
Showing 7 changed files with 407 additions and 1 deletion.
2 changes: 1 addition & 1 deletion drivers/net/ethernet/broadcom/bnx2x/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

obj-$(CONFIG_BNX2X) += bnx2x.o

bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o bnx2x_sp.o
bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o bnx2x_sp.o bnx2x_vfpf.o
13 changes: 13 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "bnx2x_sp.h"
#include "bnx2x_dcb.h"
#include "bnx2x_stats.h"
#include "bnx2x_vfpf.h"

enum bnx2x_int_mode {
BNX2X_INT_MODE_MSIX,
Expand Down Expand Up @@ -1244,6 +1245,9 @@ struct bnx2x {
struct bnx2x_vf_mbx_msg *vf2pf_mbox;
dma_addr_t vf2pf_mbox_mapping;

/* we set aside a copy of the acquire response */
struct pfvf_acquire_resp_tlv acquire_resp;

struct net_device *dev;
struct pci_dev *pdev;

Expand Down Expand Up @@ -2207,6 +2211,15 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
#define BNX2X_VPD_LEN 128
#define VENDOR_ID_LEN 4

#define VF_ACQUIRE_THRESH 3
#define VF_ACQUIRE_MAC_FILTERS 1
#define VF_ACQUIRE_MC_FILTERS 10

#define GOOD_ME_REG(me_reg) (((me_reg) & ME_REG_VF_VALID) && \
(!((me_reg) & ME_REG_VF_ERR)))
int bnx2x_get_vf_id(struct bnx2x *bp, u32 *vf_id);
int bnx2x_send_msg2pf(struct bnx2x *bp, u8 *done, dma_addr_t msg_mapping);
int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count);
/* Congestion management fairness mode */
#define CMNG_FNS_NONE 0
#define CMNG_FNS_MINMAX 1
Expand Down
185 changes: 185 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -12234,6 +12234,12 @@ static int bnx2x_init_one(struct pci_dev *pdev,
goto init_one_exit;
}

if (IS_VF(bp)) {
rc = bnx2x_vfpf_acquire(bp, tx_count, rx_count);
if (rc)
goto init_one_exit;
}

/* calc qm_cid_count */
bp->qm_cid_count = bnx2x_set_qm_cid_count(bp);
BNX2X_DEV_INFO("qm_cid_count %d\n", bp->qm_cid_count);
Expand Down Expand Up @@ -13157,4 +13163,183 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
return cp;
}

int bnx2x_send_msg2pf(struct bnx2x *bp, u8 *done, dma_addr_t msg_mapping)
{
struct cstorm_vf_zone_data __iomem *zone_data =
REG_ADDR(bp, PXP_VF_ADDR_CSDM_GLOBAL_START);
int tout = 600, interval = 100; /* wait for 60 seconds */

if (*done) {
BNX2X_ERR("done was non zero before message to pf was sent\n");
WARN_ON(true);
return -EINVAL;
}

/* Write message address */
writel(U64_LO(msg_mapping),
&zone_data->non_trigger.vf_pf_channel.msg_addr_lo);
writel(U64_HI(msg_mapping),
&zone_data->non_trigger.vf_pf_channel.msg_addr_hi);

/* make sure the address is written before FW accesses it */
wmb();

/* Trigger the PF FW */
writeb(1, &zone_data->trigger.vf_pf_channel.addr_valid);

/* Wait for PF to complete */
while ((tout >= 0) && (!*done)) {
msleep(interval);
tout -= 1;

/* progress indicator - HV can take its own sweet time in
* answering VFs...
*/
DP_CONT(BNX2X_MSG_IOV, ".");
}

if (!*done) {
BNX2X_ERR("PF response has timed out\n");
return -EAGAIN;
}
DP(BNX2X_MSG_SP, "Got a response from PF\n");
return 0;
}

int bnx2x_get_vf_id(struct bnx2x *bp, u32 *vf_id)
{
u32 me_reg;
int tout = 10, interval = 100; /* Wait for 1 sec */

do {
/* pxp traps vf read of doorbells and returns me reg value */
me_reg = readl(bp->doorbells);
if (GOOD_ME_REG(me_reg))
break;

msleep(interval);

BNX2X_ERR("Invalid ME register value: 0x%08x\n. Is pf driver up?",
me_reg);
} while (tout-- > 0);

if (!GOOD_ME_REG(me_reg)) {
BNX2X_ERR("Invalid ME register value: 0x%08x\n", me_reg);
return -EINVAL;
}

BNX2X_ERR("valid ME register value: 0x%08x\n", me_reg);

*vf_id = (me_reg & ME_REG_VF_NUM_MASK) >> ME_REG_VF_NUM_SHIFT;

return 0;
}

int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
{
int rc = 0, attempts = 0;
struct vfpf_acquire_tlv *req = &bp->vf2pf_mbox->req.acquire;
struct pfvf_acquire_resp_tlv *resp = &bp->vf2pf_mbox->resp.acquire_resp;
u32 vf_id;
bool resources_acquired = false;

/* clear mailbox and prep first tlv */
bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_ACQUIRE, sizeof(*req));

if (bnx2x_get_vf_id(bp, &vf_id))
return -EAGAIN;

req->vfdev_info.vf_id = vf_id;
req->vfdev_info.vf_os = 0;

req->resc_request.num_rxqs = rx_count;
req->resc_request.num_txqs = tx_count;
req->resc_request.num_sbs = bp->igu_sb_cnt;
req->resc_request.num_mac_filters = VF_ACQUIRE_MAC_FILTERS;
req->resc_request.num_mc_filters = VF_ACQUIRE_MC_FILTERS;

/* add list termination tlv */
bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
sizeof(struct channel_list_end_tlv));

/* output tlvs list */
bnx2x_dp_tlv_list(bp, req);

while (!resources_acquired) {
DP(BNX2X_MSG_SP, "attempting to acquire resources\n");

/* send acquire request */
rc = bnx2x_send_msg2pf(bp,
&resp->hdr.status,
bp->vf2pf_mbox_mapping);

/* PF timeout */
if (rc)
return rc;

/* copy acquire response from buffer to bp */
memcpy(&bp->acquire_resp, resp, sizeof(bp->acquire_resp));

attempts++;

/* test whether the PF accepted our request. If not, humble the
* the request and try again.
*/
if (bp->acquire_resp.hdr.status == PFVF_STATUS_SUCCESS) {
DP(BNX2X_MSG_SP, "resources acquired\n");
resources_acquired = true;
} else if (bp->acquire_resp.hdr.status ==
PFVF_STATUS_NO_RESOURCE &&
attempts < VF_ACQUIRE_THRESH) {
DP(BNX2X_MSG_SP,
"PF unwilling to fulfill resource request. Try PF recommended amount\n");

/* humble our request */
req->resc_request.num_txqs =
bp->acquire_resp.resc.num_txqs;
req->resc_request.num_rxqs =
bp->acquire_resp.resc.num_rxqs;
req->resc_request.num_sbs =
bp->acquire_resp.resc.num_sbs;
req->resc_request.num_mac_filters =
bp->acquire_resp.resc.num_mac_filters;
req->resc_request.num_vlan_filters =
bp->acquire_resp.resc.num_vlan_filters;
req->resc_request.num_mc_filters =
bp->acquire_resp.resc.num_mc_filters;

/* Clear response buffer */
memset(&bp->vf2pf_mbox->resp, 0,
sizeof(union pfvf_tlvs));
} else {
/* PF reports error */
BNX2X_ERR("Failed to get the requested amount of resources: %d. Breaking...\n",
bp->acquire_resp.hdr.status);
return -EAGAIN;
}
}

/* get HW info */
bp->common.chip_id |= (bp->acquire_resp.pfdev_info.chip_num & 0xffff);
bp->link_params.chip_id = bp->common.chip_id;
bp->db_size = bp->acquire_resp.pfdev_info.db_size;
bp->common.int_block = INT_BLOCK_IGU;
bp->common.chip_port_mode = CHIP_2_PORT_MODE;
bp->igu_dsb_id = -1;
bp->mf_ov = 0;
bp->mf_mode = 0;
bp->common.flash_size = 0;
bp->flags |=
NO_WOL_FLAG | NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG | NO_FCOE_FLAG;
bp->igu_sb_cnt = 1;
bp->igu_base_sb = bp->acquire_resp.resc.hw_sbs[0].hw_sb_id;
strlcpy(bp->fw_ver, bp->acquire_resp.pfdev_info.fw_ver,
sizeof(bp->fw_ver));

if (is_valid_ether_addr(bp->acquire_resp.resc.current_mac_addr))
memcpy(bp->dev->dev_addr,
bp->acquire_resp.resc.current_mac_addr,
ETH_ALEN);

return 0;
}
6 changes: 6 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -6558,6 +6558,12 @@
#define PXP_VF_ADDR_IGU_SIZE 0x3000
#define PXP_VF_ADDR_IGU_END\
((PXP_VF_ADDR_IGU_START) + (PXP_VF_ADDR_IGU_SIZE) - 1)

#define PXP_VF_ADDR_CSDM_GLOBAL_START 0x7600
#define PXP_VF_ADDR_CSDM_GLOBAL_SIZE (PXP_ADDR_REG_SIZE)
#define PXP_VF_ADDR_CSDM_GLOBAL_END\
((PXP_VF_ADDR_CSDM_GLOBAL_START) + (PXP_VF_ADDR_CSDM_GLOBAL_SIZE) - 1)

#define PXP_VF_ADDR_DB_START 0x7c00
#define PXP_VF_ADDR_DB_SIZE 0x200
#define PXP_VF_ADDR_DB_END\
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,9 @@ struct bnx2x_vf_mbx_msg {
union pfvf_tlvs resp;
};

void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
u16 length);
void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
u16 type, u16 length);
void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list);
#endif /* bnx2x_sriov.h */
80 changes: 80 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/* bnx2x_vfpf.c: Broadcom Everest network driver.
*
* Copyright 2009-2012 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2, available
* at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a
* license other than the GPL, without Broadcom's express prior written
* consent.
*
* Maintained by: Eilon Greenstein <eilong@broadcom.com>
* Written by: Shmulik Ravid <shmulikr@broadcom.com>
* Ariel Elior <ariele@broadcom.com>
*/

#include "bnx2x.h"
#include "bnx2x_sriov.h"

/* place a given tlv on the tlv buffer at a given offset */
void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
u16 length)
{
struct channel_tlv *tl =
(struct channel_tlv *)(tlvs_list + offset);

tl->type = type;
tl->length = length;
}

/* Clear the mailbox and init the header of the first tlv */
void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
u16 type, u16 length)
{
DP(BNX2X_MSG_IOV, "preparing to send %d tlv over vf pf channel\n",
type);

/* Clear mailbox */
memset(bp->vf2pf_mbox, 0, sizeof(struct bnx2x_vf_mbx_msg));

/* init type and length */
bnx2x_add_tlv(bp, &first_tlv->tl, 0, type, length);

/* init first tlv header */
first_tlv->resp_msg_offset = sizeof(bp->vf2pf_mbox->req);
}

/* list the types and lengths of the tlvs on the buffer */
void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list)
{
int i = 1;
struct channel_tlv *tlv = (struct channel_tlv *)tlvs_list;

while (tlv->type != CHANNEL_TLV_LIST_END) {
/* output tlv */
DP(BNX2X_MSG_IOV, "TLV number %d: type %d, length %d\n", i,
tlv->type, tlv->length);

/* advance to next tlv */
tlvs_list += tlv->length;

/* cast general tlv list pointer to channel tlv header*/
tlv = (struct channel_tlv *)tlvs_list;

i++;

/* break condition for this loop */
if (i > MAX_TLVS_IN_LIST) {
WARN(true, "corrupt tlvs");
return;
}
}

/* output last tlv */
DP(BNX2X_MSG_IOV, "TLV number %d: type %d, length %d\n", i,
tlv->type, tlv->length);
}
Loading

0 comments on commit be1f1ff

Please sign in to comment.