Skip to content

Commit

Permalink
bnx2x: Support of PF driver of a VF acquire request
Browse files Browse the repository at this point in the history
When a VF is probed by the VF driver, the VF driver sends an
'acquire' request over the VF <-> PF channel for the resources
it needs to operate (interrupts, queues, etc).
The PF driver either ratifies the request and allocates the resources,
responds with the maximum values it will allow the VF to acquire,
or fails the request entirely if there is a problem.

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 fd1fc79 commit 8ca5e17
Show file tree
Hide file tree
Showing 6 changed files with 476 additions and 11 deletions.
28 changes: 28 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,34 @@ static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to)
to_fp->txdata_ptr[0] = &bp->bnx2x_txq[new_txdata_index];
}

/**
* bnx2x_fill_fw_str - Fill buffer with FW version string.
*
* @bp: driver handle
* @buf: character buffer to fill with the fw name
* @buf_len: length of the above buffer
*
*/
void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len)
{
if (IS_PF(bp)) {
u8 phy_fw_ver[PHY_FW_VER_LEN];

phy_fw_ver[0] = '\0';
bnx2x_get_ext_phy_fw_version(&bp->link_params,
phy_fw_ver, PHY_FW_VER_LEN);
strlcpy(buf, bp->fw_ver, buf_len);
snprintf(buf + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
"bc %d.%d.%d%s%s",
(bp->common.bc_ver & 0xff0000) >> 16,
(bp->common.bc_ver & 0xff00) >> 8,
(bp->common.bc_ver & 0xff),
((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
} else {
strlcpy(buf, bp->acquire_resp.pfdev_info.fw_ver, buf_len);
}
}

int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */

/* free skb in the packet ring at pos idx
Expand Down
9 changes: 9 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
Original file line number Diff line number Diff line change
Expand Up @@ -1401,4 +1401,13 @@ static inline bool bnx2x_is_valid_ether_addr(struct bnx2x *bp, u8 *addr)
return false;
}

/**
* bnx2x_fill_fw_str - Fill buffer with FW version string.
*
* @bp: driver handle
* @buf: character buffer to fill with the fw name
* @buf_len: length of the above buffer
*
*/
void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len);
#endif /* BNX2X_CMN_H */
13 changes: 2 additions & 11 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -817,21 +817,12 @@ static void bnx2x_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct bnx2x *bp = netdev_priv(dev);
u8 phy_fw_ver[PHY_FW_VER_LEN];

strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));

phy_fw_ver[0] = '\0';
bnx2x_get_ext_phy_fw_version(&bp->link_params,
phy_fw_ver, PHY_FW_VER_LEN);
strlcpy(info->fw_version, bp->fw_ver, sizeof(info->fw_version));
snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
"bc %d.%d.%d%s%s",
(bp->common.bc_ver & 0xff0000) >> 16,
(bp->common.bc_ver & 0xff00) >> 8,
(bp->common.bc_ver & 0xff),
((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
bnx2x_fill_fw_str(bp, info->fw_version, sizeof(info->fw_version));

strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
info->n_stats = BNX2X_NUM_STATS;
info->testinfo_len = BNX2X_NUM_TESTS(bp);
Expand Down
199 changes: 199 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,63 @@ int bnx2x_iov_alloc_mem(struct bnx2x *bp)
return -ENOMEM;
}

static void bnx2x_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct bnx2x_vf_queue *q)
{
u8 cl_id = vfq_cl_id(vf, q);
u8 func_id = FW_VF_HANDLE(vf->abs_vfid);
unsigned long q_type = 0;

set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type);
set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type);

/* Queue State object */
bnx2x_init_queue_obj(bp, &q->sp_obj,
cl_id, &q->cid, 1, func_id,
bnx2x_vf_sp(bp, vf, q_data),
bnx2x_vf_sp_map(bp, vf, q_data),
q_type);

DP(BNX2X_MSG_IOV,
"initialized vf %d's queue object. func id set to %d\n",
vf->abs_vfid, q->sp_obj.func_id);

