229 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright Sunplus Technology Co., Ltd.3 * All rights reserved.4 */5 6#include <linux/platform_device.h>7#include <linux/netdevice.h>8#include <linux/of_mdio.h>9 10#include "spl2sw_define.h"11#include "spl2sw_desc.h"12 13void spl2sw_rx_descs_flush(struct spl2sw_common *comm)14{15 struct spl2sw_skb_info *rx_skbinfo;16 struct spl2sw_mac_desc *rx_desc;17 u32 i, j;18 19 for (i = 0; i < RX_DESC_QUEUE_NUM; i++) {20 rx_desc = comm->rx_desc[i];21 rx_skbinfo = comm->rx_skb_info[i];22 for (j = 0; j < comm->rx_desc_num[i]; j++) {23 rx_desc[j].addr1 = rx_skbinfo[j].mapping;24 rx_desc[j].cmd2 = (j == comm->rx_desc_num[i] - 1) ?25 RXD_EOR | comm->rx_desc_buff_size :26 comm->rx_desc_buff_size;27 wmb(); /* Set RXD_OWN after other fields are ready. */28 rx_desc[j].cmd1 = RXD_OWN;29 }30 }31}32 33void spl2sw_tx_descs_clean(struct spl2sw_common *comm)34{35 u32 i;36 37 if (!comm->tx_desc)38 return;39 40 for (i = 0; i < TX_DESC_NUM; i++) {41 comm->tx_desc[i].cmd1 = 0;42 wmb(); /* Clear TXD_OWN and then set other fields. */43 comm->tx_desc[i].cmd2 = 0;44 comm->tx_desc[i].addr1 = 0;45 comm->tx_desc[i].addr2 = 0;46 47 if (comm->tx_temp_skb_info[i].mapping) {48 dma_unmap_single(&comm->pdev->dev, comm->tx_temp_skb_info[i].mapping,49 comm->tx_temp_skb_info[i].skb->len, DMA_TO_DEVICE);50 comm->tx_temp_skb_info[i].mapping = 0;51 }52 53 if (comm->tx_temp_skb_info[i].skb) {54 dev_kfree_skb_any(comm->tx_temp_skb_info[i].skb);55 comm->tx_temp_skb_info[i].skb = NULL;56 }57 }58}59 60void spl2sw_rx_descs_clean(struct spl2sw_common *comm)61{62 struct spl2sw_skb_info *rx_skbinfo;63 struct spl2sw_mac_desc *rx_desc;64 u32 i, j;65 66 for (i = 0; i < RX_DESC_QUEUE_NUM; i++) {67 if (!comm->rx_skb_info[i])68 continue;69 70 rx_desc = comm->rx_desc[i];71 rx_skbinfo = comm->rx_skb_info[i];72 for (j = 0; j < comm->rx_desc_num[i]; j++) {73 rx_desc[j].cmd1 = 0;74 wmb(); /* Clear RXD_OWN and then set other fields. */75 rx_desc[j].cmd2 = 0;76 rx_desc[j].addr1 = 0;77 78 if (rx_skbinfo[j].skb) {79 dma_unmap_single(&comm->pdev->dev, rx_skbinfo[j].mapping,80 comm->rx_desc_buff_size, DMA_FROM_DEVICE);81 dev_kfree_skb_any(rx_skbinfo[j].skb);82 rx_skbinfo[j].skb = NULL;83 rx_skbinfo[j].mapping = 0;84 }85 }86 87 kfree(rx_skbinfo);88 comm->rx_skb_info[i] = NULL;89 }90}91 92void spl2sw_descs_clean(struct spl2sw_common *comm)93{94 spl2sw_rx_descs_clean(comm);95 spl2sw_tx_descs_clean(comm);96}97 98void spl2sw_descs_free(struct spl2sw_common *comm)99{100 u32 i;101 102 spl2sw_descs_clean(comm);103 comm->tx_desc = NULL;104 for (i = 0; i < RX_DESC_QUEUE_NUM; i++)105 comm->rx_desc[i] = NULL;106 107 /* Free descriptor area */108 if (comm->desc_base) {109 dma_free_coherent(&comm->pdev->dev, comm->desc_size, comm->desc_base,110 comm->desc_dma);111 comm->desc_base = NULL;112 comm->desc_dma = 0;113 comm->desc_size = 0;114 }115}116 117void spl2sw_tx_descs_init(struct spl2sw_common *comm)118{119 memset(comm->tx_desc, '\0', sizeof(struct spl2sw_mac_desc) *120 (TX_DESC_NUM + MAC_GUARD_DESC_NUM));121}122 123int spl2sw_rx_descs_init(struct spl2sw_common *comm)124{125 struct spl2sw_skb_info *rx_skbinfo;126 struct spl2sw_mac_desc *rx_desc;127 struct sk_buff *skb;128 u32 mapping;129 u32 i, j;130 131 for (i = 0; i < RX_DESC_QUEUE_NUM; i++) {132 comm->rx_skb_info[i] = kcalloc(comm->rx_desc_num[i], sizeof(*rx_skbinfo),133 GFP_KERNEL | GFP_DMA);134 if (!comm->rx_skb_info[i])135 goto mem_alloc_fail;136 137 rx_skbinfo = comm->rx_skb_info[i];138 rx_desc = comm->rx_desc[i];139 for (j = 0; j < comm->rx_desc_num[i]; j++) {140 skb = netdev_alloc_skb(NULL, comm->rx_desc_buff_size);141 if (!skb)142 goto mem_alloc_fail;143 144 rx_skbinfo[j].skb = skb;145 mapping = dma_map_single(&comm->pdev->dev, skb->data,146 comm->rx_desc_buff_size,147 DMA_FROM_DEVICE);148 if (dma_mapping_error(&comm->pdev->dev, mapping))149 goto mem_alloc_fail;150 151 rx_skbinfo[j].mapping = mapping;152 rx_desc[j].addr1 = mapping;153 rx_desc[j].addr2 = 0;154 rx_desc[j].cmd2 = (j == comm->rx_desc_num[i] - 1) ?155 RXD_EOR | comm->rx_desc_buff_size :156 comm->rx_desc_buff_size;157 wmb(); /* Set RXD_OWN after other fields are effective. */158 rx_desc[j].cmd1 = RXD_OWN;159 }160 }161 162 return 0;163 164mem_alloc_fail:165 spl2sw_rx_descs_clean(comm);166 return -ENOMEM;167}168 169int spl2sw_descs_alloc(struct spl2sw_common *comm)170{171 s32 desc_size;172 u32 i;173 174 /* Alloc descriptor area */175 desc_size = (TX_DESC_NUM + MAC_GUARD_DESC_NUM) * sizeof(struct spl2sw_mac_desc);176 for (i = 0; i < RX_DESC_QUEUE_NUM; i++)177 desc_size += comm->rx_desc_num[i] * sizeof(struct spl2sw_mac_desc);178 179 comm->desc_base = dma_alloc_coherent(&comm->pdev->dev, desc_size, &comm->desc_dma,180 GFP_KERNEL);181 if (!comm->desc_base)182 return -ENOMEM;183 184 comm->desc_size = desc_size;185 186 /* Setup Tx descriptor */187 comm->tx_desc = comm->desc_base;188 189 /* Setup Rx descriptor */190 comm->rx_desc[0] = &comm->tx_desc[TX_DESC_NUM + MAC_GUARD_DESC_NUM];191 for (i = 1; i < RX_DESC_QUEUE_NUM; i++)192 comm->rx_desc[i] = comm->rx_desc[i - 1] + comm->rx_desc_num[i - 1];193 194 return 0;195}196 197int spl2sw_descs_init(struct spl2sw_common *comm)198{199 u32 i, ret;200 201 /* Initialize rx descriptor's data */202 comm->rx_desc_num[0] = RX_QUEUE0_DESC_NUM;203 comm->rx_desc_num[1] = RX_QUEUE1_DESC_NUM;204 205 for (i = 0; i < RX_DESC_QUEUE_NUM; i++) {206 comm->rx_desc[i] = NULL;207 comm->rx_skb_info[i] = NULL;208 comm->rx_pos[i] = 0;209 }210 comm->rx_desc_buff_size = MAC_RX_LEN_MAX;211 212 /* Initialize tx descriptor's data */213 comm->tx_done_pos = 0;214 comm->tx_desc = NULL;215 comm->tx_pos = 0;216 comm->tx_desc_full = 0;217 for (i = 0; i < TX_DESC_NUM; i++)218 comm->tx_temp_skb_info[i].skb = NULL;219 220 /* Allocate tx & rx descriptors. */221 ret = spl2sw_descs_alloc(comm);222 if (ret)223 return ret;224 225 spl2sw_tx_descs_init(comm);226 227 return spl2sw_rx_descs_init(comm);228}229