Skip to content

Commit

Permalink
bnx2x: Support PF <-> VF Bulletin Board
Browse files Browse the repository at this point in the history
The PF <-> VF Bulletin Board is a simple interface between the
PF and the VF. The main reason for the Bulletin Board is to allow
the PF to be the initiator. The VF publishes at 'acquire' stage
the GPA of a Bulletin Board structure it has allocated. The PF notes
this GPA in the VF database. The VF samples the Bulletin Board
periodically for new messages. The latest version of the BB is always
used.

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 d16132c commit abc5a02
Show file tree
Hide file tree
Showing 8 changed files with 320 additions and 2 deletions.
6 changes: 6 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,12 @@ struct bnx2x {
/* we set aside a copy of the acquire response */
struct pfvf_acquire_resp_tlv acquire_resp;

/* bulletin board for messages from pf to vf */
union pf_vf_bulletin *pf2vf_bulletin;
dma_addr_t pf2vf_bulletin_mapping;

struct pf_vf_bulletin_content old_bulletin;

struct net_device *dev;
struct pci_dev *pdev;

Expand Down
87 changes: 87 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
Original file line number Diff line number Diff line change
Expand Up @@ -3793,6 +3793,93 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc)
return 0;
}

/* New mac for VF. Consider these cases:
* 1. VF hasn't been acquired yet - save the mac in local bulletin board and
* supply at acquire.
* 2. VF has already been acquired but has not yet initialized - store in local
* bulletin board. mac will be posted on VF bulletin board after VF init. VF
* will configure this mac when it is ready.
* 3. VF has already initialized but has not yet setup a queue - post the new
* mac on VF's bulletin board right now. VF will configure this mac when it
* is ready.
* 4. VF has already set a queue - delete any macs already configured for this
* queue and manually config the new mac.
* In any event, once this function has been called refuse any attempts by the
* VF to configure any mac for itself except for this mac. In case of a race
* where the VF fails to see the new post on its bulletin board before sending a
* mac configuration request, the PF will simply fail the request and VF can try
* again after consulting its bulletin board
*/
int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
{
struct bnx2x *bp = netdev_priv(dev);
int rc, q_logical_state, vfidx = queue;
struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);

/* if SRIOV is disabled there is nothing to do (and somewhere, someone
* has erred).
*/
if (!IS_SRIOV(bp)) {
BNX2X_ERR("bnx2x_set_vf_mac called though sriov is disabled\n");
return -EINVAL;
}

if (!is_valid_ether_addr(mac)) {
BNX2X_ERR("mac address invalid\n");
return -EINVAL;
}

/* update PF's copy of the VF's bulletin. will no longer accept mac
* configuration requests from vf unless match this mac
*/
bulletin->valid_bitmap |= 1 << MAC_ADDR_VALID;
memcpy(bulletin->mac, mac, ETH_ALEN);

/* Post update on VF's bulletin board */
rc = bnx2x_post_vf_bulletin(bp, vfidx);
if (rc) {
BNX2X_ERR("failed to update VF[%d] bulletin\n", vfidx);
return rc;
}

/* is vf initialized and queue set up? */
q_logical_state =
bnx2x_get_q_logical_state(bp, &bnx2x_vfq(vf, 0, sp_obj));
if (vf->state == VF_ENABLED &&
q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
/* configure the mac in device on this vf's queue */
unsigned long flags = 0;
struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj);

/* must lock vfpf channel to protect against vf flows */
bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);

/* remove existing eth macs */
rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_ETH_MAC, true);
if (rc) {
BNX2X_ERR("failed to delete eth macs\n");
return -EINVAL;
}

/* remove existing uc list macs */
rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_UC_LIST_MAC, true);
if (rc) {
BNX2X_ERR("failed to delete uc_list macs\n");
return -EINVAL;
}

/* configure the new mac to device */
__set_bit(RAMROD_COMP_WAIT, &flags);
bnx2x_set_mac_one(bp, (u8 *)&bulletin->mac, mac_obj, true,
BNX2X_ETH_MAC, &flags);

bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
}

return rc;
}

/* called with rtnl_lock */
int bnx2x_change_mac_addr(struct net_device *dev, void *p)
{
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,8 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev);
/* setup_tc callback */
int bnx2x_setup_tc(struct net_device *dev, u8 num_tc);

int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac);

/* select_queue callback */
u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb);