/* mac/vlan objects are per queue, but only those
* that belong to the leading queue are initialized
*/
if (vfq_is_leading(q)) {
/* mac */
bnx2x_init_mac_obj(bp, &q->mac_obj,
cl_id, q->cid, func_id,
bnx2x_vf_sp(bp, vf, mac_rdata),
bnx2x_vf_sp_map(bp, vf, mac_rdata),
BNX2X_FILTER_MAC_PENDING,
&vf->filter_state,
BNX2X_OBJ_TYPE_RX_TX,
&bp->macs_pool);
/* vlan */
bnx2x_init_vlan_obj(bp, &q->vlan_obj,
cl_id, q->cid, func_id,
bnx2x_vf_sp(bp, vf, vlan_rdata),
bnx2x_vf_sp_map(bp, vf, vlan_rdata),
BNX2X_FILTER_VLAN_PENDING,
&vf->filter_state,
BNX2X_OBJ_TYPE_RX_TX,
&bp->vlans_pool);

/* mcast */
bnx2x_init_mcast_obj(bp, &vf->mcast_obj, cl_id,
q->cid, func_id, func_id,
bnx2x_vf_sp(bp, vf, mcast_rdata),
bnx2x_vf_sp_map(bp, vf, mcast_rdata),
BNX2X_FILTER_MCAST_PENDING,
&vf->filter_state,
BNX2X_OBJ_TYPE_RX_TX);

vf->leading_rss = cl_id;
}
}

/* called by bnx2x_nic_load */
int bnx2x_iov_nic_init(struct bnx2x *bp)
{
Expand Down Expand Up @@ -940,3 +997,145 @@ void bnx2x_iov_sp_task(struct bnx2x *bp)
}
}
}

u8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf)
{
return min_t(u8, min_t(u8, vf_sb_count(vf), BNX2X_CIDS_PER_VF),
BNX2X_VF_MAX_QUEUES);
}

static
int bnx2x_vf_chk_avail_resc(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct vf_pf_resc_request *req_resc)
{
u8 rxq_cnt = vf_rxq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf);
u8 txq_cnt = vf_txq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf);

return ((req_resc->num_rxqs <= rxq_cnt) &&
(req_resc->num_txqs <= txq_cnt) &&
(req_resc->num_sbs <= vf_sb_count(vf)) &&
(req_resc->num_mac_filters <= vf_mac_rules_cnt(vf)) &&
(req_resc->num_vlan_filters <= vf_vlan_rules_cnt(vf)));
}

/* CORE VF API */
int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct vf_pf_resc_request *resc)
{
int base_vf_cid = (BP_VFDB(bp)->sriov.first_vf_in_pf + vf->index) *
BNX2X_CIDS_PER_VF;

union cdu_context *base_cxt = (union cdu_context *)
BP_VF_CXT_PAGE(bp, base_vf_cid/ILT_PAGE_CIDS)->addr +
(base_vf_cid & (ILT_PAGE_CIDS-1));
int i;

/* if state is 'acquired' the VF was not released or FLR'd, in
* this case the returned resources match the acquired already
* acquired resources. Verify that the requested numbers do
* not exceed the already acquired numbers.
*/
if (vf->state == VF_ACQUIRED) {
DP(BNX2X_MSG_IOV, "VF[%d] Trying to re-acquire resources (VF was not released or FLR'd)\n",
vf->abs_vfid);

if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
BNX2X_ERR("VF[%d] When re-acquiring resources, requested numbers must be <= then previously acquired numbers\n",
vf->abs_vfid);
return -EINVAL;
}
return 0;
}

/* Otherwise vf state must be 'free' or 'reset' */
if (vf->state != VF_FREE && vf->state != VF_RESET) {
BNX2X_ERR("VF[%d] Can not acquire a VF with state %d\n",
vf->abs_vfid, vf->state);
return -EINVAL;
}

/* static allocation:
* the global maximum number are fixed per VF. fail the request if
* requested number exceed these globals
*/
if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
DP(BNX2X_MSG_IOV,
"cannot fulfill vf resource request. Placing maximal available values in response\n");
/* set the max resource in the vf */
return -ENOMEM;
}

/* Set resources counters - 0 request means max available */
vf_sb_count(vf) = resc->num_sbs;
vf_rxq_count(vf) = resc->num_rxqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
vf_txq_count(vf) = resc->num_txqs ? : bnx2x_vf_max_queue_cnt(bp, vf);
if (resc->num_mac_filters)
vf_mac_rules_cnt(vf) = resc->num_mac_filters;
if (resc->num_vlan_filters)
vf_vlan_rules_cnt(vf) = resc->num_vlan_filters;

DP(BNX2X_MSG_IOV,
"Fulfilling vf request: sb count %d, tx_count %d, rx_count %d, mac_rules_count %d, vlan_rules_count %d\n",
vf_sb_count(vf), vf_rxq_count(vf),
vf_txq_count(vf), vf_mac_rules_cnt(vf),
vf_vlan_rules_cnt(vf));

/* Initialize the queues */
if (!vf->vfqs) {
DP(BNX2X_MSG_IOV, "vf->vfqs was not allocated\n");
return -EINVAL;
}

