Commit fc85c910 authored by David S. Miller's avatar David S. Miller

Merge branch 'qed-vf-xdp'

Yuval Mintz says:

qed*: Support VF XDP attachment

====================
Each driver queue [Rx, Tx, XDP-forwarding] requires an allocated HW/FW
connection + configured queue-zone.

VF handling by the PF has several limitations that prevented adding the
capability to perform XDP at driver-level:

 - The VF assumes there's 1-to-1 correspondance between the VF queue and
   the used connection, meaning q<x> is always going to use cid<x>,
   whereas for its own queues the PF is acquiring a new cid per each new
   queue.

 - There's a 1-to-1 correspondate between the VF-queues and the HW queue
   zones. While this is necessary for Rx-queues [as the queue-zone
   contains the producer], transmission queues can share the underlaying
   queue-zone [only shared configuration is coalescing].
   But all VF<->PF communication mechanisms assume there's a single
   identifier that identify a queue [as queue-zone == queue], while
   sharing queue-zones requires passing additional information.

 - VFs currently don't try mapping a doorbell bar - there's a small
   doorbell window in the regview allowing VFs to doorbell up to 16
   connections; but this window isn's wide enough for the added XDP
   forwarding queues.

This series is going to add the necessary infrastrucutre to finally let
our VFs support XDP assuming both the PF and VF drivers are sufficiently
new [Legacy support would be retained both for older VFs and older PFs,
but both will be needed for this new support to work].
Basically, the various database driver maintains for its queue-cids
would be revised, and queue-cids would be identified using the
(queue-zone, unique index) pair. The TLV mechanism would then be
extended to allow VFs to communicate that unique-index as well as the
already provided queue-zone. Finally, the VFs would try to map their
doorbell bar and inform their PF that they're using it.

