Skip to content

Commit

Permalink
bnx2x: Support statistics collection for VFs by the PF
Browse files Browse the repository at this point in the history
Statistics are collected by the PF driver. The collection is
performed via a query sent to the device which is basically an array
of 3-tuples of the form (statistics client, function, DMAE address).
In this patch the PF driver adds to the query, on top of the
statistics clients it is maintaining for itself (rss queues, storage,
etc), the 3-tuples for the VFs it is maintaining. The addresses used
are the GPAs of the statistics buffers supplied by the VF in the
init message on the VF <-> PF channel. The function parameter
ensures that the iommu will translate the GPA to the correct physical
address.

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 b93288d commit 67c431a
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 93 deletions.
77 changes: 5 additions & 72 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5251,7 +5251,8 @@ static void bnx2x_timer(unsigned long data)
if (!netif_running(bp->dev))
return;

if (!BP_NOMCP(bp)) {
if (IS_PF(bp) &&
!BP_NOMCP(bp)) {
int mb_idx = BP_FW_MB_IDX(bp);
u32 drv_pulse;
u32 mcp_pulse;
Expand Down Expand Up @@ -7670,66 +7671,6 @@ void bnx2x_free_mem(struct bnx2x *bp)
BCM_PAGE_SIZE * NUM_EQ_PAGES);
}

static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
{
int num_groups;
int is_fcoe_stats = NO_FCOE(bp) ? 0 : 1;

/* number of queues for statistics is number of eth queues + FCoE */
u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe_stats;

/* Total number of FW statistics requests =
* 1 for port stats + 1 for PF stats + potential 1 for FCoE stats +
* num of queues
*/
bp->fw_stats_num = 2 + is_fcoe_stats + num_queue_stats;


/* Request is built from stats_query_header and an array of
* stats_query_cmd_group each of which contains
* STATS_QUERY_CMD_COUNT rules. The real number or requests is
* configured in the stats_query_header.
*/
num_groups = ((bp->fw_stats_num) / STATS_QUERY_CMD_COUNT) +
(((bp->fw_stats_num) % STATS_QUERY_CMD_COUNT) ? 1 : 0);

bp->fw_stats_req_sz = sizeof(struct stats_query_header) +
num_groups * sizeof(struct stats_query_cmd_group);

/* Data for statistics requests + stats_conter
*
* stats_counter holds per-STORM counters that are incremented
* when STORM has finished with the current request.
*
* memory for FCoE offloaded statistics are counted anyway,
* even if they will not be sent.
*/
bp->fw_stats_data_sz = sizeof(struct per_port_stats) +
sizeof(struct per_pf_stats) +
sizeof(struct fcoe_statistics_params) +
sizeof(struct per_queue_stats) * num_queue_stats +
sizeof(struct stats_counter);

BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping,
bp->fw_stats_data_sz + bp->fw_stats_req_sz);

/* Set shortcuts */
bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats;
bp->fw_stats_req_mapping = bp->fw_stats_mapping;

bp->fw_stats_data = (struct bnx2x_fw_stats_data *)
((u8 *)bp->fw_stats + bp->fw_stats_req_sz);

bp->fw_stats_data_mapping = bp->fw_stats_mapping +
bp->fw_stats_req_sz;
return 0;

alloc_mem_err:
BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
bp->fw_stats_data_sz + bp->fw_stats_req_sz);
BNX2X_ERR("Can't allocate memory\n");
return -ENOMEM;
}

int bnx2x_alloc_mem_cnic(struct bnx2x *bp)
{
Expand Down Expand Up @@ -7776,10 +7717,6 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
sizeof(struct bnx2x_slowpath));

/* Allocated memory for FW statistics */
if (bnx2x_alloc_fw_stats_mem(bp))
goto alloc_mem_err;

/* Allocate memory for CDU context:
* This memory is allocated separately and not in the generic ILT
* functions because CDU differs in few aspects:
Expand Down Expand Up @@ -7808,20 +7745,16 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
if (bnx2x_ilt_mem_op(bp, ILT_MEMOP_ALLOC))
goto alloc_mem_err;

if (bnx2x_iov_alloc_mem(bp))
goto alloc_mem_err;

/* Slow path ring */
BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE);

/* EQ */
BNX2X_PCI_ALLOC(bp->eq_ring, &bp->eq_mapping,
BCM_PAGE_SIZE * NUM_EQ_PAGES);


/* fastpath */
/* need to be done at the end, since it's self adjusting to amount
* of memory available for RSS queues
*/
if (bnx2x_alloc_fp_mem(bp))
goto alloc_mem_err;
return 0;

alloc_mem_err:
Expand Down
21 changes: 21 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
Original file line number Diff line number Diff line change
Expand Up @@ -5199,6 +5199,27 @@ void bnx2x_init_queue_obj(struct bnx2x *bp,
obj->set_pending = bnx2x_queue_set_pending;
}

/* return a queue object's logical state*/
int bnx2x_get_q_logical_state(struct bnx2x *bp,
struct bnx2x_queue_sp_obj *obj)
{
switch (obj->state) {
case BNX2X_Q_STATE_ACTIVE:
case BNX2X_Q_STATE_MULTI_COS:
return BNX2X_Q_LOGICAL_STATE_ACTIVE;
case BNX2X_Q_STATE_RESET:
case BNX2X_Q_STATE_INITIALIZED:
case BNX2X_Q_STATE_MCOS_TERMINATED:
case BNX2X_Q_STATE_INACTIVE:
case BNX2X_Q_STATE_STOPPED:
case BNX2X_Q_STATE_TERMINATED:
case BNX2X_Q_STATE_FLRED:
return BNX2X_Q_LOGICAL_STATE_STOPPED;
default:
return -EINVAL;
}
}

