net: mvpp2: add buffer header handling in RX

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: 3f518509de ("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>
This commit is contained in:
Stefan Chulski 2021-05-25 19:04:41 +03:00 committed by David S. Miller
parent 65161c3555
commit 17f9c1b63c
2 changed files with 67 additions and 9 deletions

View 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 */

View 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();