Almost all the changes are in qed, with exception of #3 [which does some
cleanup in qede as well] and #11 that actually enables the feature.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a619cc8b e7b80dec
......@@ -412,6 +412,11 @@ struct qed_fw_data {
u32 init_ops_size;
};
enum BAR_ID {
BAR_ID_0, /* used for GRC */
BAR_ID_1 /* Used for doorbells */
};
#define DRV_MODULE_VERSION \
__stringify(QED_MAJOR_VERSION) "." \
__stringify(QED_MINOR_VERSION) "." \
......@@ -533,6 +538,9 @@ struct qed_hwfn {
u8 dcbx_no_edpm;
u8 db_bar_no_edpm;
/* L2-related */
struct qed_l2_info *p_l2_info;
struct qed_ptt *p_arfs_ptt;
struct qed_simd_fp_handler simd_proto_handler[64];
......
......@@ -135,7 +135,6 @@ struct qed_tid_seg {
struct qed_conn_type_cfg {
u32 cid_count;
u32 cid_start;
u32 cids_per_vf;
struct qed_tid_seg tid_seg[TASK_SEGMENTS];
};
......@@ -222,6 +221,9 @@ struct qed_cxt_mngr {
/* Acquired CIDs */
struct qed_cid_acquired_map acquired[MAX_CONN_TYPES];
struct qed_cid_acquired_map
acquired_vf[MAX_CONN_TYPES][MAX_NUM_VFS];
/* ILT shadow table */
struct qed_dma_mem *ilt_shadow;
u32 pf_start_line;
......@@ -1121,45 +1123,76 @@ static int qed_ilt_shadow_alloc(struct qed_hwfn *p_hwfn)
static void qed_cid_map_free(struct qed_hwfn *p_hwfn)
{
struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
u32 type;
u32 type, vf;
for (type = 0; type < MAX_CONN_TYPES; type++) {
kfree(p_mngr->acquired[type].cid_map);
p_mngr->acquired[type].max_count = 0;
p_mngr->acquired[type].start_cid = 0;
for (vf = 0; vf < MAX_NUM_VFS; vf++) {
kfree(p_mngr->acquired_vf[type][vf].cid_map);
p_mngr->acquired_vf[type][vf].max_count = 0;
p_mngr->acquired_vf[type][vf].start_cid = 0;
}
}
}
static int
qed_cid_map_alloc_single(struct qed_hwfn *p_hwfn,
u32 type,
u32 cid_start,
u32 cid_count, struct qed_cid_acquired_map *p_map)
{
u32 size;
if (!cid_count)
return 0;
size = DIV_ROUND_UP(cid_count,
sizeof(unsigned long) * BITS_PER_BYTE) *
sizeof(unsigned long);
p_map->cid_map = kzalloc(size, GFP_KERNEL);
if (!p_map->cid_map)
return -ENOMEM;
p_map->max_count = cid_count;
p_map->start_cid = cid_start;
DP_VERBOSE(p_hwfn, QED_MSG_CXT,
"Type %08x start: %08x count %08x\n",
type, p_map->start_cid, p_map->max_count);
return 0;
}
static int qed_cid_map_alloc(struct qed_hwfn *p_hwfn)
{
struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
u32 start_cid = 0;
u32 type;
u32 start_cid = 0, vf_start_cid = 0;
u32 type, vf;
for (type = 0; type < MAX_CONN_TYPES; type++) {
u32 cid_cnt = p_hwfn->p_cxt_mngr->conn_cfg[type].cid_count;
u32 size;
if (cid_cnt == 0)
continue;
struct qed_conn_type_cfg *p_cfg = &p_mngr->conn_cfg[type];
struct qed_cid_acquired_map *p_map;
size = DIV_ROUND_UP(cid_cnt,
sizeof(unsigned long) * BITS_PER_BYTE) *
sizeof(unsigned long);
p_mngr->acquired[type].cid_map = kzalloc(size, GFP_KERNEL);
if (!p_mngr->acquired[type].cid_map)
/* Handle PF maps */
p_map = &p_mngr->acquired[type];
if (qed_cid_map_alloc_single(p_hwfn, type, start_cid,
p_cfg->cid_count, p_map))
goto cid_map_fail;
p_mngr->acquired[type].max_count = cid_cnt;
p_mngr->acquired[type].start_cid = start_cid;
p_hwfn->p_cxt_mngr->conn_cfg[type].cid_start = start_cid;
/* Handle VF maps */
for (vf = 0; vf < MAX_NUM_VFS; vf++) {
p_map = &p_mngr->acquired_vf[type][vf];
if (qed_cid_map_alloc_single(p_hwfn, type,
vf_start_cid,
p_cfg->cids_per_vf, p_map))
goto cid_map_fail;
}
DP_VERBOSE(p_hwfn, QED_MSG_CXT,
"Type %08x start: %08x count %08x\n",
type, p_mngr->acquired[type].start_cid,
p_mngr->acquired[type].max_count);
start_cid += cid_cnt;
start_cid += p_cfg->cid_count;
vf_start_cid += p_cfg->cids_per_vf;
}
return 0;
......@@ -1265,19 +1298,36 @@ void qed_cxt_mngr_free(struct qed_hwfn *p_hwfn)
void qed_cxt_mngr_setup(struct qed_hwfn *p_hwfn)
{
struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
struct qed_cid_acquired_map *p_map;
struct qed_conn_type_cfg *p_cfg;
int type;
u32 len;
/* Reset acquired cids */
for (type = 0; type < MAX_CONN_TYPES; type++) {
u32 cid_cnt = p_hwfn->p_cxt_mngr->conn_cfg[type].cid_count;
u32 vf;
p_cfg = &p_mngr->conn_cfg[type];
if (p_cfg->cid_count) {
p_map = &p_mngr->acquired[type];
len = DIV_ROUND_UP(p_map->max_count,
sizeof(unsigned long) *
BITS_PER_BYTE) *
sizeof(unsigned long);
memset(p_map->cid_map, 0, len);
}
if (cid_cnt == 0)
if (!p_cfg->cids_per_vf)
continue;
memset(p_mngr->acquired[type].cid_map, 0,
DIV_ROUND_UP(cid_cnt,
sizeof(unsigned long) * BITS_PER_BYTE) *
sizeof(unsigned long));
for (vf = 0; vf < MAX_NUM_VFS; vf++) {
p_map = &p_mngr->acquired_vf[type][vf];
len = DIV_ROUND_UP(p_map->max_count,
sizeof(unsigned long) *
BITS_PER_BYTE) *
sizeof(unsigned long);
memset(p_map->cid_map, 0, len);
}
}
}
......@@ -1841,91 +1891,145 @@ void qed_cxt_hw_init_pf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
qed_prs_init_pf(p_hwfn);
}
int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
enum protocol_type type, u32 *p_cid)
int _qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
enum protocol_type type, u32 *p_cid, u8 vfid)
{
struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
struct qed_cid_acquired_map *p_map;
u32 rel_cid;
if (type >= MAX_CONN_TYPES || !p_mngr->acquired[type].cid_map) {
if (type >= MAX_CONN_TYPES) {
DP_NOTICE(p_hwfn, "Invalid protocol type %d", type);
return -EINVAL;
}
rel_cid = find_first_zero_bit(p_mngr->acquired[type].cid_map,
p_mngr->acquired[type].max_count);
if (vfid >= MAX_NUM_VFS && vfid != QED_CXT_PF_CID) {
DP_NOTICE(p_hwfn, "VF [%02x] is out of range\n", vfid);
return -EINVAL;
}
if (rel_cid >= p_mngr->acquired[type].max_count) {
/* Determine the right map to take this CID from */
if (vfid == QED_CXT_PF_CID)
p_map = &p_mngr->acquired[type];
else
p_map = &p_mngr->acquired_vf[type][vfid];
if (!p_map->cid_map) {
DP_NOTICE(p_hwfn, "Invalid protocol type %d", type);
return -EINVAL;
}
rel_cid = find_first_zero_bit(p_map->cid_map, p_map->max_count);
if (rel_cid >= p_map->max_count) {
DP_NOTICE(p_hwfn, "no CID available for protocol %d\n", type);
return -EINVAL;
}
__set_bit(rel_cid, p_mngr->acquired[type].cid_map);
__set_bit(rel_cid, p_map->cid_map);
*p_cid = rel_cid + p_mngr->acquired[type].start_cid;
*p_cid = rel_cid + p_map->start_cid;
DP_VERBOSE(p_hwfn, QED_MSG_CXT,
"Acquired cid 0x%08x [rel. %08x] vfid %02x type %d\n",
*p_cid, rel_cid, vfid, type);
return 0;
}
int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
enum protocol_type type, u32 *p_cid)
{
return _qed_cxt_acquire_cid(p_hwfn, type, p_cid, QED_CXT_PF_CID);
}
static bool qed_cxt_test_cid_acquired(struct qed_hwfn *p_hwfn,
u32 cid, enum protocol_type *p_type)
u32 cid,
u8 vfid,
enum protocol_type *p_type,
struct qed_cid_acquired_map **pp_map)
{
struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
struct qed_cid_acquired_map *p_map;
enum protocol_type p;
u32 rel_cid;
/* Iterate over protocols and find matching cid range */
for (p = 0; p < MAX_CONN_TYPES; p++) {
p_map = &p_mngr->acquired[p];
for (*p_type = 0; *p_type < MAX_CONN_TYPES; (*p_type)++) {
if (vfid == QED_CXT_PF_CID)
*pp_map = &p_mngr->acquired[*p_type];
else
*pp_map = &p_mngr->acquired_vf[*p_type][vfid];
if (!p_map->cid_map)
if (!((*pp_map)->cid_map))
continue;
if (cid >= p_map->start_cid &&
cid < p_map->start_cid + p_map->max_count)
if (cid >= (*pp_map)->start_cid &&
cid < (*pp_map)->start_cid + (*pp_map)->max_count)
break;
}
*p_type = p;
if (p == MAX_CONN_TYPES) {
DP_NOTICE(p_hwfn, "Invalid CID %d", cid);
return false;
if (*p_type == MAX_CONN_TYPES) {
DP_NOTICE(p_hwfn, "Invalid CID %d vfid %02x", cid, vfid);
goto fail;
}
rel_cid = cid - p_map->start_cid;
if (!test_bit(rel_cid, p_map->cid_map)) {
DP_NOTICE(p_hwfn, "CID %d not acquired", cid);
return false;
rel_cid = cid - (*pp_map)->start_cid;
if (!test_bit(rel_cid, (*pp_map)->cid_map)) {
DP_NOTICE(p_hwfn, "CID %d [vifd %02x] not acquired",
cid, vfid);
goto fail;
}
return true;
fail:
*p_type = MAX_CONN_TYPES;
*pp_map = NULL;
return false;
}
void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid)
void _qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid, u8 vfid)
{
struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
struct qed_cid_acquired_map *p_map = NULL;
enum protocol_type type;
bool b_acquired;
u32 rel_cid;
if (vfid != QED_CXT_PF_CID && vfid > MAX_NUM_VFS) {
DP_NOTICE(p_hwfn,
"Trying to return incorrect CID belonging to VF %02x\n",
vfid);
return;
}
/* Test acquired and find matching per-protocol map */
b_acquired = qed_cxt_test_cid_acquired(p_hwfn, cid, &type);
b_acquired = qed_cxt_test_cid_acquired(p_hwfn, cid, vfid,
&type, &p_map);
if (!b_acquired)
return;
rel_cid = cid - p_mngr->acquired[type].start_cid;
__clear_bit(rel_cid, p_mngr->acquired[type].cid_map);
rel_cid = cid - p_map->start_cid;
clear_bit(rel_cid, p_map->cid_map);
DP_VERBOSE(p_hwfn, QED_MSG_CXT,
"Released CID 0x%08x [rel. %08x] vfid %02x type %d\n",
cid, rel_cid, vfid, type);
}
void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid)
{
_qed_cxt_release_cid(p_hwfn, cid, QED_CXT_PF_CID);
}
int qed_cxt_get_cid_info(struct qed_hwfn *p_hwfn, struct qed_cxt_info *p_info)
{
struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
struct qed_cid_acquired_map *p_map = NULL;
u32 conn_cxt_size, hw_p_size, cxts_per_p, line;
enum protocol_type type;
bool b_acquired;
/* Test acquired and find matching per-protocol map */
b_acquired = qed_cxt_test_cid_acquired(p_hwfn, p_info->iid, &type);
b_acquired = qed_cxt_test_cid_acquired(p_hwfn, p_info->iid,
QED_CXT_PF_CID, &type, &p_map);
if (!b_acquired)
return -EINVAL;
......@@ -2012,8 +2116,12 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn, u32 rdma_tasks)
struct qed_eth_pf_params *p_params =
&p_hwfn->pf_params.eth_pf_params;
qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_ETH,
p_params->num_cons, 1);
if (!p_params->num_vf_cons)
p_params->num_vf_cons =
ETH_PF_PARAMS_VF_CONS_DEFAULT;
qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_ETH,
p_params->num_cons,
p_params->num_vf_cons);
p_hwfn->p_cxt_mngr->arfs_count = p_params->num_arfs_filters;
break;
}
......
......@@ -53,19 +53,6 @@ struct qed_tid_mem {
u8 *blocks[MAX_TID_BLOCKS]; /* 4K */
};
/**
* @brief qed_cxt_acquire - Acquire a new cid of a specific protocol type
*
* @param p_hwfn
* @param type
* @param p_cid
*
* @return int
*/
int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
enum protocol_type type,
u32 *p_cid);
/**
* @brief qedo_cid_get_cxt_info - Returns the context info for a specific cid
*
......@@ -195,14 +182,51 @@ void qed_qm_init_pf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
*/
int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
#define QED_CXT_PF_CID (0xff)
/**
* @brief qed_cxt_release - Release a cid
*
* @param p_hwfn
* @param cid
*/
void qed_cxt_release_cid(struct qed_hwfn *p_hwfn,
u32 cid);
void qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid);
/**
* @brief qed_cxt_release - Release a cid belonging to a vf-queue
*
* @param p_hwfn
* @param cid
* @param vfid - engine relative index. QED_CXT_PF_CID if belongs to PF
*/
void _qed_cxt_release_cid(struct qed_hwfn *p_hwfn, u32 cid, u8 vfid);
/**
* @brief qed_cxt_acquire - Acquire a new cid of a specific protocol type
*
* @param p_hwfn
* @param type
* @param p_cid
*
* @return int
*/
int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
enum protocol_type type, u32 *p_cid);
/**
* @brief _qed_cxt_acquire - Acquire a new cid of a specific protocol type
* for a vf-queue
*
* @param p_hwfn
* @param type
* @param p_cid
* @param vfid - engine relative index. QED_CXT_PF_CID if belongs to PF
*
* @return int
*/
int _qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
enum protocol_type type, u32 *p_cid, u8 vfid);
int qed_cxt_dynamic_ilt_alloc(struct qed_hwfn *p_hwfn,
enum qed_cxt_elem_type elem_type, u32 iid);
u32 qed_cxt_get_proto_tid_count(struct qed_hwfn *p_hwfn,
......
......@@ -69,12 +69,6 @@ static DEFINE_SPINLOCK(qm_lock);
#define QED_MIN_DPIS (4)
#define QED_MIN_PWM_REGION (QED_WID_SIZE * QED_MIN_DPIS)
/* API common to all protocols */
enum BAR_ID {
BAR_ID_0, /* used for GRC */
BAR_ID_1 /* Used for doorbells */
};
static u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, enum BAR_ID bar_id)
{
......@@ -83,7 +77,7 @@ static u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn,
u32 val;
if (IS_VF(p_hwfn->cdev))
return 1 << 17;
return qed_vf_hw_bar_size(p_hwfn, bar_id);
val = qed_rd(p_hwfn, p_ptt, bar_reg);
if (val)
......@@ -154,8 +148,11 @@ void qed_resc_free(struct qed_dev *cdev)
{
int i;
if (IS_VF(cdev))
if (IS_VF(cdev)) {
for_each_hwfn(cdev, i)
qed_l2_free(&cdev->hwfns[i]);
return;
}
kfree(cdev->fw_data);
cdev->fw_data = NULL;
......@@ -183,6 +180,7 @@ void qed_resc_free(struct qed_dev *cdev)
qed_ooo_free(p_hwfn);
}
qed_iov_free(p_hwfn);
qed_l2_free(p_hwfn);
qed_dmae_info_free(p_hwfn);
qed_dcbx_info_free(p_hwfn);
}
......@@ -848,8 +846,14 @@ int qed_resc_alloc(struct qed_dev *cdev)
u32 line_count;
int i, rc = 0;
if (IS_VF(cdev))
if (IS_VF(cdev)) {
for_each_hwfn(cdev, i) {
rc = qed_l2_alloc(&cdev->hwfns[i]);
if (rc)
return rc;
}
return rc;
}
cdev->fw_data = kzalloc(sizeof(*cdev->fw_data), GFP_KERNEL);
if (!cdev->fw_data)
......@@ -960,6 +964,10 @@ int qed_resc_alloc(struct qed_dev *cdev)
if (rc)
goto alloc_err;
rc = qed_l2_alloc(p_hwfn);
if (rc)
goto alloc_err;
#ifdef CONFIG_QED_LL2
if (p_hwfn->using_ll2) {
rc = qed_ll2_alloc(p_hwfn);
......@@ -1011,8 +1019,11 @@ void qed_resc_setup(struct qed_dev *cdev)
{
int i;
if (IS_VF(cdev))
if (IS_VF(cdev)) {
for_each_hwfn(cdev, i)
qed_l2_setup(&cdev->hwfns[i]);
return;
}
for_each_hwfn(cdev, i) {
struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
......@@ -1030,6 +1041,7 @@ void qed_resc_setup(struct qed_dev *cdev)
qed_int_setup(p_hwfn, p_hwfn->p_main_ptt);
qed_l2_setup(p_hwfn);
qed_iov_setup(p_hwfn);
#ifdef CONFIG_QED_LL2
if (p_hwfn->using_ll2)
......
This diff is collapsed.
......@@ -277,40 +277,87 @@ void qed_get_vport_stats(struct qed_dev *cdev, struct qed_eth_stats *stats);
void qed_reset_vport_stats(struct qed_dev *cdev);
struct qed_queue_cid {
/* 'Relative' is a relative term ;-). Usually the indices [not counting
* SBs] would be PF-relative, but there are some cases where that isn't
* the case - specifically for a PF configuring its VF indices it's
* possible some fields [E.g., stats-id] in 'rel' would already be abs.
#define MAX_QUEUES_PER_QZONE (sizeof(unsigned long) * 8)
#define QED_QUEUE_CID_SELF (0xff)
/* Almost identical to the qed_queue_start_common_params,
* but here we maintain the SB index in IGU CAM.
*/
struct qed_queue_cid_params {
u8 vport_id;
u16 queue_id;
u8 stats_id;
};
/* Additional parameters required for initialization of the queue_cid
* and are relevant only for a PF initializing one for its VFs.
*/
struct qed_queue_cid_vf_params {
/* Should match the VF's relative index */
u8 vfid;
/* 0-based queue index. Should reflect the relative qzone the
* VF thinks is associated with it [in its range].
*/
u8 vf_qid;
/* Indicates a VF is legacy, making it differ in several things:
* - Producers would be placed in a different place.
* - Makes assumptions regarding the CIDs.
*/
struct qed_queue_start_common_params rel;
struct qed_queue_start_common_params abs;
u8 vf_legacy;
u8 qid_usage_idx;
};
struct qed_queue_cid {
/* For stats-id, the `rel' is actually absolute as well */
struct qed_queue_cid_params rel;
struct qed_queue_cid_params abs;
/* These have no 'relative' meaning */
u16 sb_igu_id;
u8 sb_idx;
u32 cid;
u16 opaque_fid;
bool b_is_rx;
/* VFs queues are mapped differently, so we need to know the
* relative queue associated with them [0-based].
* Notice this is relevant on the *PF* queue-cid of its VF's queues,
* and not on the VF itself.
*/
bool is_vf;
u8 vfid;
u8 vf_qid;
/* Legacy VFs might have Rx producer located elsewhere */
bool b_legacy_vf;
/* We need an additional index to differentiate between queues opened
* for same queue-zone, as VFs would have to communicate the info
* to the PF [otherwise PF has no way to differentiate].
*/
u8 qid_usage_idx;
u8 vf_legacy;
#define QED_QCID_LEGACY_VF_RX_PROD (BIT(0))
#define QED_QCID_LEGACY_VF_CID (BIT(1))
struct qed_hwfn *p_owner;
};
int qed_l2_alloc(struct qed_hwfn *p_hwfn);
void qed_l2_setup(struct qed_hwfn *p_hwfn);
void qed_l2_free(struct qed_hwfn *p_hwfn);
void qed_eth_queue_cid_release(struct qed_hwfn *p_hwfn,
struct qed_queue_cid *p_cid);
struct qed_queue_cid *_qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn,
u16 opaque_fid,
u32 cid,
u8 vf_qid,
struct qed_queue_start_common_params
*p_params);
struct qed_queue_cid *
qed_eth_queue_to_cid(struct qed_hwfn *p_hwfn,
u16 opaque_fid,
struct qed_queue_start_common_params *p_params,
bool b_is_rx,
struct qed_queue_cid_vf_params *p_vf_params);
int
qed_sp_eth_vport_start(struct qed_hwfn *p_hwfn,
......
......@@ -122,7 +122,7 @@ static void qed_free_pci(struct qed_dev *cdev)
{
struct pci_dev *pdev = cdev->pdev;
if (cdev->doorbells)
if (cdev->doorbells && cdev->db_size)
iounmap(cdev->doorbells);
if (cdev->regview)
iounmap(cdev->regview);
......@@ -206,16 +206,24 @@ static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev)
goto err2;
}
if (IS_PF(cdev)) {
cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2);
cdev->db_size = pci_resource_len(cdev->pdev, 2);
cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size);
if (!cdev->doorbells) {
DP_NOTICE(cdev, "Cannot map doorbell space\n");
return -ENOMEM;
cdev->db_phys_addr = pci_resource_start(cdev->pdev, 2);
cdev->db_size = pci_resource_len(cdev->pdev, 2);
if (!cdev->db_size) {
if (IS_PF(cdev)) {
DP_NOTICE(cdev, "No Doorbell bar available\n");
return -EINVAL;
} else {
return 0;
}
}
cdev->doorbells = ioremap_wc(cdev->db_phys_addr, cdev->db_size);
if (!cdev->doorbells) {
DP_NOTICE(cdev, "Cannot map doorbell space\n");
return -ENOMEM;
}
return 0;
err2:
......
......@@ -560,6 +560,7 @@
0x2aae60UL
#define PGLUE_B_REG_PF_BAR1_SIZE \
0x2aae64UL
#define PGLUE_B_REG_VF_BAR1_SIZE 0x2aae68UL
#define PRS_REG_ENCAPSULATION_TYPE_EN 0x1f0730UL
#define PRS_REG_GRE_PROTOCOL 0x1f0734UL
#define PRS_REG_VXLAN_PORT 0x1f0738UL
......
This diff is collapsed.
......@@ -149,12 +149,21 @@ struct qed_iov_vf_mbx {
struct vfpf_first_tlv first_tlv;
};
struct qed_vf_q_info {
#define QED_IOV_LEGACY_QID_RX (0)
#define QED_IOV_LEGACY_QID_TX (1)
#define QED_IOV_QID_INVALID (0xFE)
struct qed_vf_queue_cid {
bool b_is_tx;
struct qed_queue_cid *p_cid;
};
/* Describes a qzone associated with the VF */
struct qed_vf_queue {
u16 fw_rx_qid;
struct qed_queue_cid *p_rx_cid;
u16 fw_tx_qid;
struct qed_queue_cid *p_tx_cid;
u8 fw_cid;
struct qed_vf_queue_cid cids[MAX_QUEUES_PER_QZONE];
};
enum vf_state {
......@@ -212,7 +221,8 @@ struct qed_vf_info {
u8 num_mac_filters;
u8 num_vlan_filters;
struct qed_vf_q_info vf_queues[QED_MAX_VF_CHAINS_PER_PF];
struct qed_vf_queue vf_queues[QED_MAX_VF_CHAINS_PER_PF];
u16 igu_sbs[QED_MAX_VF_CHAINS_PER_PF];
u8 num_active_rxqs;
struct qed_public_vf_info p_vf_info;
......
This diff is collapsed.
......@@ -46,7 +46,8 @@ struct vf_pf_resc_request {
u8 num_mac_filters;
u8 num_vlan_filters;
u8 num_mc_filters;
u16 padding;
u8 num_cids;
u8 padding;
};
struct hw_sb_info {
......@@ -113,6 +114,17 @@ struct vfpf_acquire_tlv {
struct vf_pf_vfdev_info {
#define VFPF_ACQUIRE_CAP_PRE_FP_HSI (1 << 0) /* VF pre-FP hsi version */
#define VFPF_ACQUIRE_CAP_100G (1 << 1) /* VF can support 100g */
/* A requirement for supporting multi-Tx queues on a single queue-zone,
* VF would pass qids as additional information whenever passing queue
* references.
*/
#define VFPF_ACQUIRE_CAP_QUEUE_QIDS BIT(2)
/* The VF is using the physical bar. While this is mostly internal
* to the VF, might affect the number of CIDs supported assuming
* QUEUE_QIDS is set.
*/
#define VFPF_ACQUIRE_CAP_PHYSICAL_BAR BIT(3)
u64 capabilities;
u8 fw_major;
u8 fw_minor;
......@@ -185,6 +197,9 @@ struct pfvf_acquire_resp_tlv {
*/
#define PFVF_ACQUIRE_CAP_POST_FW_OVERRIDE BIT(2)
/* PF expects queues to be received with additional qids */
#define PFVF_ACQUIRE_CAP_QUEUE_QIDS BIT(3)
u16 db_size;
u8 indices_per_sb;
u8 os_type;
......@@ -193,7 +208,8 @@ struct pfvf_acquire_resp_tlv {
u16 chip_rev;
u8 dev_type;
u8 padding;
/* Doorbell bar size configured in HW: log(size) or 0 */
u8 bar_size;
struct pfvf_stats_info stats_info;
......@@ -221,7 +237,8 @@ struct pfvf_acquire_resp_tlv {
u8 num_mac_filters;
u8 num_vlan_filters;
u8 num_mc_filters;
u8 padding[2];
u8 num_cids;
u8 padding;
} resc;
u32 bulletin_size;
......@@ -234,6 +251,16 @@ struct pfvf_start_queue_resp_tlv {
u8 padding[4];
};
/* Extended queue information - additional index for reference inside qzone.
* If commmunicated between VF/PF, each TLV relating to queues should be
* extended by one such [or have a future base TLV that already contains info].
*/
struct vfpf_qid_tlv {
struct channel_tlv tl;
u8 qid;
u8 padding[3];
};
/* Setup Queue */
struct vfpf_start_rxq_tlv {
struct vfpf_first_tlv first_tlv;
......@@ -597,6 +624,8 @@ enum {
CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN,
CHANNEL_TLV_VPORT_UPDATE_SGE_TPA,
CHANNEL_TLV_UPDATE_TUNN_PARAM,
CHANNEL_TLV_RESERVED,
CHANNEL_TLV_QID,
CHANNEL_TLV_MAX,
/* Required for iterating over vport-update tlvs.
......@@ -605,6 +634,12 @@ enum {
CHANNEL_TLV_VPORT_UPDATE_MAX = CHANNEL_TLV_VPORT_UPDATE_SGE_TPA + 1,
};
/* Default number of CIDs [total of both Rx and Tx] to be requested
* by default, and maximum possible number.
*/
#define QED_ETH_VF_DEFAULT_NUM_CIDS (32)
#define QED_ETH_VF_MAX_NUM_CIDS (250)
/* This data is held in the qed_hwfn structure for VFs only. */
struct qed_vf_iov {
union vfpf_tlvs *vf2pf_request;
......@@ -635,6 +670,11 @@ struct qed_vf_iov {
* compatibility [with older PFs] we'd still need to store these.
*/
struct qed_sb_info *sbs_info[PFVF_MAX_SBS_PER_VF];
/* Determines whether VF utilizes doorbells via limited register
* bar or via the doorbell bar.
*/
bool b_doorbell_bar;
};
#ifdef CONFIG_QED_SRIOV
......@@ -683,6 +723,22 @@ void qed_vf_get_link_caps(struct qed_hwfn *p_hwfn,
*/
void qed_vf_get_num_rxqs(struct qed_hwfn *p_hwfn, u8 *num_rxqs);
/**
* @brief Get number of Rx queues allocated for VF by qed
*
* @param p_hwfn
* @param num_txqs - allocated RX queues
*/
void qed_vf_get_num_txqs(struct qed_hwfn *p_hwfn, u8 *num_txqs);
/**
* @brief Get number of available connections [both Rx and Tx] for VF
*
* @param p_hwfn
* @param num_cids - allocated number of connections
*/
void qed_vf_get_num_cids(struct qed_hwfn *p_hwfn, u8 *num_cids);
/**
* @brief Get port mac address for VF
*
......@@ -935,6 +991,8 @@ void qed_iov_vf_task(struct work_struct *work);
void qed_vf_set_vf_start_tunn_update_param(struct qed_tunnel_info *p_tun);
int qed_vf_pf_tunnel_param_update(struct qed_hwfn *p_hwfn,
struct qed_tunnel_info *p_tunn);
u32 qed_vf_hw_bar_size(struct qed_hwfn *p_hwfn, enum BAR_ID bar_id);
#else
static inline void qed_vf_get_link_params(struct qed_hwfn *p_hwfn,
struct qed_mcp_link_params *params)
......@@ -956,6 +1014,14 @@ static inline void qed_vf_get_num_rxqs(struct qed_hwfn *p_hwfn, u8 *num_rxqs)
{
}
static inline void qed_vf_get_num_txqs(struct qed_hwfn *p_hwfn, u8 *num_txqs)
{
}
static inline void qed_vf_get_num_cids(struct qed_hwfn *p_hwfn, u8 *num_cids)
{
}
static inline void qed_vf_get_port_mac(struct qed_hwfn *p_hwfn, u8 *port_mac)
{
}
......@@ -1107,6 +1173,13 @@ static inline int qed_vf_pf_tunnel_param_update(struct qed_hwfn *p_hwfn,
{
return -EINVAL;
}
static inline u32
qed_vf_hw_bar_size(struct qed_hwfn *p_hwfn,
enum BAR_ID bar_id)
{
return 0;
}
#endif
#endif
......@@ -580,6 +580,24 @@ static const struct net_device_ops qede_netdev_vf_ops = {
.ndo_features_check = qede_features_check,
};
static const struct net_device_ops qede_netdev_vf_xdp_ops = {
.ndo_open = qede_open,
.ndo_stop = qede_close,
.ndo_start_xmit = qede_start_xmit,
.ndo_set_rx_mode = qede_set_rx_mode,
.ndo_set_mac_address = qede_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = qede_change_mtu,
.ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
.ndo_set_features = qede_set_features,
.ndo_get_stats64 = qede_get_stats64,
.ndo_udp_tunnel_add = qede_udp_tunnel_add,
.ndo_udp_tunnel_del = qede_udp_tunnel_del,
.ndo_features_check = qede_features_check,
.ndo_xdp = qede_xdp,
};
/* -------------------------------------------------------------------------
* START OF PROBE / REMOVE
* -------------------------------------------------------------------------
......@@ -645,10 +663,14 @@ static void qede_init_ndev(struct qede_dev *edev)
ndev->watchdog_timeo = TX_TIMEOUT;
if (IS_VF(edev))
ndev->netdev_ops = &qede_netdev_vf_ops;
else
if (IS_VF(edev)) {
if (edev->dev_info.xdp_supported)
ndev->netdev_ops = &qede_netdev_vf_xdp_ops;
else
ndev->netdev_ops = &qede_netdev_vf_ops;
} else {
ndev->netdev_ops = &qede_netdev_ops;
}
qede_set_ethtool_ops(ndev);
......@@ -846,6 +868,12 @@ static void qede_update_pf_params(struct qed_dev *cdev)
/* 64 rx + 64 tx + 64 XDP */
memset(&pf_params, 0, sizeof(struct qed_pf_params));
pf_params.eth_pf_params.num_cons = (MAX_SB_PER_PF_MIMD - 1) * 3;
/* Same for VFs - make sure they'll have sufficient connections
* to support XDP Tx queues.
*/
pf_params.eth_pf_params.num_vf_cons = 48;
#ifdef CONFIG_RFS_ACCEL
pf_params.eth_pf_params.num_arfs_filters = QEDE_RFS_MAX_FLTR;
#endif
......@@ -1770,7 +1798,7 @@ static int qede_start_txq(struct qede_dev *edev,
else
params.queue_id = txq->index;
params.sb = fp->sb_info->igu_sb_id;
params.p_sb = fp->sb_info;
params.sb_idx = sb_idx;
rc = edev->ops->q_tx_start(edev->cdev, rss_id, &params, phys_table,
......@@ -1849,7 +1877,7 @@ static int qede_start_queues(struct qede_dev *edev, bool clear_stats)
memset(&q_params, 0, sizeof(q_params));
q_params.queue_id = rxq->rxq_id;
q_params.vport_id = 0;
q_params.sb = fp->sb_info->igu_sb_id;
q_params.p_sb = fp->sb_info;
q_params.sb_idx = RX_PI;
p_phys_table =
......
......@@ -47,8 +47,7 @@ struct qed_queue_start_common_params {
/* Relative, but relevant only for PFs */
u8 stats_id;
/* These are always absolute */
u16 sb;
struct qed_sb_info *p_sb;
u8 sb_idx;
};
......@@ -74,6 +73,9 @@ struct qed_dev_eth_info {
/* Legacy VF - this affects the datapath, so qede has to know */
bool is_legacy;
/* Might depend on available resources [in case of VF] */
bool xdp_supported;
};
struct qed_update_vport_rss_params {
......
......@@ -185,6 +185,10 @@ struct qed_eth_pf_params {
*/
u16 num_cons;
/* per-VF number of CIDs */
u8 num_vf_cons;
#define ETH_PF_PARAMS_VF_CONS_DEFAULT (32)
/* To enable arfs, previous to HW-init a positive number needs to be
* set [as filters require allocated searcher ILT memory].
* This will set the maximal number of configured steering-filters.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment