]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
net: mvpp2: add buffer header handling in RX
authorStefan Chulski <stefanc@marvell.com>
Tue, 25 May 2021 16:04:41 +0000 (19:04 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 25 May 2021 22:49:04 +0000 (15:49 -0700)
If Link Partner sends frames larger than RX buffer size, MAC mark it
as oversize but still would pass it to the Packet Processor.
In this scenario, Packet Processor scatter frame between multiple buffers,
but only a single buffer would be returned to the Buffer Manager pool and
it would not refill the poll.

Patch add handling of oversize error with buffer header handling, so all
buffers would be returned to the Buffer Manager pool.

Fixes: 3f518509dedc ("ethernet: Add new driver for Marvell Armada 375 network unit")
Reported-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Stefan Chulski <stefanc@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/marvell/mvpp2/mvpp2.h
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c

index 8edba5ea90f03bac6004a3cc43e119161ce0d1ad..4a61c90003b5ead489bc5147fc068c3d12976b3c 100644 (file)
@@ -993,6 +993,14 @@ enum mvpp22_ptp_packet_format {
 
 #define MVPP2_DESC_DMA_MASK    DMA_BIT_MASK(40)
 
+/* Buffer header info bits */
+#define MVPP2_B_HDR_INFO_MC_ID_MASK    0xfff
+#define MVPP2_B_HDR_INFO_MC_ID(info)   ((info) & MVPP2_B_HDR_INFO_MC_ID_MASK)
+#define MVPP2_B_HDR_INFO_LAST_OFFS     12
+#define MVPP2_B_HDR_INFO_LAST_MASK     BIT(12)
+#define MVPP2_B_HDR_INFO_IS_LAST(info) \
+          (((info) & MVPP2_B_HDR_INFO_LAST_MASK) >> MVPP2_B_HDR_INFO_LAST_OFFS)
+
 struct mvpp2_tai;
 
 /* Definitions */
@@ -1002,6 +1010,20 @@ struct mvpp2_rss_table {
        u32 indir[MVPP22_RSS_TABLE_ENTRIES];
 };
 
+struct mvpp2_buff_hdr {
+       __le32 next_phys_addr;
+       __le32 next_dma_addr;
+       __le16 byte_count;
+       __le16 info;
+       __le16 reserved1;       /* bm_qset (for future use, BM) */
+       u8 next_phys_addr_high;
+       u8 next_dma_addr_high;
+       __le16 reserved2;
+       __le16 reserved3;
+       __le16 reserved4;
+       __le16 reserved5;
+};
+
 /* Shared Packet Processor resources */
 struct mvpp2 {
        /* Shared registers' base addresses */
index ec706d614cacc146221bcaf037f7a46c9162add7..d39c7639cdbab16b5688d294d7e55ac71421853f 100644 (file)
@@ -3839,6 +3839,35 @@ mvpp2_run_xdp(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq,
        return ret;
 }
 
+static void mvpp2_buff_hdr_pool_put(struct mvpp2_port *port, struct mvpp2_rx_desc *rx_desc,
+                                   int pool, u32 rx_status)
+{
+       phys_addr_t phys_addr, phys_addr_next;
+       dma_addr_t dma_addr, dma_addr_next;
+       struct mvpp2_buff_hdr *buff_hdr;
+
+       phys_addr = mvpp2_rxdesc_dma_addr_get(port, rx_desc);
+       dma_addr = mvpp2_rxdesc_cookie_get(port, rx_desc);
+
+       do {
+               buff_hdr = (struct mvpp2_buff_hdr *)phys_to_virt(phys_addr);
+
+               phys_addr_next = le32_to_cpu(buff_hdr->next_phys_addr);
+               dma_addr_next = le32_to_cpu(buff_hdr->next_dma_addr);
+
+               if (port->priv->hw_version >= MVPP22) {
+                       phys_addr_next |= ((u64)buff_hdr->next_phys_addr_high << 32);
+                       dma_addr_next |= ((u64)buff_hdr->next_dma_addr_high << 32);
+               }
+
+               mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
+
+               phys_addr = phys_addr_next;
+               dma_addr = dma_addr_next;
+
+       } while (!MVPP2_B_HDR_INFO_IS_LAST(le16_to_cpu(buff_hdr->info)));
+}
+
 /* Main rx processing */
 static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
                    int rx_todo, struct mvpp2_rx_queue *rxq)
@@ -3885,14 +3914,6 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
                        MVPP2_RXD_BM_POOL_ID_OFFS;
                bm_pool = &port->priv->bm_pools[pool];
 
-               /* In case of an error, release the requested buffer pointer
-                * to the Buffer Manager. This request process is controlled
-                * by the hardware, and the information about the buffer is
-                * comprised by the RX descriptor.
-                */
-               if (rx_status & MVPP2_RXD_ERR_SUMMARY)
-                       goto err_drop_frame;
-
                if (port->priv->percpu_pools) {
                        pp = port->priv->page_pool[pool];
                        dma_dir = page_pool_get_dma_dir(pp);
@@ -3904,6 +3925,18 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
                                        rx_bytes + MVPP2_MH_SIZE,
                                        dma_dir);
 
+               /* Buffer header not supported */
+               if (rx_status & MVPP2_RXD_BUF_HDR)
+                       goto err_drop_frame;
+
+               /* In case of an error, release the requested buffer pointer
+                * to the Buffer Manager. This request process is controlled
+                * by the hardware, and the information about the buffer is
+                * comprised by the RX descriptor.
+                */
+               if (rx_status & MVPP2_RXD_ERR_SUMMARY)
+                       goto err_drop_frame;
+
                /* Prefetch header */
                prefetch(data);
 
@@ -3985,7 +4018,10 @@ err_drop_frame:
                dev->stats.rx_errors++;
                mvpp2_rx_error(port, rx_desc);
                /* Return the buffer to the pool */
-               mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
+               if (rx_status & MVPP2_RXD_BUF_HDR)
+                       mvpp2_buff_hdr_pool_put(port, rx_desc, pool, rx_status);
+               else
+                       mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
        }
 
        rcu_read_unlock();