/********************** Function state object *********************************/
enum bnx2x_func_state bnx2x_func_get_state(struct bnx2x *bp,
struct bnx2x_func_sp_obj *o)
Expand Down
9 changes: 9 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,12 @@ enum bnx2x_q_state {
BNX2X_Q_STATE_MAX,
};

/* Allowed Queue states */
enum bnx2x_q_logical_state {
BNX2X_Q_LOGICAL_STATE_ACTIVE,
BNX2X_Q_LOGICAL_STATE_STOPPED,
};

/* Allowed commands */
enum bnx2x_queue_cmd {
BNX2X_Q_CMD_INIT,
Expand Down Expand Up @@ -1261,6 +1267,9 @@ void bnx2x_init_queue_obj(struct bnx2x *bp,
int bnx2x_queue_state_change(struct bnx2x *bp,
struct bnx2x_queue_state_params *params);

int bnx2x_get_q_logical_state(struct bnx2x *bp,
struct bnx2x_queue_sp_obj *obj);

/********************* VLAN-MAC ****************/
void bnx2x_init_mac_obj(struct bnx2x *bp,
struct bnx2x_vlan_mac_obj *mac_obj,
Expand Down
91 changes: 91 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,80 @@ void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work)
}
}

void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
{
int i;
int first_queue_query_index, num_queues_req;
dma_addr_t cur_data_offset;
struct stats_query_entry *cur_query_entry;
u8 stats_count = 0;
bool is_fcoe = false;

if (!IS_SRIOV(bp))
return;

if (!NO_FCOE(bp))
is_fcoe = true;

/* fcoe adds one global request and one queue request */
num_queues_req = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe;
first_queue_query_index = BNX2X_FIRST_QUEUE_QUERY_IDX -
(is_fcoe ? 0 : 1);

DP(BNX2X_MSG_IOV,
"BNX2X_NUM_ETH_QUEUES %d, is_fcoe %d, first_queue_query_index %d => determined the last non virtual statistics query index is %d. Will add queries on top of that\n",
BNX2X_NUM_ETH_QUEUES(bp), is_fcoe, first_queue_query_index,
first_queue_query_index + num_queues_req);

cur_data_offset = bp->fw_stats_data_mapping +
offsetof(struct bnx2x_fw_stats_data, queue_stats) +
num_queues_req * sizeof(struct per_queue_stats);

cur_query_entry = &bp->fw_stats_req->
query[first_queue_query_index + num_queues_req];

for_each_vf(bp, i) {
int j;
struct bnx2x_virtf *vf = BP_VF(bp, i);

if (vf->state != VF_ENABLED) {
DP(BNX2X_MSG_IOV,
"vf %d not enabled so no stats for it\n",
vf->abs_vfid);
continue;
}

DP(BNX2X_MSG_IOV, "add addresses for vf %d\n", vf->abs_vfid);
for_each_vfq(vf, j) {
struct bnx2x_vf_queue *rxq = vfq_get(vf, j);

/* collect stats fro active queues only */
if (bnx2x_get_q_logical_state(bp, &rxq->sp_obj) ==
BNX2X_Q_LOGICAL_STATE_STOPPED)
continue;

/* create stats query entry for this queue */
cur_query_entry->kind = STATS_TYPE_QUEUE;
cur_query_entry->index = vfq_cl_id(vf, rxq);
cur_query_entry->funcID =
cpu_to_le16(FW_VF_HANDLE(vf->abs_vfid));
cur_query_entry->address.hi =
cpu_to_le32(U64_HI(vf->fw_stat_map));
cur_query_entry->address.lo =
cpu_to_le32(U64_LO(vf->fw_stat_map));
DP(BNX2X_MSG_IOV,
"added address %x %x for vf %d queue %d client %d\n",
cur_query_entry->address.hi,
cur_query_entry->address.lo, cur_query_entry->funcID,
j, cur_query_entry->index);
cur_query_entry++;
cur_data_offset += sizeof(struct per_queue_stats);
stats_count++;
}
}
bp->fw_stats_req->hdr.cmd_num = bp->fw_stats_num + stats_count;
}

void bnx2x_iov_sp_task(struct bnx2x *bp)
{
int i;
Expand All @@ -1089,6 +1163,23 @@ void bnx2x_iov_sp_task(struct bnx2x *bp)
}
}
}

static inline
struct bnx2x_virtf *__vf_from_stat_id(struct bnx2x *bp, u8 stat_id)
{
int i;
struct bnx2x_virtf *vf = NULL;

for_each_vf(bp, i) {
vf = BP_VF(bp, i);
if (stat_id >= vf->igu_base_id &&
stat_id < vf->igu_base_id + vf_sb_count(vf))
break;
}
return vf;
}

/* VF API helpers */
static void bnx2x_vf_qtbl_set_q(struct bnx2x *bp, u8 abs_vfid, u8 qid,
u8 enable)
{
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,8 @@ void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
struct bnx2x_queue_sp_obj **q_obj);
void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work);
int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem);
void bnx2x_iov_adjust_stats_req(struct bnx2x *bp);
void bnx2x_iov_storm_stats_update(struct bnx2x *bp);
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);
Expand Down
Loading

0 comments on commit 67c431a

Please sign in to comment.