
driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBFE17 CVE: NA -------------------------------- Implement the fxgmac_request_irqs to request legacy or msix irqs, msix irqs. Implement the fxgmac_create_skb to create skb for rx. Implement the fxgmac_isr function to handle legacy irq. Implement the fxgmac_dma_isr function to handle tx and rx irq. Implement the fxgmac_all_poll for legacy irq. Implement the fxgmac_one_poll_rx and fxgmac_one_poll_tx for msix irq. Implement the fxgmac_tx_poll and fxgmac_rx_poll to handle tx and rx. Signed-off-by: Frank_Sae <Frank.Sae@motor-comm.com> --- .../ethernet/motorcomm/yt6801/yt6801_desc.c | 296 +++++++++++++ .../ethernet/motorcomm/yt6801/yt6801_desc.h | 14 + .../ethernet/motorcomm/yt6801/yt6801_main.c | 398 ++++++++++++++++++ .../ethernet/motorcomm/yt6801/yt6801_type.h | 94 +++++ 4 files changed, 802 insertions(+) diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.c index 0891c4fef..39394f8a9 100644 --- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.c +++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.c @@ -267,3 +267,299 @@ int fxgmac_channels_rings_alloc(struct fxgmac_pdata *priv) fxgmac_channels_rings_free(priv); return ret; } + +static void fxgmac_set_buffer_data(struct fxgmac_buffer_data *bd, + struct fxgmac_page_alloc *pa, + unsigned int len) +{ + get_page(pa->pages); + bd->pa = *pa; + + bd->dma_base = pa->pages_dma; + bd->dma_off = pa->pages_offset; + bd->dma_len = len; + + pa->pages_offset += len; + if ((pa->pages_offset + len) > pa->pages_len) { + /* This data descriptor is responsible for unmapping page(s) */ + bd->pa_unmap = *pa; + + /* Get a new allocation next time */ + pa->pages = NULL; + pa->pages_len = 0; + pa->pages_offset = 0; + pa->pages_dma = 0; + } +} + +static int fxgmac_alloc_pages(struct fxgmac_pdata *priv, + struct fxgmac_page_alloc *pa, gfp_t gfp, + int order) +{ + struct page *pages = NULL; + dma_addr_t pages_dma; + + /* Try to obtain pages, decreasing order if necessary */ + gfp |= __GFP_COMP | __GFP_NOWARN; + while (order >= 0) { + pages = alloc_pages(gfp, order); + if (pages) + break; + + order--; + } + + if (!pages) + return -ENOMEM; + + /* Map the pages */ + pages_dma = dma_map_page(priv->dev, pages, 0, PAGE_SIZE << order, + DMA_FROM_DEVICE); + if (dma_mapping_error(priv->dev, pages_dma)) { + put_page(pages); + return -ENOMEM; + } + + pa->pages = pages; + pa->pages_len = PAGE_SIZE << order; + pa->pages_offset = 0; + pa->pages_dma = pages_dma; + + return 0; +} + +#define FXGMAC_SKB_ALLOC_SIZE 512 + +int fxgmac_rx_buffe_map(struct fxgmac_pdata *priv, struct fxgmac_ring *ring, + struct fxgmac_desc_data *desc_data) +{ + int ret; + + if (!ring->rx_hdr_pa.pages) { + ret = fxgmac_alloc_pages(priv, &ring->rx_hdr_pa, GFP_ATOMIC, 0); + if (ret) + return ret; + } + /* Set up the header page info */ + fxgmac_set_buffer_data(&desc_data->rx.hdr, &ring->rx_hdr_pa, + priv->rx_buf_size); + + return 0; +} + +void fxgmac_desc_tx_reset(struct fxgmac_desc_data *desc_data) +{ + struct fxgmac_dma_desc *dma_desc = desc_data->dma_desc; + + /* Reset the Tx descriptor + * Set buffer 1 (lo) address to zero + * Set buffer 1 (hi) address to zero + * Reset all other control bits (IC, TTSE, B2L & B1L) + * Reset all other control bits (OWN, CTXT, FD, LD, CPC, CIC, etc) + */ + dma_desc->desc0 = 0; + dma_desc->desc1 = 0; + dma_desc->desc2 = 0; + dma_desc->desc3 = 0; + + /* Make sure ownership is written to the descriptor */ + dma_wmb(); +} + +void fxgmac_desc_rx_reset(struct fxgmac_desc_data *desc_data) +{ + struct fxgmac_dma_desc *dma_desc = desc_data->dma_desc; + dma_addr_t hdr_dma; + + /* Reset the Rx descriptor + * Set buffer 1 (lo) address to header dma address (lo) + * Set buffer 1 (hi) address to header dma address (hi) + * set control bits OWN and INTE + */ + hdr_dma = desc_data->rx.hdr.dma_base + desc_data->rx.hdr.dma_off; + dma_desc->desc0 = cpu_to_le32(lower_32_bits(hdr_dma)); + dma_desc->desc1 = cpu_to_le32(upper_32_bits(hdr_dma)); + dma_desc->desc2 = 0; + dma_desc->desc3 = 0; + fxgmac_desc_wr_bits(&dma_desc->desc3, RX_DESC3_INTE, 1); + fxgmac_desc_wr_bits(&dma_desc->desc3, RX_DESC3_BUF2V, 0); + fxgmac_desc_wr_bits(&dma_desc->desc3, RX_DESC3_BUF1V, 1); + + /* Since the Rx DMA engine is likely running, make sure everything + * is written to the descriptor(s) before setting the OWN bit + * for the descriptor + */ + dma_wmb(); + + fxgmac_desc_wr_bits(&dma_desc->desc3, RX_DESC3_OWN, 1); + + /* Make sure ownership is written to the descriptor */ + dma_wmb(); +} + +int fxgmac_tx_skb_map(struct fxgmac_channel *channel, struct sk_buff *skb) +{ + struct fxgmac_pdata *priv = channel->priv; + struct fxgmac_ring *ring = channel->tx_ring; + unsigned int start_index, cur_index; + struct fxgmac_desc_data *desc_data; + unsigned int offset, datalen, len; + struct fxgmac_pkt_info *pkt_info; + unsigned int tso, vlan; + dma_addr_t skb_dma; + skb_frag_t *frag; + + offset = 0; + start_index = ring->cur; + cur_index = ring->cur; + pkt_info = &ring->pkt_info; + pkt_info->desc_count = 0; + pkt_info->length = 0; + + tso = FIELD_GET(ATTR_TX_TSO_ENABLE, pkt_info->attr); + vlan = FIELD_GET(ATTR_TX_VLAN_CTAG, pkt_info->attr); + + /* Save space for a context descriptor if needed */ + if ((tso && pkt_info->mss != ring->tx.cur_mss) || + (vlan && pkt_info->vlan_ctag != ring->tx.cur_vlan_ctag)) + cur_index = FXGMAC_GET_ENTRY(cur_index, ring->dma_desc_count); + + desc_data = FXGMAC_GET_DESC_DATA(ring, cur_index); + + if (tso) { + /* Map the TSO header */ + skb_dma = dma_map_single(priv->dev, skb->data, + pkt_info->header_len, DMA_TO_DEVICE); + if (dma_mapping_error(priv->dev, skb_dma)) { + dev_err(priv->dev, "dma map single failed\n"); + goto err_out; + } + desc_data->skb_dma = skb_dma; + desc_data->skb_dma_len = pkt_info->header_len; + + offset = pkt_info->header_len; + pkt_info->length += pkt_info->header_len; + + cur_index = FXGMAC_GET_ENTRY(cur_index, ring->dma_desc_count); + desc_data = FXGMAC_GET_DESC_DATA(ring, cur_index); + } + + /* Map the (remainder of the) packet */ + for (datalen = skb_headlen(skb) - offset; datalen;) { + len = min_t(unsigned int, datalen, FXGMAC_TX_MAX_BUF_SIZE); + skb_dma = dma_map_single(priv->dev, skb->data + offset, len, + DMA_TO_DEVICE); + if (dma_mapping_error(priv->dev, skb_dma)) { + dev_err(priv->dev, "dma map single failed\n"); + goto err_out; + } + desc_data->skb_dma = skb_dma; + desc_data->skb_dma_len = len; + + datalen -= len; + offset += len; + pkt_info->length += len; + + cur_index = FXGMAC_GET_ENTRY(cur_index, ring->dma_desc_count); + desc_data = FXGMAC_GET_DESC_DATA(ring, cur_index); + } + + for (u32 i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + offset = 0; + + for (datalen = skb_frag_size(frag); datalen;) { + len = min_t(unsigned int, datalen, + FXGMAC_TX_MAX_BUF_SIZE); + skb_dma = skb_frag_dma_map(priv->dev, frag, offset, len, + DMA_TO_DEVICE); + if (dma_mapping_error(priv->dev, skb_dma)) { + dev_err(priv->dev, "skb frag dma map failed\n"); + goto err_out; + } + desc_data->skb_dma = skb_dma; + desc_data->skb_dma_len = len; + desc_data->mapped_as_page = 1; + + datalen -= len; + offset += len; + pkt_info->length += len; + + cur_index = FXGMAC_GET_ENTRY(cur_index, + ring->dma_desc_count); + desc_data = FXGMAC_GET_DESC_DATA(ring, cur_index); + } + } + + /* Save the skb address in the last entry. We always have some data + * that has been mapped so desc_data is always advanced past the last + * piece of mapped data - use the entry pointed to by cur_index - 1. + */ + desc_data = FXGMAC_GET_DESC_DATA(ring, (cur_index - 1) & + (ring->dma_desc_count - 1)); + desc_data->skb = skb; + + /* Save the number of descriptor entries used */ + if (start_index <= cur_index) + pkt_info->desc_count = cur_index - start_index; + else + pkt_info->desc_count = + ring->dma_desc_count - start_index + cur_index; + + return pkt_info->desc_count; + +err_out: + while (start_index < cur_index) { + desc_data = FXGMAC_GET_DESC_DATA(ring, start_index); + start_index = + FXGMAC_GET_ENTRY(start_index, ring->dma_desc_count); + fxgmac_desc_data_unmap(priv, desc_data); + } + + return 0; +} + +void fxgmac_dump_rx_desc(struct fxgmac_pdata *priv, struct fxgmac_ring *ring, + unsigned int idx) +{ + struct fxgmac_desc_data *desc_data; + struct fxgmac_dma_desc *dma_desc; + + desc_data = FXGMAC_GET_DESC_DATA(ring, idx); + dma_desc = desc_data->dma_desc; + dev_dbg(priv->dev, "RX: dma_desc=%p, dma_desc_addr=%pad, RX_DESC[%d RX BY DEVICE] = %08x:%08x:%08x:%08x\n\n", + dma_desc, &desc_data->dma_desc_addr, idx, + le32_to_cpu(dma_desc->desc0), le32_to_cpu(dma_desc->desc1), + le32_to_cpu(dma_desc->desc2), le32_to_cpu(dma_desc->desc3)); +} + +void fxgmac_dump_tx_desc(struct fxgmac_pdata *priv, struct fxgmac_ring *ring, + unsigned int idx, unsigned int count, + unsigned int flag) +{ + struct fxgmac_desc_data *desc_data; + + while (count--) { + desc_data = FXGMAC_GET_DESC_DATA(ring, idx); + dev_dbg(priv->dev, "TX: dma_desc=%p, dma_desc_addr=%pad, TX_DESC[%d %s] = %08x:%08x:%08x:%08x\n", + desc_data->dma_desc, &desc_data->dma_desc_addr, idx, + (flag == 1) ? "QUEUED FOR TX" : "TX BY DEVICE", + le32_to_cpu(desc_data->dma_desc->desc0), + le32_to_cpu(desc_data->dma_desc->desc1), + le32_to_cpu(desc_data->dma_desc->desc2), + le32_to_cpu(desc_data->dma_desc->desc3)); + + idx++; + } +} + +int fxgmac_is_tx_complete(struct fxgmac_dma_desc *dma_desc) +{ + return !fxgmac_desc_rd_bits(dma_desc->desc3, TX_DESC3_OWN); +} + +int fxgmac_is_last_desc(struct fxgmac_dma_desc *dma_desc) +{ + /* Rx and Tx share LD bit, so check TDES3.LD bit */ + return fxgmac_desc_rd_bits(dma_desc->desc3, TX_DESC3_LD); +} diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.h b/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.h index dfe783004..b238f20be 100644 --- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.h +++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_desc.h @@ -13,9 +13,23 @@ #define FXGMAC_GET_DESC_DATA(ring, idx) ((ring)->desc_data_head + (idx)) #define FXGMAC_GET_ENTRY(x, size) (((x) + 1) & ((size) - 1)) +void fxgmac_desc_tx_reset(struct fxgmac_desc_data *desc_data); +void fxgmac_desc_rx_reset(struct fxgmac_desc_data *desc_data); void fxgmac_desc_data_unmap(struct fxgmac_pdata *priv, struct fxgmac_desc_data *desc_data); int fxgmac_channels_rings_alloc(struct fxgmac_pdata *priv); void fxgmac_channels_rings_free(struct fxgmac_pdata *priv); +int fxgmac_tx_skb_map(struct fxgmac_channel *channel, struct sk_buff *skb); +int fxgmac_rx_buffe_map(struct fxgmac_pdata *priv, struct fxgmac_ring *ring, + struct fxgmac_desc_data *desc_data); +void fxgmac_dump_tx_desc(struct fxgmac_pdata *priv, struct fxgmac_ring *ring, + unsigned int idx, unsigned int count, + unsigned int flag); +void fxgmac_dump_rx_desc(struct fxgmac_pdata *priv, struct fxgmac_ring *ring, + unsigned int idx); + +int fxgmac_is_tx_complete(struct fxgmac_dma_desc *dma_desc); +int fxgmac_is_last_desc(struct fxgmac_dma_desc *dma_desc); + #endif /* YT6801_DESC_H */ diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c index 80657021c..701ad23d4 100644 --- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c +++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c @@ -110,17 +110,72 @@ static int fxgmac_mdio_register(struct fxgmac_pdata *priv) return 0; } +static unsigned int fxgmac_desc_tx_avail(struct fxgmac_ring *ring) +{ + if (ring->dirty > ring->cur) + return ring->dirty - ring->cur; + else + return ring->dma_desc_count - ring->cur + ring->dirty; +} + static void fxgmac_enable_msix_one_irq(struct fxgmac_pdata *priv, u32 int_id) { fxgmac_io_wr(priv, MSIX_TBL_MASK + int_id * 16, 0); } +static void fxgmac_disable_msix_one_irq(struct fxgmac_pdata *priv, u32 intid) +{ + fxgmac_io_wr(priv, MSIX_TBL_MASK + intid * 16, 1); +} + static void fxgmac_disable_mgm_irq(struct fxgmac_pdata *priv) { fxgmac_io_wr_bits(priv, MGMT_INT_CTRL0, MGMT_INT_CTRL0_INT_MASK, MGMT_INT_CTRL0_INT_MASK_MASK); } +static irqreturn_t fxgmac_isr(int irq, void *data) +{ + struct fxgmac_pdata *priv = data; + u32 val; + + val = fxgmac_io_rd(priv, MGMT_INT_CTRL0); + if (!(val & MGMT_INT_CTRL0_INT_STATUS_RXTX)) + return IRQ_NONE; + + /* Restart the device on a Fatal Bus Error */ + for (u32 i = 0; i < priv->channel_count; i++) { + val = fxgmac_dma_io_rd(priv->channel_head + i, DMA_CH_SR); + if (FIELD_GET(DMA_CH_SR_FBE, val)) + schedule_work(&priv->restart_work); + /* Clear all the interrupts which are set */ + fxgmac_dma_io_wr(priv->channel_head + i, DMA_CH_SR, val); + } + + fxgmac_disable_mgm_irq(priv); + napi_schedule_irqoff(&priv->napi); /* Turn on polling */ + return IRQ_HANDLED; +} + +static irqreturn_t fxgmac_dma_isr(int irq, void *data) +{ + struct fxgmac_channel *channel = data; + + if (irq == channel->dma_irq_tx) { + fxgmac_disable_msix_one_irq(channel->priv, MSI_ID_TXQ0); + /* Clear Tx signal */ + fxgmac_dma_io_wr(channel, DMA_CH_SR, DMA_CH_SR_TI); + napi_schedule_irqoff(&channel->napi_tx); + return IRQ_HANDLED; + } + + fxgmac_disable_msix_one_irq(channel->priv, channel->queue_index); + /* Clear Rx signal */ + fxgmac_dma_io_wr(channel, DMA_CH_SR, DMA_CH_SR_RI); + napi_schedule_irqoff(&channel->napi_rx); + return IRQ_HANDLED; +} + static void napi_disable_del(struct fxgmac_pdata *priv, struct napi_struct *n, u32 flag) { @@ -1875,6 +1930,30 @@ static int fxgmac_drv_probe(struct device *dev, struct fxgmac_resources *res) return ret; } +static void fxgmac_dbg_pkt(struct fxgmac_pdata *priv, struct sk_buff *skb, + bool tx_rx) +{ + struct ethhdr *eth = (struct ethhdr *)skb->data; + unsigned char buffer[128]; + + dev_dbg(priv->dev, "\n************** SKB dump ****************\n"); + dev_dbg(priv->dev, "%s, packet of %d bytes\n", (tx_rx ? "TX" : "RX"), + skb->len); + dev_dbg(priv->dev, "Dst MAC addr: %pM\n", eth->h_dest); + dev_dbg(priv->dev, "Src MAC addr: %pM\n", eth->h_source); + dev_dbg(priv->dev, "Protocol: %#06x\n", ntohs(eth->h_proto)); + + for (u32 i = 0; i < skb->len; i += 32) { + unsigned int len = min(skb->len - i, 32U); + + hex_dump_to_buffer(&skb->data[i], len, 32, 1, buffer, + sizeof(buffer), false); + dev_dbg(priv->dev, " %#06x: %s\n", i, buffer); + } + + dev_dbg(priv->dev, "\n************** SKB dump ****************\n"); +} + static const struct net_device_ops fxgmac_netdev_ops = { .ndo_open = fxgmac_open, }; @@ -1884,6 +1963,325 @@ const struct net_device_ops *fxgmac_get_netdev_ops(void) return &fxgmac_netdev_ops; } +static void fxgmac_rx_refresh(struct fxgmac_channel *channel) +{ + struct fxgmac_ring *ring = channel->rx_ring; + struct fxgmac_pdata *priv = channel->priv; + struct fxgmac_desc_data *desc_data; + + while (ring->dirty != ring->cur) { + desc_data = FXGMAC_GET_DESC_DATA(ring, ring->dirty); + + /* Reset desc_data values */ + fxgmac_desc_data_unmap(priv, desc_data); + + if (fxgmac_rx_buffe_map(priv, ring, desc_data)) + break; + + fxgmac_desc_rx_reset(desc_data); + ring->dirty = + FXGMAC_GET_ENTRY(ring->dirty, ring->dma_desc_count); + } + + /* Make sure everything is written before the register write */ + wmb(); + + /* Update the Rx Tail Pointer Register with address of + * the last cleaned entry + */ + desc_data = FXGMAC_GET_DESC_DATA(ring, (ring->dirty - 1) & + (ring->dma_desc_count - 1)); + fxgmac_dma_io_wr(channel, DMA_CH_RDTR_LO, + lower_32_bits(desc_data->dma_desc_addr)); +} + +static struct sk_buff *fxgmac_create_skb(struct fxgmac_pdata *priv, + struct napi_struct *napi, + struct fxgmac_desc_data *desc_data, + unsigned int len) +{ + unsigned int copy_len; + struct sk_buff *skb; + u8 *packet; + + skb = napi_alloc_skb(napi, desc_data->rx.hdr.dma_len); + if (!skb) + return NULL; + + /* Start with the header buffer which may contain just the header + * or the header plus data + */ + dma_sync_single_range_for_cpu(priv->dev, desc_data->rx.hdr.dma_base, + desc_data->rx.hdr.dma_off, + desc_data->rx.hdr.dma_len, + DMA_FROM_DEVICE); + + packet = page_address(desc_data->rx.hdr.pa.pages) + + desc_data->rx.hdr.pa.pages_offset; + copy_len = min(desc_data->rx.hdr.dma_len, len); + skb_copy_to_linear_data(skb, packet, copy_len); + skb_put(skb, copy_len); + + return skb; +} + +static int fxgmac_tx_poll(struct fxgmac_channel *channel) +{ + struct fxgmac_pdata *priv = channel->priv; + unsigned int cur, tx_packets = 0, tx_bytes = 0; + struct fxgmac_ring *ring = channel->tx_ring; + struct net_device *ndev = priv->ndev; + struct fxgmac_desc_data *desc_data; + struct fxgmac_dma_desc *dma_desc; + struct netdev_queue *txq; + int processed = 0; + + /* Nothing to do if there isn't a Tx ring for this channel */ + if (!ring) + return 0; + + if (ring->cur != ring->dirty && (netif_msg_tx_done(priv))) + netdev_dbg(priv->ndev, "%s, ring_cur=%d,ring_dirty=%d,qIdx=%d\n", + __func__, ring->cur, ring->dirty, + channel->queue_index); + + cur = ring->cur; + + /* Be sure we get ring->cur before accessing descriptor data */ + smp_rmb(); + + txq = netdev_get_tx_queue(ndev, channel->queue_index); + while (ring->dirty != cur) { + desc_data = FXGMAC_GET_DESC_DATA(ring, ring->dirty); + dma_desc = desc_data->dma_desc; + + if (!fxgmac_is_tx_complete(dma_desc)) + break; + + /* Make sure descriptor fields are read after reading + * the OWN bit + */ + dma_rmb(); + + if (netif_msg_tx_done(priv)) + fxgmac_dump_tx_desc(priv, ring, ring->dirty, 1, 0); + + if (fxgmac_is_last_desc(dma_desc)) { + tx_packets += desc_data->tx.packets; + tx_bytes += desc_data->tx.bytes; + } + + /* Free the SKB and reset the descriptor for re-use */ + fxgmac_desc_data_unmap(priv, desc_data); + fxgmac_desc_tx_reset(desc_data); + + processed++; + ring->dirty = + FXGMAC_GET_ENTRY(ring->dirty, ring->dma_desc_count); + } + + if (!processed) + return 0; + + netdev_tx_completed_queue(txq, tx_packets, tx_bytes); + + /* Make sure ownership is written to the descriptor */ + smp_wmb(); + if (ring->tx.queue_stopped == 1 && + (fxgmac_desc_tx_avail(ring) > FXGMAC_TX_DESC_MIN_FREE)) { + ring->tx.queue_stopped = 0; + netif_tx_wake_queue(txq); + } + + return processed; +} + +static int fxgmac_one_poll_tx(struct napi_struct *napi, int budget) +{ + struct fxgmac_channel *channel = + container_of(napi, struct fxgmac_channel, napi_tx); + struct fxgmac_pdata *priv = channel->priv; + int ret; + + ret = fxgmac_tx_poll(channel); + if (napi_complete_done(napi, 0)) + fxgmac_enable_msix_one_irq(priv, MSI_ID_TXQ0); + + return ret; +} + +static unsigned int fxgmac_desc_rx_dirty(struct fxgmac_ring *ring) +{ + unsigned int dirty; + + if (ring->dirty <= ring->cur) + dirty = ring->cur - ring->dirty; + else + dirty = ring->dma_desc_count - ring->dirty + ring->cur; + + return dirty; +} + +static int fxgmac_rx_poll(struct fxgmac_channel *channel, int budget) +{ + struct fxgmac_pdata *priv = channel->priv; + struct fxgmac_ring *ring = channel->rx_ring; + struct net_device *ndev = priv->ndev; + u32 context_next, context, incomplete; + struct fxgmac_desc_data *desc_data; + struct fxgmac_pkt_info *pkt_info; + struct napi_struct *napi; + u32 len, max_len; + int packet_count = 0; + + struct sk_buff *skb; + + /* Nothing to do if there isn't a Rx ring for this channel */ + if (!ring) + return 0; + + napi = (priv->per_channel_irq) ? &channel->napi_rx : &priv->napi; + pkt_info = &ring->pkt_info; + + while (packet_count < budget) { + memset(pkt_info, 0, sizeof(*pkt_info)); + skb = NULL; + len = 0; + +read_again: + desc_data = FXGMAC_GET_DESC_DATA(ring, ring->cur); + + if (fxgmac_desc_rx_dirty(ring) > FXGMAC_RX_DESC_MAX_DIRTY) + fxgmac_rx_refresh(channel); + + if (fxgmac_dev_read(channel)) + break; + + ring->cur = FXGMAC_GET_ENTRY(ring->cur, ring->dma_desc_count); + incomplete = FIELD_GET(ATTR_RX_INCOMPLETE, pkt_info->attr); + context_next = FIELD_GET(ATTR_RX_CONTEXT_NEXT, pkt_info->attr); + context = FIELD_GET(ATTR_RX_CONTEXT, pkt_info->attr); + + if (incomplete || context_next) + goto read_again; + + if (pkt_info->errors) { + dev_kfree_skb(skb); + priv->ndev->stats.rx_dropped++; + netdev_err(priv->ndev, "Received packet failed\n"); + goto next_packet; + } + + if (!context) { + len = desc_data->rx.len; + if (len == 0) { + if (net_ratelimit()) + netdev_err(priv->ndev, "A packet of length 0 was received\n"); + priv->ndev->stats.rx_length_errors++; + priv->ndev->stats.rx_dropped++; + goto next_packet; + } + + if (len && !skb) { + skb = fxgmac_create_skb(priv, napi, desc_data, + len); + if (unlikely(!skb)) { + if (net_ratelimit()) + netdev_err(priv->ndev, "create skb failed\n"); + priv->ndev->stats.rx_dropped++; + goto next_packet; + } + } + max_len = ndev->mtu + ETH_HLEN; + if (!(ndev->features & NETIF_F_HW_VLAN_CTAG_RX) && + skb->protocol == htons(ETH_P_8021Q)) + max_len += VLAN_HLEN; + + if (len > max_len) { + if (net_ratelimit()) + netdev_err(priv->ndev, "len %d larger than max size %d\n", + len, max_len); + priv->ndev->stats.rx_length_errors++; + priv->ndev->stats.rx_dropped++; + dev_kfree_skb(skb); + goto next_packet; + } + } + + if (!skb) { + priv->ndev->stats.rx_dropped++; + goto next_packet; + } + + if (netif_msg_pktdata(priv)) + fxgmac_dbg_pkt(priv, skb, false); + + skb_checksum_none_assert(skb); + if (ndev->features & NETIF_F_RXCSUM) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + if (FIELD_GET(ATTR_RX_VLAN_CTAG, pkt_info->attr)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + pkt_info->vlan_ctag); + + if (FIELD_GET(ATTR_RX_RSS_HASH, pkt_info->attr)) + skb_set_hash(skb, pkt_info->rss_hash, + pkt_info->rss_hash_type); + + skb->dev = ndev; + skb->protocol = eth_type_trans(skb, ndev); + skb_record_rx_queue(skb, channel->queue_index); + napi_gro_receive(napi, skb); + +next_packet: + packet_count++; + priv->ndev->stats.rx_packets++; + priv->ndev->stats.rx_bytes += len; + } + + return packet_count; +} + +static int fxgmac_one_poll_rx(struct napi_struct *napi, int budget) +{ + struct fxgmac_channel *channel = + container_of(napi, struct fxgmac_channel, napi_rx); + int processed = fxgmac_rx_poll(channel, budget); + + if (processed < budget && (napi_complete_done(napi, processed))) + fxgmac_enable_msix_one_irq(channel->priv, channel->queue_index); + + return processed; +} + +static int fxgmac_all_poll(struct napi_struct *napi, int budget) +{ + struct fxgmac_channel *channel; + struct fxgmac_pdata *priv; + int processed = 0; + + priv = container_of(napi, struct fxgmac_pdata, napi); + do { + channel = priv->channel_head; + /* Only support 1 tx channel, poll ch 0. */ + fxgmac_tx_poll(priv->channel_head + 0); + for (u32 i = 0; i < priv->channel_count; i++, channel++) + processed += fxgmac_rx_poll(channel, budget); + } while (false); + + /* If we processed everything, we are done */ + if (processed < budget) { + /* Turn off polling */ + if (napi_complete_done(napi, processed)) + fxgmac_enable_mgm_irq(priv); + } + + if ((processed) && (netif_msg_rx_status(priv))) + netdev_dbg(priv->ndev, "%s,received:%d\n", __func__, processed); + + return processed; +} + static void napi_add_enable(struct fxgmac_pdata *priv, struct napi_struct *napi, int (*poll)(struct napi_struct *, int), u32 flag) diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h b/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h index 228e0fa56..07aff6210 100644 --- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h +++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h @@ -499,6 +499,63 @@ #define DMA_CH_SR_RPS BIT(8) #define DMA_CH_SR_FBE BIT(12) +/* Receive Normal Descriptor (Read Format) */ +#define RX_DESC0_OVT GENMASK(15, 0) /* Outer VLAN Tag */ + +#define RX_DESC2_HL GENMASK(9, 0) /* L3/L4 Header Length */ + +#define RX_DESC3_PL GENMASK(14, 0) /* Packet Length */ +#define RX_DESC3_ES BIT(15) /* Error Summary */ +#define RX_DESC3_ETLT GENMASK(18, 16) /* Length/Type Field */ +#define RX_DESC3_BUF1V BIT(24) /* Receive Status RDES1 Valid */ +#define RX_DESC3_BUF2V BIT(25) /* Receive Status RDES2 Valid */ +#define RX_DESC3_LD BIT(28) /* Last Descriptor */ +#define RX_DESC3_FD BIT(29) /* First Descriptor */ +#define RX_DESC3_INTE BIT(30) +#define RX_DESC3_OWN BIT(31) /* Own Bit */ + +/* Transmit Normal Descriptor (Read Format) */ +#define TX_DESC2_HL_B1L GENMASK(13, 0) /* Header Length or Buffer 1 Length */ +#define TX_DESC2_VTIR GENMASK(15, 14) /* VLAN Tag Insertion/Replacement */ +#define TX_DESC2_TTSE BIT(30) /* Transmit Timestamp Enable */ +#define TX_DESC2_IC BIT(31) /* Interrupt on Completion. */ +#define TX_DESC3_TCPPL GENMASK(17, 0) /* TCP Packet Length.*/ +#define TX_DESC3_FL GENMASK(14, 0) /* Frame Length */ +#define TX_DESC3_CIC GENMASK(17, 16) /* Checksum Insertion Control */ +#define TX_DESC3_TSE BIT(18) /* TCP Segmentation Enable */ +#define TX_DESC3_TCPHDRLEN GENMASK(22, 19) /* TCP/UDP Header Length. */ +#define TX_DESC3_CPC GENMASK(27, 26) /* CRC Pad Control */ +#define TX_DESC3_LD BIT(28) /* Last Descriptor */ +#define TX_DESC3_FD BIT(29) /* First Descriptor */ +#define TX_DESC3_CTXT BIT(30) /* Context Type */ +#define TX_DESC3_OWN BIT(31) /* Own Bit */ + +/* Transmit Context Descriptor */ +#define TX_CONTEXT_DESC2_MSS GENMASK(13, 0) /* Maximum Segment Size */ +#define TX_CONTEXT_DESC2_IVLTV GENMASK(31, 16) /* Inner VLAN Tag. */ + +#define TX_CONTEXT_DESC3_VT GENMASK(15, 0) /* VLAN Tag */ +#define TX_CONTEXT_DESC3_VLTV BIT(16) /* Inner VLAN Tag Valid */ +#define TX_CONTEXT_DESC3_IVLTV BIT(17) /* Inner VLAN TAG valid. */ +/* Inner VLAN Tag Insert/Replace */ +#define TX_CONTEXT_DESC3_IVTIR GENMASK(19, 18) +#define TX_CONTEXT_DESC3_TCMSSV BIT(26) /* Timestamp correct or MSS Valid */ +#define TX_CONTEXT_DESC3_CTXT BIT(30) /* Context Type */ + +/* Receive Normal Descriptor (Write-Back Format) */ +#define RX_DESC0_WB_OVT GENMASK(15, 0) /* Outer VLAN Tag. */ +#define RX_DESC0_WB_IVT GENMASK(31, 16) /* Inner VLAN Tag. */ + +#define RX_DESC1_WB_PT GENMASK(2, 0) /* Payload Type */ +#define RX_DESC1_WB_IPHE BIT(3) /* IP Header Error. */ +#define RX_DESC1_WB_IPV4 BIT(4) /* IPV4 Header Present */ +#define RX_DESC1_WB_IPV6 BIT(5) /* IPV6 Header Present. */ +#define RX_DESC1_WB_IPCE BIT(7) /* IP Payload Error. */ + +#define RX_DESC2_WB_RAPARSER GENMASK(13, 11) /* Parse error */ +#define RX_DESC2_WB_DAF BIT(17) /* DA Filter Fail */ +#define RX_DESC2_WB_HF BIT(18) /* Hash Filter Status. */ + struct fxgmac_ring_buf { struct sk_buff *skb; dma_addr_t skb_dma; @@ -543,6 +600,43 @@ struct fxgmac_rx_desc_data { unsigned short len; /* Length of received packet */ }; +struct fxgmac_pkt_info { + struct sk_buff *skb; +#define ATTR_TX_CSUM_ENABLE BIT(0) +#define ATTR_TX_TSO_ENABLE BIT(1) +#define ATTR_TX_VLAN_CTAG BIT(2) +#define ATTR_TX_PTP BIT(3) + +#define ATTR_RX_CSUM_DONE BIT(0) +#define ATTR_RX_VLAN_CTAG BIT(1) +#define ATTR_RX_INCOMPLETE BIT(2) +#define ATTR_RX_CONTEXT_NEXT BIT(3) +#define ATTR_RX_CONTEXT BIT(4) +#define ATTR_RX_RX_TSTAMP BIT(5) +#define ATTR_RX_RSS_HASH BIT(6) + unsigned int attr; + +#define ERRORS_RX_LENGTH BIT(0) +#define ERRORS_RX_OVERRUN BIT(1) +#define ERRORS_RX_CRC BIT(2) +#define ERRORS_RX_FRAME BIT(3) + unsigned int errors; + unsigned int desc_count; /* descriptors needed for this packet */ + unsigned int length; + unsigned int tx_packets; + unsigned int tx_bytes; + + unsigned int header_len; + unsigned int tcp_header_len; + unsigned int tcp_payload_len; + unsigned short mss; + unsigned short vlan_ctag; + + u64 rx_tstamp; + u32 rss_hash; + enum pkt_hash_types rss_hash_type; +}; + struct fxgmac_desc_data { struct fxgmac_dma_desc *dma_desc; /* Virtual address of descriptor */ dma_addr_t dma_desc_addr; /* DMA address of descriptor */ -- 2.34.1