for_each_vfq(vf, i) {
struct bnx2x_vf_queue *q = vfq_get(vf, i);

if (!q) {
DP(BNX2X_MSG_IOV, "q number %d was not allocated\n", i);
return -EINVAL;
}

q->index = i;
q->cxt = &((base_cxt + i)->eth);
q->cid = BNX2X_FIRST_VF_CID + base_vf_cid + i;

DP(BNX2X_MSG_IOV, "VFQ[%d:%d]: index %d, cid 0x%x, cxt %p\n",
vf->abs_vfid, i, q->index, q->cid, q->cxt);

/* init SP objects */
bnx2x_vfq_init(bp, vf, q);
}
vf->state = VF_ACQUIRED;
return 0;
}

void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
enum channel_tlvs tlv)
{
/* lock the channel */
mutex_lock(&vf->op_mutex);

/* record the locking op */
vf->op_current = tlv;

/* log the lock */
DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel locked by %d\n",
vf->abs_vfid, tlv);
}

void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
enum channel_tlvs expected_tlv)
{
WARN(expected_tlv != vf->op_current,
"lock mismatch: expected %d found %d", expected_tlv,
vf->op_current);

/* lock the channel */
mutex_unlock(&vf->op_mutex);

/* log the unlock */
DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel unlocked by %d\n",
vf->abs_vfid, vf->op_current);

/* record the locking op */
vf->op_current = CHANNEL_TLV_NONE;
}
43 changes: 43 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@
#ifndef BNX2X_SRIOV_H
#define BNX2X_SRIOV_H

#include "bnx2x_vfpf.h"
#include "bnx2x_cmn.h"

/* The bnx2x device structure holds vfdb structure described below.
* The VF array is indexed by the relative vfid.
*/
#define BNX2X_VF_MAX_QUEUES 16
struct bnx2x_sriov {
u32 first_vf_in_pf;

Expand Down Expand Up @@ -257,6 +261,12 @@ struct bnx2x_virtf {
#define for_each_vf(bp, var) \
for ((var) = 0; (var) < BNX2X_NR_VIRTFN(bp); (var)++)

#define for_each_vfq(vf, var) \
for ((var) = 0; (var) < vf_rxq_count(vf); (var)++)

#define for_each_vf_sb(vf, var) \
for ((var) = 0; (var) < vf_sb_count(vf); (var)++)

#define HW_VF_HANDLE(bp, abs_vfid) \
(u16)(BP_ABS_FUNC((bp)) | (1<<3) | ((u16)(abs_vfid) << 4))

Expand All @@ -265,6 +275,13 @@ struct bnx2x_virtf {
#define FW_VF_HANDLE(abs_vfid) \
(abs_vfid + FW_PF_MAX_HANDLE)

/* locking and unlocking the channel mutex */
void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
enum channel_tlvs tlv);

void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
enum channel_tlvs expected_tlv);

/* VF mail box (aka vf-pf channel) */

/* a container for the bi-directional vf<-->pf messages.
Expand Down Expand Up @@ -365,11 +382,32 @@ static inline struct bnx2x_vf_queue *vfq_get(struct bnx2x_virtf *vf, u8 index)
return &(vf->vfqs[index]);
}

static inline bool vfq_is_leading(struct bnx2x_vf_queue *vfq)
{
return (vfq->index == 0);
}

/* FW ids */
static inline u8 vf_igu_sb(struct bnx2x_virtf *vf, u16 sb_idx)
{
return vf->igu_base_id + sb_idx;
}

static inline u8 vf_hc_qzone(struct bnx2x_virtf *vf, u16 sb_idx)
{
return vf_igu_sb(vf, sb_idx);
}

static u8 vfq_cl_id(struct bnx2x_virtf *vf, struct bnx2x_vf_queue *q)
{
return vf->igu_base_id + q->index;
}

static inline u8 vfq_qzone_id(struct bnx2x_virtf *vf, struct bnx2x_vf_queue *q)
{
return vfq_cl_id(vf, q);
}

/* global iov routines */
int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line);
int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param, int num_vfs_param);
Expand All @@ -387,6 +425,10 @@ void bnx2x_iov_sp_task(struct bnx2x *bp);
/* global vf mailbox routines */
void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event);
void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid);
/* acquire */
int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct vf_pf_resc_request *resc);

static inline struct bnx2x_vfop *bnx2x_vfop_cur(struct bnx2x *bp,
struct bnx2x_virtf *vf)
{
Expand All @@ -396,6 +438,7 @@ static inline struct bnx2x_vfop *bnx2x_vfop_cur(struct bnx2x *bp,
}

int bnx2x_vf_idx_by_abs_fid(struct bnx2x *bp, u16 abs_vfid);
u8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf);
/* VF FLR helpers */
int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid);
void bnx2x_vf_enable_access(struct bnx2x *bp, u8 abs_vfid);
Expand Down
Loading

0 comments on commit 8ca5e17

Please sign in to comment.