1 // SPDX-License-Identifier: GPL-2.0-only 2 /******************************************************************************* 3 This contains the functions to handle the normal descriptors. 4 5 Copyright (C) 2007-2009 STMicroelectronics Ltd 6 7 8 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> 9 *******************************************************************************/ 10 11 #include <linux/stmmac.h> 12 #include "common.h" 13 #include "descs_com.h" 14 15 static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x, 16 struct dma_desc *p, void __iomem *ioaddr) 17 { 18 struct net_device_stats *stats = (struct net_device_stats *)data; 19 unsigned int tdes0 = le32_to_cpu(p->des0); 20 unsigned int tdes1 = le32_to_cpu(p->des1); 21 int ret = tx_done; 22 23 /* Get tx owner first */ 24 if (unlikely(tdes0 & TDES0_OWN)) 25 return tx_dma_own; 26 27 /* Verify tx error by looking at the last segment. */ 28 if (likely(!(tdes1 & TDES1_LAST_SEGMENT))) 29 return tx_not_ls; 30 31 if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) { 32 if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) { 33 x->tx_underflow++; 34 stats->tx_fifo_errors++; 35 } 36 if (unlikely(tdes0 & TDES0_NO_CARRIER)) { 37 x->tx_carrier++; 38 stats->tx_carrier_errors++; 39 } 40 if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) { 41 x->tx_losscarrier++; 42 stats->tx_carrier_errors++; 43 } 44 if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) || 45 (tdes0 & TDES0_EXCESSIVE_COLLISIONS) || 46 (tdes0 & TDES0_LATE_COLLISION))) { 47 unsigned int collisions; 48 49 collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3; 50 stats->collisions += collisions; 51 } 52 ret = tx_err; 53 } 54 55 if (tdes0 & TDES0_VLAN_FRAME) 56 x->tx_vlan++; 57 58 if (unlikely(tdes0 & TDES0_DEFERRED)) 59 x->tx_deferred++; 60 61 return ret; 62 } 63 64 static int ndesc_get_tx_len(struct dma_desc *p) 65 { 66 return (le32_to_cpu(p->des1) & RDES1_BUFFER1_SIZE_MASK); 67 } 68 69 /* This function verifies if each incoming frame has some errors 70 * and, if required, updates the multicast statistics. 71 * In case of success, it returns good_frame because the GMAC device 72 * is supposed to be able to compute the csum in HW. */ 73 static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x, 74 struct dma_desc *p) 75 { 76 int ret = good_frame; 77 unsigned int rdes0 = le32_to_cpu(p->des0); 78 struct net_device_stats *stats = (struct net_device_stats *)data; 79 80 if (unlikely(rdes0 & RDES0_OWN)) 81 return dma_own; 82 83 if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) { 84 stats->rx_length_errors++; 85 return discard_frame; 86 } 87 88 if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) { 89 if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) 90 x->rx_desc++; 91 if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL)) 92 x->sa_filter_fail++; 93 if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR)) 94 x->overflow_error++; 95 if (unlikely(rdes0 & RDES0_IPC_CSUM_ERROR)) 96 x->ipc_csum_error++; 97 if (unlikely(rdes0 & RDES0_COLLISION)) { 98 x->rx_collision++; 99 stats->collisions++; 100 } 101 if (unlikely(rdes0 & RDES0_CRC_ERROR)) { 102 x->rx_crc_errors++; 103 stats->rx_crc_errors++; 104 } 105 ret = discard_frame; 106 } 107 if (unlikely(rdes0 & RDES0_DRIBBLING)) 108 x->dribbling_bit++; 109 110 if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) { 111 x->rx_length++; 112 ret = discard_frame; 113 } 114 if (unlikely(rdes0 & RDES0_MII_ERROR)) { 115 x->rx_mii++; 116 ret = discard_frame; 117 } 118 #ifdef STMMAC_VLAN_TAG_USED 119 if (rdes0 & RDES0_VLAN_TAG) 120 x->vlan_tag++; 121 #endif 122 return ret; 123 } 124 125 static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode, 126 int end, int bfsize) 127 { 128 int bfsize1; 129 130 p->des0 |= cpu_to_le32(RDES0_OWN); 131 132 bfsize1 = min(bfsize, BUF_SIZE_2KiB - 1); 133 p->des1 |= cpu_to_le32(bfsize1 & RDES1_BUFFER1_SIZE_MASK); 134 135 if (mode == STMMAC_CHAIN_MODE) 136 ndesc_rx_set_on_chain(p, end); 137 else 138 ndesc_rx_set_on_ring(p, end, bfsize); 139 140 if (disable_rx_ic) 141 p->des1 |= cpu_to_le32(RDES1_DISABLE_IC); 142 } 143 144 static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end) 145 { 146 p->des0 &= cpu_to_le32(~TDES0_OWN); 147 if (mode == STMMAC_CHAIN_MODE) 148 ndesc_tx_set_on_chain(p); 149 else 150 ndesc_end_tx_desc_on_ring(p, end); 151 } 152 153 static int ndesc_get_tx_owner(struct dma_desc *p) 154 { 155 return (le32_to_cpu(p->des0) & TDES0_OWN) >> 31; 156 } 157 158 static void ndesc_set_tx_owner(struct dma_desc *p) 159 { 160 p->des0 |= cpu_to_le32(TDES0_OWN); 161 } 162 163 static void ndesc_set_rx_owner(struct dma_desc *p, int disable_rx_ic) 164 { 165 p->des0 |= cpu_to_le32(RDES0_OWN); 166 } 167 168 static int ndesc_get_tx_ls(struct dma_desc *p) 169 { 170 return (le32_to_cpu(p->des1) & TDES1_LAST_SEGMENT) >> 30; 171 } 172 173 static void ndesc_release_tx_desc(struct dma_desc *p, int mode) 174 { 175 int ter = (le32_to_cpu(p->des1) & TDES1_END_RING) >> 25; 176 177 memset(p, 0, offsetof(struct dma_desc, des2)); 178 if (mode == STMMAC_CHAIN_MODE) 179 ndesc_tx_set_on_chain(p); 180 else 181 ndesc_end_tx_desc_on_ring(p, ter); 182 } 183 184 static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, 185 bool csum_flag, int mode, bool tx_own, 186 bool ls, unsigned int tot_pkt_len) 187 { 188 unsigned int tdes1 = le32_to_cpu(p->des1); 189 190 if (is_fs) 191 tdes1 |= TDES1_FIRST_SEGMENT; 192 else 193 tdes1 &= ~TDES1_FIRST_SEGMENT; 194 195 if (likely(csum_flag)) 196 tdes1 |= (TX_CIC_FULL) << TDES1_CHECKSUM_INSERTION_SHIFT; 197 else 198 tdes1 &= ~(TX_CIC_FULL << TDES1_CHECKSUM_INSERTION_SHIFT); 199 200 if (ls) 201 tdes1 |= TDES1_LAST_SEGMENT; 202 203 p->des1 = cpu_to_le32(tdes1); 204 205 if (mode == STMMAC_CHAIN_MODE) 206 norm_set_tx_desc_len_on_chain(p, len); 207 else 208 norm_set_tx_desc_len_on_ring(p, len); 209 210 if (tx_own) 211 p->des0 |= cpu_to_le32(TDES0_OWN); 212 } 213 214 static void ndesc_set_tx_ic(struct dma_desc *p) 215 { 216 p->des1 |= cpu_to_le32(TDES1_INTERRUPT); 217 } 218 219 static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type) 220 { 221 unsigned int csum = 0; 222 223 /* The type-1 checksum offload engines append the checksum at 224 * the end of frame and the two bytes of checksum are added in 225 * the length. 226 * Adjust for that in the framelen for type-1 checksum offload 227 * engines 228 */ 229 if (rx_coe_type == STMMAC_RX_COE_TYPE1) 230 csum = 2; 231 232 return (((le32_to_cpu(p->des0) & RDES0_FRAME_LEN_MASK) 233 >> RDES0_FRAME_LEN_SHIFT) - 234 csum); 235 236 } 237 238 static void ndesc_enable_tx_timestamp(struct dma_desc *p) 239 { 240 p->des1 |= cpu_to_le32(TDES1_TIME_STAMP_ENABLE); 241 } 242 243 static int ndesc_get_tx_timestamp_status(struct dma_desc *p) 244 { 245 return (le32_to_cpu(p->des0) & TDES0_TIME_STAMP_STATUS) >> 17; 246 } 247 248 static void ndesc_get_timestamp(void *desc, u32 ats, u64 *ts) 249 { 250 struct dma_desc *p = (struct dma_desc *)desc; 251 u64 ns; 252 253 ns = le32_to_cpu(p->des2); 254 /* convert high/sec time stamp value to nanosecond */ 255 ns += le32_to_cpu(p->des3) * 1000000000ULL; 256 257 *ts = ns; 258 } 259 260 static int ndesc_get_rx_timestamp_status(void *desc, void *next_desc, u32 ats) 261 { 262 struct dma_desc *p = (struct dma_desc *)desc; 263 264 if ((le32_to_cpu(p->des2) == 0xffffffff) && 265 (le32_to_cpu(p->des3) == 0xffffffff)) 266 /* timestamp is corrupted, hence don't store it */ 267 return 0; 268 else 269 return 1; 270 } 271 272 static void ndesc_display_ring(void *head, unsigned int size, bool rx) 273 { 274 struct dma_desc *p = (struct dma_desc *)head; 275 int i; 276 277 pr_info("%s descriptor ring:\n", rx ? "RX" : "TX"); 278 279 for (i = 0; i < size; i++) { 280 u64 x; 281 282 x = *(u64 *)p; 283 pr_info("%03d [0x%x]: 0x%x 0x%x 0x%x 0x%x", 284 i, (unsigned int)virt_to_phys(p), 285 (unsigned int)x, (unsigned int)(x >> 32), 286 p->des2, p->des3); 287 p++; 288 } 289 pr_info("\n"); 290 } 291 292 static void ndesc_get_addr(struct dma_desc *p, unsigned int *addr) 293 { 294 *addr = le32_to_cpu(p->des2); 295 } 296 297 static void ndesc_set_addr(struct dma_desc *p, dma_addr_t addr) 298 { 299 p->des2 = cpu_to_le32(addr); 300 } 301 302 static void ndesc_clear(struct dma_desc *p) 303 { 304 p->des2 = 0; 305 } 306 307 const struct stmmac_desc_ops ndesc_ops = { 308 .tx_status = ndesc_get_tx_status, 309 .rx_status = ndesc_get_rx_status, 310 .get_tx_len = ndesc_get_tx_len, 311 .init_rx_desc = ndesc_init_rx_desc, 312 .init_tx_desc = ndesc_init_tx_desc, 313 .get_tx_owner = ndesc_get_tx_owner, 314 .release_tx_desc = ndesc_release_tx_desc, 315 .prepare_tx_desc = ndesc_prepare_tx_desc, 316 .set_tx_ic = ndesc_set_tx_ic, 317 .get_tx_ls = ndesc_get_tx_ls, 318 .set_tx_owner = ndesc_set_tx_owner, 319 .set_rx_owner = ndesc_set_rx_owner, 320 .get_rx_frame_len = ndesc_get_rx_frame_len, 321 .enable_tx_timestamp = ndesc_enable_tx_timestamp, 322 .get_tx_timestamp_status = ndesc_get_tx_timestamp_status, 323 .get_timestamp = ndesc_get_timestamp, 324 .get_rx_timestamp_status = ndesc_get_rx_timestamp_status, 325 .display_ring = ndesc_display_ring, 326 .get_addr = ndesc_get_addr, 327 .set_addr = ndesc_set_addr, 328 .clear = ndesc_clear, 329 }; 330