| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- // SPDX-License-Identifier: GPL-2.0
- /* Copyright Sunplus Technology Co., Ltd.
- * All rights reserved.
- */
- #include <linux/platform_device.h>
- #include <linux/netdevice.h>
- #include <linux/of_mdio.h>
- #include "spl2sw_define.h"
- #include "spl2sw_desc.h"
- void spl2sw_rx_descs_flush(struct spl2sw_common *comm)
- {
- struct spl2sw_skb_info *rx_skbinfo;
- struct spl2sw_mac_desc *rx_desc;
- u32 i, j;
- for (i = 0; i < RX_DESC_QUEUE_NUM; i++) {
- rx_desc = comm->rx_desc[i];
- rx_skbinfo = comm->rx_skb_info[i];
- for (j = 0; j < comm->rx_desc_num[i]; j++) {
- rx_desc[j].addr1 = rx_skbinfo[j].mapping;
- rx_desc[j].cmd2 = (j == comm->rx_desc_num[i] - 1) ?
- RXD_EOR | comm->rx_desc_buff_size :
- comm->rx_desc_buff_size;
- wmb(); /* Set RXD_OWN after other fields are ready. */
- rx_desc[j].cmd1 = RXD_OWN;
- }
- }
- }
- void spl2sw_tx_descs_clean(struct spl2sw_common *comm)
- {
- u32 i;
- if (!comm->tx_desc)
- return;
- for (i = 0; i < TX_DESC_NUM; i++) {
- comm->tx_desc[i].cmd1 = 0;
- wmb(); /* Clear TXD_OWN and then set other fields. */
- comm->tx_desc[i].cmd2 = 0;
- comm->tx_desc[i].addr1 = 0;
- comm->tx_desc[i].addr2 = 0;
- if (comm->tx_temp_skb_info[i].mapping) {
- dma_unmap_single(&comm->pdev->dev, comm->tx_temp_skb_info[i].mapping,
- comm->tx_temp_skb_info[i].skb->len, DMA_TO_DEVICE);
- comm->tx_temp_skb_info[i].mapping = 0;
- }
- if (comm->tx_temp_skb_info[i].skb) {
- dev_kfree_skb_any(comm->tx_temp_skb_info[i].skb);
- comm->tx_temp_skb_info[i].skb = NULL;
- }
- }
- }
- void spl2sw_rx_descs_clean(struct spl2sw_common *comm)
- {
- struct spl2sw_skb_info *rx_skbinfo;
- struct spl2sw_mac_desc *rx_desc;
- u32 i, j;
- for (i = 0; i < RX_DESC_QUEUE_NUM; i++) {
- if (!comm->rx_skb_info[i])
- continue;
- rx_desc = comm->rx_desc[i];
- rx_skbinfo = comm->rx_skb_info[i];
- for (j = 0; j < comm->rx_desc_num[i]; j++) {
- rx_desc[j].cmd1 = 0;
- wmb(); /* Clear RXD_OWN and then set other fields. */
- rx_desc[j].cmd2 = 0;
- rx_desc[j].addr1 = 0;
- if (rx_skbinfo[j].skb) {
- dma_unmap_single(&comm->pdev->dev, rx_skbinfo[j].mapping,
- comm->rx_desc_buff_size, DMA_FROM_DEVICE);
- dev_kfree_skb_any(rx_skbinfo[j].skb);
- rx_skbinfo[j].skb = NULL;
- rx_skbinfo[j].mapping = 0;
- }
- }
- kfree(rx_skbinfo);
- comm->rx_skb_info[i] = NULL;
- }
- }
- void spl2sw_descs_clean(struct spl2sw_common *comm)
- {
- spl2sw_rx_descs_clean(comm);
- spl2sw_tx_descs_clean(comm);
- }
- void spl2sw_descs_free(struct spl2sw_common *comm)
- {
- u32 i;
- spl2sw_descs_clean(comm);
- comm->tx_desc = NULL;
- for (i = 0; i < RX_DESC_QUEUE_NUM; i++)
- comm->rx_desc[i] = NULL;
- /* Free descriptor area */
- if (comm->desc_base) {
- dma_free_coherent(&comm->pdev->dev, comm->desc_size, comm->desc_base,
- comm->desc_dma);
- comm->desc_base = NULL;
- comm->desc_dma = 0;
- comm->desc_size = 0;
- }
- }
- void spl2sw_tx_descs_init(struct spl2sw_common *comm)
- {
- memset(comm->tx_desc, '\0', sizeof(struct spl2sw_mac_desc) *
- (TX_DESC_NUM + MAC_GUARD_DESC_NUM));
- }
- int spl2sw_rx_descs_init(struct spl2sw_common *comm)
- {
- struct spl2sw_skb_info *rx_skbinfo;
- struct spl2sw_mac_desc *rx_desc;
- struct sk_buff *skb;
- u32 mapping;
- u32 i, j;
- for (i = 0; i < RX_DESC_QUEUE_NUM; i++) {
- comm->rx_skb_info[i] = kzalloc_objs(*rx_skbinfo,
- comm->rx_desc_num[i],
- GFP_KERNEL | GFP_DMA);
- if (!comm->rx_skb_info[i])
- goto mem_alloc_fail;
- rx_skbinfo = comm->rx_skb_info[i];
- rx_desc = comm->rx_desc[i];
- for (j = 0; j < comm->rx_desc_num[i]; j++) {
- skb = netdev_alloc_skb(NULL, comm->rx_desc_buff_size);
- if (!skb)
- goto mem_alloc_fail;
- rx_skbinfo[j].skb = skb;
- mapping = dma_map_single(&comm->pdev->dev, skb->data,
- comm->rx_desc_buff_size,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(&comm->pdev->dev, mapping))
- goto mem_alloc_fail;
- rx_skbinfo[j].mapping = mapping;
- rx_desc[j].addr1 = mapping;
- rx_desc[j].addr2 = 0;
- rx_desc[j].cmd2 = (j == comm->rx_desc_num[i] - 1) ?
- RXD_EOR | comm->rx_desc_buff_size :
- comm->rx_desc_buff_size;
- wmb(); /* Set RXD_OWN after other fields are effective. */
- rx_desc[j].cmd1 = RXD_OWN;
- }
- }
- return 0;
- mem_alloc_fail:
- spl2sw_rx_descs_clean(comm);
- return -ENOMEM;
- }
- int spl2sw_descs_alloc(struct spl2sw_common *comm)
- {
- s32 desc_size;
- u32 i;
- /* Alloc descriptor area */
- desc_size = (TX_DESC_NUM + MAC_GUARD_DESC_NUM) * sizeof(struct spl2sw_mac_desc);
- for (i = 0; i < RX_DESC_QUEUE_NUM; i++)
- desc_size += comm->rx_desc_num[i] * sizeof(struct spl2sw_mac_desc);
- comm->desc_base = dma_alloc_coherent(&comm->pdev->dev, desc_size, &comm->desc_dma,
- GFP_KERNEL);
- if (!comm->desc_base)
- return -ENOMEM;
- comm->desc_size = desc_size;
- /* Setup Tx descriptor */
- comm->tx_desc = comm->desc_base;
- /* Setup Rx descriptor */
- comm->rx_desc[0] = &comm->tx_desc[TX_DESC_NUM + MAC_GUARD_DESC_NUM];
- for (i = 1; i < RX_DESC_QUEUE_NUM; i++)
- comm->rx_desc[i] = comm->rx_desc[i - 1] + comm->rx_desc_num[i - 1];
- return 0;
- }
- int spl2sw_descs_init(struct spl2sw_common *comm)
- {
- u32 i, ret;
- /* Initialize rx descriptor's data */
- comm->rx_desc_num[0] = RX_QUEUE0_DESC_NUM;
- comm->rx_desc_num[1] = RX_QUEUE1_DESC_NUM;
- for (i = 0; i < RX_DESC_QUEUE_NUM; i++) {
- comm->rx_desc[i] = NULL;
- comm->rx_skb_info[i] = NULL;
- comm->rx_pos[i] = 0;
- }
- comm->rx_desc_buff_size = MAC_RX_LEN_MAX;
- /* Initialize tx descriptor's data */
- comm->tx_done_pos = 0;
- comm->tx_desc = NULL;
- comm->tx_pos = 0;
- comm->tx_desc_full = 0;
- for (i = 0; i < TX_DESC_NUM; i++)
- comm->tx_temp_skb_info[i].skb = NULL;
- /* Allocate tx & rx descriptors. */
- ret = spl2sw_descs_alloc(comm);
- if (ret)
- return ret;
- spl2sw_tx_descs_init(comm);
- return spl2sw_rx_descs_init(comm);
- }
|