Expand Down
94 changes: 92 additions & 2 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5248,6 +5248,61 @@ void bnx2x_drv_pulse(struct bnx2x *bp)
bp->fw_drv_pulse_wr_seq);
}

/* crc is the first field in the bulletin board. compute the crc over the
* entire bulletin board excluding the crc field itself
*/
u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
struct pf_vf_bulletin_content *bulletin)
{
return crc32(BULLETIN_CRC_SEED,
((u8 *)bulletin) + sizeof(bulletin->crc),
BULLETIN_CONTENT_SIZE - sizeof(bulletin->crc));
}

/* Check for new posts on the bulletin board */
enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
{
struct pf_vf_bulletin_content bulletin = bp->pf2vf_bulletin->content;
int attempts;

/* bulletin board hasn't changed since last sample */
if (bp->old_bulletin.version == bulletin.version)
return PFVF_BULLETIN_UNCHANGED;

/* validate crc of new bulletin board */
if (bp->old_bulletin.version != bp->pf2vf_bulletin->content.version) {
/* sampling structure in mid post may result with corrupted data
* validate crc to ensure coherency.
*/
for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) {
bulletin = bp->pf2vf_bulletin->content;
if (bulletin.crc == bnx2x_crc_vf_bulletin(bp,
&bulletin))
break;

BNX2X_ERR("bad crc on bulletin board. contained %x computed %x\n",
bulletin.crc,
bnx2x_crc_vf_bulletin(bp, &bulletin));
}
if (attempts >= BULLETIN_ATTEMPTS) {
BNX2X_ERR("pf to vf bulletin board crc was wrong %d consecutive times. Aborting\n",
attempts);
return PFVF_BULLETIN_CRC_ERR;
}
}

/* the mac address in bulletin board is valid and is new */
if (bulletin.valid_bitmap & 1 << MAC_ADDR_VALID &&
memcmp(bulletin.mac, bp->old_bulletin.mac, ETH_ALEN)) {
/* update new mac to net device */
memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN);
}

/* copy new bulletin board to bp */
bp->old_bulletin = bulletin;

return PFVF_BULLETIN_UPDATED;
}

static void bnx2x_timer(unsigned long data)
{
Expand Down Expand Up @@ -5284,6 +5339,10 @@ static void bnx2x_timer(unsigned long data)
if (bp->state == BNX2X_STATE_OPEN)
bnx2x_stats_handle(bp, STATS_EVENT_UPDATE);

/* sample pf vf bulletin board for new posts from pf */
if (IS_VF(bp))
bnx2x_sample_bulletin(bp);

mod_timer(&bp->timer, jiffies + bp->current_interval);
}

Expand Down Expand Up @@ -11660,7 +11719,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
.ndo_poll_controller = poll_bnx2x,
#endif
.ndo_setup_tc = bnx2x_setup_tc,

.ndo_set_vf_mac = bnx2x_set_vf_mac,
#ifdef NETDEV_FCOE_WWNN
.ndo_fcoe_get_wwn = bnx2x_fcoe_get_wwn,
#endif
Expand Down Expand Up @@ -12321,6 +12380,11 @@ static int bnx2x_init_one(struct pci_dev *pdev,
/* allocate vf2pf mailbox for vf to pf channel */
BNX2X_PCI_ALLOC(bp->vf2pf_mbox, &bp->vf2pf_mbox_mapping,
sizeof(struct bnx2x_vf_mbx_msg));

/* allocate pf 2 vf bulletin board */
BNX2X_PCI_ALLOC(bp->pf2vf_bulletin, &bp->pf2vf_bulletin_mapping,
sizeof(union pf_vf_bulletin));

} else {
doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT);
if (doorbell_size > pci_resource_len(pdev, 2)) {
Expand Down Expand Up @@ -13379,6 +13443,9 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
req->resc_request.num_mac_filters = VF_ACQUIRE_MAC_FILTERS;
req->resc_request.num_mc_filters = VF_ACQUIRE_MC_FILTERS;

/* pf 2 vf bulletin board address */
req->bulletin_addr = bp->pf2vf_bulletin_mapping;

/* add list termination tlv */
bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
sizeof(struct channel_list_end_tlv));
Expand Down Expand Up @@ -13701,6 +13768,7 @@ int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx)
return rc;
}

