|
@@ -179,50 +179,99 @@ unlock:
|
|
|
mutex_unlock(&priv->state_lock);
|
|
|
}
|
|
|
|
|
|
-int mlx5e_alloc_rx_wqe(struct mlx5e_rq *rq, struct mlx5e_rx_wqe *wqe, u16 ix)
|
|
|
+#define RQ_PAGE_SIZE(rq) ((1 << rq->buff.page_order) << PAGE_SHIFT)
|
|
|
+
|
|
|
+static inline bool mlx5e_rx_cache_put(struct mlx5e_rq *rq,
|
|
|
+ struct mlx5e_dma_info *dma_info)
|
|
|
{
|
|
|
- struct sk_buff *skb;
|
|
|
- dma_addr_t dma_addr;
|
|
|
+ struct mlx5e_page_cache *cache = &rq->page_cache;
|
|
|
+ u32 tail_next = (cache->tail + 1) & (MLX5E_CACHE_SIZE - 1);
|
|
|
|
|
|
- skb = napi_alloc_skb(rq->cq.napi, rq->wqe_sz);
|
|
|
- if (unlikely(!skb))
|
|
|
- return -ENOMEM;
|
|
|
+ if (tail_next == cache->head) {
|
|
|
+ rq->stats.cache_full++;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ cache->page_cache[cache->tail] = *dma_info;
|
|
|
+ cache->tail = tail_next;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static inline bool mlx5e_rx_cache_get(struct mlx5e_rq *rq,
|
|
|
+ struct mlx5e_dma_info *dma_info)
|
|
|
+{
|
|
|
+ struct mlx5e_page_cache *cache = &rq->page_cache;
|
|
|
+
|
|
|
+ if (unlikely(cache->head == cache->tail)) {
|
|
|
+ rq->stats.cache_empty++;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (page_ref_count(cache->page_cache[cache->head].page) != 1) {
|
|
|
+ rq->stats.cache_busy++;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ *dma_info = cache->page_cache[cache->head];
|
|
|
+ cache->head = (cache->head + 1) & (MLX5E_CACHE_SIZE - 1);
|
|
|
+ rq->stats.cache_reuse++;
|
|
|
+
|
|
|
+ dma_sync_single_for_device(rq->pdev, dma_info->addr,
|
|
|
+ RQ_PAGE_SIZE(rq),
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
+ return true;
|
|
|
+}
|
|
|
|
|
|
- dma_addr = dma_map_single(rq->pdev,
|
|
|
- /* hw start padding */
|
|
|
- skb->data,
|
|
|
- /* hw end padding */
|
|
|
- rq->wqe_sz,
|
|
|
- DMA_FROM_DEVICE);
|
|
|
+static inline int mlx5e_page_alloc_mapped(struct mlx5e_rq *rq,
|
|
|
+ struct mlx5e_dma_info *dma_info)
|
|
|
+{
|
|
|
+ struct page *page;
|
|
|
|
|
|
- if (unlikely(dma_mapping_error(rq->pdev, dma_addr)))
|
|
|
- goto err_free_skb;
|
|
|
+ if (mlx5e_rx_cache_get(rq, dma_info))
|
|
|
+ return 0;
|
|
|
|
|
|
- *((dma_addr_t *)skb->cb) = dma_addr;
|
|
|
- wqe->data.addr = cpu_to_be64(dma_addr);
|
|
|
+ page = dev_alloc_pages(rq->buff.page_order);
|
|
|
+ if (unlikely(!page))
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- rq->skb[ix] = skb;
|
|
|
+ dma_info->page = page;
|
|
|
+ dma_info->addr = dma_map_page(rq->pdev, page, 0,
|
|
|
+ RQ_PAGE_SIZE(rq), DMA_FROM_DEVICE);
|
|
|
+ if (unlikely(dma_mapping_error(rq->pdev, dma_info->addr))) {
|
|
|
+ put_page(page);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
+}
|
|
|
|
|
|
-err_free_skb:
|
|
|
- dev_kfree_skb(skb);
|
|
|
+void mlx5e_page_release(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info,
|
|
|
+ bool recycle)
|
|
|
+{
|
|
|
+ if (likely(recycle) && mlx5e_rx_cache_put(rq, dma_info))
|
|
|
+ return;
|
|
|
+
|
|
|
+ dma_unmap_page(rq->pdev, dma_info->addr, RQ_PAGE_SIZE(rq),
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
+ put_page(dma_info->page);
|
|
|
+}
|
|
|
+
|
|
|
+int mlx5e_alloc_rx_wqe(struct mlx5e_rq *rq, struct mlx5e_rx_wqe *wqe, u16 ix)
|
|
|
+{
|
|
|
+ struct mlx5e_dma_info *di = &rq->dma_info[ix];
|
|
|
|
|
|
- return -ENOMEM;
|
|
|
+ if (unlikely(mlx5e_page_alloc_mapped(rq, di)))
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ wqe->data.addr = cpu_to_be64(di->addr + MLX5_RX_HEADROOM);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
void mlx5e_dealloc_rx_wqe(struct mlx5e_rq *rq, u16 ix)
|
|
|
{
|
|
|
- struct sk_buff *skb = rq->skb[ix];
|
|
|
+ struct mlx5e_dma_info *di = &rq->dma_info[ix];
|
|
|
|
|
|
- if (skb) {
|
|
|
- rq->skb[ix] = NULL;
|
|
|
- dma_unmap_single(rq->pdev,
|
|
|
- *((dma_addr_t *)skb->cb),
|
|
|
- rq->wqe_sz,
|
|
|
- DMA_FROM_DEVICE);
|
|
|
- dev_kfree_skb(skb);
|
|
|
- }
|
|
|
+ mlx5e_page_release(rq, di, true);
|
|
|
}
|
|
|
|
|
|
static inline int mlx5e_mpwqe_strides_per_page(struct mlx5e_rq *rq)
|
|
@@ -305,79 +354,6 @@ static inline void mlx5e_post_umr_wqe(struct mlx5e_rq *rq, u16 ix)
|
|
|
mlx5e_tx_notify_hw(sq, &wqe->ctrl, 0);
|
|
|
}
|
|
|
|
|
|
-static inline bool mlx5e_rx_cache_put(struct mlx5e_rq *rq,
|
|
|
- struct mlx5e_dma_info *dma_info)
|
|
|
-{
|
|
|
- struct mlx5e_page_cache *cache = &rq->page_cache;
|
|
|
- u32 tail_next = (cache->tail + 1) & (MLX5E_CACHE_SIZE - 1);
|
|
|
-
|
|
|
- if (tail_next == cache->head) {
|
|
|
- rq->stats.cache_full++;
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- cache->page_cache[cache->tail] = *dma_info;
|
|
|
- cache->tail = tail_next;
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-static inline bool mlx5e_rx_cache_get(struct mlx5e_rq *rq,
|
|
|
- struct mlx5e_dma_info *dma_info)
|
|
|
-{
|
|
|
- struct mlx5e_page_cache *cache = &rq->page_cache;
|
|
|
-
|
|
|
- if (unlikely(cache->head == cache->tail)) {
|
|
|
- rq->stats.cache_empty++;
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- if (page_ref_count(cache->page_cache[cache->head].page) != 1) {
|
|
|
- rq->stats.cache_busy++;
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- *dma_info = cache->page_cache[cache->head];
|
|
|
- cache->head = (cache->head + 1) & (MLX5E_CACHE_SIZE - 1);
|
|
|
- rq->stats.cache_reuse++;
|
|
|
-
|
|
|
- dma_sync_single_for_device(rq->pdev, dma_info->addr, PAGE_SIZE,
|
|
|
- DMA_FROM_DEVICE);
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-static inline int mlx5e_page_alloc_mapped(struct mlx5e_rq *rq,
|
|
|
- struct mlx5e_dma_info *dma_info)
|
|
|
-{
|
|
|
- struct page *page;
|
|
|
-
|
|
|
- if (mlx5e_rx_cache_get(rq, dma_info))
|
|
|
- return 0;
|
|
|
-
|
|
|
- page = dev_alloc_page();
|
|
|
- if (unlikely(!page))
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- dma_info->page = page;
|
|
|
- dma_info->addr = dma_map_page(rq->pdev, page, 0, PAGE_SIZE,
|
|
|
- DMA_FROM_DEVICE);
|
|
|
- if (unlikely(dma_mapping_error(rq->pdev, dma_info->addr))) {
|
|
|
- put_page(page);
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-void mlx5e_page_release(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info,
|
|
|
- bool recycle)
|
|
|
-{
|
|
|
- if (likely(recycle) && mlx5e_rx_cache_put(rq, dma_info))
|
|
|
- return;
|
|
|
-
|
|
|
- dma_unmap_page(rq->pdev, dma_info->addr, PAGE_SIZE, DMA_FROM_DEVICE);
|
|
|
- put_page(dma_info->page);
|
|
|
-}
|
|
|
-
|
|
|
static int mlx5e_alloc_rx_umr_mpwqe(struct mlx5e_rq *rq,
|
|
|
struct mlx5e_rx_wqe *wqe,
|
|
|
u16 ix)
|
|
@@ -448,7 +424,7 @@ void mlx5e_post_rx_mpwqe(struct mlx5e_rq *rq)
|
|
|
mlx5_wq_ll_update_db_record(wq);
|
|
|
}
|
|
|
|
|
|
-int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, struct mlx5e_rx_wqe *wqe, u16 ix)
|
|
|
+int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, struct mlx5e_rx_wqe *wqe, u16 ix)
|
|
|
{
|
|
|
int err;
|
|
|
|
|
@@ -658,31 +634,46 @@ static inline void mlx5e_complete_rx_cqe(struct mlx5e_rq *rq,
|
|
|
|
|
|
void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
|
|
|
{
|
|
|
+ struct mlx5e_dma_info *di;
|
|
|
struct mlx5e_rx_wqe *wqe;
|
|
|
- struct sk_buff *skb;
|
|
|
__be16 wqe_counter_be;
|
|
|
+ struct sk_buff *skb;
|
|
|
u16 wqe_counter;
|
|
|
u32 cqe_bcnt;
|
|
|
+ void *va;
|
|
|
|
|
|
wqe_counter_be = cqe->wqe_counter;
|
|
|
wqe_counter = be16_to_cpu(wqe_counter_be);
|
|
|
wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_counter);
|
|
|
- skb = rq->skb[wqe_counter];
|
|
|
- prefetch(skb->data);
|
|
|
- rq->skb[wqe_counter] = NULL;
|
|
|
+ di = &rq->dma_info[wqe_counter];
|
|
|
+ va = page_address(di->page);
|
|
|
|
|
|
- dma_unmap_single(rq->pdev,
|
|
|
- *((dma_addr_t *)skb->cb),
|
|
|
- rq->wqe_sz,
|
|
|
- DMA_FROM_DEVICE);
|
|
|
+ dma_sync_single_range_for_cpu(rq->pdev,
|
|
|
+ di->addr,
|
|
|
+ MLX5_RX_HEADROOM,
|
|
|
+ rq->buff.wqe_sz,
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
+ prefetch(va + MLX5_RX_HEADROOM);
|
|
|
|
|
|
if (unlikely((cqe->op_own >> 4) != MLX5_CQE_RESP_SEND)) {
|
|
|
rq->stats.wqe_err++;
|
|
|
- dev_kfree_skb(skb);
|
|
|
+ mlx5e_page_release(rq, di, true);
|
|
|
goto wq_ll_pop;
|
|
|
}
|
|
|
|
|
|
+ skb = build_skb(va, RQ_PAGE_SIZE(rq));
|
|
|
+ if (unlikely(!skb)) {
|
|
|
+ rq->stats.buff_alloc_err++;
|
|
|
+ mlx5e_page_release(rq, di, true);
|
|
|
+ goto wq_ll_pop;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* queue up for recycling ..*/
|
|
|
+ page_ref_inc(di->page);
|
|
|
+ mlx5e_page_release(rq, di, true);
|
|
|
+
|
|
|
cqe_bcnt = be32_to_cpu(cqe->byte_cnt);
|
|
|
+ skb_reserve(skb, MLX5_RX_HEADROOM);
|
|
|
skb_put(skb, cqe_bcnt);
|
|
|
|
|
|
mlx5e_complete_rx_cqe(rq, cqe, cqe_bcnt, skb);
|