Merge branch 'ionic-struct-cleanups'

Shannon Nelson says:

====================
ionic: struct cleanups

This patchset has a few changes for better cacheline use,
to cleanup a page handling API, and to streamline the
Adminq/Notifyq queue handling.  Lastly, we also have a couple
of fixes pointed out by the friendly kernel test robot.

v2: dropped change to irq coalesce default
    fixed Neel's attributions to Co-developed-by
    dropped the unnecessary new call to dma_sync_single_for_cpu()
    added 2 patches from kernel test robot results
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-09-02 15:47:01 -07:00
commit 22b330b622
8 changed files with 91 additions and 138 deletions

View File

@ -64,9 +64,6 @@ struct ionic_admin_ctx {
union ionic_adminq_comp comp; union ionic_adminq_comp comp;
}; };
int ionic_napi(struct napi_struct *napi, int budget, ionic_cq_cb cb,
ionic_cq_done_cb done_cb, void *done_arg);
int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx); int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx);
int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_wait); int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_wait);
int ionic_set_dma_mask(struct ionic *ionic); int ionic_set_dma_mask(struct ionic *ionic);

View File

@ -467,9 +467,7 @@ int ionic_cq_init(struct ionic_lif *lif, struct ionic_cq *cq,
struct ionic_intr_info *intr, struct ionic_intr_info *intr,
unsigned int num_descs, size_t desc_size) unsigned int num_descs, size_t desc_size)
{ {
struct ionic_cq_info *cur;
unsigned int ring_size; unsigned int ring_size;
unsigned int i;
if (desc_size == 0 || !is_power_of_2(num_descs)) if (desc_size == 0 || !is_power_of_2(num_descs))
return -EINVAL; return -EINVAL;
@ -485,19 +483,6 @@ int ionic_cq_init(struct ionic_lif *lif, struct ionic_cq *cq,
cq->tail_idx = 0; cq->tail_idx = 0;
cq->done_color = 1; cq->done_color = 1;
cur = cq->info;
for (i = 0; i < num_descs; i++) {
if (i + 1 == num_descs) {
cur->next = cq->info;
cur->last = true;
} else {
cur->next = cur + 1;
}
cur->index = i;
cur++;
}
return 0; return 0;
} }
@ -551,9 +536,7 @@ int ionic_q_init(struct ionic_lif *lif, struct ionic_dev *idev,
unsigned int num_descs, size_t desc_size, unsigned int num_descs, size_t desc_size,
size_t sg_desc_size, unsigned int pid) size_t sg_desc_size, unsigned int pid)
{ {
struct ionic_desc_info *cur;
unsigned int ring_size; unsigned int ring_size;
unsigned int i;
if (desc_size == 0 || !is_power_of_2(num_descs)) if (desc_size == 0 || !is_power_of_2(num_descs))
return -EINVAL; return -EINVAL;
@ -574,18 +557,6 @@ int ionic_q_init(struct ionic_lif *lif, struct ionic_dev *idev,
snprintf(q->name, sizeof(q->name), "L%d-%s%u", lif->index, name, index); snprintf(q->name, sizeof(q->name), "L%d-%s%u", lif->index, name, index);
cur = q->info;
for (i = 0; i < num_descs; i++) {
if (i + 1 == num_descs)
cur->next = q->info;
else
cur->next = cur + 1;
cur->index = i;
cur->left = num_descs - i;
cur++;
}
return 0; return 0;
} }
@ -652,6 +623,7 @@ void ionic_q_service(struct ionic_queue *q, struct ionic_cq_info *cq_info,
struct ionic_desc_info *desc_info; struct ionic_desc_info *desc_info;
ionic_desc_cb cb; ionic_desc_cb cb;
void *cb_arg; void *cb_arg;
u16 index;
/* check for empty queue */ /* check for empty queue */
if (q->tail_idx == q->head_idx) if (q->tail_idx == q->head_idx)
@ -665,6 +637,7 @@ void ionic_q_service(struct ionic_queue *q, struct ionic_cq_info *cq_info,
do { do {
desc_info = &q->info[q->tail_idx]; desc_info = &q->info[q->tail_idx];
index = q->tail_idx;
q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1); q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
cb = desc_info->cb; cb = desc_info->cb;
@ -675,5 +648,5 @@ void ionic_q_service(struct ionic_queue *q, struct ionic_cq_info *cq_info,
if (cb) if (cb)
cb(q, desc_info, cq_info, cb_arg); cb(q, desc_info, cq_info, cb_arg);
} while (desc_info->index != stop_index); } while (index != stop_index);
} }

View File

@ -156,9 +156,6 @@ struct ionic_cq_info {
struct ionic_admin_comp *admincq; struct ionic_admin_comp *admincq;
struct ionic_notifyq_event *notifyq; struct ionic_notifyq_event *notifyq;
}; };
struct ionic_cq_info *next;
unsigned int index;
bool last;
}; };
struct ionic_queue; struct ionic_queue;
@ -186,9 +183,6 @@ struct ionic_desc_info {
struct ionic_txq_sg_desc *txq_sg_desc; struct ionic_txq_sg_desc *txq_sg_desc;
struct ionic_rxq_sg_desc *rxq_sgl_desc; struct ionic_rxq_sg_desc *rxq_sgl_desc;
}; };
struct ionic_desc_info *next;
unsigned int index;
unsigned int left;
unsigned int npages; unsigned int npages;
struct ionic_page_info pages[IONIC_RX_MAX_SG_ELEMS + 1]; struct ionic_page_info pages[IONIC_RX_MAX_SG_ELEMS + 1];
ionic_desc_cb cb; ionic_desc_cb cb;
@ -199,16 +193,17 @@ struct ionic_desc_info {
struct ionic_queue { struct ionic_queue {
struct device *dev; struct device *dev;
u64 dbell_count;
u64 drop;
u64 stop;
u64 wake;
struct ionic_lif *lif; struct ionic_lif *lif;
struct ionic_desc_info *info; struct ionic_desc_info *info;
struct ionic_dev *idev;
u16 head_idx; u16 head_idx;
u16 tail_idx; u16 tail_idx;
unsigned int index; unsigned int index;
unsigned int num_descs;
u64 dbell_count;
u64 stop;
u64 wake;
u64 drop;
struct ionic_dev *idev;
unsigned int type; unsigned int type;
unsigned int hw_index; unsigned int hw_index;
unsigned int hw_type; unsigned int hw_type;
@ -226,7 +221,6 @@ struct ionic_queue {
}; };
dma_addr_t base_pa; dma_addr_t base_pa;
dma_addr_t sg_base_pa; dma_addr_t sg_base_pa;
unsigned int num_descs;
unsigned int desc_size; unsigned int desc_size;
unsigned int sg_desc_size; unsigned int sg_desc_size;
unsigned int pid; unsigned int pid;
@ -246,8 +240,6 @@ struct ionic_intr_info {
}; };
struct ionic_cq { struct ionic_cq {
void *base;
dma_addr_t base_pa;
struct ionic_lif *lif; struct ionic_lif *lif;
struct ionic_cq_info *info; struct ionic_cq_info *info;
struct ionic_queue *bound_q; struct ionic_queue *bound_q;
@ -255,8 +247,10 @@ struct ionic_cq {
u16 tail_idx; u16 tail_idx;
bool done_color; bool done_color;
unsigned int num_descs; unsigned int num_descs;
u64 compl_count;
unsigned int desc_size; unsigned int desc_size;
u64 compl_count;
void *base;
dma_addr_t base_pa;
}; };
struct ionic; struct ionic;

View File

@ -298,8 +298,8 @@ static void ionic_get_pauseparam(struct net_device *netdev,
pause_type = lif->ionic->idev.port_info->config.pause_type; pause_type = lif->ionic->idev.port_info->config.pause_type;
if (pause_type) { if (pause_type) {
pause->rx_pause = pause_type & IONIC_PAUSE_F_RX ? 1 : 0; pause->rx_pause = (pause_type & IONIC_PAUSE_F_RX) ? 1 : 0;
pause->tx_pause = pause_type & IONIC_PAUSE_F_TX ? 1 : 0; pause->tx_pause = (pause_type & IONIC_PAUSE_F_TX) ? 1 : 0;
} }
} }

View File

@ -800,21 +800,6 @@ static bool ionic_notifyq_service(struct ionic_cq *cq,
return true; return true;
} }
static int ionic_notifyq_clean(struct ionic_lif *lif, int budget)
{
struct ionic_dev *idev = &lif->ionic->idev;
struct ionic_cq *cq = &lif->notifyqcq->cq;
u32 work_done;
work_done = ionic_cq_service(cq, budget, ionic_notifyq_service,
NULL, NULL);
if (work_done)
ionic_intr_credits(idev->intr_ctrl, cq->bound_intr->index,
work_done, IONIC_INTR_CRED_RESET_COALESCE);
return work_done;
}
static bool ionic_adminq_service(struct ionic_cq *cq, static bool ionic_adminq_service(struct ionic_cq *cq,
struct ionic_cq_info *cq_info) struct ionic_cq_info *cq_info)
{ {
@ -830,15 +815,36 @@ static bool ionic_adminq_service(struct ionic_cq *cq,
static int ionic_adminq_napi(struct napi_struct *napi, int budget) static int ionic_adminq_napi(struct napi_struct *napi, int budget)
{ {
struct ionic_intr_info *intr = napi_to_cq(napi)->bound_intr;
struct ionic_lif *lif = napi_to_cq(napi)->lif; struct ionic_lif *lif = napi_to_cq(napi)->lif;
struct ionic_dev *idev = &lif->ionic->idev;
unsigned int flags = 0;
int n_work = 0; int n_work = 0;
int a_work = 0; int a_work = 0;
int work_done;
if (likely(lif->notifyqcq && lif->notifyqcq->flags & IONIC_QCQ_F_INITED)) if (lif->notifyqcq && lif->notifyqcq->flags & IONIC_QCQ_F_INITED)
n_work = ionic_notifyq_clean(lif, budget); n_work = ionic_cq_service(&lif->notifyqcq->cq, budget,
a_work = ionic_napi(napi, budget, ionic_adminq_service, NULL, NULL); ionic_notifyq_service, NULL, NULL);
return max(n_work, a_work); if (lif->adminqcq && lif->adminqcq->flags & IONIC_QCQ_F_INITED)
a_work = ionic_cq_service(&lif->adminqcq->cq, budget,
ionic_adminq_service, NULL, NULL);
work_done = max(n_work, a_work);
if (work_done < budget && napi_complete_done(napi, work_done)) {
flags |= IONIC_INTR_CRED_UNMASK;
DEBUG_STATS_INTR_REARM(intr);
}
if (work_done || flags) {
flags |= IONIC_INTR_CRED_RESET_COALESCE;
ionic_intr_credits(idev->intr_ctrl,
intr->index,
n_work + a_work, flags);
}
return work_done;
} }
void ionic_get_stats64(struct net_device *netdev, void ionic_get_stats64(struct net_device *netdev,

View File

@ -16,32 +16,32 @@
#define IONIC_TX_BUDGET_DEFAULT 256 #define IONIC_TX_BUDGET_DEFAULT 256
struct ionic_tx_stats { struct ionic_tx_stats {
u64 dma_map_err;
u64 pkts; u64 pkts;
u64 bytes; u64 bytes;
u64 clean;
u64 linearize;
u64 csum_none; u64 csum_none;
u64 csum; u64 csum;
u64 crc32_csum;
u64 tso; u64 tso;
u64 tso_bytes; u64 tso_bytes;
u64 frags; u64 frags;
u64 vlan_inserted; u64 vlan_inserted;
u64 clean;
u64 linearize;
u64 crc32_csum;
u64 sg_cntr[IONIC_MAX_NUM_SG_CNTR]; u64 sg_cntr[IONIC_MAX_NUM_SG_CNTR];
u64 dma_map_err;
}; };
struct ionic_rx_stats { struct ionic_rx_stats {
u64 dma_map_err;
u64 alloc_err;
u64 pkts; u64 pkts;
u64 bytes; u64 bytes;
u64 csum_none; u64 csum_none;
u64 csum_complete; u64 csum_complete;
u64 csum_error;
u64 buffers_posted; u64 buffers_posted;
u64 dropped; u64 dropped;
u64 vlan_stripped; u64 vlan_stripped;
u64 csum_error;
u64 dma_map_err;
u64 alloc_err;
}; };
#define IONIC_QCQ_F_INITED BIT(0) #define IONIC_QCQ_F_INITED BIT(0)

View File

@ -305,32 +305,6 @@ int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
return ionic_adminq_check_err(lif, ctx, (remaining == 0)); return ionic_adminq_check_err(lif, ctx, (remaining == 0));
} }
int ionic_napi(struct napi_struct *napi, int budget, ionic_cq_cb cb,
ionic_cq_done_cb done_cb, void *done_arg)
{
struct ionic_qcq *qcq = napi_to_qcq(napi);
struct ionic_cq *cq = &qcq->cq;
u32 work_done, flags = 0;
work_done = ionic_cq_service(cq, budget, cb, done_cb, done_arg);
if (work_done < budget && napi_complete_done(napi, work_done)) {
flags |= IONIC_INTR_CRED_UNMASK;
DEBUG_STATS_INTR_REARM(cq->bound_intr);
}
if (work_done || flags) {
flags |= IONIC_INTR_CRED_RESET_COALESCE;
ionic_intr_credits(cq->lif->ionic->idev.intr_ctrl,
cq->bound_intr->index,
work_done, flags);
}
DEBUG_STATS_NAPI_POLL(qcq, work_done);
return work_done;
}
static void ionic_dev_cmd_clean(struct ionic *ionic) static void ionic_dev_cmd_clean(struct ionic *ionic)
{ {
union ionic_dev_cmd_regs *regs = ionic->idev.dev_cmd_regs; union ionic_dev_cmd_regs *regs = ionic->idev.dev_cmd_regs;

View File

@ -238,10 +238,10 @@ static bool ionic_rx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info)
if (q->tail_idx == q->head_idx) if (q->tail_idx == q->head_idx)
return false; return false;
desc_info = &q->info[q->tail_idx]; if (q->tail_idx != le16_to_cpu(comp->comp_index))
if (desc_info->index != le16_to_cpu(comp->comp_index))
return false; return false;
desc_info = &q->info[q->tail_idx];
q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1); q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
/* clean the related q entry, only one per qc completion */ /* clean the related q entry, only one per qc completion */
@ -266,40 +266,49 @@ void ionic_rx_flush(struct ionic_cq *cq)
work_done, IONIC_INTR_CRED_RESET_COALESCE); work_done, IONIC_INTR_CRED_RESET_COALESCE);
} }
static struct page *ionic_rx_page_alloc(struct ionic_queue *q, static int ionic_rx_page_alloc(struct ionic_queue *q,
dma_addr_t *dma_addr) struct ionic_page_info *page_info)
{ {
struct ionic_lif *lif = q->lif; struct ionic_lif *lif = q->lif;
struct ionic_rx_stats *stats; struct ionic_rx_stats *stats;
struct net_device *netdev; struct net_device *netdev;
struct device *dev; struct device *dev;
struct page *page;
netdev = lif->netdev; netdev = lif->netdev;
dev = lif->ionic->dev; dev = lif->ionic->dev;
stats = q_to_rx_stats(q); stats = q_to_rx_stats(q);
page = alloc_page(GFP_ATOMIC);
if (unlikely(!page)) { if (unlikely(!page_info)) {
net_err_ratelimited("%s: Page alloc failed on %s!\n", net_err_ratelimited("%s: %s invalid page_info in alloc\n",
netdev->name, q->name);
return -EINVAL;
}
page_info->page = dev_alloc_page();
if (unlikely(!page_info->page)) {
net_err_ratelimited("%s: %s page alloc failed\n",
netdev->name, q->name); netdev->name, q->name);
stats->alloc_err++; stats->alloc_err++;
return NULL; return -ENOMEM;
} }
*dma_addr = dma_map_page(dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); page_info->dma_addr = dma_map_page(dev, page_info->page, 0, PAGE_SIZE,
if (unlikely(dma_mapping_error(dev, *dma_addr))) { DMA_FROM_DEVICE);
__free_page(page); if (unlikely(dma_mapping_error(dev, page_info->dma_addr))) {
net_err_ratelimited("%s: DMA single map failed on %s!\n", put_page(page_info->page);
page_info->dma_addr = 0;
page_info->page = NULL;
net_err_ratelimited("%s: %s dma map failed\n",
netdev->name, q->name); netdev->name, q->name);
stats->dma_map_err++; stats->dma_map_err++;
return NULL; return -EIO;
} }
return page; return 0;
} }
static void ionic_rx_page_free(struct ionic_queue *q, struct page *page, static void ionic_rx_page_free(struct ionic_queue *q,
dma_addr_t dma_addr) struct ionic_page_info *page_info)
{ {
struct ionic_lif *lif = q->lif; struct ionic_lif *lif = q->lif;
struct net_device *netdev; struct net_device *netdev;
@ -308,15 +317,23 @@ static void ionic_rx_page_free(struct ionic_queue *q, struct page *page,
netdev = lif->netdev; netdev = lif->netdev;
dev = lif->ionic->dev; dev = lif->ionic->dev;
if (unlikely(!page)) { if (unlikely(!page_info)) {
net_err_ratelimited("%s: Trying to free unallocated buffer on %s!\n", net_err_ratelimited("%s: %s invalid page_info in free\n",
netdev->name, q->name); netdev->name, q->name);
return; return;
} }
dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_FROM_DEVICE); if (unlikely(!page_info->page)) {
net_err_ratelimited("%s: %s invalid page in free\n",
netdev->name, q->name);
return;
}
__free_page(page); dma_unmap_page(dev, page_info->dma_addr, PAGE_SIZE, DMA_FROM_DEVICE);
put_page(page_info->page);
page_info->dma_addr = 0;
page_info->page = NULL;
} }
void ionic_rx_fill(struct ionic_queue *q) void ionic_rx_fill(struct ionic_queue *q)
@ -352,8 +369,7 @@ void ionic_rx_fill(struct ionic_queue *q)
desc->opcode = (nfrags > 1) ? IONIC_RXQ_DESC_OPCODE_SG : desc->opcode = (nfrags > 1) ? IONIC_RXQ_DESC_OPCODE_SG :
IONIC_RXQ_DESC_OPCODE_SIMPLE; IONIC_RXQ_DESC_OPCODE_SIMPLE;
desc_info->npages = nfrags; desc_info->npages = nfrags;
page_info->page = ionic_rx_page_alloc(q, &page_info->dma_addr); if (unlikely(ionic_rx_page_alloc(q, page_info))) {
if (unlikely(!page_info->page)) {
desc->addr = 0; desc->addr = 0;
desc->len = 0; desc->len = 0;
return; return;
@ -370,8 +386,7 @@ void ionic_rx_fill(struct ionic_queue *q)
continue; continue;
sg_elem = &sg_desc->elems[j]; sg_elem = &sg_desc->elems[j];
page_info->page = ionic_rx_page_alloc(q, &page_info->dma_addr); if (unlikely(ionic_rx_page_alloc(q, page_info))) {
if (unlikely(!page_info->page)) {
sg_elem->addr = 0; sg_elem->addr = 0;
sg_elem->len = 0; sg_elem->len = 0;
return; return;
@ -409,14 +424,8 @@ void ionic_rx_empty(struct ionic_queue *q)
desc->addr = 0; desc->addr = 0;
desc->len = 0; desc->len = 0;
for (i = 0; i < desc_info->npages; i++) { for (i = 0; i < desc_info->npages; i++)
if (likely(desc_info->pages[i].page)) { ionic_rx_page_free(q, &desc_info->pages[i]);
ionic_rx_page_free(q, desc_info->pages[i].page,
desc_info->pages[i].dma_addr);
desc_info->pages[i].page = NULL;
desc_info->pages[i].dma_addr = 0;
}
}
desc_info->cb_arg = NULL; desc_info->cb_arg = NULL;
idx = (idx + 1) & (q->num_descs - 1); idx = (idx + 1) & (q->num_descs - 1);
@ -626,6 +635,7 @@ static bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info)
struct ionic_txq_comp *comp = cq_info->cq_desc; struct ionic_txq_comp *comp = cq_info->cq_desc;
struct ionic_queue *q = cq->bound_q; struct ionic_queue *q = cq->bound_q;
struct ionic_desc_info *desc_info; struct ionic_desc_info *desc_info;
u16 index;
if (!color_match(comp->color, cq->done_color)) if (!color_match(comp->color, cq->done_color))
return false; return false;
@ -635,11 +645,12 @@ static bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info)
*/ */
do { do {
desc_info = &q->info[q->tail_idx]; desc_info = &q->info[q->tail_idx];
index = q->tail_idx;
q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1); q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
ionic_tx_clean(q, desc_info, cq_info, desc_info->cb_arg); ionic_tx_clean(q, desc_info, cq_info, desc_info->cb_arg);
desc_info->cb = NULL; desc_info->cb = NULL;
desc_info->cb_arg = NULL; desc_info->cb_arg = NULL;
} while (desc_info->index != le16_to_cpu(comp->comp_index)); } while (index != le16_to_cpu(comp->comp_index));
return true; return true;
} }
@ -659,7 +670,6 @@ void ionic_tx_flush(struct ionic_cq *cq)
void ionic_tx_empty(struct ionic_queue *q) void ionic_tx_empty(struct ionic_queue *q)
{ {
struct ionic_desc_info *desc_info; struct ionic_desc_info *desc_info;
int done = 0;
/* walk the not completed tx entries, if any */ /* walk the not completed tx entries, if any */
while (q->head_idx != q->tail_idx) { while (q->head_idx != q->tail_idx) {
@ -668,7 +678,6 @@ void ionic_tx_empty(struct ionic_queue *q)
ionic_tx_clean(q, desc_info, NULL, desc_info->cb_arg); ionic_tx_clean(q, desc_info, NULL, desc_info->cb_arg);
desc_info->cb = NULL; desc_info->cb = NULL;
desc_info->cb_arg = NULL; desc_info->cb_arg = NULL;
done++;
} }
} }