1aa8bca4cSXuan Zhuo // SPDX-License-Identifier: GPL-2.0-or-later 2aa8bca4cSXuan Zhuo /* 3aa8bca4cSXuan Zhuo * Driver for Alibaba Elastic Ethernet Adapter. 4aa8bca4cSXuan Zhuo * 5aa8bca4cSXuan Zhuo * Copyright (C) 2025 Alibaba Inc. 6aa8bca4cSXuan Zhuo */ 7aa8bca4cSXuan Zhuo 8aa8bca4cSXuan Zhuo #include <net/netdev_rx_queue.h> 9aa8bca4cSXuan Zhuo #include <net/page_pool/helpers.h> 10aa8bca4cSXuan Zhuo 11aa8bca4cSXuan Zhuo #include "eea_adminq.h" 12aa8bca4cSXuan Zhuo #include "eea_net.h" 13aa8bca4cSXuan Zhuo #include "eea_pci.h" 14aa8bca4cSXuan Zhuo #include "eea_ring.h" 15aa8bca4cSXuan Zhuo 16aa8bca4cSXuan Zhuo #define EEA_ENABLE_F_NAPI BIT(0) 17aa8bca4cSXuan Zhuo 18aa8bca4cSXuan Zhuo #define EEA_PAGE_FRAGS_NUM 1024 19aa8bca4cSXuan Zhuo 20df9cad6bSXuan Zhuo #define EEA_RX_BUF_ALIGN 128 21df9cad6bSXuan Zhuo 22df9cad6bSXuan Zhuo #define EEA_RX_BUF_MAX_LEN (10 * 1024) 23df9cad6bSXuan Zhuo 24df9cad6bSXuan Zhuo struct eea_rx_ctx { 25df9cad6bSXuan Zhuo u32 len; 26df9cad6bSXuan Zhuo u32 hdr_len; 27df9cad6bSXuan Zhuo 28df9cad6bSXuan Zhuo u16 flags; 29df9cad6bSXuan Zhuo bool more; 30df9cad6bSXuan Zhuo 31df9cad6bSXuan Zhuo struct eea_rx_meta *meta; 32*5f4f7bc0SXuan Zhuo 33*5f4f7bc0SXuan Zhuo struct eea_rx_ctx_stats stats; 34df9cad6bSXuan Zhuo }; 35df9cad6bSXuan Zhuo 36df9cad6bSXuan Zhuo static struct eea_rx_meta *eea_rx_meta_get(struct eea_net_rx *rx) 37df9cad6bSXuan Zhuo { 38df9cad6bSXuan Zhuo struct eea_rx_meta *meta; 39df9cad6bSXuan Zhuo 40df9cad6bSXuan Zhuo if (!rx->free) 41df9cad6bSXuan Zhuo return NULL; 42df9cad6bSXuan Zhuo 43df9cad6bSXuan Zhuo meta = rx->free; 44df9cad6bSXuan Zhuo rx->free = meta->next; 45df9cad6bSXuan Zhuo 46df9cad6bSXuan Zhuo return meta; 47df9cad6bSXuan Zhuo } 48df9cad6bSXuan Zhuo 49df9cad6bSXuan Zhuo static void eea_rx_meta_put(struct eea_net_rx *rx, struct eea_rx_meta *meta) 50df9cad6bSXuan Zhuo { 51df9cad6bSXuan Zhuo meta->next = rx->free; 52df9cad6bSXuan Zhuo rx->free = meta; 53df9cad6bSXuan Zhuo } 54df9cad6bSXuan Zhuo 55aa8bca4cSXuan Zhuo static void eea_free_rx_buffer(struct eea_net_rx *rx, struct eea_rx_meta *meta, 56aa8bca4cSXuan Zhuo bool allow_direct) 57aa8bca4cSXuan Zhuo { 58aa8bca4cSXuan Zhuo u32 drain_count; 59aa8bca4cSXuan Zhuo 60aa8bca4cSXuan Zhuo drain_count = EEA_PAGE_FRAGS_NUM - meta->frags; 61aa8bca4cSXuan Zhuo 62aa8bca4cSXuan Zhuo if (page_pool_unref_page(meta->page, drain_count) == 0) 63aa8bca4cSXuan Zhuo page_pool_put_unrefed_page(rx->pp, meta->page, -1, 64aa8bca4cSXuan Zhuo allow_direct); 65aa8bca4cSXuan Zhuo 66aa8bca4cSXuan Zhuo meta->page = NULL; 67aa8bca4cSXuan Zhuo } 68aa8bca4cSXuan Zhuo 69df9cad6bSXuan Zhuo static void eea_rx_meta_dma_sync_for_device(struct eea_net_rx *rx, 70df9cad6bSXuan Zhuo struct eea_rx_meta *meta) 71df9cad6bSXuan Zhuo { 72df9cad6bSXuan Zhuo u32 len; 73df9cad6bSXuan Zhuo 74df9cad6bSXuan Zhuo if (meta->sync_for_cpu <= meta->offset + rx->headroom) 75df9cad6bSXuan Zhuo return; 76df9cad6bSXuan Zhuo 77df9cad6bSXuan Zhuo len = meta->sync_for_cpu - meta->offset - rx->headroom; 78df9cad6bSXuan Zhuo 79df9cad6bSXuan Zhuo dma_sync_single_for_device(rx->enet->edev->dma_dev, 80df9cad6bSXuan Zhuo meta->dma + meta->offset + rx->headroom, 81df9cad6bSXuan Zhuo len, DMA_FROM_DEVICE); 82df9cad6bSXuan Zhuo meta->sync_for_cpu = 0; 83df9cad6bSXuan Zhuo } 84df9cad6bSXuan Zhuo 85df9cad6bSXuan Zhuo static void meta_align_offset(struct eea_net_rx *rx, struct eea_rx_meta *meta) 86df9cad6bSXuan Zhuo { 87df9cad6bSXuan Zhuo int h, b; 88df9cad6bSXuan Zhuo 89df9cad6bSXuan Zhuo h = rx->headroom; 90df9cad6bSXuan Zhuo b = meta->offset + h; 91df9cad6bSXuan Zhuo 92df9cad6bSXuan Zhuo /* For better performance, we align the buffer address to 93df9cad6bSXuan Zhuo * EEA_RX_BUF_ALIGN, as required by the device design. 94df9cad6bSXuan Zhuo */ 95df9cad6bSXuan Zhuo b = ALIGN(b, EEA_RX_BUF_ALIGN); 96df9cad6bSXuan Zhuo 97df9cad6bSXuan Zhuo meta->offset = b - h; 98df9cad6bSXuan Zhuo } 99df9cad6bSXuan Zhuo 100df9cad6bSXuan Zhuo static int eea_alloc_rx_buffer(struct eea_net_rx *rx, struct eea_rx_meta *meta) 101df9cad6bSXuan Zhuo { 102df9cad6bSXuan Zhuo struct page *page; 103df9cad6bSXuan Zhuo 104df9cad6bSXuan Zhuo if (meta->page) { 105df9cad6bSXuan Zhuo eea_rx_meta_dma_sync_for_device(rx, meta); 106df9cad6bSXuan Zhuo return 0; 107df9cad6bSXuan Zhuo } 108df9cad6bSXuan Zhuo 109df9cad6bSXuan Zhuo page = page_pool_dev_alloc_pages(rx->pp); 110df9cad6bSXuan Zhuo if (!page) 111df9cad6bSXuan Zhuo return -ENOMEM; 112df9cad6bSXuan Zhuo 113df9cad6bSXuan Zhuo page_pool_fragment_page(page, EEA_PAGE_FRAGS_NUM); 114df9cad6bSXuan Zhuo 115df9cad6bSXuan Zhuo meta->page = page; 116df9cad6bSXuan Zhuo meta->dma = page_pool_get_dma_addr(page); 117df9cad6bSXuan Zhuo meta->offset = 0; 118df9cad6bSXuan Zhuo meta->frags = 0; 119df9cad6bSXuan Zhuo meta->sync_for_cpu = 0; 120df9cad6bSXuan Zhuo 121df9cad6bSXuan Zhuo meta_align_offset(rx, meta); 122df9cad6bSXuan Zhuo 123df9cad6bSXuan Zhuo return 0; 124df9cad6bSXuan Zhuo } 125df9cad6bSXuan Zhuo 126df9cad6bSXuan Zhuo static u32 eea_consume_rx_buffer(struct eea_net_rx *rx, 127df9cad6bSXuan Zhuo struct eea_rx_meta *meta, 128df9cad6bSXuan Zhuo u32 consumed) 129df9cad6bSXuan Zhuo { 130df9cad6bSXuan Zhuo u32 offset; 131df9cad6bSXuan Zhuo int min; 132df9cad6bSXuan Zhuo 133df9cad6bSXuan Zhuo offset = meta->offset; 134df9cad6bSXuan Zhuo 135df9cad6bSXuan Zhuo meta->offset += consumed; 136df9cad6bSXuan Zhuo ++meta->frags; 137df9cad6bSXuan Zhuo 138df9cad6bSXuan Zhuo min = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 139df9cad6bSXuan Zhuo min += rx->headroom; 140df9cad6bSXuan Zhuo min += SKB_DATA_ALIGN(ETH_DATA_LEN); 141df9cad6bSXuan Zhuo 142df9cad6bSXuan Zhuo meta_align_offset(rx, meta); 143df9cad6bSXuan Zhuo 144df9cad6bSXuan Zhuo if (min + meta->offset > PAGE_SIZE) { 145df9cad6bSXuan Zhuo eea_free_rx_buffer(rx, meta, true); 146df9cad6bSXuan Zhuo return PAGE_SIZE - offset; 147df9cad6bSXuan Zhuo } 148df9cad6bSXuan Zhuo 149df9cad6bSXuan Zhuo return meta->offset - offset; 150df9cad6bSXuan Zhuo } 151df9cad6bSXuan Zhuo 152aa8bca4cSXuan Zhuo static void eea_free_rx_hdr(struct eea_net_rx *rx, struct eea_net_cfg *cfg) 153aa8bca4cSXuan Zhuo { 154aa8bca4cSXuan Zhuo struct eea_rx_meta *meta; 155aa8bca4cSXuan Zhuo int i; 156aa8bca4cSXuan Zhuo 157aa8bca4cSXuan Zhuo for (i = 0; i < cfg->rx_ring_depth; ++i) { 158aa8bca4cSXuan Zhuo meta = &rx->meta[i]; 159aa8bca4cSXuan Zhuo meta->hdr_addr = NULL; 160aa8bca4cSXuan Zhuo 161aa8bca4cSXuan Zhuo if (!meta->hdr_page) 162aa8bca4cSXuan Zhuo continue; 163aa8bca4cSXuan Zhuo 164aa8bca4cSXuan Zhuo dma_unmap_page(rx->dma_dev, meta->hdr_dma, PAGE_SIZE, 165aa8bca4cSXuan Zhuo DMA_FROM_DEVICE); 166aa8bca4cSXuan Zhuo put_page(meta->hdr_page); 167aa8bca4cSXuan Zhuo 168aa8bca4cSXuan Zhuo meta->hdr_page = NULL; 169aa8bca4cSXuan Zhuo } 170aa8bca4cSXuan Zhuo } 171aa8bca4cSXuan Zhuo 172aa8bca4cSXuan Zhuo static int eea_alloc_rx_hdr(struct eea_net_init_ctx *ctx, struct eea_net_rx *rx) 173aa8bca4cSXuan Zhuo { 174aa8bca4cSXuan Zhuo struct page *hdr_page = NULL; 175aa8bca4cSXuan Zhuo struct eea_rx_meta *meta; 176aa8bca4cSXuan Zhuo u32 offset = 0, hdrsize; 177aa8bca4cSXuan Zhuo struct device *dmadev; 178aa8bca4cSXuan Zhuo dma_addr_t dma; 179aa8bca4cSXuan Zhuo int i; 180aa8bca4cSXuan Zhuo 181aa8bca4cSXuan Zhuo dmadev = ctx->edev->dma_dev; 182aa8bca4cSXuan Zhuo hdrsize = ctx->cfg.split_hdr; 183aa8bca4cSXuan Zhuo 184aa8bca4cSXuan Zhuo for (i = 0; i < ctx->cfg.rx_ring_depth; ++i) { 185aa8bca4cSXuan Zhuo meta = &rx->meta[i]; 186aa8bca4cSXuan Zhuo meta->hdr_page = NULL; 187aa8bca4cSXuan Zhuo 188aa8bca4cSXuan Zhuo if (!hdr_page || offset + hdrsize > PAGE_SIZE) { 189aa8bca4cSXuan Zhuo hdr_page = alloc_page(GFP_KERNEL); 190aa8bca4cSXuan Zhuo if (!hdr_page) 191aa8bca4cSXuan Zhuo goto err; 192aa8bca4cSXuan Zhuo 193aa8bca4cSXuan Zhuo dma = dma_map_page(dmadev, hdr_page, 0, PAGE_SIZE, 194aa8bca4cSXuan Zhuo DMA_FROM_DEVICE); 195aa8bca4cSXuan Zhuo 196aa8bca4cSXuan Zhuo if (unlikely(dma_mapping_error(dmadev, dma))) { 197aa8bca4cSXuan Zhuo put_page(hdr_page); 198aa8bca4cSXuan Zhuo goto err; 199aa8bca4cSXuan Zhuo } 200aa8bca4cSXuan Zhuo 201aa8bca4cSXuan Zhuo offset = 0; 202aa8bca4cSXuan Zhuo meta->hdr_page = hdr_page; 203aa8bca4cSXuan Zhuo } 204aa8bca4cSXuan Zhuo 205aa8bca4cSXuan Zhuo meta->hdr_dma = dma + offset; 206aa8bca4cSXuan Zhuo meta->hdr_addr = page_address(hdr_page) + offset; 207aa8bca4cSXuan Zhuo offset += hdrsize; 208aa8bca4cSXuan Zhuo } 209aa8bca4cSXuan Zhuo 210aa8bca4cSXuan Zhuo return 0; 211aa8bca4cSXuan Zhuo 212aa8bca4cSXuan Zhuo err: 213aa8bca4cSXuan Zhuo eea_free_rx_hdr(rx, &ctx->cfg); 214aa8bca4cSXuan Zhuo return -ENOMEM; 215aa8bca4cSXuan Zhuo } 216aa8bca4cSXuan Zhuo 217df9cad6bSXuan Zhuo static void eea_rx_meta_dma_sync_for_cpu(struct eea_net_rx *rx, 218df9cad6bSXuan Zhuo struct eea_rx_meta *meta, u32 len) 219df9cad6bSXuan Zhuo { 220df9cad6bSXuan Zhuo dma_sync_single_for_cpu(rx->enet->edev->dma_dev, 221df9cad6bSXuan Zhuo meta->dma + meta->offset + meta->headroom, 222df9cad6bSXuan Zhuo len, DMA_FROM_DEVICE); 223df9cad6bSXuan Zhuo meta->sync_for_cpu = meta->offset + meta->headroom + len; 224df9cad6bSXuan Zhuo } 225df9cad6bSXuan Zhuo 226df9cad6bSXuan Zhuo static int eea_harden_check_overflow(struct eea_rx_ctx *ctx, 227df9cad6bSXuan Zhuo struct eea_net *enet) 228df9cad6bSXuan Zhuo { 229df9cad6bSXuan Zhuo u32 max_len; 230df9cad6bSXuan Zhuo 231df9cad6bSXuan Zhuo max_len = ctx->meta->truesize - ctx->meta->headroom - 232df9cad6bSXuan Zhuo ctx->meta->tailroom; 233df9cad6bSXuan Zhuo 234df9cad6bSXuan Zhuo if (unlikely(ctx->len > max_len)) { 235df9cad6bSXuan Zhuo pr_debug("%s: rx error: len %u exceeds truesize %u\n", 236df9cad6bSXuan Zhuo enet->netdev->name, ctx->len, max_len); 237*5f4f7bc0SXuan Zhuo ++ctx->stats.length_errors; 238df9cad6bSXuan Zhuo return -EINVAL; 239df9cad6bSXuan Zhuo } 240df9cad6bSXuan Zhuo 241df9cad6bSXuan Zhuo return 0; 242df9cad6bSXuan Zhuo } 243df9cad6bSXuan Zhuo 244df9cad6bSXuan Zhuo static int eea_harden_check_size(struct eea_rx_ctx *ctx, struct eea_net *enet) 245df9cad6bSXuan Zhuo { 246df9cad6bSXuan Zhuo int err; 247df9cad6bSXuan Zhuo 248df9cad6bSXuan Zhuo err = eea_harden_check_overflow(ctx, enet); 249df9cad6bSXuan Zhuo if (err) 250df9cad6bSXuan Zhuo return err; 251df9cad6bSXuan Zhuo 252df9cad6bSXuan Zhuo if (ctx->hdr_len) { 253df9cad6bSXuan Zhuo if (unlikely(ctx->hdr_len < ETH_HLEN)) { 254df9cad6bSXuan Zhuo pr_debug("%s: short hdr %u\n", enet->netdev->name, 255df9cad6bSXuan Zhuo ctx->hdr_len); 256*5f4f7bc0SXuan Zhuo ++ctx->stats.length_errors; 257df9cad6bSXuan Zhuo return -EINVAL; 258df9cad6bSXuan Zhuo } 259df9cad6bSXuan Zhuo 260df9cad6bSXuan Zhuo if (unlikely(ctx->hdr_len > enet->cfg.split_hdr)) { 261df9cad6bSXuan Zhuo pr_debug("%s: rx error: hdr len %u exceeds hdr buffer size %u\n", 262df9cad6bSXuan Zhuo enet->netdev->name, ctx->hdr_len, 263df9cad6bSXuan Zhuo enet->cfg.split_hdr); 264*5f4f7bc0SXuan Zhuo ++ctx->stats.length_errors; 265df9cad6bSXuan Zhuo return -EINVAL; 266df9cad6bSXuan Zhuo } 267df9cad6bSXuan Zhuo 268df9cad6bSXuan Zhuo return 0; 269df9cad6bSXuan Zhuo } 270df9cad6bSXuan Zhuo 271df9cad6bSXuan Zhuo if (unlikely(ctx->len < ETH_HLEN)) { 272df9cad6bSXuan Zhuo pr_debug("%s: short packet %u\n", enet->netdev->name, ctx->len); 273*5f4f7bc0SXuan Zhuo ++ctx->stats.length_errors; 274df9cad6bSXuan Zhuo return -EINVAL; 275df9cad6bSXuan Zhuo } 276df9cad6bSXuan Zhuo 277df9cad6bSXuan Zhuo return 0; 278df9cad6bSXuan Zhuo } 279df9cad6bSXuan Zhuo 280df9cad6bSXuan Zhuo static struct sk_buff *eea_build_skb(void *buf, u32 buflen, u32 headroom, 281df9cad6bSXuan Zhuo u32 len) 282df9cad6bSXuan Zhuo { 283df9cad6bSXuan Zhuo struct sk_buff *skb; 284df9cad6bSXuan Zhuo 285df9cad6bSXuan Zhuo skb = build_skb(buf, buflen); 286df9cad6bSXuan Zhuo if (unlikely(!skb)) 287df9cad6bSXuan Zhuo return NULL; 288df9cad6bSXuan Zhuo 289df9cad6bSXuan Zhuo skb_reserve(skb, headroom); 290df9cad6bSXuan Zhuo skb_put(skb, len); 291df9cad6bSXuan Zhuo 292df9cad6bSXuan Zhuo return skb; 293df9cad6bSXuan Zhuo } 294df9cad6bSXuan Zhuo 295df9cad6bSXuan Zhuo static struct sk_buff *eea_rx_build_split_hdr_skb(struct eea_net_rx *rx, 296df9cad6bSXuan Zhuo struct eea_rx_ctx *ctx) 297df9cad6bSXuan Zhuo { 298df9cad6bSXuan Zhuo struct eea_rx_meta *meta = ctx->meta; 299df9cad6bSXuan Zhuo u32 truesize, offset; 300df9cad6bSXuan Zhuo struct sk_buff *skb; 301df9cad6bSXuan Zhuo struct page *page; 302df9cad6bSXuan Zhuo 303df9cad6bSXuan Zhuo dma_sync_single_for_cpu(rx->enet->edev->dma_dev, meta->hdr_dma, 304df9cad6bSXuan Zhuo ctx->hdr_len, DMA_FROM_DEVICE); 305df9cad6bSXuan Zhuo 306df9cad6bSXuan Zhuo skb = napi_alloc_skb(rx->napi, ctx->hdr_len); 307df9cad6bSXuan Zhuo if (unlikely(!skb)) 308df9cad6bSXuan Zhuo return NULL; 309df9cad6bSXuan Zhuo 310df9cad6bSXuan Zhuo skb_put_data(skb, ctx->meta->hdr_addr, ctx->hdr_len); 311df9cad6bSXuan Zhuo 312df9cad6bSXuan Zhuo if (ctx->len) { 313df9cad6bSXuan Zhuo page = meta->page; 314df9cad6bSXuan Zhuo offset = meta->offset + meta->headroom; 315df9cad6bSXuan Zhuo 316df9cad6bSXuan Zhuo truesize = eea_consume_rx_buffer(rx, meta, 317df9cad6bSXuan Zhuo meta->headroom + ctx->len); 318df9cad6bSXuan Zhuo 319df9cad6bSXuan Zhuo skb_add_rx_frag(skb, 0, page, offset, ctx->len, truesize); 320df9cad6bSXuan Zhuo } 321df9cad6bSXuan Zhuo 322df9cad6bSXuan Zhuo skb_mark_for_recycle(skb); 323df9cad6bSXuan Zhuo 324df9cad6bSXuan Zhuo return skb; 325df9cad6bSXuan Zhuo } 326df9cad6bSXuan Zhuo 327df9cad6bSXuan Zhuo static struct sk_buff *eea_rx_build_skb(struct eea_net_rx *rx, 328df9cad6bSXuan Zhuo struct eea_rx_ctx *ctx) 329df9cad6bSXuan Zhuo { 330df9cad6bSXuan Zhuo struct eea_rx_meta *meta = ctx->meta; 331df9cad6bSXuan Zhuo u32 shinfo_size, bufsize, truesize; 332df9cad6bSXuan Zhuo struct sk_buff *skb; 333df9cad6bSXuan Zhuo struct page *page; 334df9cad6bSXuan Zhuo void *buf; 335df9cad6bSXuan Zhuo 336df9cad6bSXuan Zhuo page = meta->page; 337df9cad6bSXuan Zhuo 338df9cad6bSXuan Zhuo shinfo_size = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 339df9cad6bSXuan Zhuo 340df9cad6bSXuan Zhuo buf = page_address(page) + meta->offset; 341df9cad6bSXuan Zhuo bufsize = meta->headroom + SKB_DATA_ALIGN(ctx->len) + shinfo_size; 342df9cad6bSXuan Zhuo 343df9cad6bSXuan Zhuo skb = eea_build_skb(buf, bufsize, meta->headroom, ctx->len); 344df9cad6bSXuan Zhuo if (unlikely(!skb)) 345df9cad6bSXuan Zhuo return NULL; 346df9cad6bSXuan Zhuo 347df9cad6bSXuan Zhuo truesize = eea_consume_rx_buffer(rx, meta, bufsize); 348df9cad6bSXuan Zhuo skb_mark_for_recycle(skb); 349df9cad6bSXuan Zhuo 350df9cad6bSXuan Zhuo skb->truesize += truesize - bufsize; 351df9cad6bSXuan Zhuo 352df9cad6bSXuan Zhuo return skb; 353df9cad6bSXuan Zhuo } 354df9cad6bSXuan Zhuo 355df9cad6bSXuan Zhuo static void process_remain_buf(struct eea_net_rx *rx, struct eea_rx_ctx *ctx) 356df9cad6bSXuan Zhuo { 357df9cad6bSXuan Zhuo struct eea_net *enet = rx->enet; 358df9cad6bSXuan Zhuo struct sk_buff *head_skb; 359df9cad6bSXuan Zhuo u32 offset, truesize, nr_frags; 360df9cad6bSXuan Zhuo struct page *page; 361df9cad6bSXuan Zhuo 362df9cad6bSXuan Zhuo if (eea_harden_check_overflow(ctx, enet)) 363df9cad6bSXuan Zhuo goto err; 364df9cad6bSXuan Zhuo 365df9cad6bSXuan Zhuo head_skb = rx->pkt.head_skb; 366df9cad6bSXuan Zhuo 367df9cad6bSXuan Zhuo nr_frags = skb_shinfo(head_skb)->nr_frags; 368df9cad6bSXuan Zhuo if (unlikely(nr_frags >= MAX_SKB_FRAGS)) 369df9cad6bSXuan Zhuo goto err; 370df9cad6bSXuan Zhuo 371df9cad6bSXuan Zhuo offset = ctx->meta->offset + ctx->meta->headroom; 372df9cad6bSXuan Zhuo page = ctx->meta->page; 373df9cad6bSXuan Zhuo truesize = eea_consume_rx_buffer(rx, ctx->meta, 374df9cad6bSXuan Zhuo ctx->meta->headroom + ctx->len); 375df9cad6bSXuan Zhuo 376df9cad6bSXuan Zhuo skb_add_rx_frag(head_skb, nr_frags, page, offset, ctx->len, truesize); 377df9cad6bSXuan Zhuo 378df9cad6bSXuan Zhuo return; 379df9cad6bSXuan Zhuo 380df9cad6bSXuan Zhuo err: 381df9cad6bSXuan Zhuo dev_kfree_skb(rx->pkt.head_skb); 382*5f4f7bc0SXuan Zhuo ++ctx->stats.drops; 383df9cad6bSXuan Zhuo rx->pkt.do_drop = true; 384df9cad6bSXuan Zhuo rx->pkt.head_skb = NULL; 385df9cad6bSXuan Zhuo } 386df9cad6bSXuan Zhuo 387df9cad6bSXuan Zhuo static void process_first_buf(struct eea_net_rx *rx, struct eea_rx_ctx *ctx) 388df9cad6bSXuan Zhuo { 389df9cad6bSXuan Zhuo struct eea_net *enet = rx->enet; 390df9cad6bSXuan Zhuo struct sk_buff *skb = NULL; 391df9cad6bSXuan Zhuo 392df9cad6bSXuan Zhuo if (eea_harden_check_size(ctx, enet)) 393df9cad6bSXuan Zhuo goto err; 394df9cad6bSXuan Zhuo 395df9cad6bSXuan Zhuo rx->pkt.data_valid = ctx->flags & EEA_DESC_F_DATA_VALID; 396df9cad6bSXuan Zhuo 397df9cad6bSXuan Zhuo if (ctx->hdr_len) 398df9cad6bSXuan Zhuo skb = eea_rx_build_split_hdr_skb(rx, ctx); 399df9cad6bSXuan Zhuo else 400df9cad6bSXuan Zhuo skb = eea_rx_build_skb(rx, ctx); 401df9cad6bSXuan Zhuo 402df9cad6bSXuan Zhuo if (unlikely(!skb)) 403df9cad6bSXuan Zhuo goto err; 404df9cad6bSXuan Zhuo 405df9cad6bSXuan Zhuo rx->pkt.head_skb = skb; 406df9cad6bSXuan Zhuo 407df9cad6bSXuan Zhuo return; 408df9cad6bSXuan Zhuo 409df9cad6bSXuan Zhuo err: 410*5f4f7bc0SXuan Zhuo ++ctx->stats.drops; 411df9cad6bSXuan Zhuo rx->pkt.do_drop = true; 412df9cad6bSXuan Zhuo } 413df9cad6bSXuan Zhuo 414df9cad6bSXuan Zhuo static void eea_submit_skb(struct eea_net_rx *rx, struct sk_buff *skb, 415df9cad6bSXuan Zhuo struct eea_rx_cdesc *desc) 416df9cad6bSXuan Zhuo { 417df9cad6bSXuan Zhuo struct eea_net *enet = rx->enet; 418df9cad6bSXuan Zhuo 419df9cad6bSXuan Zhuo if (rx->pkt.data_valid) 420df9cad6bSXuan Zhuo skb->ip_summed = CHECKSUM_UNNECESSARY; 421df9cad6bSXuan Zhuo 422df9cad6bSXuan Zhuo if (enet->cfg.ts_cfg.rx_filter == HWTSTAMP_FILTER_ALL) 423df9cad6bSXuan Zhuo skb_hwtstamps(skb)->hwtstamp = EEA_DESC_TS(desc) + 424df9cad6bSXuan Zhuo enet->hw_ts_offset; 425df9cad6bSXuan Zhuo 426df9cad6bSXuan Zhuo skb_record_rx_queue(skb, rx->index); 427df9cad6bSXuan Zhuo skb->protocol = eth_type_trans(skb, enet->netdev); 428df9cad6bSXuan Zhuo 429df9cad6bSXuan Zhuo napi_gro_receive(rx->napi, skb); 430df9cad6bSXuan Zhuo } 431df9cad6bSXuan Zhuo 432df9cad6bSXuan Zhuo static int eea_rx_desc_to_ctx(struct eea_net_rx *rx, 433df9cad6bSXuan Zhuo struct eea_rx_ctx *ctx, 434df9cad6bSXuan Zhuo struct eea_rx_cdesc *desc) 435df9cad6bSXuan Zhuo { 436df9cad6bSXuan Zhuo u16 id; 437df9cad6bSXuan Zhuo 438df9cad6bSXuan Zhuo ctx->meta = NULL; 439df9cad6bSXuan Zhuo 440df9cad6bSXuan Zhuo id = le16_to_cpu(desc->id); 441df9cad6bSXuan Zhuo if (unlikely(id >= rx->ering->num)) { 442df9cad6bSXuan Zhuo if (net_ratelimit()) 443df9cad6bSXuan Zhuo netdev_err(rx->enet->netdev, "rx invalid id %d\n", id); 444df9cad6bSXuan Zhuo return -EINVAL; 445df9cad6bSXuan Zhuo } 446df9cad6bSXuan Zhuo 447df9cad6bSXuan Zhuo ctx->meta = &rx->meta[id]; 448df9cad6bSXuan Zhuo if (!ctx->meta->in_use) { 449df9cad6bSXuan Zhuo if (net_ratelimit()) 450df9cad6bSXuan Zhuo netdev_err(rx->enet->netdev, "rx invalid id %d\n", id); 451df9cad6bSXuan Zhuo ctx->meta = NULL; 452df9cad6bSXuan Zhuo return -EINVAL; 453df9cad6bSXuan Zhuo } 454df9cad6bSXuan Zhuo 455df9cad6bSXuan Zhuo ctx->meta->in_use = false; 456df9cad6bSXuan Zhuo 457df9cad6bSXuan Zhuo ctx->len = le16_to_cpu(desc->len); 458df9cad6bSXuan Zhuo if (unlikely(ctx->len > ctx->meta->len)) { 459df9cad6bSXuan Zhuo if (net_ratelimit()) 460df9cad6bSXuan Zhuo netdev_err(rx->enet->netdev, "rx invalid len(%d) id:%d\n", 461df9cad6bSXuan Zhuo ctx->len, id); 462df9cad6bSXuan Zhuo return -EINVAL; 463df9cad6bSXuan Zhuo } 464df9cad6bSXuan Zhuo 465df9cad6bSXuan Zhuo ctx->flags = le16_to_cpu(desc->flags); 466df9cad6bSXuan Zhuo 467df9cad6bSXuan Zhuo ctx->hdr_len = 0; 468df9cad6bSXuan Zhuo if (ctx->flags & EEA_DESC_F_SPLIT_HDR) { 469df9cad6bSXuan Zhuo ctx->hdr_len = le16_to_cpu(desc->len_ex) & 470df9cad6bSXuan Zhuo EEA_RX_CDESC_HDR_LEN_MASK; 471*5f4f7bc0SXuan Zhuo ctx->stats.split_hdr_bytes += ctx->hdr_len; 472*5f4f7bc0SXuan Zhuo ++ctx->stats.split_hdr_packets; 473df9cad6bSXuan Zhuo } 474df9cad6bSXuan Zhuo 475df9cad6bSXuan Zhuo ctx->more = ctx->flags & EEA_RING_DESC_F_MORE; 476df9cad6bSXuan Zhuo 477df9cad6bSXuan Zhuo return 0; 478df9cad6bSXuan Zhuo } 479df9cad6bSXuan Zhuo 480df9cad6bSXuan Zhuo static int eea_cleanrx(struct eea_net_rx *rx, int budget, 481df9cad6bSXuan Zhuo struct eea_rx_ctx *ctx) 482df9cad6bSXuan Zhuo { 483df9cad6bSXuan Zhuo struct eea_rx_cdesc *desc; 484df9cad6bSXuan Zhuo struct eea_rx_meta *meta; 485df9cad6bSXuan Zhuo int recv, err; 486df9cad6bSXuan Zhuo 487df9cad6bSXuan Zhuo for (recv = 0; recv < budget; ) { 488df9cad6bSXuan Zhuo desc = eea_ering_cq_get_desc(rx->ering); 489df9cad6bSXuan Zhuo if (!desc) 490df9cad6bSXuan Zhuo break; 491df9cad6bSXuan Zhuo 492df9cad6bSXuan Zhuo err = eea_rx_desc_to_ctx(rx, ctx, desc); 493df9cad6bSXuan Zhuo if (unlikely(err)) { 494df9cad6bSXuan Zhuo if (ctx->meta) 495df9cad6bSXuan Zhuo eea_rx_meta_put(rx, ctx->meta); 496df9cad6bSXuan Zhuo 497*5f4f7bc0SXuan Zhuo if (rx->pkt.head_skb) { 498df9cad6bSXuan Zhuo dev_kfree_skb(rx->pkt.head_skb); 499*5f4f7bc0SXuan Zhuo ++ctx->stats.drops; 500*5f4f7bc0SXuan Zhuo } 501df9cad6bSXuan Zhuo 502df9cad6bSXuan Zhuo /* A hardware error occurred; we are attempting to 503df9cad6bSXuan Zhuo * mitigate the impact. Subsequent packets may be 504df9cad6bSXuan Zhuo * corrupted. 505df9cad6bSXuan Zhuo */ 506df9cad6bSXuan Zhuo ctx->more = false; 507df9cad6bSXuan Zhuo goto ack; 508df9cad6bSXuan Zhuo } 509df9cad6bSXuan Zhuo 510df9cad6bSXuan Zhuo meta = ctx->meta; 511df9cad6bSXuan Zhuo 512df9cad6bSXuan Zhuo if (unlikely(rx->pkt.do_drop)) 513df9cad6bSXuan Zhuo goto skip; 514df9cad6bSXuan Zhuo 515df9cad6bSXuan Zhuo eea_rx_meta_dma_sync_for_cpu(rx, meta, ctx->len); 516df9cad6bSXuan Zhuo 517df9cad6bSXuan Zhuo rx->pkt.recv_len += ctx->len; 518df9cad6bSXuan Zhuo rx->pkt.recv_len += ctx->hdr_len; 519df9cad6bSXuan Zhuo 520df9cad6bSXuan Zhuo if (!rx->pkt.idx) 521df9cad6bSXuan Zhuo process_first_buf(rx, ctx); 522df9cad6bSXuan Zhuo else 523df9cad6bSXuan Zhuo process_remain_buf(rx, ctx); 524df9cad6bSXuan Zhuo 525df9cad6bSXuan Zhuo ++rx->pkt.idx; 526df9cad6bSXuan Zhuo 527*5f4f7bc0SXuan Zhuo if (!ctx->more && rx->pkt.head_skb) { 528df9cad6bSXuan Zhuo eea_submit_skb(rx, rx->pkt.head_skb, desc); 529*5f4f7bc0SXuan Zhuo ctx->stats.bytes += rx->pkt.recv_len; 530*5f4f7bc0SXuan Zhuo ++ctx->stats.packets; 531*5f4f7bc0SXuan Zhuo } 532df9cad6bSXuan Zhuo 533df9cad6bSXuan Zhuo skip: 534df9cad6bSXuan Zhuo eea_rx_meta_put(rx, meta); 535df9cad6bSXuan Zhuo ack: 536df9cad6bSXuan Zhuo eea_ering_cq_ack_desc(rx->ering, 1); 537*5f4f7bc0SXuan Zhuo ++ctx->stats.descs; 538df9cad6bSXuan Zhuo 539df9cad6bSXuan Zhuo if (!ctx->more) { 540df9cad6bSXuan Zhuo memset(&rx->pkt, 0, sizeof(rx->pkt)); 541df9cad6bSXuan Zhuo ++recv; 542df9cad6bSXuan Zhuo } 543df9cad6bSXuan Zhuo } 544df9cad6bSXuan Zhuo 545df9cad6bSXuan Zhuo return recv; 546df9cad6bSXuan Zhuo } 547df9cad6bSXuan Zhuo 548df9cad6bSXuan Zhuo static void eea_rx_dma_sync_hdr(struct eea_net_rx *rx, dma_addr_t addr) 549df9cad6bSXuan Zhuo { 550df9cad6bSXuan Zhuo dma_sync_single_for_device(rx->dma_dev, addr, 551df9cad6bSXuan Zhuo rx->enet->cfg.split_hdr, 552df9cad6bSXuan Zhuo DMA_FROM_DEVICE); 553df9cad6bSXuan Zhuo } 554df9cad6bSXuan Zhuo 555df9cad6bSXuan Zhuo /* Only be called from napi. */ 556*5f4f7bc0SXuan Zhuo static void eea_rx_post(struct eea_net_rx *rx, struct eea_rx_ctx *ctx) 557df9cad6bSXuan Zhuo { 558df9cad6bSXuan Zhuo u32 tailroom, headroom, room, len; 559df9cad6bSXuan Zhuo struct eea_rx_meta *meta; 560df9cad6bSXuan Zhuo struct eea_rx_desc *desc; 561df9cad6bSXuan Zhuo int err = 0, num = 0; 562df9cad6bSXuan Zhuo dma_addr_t addr; 563df9cad6bSXuan Zhuo 564df9cad6bSXuan Zhuo tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 565df9cad6bSXuan Zhuo headroom = rx->headroom; 566df9cad6bSXuan Zhuo room = headroom + tailroom; 567df9cad6bSXuan Zhuo 568df9cad6bSXuan Zhuo while (true) { 569df9cad6bSXuan Zhuo meta = eea_rx_meta_get(rx); 570df9cad6bSXuan Zhuo if (!meta) 571df9cad6bSXuan Zhuo break; 572df9cad6bSXuan Zhuo 573df9cad6bSXuan Zhuo err = eea_alloc_rx_buffer(rx, meta); 574df9cad6bSXuan Zhuo if (err) { 575df9cad6bSXuan Zhuo eea_rx_meta_put(rx, meta); 576df9cad6bSXuan Zhuo break; 577df9cad6bSXuan Zhuo } 578df9cad6bSXuan Zhuo 579df9cad6bSXuan Zhuo len = min_t(u32, PAGE_SIZE - meta->offset - room, 580df9cad6bSXuan Zhuo EEA_RX_BUF_MAX_LEN); 581df9cad6bSXuan Zhuo 582df9cad6bSXuan Zhuo len = ALIGN_DOWN(len, SMP_CACHE_BYTES); 583df9cad6bSXuan Zhuo 584df9cad6bSXuan Zhuo addr = meta->dma + meta->offset + headroom; 585df9cad6bSXuan Zhuo 586df9cad6bSXuan Zhuo desc = eea_ering_sq_alloc_desc(rx->ering, meta->id, true, 0); 587df9cad6bSXuan Zhuo desc->addr = cpu_to_le64(addr); 588df9cad6bSXuan Zhuo desc->len = cpu_to_le16(len); 589df9cad6bSXuan Zhuo 590df9cad6bSXuan Zhuo if (meta->hdr_addr) { 591df9cad6bSXuan Zhuo eea_rx_dma_sync_hdr(rx, meta->hdr_dma); 592df9cad6bSXuan Zhuo desc->hdr_addr = cpu_to_le64(meta->hdr_dma); 593df9cad6bSXuan Zhuo } 594df9cad6bSXuan Zhuo 595df9cad6bSXuan Zhuo eea_ering_sq_commit_desc(rx->ering); 596df9cad6bSXuan Zhuo 597df9cad6bSXuan Zhuo meta->truesize = len + room; 598df9cad6bSXuan Zhuo meta->headroom = headroom; 599df9cad6bSXuan Zhuo meta->tailroom = tailroom; 600df9cad6bSXuan Zhuo meta->len = len; 601df9cad6bSXuan Zhuo meta->in_use = true; 602df9cad6bSXuan Zhuo ++num; 603df9cad6bSXuan Zhuo } 604df9cad6bSXuan Zhuo 605*5f4f7bc0SXuan Zhuo if (num) { 606df9cad6bSXuan Zhuo eea_ering_kick(rx->ering); 607*5f4f7bc0SXuan Zhuo ++ctx->stats.kicks; 608*5f4f7bc0SXuan Zhuo } 609df9cad6bSXuan Zhuo } 610df9cad6bSXuan Zhuo 611aa8bca4cSXuan Zhuo static int eea_poll(struct napi_struct *napi, int budget) 612aa8bca4cSXuan Zhuo { 613df9cad6bSXuan Zhuo struct eea_irq_blk *blk = container_of(napi, struct eea_irq_blk, napi); 614df9cad6bSXuan Zhuo struct eea_net_rx *rx = blk->rx; 615df9cad6bSXuan Zhuo struct eea_net_tx *tx = &rx->enet->tx[rx->index]; 616df9cad6bSXuan Zhuo struct eea_rx_ctx ctx = {}; 617df9cad6bSXuan Zhuo bool busy = false; 618df9cad6bSXuan Zhuo u32 received; 619df9cad6bSXuan Zhuo 620df9cad6bSXuan Zhuo busy |= eea_poll_tx(tx, budget) >= budget; 621df9cad6bSXuan Zhuo 622df9cad6bSXuan Zhuo received = eea_cleanrx(rx, budget, &ctx); 623df9cad6bSXuan Zhuo 624df9cad6bSXuan Zhuo if (rx->ering->num_free > budget) { 625df9cad6bSXuan Zhuo /* Due to the hardware design, there is no notification when 626df9cad6bSXuan Zhuo * buffers are exhausted. Therefore, we should proactively 627df9cad6bSXuan Zhuo * pre-fill the buffers to avoid starvation. 628df9cad6bSXuan Zhuo */ 629*5f4f7bc0SXuan Zhuo eea_rx_post(rx, &ctx); 630df9cad6bSXuan Zhuo 631df9cad6bSXuan Zhuo if (rx->ering->num - rx->ering->num_free < budget) 632df9cad6bSXuan Zhuo busy = true; 633df9cad6bSXuan Zhuo } 634df9cad6bSXuan Zhuo 635*5f4f7bc0SXuan Zhuo eea_update_rx_stats(&rx->stats, &ctx.stats); 636*5f4f7bc0SXuan Zhuo 637df9cad6bSXuan Zhuo busy |= received >= budget; 638df9cad6bSXuan Zhuo 639df9cad6bSXuan Zhuo if (busy) 640df9cad6bSXuan Zhuo return budget; 641df9cad6bSXuan Zhuo 642df9cad6bSXuan Zhuo if (napi_complete_done(napi, received)) 643df9cad6bSXuan Zhuo eea_ering_irq_active(rx->ering, tx->ering); 644df9cad6bSXuan Zhuo 645df9cad6bSXuan Zhuo return received; 646aa8bca4cSXuan Zhuo } 647aa8bca4cSXuan Zhuo 648aa8bca4cSXuan Zhuo static void eea_free_rx_buffers(struct eea_net_rx *rx, struct eea_net_cfg *cfg) 649aa8bca4cSXuan Zhuo { 650aa8bca4cSXuan Zhuo struct eea_rx_meta *meta; 651aa8bca4cSXuan Zhuo u32 i; 652aa8bca4cSXuan Zhuo 653df9cad6bSXuan Zhuo if (rx->pkt.head_skb) { 654df9cad6bSXuan Zhuo dev_kfree_skb(rx->pkt.head_skb); 655df9cad6bSXuan Zhuo rx->pkt.head_skb = NULL; 656df9cad6bSXuan Zhuo } 657df9cad6bSXuan Zhuo 658aa8bca4cSXuan Zhuo for (i = 0; i < cfg->rx_ring_depth; ++i) { 659aa8bca4cSXuan Zhuo meta = &rx->meta[i]; 660aa8bca4cSXuan Zhuo if (!meta->page) 661aa8bca4cSXuan Zhuo continue; 662aa8bca4cSXuan Zhuo 663aa8bca4cSXuan Zhuo eea_free_rx_buffer(rx, meta, false); 664aa8bca4cSXuan Zhuo } 665aa8bca4cSXuan Zhuo } 666aa8bca4cSXuan Zhuo 667aa8bca4cSXuan Zhuo static struct page_pool *eea_create_pp(struct eea_net_init_ctx *ctx, u32 idx) 668aa8bca4cSXuan Zhuo { 669aa8bca4cSXuan Zhuo struct page_pool_params pp_params = {0}; 670aa8bca4cSXuan Zhuo 671aa8bca4cSXuan Zhuo pp_params.order = 0; 672aa8bca4cSXuan Zhuo pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; 673aa8bca4cSXuan Zhuo pp_params.pool_size = ctx->cfg.rx_ring_depth; 674aa8bca4cSXuan Zhuo pp_params.nid = dev_to_node(ctx->edev->dma_dev); 675aa8bca4cSXuan Zhuo pp_params.dev = ctx->edev->dma_dev; 676aa8bca4cSXuan Zhuo pp_params.netdev = ctx->netdev; 677aa8bca4cSXuan Zhuo pp_params.dma_dir = DMA_FROM_DEVICE; 678aa8bca4cSXuan Zhuo pp_params.max_len = PAGE_SIZE; 679aa8bca4cSXuan Zhuo pp_params.queue_idx = idx; 680aa8bca4cSXuan Zhuo 681aa8bca4cSXuan Zhuo return page_pool_create(&pp_params); 682aa8bca4cSXuan Zhuo } 683aa8bca4cSXuan Zhuo 684aa8bca4cSXuan Zhuo static void eea_destroy_page_pool(struct eea_net_rx *rx) 685aa8bca4cSXuan Zhuo { 686aa8bca4cSXuan Zhuo if (rx->pp) 687aa8bca4cSXuan Zhuo page_pool_destroy(rx->pp); 688aa8bca4cSXuan Zhuo } 689aa8bca4cSXuan Zhuo 690aa8bca4cSXuan Zhuo void enet_rx_stop(struct eea_net_rx *rx) 691aa8bca4cSXuan Zhuo { 692aa8bca4cSXuan Zhuo if (rx->flags & EEA_ENABLE_F_NAPI) { 693aa8bca4cSXuan Zhuo rx->flags &= ~EEA_ENABLE_F_NAPI; 694aa8bca4cSXuan Zhuo 695aa8bca4cSXuan Zhuo disable_irq(rx->enet->irq_blks[rx->index].irq); 696aa8bca4cSXuan Zhuo napi_disable(rx->napi); 697aa8bca4cSXuan Zhuo 698aa8bca4cSXuan Zhuo page_pool_disable_direct_recycling(rx->pp); 699aa8bca4cSXuan Zhuo netif_napi_del(rx->napi); 700aa8bca4cSXuan Zhuo } 701aa8bca4cSXuan Zhuo } 702aa8bca4cSXuan Zhuo 703aa8bca4cSXuan Zhuo void enet_rx_start(struct eea_net_rx *rx) 704aa8bca4cSXuan Zhuo { 705aa8bca4cSXuan Zhuo netif_napi_add(rx->enet->netdev, rx->napi, eea_poll); 706aa8bca4cSXuan Zhuo 707aa8bca4cSXuan Zhuo page_pool_enable_direct_recycling(rx->pp, rx->napi); 708aa8bca4cSXuan Zhuo 709aa8bca4cSXuan Zhuo napi_enable(rx->napi); 710aa8bca4cSXuan Zhuo 711aa8bca4cSXuan Zhuo rx->flags |= EEA_ENABLE_F_NAPI; 712aa8bca4cSXuan Zhuo 713aa8bca4cSXuan Zhuo local_bh_disable(); 714aa8bca4cSXuan Zhuo napi_schedule(rx->napi); 715aa8bca4cSXuan Zhuo local_bh_enable(); 716aa8bca4cSXuan Zhuo 717aa8bca4cSXuan Zhuo enable_irq(rx->enet->irq_blks[rx->index].irq); 718aa8bca4cSXuan Zhuo } 719aa8bca4cSXuan Zhuo 720aa8bca4cSXuan Zhuo /* Maybe called before eea_bind_q_and_cfg. So the cfg must be passed. */ 721aa8bca4cSXuan Zhuo void eea_free_rx(struct eea_net_rx *rx, struct eea_net_cfg *cfg) 722aa8bca4cSXuan Zhuo { 723aa8bca4cSXuan Zhuo if (!rx) 724aa8bca4cSXuan Zhuo return; 725aa8bca4cSXuan Zhuo 726aa8bca4cSXuan Zhuo if (rx->ering) { 727aa8bca4cSXuan Zhuo eea_ering_free(rx->ering); 728aa8bca4cSXuan Zhuo rx->ering = NULL; 729aa8bca4cSXuan Zhuo } 730aa8bca4cSXuan Zhuo 731aa8bca4cSXuan Zhuo if (rx->meta) { 732aa8bca4cSXuan Zhuo eea_free_rx_buffers(rx, cfg); 733aa8bca4cSXuan Zhuo eea_free_rx_hdr(rx, cfg); 734aa8bca4cSXuan Zhuo kvfree(rx->meta); 735aa8bca4cSXuan Zhuo rx->meta = NULL; 736aa8bca4cSXuan Zhuo } 737aa8bca4cSXuan Zhuo 738aa8bca4cSXuan Zhuo if (rx->pp) { 739aa8bca4cSXuan Zhuo eea_destroy_page_pool(rx); 740aa8bca4cSXuan Zhuo rx->pp = NULL; 741aa8bca4cSXuan Zhuo } 742aa8bca4cSXuan Zhuo 743aa8bca4cSXuan Zhuo kfree(rx); 744aa8bca4cSXuan Zhuo } 745aa8bca4cSXuan Zhuo 746aa8bca4cSXuan Zhuo static void eea_rx_meta_init(struct eea_net_rx *rx, u32 num) 747aa8bca4cSXuan Zhuo { 748aa8bca4cSXuan Zhuo struct eea_rx_meta *meta; 749aa8bca4cSXuan Zhuo int i; 750aa8bca4cSXuan Zhuo 751aa8bca4cSXuan Zhuo rx->free = NULL; 752aa8bca4cSXuan Zhuo 753aa8bca4cSXuan Zhuo for (i = 0; i < num; ++i) { 754aa8bca4cSXuan Zhuo meta = &rx->meta[i]; 755aa8bca4cSXuan Zhuo meta->id = i; 756aa8bca4cSXuan Zhuo meta->next = rx->free; 757aa8bca4cSXuan Zhuo rx->free = meta; 758aa8bca4cSXuan Zhuo } 759aa8bca4cSXuan Zhuo } 760aa8bca4cSXuan Zhuo 761aa8bca4cSXuan Zhuo struct eea_net_rx *eea_alloc_rx(struct eea_net_init_ctx *ctx, u32 idx) 762aa8bca4cSXuan Zhuo { 763aa8bca4cSXuan Zhuo struct eea_ring *ering; 764aa8bca4cSXuan Zhuo struct eea_net_rx *rx; 765aa8bca4cSXuan Zhuo int err; 766aa8bca4cSXuan Zhuo 767aa8bca4cSXuan Zhuo rx = kzalloc(sizeof(*rx), GFP_KERNEL); 768aa8bca4cSXuan Zhuo if (!rx) 769aa8bca4cSXuan Zhuo return rx; 770aa8bca4cSXuan Zhuo 771aa8bca4cSXuan Zhuo rx->index = idx; 772aa8bca4cSXuan Zhuo snprintf(rx->name, sizeof(rx->name), "rx.%u", idx); 773aa8bca4cSXuan Zhuo 774*5f4f7bc0SXuan Zhuo u64_stats_init(&rx->stats.syncp); 775*5f4f7bc0SXuan Zhuo 776aa8bca4cSXuan Zhuo /* ering */ 777aa8bca4cSXuan Zhuo ering = eea_ering_alloc(idx * 2, ctx->cfg.rx_ring_depth, ctx->edev, 778aa8bca4cSXuan Zhuo ctx->cfg.rx_sq_desc_size, 779aa8bca4cSXuan Zhuo ctx->cfg.rx_cq_desc_size, 780aa8bca4cSXuan Zhuo rx->name); 781aa8bca4cSXuan Zhuo if (!ering) 782aa8bca4cSXuan Zhuo goto err_free_rx; 783aa8bca4cSXuan Zhuo 784aa8bca4cSXuan Zhuo rx->ering = ering; 785aa8bca4cSXuan Zhuo 786aa8bca4cSXuan Zhuo rx->dma_dev = ctx->edev->dma_dev; 787aa8bca4cSXuan Zhuo 788aa8bca4cSXuan Zhuo /* meta */ 789aa8bca4cSXuan Zhuo rx->meta = kvcalloc(ctx->cfg.rx_ring_depth, 790aa8bca4cSXuan Zhuo sizeof(*rx->meta), GFP_KERNEL); 791aa8bca4cSXuan Zhuo if (!rx->meta) 792aa8bca4cSXuan Zhuo goto err_free_rx; 793aa8bca4cSXuan Zhuo 794aa8bca4cSXuan Zhuo eea_rx_meta_init(rx, ctx->cfg.rx_ring_depth); 795aa8bca4cSXuan Zhuo 796aa8bca4cSXuan Zhuo if (ctx->cfg.split_hdr) { 797aa8bca4cSXuan Zhuo err = eea_alloc_rx_hdr(ctx, rx); 798aa8bca4cSXuan Zhuo if (err) 799aa8bca4cSXuan Zhuo goto err_free_rx; 800aa8bca4cSXuan Zhuo } 801aa8bca4cSXuan Zhuo 802aa8bca4cSXuan Zhuo rx->pp = eea_create_pp(ctx, idx); 803aa8bca4cSXuan Zhuo if (IS_ERR(rx->pp)) { 804aa8bca4cSXuan Zhuo err = PTR_ERR(rx->pp); 805aa8bca4cSXuan Zhuo rx->pp = NULL; 806aa8bca4cSXuan Zhuo goto err_free_rx; 807aa8bca4cSXuan Zhuo } 808aa8bca4cSXuan Zhuo 809aa8bca4cSXuan Zhuo return rx; 810aa8bca4cSXuan Zhuo 811aa8bca4cSXuan Zhuo err_free_rx: 812aa8bca4cSXuan Zhuo eea_free_rx(rx, &ctx->cfg); 813aa8bca4cSXuan Zhuo return NULL; 814aa8bca4cSXuan Zhuo } 815