| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * This contains the functions to handle the descriptors for DesignWare databook |
|---|
| 3 | 4 | * 4.xx. |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * Copyright (C) 2015 STMicroelectronics Ltd |
|---|
| 6 | 7 | * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 8 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 9 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 10 | | - * |
|---|
| 11 | 8 | * Author: Alexandre Torgue <alexandre.torgue@st.com> |
|---|
| 12 | 9 | */ |
|---|
| 13 | 10 | |
|---|
| 14 | 11 | #include <linux/stmmac.h> |
|---|
| 15 | 12 | #include "common.h" |
|---|
| 13 | +#include "dwmac4.h" |
|---|
| 16 | 14 | #include "dwmac4_descs.h" |
|---|
| 17 | 15 | |
|---|
| 18 | 16 | static int dwmac4_wrback_get_tx_status(void *data, struct stmmac_extra_stats *x, |
|---|
| .. | .. |
|---|
| 86 | 84 | if (unlikely(rdes3 & RDES3_OWN)) |
|---|
| 87 | 85 | return dma_own; |
|---|
| 88 | 86 | |
|---|
| 89 | | - /* Verify rx error by looking at the last segment. */ |
|---|
| 90 | | - if (likely(!(rdes3 & RDES3_LAST_DESCRIPTOR))) |
|---|
| 87 | + if (unlikely(rdes3 & RDES3_CONTEXT_DESCRIPTOR)) |
|---|
| 91 | 88 | return discard_frame; |
|---|
| 89 | + if (likely(!(rdes3 & RDES3_LAST_DESCRIPTOR))) |
|---|
| 90 | + return rx_not_ls; |
|---|
| 92 | 91 | |
|---|
| 93 | 92 | if (unlikely(rdes3 & RDES3_ERROR_SUMMARY)) { |
|---|
| 94 | 93 | if (unlikely(rdes3 & RDES3_GIANT_PACKET)) |
|---|
| .. | .. |
|---|
| 191 | 190 | |
|---|
| 192 | 191 | static void dwmac4_set_rx_owner(struct dma_desc *p, int disable_rx_ic) |
|---|
| 193 | 192 | { |
|---|
| 194 | | - p->des3 = cpu_to_le32(RDES3_OWN | RDES3_BUFFER1_VALID_ADDR); |
|---|
| 193 | + p->des3 |= cpu_to_le32(RDES3_OWN | RDES3_BUFFER1_VALID_ADDR); |
|---|
| 195 | 194 | |
|---|
| 196 | 195 | if (!disable_rx_ic) |
|---|
| 197 | 196 | p->des3 |= cpu_to_le32(RDES3_INT_ON_COMPLETION_EN); |
|---|
| .. | .. |
|---|
| 271 | 270 | int ret = -EINVAL; |
|---|
| 272 | 271 | |
|---|
| 273 | 272 | /* Get the status from normal w/b descriptor */ |
|---|
| 274 | | - if (likely(p->des3 & TDES3_RS1V)) { |
|---|
| 273 | + if (likely(le32_to_cpu(p->des3) & RDES3_RDES1_VALID)) { |
|---|
| 275 | 274 | if (likely(le32_to_cpu(p->des1) & RDES1_TIMESTAMP_AVAILABLE)) { |
|---|
| 276 | 275 | int i = 0; |
|---|
| 277 | 276 | |
|---|
| .. | .. |
|---|
| 403 | 402 | p->des2 |= cpu_to_le32(TDES2_INTERRUPT_ON_COMPLETION); |
|---|
| 404 | 403 | } |
|---|
| 405 | 404 | |
|---|
| 406 | | -static void dwmac4_display_ring(void *head, unsigned int size, bool rx) |
|---|
| 405 | +static void dwmac4_display_ring(void *head, unsigned int size, bool rx, |
|---|
| 406 | + dma_addr_t dma_rx_phy, unsigned int desc_size) |
|---|
| 407 | 407 | { |
|---|
| 408 | | - struct dma_desc *p = (struct dma_desc *)head; |
|---|
| 408 | + dma_addr_t dma_addr; |
|---|
| 409 | 409 | int i; |
|---|
| 410 | 410 | |
|---|
| 411 | 411 | pr_info("%s descriptor ring:\n", rx ? "RX" : "TX"); |
|---|
| 412 | 412 | |
|---|
| 413 | | - for (i = 0; i < size; i++) { |
|---|
| 414 | | - pr_info("%03d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n", |
|---|
| 415 | | - i, (unsigned int)virt_to_phys(p), |
|---|
| 416 | | - le32_to_cpu(p->des0), le32_to_cpu(p->des1), |
|---|
| 417 | | - le32_to_cpu(p->des2), le32_to_cpu(p->des3)); |
|---|
| 418 | | - p++; |
|---|
| 413 | + if (desc_size == sizeof(struct dma_desc)) { |
|---|
| 414 | + struct dma_desc *p = (struct dma_desc *)head; |
|---|
| 415 | + |
|---|
| 416 | + for (i = 0; i < size; i++) { |
|---|
| 417 | + dma_addr = dma_rx_phy + i * sizeof(*p); |
|---|
| 418 | + pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x\n", |
|---|
| 419 | + i, &dma_addr, |
|---|
| 420 | + le32_to_cpu(p->des0), le32_to_cpu(p->des1), |
|---|
| 421 | + le32_to_cpu(p->des2), le32_to_cpu(p->des3)); |
|---|
| 422 | + p++; |
|---|
| 423 | + } |
|---|
| 424 | + } else if (desc_size == sizeof(struct dma_extended_desc)) { |
|---|
| 425 | + struct dma_extended_desc *extp = (struct dma_extended_desc *)head; |
|---|
| 426 | + |
|---|
| 427 | + for (i = 0; i < size; i++) { |
|---|
| 428 | + dma_addr = dma_rx_phy + i * sizeof(*extp); |
|---|
| 429 | + pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", |
|---|
| 430 | + i, &dma_addr, |
|---|
| 431 | + le32_to_cpu(extp->basic.des0), le32_to_cpu(extp->basic.des1), |
|---|
| 432 | + le32_to_cpu(extp->basic.des2), le32_to_cpu(extp->basic.des3), |
|---|
| 433 | + le32_to_cpu(extp->des4), le32_to_cpu(extp->des5), |
|---|
| 434 | + le32_to_cpu(extp->des6), le32_to_cpu(extp->des7)); |
|---|
| 435 | + extp++; |
|---|
| 436 | + } |
|---|
| 437 | + } else if (desc_size == sizeof(struct dma_edesc)) { |
|---|
| 438 | + struct dma_edesc *ep = (struct dma_edesc *)head; |
|---|
| 439 | + |
|---|
| 440 | + for (i = 0; i < size; i++) { |
|---|
| 441 | + dma_addr = dma_rx_phy + i * sizeof(*ep); |
|---|
| 442 | + pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", |
|---|
| 443 | + i, &dma_addr, |
|---|
| 444 | + le32_to_cpu(ep->des4), le32_to_cpu(ep->des5), |
|---|
| 445 | + le32_to_cpu(ep->des6), le32_to_cpu(ep->des7), |
|---|
| 446 | + le32_to_cpu(ep->basic.des0), le32_to_cpu(ep->basic.des1), |
|---|
| 447 | + le32_to_cpu(ep->basic.des2), le32_to_cpu(ep->basic.des3)); |
|---|
| 448 | + ep++; |
|---|
| 449 | + } |
|---|
| 450 | + } else { |
|---|
| 451 | + pr_err("unsupported descriptor!"); |
|---|
| 419 | 452 | } |
|---|
| 420 | 453 | } |
|---|
| 421 | 454 | |
|---|
| .. | .. |
|---|
| 434 | 467 | |
|---|
| 435 | 468 | static void dwmac4_set_addr(struct dma_desc *p, dma_addr_t addr) |
|---|
| 436 | 469 | { |
|---|
| 437 | | - p->des0 = cpu_to_le32(addr); |
|---|
| 438 | | - p->des1 = 0; |
|---|
| 470 | + p->des0 = cpu_to_le32(lower_32_bits(addr)); |
|---|
| 471 | + p->des1 = cpu_to_le32(upper_32_bits(addr)); |
|---|
| 439 | 472 | } |
|---|
| 440 | 473 | |
|---|
| 441 | 474 | static void dwmac4_clear(struct dma_desc *p) |
|---|
| .. | .. |
|---|
| 444 | 477 | p->des1 = 0; |
|---|
| 445 | 478 | p->des2 = 0; |
|---|
| 446 | 479 | p->des3 = 0; |
|---|
| 480 | +} |
|---|
| 481 | + |
|---|
| 482 | +static void dwmac4_set_sarc(struct dma_desc *p, u32 sarc_type) |
|---|
| 483 | +{ |
|---|
| 484 | + sarc_type <<= TDES3_SA_INSERT_CTRL_SHIFT; |
|---|
| 485 | + |
|---|
| 486 | + p->des3 |= cpu_to_le32(sarc_type & TDES3_SA_INSERT_CTRL_MASK); |
|---|
| 487 | +} |
|---|
| 488 | + |
|---|
| 489 | +static int set_16kib_bfsize(int mtu) |
|---|
| 490 | +{ |
|---|
| 491 | + int ret = 0; |
|---|
| 492 | + |
|---|
| 493 | + if (unlikely(mtu >= BUF_SIZE_8KiB)) |
|---|
| 494 | + ret = BUF_SIZE_16KiB; |
|---|
| 495 | + return ret; |
|---|
| 496 | +} |
|---|
| 497 | + |
|---|
| 498 | +static void dwmac4_set_vlan_tag(struct dma_desc *p, u16 tag, u16 inner_tag, |
|---|
| 499 | + u32 inner_type) |
|---|
| 500 | +{ |
|---|
| 501 | + p->des0 = 0; |
|---|
| 502 | + p->des1 = 0; |
|---|
| 503 | + p->des2 = 0; |
|---|
| 504 | + p->des3 = 0; |
|---|
| 505 | + |
|---|
| 506 | + /* Inner VLAN */ |
|---|
| 507 | + if (inner_type) { |
|---|
| 508 | + u32 des = inner_tag << TDES2_IVT_SHIFT; |
|---|
| 509 | + |
|---|
| 510 | + des &= TDES2_IVT_MASK; |
|---|
| 511 | + p->des2 = cpu_to_le32(des); |
|---|
| 512 | + |
|---|
| 513 | + des = inner_type << TDES3_IVTIR_SHIFT; |
|---|
| 514 | + des &= TDES3_IVTIR_MASK; |
|---|
| 515 | + p->des3 = cpu_to_le32(des | TDES3_IVLTV); |
|---|
| 516 | + } |
|---|
| 517 | + |
|---|
| 518 | + /* Outer VLAN */ |
|---|
| 519 | + p->des3 |= cpu_to_le32(tag & TDES3_VLAN_TAG); |
|---|
| 520 | + p->des3 |= cpu_to_le32(TDES3_VLTV); |
|---|
| 521 | + |
|---|
| 522 | + p->des3 |= cpu_to_le32(TDES3_CONTEXT_TYPE); |
|---|
| 523 | +} |
|---|
| 524 | + |
|---|
| 525 | +static void dwmac4_set_vlan(struct dma_desc *p, u32 type) |
|---|
| 526 | +{ |
|---|
| 527 | + type <<= TDES2_VLAN_TAG_SHIFT; |
|---|
| 528 | + p->des2 |= cpu_to_le32(type & TDES2_VLAN_TAG_MASK); |
|---|
| 529 | +} |
|---|
| 530 | + |
|---|
| 531 | +static void dwmac4_get_rx_header_len(struct dma_desc *p, unsigned int *len) |
|---|
| 532 | +{ |
|---|
| 533 | + *len = le32_to_cpu(p->des2) & RDES2_HL; |
|---|
| 534 | +} |
|---|
| 535 | + |
|---|
| 536 | +static void dwmac4_set_sec_addr(struct dma_desc *p, dma_addr_t addr, bool buf2_valid) |
|---|
| 537 | +{ |
|---|
| 538 | + p->des2 = cpu_to_le32(lower_32_bits(addr)); |
|---|
| 539 | + p->des3 = cpu_to_le32(upper_32_bits(addr)); |
|---|
| 540 | + |
|---|
| 541 | + if (buf2_valid) |
|---|
| 542 | + p->des3 |= cpu_to_le32(RDES3_BUFFER2_VALID_ADDR); |
|---|
| 543 | + else |
|---|
| 544 | + p->des3 &= cpu_to_le32(~RDES3_BUFFER2_VALID_ADDR); |
|---|
| 545 | +} |
|---|
| 546 | + |
|---|
| 547 | +static void dwmac4_set_tbs(struct dma_edesc *p, u32 sec, u32 nsec) |
|---|
| 548 | +{ |
|---|
| 549 | + p->des4 = cpu_to_le32((sec & TDES4_LT) | TDES4_LTV); |
|---|
| 550 | + p->des5 = cpu_to_le32(nsec & TDES5_LT); |
|---|
| 551 | + p->des6 = 0; |
|---|
| 552 | + p->des7 = 0; |
|---|
| 447 | 553 | } |
|---|
| 448 | 554 | |
|---|
| 449 | 555 | const struct stmmac_desc_ops dwmac4_desc_ops = { |
|---|
| .. | .. |
|---|
| 470 | 576 | .get_addr = dwmac4_get_addr, |
|---|
| 471 | 577 | .set_addr = dwmac4_set_addr, |
|---|
| 472 | 578 | .clear = dwmac4_clear, |
|---|
| 579 | + .set_sarc = dwmac4_set_sarc, |
|---|
| 580 | + .set_vlan_tag = dwmac4_set_vlan_tag, |
|---|
| 581 | + .set_vlan = dwmac4_set_vlan, |
|---|
| 582 | + .get_rx_header_len = dwmac4_get_rx_header_len, |
|---|
| 583 | + .set_sec_addr = dwmac4_set_sec_addr, |
|---|
| 584 | + .set_tbs = dwmac4_set_tbs, |
|---|
| 473 | 585 | }; |
|---|
| 474 | 586 | |
|---|
| 475 | | -const struct stmmac_mode_ops dwmac4_ring_mode_ops = { }; |
|---|
| 587 | +const struct stmmac_mode_ops dwmac4_ring_mode_ops = { |
|---|
| 588 | + .set_16kib_bfsize = set_16kib_bfsize, |
|---|
| 589 | +}; |
|---|