Commit 7fc3b978 authored by David S. Miller's avatar David S. Miller

Merge branch 'qed-qede-improve-chain-API-and-add-XDP_REDIRECT-support'

Alexander Lobakin says:

====================
qed, qede: improve chain API and add XDP_REDIRECT support

This series adds missing XDP_REDIRECT case handling in QLogic Everest
Ethernet driver with all necessary prerequisites and ops.
QEDE Tx relies heavily on chain API, so make sure it is in its best
at first.

v2 (from [1]):
 - add missing includes to #003 to pass the build on Alpha;
 - no functional changes.

[1] https://lore.kernel.org/netdev/20200722155349.747-1-alobakin@marvell.com/
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f1fa27f5 d1b25b79
......@@ -346,9 +346,14 @@ static void qedr_free_resources(struct qedr_dev *dev)
static int qedr_alloc_resources(struct qedr_dev *dev)
{
struct qed_chain_init_params params = {
.mode = QED_CHAIN_MODE_PBL,
.intended_use = QED_CHAIN_USE_TO_CONSUME,
.cnt_type = QED_CHAIN_CNT_TYPE_U16,
.elem_size = sizeof(struct regpair *),
};
struct qedr_cnq *cnq;
__le16 *cons_pi;
u16 n_entries;
int i, rc;
dev->sgid_tbl = kcalloc(QEDR_MAX_SGID, sizeof(union ib_gid),
......@@ -382,7 +387,9 @@ static int qedr_alloc_resources(struct qedr_dev *dev)
dev->sb_start = dev->ops->rdma_get_start_sb(dev->cdev);
/* Allocate CNQ PBLs */
n_entries = min_t(u32, QED_RDMA_MAX_CNQ_SIZE, QEDR_ROCE_MAX_CNQ_SIZE);
params.num_elems = min_t(u32, QED_RDMA_MAX_CNQ_SIZE,
QEDR_ROCE_MAX_CNQ_SIZE);
for (i = 0; i < dev->num_cnq; i++) {
cnq = &dev->cnq_array[i];
......@@ -391,13 +398,8 @@ static int qedr_alloc_resources(struct qedr_dev *dev)
if (rc)
goto err3;
rc = dev->ops->common->chain_alloc(dev->cdev,
QED_CHAIN_USE_TO_CONSUME,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U16,
n_entries,
sizeof(struct regpair *),
&cnq->pbl, NULL);
rc = dev->ops->common->chain_alloc(dev->cdev, &cnq->pbl,
&params);
if (rc)
goto err4;
......
......@@ -891,6 +891,12 @@ int qedr_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
udata, struct qedr_ucontext, ibucontext);
struct qed_rdma_destroy_cq_out_params destroy_oparams;
struct qed_rdma_destroy_cq_in_params destroy_iparams;
struct qed_chain_init_params chain_params = {
.mode = QED_CHAIN_MODE_PBL,
.intended_use = QED_CHAIN_USE_TO_CONSUME,
.cnt_type = QED_CHAIN_CNT_TYPE_U32,
.elem_size = sizeof(union rdma_cqe),
};
struct qedr_dev *dev = get_qedr_dev(ibdev);
struct qed_rdma_create_cq_in_params params;
struct qedr_create_cq_ureq ureq = {};
......@@ -917,6 +923,7 @@ int qedr_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
chain_entries = qedr_align_cq_entries(entries);
chain_entries = min_t(int, chain_entries, QEDR_MAX_CQES);
chain_params.num_elems = chain_entries;
/* calc db offset. user will add DPI base, kernel will add db addr */
db_offset = DB_ADDR_SHIFT(DQ_PWM_OFFSET_UCM_RDMA_CQ_CONS_32BIT);
......@@ -951,13 +958,8 @@ int qedr_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
} else {
cq->cq_type = QEDR_CQ_TYPE_KERNEL;
rc = dev->ops->common->chain_alloc(dev->cdev,
QED_CHAIN_USE_TO_CONSUME,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U32,
chain_entries,
sizeof(union rdma_cqe),
&cq->pbl, NULL);
rc = dev->ops->common->chain_alloc(dev->cdev, &cq->pbl,
&chain_params);
if (rc)
goto err0;
......@@ -1446,6 +1448,12 @@ static int qedr_alloc_srq_kernel_params(struct qedr_srq *srq,
struct ib_srq_init_attr *init_attr)
{
struct qedr_srq_hwq_info *hw_srq = &srq->hw_srq;
struct qed_chain_init_params params = {
.mode = QED_CHAIN_MODE_PBL,
.intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE,
.cnt_type = QED_CHAIN_CNT_TYPE_U32,
.elem_size = QEDR_SRQ_WQE_ELEM_SIZE,
};
dma_addr_t phy_prod_pair_addr;
u32 num_elems;
void *va;
......@@ -1464,13 +1472,9 @@ static int qedr_alloc_srq_kernel_params(struct qedr_srq *srq,
hw_srq->virt_prod_pair_addr = va;
num_elems = init_attr->attr.max_wr * RDMA_MAX_SRQ_WQE_SIZE;
rc = dev->ops->common->chain_alloc(dev->cdev,
QED_CHAIN_USE_TO_CONSUME_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U32,
num_elems,
QEDR_SRQ_WQE_ELEM_SIZE,
&hw_srq->pbl, NULL);
params.num_elems = num_elems;
rc = dev->ops->common->chain_alloc(dev->cdev, &hw_srq->pbl, &params);
if (rc)
goto err0;
......@@ -1901,29 +1905,28 @@ qedr_roce_create_kernel_qp(struct qedr_dev *dev,
u32 n_sq_elems, u32 n_rq_elems)
{
struct qed_rdma_create_qp_out_params out_params;
struct qed_chain_init_params params = {
.mode = QED_CHAIN_MODE_PBL,
.cnt_type = QED_CHAIN_CNT_TYPE_U32,
};
int rc;
rc = dev->ops->common->chain_alloc(dev->cdev,
QED_CHAIN_USE_TO_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U32,
n_sq_elems,
QEDR_SQE_ELEMENT_SIZE,
&qp->sq.pbl, NULL);
params.intended_use = QED_CHAIN_USE_TO_PRODUCE;
params.num_elems = n_sq_elems;
params.elem_size = QEDR_SQE_ELEMENT_SIZE;
rc = dev->ops->common->chain_alloc(dev->cdev, &qp->sq.pbl, &params);
if (rc)
return rc;
in_params->sq_num_pages = qed_chain_get_page_cnt(&qp->sq.pbl);
in_params->sq_pbl_ptr = qed_chain_get_pbl_phys(&qp->sq.pbl);
rc = dev->ops->common->chain_alloc(dev->cdev,
QED_CHAIN_USE_TO_CONSUME_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U32,
n_rq_elems,
QEDR_RQE_ELEMENT_SIZE,
&qp->rq.pbl, NULL);
params.intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE;
params.elem_size = n_rq_elems;
params.elem_size = QEDR_RQE_ELEMENT_SIZE;
rc = dev->ops->common->chain_alloc(dev->cdev, &qp->rq.pbl, &params);
if (rc)
return rc;
......@@ -1949,14 +1952,19 @@ qedr_iwarp_create_kernel_qp(struct qedr_dev *dev,
u32 n_sq_elems, u32 n_rq_elems)
{
struct qed_rdma_create_qp_out_params out_params;
struct qed_chain_ext_pbl ext_pbl;
struct qed_chain_init_params params = {
.mode = QED_CHAIN_MODE_PBL,
.cnt_type = QED_CHAIN_CNT_TYPE_U32,
};
int rc;
in_params->sq_num_pages = QED_CHAIN_PAGE_CNT(n_sq_elems,
QEDR_SQE_ELEMENT_SIZE,
QED_CHAIN_PAGE_SIZE,
QED_CHAIN_MODE_PBL);
in_params->rq_num_pages = QED_CHAIN_PAGE_CNT(n_rq_elems,
QEDR_RQE_ELEMENT_SIZE,
QED_CHAIN_PAGE_SIZE,
QED_CHAIN_MODE_PBL);
qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx,
......@@ -1966,31 +1974,24 @@ qedr_iwarp_create_kernel_qp(struct qedr_dev *dev,
return -EINVAL;
/* Now we allocate the chain */
ext_pbl.p_pbl_virt = out_params.sq_pbl_virt;
ext_pbl.p_pbl_phys = out_params.sq_pbl_phys;
rc = dev->ops->common->chain_alloc(dev->cdev,
QED_CHAIN_USE_TO_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U32,
n_sq_elems,
QEDR_SQE_ELEMENT_SIZE,
&qp->sq.pbl, &ext_pbl);
params.intended_use = QED_CHAIN_USE_TO_PRODUCE;
params.num_elems = n_sq_elems;
params.elem_size = QEDR_SQE_ELEMENT_SIZE;
params.ext_pbl_virt = out_params.sq_pbl_virt;
params.ext_pbl_phys = out_params.sq_pbl_phys;
rc = dev->ops->common->chain_alloc(dev->cdev, &qp->sq.pbl, &params);
if (rc)
goto err;
ext_pbl.p_pbl_virt = out_params.rq_pbl_virt;
ext_pbl.p_pbl_phys = out_params.rq_pbl_phys;
rc = dev->ops->common->chain_alloc(dev->cdev,
QED_CHAIN_USE_TO_CONSUME_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U32,
n_rq_elems,
QEDR_RQE_ELEMENT_SIZE,
&qp->rq.pbl, &ext_pbl);
params.intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE;
params.num_elems = n_rq_elems;
params.elem_size = QEDR_RQE_ELEMENT_SIZE;
params.ext_pbl_virt = out_params.rq_pbl_virt;
params.ext_pbl_phys = out_params.rq_pbl_phys;
rc = dev->ops->common->chain_alloc(dev->cdev, &qp->rq.pbl, &params);
if (rc)
goto err;
......
......@@ -3,12 +3,35 @@
obj-$(CONFIG_QED) := qed.o
qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \
qed_int.o qed_main.o qed_mcp.o qed_sp_commands.o qed_spq.o qed_l2.o \
qed_selftest.o qed_dcbx.o qed_debug.o qed_ptp.o qed_mng_tlv.o
qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
qed-$(CONFIG_QED_LL2) += qed_ll2.o
qed-$(CONFIG_QED_RDMA) += qed_roce.o qed_rdma.o qed_iwarp.o
qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o
qed-y := \
qed_chain.o \
qed_cxt.o \
qed_dcbx.o \
qed_debug.o \
qed_dev.o \
qed_hw.o \
qed_init_fw_funcs.o \
qed_init_ops.o \
qed_int.o \
qed_l2.o \
qed_main.o \
qed_mcp.o \
qed_mng_tlv.o \
qed_ptp.o \
qed_selftest.o \
qed_sp_commands.o \
qed_spq.o
qed-$(CONFIG_QED_FCOE) += qed_fcoe.o
qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o
qed-$(CONFIG_QED_LL2) += qed_ll2.o
qed-$(CONFIG_QED_OOO) += qed_ooo.o
qed-$(CONFIG_QED_RDMA) += \
qed_iwarp.o \
qed_rdma.o \
qed_roce.o
qed-$(CONFIG_QED_SRIOV) += \
qed_sriov.o \
qed_vf.o
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
/* Copyright (c) 2020 Marvell International Ltd. */
#include <linux/dma-mapping.h>
#include <linux/qed/qed_chain.h>
#include <linux/vmalloc.h>
#include "qed_dev_api.h"
static void qed_chain_init(struct qed_chain *chain,
const struct qed_chain_init_params *params,
u32 page_cnt)
{
memset(chain, 0, sizeof(*chain));
chain->elem_size = params->elem_size;
chain->intended_use = params->intended_use;
chain->mode = params->mode;
chain->cnt_type = params->cnt_type;
chain->elem_per_page = ELEMS_PER_PAGE(params->elem_size,
params->page_size);
chain->usable_per_page = USABLE_ELEMS_PER_PAGE(params->elem_size,
params->page_size,
params->mode);
chain->elem_unusable = UNUSABLE_ELEMS_PER_PAGE(params->elem_size,
params->mode);
chain->elem_per_page_mask = chain->elem_per_page - 1;
chain->next_page_mask = chain->usable_per_page &
chain->elem_per_page_mask;
chain->page_size = params->page_size;
chain->page_cnt = page_cnt;
chain->capacity = chain->usable_per_page * page_cnt;
chain->size = chain->elem_per_page * page_cnt;
if (params->ext_pbl_virt) {
chain->pbl_sp.table_virt = params->ext_pbl_virt;
chain->pbl_sp.table_phys = params->ext_pbl_phys;
chain->b_external_pbl = true;
}
}
static void qed_chain_init_next_ptr_elem(const struct qed_chain *chain,
void *virt_curr, void *virt_next,
dma_addr_t phys_next)
{
struct qed_chain_next *next;
u32 size;
size = chain->elem_size * chain->usable_per_page;
next = virt_curr + size;
DMA_REGPAIR_LE(next->next_phys, phys_next);
next->next_virt = virt_next;
}
static void qed_chain_init_mem(struct qed_chain *chain, void *virt_addr,
dma_addr_t phys_addr)
{
chain->p_virt_addr = virt_addr;
chain->p_phys_addr = phys_addr;
}
static void qed_chain_free_next_ptr(struct qed_dev *cdev,
struct qed_chain *chain)
{
struct device *dev = &cdev->pdev->dev;
struct qed_chain_next *next;
dma_addr_t phys, phys_next;
void *virt, *virt_next;
u32 size, i;
size = chain->elem_size * chain->usable_per_page;
virt = chain->p_virt_addr;
phys = chain->p_phys_addr;
for (i = 0; i < chain->page_cnt; i++) {
if (!virt)
break;
next = virt + size;
virt_next = next->next_virt;
phys_next = HILO_DMA_REGPAIR(next->next_phys);
dma_free_coherent(dev, chain->page_size, virt, phys);
virt = virt_next;
phys = phys_next;
}
}
static void qed_chain_free_single(struct qed_dev *cdev,
struct qed_chain *chain)
{
if (!chain->p_virt_addr)
return;
dma_free_coherent(&cdev->pdev->dev, chain->page_size,
chain->p_virt_addr, chain->p_phys_addr);
}
static void qed_chain_free_pbl(struct qed_dev *cdev, struct qed_chain *chain)
{
struct device *dev = &cdev->pdev->dev;
struct addr_tbl_entry *entry;
u32 i;
if (!chain->pbl.pp_addr_tbl)
return;
for (i = 0; i < chain->page_cnt; i++) {
entry = chain->pbl.pp_addr_tbl + i;
if (!entry->virt_addr)
break;
dma_free_coherent(dev, chain->page_size, entry->virt_addr,
entry->dma_map);
}
if (!chain->b_external_pbl)
dma_free_coherent(dev, chain->pbl_sp.table_size,
chain->pbl_sp.table_virt,
chain->pbl_sp.table_phys);
vfree(chain->pbl.pp_addr_tbl);
chain->pbl.pp_addr_tbl = NULL;
}
/**
* qed_chain_free() - Free chain DMA memory.
*
* @cdev: Main device structure.
* @chain: Chain to free.
*/
void qed_chain_free(struct qed_dev *cdev, struct qed_chain *chain)
{
switch (chain->mode) {
case QED_CHAIN_MODE_NEXT_PTR:
qed_chain_free_next_ptr(cdev, chain);
break;
case QED_CHAIN_MODE_SINGLE:
qed_chain_free_single(cdev, chain);
break;
case QED_CHAIN_MODE_PBL:
qed_chain_free_pbl(cdev, chain);
break;
default:
return;
}
qed_chain_init_mem(chain, NULL, 0);
}
static int
qed_chain_alloc_sanity_check(struct qed_dev *cdev,
const struct qed_chain_init_params *params,
u32 page_cnt)
{
u64 chain_size;
chain_size = ELEMS_PER_PAGE(params->elem_size, params->page_size);
chain_size *= page_cnt;
if (!chain_size)
return -EINVAL;
/* The actual chain size can be larger than the maximal possible value
* after rounding up the requested elements number to pages, and after
* taking into account the unusuable elements (next-ptr elements).
* The size of a "u16" chain can be (U16_MAX + 1) since the chain
* size/capacity fields are of u32 type.
*/
switch (params->cnt_type) {
case QED_CHAIN_CNT_TYPE_U16:
if (chain_size > U16_MAX + 1)
break;
return 0;
case QED_CHAIN_CNT_TYPE_U32:
if (chain_size > U32_MAX)
break;
return 0;
default:
return -EINVAL;
}
DP_NOTICE(cdev,
"The actual chain size (0x%llx) is larger than the maximal possible value\n",
chain_size);
return -EINVAL;
}
static int qed_chain_alloc_next_ptr(struct qed_dev *cdev,
struct qed_chain *chain)
{
struct device *dev = &cdev->pdev->dev;
void *virt, *virt_prev = NULL;
dma_addr_t phys;
u32 i;
for (i = 0; i < chain->page_cnt; i++) {
virt = dma_alloc_coherent(dev, chain->page_size, &phys,
GFP_KERNEL);
if (!virt)
return -ENOMEM;
if (i == 0) {
qed_chain_init_mem(chain, virt, phys);
qed_chain_reset(chain);
} else {
qed_chain_init_next_ptr_elem(chain, virt_prev, virt,
phys);
}
virt_prev = virt;
}
/* Last page's next element should point to the beginning of the
* chain.
*/
qed_chain_init_next_ptr_elem(chain, virt_prev, chain->p_virt_addr,
chain->p_phys_addr);
return 0;
}
static int qed_chain_alloc_single(struct qed_dev *cdev,
struct qed_chain *chain)
{
dma_addr_t phys;
void *virt;
virt = dma_alloc_coherent(&cdev->pdev->dev, chain->page_size,
&phys, GFP_KERNEL);
if (!virt)
return -ENOMEM;
qed_chain_init_mem(chain, virt, phys);
qed_chain_reset(chain);
return 0;
}
static int qed_chain_alloc_pbl(struct qed_dev *cdev, struct qed_chain *chain)
{
struct device *dev = &cdev->pdev->dev;
struct addr_tbl_entry *addr_tbl;
dma_addr_t phys, pbl_phys;
__le64 *pbl_virt;
u32 page_cnt, i;
size_t size;
void *virt;
page_cnt = chain->page_cnt;
size = array_size(page_cnt, sizeof(*addr_tbl));
if (unlikely(size == SIZE_MAX))
return -EOVERFLOW;
addr_tbl = vzalloc(size);
if (!addr_tbl)
return -ENOMEM;
chain->pbl.pp_addr_tbl = addr_tbl;
if (chain->b_external_pbl)
goto alloc_pages;
size = array_size(page_cnt, sizeof(*pbl_virt));
if (unlikely(size == SIZE_MAX))
return -EOVERFLOW;
pbl_virt = dma_alloc_coherent(dev, size, &pbl_phys, GFP_KERNEL);
if (!pbl_virt)
return -ENOMEM;
chain->pbl_sp.table_virt = pbl_virt;
chain->pbl_sp.table_phys = pbl_phys;
chain->pbl_sp.table_size = size;
alloc_pages:
for (i = 0; i < page_cnt; i++) {
virt = dma_alloc_coherent(dev, chain->page_size, &phys,
GFP_KERNEL);
if (!virt)
return -ENOMEM;
if (i == 0) {
qed_chain_init_mem(chain, virt, phys);
qed_chain_reset(chain);
}
/* Fill the PBL table with the physical address of the page */
pbl_virt[i] = cpu_to_le64(phys);
/* Keep the virtual address of the page */
addr_tbl[i].virt_addr = virt;
addr_tbl[i].dma_map = phys;
}
return 0;
}
/**
* qed_chain_alloc() - Allocate and initialize a chain.
*
* @cdev: Main device structure.
* @chain: Chain to be processed.
* @params: Chain initialization parameters.
*
* Return: 0 on success, negative errno otherwise.
*/
int qed_chain_alloc(struct qed_dev *cdev, struct qed_chain *chain,
struct qed_chain_init_params *params)
{
u32 page_cnt;
int rc;
if (!params->page_size)
params->page_size = QED_CHAIN_PAGE_SIZE;
if (params->mode == QED_CHAIN_MODE_SINGLE)
page_cnt = 1;
else
page_cnt = QED_CHAIN_PAGE_CNT(params->num_elems,
params->elem_size,
params->page_size,
params->mode);
rc = qed_chain_alloc_sanity_check(cdev, params, page_cnt);
if (rc) {
DP_NOTICE(cdev,
"Cannot allocate a chain with the given arguments:\n");
DP_NOTICE(cdev,
"[use_mode %d, mode %d, cnt_type %d, num_elems %d, elem_size %zu, page_size %u]\n",
params->intended_use, params->mode, params->cnt_type,
params->num_elems, params->elem_size,
params->page_size);
return rc;
}
qed_chain_init(chain, params, page_cnt);
switch (params->mode) {
case QED_CHAIN_MODE_NEXT_PTR:
rc = qed_chain_alloc_next_ptr(cdev, chain);
break;
case QED_CHAIN_MODE_SINGLE:
rc = qed_chain_alloc_single(cdev, chain);
break;
case QED_CHAIN_MODE_PBL:
rc = qed_chain_alloc_pbl(cdev, chain);
break;
default:
return -EINVAL;
}
if (!rc)
return 0;
qed_chain_free(cdev, chain);
return rc;
}
......@@ -4716,279 +4716,6 @@ void qed_hw_remove(struct qed_dev *cdev)
qed_mcp_nvm_info_free(p_hwfn);
}
static void qed_chain_free_next_ptr(struct qed_dev *cdev,
struct qed_chain *p_chain)
{
void *p_virt = p_chain->p_virt_addr, *p_virt_next = NULL;
dma_addr_t p_phys = p_chain->p_phys_addr, p_phys_next = 0;
struct qed_chain_next *p_next;
u32 size, i;
if (!p_virt)
return;
size = p_chain->elem_size * p_chain->usable_per_page;
for (i = 0; i < p_chain->page_cnt; i++) {
if (!p_virt)
break;
p_next = (struct qed_chain_next *)((u8 *)p_virt + size);
p_virt_next = p_next->next_virt;
p_phys_next = HILO_DMA_REGPAIR(p_next->next_phys);
dma_free_coherent(&cdev->pdev->dev,
QED_CHAIN_PAGE_SIZE, p_virt, p_phys);
p_virt = p_virt_next;
p_phys = p_phys_next;
}
}
static void qed_chain_free_single(struct qed_dev *cdev,
struct qed_chain *p_chain)
{
if (!p_chain->p_virt_addr)
return;
dma_free_coherent(&cdev->pdev->dev,
QED_CHAIN_PAGE_SIZE,
p_chain->p_virt_addr, p_chain->p_phys_addr);
}
static void qed_chain_free_pbl(struct qed_dev *cdev, struct qed_chain *p_chain)
{
struct addr_tbl_entry *pp_addr_tbl = p_chain->pbl.pp_addr_tbl;
u32 page_cnt = p_chain->page_cnt, i, pbl_size;
if (!pp_addr_tbl)
return;
for (i = 0; i < page_cnt; i++) {
if (!pp_addr_tbl[i].virt_addr || !pp_addr_tbl[i].dma_map)
break;
dma_free_coherent(&cdev->pdev->dev,
QED_CHAIN_PAGE_SIZE,
pp_addr_tbl[i].virt_addr,
pp_addr_tbl[i].dma_map);
}
pbl_size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE;
if (!p_chain->b_external_pbl)
dma_free_coherent(&cdev->pdev->dev,
pbl_size,
p_chain->pbl_sp.p_virt_table,
p_chain->pbl_sp.p_phys_table);
vfree(p_chain->pbl.pp_addr_tbl);
p_chain->pbl.pp_addr_tbl = NULL;
}
void qed_chain_free(struct qed_dev *cdev, struct qed_chain *p_chain)
{
switch (p_chain->mode) {
case QED_CHAIN_MODE_NEXT_PTR:
qed_chain_free_next_ptr(cdev, p_chain);
break;
case QED_CHAIN_MODE_SINGLE:
qed_chain_free_single(cdev, p_chain);
break;
case QED_CHAIN_MODE_PBL:
qed_chain_free_pbl(cdev, p_chain);
break;
}
}
static int
qed_chain_alloc_sanity_check(struct qed_dev *cdev,
enum qed_chain_cnt_type cnt_type,
size_t elem_size, u32 page_cnt)
{
u64 chain_size = ELEMS_PER_PAGE(elem_size) * page_cnt;
/* The actual chain size can be larger than the maximal possible value
* after rounding up the requested elements number to pages, and after
* taking into acount the unusuable elements (next-ptr elements).
* The size of a "u16" chain can be (U16_MAX + 1) since the chain
* size/capacity fields are of a u32 type.
*/
if ((cnt_type == QED_CHAIN_CNT_TYPE_U16 &&
chain_size > ((u32)U16_MAX + 1)) ||
(cnt_type == QED_CHAIN_CNT_TYPE_U32 && chain_size > U32_MAX)) {
DP_NOTICE(cdev,
"The actual chain size (0x%llx) is larger than the maximal possible value\n",
chain_size);
return -EINVAL;
}
return 0;
}
static int
qed_chain_alloc_next_ptr(struct qed_dev *cdev, struct qed_chain *p_chain)
{
void *p_virt = NULL, *p_virt_prev = NULL;
dma_addr_t p_phys = 0;
u32 i;
for (i = 0; i < p_chain->page_cnt; i++) {
p_virt = dma_alloc_coherent(&cdev->pdev->dev,
QED_CHAIN_PAGE_SIZE,
&p_phys, GFP_KERNEL);
if (!p_virt)
return -ENOMEM;
if (i == 0) {
qed_chain_init_mem(p_chain, p_virt, p_phys);
qed_chain_reset(p_chain);
} else {
qed_chain_init_next_ptr_elem(p_chain, p_virt_prev,
p_virt, p_phys);
}
p_virt_prev = p_virt;
}
/* Last page's next element should point to the beginning of the
* chain.
*/
qed_chain_init_next_ptr_elem(p_chain, p_virt_prev,
p_chain->p_virt_addr,
p_chain->p_phys_addr);
return 0;
}
static int
qed_chain_alloc_single(struct qed_dev *cdev, struct qed_chain *p_chain)
{
dma_addr_t p_phys = 0;
void *p_virt = NULL;
p_virt = dma_alloc_coherent(&cdev->pdev->dev,
QED_CHAIN_PAGE_SIZE, &p_phys, GFP_KERNEL);
if (!p_virt)
return -ENOMEM;
qed_chain_init_mem(p_chain, p_virt, p_phys);
qed_chain_reset(p_chain);
return 0;
}
static int
qed_chain_alloc_pbl(struct qed_dev *cdev,
struct qed_chain *p_chain,
struct qed_chain_ext_pbl *ext_pbl)
{
u32 page_cnt = p_chain->page_cnt, size, i;
dma_addr_t p_phys = 0, p_pbl_phys = 0;
struct addr_tbl_entry *pp_addr_tbl;
u8 *p_pbl_virt = NULL;
void *p_virt = NULL;
size = page_cnt * sizeof(*pp_addr_tbl);
pp_addr_tbl = vzalloc(size);
if (!pp_addr_tbl)
return -ENOMEM;
/* The allocation of the PBL table is done with its full size, since it
* is expected to be successive.
* qed_chain_init_pbl_mem() is called even in a case of an allocation
* failure, since tbl was previously allocated, and it
* should be saved to allow its freeing during the error flow.
*/
size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE;
if (!ext_pbl) {
p_pbl_virt = dma_alloc_coherent(&cdev->pdev->dev,
size, &p_pbl_phys, GFP_KERNEL);
} else {
p_pbl_virt = ext_pbl->p_pbl_virt;
p_pbl_phys = ext_pbl->p_pbl_phys;
p_chain->b_external_pbl = true;
}
qed_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys, pp_addr_tbl);
if (!p_pbl_virt)
return -ENOMEM;
for (i = 0; i < page_cnt; i++) {
p_virt = dma_alloc_coherent(&cdev->pdev->dev,
QED_CHAIN_PAGE_SIZE,
&p_phys, GFP_KERNEL);
if (!p_virt)
return -ENOMEM;
if (i == 0) {
qed_chain_init_mem(p_chain, p_virt, p_phys);
qed_chain_reset(p_chain);
}
/* Fill the PBL table with the physical address of the page */
*(dma_addr_t *)p_pbl_virt = p_phys;
/* Keep the virtual address of the page */
p_chain->pbl.pp_addr_tbl[i].virt_addr = p_virt;
p_chain->pbl.pp_addr_tbl[i].dma_map = p_phys;
p_pbl_virt += QED_CHAIN_PBL_ENTRY_SIZE;
}
return 0;
}
int qed_chain_alloc(struct qed_dev *cdev,
enum qed_chain_use_mode intended_use,
enum qed_chain_mode mode,
enum qed_chain_cnt_type cnt_type,
u32 num_elems,
size_t elem_size,
struct qed_chain *p_chain,
struct qed_chain_ext_pbl *ext_pbl)
{
u32 page_cnt;
int rc = 0;
if (mode == QED_CHAIN_MODE_SINGLE)
page_cnt = 1;
else
page_cnt = QED_CHAIN_PAGE_CNT(num_elems, elem_size, mode);
rc = qed_chain_alloc_sanity_check(cdev, cnt_type, elem_size, page_cnt);
if (rc) {
DP_NOTICE(cdev,
"Cannot allocate a chain with the given arguments:\n");
DP_NOTICE(cdev,
"[use_mode %d, mode %d, cnt_type %d, num_elems %d, elem_size %zu]\n",
intended_use, mode, cnt_type, num_elems, elem_size);
return rc;
}
qed_chain_init_params(p_chain, page_cnt, (u8) elem_size, intended_use,
mode, cnt_type);
switch (mode) {
case QED_CHAIN_MODE_NEXT_PTR:
rc = qed_chain_alloc_next_ptr(cdev, p_chain);
break;
case QED_CHAIN_MODE_SINGLE:
rc = qed_chain_alloc_single(cdev, p_chain);
break;
case QED_CHAIN_MODE_PBL:
rc = qed_chain_alloc_pbl(cdev, p_chain, ext_pbl);
break;
}
if (rc)
goto nomem;
return 0;
nomem:
qed_chain_free(cdev, p_chain);
return rc;
}
int qed_fw_l2_queue(struct qed_hwfn *p_hwfn, u16 src_id, u16 *dst_id)
{
if (src_id >= RESC_NUM(p_hwfn, QED_L2_QUEUE)) {
......
......@@ -254,35 +254,9 @@ int qed_dmae_host2host(struct qed_hwfn *p_hwfn,
dma_addr_t dest_addr,
u32 size_in_dwords, struct qed_dmae_params *p_params);
/**
* @brief qed_chain_alloc - Allocate and initialize a chain
*
* @param p_hwfn
* @param intended_use
* @param mode
* @param num_elems
* @param elem_size
* @param p_chain
* @param ext_pbl - a possible external PBL
*
* @return int
*/
int
qed_chain_alloc(struct qed_dev *cdev,
enum qed_chain_use_mode intended_use,
enum qed_chain_mode mode,
enum qed_chain_cnt_type cnt_type,
u32 num_elems,
size_t elem_size,
struct qed_chain *p_chain, struct qed_chain_ext_pbl *ext_pbl);
/**
* @brief qed_chain_free - Free chain DMA memory
*
* @param p_hwfn
* @param p_chain
*/
void qed_chain_free(struct qed_dev *cdev, struct qed_chain *p_chain);
int qed_chain_alloc(struct qed_dev *cdev, struct qed_chain *chain,
struct qed_chain_init_params *params);
void qed_chain_free(struct qed_dev *cdev, struct qed_chain *chain);
/**
* @@brief qed_fw_l2_queue - Get absolute L2 queue ID
......
......@@ -684,9 +684,13 @@ static int qed_iscsi_setup_connection(struct qed_iscsi_conn *p_conn)
static int qed_iscsi_allocate_connection(struct qed_hwfn *p_hwfn,
struct qed_iscsi_conn **p_out_conn)
{
u16 uhq_num_elements = 0, xhq_num_elements = 0, r2tq_num_elements = 0;
struct scsi_terminate_extra_params *p_q_cnts = NULL;
struct qed_iscsi_pf_params *p_params = NULL;
struct qed_chain_init_params params = {
.mode = QED_CHAIN_MODE_PBL,
.intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE,
.cnt_type = QED_CHAIN_CNT_TYPE_U16,
};
struct tcp_upload_params *p_tcp = NULL;
struct qed_iscsi_conn *p_conn = NULL;
int rc = 0;
......@@ -727,34 +731,25 @@ static int qed_iscsi_allocate_connection(struct qed_hwfn *p_hwfn,
goto nomem_upload_param;
p_conn->tcp_upload_params_virt_addr = p_tcp;
r2tq_num_elements = p_params->num_r2tq_pages_in_ring *
QED_CHAIN_PAGE_SIZE / 0x80;
rc = qed_chain_alloc(p_hwfn->cdev,
QED_CHAIN_USE_TO_CONSUME_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U16,
r2tq_num_elements, 0x80, &p_conn->r2tq, NULL);
params.num_elems = p_params->num_r2tq_pages_in_ring *
QED_CHAIN_PAGE_SIZE / sizeof(struct iscsi_wqe);
params.elem_size = sizeof(struct iscsi_wqe);
rc = qed_chain_alloc(p_hwfn->cdev, &p_conn->r2tq, &params);
if (rc)
goto nomem_r2tq;
uhq_num_elements = p_params->num_uhq_pages_in_ring *
params.num_elems = p_params->num_uhq_pages_in_ring *
QED_CHAIN_PAGE_SIZE / sizeof(struct iscsi_uhqe);
rc = qed_chain_alloc(p_hwfn->cdev,
QED_CHAIN_USE_TO_CONSUME_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U16,
uhq_num_elements,
sizeof(struct iscsi_uhqe), &p_conn->uhq, NULL);
params.elem_size = sizeof(struct iscsi_uhqe);
rc = qed_chain_alloc(p_hwfn->cdev, &p_conn->uhq, &params);
if (rc)
goto nomem_uhq;
xhq_num_elements = uhq_num_elements;
rc = qed_chain_alloc(p_hwfn->cdev,
QED_CHAIN_USE_TO_CONSUME_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U16,
xhq_num_elements,
sizeof(struct iscsi_xhqe), &p_conn->xhq, NULL);
params.elem_size = sizeof(struct iscsi_xhqe);
rc = qed_chain_alloc(p_hwfn->cdev, &p_conn->xhq, &params);
if (rc)
goto nomem;
......
......@@ -1125,6 +1125,12 @@ static int
qed_ll2_acquire_connection_rx(struct qed_hwfn *p_hwfn,
struct qed_ll2_info *p_ll2_info)
{
struct qed_chain_init_params params = {
.intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE,
.cnt_type = QED_CHAIN_CNT_TYPE_U16,
.num_elems = p_ll2_info->input.rx_num_desc,
};
struct qed_dev *cdev = p_hwfn->cdev;
struct qed_ll2_rx_packet *p_descq;
u32 capacity;
int rc = 0;
......@@ -1132,13 +1138,10 @@ qed_ll2_acquire_connection_rx(struct qed_hwfn *p_hwfn,
if (!p_ll2_info->input.rx_num_desc)
goto out;
rc = qed_chain_alloc(p_hwfn->cdev,
QED_CHAIN_USE_TO_CONSUME_PRODUCE,
QED_CHAIN_MODE_NEXT_PTR,
QED_CHAIN_CNT_TYPE_U16,
p_ll2_info->input.rx_num_desc,
sizeof(struct core_rx_bd),
&p_ll2_info->rx_queue.rxq_chain, NULL);
params.mode = QED_CHAIN_MODE_NEXT_PTR;
params.elem_size = sizeof(struct core_rx_bd);
rc = qed_chain_alloc(cdev, &p_ll2_info->rx_queue.rxq_chain, &params);
if (rc) {
DP_NOTICE(p_hwfn, "Failed to allocate ll2 rxq chain\n");
goto out;
......@@ -1154,13 +1157,10 @@ qed_ll2_acquire_connection_rx(struct qed_hwfn *p_hwfn,
}
p_ll2_info->rx_queue.descq_array = p_descq;
rc = qed_chain_alloc(p_hwfn->cdev,
QED_CHAIN_USE_TO_CONSUME_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U16,
p_ll2_info->input.rx_num_desc,
sizeof(struct core_rx_fast_path_cqe),
&p_ll2_info->rx_queue.rcq_chain, NULL);
params.mode = QED_CHAIN_MODE_PBL;
params.elem_size = sizeof(struct core_rx_fast_path_cqe);
rc = qed_chain_alloc(cdev, &p_ll2_info->rx_queue.rcq_chain, &params);
if (rc) {
DP_NOTICE(p_hwfn, "Failed to allocate ll2 rcq chain\n");
goto out;
......@@ -1177,6 +1177,13 @@ qed_ll2_acquire_connection_rx(struct qed_hwfn *p_hwfn,
static int qed_ll2_acquire_connection_tx(struct qed_hwfn *p_hwfn,
struct qed_ll2_info *p_ll2_info)
{
struct qed_chain_init_params params = {
.mode = QED_CHAIN_MODE_PBL,
.intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE,
.cnt_type = QED_CHAIN_CNT_TYPE_U16,
.num_elems = p_ll2_info->input.tx_num_desc,
.elem_size = sizeof(struct core_tx_bd),
};
struct qed_ll2_tx_packet *p_descq;
u32 desc_size;
u32 capacity;
......@@ -1185,13 +1192,8 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn *p_hwfn,
if (!p_ll2_info->input.tx_num_desc)
goto out;
rc = qed_chain_alloc(p_hwfn->cdev,
QED_CHAIN_USE_TO_CONSUME_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U16,
p_ll2_info->input.tx_num_desc,
sizeof(struct core_tx_bd),
&p_ll2_info->tx_queue.txq_chain, NULL);
rc = qed_chain_alloc(p_hwfn->cdev, &p_ll2_info->tx_queue.txq_chain,
&params);
if (rc)
goto out;
......
......@@ -366,11 +366,11 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
/* Place EQ address in RAMROD */
DMA_REGPAIR_LE(p_ramrod->event_ring_pbl_addr,
p_hwfn->p_eq->chain.pbl_sp.p_phys_table);
qed_chain_get_pbl_phys(&p_hwfn->p_eq->chain));
page_cnt = (u8)qed_chain_get_page_cnt(&p_hwfn->p_eq->chain);
p_ramrod->event_ring_num_pages = page_cnt;
DMA_REGPAIR_LE(p_ramrod->consolid_q_pbl_addr,
p_hwfn->p_consq->chain.pbl_sp.p_phys_table);
qed_chain_get_pbl_phys(&p_hwfn->p_consq->chain));
qed_tunn_set_pf_start_params(p_hwfn, p_tunn, &p_ramrod->tunnel_config);
......
......@@ -382,22 +382,26 @@ int qed_eq_completion(struct qed_hwfn *p_hwfn, void *cookie)
int qed_eq_alloc(struct qed_hwfn *p_hwfn, u16 num_elem)
{
struct qed_chain_init_params params = {
.mode = QED_CHAIN_MODE_PBL,
.intended_use = QED_CHAIN_USE_TO_PRODUCE,
.cnt_type = QED_CHAIN_CNT_TYPE_U16,
.num_elems = num_elem,
.elem_size = sizeof(union event_ring_element),
};
struct qed_eq *p_eq;
int ret;
/* Allocate EQ struct */
p_eq = kzalloc(sizeof(*p_eq), GFP_KERNEL);
if (!p_eq)
return -ENOMEM;
/* Allocate and initialize EQ chain*/
if (qed_chain_alloc(p_hwfn->cdev,
QED_CHAIN_USE_TO_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U16,
num_elem,
sizeof(union event_ring_element),
&p_eq->chain, NULL))
ret = qed_chain_alloc(p_hwfn->cdev, &p_eq->chain, &params);
if (ret) {
DP_NOTICE(p_hwfn, "Failed to allocate EQ chain\n");
goto eq_allocate_fail;
}
/* register EQ completion on the SP SB */
qed_int_register_cb(p_hwfn, qed_eq_completion,
......@@ -408,7 +412,8 @@ int qed_eq_alloc(struct qed_hwfn *p_hwfn, u16 num_elem)
eq_allocate_fail:
kfree(p_eq);
return -ENOMEM;
return ret;
}
void qed_eq_setup(struct qed_hwfn *p_hwfn)
......@@ -529,10 +534,18 @@ void qed_spq_setup(struct qed_hwfn *p_hwfn)
int qed_spq_alloc(struct qed_hwfn *p_hwfn)
{
struct qed_chain_init_params params = {
.mode = QED_CHAIN_MODE_SINGLE,
.intended_use = QED_CHAIN_USE_TO_PRODUCE,
.cnt_type = QED_CHAIN_CNT_TYPE_U16,
.elem_size = sizeof(struct slow_path_element),
};
struct qed_dev *cdev = p_hwfn->cdev;
struct qed_spq_entry *p_virt = NULL;
struct qed_spq *p_spq = NULL;
dma_addr_t p_phys = 0;
u32 capacity;
int ret;
/* SPQ struct */
p_spq = kzalloc(sizeof(struct qed_spq), GFP_KERNEL);
......@@ -540,22 +553,21 @@ int qed_spq_alloc(struct qed_hwfn *p_hwfn)
return -ENOMEM;
/* SPQ ring */
if (qed_chain_alloc(p_hwfn->cdev,
QED_CHAIN_USE_TO_PRODUCE,
QED_CHAIN_MODE_SINGLE,
QED_CHAIN_CNT_TYPE_U16,
0, /* N/A when the mode is SINGLE */
sizeof(struct slow_path_element),
&p_spq->chain, NULL))
goto spq_allocate_fail;
ret = qed_chain_alloc(cdev, &p_spq->chain, &params);
if (ret) {
DP_NOTICE(p_hwfn, "Failed to allocate SPQ chain\n");
goto spq_chain_alloc_fail;
}
/* allocate and fill the SPQ elements (incl. ramrod data list) */
capacity = qed_chain_get_capacity(&p_spq->chain);
p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
ret = -ENOMEM;
p_virt = dma_alloc_coherent(&cdev->pdev->dev,
capacity * sizeof(struct qed_spq_entry),
&p_phys, GFP_KERNEL);
if (!p_virt)
goto spq_allocate_fail;
goto spq_alloc_fail;
p_spq->p_virt = p_virt;
p_spq->p_phys = p_phys;
......@@ -563,10 +575,12 @@ int qed_spq_alloc(struct qed_hwfn *p_hwfn)
return 0;
spq_allocate_fail:
qed_chain_free(p_hwfn->cdev, &p_spq->chain);
spq_alloc_fail:
qed_chain_free(cdev, &p_spq->chain);
spq_chain_alloc_fail:
kfree(p_spq);
return -ENOMEM;
return ret;
}
void qed_spq_free(struct qed_hwfn *p_hwfn)
......@@ -967,30 +981,40 @@ int qed_spq_completion(struct qed_hwfn *p_hwfn,
return 0;
}
#define QED_SPQ_CONSQ_ELEM_SIZE 0x80
int qed_consq_alloc(struct qed_hwfn *p_hwfn)
{
struct qed_chain_init_params params = {
.mode = QED_CHAIN_MODE_PBL,
.intended_use = QED_CHAIN_USE_TO_PRODUCE,
.cnt_type = QED_CHAIN_CNT_TYPE_U16,
.num_elems = QED_CHAIN_PAGE_SIZE / QED_SPQ_CONSQ_ELEM_SIZE,
.elem_size = QED_SPQ_CONSQ_ELEM_SIZE,
};
struct qed_consq *p_consq;
int ret;
/* Allocate ConsQ struct */
p_consq = kzalloc(sizeof(*p_consq), GFP_KERNEL);
if (!p_consq)
return -ENOMEM;
/* Allocate and initialize EQ chain*/
if (qed_chain_alloc(p_hwfn->cdev,
QED_CHAIN_USE_TO_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U16,
QED_CHAIN_PAGE_SIZE / 0x80,
0x80, &p_consq->chain, NULL))
goto consq_allocate_fail;
/* Allocate and initialize ConsQ chain */
ret = qed_chain_alloc(p_hwfn->cdev, &p_consq->chain, &params);
if (ret) {
DP_NOTICE(p_hwfn, "Failed to allocate ConsQ chain");
goto consq_alloc_fail;
}
p_hwfn->p_consq = p_consq;
return 0;
consq_allocate_fail:
consq_alloc_fail:
kfree(p_consq);
return -ENOMEM;
return ret;
}
void qed_consq_setup(struct qed_hwfn *p_hwfn)
......
......@@ -177,7 +177,8 @@ struct qede_dev {
u8 dp_level;
unsigned long flags;
#define IS_VF(edev) (test_bit(QEDE_FLAGS_IS_VF, &(edev)->flags))
#define IS_VF(edev) test_bit(QEDE_FLAGS_IS_VF, \
&(edev)->flags)
const struct qed_eth_ops *ops;
struct qede_ptp *ptp;
......@@ -198,6 +199,8 @@ struct qede_dev {
u8 fp_num_rx;
u16 req_queues;
u16 num_queues;
u16 total_xdp_queues;
#define QEDE_QUEUE_CNT(edev) ((edev)->num_queues)
#define QEDE_RSS_COUNT(edev) ((edev)->num_queues - (edev)->fp_num_tx)
#define QEDE_RX_QUEUE_IDX(edev, i) (i)
......@@ -205,7 +208,7 @@ struct qede_dev {
struct qed_int_info int_info;
/* Smaller private varaiant of the RTNL lock */
/* Smaller private variant of the RTNL lock */
struct mutex qede_lock;
u32 state; /* Protected by qede_lock */
u16 rx_buf_size;
......@@ -226,22 +229,28 @@ struct qede_dev {
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
struct qede_stats stats;
/* Bitfield to track initialized RSS params */
u32 rss_params_inited;
#define QEDE_RSS_INDIR_INITED BIT(0)
#define QEDE_RSS_KEY_INITED BIT(1)
#define QEDE_RSS_CAPS_INITED BIT(2)
u32 rss_params_inited; /* bit-field to track initialized rss params */
u16 rss_ind_table[128];
u32 rss_key[10];
u8 rss_caps;
u16 q_num_rx_buffers; /* Must be a power of two */
u16 q_num_tx_buffers; /* Must be a power of two */
/* Both must be a power of two */
u16 q_num_rx_buffers;
u16 q_num_tx_buffers;
bool gro_disable;
struct list_head vlan_list;
u16 configured_vlans;
u16 non_configured_vlans;
bool accept_any_vlan;
struct delayed_work sp_task;
unsigned long sp_flags;
u16 vxlan_dst_port;
......@@ -373,6 +382,7 @@ struct sw_tx_bd {
struct sw_tx_xdp {
struct page *page;
struct xdp_frame *xdpf;
dma_addr_t mapping;
};
......@@ -394,6 +404,10 @@ struct qede_tx_queue {
void __iomem *doorbell_addr;
union db_prod tx_db;
/* Spinlock for XDP queues in case of XDP_REDIRECT */
spinlock_t xdp_tx_lock;
int index; /* Slowpath only */
#define QEDE_TXQ_XDP_TO_IDX(edev, txq) ((txq)->index - \
QEDE_MAX_TSS_CNT(edev))
......@@ -436,25 +450,30 @@ struct qede_tx_queue {
struct qede_fastpath {
struct qede_dev *edev;
u8 type;
#define QEDE_FASTPATH_TX BIT(0)
#define QEDE_FASTPATH_RX BIT(1)
#define QEDE_FASTPATH_XDP BIT(2)
#define QEDE_FASTPATH_COMBINED (QEDE_FASTPATH_TX | QEDE_FASTPATH_RX)
u8 type;
u8 id;
u8 xdp_xmit;
#define QEDE_XDP_TX BIT(0)
#define QEDE_XDP_REDIRECT BIT(1)
struct napi_struct napi;
struct qed_sb_info *sb_info;
struct qede_rx_queue *rxq;
struct qede_tx_queue *txq;
struct qede_tx_queue *xdp_tx;
#define VEC_NAME_SIZE (sizeof_field(struct net_device, name) + 8)
char name[VEC_NAME_SIZE];
char name[IFNAMSIZ + 8];
};
/* Debug print definitions */
#define DP_NAME(edev) ((edev)->ndev->name)
#define DP_NAME(edev) netdev_name((edev)->ndev)
#define XMIT_PLAIN 0
#define XMIT_L4_CSUM BIT(0)
......@@ -503,6 +522,8 @@ struct qede_reload_args {
/* Datapath functions definition */
netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev);
int qede_xdp_transmit(struct net_device *dev, int n_frames,
struct xdp_frame **frames, u32 flags);
u16 qede_select_queue(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev);
netdev_features_t qede_features_check(struct sk_buff *skb,
......
......@@ -302,51 +302,94 @@ static inline void qede_update_tx_producer(struct qede_tx_queue *txq)
wmb();
}
static int qede_xdp_xmit(struct qede_dev *edev, struct qede_fastpath *fp,
struct sw_rx_data *metadata, u16 padding, u16 length)
static int qede_xdp_xmit(struct qede_tx_queue *txq, dma_addr_t dma, u16 pad,
u16 len, struct page *page, struct xdp_frame *xdpf)
{
struct qede_tx_queue *txq = fp->xdp_tx;
struct eth_tx_1st_bd *first_bd;
u16 idx = txq->sw_tx_prod;
struct eth_tx_1st_bd *bd;
struct sw_tx_xdp *xdp;
u16 val;
if (!qed_chain_get_elem_left(&txq->tx_pbl)) {
if (unlikely(qed_chain_get_elem_used(&txq->tx_pbl) >=
txq->num_tx_buffers)) {
txq->stopped_cnt++;
return -ENOMEM;
}
first_bd = (struct eth_tx_1st_bd *)qed_chain_produce(&txq->tx_pbl);
memset(first_bd, 0, sizeof(*first_bd));
first_bd->data.bd_flags.bitfields =
BIT(ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT);
bd = qed_chain_produce(&txq->tx_pbl);
bd->data.nbds = 1;
bd->data.bd_flags.bitfields = BIT(ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT);
val = (length & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) <<
val = (len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) <<
ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT;
first_bd->data.bitfields |= cpu_to_le16(val);
first_bd->data.nbds = 1;
bd->data.bitfields = cpu_to_le16(val);
/* We can safely ignore the offset, as it's 0 for XDP */
BD_SET_UNMAP_ADDR_LEN(first_bd, metadata->mapping + padding, length);
BD_SET_UNMAP_ADDR_LEN(bd, dma + pad, len);
/* Synchronize the buffer back to device, as program [probably]
* has changed it.
*/
dma_sync_single_for_device(&edev->pdev->dev,
metadata->mapping + padding,
length, PCI_DMA_TODEVICE);
xdp = txq->sw_tx_ring.xdp + txq->sw_tx_prod;
xdp->mapping = dma;
xdp->page = page;
xdp->xdpf = xdpf;
txq->sw_tx_ring.xdp[idx].page = metadata->data;
txq->sw_tx_ring.xdp[idx].mapping = metadata->mapping;
txq->sw_tx_prod = (txq->sw_tx_prod + 1) % txq->num_tx_buffers;
/* Mark the fastpath for future XDP doorbell */
fp->xdp_xmit = 1;
return 0;
}
int qede_xdp_transmit(struct net_device *dev, int n_frames,
struct xdp_frame **frames, u32 flags)
{
struct qede_dev *edev = netdev_priv(dev);
struct device *dmadev = &edev->pdev->dev;
struct qede_tx_queue *xdp_tx;
struct xdp_frame *xdpf;
dma_addr_t mapping;
int i, drops = 0;
u16 xdp_prod;
if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
return -EINVAL;
if (unlikely(!netif_running(dev)))
return -ENETDOWN;
i = smp_processor_id() % edev->total_xdp_queues;
xdp_tx = edev->fp_array[i].xdp_tx;
spin_lock(&xdp_tx->xdp_tx_lock);
for (i = 0; i < n_frames; i++) {
xdpf = frames[i];
mapping = dma_map_single(dmadev, xdpf->data, xdpf->len,
DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dmadev, mapping))) {
xdp_return_frame_rx_napi(xdpf);
drops++;
continue;
}
if (unlikely(qede_xdp_xmit(xdp_tx, mapping, 0, xdpf->len,
NULL, xdpf))) {
xdp_return_frame_rx_napi(xdpf);
drops++;
}
}
if (flags & XDP_XMIT_FLUSH) {
xdp_prod = qed_chain_get_prod_idx(&xdp_tx->tx_pbl);
xdp_tx->tx_db.data.bd_prod = cpu_to_le16(xdp_prod);
qede_update_tx_producer(xdp_tx);
}
spin_unlock(&xdp_tx->xdp_tx_lock);
return n_frames - drops;
}
int qede_txq_has_work(struct qede_tx_queue *txq)
{
u16 hw_bd_cons;
......@@ -362,20 +405,31 @@ int qede_txq_has_work(struct qede_tx_queue *txq)
static void qede_xdp_tx_int(struct qede_dev *edev, struct qede_tx_queue *txq)
{
u16 hw_bd_cons, idx;
struct sw_tx_xdp *xdp_info, *xdp_arr = txq->sw_tx_ring.xdp;
struct device *dev = &edev->pdev->dev;
struct xdp_frame *xdpf;
u16 hw_bd_cons;
hw_bd_cons = le16_to_cpu(*txq->hw_cons_ptr);
barrier();
while (hw_bd_cons != qed_chain_get_cons_idx(&txq->tx_pbl)) {
qed_chain_consume(&txq->tx_pbl);
idx = txq->sw_tx_cons;
xdp_info = xdp_arr + txq->sw_tx_cons;
xdpf = xdp_info->xdpf;
if (xdpf) {
dma_unmap_single(dev, xdp_info->mapping, xdpf->len,
DMA_TO_DEVICE);
xdp_return_frame(xdpf);
dma_unmap_page(&edev->pdev->dev,
txq->sw_tx_ring.xdp[idx].mapping,
PAGE_SIZE, DMA_BIDIRECTIONAL);
__free_page(txq->sw_tx_ring.xdp[idx].page);
xdp_info->xdpf = NULL;
} else {
dma_unmap_page(dev, xdp_info->mapping, PAGE_SIZE,
DMA_BIDIRECTIONAL);
__free_page(xdp_info->page);
}
qed_chain_consume(&txq->tx_pbl);
txq->sw_tx_cons = (txq->sw_tx_cons + 1) % txq->num_tx_buffers;
txq->xmit_pkts++;
}
......@@ -1064,32 +1118,59 @@ static bool qede_rx_xdp(struct qede_dev *edev,
switch (act) {
case XDP_TX:
/* We need the replacement buffer before transmit. */
if (qede_alloc_rx_buffer(rxq, true)) {
if (unlikely(qede_alloc_rx_buffer(rxq, true))) {
qede_recycle_rx_bd_ring(rxq, 1);
trace_xdp_exception(edev->ndev, prog, act);
return false;
break;
}
/* Now if there's a transmission problem, we'd still have to
* throw current buffer, as replacement was already allocated.
*/
if (qede_xdp_xmit(edev, fp, bd, *data_offset, *len)) {
dma_unmap_page(rxq->dev, bd->mapping,
PAGE_SIZE, DMA_BIDIRECTIONAL);
if (unlikely(qede_xdp_xmit(fp->xdp_tx, bd->mapping,
*data_offset, *len, bd->data,
NULL))) {
dma_unmap_page(rxq->dev, bd->mapping, PAGE_SIZE,
rxq->data_direction);
__free_page(bd->data);
trace_xdp_exception(edev->ndev, prog, act);
} else {
dma_sync_single_for_device(rxq->dev,
bd->mapping + *data_offset,
*len, rxq->data_direction);
fp->xdp_xmit |= QEDE_XDP_TX;
}
/* Regardless, we've consumed an Rx BD */
qede_rx_bd_ring_consume(rxq);
return false;
break;
case XDP_REDIRECT:
/* We need the replacement buffer before transmit. */
if (unlikely(qede_alloc_rx_buffer(rxq, true))) {
qede_recycle_rx_bd_ring(rxq, 1);
trace_xdp_exception(edev->ndev, prog, act);
break;
}
dma_unmap_page(rxq->dev, bd->mapping, PAGE_SIZE,
rxq->data_direction);
if (unlikely(xdp_do_redirect(edev->ndev, &xdp, prog)))
DP_NOTICE(edev, "Failed to redirect the packet\n");
else
fp->xdp_xmit |= QEDE_XDP_REDIRECT;
qede_rx_bd_ring_consume(rxq);
break;
default:
bpf_warn_invalid_xdp_action(act);
/* Fall through */
fallthrough;
case XDP_ABORTED:
trace_xdp_exception(edev->ndev, prog, act);
/* Fall through */
fallthrough;
case XDP_DROP:
qede_recycle_rx_bd_ring(rxq, cqe->bd_num);
}
......@@ -1353,6 +1434,9 @@ int qede_poll(struct napi_struct *napi, int budget)
napi);
struct qede_dev *edev = fp->edev;
int rx_work_done = 0;
u16 xdp_prod;
fp->xdp_xmit = 0;
if (likely(fp->type & QEDE_FASTPATH_TX)) {
int cos;
......@@ -1380,14 +1464,16 @@ int qede_poll(struct napi_struct *napi, int budget)
}
}
if (fp->xdp_xmit) {
u16 xdp_prod = qed_chain_get_prod_idx(&fp->xdp_tx->tx_pbl);
if (fp->xdp_xmit & QEDE_XDP_TX) {
xdp_prod = qed_chain_get_prod_idx(&fp->xdp_tx->tx_pbl);
fp->xdp_xmit = 0;
fp->xdp_tx->tx_db.data.bd_prod = cpu_to_le16(xdp_prod);
qede_update_tx_producer(fp->xdp_tx);
}
if (fp->xdp_xmit & QEDE_XDP_REDIRECT)
xdp_do_flush_map();
return rx_work_done;
}
......
......@@ -672,6 +672,7 @@ static const struct net_device_ops qede_netdev_ops = {
#ifdef CONFIG_RFS_ACCEL
.ndo_rx_flow_steer = qede_rx_flow_steer,
#endif
.ndo_xdp_xmit = qede_xdp_transmit,
.ndo_setup_tc = qede_setup_tc_offload,
};
......@@ -712,6 +713,7 @@ static const struct net_device_ops qede_netdev_vf_xdp_ops = {
.ndo_udp_tunnel_del = udp_tunnel_nic_del_port,
.ndo_features_check = qede_features_check,
.ndo_bpf = qede_xdp,
.ndo_xdp_xmit = qede_xdp_transmit,
};
/* -------------------------------------------------------------------------
......@@ -1442,6 +1444,11 @@ static void qede_set_tpa_param(struct qede_rx_queue *rxq)
/* This function allocates all memory needed per Rx queue */
static int qede_alloc_mem_rxq(struct qede_dev *edev, struct qede_rx_queue *rxq)
{
struct qed_chain_init_params params = {
.cnt_type = QED_CHAIN_CNT_TYPE_U16,
.num_elems = RX_RING_SIZE,
};
struct qed_dev *cdev = edev->cdev;
int i, rc, size;
rxq->num_rx_buffers = edev->q_num_rx_buffers;
......@@ -1477,24 +1484,20 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev, struct qede_rx_queue *rxq)
}
/* Allocate FW Rx ring */
rc = edev->ops->common->chain_alloc(edev->cdev,
QED_CHAIN_USE_TO_CONSUME_PRODUCE,
QED_CHAIN_MODE_NEXT_PTR,
QED_CHAIN_CNT_TYPE_U16,
RX_RING_SIZE,
sizeof(struct eth_rx_bd),
&rxq->rx_bd_ring, NULL);
params.mode = QED_CHAIN_MODE_NEXT_PTR;
params.intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE;
params.elem_size = sizeof(struct eth_rx_bd);
rc = edev->ops->common->chain_alloc(cdev, &rxq->rx_bd_ring, &params);
if (rc)
goto err;
/* Allocate FW completion ring */
rc = edev->ops->common->chain_alloc(edev->cdev,
QED_CHAIN_USE_TO_CONSUME,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U16,
RX_RING_SIZE,
sizeof(union eth_rx_cqe),
&rxq->rx_comp_ring, NULL);
params.mode = QED_CHAIN_MODE_PBL;
params.intended_use = QED_CHAIN_USE_TO_CONSUME;
params.elem_size = sizeof(union eth_rx_cqe);
rc = edev->ops->common->chain_alloc(cdev, &rxq->rx_comp_ring, &params);
if (rc)
goto err;
......@@ -1531,7 +1534,13 @@ static void qede_free_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq)
/* This function allocates all memory needed per Tx queue */
static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq)
{
union eth_tx_bd_types *p_virt;
struct qed_chain_init_params params = {
.mode = QED_CHAIN_MODE_PBL,
.intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE,
.cnt_type = QED_CHAIN_CNT_TYPE_U16,
.num_elems = edev->q_num_tx_buffers,
.elem_size = sizeof(union eth_tx_bd_types),
};
int size, rc;
txq->num_tx_buffers = edev->q_num_tx_buffers;
......@@ -1549,13 +1558,7 @@ static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq)
goto err;
}
rc = edev->ops->common->chain_alloc(edev->cdev,
QED_CHAIN_USE_TO_CONSUME_PRODUCE,
QED_CHAIN_MODE_PBL,
QED_CHAIN_CNT_TYPE_U16,
txq->num_tx_buffers,
sizeof(*p_virt),
&txq->tx_pbl, NULL);
rc = edev->ops->common->chain_alloc(edev->cdev, &txq->tx_pbl, &params);
if (rc)
goto err;
......@@ -1711,6 +1714,7 @@ static void qede_init_fp(struct qede_dev *edev)
{
int queue_id, rxq_index = 0, txq_index = 0;
struct qede_fastpath *fp;
bool init_xdp = false;
for_each_queue(queue_id) {
fp = &edev->fp_array[queue_id];
......@@ -1722,6 +1726,9 @@ static void qede_init_fp(struct qede_dev *edev)
fp->xdp_tx->index = QEDE_TXQ_IDX_TO_XDP(edev,
rxq_index);
fp->xdp_tx->is_xdp = 1;
spin_lock_init(&fp->xdp_tx->xdp_tx_lock);
init_xdp = true;
}
if (fp->type & QEDE_FASTPATH_RX) {
......@@ -1737,6 +1744,13 @@ static void qede_init_fp(struct qede_dev *edev)
/* Driver have no error path from here */
WARN_ON(xdp_rxq_info_reg(&fp->rxq->xdp_rxq, edev->ndev,
fp->rxq->rxq_id) < 0);
if (xdp_rxq_info_reg_mem_model(&fp->rxq->xdp_rxq,
MEM_TYPE_PAGE_ORDER0,
NULL)) {
DP_NOTICE(edev,
"Failed to register XDP memory model\n");
}
}
if (fp->type & QEDE_FASTPATH_TX) {
......@@ -1762,6 +1776,11 @@ static void qede_init_fp(struct qede_dev *edev)
snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
edev->ndev->name, queue_id);
}
if (init_xdp) {
edev->total_xdp_queues = QEDE_RSS_COUNT(edev);
DP_INFO(edev, "Total XDP queues: %u\n", edev->total_xdp_queues);
}
}
static int qede_set_real_num_queues(struct qede_dev *edev)
......
This diff is collapsed.
......@@ -948,13 +948,8 @@ struct qed_common_ops {
u8 dp_level);
int (*chain_alloc)(struct qed_dev *cdev,
enum qed_chain_use_mode intended_use,
enum qed_chain_mode mode,
enum qed_chain_cnt_type cnt_type,
u32 num_elems,
size_t elem_size,
struct qed_chain *p_chain,
struct qed_chain_ext_pbl *ext_pbl);
struct qed_chain *chain,
struct qed_chain_init_params *params);
void (*chain_free)(struct qed_dev *cdev,
struct qed_chain *p_chain);
......
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