Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 351246
b: refs/heads/master
c: abc5a02
h: refs/heads/master
v: v3
  • Loading branch information
Ariel Elior authored and David S. Miller committed Jan 2, 2013
1 parent 358b237 commit 53034c8
Show file tree
Hide file tree
Showing 9 changed files with 321 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d16132cef8a72ff7563aff95f03bf505779fe3e6
refs/heads/master: abc5a021ba645cd162205209bd5664a0d4b866a6
6 changes: 6 additions & 0 deletions trunk/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 trunk/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 trunk/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 trunk/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 trunk/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 trunk/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 53034c8

Please sign in to comment.