/* PF failed the transaction */
if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("TEARDOWN for queue %d failed: %d\n", qidx,
resp->hdr.status);
Expand All @@ -13727,6 +13795,9 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp)
req->filters[0].flags =
VFPF_Q_FILTER_DEST_MAC_VALID | VFPF_Q_FILTER_SET_MAC;

/* sample bulletin board for new mac */
bnx2x_sample_bulletin(bp);

/* copy mac from device to request */
memcpy(req->filters[0].mac, bp->dev->dev_addr, ETH_ALEN);

Expand All @@ -13744,7 +13815,26 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp)
return rc;
}

/* PF failed the transaction */
/* failure may mean PF was configured with a new mac for us */
while (resp->hdr.status == PFVF_STATUS_FAILURE) {
DP(BNX2X_MSG_IOV,
"vfpf SET MAC failed. Check bulletin board for new posts\n");

/* check if bulletin board was updated */
if (bnx2x_sample_bulletin(bp) == PFVF_BULLETIN_UPDATED) {
/* copy mac from device to request */
memcpy(req->filters[0].mac, bp->dev->dev_addr,
ETH_ALEN);

/* send message to pf */
rc = bnx2x_send_msg2pf(bp, &resp->hdr.status,
bp->vf2pf_mbox_mapping);
} else {
/* no new info in bulletin */
break;
}
}

if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("vfpf SET MAC failed: %d\n", resp->hdr.status);
return -EINVAL;
Expand Down
13 changes: 13 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
Original file line number Diff line number Diff line change
Expand Up @@ -2058,6 +2058,10 @@ void bnx2x_iov_free_mem(struct bnx2x *bp)
BNX2X_PCI_FREE(BP_VF_MBX_DMA(bp)->addr,
BP_VF_MBX_DMA(bp)->mapping,
BP_VF_MBX_DMA(bp)->size);

BNX2X_PCI_FREE(BP_VF_BULLETIN_DMA(bp)->addr,
BP_VF_BULLETIN_DMA(bp)->mapping,
BP_VF_BULLETIN_DMA(bp)->size);
}

int bnx2x_iov_alloc_mem(struct bnx2x *bp)
Expand Down Expand Up @@ -2097,6 +2101,12 @@ int bnx2x_iov_alloc_mem(struct bnx2x *bp)
tot_size);
BP_VF_MBX_DMA(bp)->size = tot_size;

/* allocate local bulletin boards */
tot_size = BNX2X_NR_VIRTFN(bp) * BULLETIN_CONTENT_SIZE;
BNX2X_PCI_ALLOC(BP_VF_BULLETIN_DMA(bp)->addr,
&BP_VF_BULLETIN_DMA(bp)->mapping, tot_size);
BP_VF_BULLETIN_DMA(bp)->size = tot_size;

return 0;

alloc_mem_err:
Expand Down Expand Up @@ -2810,6 +2820,9 @@ int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf, dma_addr_t *sb_map)

vf->state = VF_ENABLED;

/* update vf bulletin board */
bnx2x_post_vf_bulletin(bp, vf->index);

return 0;
}

Expand Down
18 changes: 18 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,12 @@ struct bnx2x_vfdb {
struct bnx2x_vf_mbx mbxs[BNX2X_MAX_NUM_OF_VFS];
#define BP_VF_MBX(bp, vfid) (&((bp)->vfdb->mbxs[(vfid)]))

struct hw_dma bulletin_dma;
#define BP_VF_BULLETIN_DMA(bp) (&((bp)->vfdb->bulletin_dma))
#define BP_VF_BULLETIN(bp, vf) \
(((struct pf_vf_bulletin_content *)(BP_VF_BULLETIN_DMA(bp)->addr)) \
+ (vf))

struct hw_dma sp_dma;
#define bnx2x_vf_sp(bp, vf, field) ((bp)->vfdb->sp_dma.addr + \
(vf)->index * sizeof(struct bnx2x_vf_sp) + \
Expand Down Expand Up @@ -702,4 +708,16 @@ void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list);

bool bnx2x_tlv_supported(u16 tlvtype);

u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
struct pf_vf_bulletin_content *bulletin);
int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf);

enum sample_bulletin_result {
PFVF_BULLETIN_UNCHANGED,
PFVF_BULLETIN_UPDATED,
PFVF_BULLETIN_CRC_ERR
};

enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);

#endif /* bnx2x_sriov.h */
Loading

0 comments on commit abc5a02

Please sign in to comment.