.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * This is the driver for the GMAC on-chip Ethernet controller for ST SoCs. |
---|
3 | 4 | * DWC Ether MAC version 4.00 has been used for developing this code. |
---|
.. | .. |
---|
5 | 6 | * This only implements the mac core functions for this chip. |
---|
6 | 7 | * |
---|
7 | 8 | * Copyright (C) 2015 STMicroelectronics Ltd |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or modify it |
---|
10 | | - * under the terms and conditions of the GNU General Public License, |
---|
11 | | - * version 2, as published by the Free Software Foundation. |
---|
12 | 9 | * |
---|
13 | 10 | * Author: Alexandre Torgue <alexandre.torgue@st.com> |
---|
14 | 11 | */ |
---|
.. | .. |
---|
28 | 25 | { |
---|
29 | 26 | void __iomem *ioaddr = hw->pcsr; |
---|
30 | 27 | u32 value = readl(ioaddr + GMAC_CONFIG); |
---|
31 | | - int mtu = dev->mtu; |
---|
32 | 28 | |
---|
33 | 29 | value |= GMAC_CORE_INIT; |
---|
34 | | - |
---|
35 | | - if (mtu > 1500) |
---|
36 | | - value |= GMAC_CONFIG_2K; |
---|
37 | | - if (mtu > 2000) |
---|
38 | | - value |= GMAC_CONFIG_JE; |
---|
39 | 30 | |
---|
40 | 31 | if (hw->ps) { |
---|
41 | 32 | value |= GMAC_CONFIG_TE; |
---|
.. | .. |
---|
196 | 187 | default: |
---|
197 | 188 | break; |
---|
198 | 189 | } |
---|
| 190 | + |
---|
| 191 | + writel(value, ioaddr + MTL_OPERATION_MODE); |
---|
199 | 192 | } |
---|
200 | 193 | |
---|
201 | 194 | static void dwmac4_set_mtl_tx_queue_weight(struct mac_device_info *hw, |
---|
.. | .. |
---|
222 | 215 | if (queue == 0 || queue == 4) { |
---|
223 | 216 | value &= ~MTL_RXQ_DMA_Q04MDMACH_MASK; |
---|
224 | 217 | value |= MTL_RXQ_DMA_Q04MDMACH(chan); |
---|
| 218 | + } else if (queue > 4) { |
---|
| 219 | + value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(queue - 4); |
---|
| 220 | + value |= MTL_RXQ_DMA_QXMDMACH(chan, queue - 4); |
---|
225 | 221 | } else { |
---|
226 | 222 | value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(queue); |
---|
227 | 223 | value |= MTL_RXQ_DMA_QXMDMACH(chan, queue); |
---|
.. | .. |
---|
401 | 397 | writel(value, ioaddr + GMAC4_LPI_TIMER_CTRL); |
---|
402 | 398 | } |
---|
403 | 399 | |
---|
| 400 | +static void dwmac4_write_single_vlan(struct net_device *dev, u16 vid) |
---|
| 401 | +{ |
---|
| 402 | + void __iomem *ioaddr = (void __iomem *)dev->base_addr; |
---|
| 403 | + u32 val; |
---|
| 404 | + |
---|
| 405 | + val = readl(ioaddr + GMAC_VLAN_TAG); |
---|
| 406 | + val &= ~GMAC_VLAN_TAG_VID; |
---|
| 407 | + val |= GMAC_VLAN_TAG_ETV | vid; |
---|
| 408 | + |
---|
| 409 | + writel(val, ioaddr + GMAC_VLAN_TAG); |
---|
| 410 | +} |
---|
| 411 | + |
---|
| 412 | +static int dwmac4_write_vlan_filter(struct net_device *dev, |
---|
| 413 | + struct mac_device_info *hw, |
---|
| 414 | + u8 index, u32 data) |
---|
| 415 | +{ |
---|
| 416 | + void __iomem *ioaddr = (void __iomem *)dev->base_addr; |
---|
| 417 | + int i, timeout = 10; |
---|
| 418 | + u32 val; |
---|
| 419 | + |
---|
| 420 | + if (index >= hw->num_vlan) |
---|
| 421 | + return -EINVAL; |
---|
| 422 | + |
---|
| 423 | + writel(data, ioaddr + GMAC_VLAN_TAG_DATA); |
---|
| 424 | + |
---|
| 425 | + val = readl(ioaddr + GMAC_VLAN_TAG); |
---|
| 426 | + val &= ~(GMAC_VLAN_TAG_CTRL_OFS_MASK | |
---|
| 427 | + GMAC_VLAN_TAG_CTRL_CT | |
---|
| 428 | + GMAC_VLAN_TAG_CTRL_OB); |
---|
| 429 | + val |= (index << GMAC_VLAN_TAG_CTRL_OFS_SHIFT) | GMAC_VLAN_TAG_CTRL_OB; |
---|
| 430 | + |
---|
| 431 | + writel(val, ioaddr + GMAC_VLAN_TAG); |
---|
| 432 | + |
---|
| 433 | + for (i = 0; i < timeout; i++) { |
---|
| 434 | + val = readl(ioaddr + GMAC_VLAN_TAG); |
---|
| 435 | + if (!(val & GMAC_VLAN_TAG_CTRL_OB)) |
---|
| 436 | + return 0; |
---|
| 437 | + udelay(1); |
---|
| 438 | + } |
---|
| 439 | + |
---|
| 440 | + netdev_err(dev, "Timeout accessing MAC_VLAN_Tag_Filter\n"); |
---|
| 441 | + |
---|
| 442 | + return -EBUSY; |
---|
| 443 | +} |
---|
| 444 | + |
---|
| 445 | +static int dwmac4_add_hw_vlan_rx_fltr(struct net_device *dev, |
---|
| 446 | + struct mac_device_info *hw, |
---|
| 447 | + __be16 proto, u16 vid) |
---|
| 448 | +{ |
---|
| 449 | + int index = -1; |
---|
| 450 | + u32 val = 0; |
---|
| 451 | + int i, ret; |
---|
| 452 | + |
---|
| 453 | + if (vid > 4095) |
---|
| 454 | + return -EINVAL; |
---|
| 455 | + |
---|
| 456 | + /* Single Rx VLAN Filter */ |
---|
| 457 | + if (hw->num_vlan == 1) { |
---|
| 458 | + /* For single VLAN filter, VID 0 means VLAN promiscuous */ |
---|
| 459 | + if (vid == 0) { |
---|
| 460 | + netdev_warn(dev, "Adding VLAN ID 0 is not supported\n"); |
---|
| 461 | + return -EPERM; |
---|
| 462 | + } |
---|
| 463 | + |
---|
| 464 | + if (hw->vlan_filter[0] & GMAC_VLAN_TAG_VID) { |
---|
| 465 | + netdev_err(dev, "Only single VLAN ID supported\n"); |
---|
| 466 | + return -EPERM; |
---|
| 467 | + } |
---|
| 468 | + |
---|
| 469 | + hw->vlan_filter[0] = vid; |
---|
| 470 | + dwmac4_write_single_vlan(dev, vid); |
---|
| 471 | + |
---|
| 472 | + return 0; |
---|
| 473 | + } |
---|
| 474 | + |
---|
| 475 | + /* Extended Rx VLAN Filter Enable */ |
---|
| 476 | + val |= GMAC_VLAN_TAG_DATA_ETV | GMAC_VLAN_TAG_DATA_VEN | vid; |
---|
| 477 | + |
---|
| 478 | + for (i = 0; i < hw->num_vlan; i++) { |
---|
| 479 | + if (hw->vlan_filter[i] == val) |
---|
| 480 | + return 0; |
---|
| 481 | + else if (!(hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VEN)) |
---|
| 482 | + index = i; |
---|
| 483 | + } |
---|
| 484 | + |
---|
| 485 | + if (index == -1) { |
---|
| 486 | + netdev_err(dev, "MAC_VLAN_Tag_Filter full (size: %0u)\n", |
---|
| 487 | + hw->num_vlan); |
---|
| 488 | + return -EPERM; |
---|
| 489 | + } |
---|
| 490 | + |
---|
| 491 | + ret = dwmac4_write_vlan_filter(dev, hw, index, val); |
---|
| 492 | + |
---|
| 493 | + if (!ret) |
---|
| 494 | + hw->vlan_filter[index] = val; |
---|
| 495 | + |
---|
| 496 | + return ret; |
---|
| 497 | +} |
---|
| 498 | + |
---|
| 499 | +static int dwmac4_del_hw_vlan_rx_fltr(struct net_device *dev, |
---|
| 500 | + struct mac_device_info *hw, |
---|
| 501 | + __be16 proto, u16 vid) |
---|
| 502 | +{ |
---|
| 503 | + int i, ret = 0; |
---|
| 504 | + |
---|
| 505 | + /* Single Rx VLAN Filter */ |
---|
| 506 | + if (hw->num_vlan == 1) { |
---|
| 507 | + if ((hw->vlan_filter[0] & GMAC_VLAN_TAG_VID) == vid) { |
---|
| 508 | + hw->vlan_filter[0] = 0; |
---|
| 509 | + dwmac4_write_single_vlan(dev, 0); |
---|
| 510 | + } |
---|
| 511 | + return 0; |
---|
| 512 | + } |
---|
| 513 | + |
---|
| 514 | + /* Extended Rx VLAN Filter Enable */ |
---|
| 515 | + for (i = 0; i < hw->num_vlan; i++) { |
---|
| 516 | + if ((hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VID) == vid) { |
---|
| 517 | + ret = dwmac4_write_vlan_filter(dev, hw, i, 0); |
---|
| 518 | + |
---|
| 519 | + if (!ret) |
---|
| 520 | + hw->vlan_filter[i] = 0; |
---|
| 521 | + else |
---|
| 522 | + return ret; |
---|
| 523 | + } |
---|
| 524 | + } |
---|
| 525 | + |
---|
| 526 | + return ret; |
---|
| 527 | +} |
---|
| 528 | + |
---|
| 529 | +static void dwmac4_restore_hw_vlan_rx_fltr(struct net_device *dev, |
---|
| 530 | + struct mac_device_info *hw) |
---|
| 531 | +{ |
---|
| 532 | + void __iomem *ioaddr = hw->pcsr; |
---|
| 533 | + u32 value; |
---|
| 534 | + u32 hash; |
---|
| 535 | + u32 val; |
---|
| 536 | + int i; |
---|
| 537 | + |
---|
| 538 | + /* Single Rx VLAN Filter */ |
---|
| 539 | + if (hw->num_vlan == 1) { |
---|
| 540 | + dwmac4_write_single_vlan(dev, hw->vlan_filter[0]); |
---|
| 541 | + return; |
---|
| 542 | + } |
---|
| 543 | + |
---|
| 544 | + /* Extended Rx VLAN Filter Enable */ |
---|
| 545 | + for (i = 0; i < hw->num_vlan; i++) { |
---|
| 546 | + if (hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VEN) { |
---|
| 547 | + val = hw->vlan_filter[i]; |
---|
| 548 | + dwmac4_write_vlan_filter(dev, hw, i, val); |
---|
| 549 | + } |
---|
| 550 | + } |
---|
| 551 | + |
---|
| 552 | + hash = readl(ioaddr + GMAC_VLAN_HASH_TABLE); |
---|
| 553 | + if (hash & GMAC_VLAN_VLHT) { |
---|
| 554 | + value = readl(ioaddr + GMAC_VLAN_TAG); |
---|
| 555 | + value |= GMAC_VLAN_VTHM; |
---|
| 556 | + writel(value, ioaddr + GMAC_VLAN_TAG); |
---|
| 557 | + } |
---|
| 558 | +} |
---|
| 559 | + |
---|
404 | 560 | static void dwmac4_set_filter(struct mac_device_info *hw, |
---|
405 | 561 | struct net_device *dev) |
---|
406 | 562 | { |
---|
407 | 563 | void __iomem *ioaddr = (void __iomem *)dev->base_addr; |
---|
408 | | - unsigned int value = 0; |
---|
| 564 | + int numhashregs = (hw->multicast_filter_bins >> 5); |
---|
| 565 | + int mcbitslog2 = hw->mcast_bits_log2; |
---|
| 566 | + unsigned int value; |
---|
| 567 | + u32 mc_filter[8]; |
---|
| 568 | + int i; |
---|
409 | 569 | |
---|
| 570 | + memset(mc_filter, 0, sizeof(mc_filter)); |
---|
| 571 | + |
---|
| 572 | + value = readl(ioaddr + GMAC_PACKET_FILTER); |
---|
| 573 | + value &= ~GMAC_PACKET_FILTER_HMC; |
---|
| 574 | + value &= ~GMAC_PACKET_FILTER_HPF; |
---|
| 575 | + value &= ~GMAC_PACKET_FILTER_PCF; |
---|
| 576 | + value &= ~GMAC_PACKET_FILTER_PM; |
---|
| 577 | + value &= ~GMAC_PACKET_FILTER_PR; |
---|
| 578 | + value &= ~GMAC_PACKET_FILTER_RA; |
---|
410 | 579 | if (dev->flags & IFF_PROMISC) { |
---|
411 | | - value = GMAC_PACKET_FILTER_PR; |
---|
| 580 | + /* VLAN Tag Filter Fail Packets Queuing */ |
---|
| 581 | + if (hw->vlan_fail_q_en) { |
---|
| 582 | + value = readl(ioaddr + GMAC_RXQ_CTRL4); |
---|
| 583 | + value &= ~GMAC_RXQCTRL_VFFQ_MASK; |
---|
| 584 | + value |= GMAC_RXQCTRL_VFFQE | |
---|
| 585 | + (hw->vlan_fail_q << GMAC_RXQCTRL_VFFQ_SHIFT); |
---|
| 586 | + writel(value, ioaddr + GMAC_RXQ_CTRL4); |
---|
| 587 | + value = GMAC_PACKET_FILTER_PR | GMAC_PACKET_FILTER_RA; |
---|
| 588 | + } else { |
---|
| 589 | + value = GMAC_PACKET_FILTER_PR | GMAC_PACKET_FILTER_PCF; |
---|
| 590 | + } |
---|
| 591 | + |
---|
412 | 592 | } else if ((dev->flags & IFF_ALLMULTI) || |
---|
413 | | - (netdev_mc_count(dev) > HASH_TABLE_SIZE)) { |
---|
| 593 | + (netdev_mc_count(dev) > hw->multicast_filter_bins)) { |
---|
414 | 594 | /* Pass all multi */ |
---|
415 | | - value = GMAC_PACKET_FILTER_PM; |
---|
416 | | - /* Set the 64 bits of the HASH tab. To be updated if taller |
---|
417 | | - * hash table is used |
---|
418 | | - */ |
---|
419 | | - writel(0xffffffff, ioaddr + GMAC_HASH_TAB_0_31); |
---|
420 | | - writel(0xffffffff, ioaddr + GMAC_HASH_TAB_32_63); |
---|
421 | | - } else if (!netdev_mc_empty(dev)) { |
---|
422 | | - u32 mc_filter[2]; |
---|
| 595 | + value |= GMAC_PACKET_FILTER_PM; |
---|
| 596 | + /* Set all the bits of the HASH tab */ |
---|
| 597 | + memset(mc_filter, 0xff, sizeof(mc_filter)); |
---|
| 598 | + } else if (!netdev_mc_empty(dev) && (dev->flags & IFF_MULTICAST)) { |
---|
423 | 599 | struct netdev_hw_addr *ha; |
---|
424 | 600 | |
---|
425 | 601 | /* Hash filter for multicast */ |
---|
426 | | - value = GMAC_PACKET_FILTER_HMC; |
---|
| 602 | + value |= GMAC_PACKET_FILTER_HMC; |
---|
427 | 603 | |
---|
428 | | - memset(mc_filter, 0, sizeof(mc_filter)); |
---|
429 | 604 | netdev_for_each_mc_addr(ha, dev) { |
---|
430 | | - /* The upper 6 bits of the calculated CRC are used to |
---|
431 | | - * index the content of the Hash Table Reg 0 and 1. |
---|
| 605 | + /* The upper n bits of the calculated CRC are used to |
---|
| 606 | + * index the contents of the hash table. The number of |
---|
| 607 | + * bits used depends on the hardware configuration |
---|
| 608 | + * selected at core configuration time. |
---|
432 | 609 | */ |
---|
433 | | - int bit_nr = |
---|
434 | | - (bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26); |
---|
435 | | - /* The most significant bit determines the register |
---|
436 | | - * to use while the other 5 bits determines the bit |
---|
437 | | - * within the selected register |
---|
| 610 | + u32 bit_nr = bitrev32(~crc32_le(~0, ha->addr, |
---|
| 611 | + ETH_ALEN)) >> (32 - mcbitslog2); |
---|
| 612 | + /* The most significant bit determines the register to |
---|
| 613 | + * use (H/L) while the other 5 bits determine the bit |
---|
| 614 | + * within the register. |
---|
438 | 615 | */ |
---|
439 | | - mc_filter[bit_nr >> 5] |= (1 << (bit_nr & 0x1F)); |
---|
| 616 | + mc_filter[bit_nr >> 5] |= (1 << (bit_nr & 0x1f)); |
---|
440 | 617 | } |
---|
441 | | - writel(mc_filter[0], ioaddr + GMAC_HASH_TAB_0_31); |
---|
442 | | - writel(mc_filter[1], ioaddr + GMAC_HASH_TAB_32_63); |
---|
443 | 618 | } |
---|
| 619 | + |
---|
| 620 | + for (i = 0; i < numhashregs; i++) |
---|
| 621 | + writel(mc_filter[i], ioaddr + GMAC_HASH_TAB(i)); |
---|
| 622 | + |
---|
| 623 | + value |= GMAC_PACKET_FILTER_HPF; |
---|
444 | 624 | |
---|
445 | 625 | /* Handle multiple unicast addresses */ |
---|
446 | 626 | if (netdev_uc_count(dev) > hw->unicast_filter_entries) { |
---|
.. | .. |
---|
457 | 637 | reg++; |
---|
458 | 638 | } |
---|
459 | 639 | |
---|
460 | | - while (reg <= GMAC_MAX_PERFECT_ADDRESSES) { |
---|
| 640 | + while (reg < GMAC_MAX_PERFECT_ADDRESSES) { |
---|
461 | 641 | writel(0, ioaddr + GMAC_ADDR_HIGH(reg)); |
---|
462 | 642 | writel(0, ioaddr + GMAC_ADDR_LOW(reg)); |
---|
463 | 643 | reg++; |
---|
464 | 644 | } |
---|
465 | 645 | } |
---|
| 646 | + |
---|
| 647 | + /* VLAN filtering */ |
---|
| 648 | + if (dev->flags & IFF_PROMISC && !hw->vlan_fail_q_en) |
---|
| 649 | + value &= ~GMAC_PACKET_FILTER_VTFE; |
---|
| 650 | + else if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) |
---|
| 651 | + value |= GMAC_PACKET_FILTER_VTFE; |
---|
466 | 652 | |
---|
467 | 653 | writel(value, ioaddr + GMAC_PACKET_FILTER); |
---|
468 | 654 | } |
---|
.. | .. |
---|
479 | 665 | if (fc & FLOW_RX) { |
---|
480 | 666 | pr_debug("\tReceive Flow-Control ON\n"); |
---|
481 | 667 | flow |= GMAC_RX_FLOW_CTRL_RFE; |
---|
| 668 | + } else { |
---|
| 669 | + pr_debug("\tReceive Flow-Control OFF\n"); |
---|
482 | 670 | } |
---|
483 | 671 | writel(flow, ioaddr + GMAC_RX_FLOW_CTRL); |
---|
484 | 672 | |
---|
.. | .. |
---|
715 | 903 | x->mac_gmii_rx_proto_engine++; |
---|
716 | 904 | } |
---|
717 | 905 | |
---|
| 906 | +static void dwmac4_set_mac_loopback(void __iomem *ioaddr, bool enable) |
---|
| 907 | +{ |
---|
| 908 | + u32 value = readl(ioaddr + GMAC_CONFIG); |
---|
| 909 | + |
---|
| 910 | + if (enable) |
---|
| 911 | + value |= GMAC_CONFIG_LM; |
---|
| 912 | + else |
---|
| 913 | + value &= ~GMAC_CONFIG_LM; |
---|
| 914 | + |
---|
| 915 | + writel(value, ioaddr + GMAC_CONFIG); |
---|
| 916 | +} |
---|
| 917 | + |
---|
| 918 | +static void dwmac4_update_vlan_hash(struct mac_device_info *hw, u32 hash, |
---|
| 919 | + __le16 perfect_match, bool is_double) |
---|
| 920 | +{ |
---|
| 921 | + void __iomem *ioaddr = hw->pcsr; |
---|
| 922 | + u32 value; |
---|
| 923 | + |
---|
| 924 | + writel(hash, ioaddr + GMAC_VLAN_HASH_TABLE); |
---|
| 925 | + |
---|
| 926 | + value = readl(ioaddr + GMAC_VLAN_TAG); |
---|
| 927 | + |
---|
| 928 | + if (hash) { |
---|
| 929 | + value |= GMAC_VLAN_VTHM | GMAC_VLAN_ETV; |
---|
| 930 | + if (is_double) { |
---|
| 931 | + value |= GMAC_VLAN_EDVLP; |
---|
| 932 | + value |= GMAC_VLAN_ESVL; |
---|
| 933 | + value |= GMAC_VLAN_DOVLTC; |
---|
| 934 | + } |
---|
| 935 | + |
---|
| 936 | + writel(value, ioaddr + GMAC_VLAN_TAG); |
---|
| 937 | + } else if (perfect_match) { |
---|
| 938 | + u32 value = GMAC_VLAN_ETV; |
---|
| 939 | + |
---|
| 940 | + if (is_double) { |
---|
| 941 | + value |= GMAC_VLAN_EDVLP; |
---|
| 942 | + value |= GMAC_VLAN_ESVL; |
---|
| 943 | + value |= GMAC_VLAN_DOVLTC; |
---|
| 944 | + } |
---|
| 945 | + |
---|
| 946 | + writel(value | perfect_match, ioaddr + GMAC_VLAN_TAG); |
---|
| 947 | + } else { |
---|
| 948 | + value &= ~(GMAC_VLAN_VTHM | GMAC_VLAN_ETV); |
---|
| 949 | + value &= ~(GMAC_VLAN_EDVLP | GMAC_VLAN_ESVL); |
---|
| 950 | + value &= ~GMAC_VLAN_DOVLTC; |
---|
| 951 | + value &= ~GMAC_VLAN_VID; |
---|
| 952 | + |
---|
| 953 | + writel(value, ioaddr + GMAC_VLAN_TAG); |
---|
| 954 | + } |
---|
| 955 | +} |
---|
| 956 | + |
---|
| 957 | +static void dwmac4_sarc_configure(void __iomem *ioaddr, int val) |
---|
| 958 | +{ |
---|
| 959 | + u32 value = readl(ioaddr + GMAC_CONFIG); |
---|
| 960 | + |
---|
| 961 | + value &= ~GMAC_CONFIG_SARC; |
---|
| 962 | + value |= val << GMAC_CONFIG_SARC_SHIFT; |
---|
| 963 | + |
---|
| 964 | + writel(value, ioaddr + GMAC_CONFIG); |
---|
| 965 | +} |
---|
| 966 | + |
---|
| 967 | +static void dwmac4_enable_vlan(struct mac_device_info *hw, u32 type) |
---|
| 968 | +{ |
---|
| 969 | + void __iomem *ioaddr = hw->pcsr; |
---|
| 970 | + u32 value; |
---|
| 971 | + |
---|
| 972 | + value = readl(ioaddr + GMAC_VLAN_INCL); |
---|
| 973 | + value |= GMAC_VLAN_VLTI; |
---|
| 974 | + value |= GMAC_VLAN_CSVL; /* Only use SVLAN */ |
---|
| 975 | + value &= ~GMAC_VLAN_VLC; |
---|
| 976 | + value |= (type << GMAC_VLAN_VLC_SHIFT) & GMAC_VLAN_VLC; |
---|
| 977 | + writel(value, ioaddr + GMAC_VLAN_INCL); |
---|
| 978 | +} |
---|
| 979 | + |
---|
| 980 | +static void dwmac4_set_arp_offload(struct mac_device_info *hw, bool en, |
---|
| 981 | + u32 addr) |
---|
| 982 | +{ |
---|
| 983 | + void __iomem *ioaddr = hw->pcsr; |
---|
| 984 | + u32 value; |
---|
| 985 | + |
---|
| 986 | + writel(addr, ioaddr + GMAC_ARP_ADDR); |
---|
| 987 | + |
---|
| 988 | + value = readl(ioaddr + GMAC_CONFIG); |
---|
| 989 | + if (en) |
---|
| 990 | + value |= GMAC_CONFIG_ARPEN; |
---|
| 991 | + else |
---|
| 992 | + value &= ~GMAC_CONFIG_ARPEN; |
---|
| 993 | + writel(value, ioaddr + GMAC_CONFIG); |
---|
| 994 | +} |
---|
| 995 | + |
---|
| 996 | +static int dwmac4_config_l3_filter(struct mac_device_info *hw, u32 filter_no, |
---|
| 997 | + bool en, bool ipv6, bool sa, bool inv, |
---|
| 998 | + u32 match) |
---|
| 999 | +{ |
---|
| 1000 | + void __iomem *ioaddr = hw->pcsr; |
---|
| 1001 | + u32 value; |
---|
| 1002 | + |
---|
| 1003 | + value = readl(ioaddr + GMAC_PACKET_FILTER); |
---|
| 1004 | + value |= GMAC_PACKET_FILTER_IPFE; |
---|
| 1005 | + writel(value, ioaddr + GMAC_PACKET_FILTER); |
---|
| 1006 | + |
---|
| 1007 | + value = readl(ioaddr + GMAC_L3L4_CTRL(filter_no)); |
---|
| 1008 | + |
---|
| 1009 | + /* For IPv6 not both SA/DA filters can be active */ |
---|
| 1010 | + if (ipv6) { |
---|
| 1011 | + value |= GMAC_L3PEN0; |
---|
| 1012 | + value &= ~(GMAC_L3SAM0 | GMAC_L3SAIM0); |
---|
| 1013 | + value &= ~(GMAC_L3DAM0 | GMAC_L3DAIM0); |
---|
| 1014 | + if (sa) { |
---|
| 1015 | + value |= GMAC_L3SAM0; |
---|
| 1016 | + if (inv) |
---|
| 1017 | + value |= GMAC_L3SAIM0; |
---|
| 1018 | + } else { |
---|
| 1019 | + value |= GMAC_L3DAM0; |
---|
| 1020 | + if (inv) |
---|
| 1021 | + value |= GMAC_L3DAIM0; |
---|
| 1022 | + } |
---|
| 1023 | + } else { |
---|
| 1024 | + value &= ~GMAC_L3PEN0; |
---|
| 1025 | + if (sa) { |
---|
| 1026 | + value |= GMAC_L3SAM0; |
---|
| 1027 | + if (inv) |
---|
| 1028 | + value |= GMAC_L3SAIM0; |
---|
| 1029 | + } else { |
---|
| 1030 | + value |= GMAC_L3DAM0; |
---|
| 1031 | + if (inv) |
---|
| 1032 | + value |= GMAC_L3DAIM0; |
---|
| 1033 | + } |
---|
| 1034 | + } |
---|
| 1035 | + |
---|
| 1036 | + writel(value, ioaddr + GMAC_L3L4_CTRL(filter_no)); |
---|
| 1037 | + |
---|
| 1038 | + if (sa) { |
---|
| 1039 | + writel(match, ioaddr + GMAC_L3_ADDR0(filter_no)); |
---|
| 1040 | + } else { |
---|
| 1041 | + writel(match, ioaddr + GMAC_L3_ADDR1(filter_no)); |
---|
| 1042 | + } |
---|
| 1043 | + |
---|
| 1044 | + if (!en) |
---|
| 1045 | + writel(0, ioaddr + GMAC_L3L4_CTRL(filter_no)); |
---|
| 1046 | + |
---|
| 1047 | + return 0; |
---|
| 1048 | +} |
---|
| 1049 | + |
---|
| 1050 | +static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no, |
---|
| 1051 | + bool en, bool udp, bool sa, bool inv, |
---|
| 1052 | + u32 match) |
---|
| 1053 | +{ |
---|
| 1054 | + void __iomem *ioaddr = hw->pcsr; |
---|
| 1055 | + u32 value; |
---|
| 1056 | + |
---|
| 1057 | + value = readl(ioaddr + GMAC_PACKET_FILTER); |
---|
| 1058 | + value |= GMAC_PACKET_FILTER_IPFE; |
---|
| 1059 | + writel(value, ioaddr + GMAC_PACKET_FILTER); |
---|
| 1060 | + |
---|
| 1061 | + value = readl(ioaddr + GMAC_L3L4_CTRL(filter_no)); |
---|
| 1062 | + if (udp) { |
---|
| 1063 | + value |= GMAC_L4PEN0; |
---|
| 1064 | + } else { |
---|
| 1065 | + value &= ~GMAC_L4PEN0; |
---|
| 1066 | + } |
---|
| 1067 | + |
---|
| 1068 | + value &= ~(GMAC_L4SPM0 | GMAC_L4SPIM0); |
---|
| 1069 | + value &= ~(GMAC_L4DPM0 | GMAC_L4DPIM0); |
---|
| 1070 | + if (sa) { |
---|
| 1071 | + value |= GMAC_L4SPM0; |
---|
| 1072 | + if (inv) |
---|
| 1073 | + value |= GMAC_L4SPIM0; |
---|
| 1074 | + } else { |
---|
| 1075 | + value |= GMAC_L4DPM0; |
---|
| 1076 | + if (inv) |
---|
| 1077 | + value |= GMAC_L4DPIM0; |
---|
| 1078 | + } |
---|
| 1079 | + |
---|
| 1080 | + writel(value, ioaddr + GMAC_L3L4_CTRL(filter_no)); |
---|
| 1081 | + |
---|
| 1082 | + if (sa) { |
---|
| 1083 | + value = match & GMAC_L4SP0; |
---|
| 1084 | + } else { |
---|
| 1085 | + value = (match << GMAC_L4DP0_SHIFT) & GMAC_L4DP0; |
---|
| 1086 | + } |
---|
| 1087 | + |
---|
| 1088 | + writel(value, ioaddr + GMAC_L4_ADDR(filter_no)); |
---|
| 1089 | + |
---|
| 1090 | + if (!en) |
---|
| 1091 | + writel(0, ioaddr + GMAC_L3L4_CTRL(filter_no)); |
---|
| 1092 | + |
---|
| 1093 | + return 0; |
---|
| 1094 | +} |
---|
| 1095 | + |
---|
| 1096 | +#ifdef CONFIG_STMMAC_FULL |
---|
718 | 1097 | const struct stmmac_ops dwmac4_ops = { |
---|
719 | 1098 | .core_init = dwmac4_core_init, |
---|
720 | 1099 | .set_mac = stmmac_set_mac, |
---|
.. | .. |
---|
744 | 1123 | .pcs_get_adv_lp = dwmac4_get_adv_lp, |
---|
745 | 1124 | .debug = dwmac4_debug, |
---|
746 | 1125 | .set_filter = dwmac4_set_filter, |
---|
| 1126 | + .set_mac_loopback = dwmac4_set_mac_loopback, |
---|
| 1127 | + .update_vlan_hash = dwmac4_update_vlan_hash, |
---|
| 1128 | + .sarc_configure = dwmac4_sarc_configure, |
---|
| 1129 | + .enable_vlan = dwmac4_enable_vlan, |
---|
| 1130 | + .set_arp_offload = dwmac4_set_arp_offload, |
---|
| 1131 | + .config_l3_filter = dwmac4_config_l3_filter, |
---|
| 1132 | + .config_l4_filter = dwmac4_config_l4_filter, |
---|
| 1133 | + .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, |
---|
| 1134 | + .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr, |
---|
| 1135 | + .restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr, |
---|
747 | 1136 | }; |
---|
| 1137 | +#endif |
---|
748 | 1138 | |
---|
749 | 1139 | const struct stmmac_ops dwmac410_ops = { |
---|
750 | 1140 | .core_init = dwmac4_core_init, |
---|
.. | .. |
---|
775 | 1165 | .pcs_get_adv_lp = dwmac4_get_adv_lp, |
---|
776 | 1166 | .debug = dwmac4_debug, |
---|
777 | 1167 | .set_filter = dwmac4_set_filter, |
---|
| 1168 | +#ifdef CONFIG_STMMAC_FULL |
---|
| 1169 | + .flex_pps_config = dwmac5_flex_pps_config, |
---|
| 1170 | +#endif |
---|
| 1171 | + .set_mac_loopback = dwmac4_set_mac_loopback, |
---|
| 1172 | + .update_vlan_hash = dwmac4_update_vlan_hash, |
---|
| 1173 | + .sarc_configure = dwmac4_sarc_configure, |
---|
| 1174 | + .enable_vlan = dwmac4_enable_vlan, |
---|
| 1175 | + .set_arp_offload = dwmac4_set_arp_offload, |
---|
| 1176 | + .config_l3_filter = dwmac4_config_l3_filter, |
---|
| 1177 | + .config_l4_filter = dwmac4_config_l4_filter, |
---|
| 1178 | +#ifdef CONFIG_STMMAC_FULL |
---|
| 1179 | + .est_configure = dwmac5_est_configure, |
---|
| 1180 | + .fpe_configure = dwmac5_fpe_configure, |
---|
| 1181 | +#endif |
---|
| 1182 | + .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, |
---|
| 1183 | + .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr, |
---|
| 1184 | + .restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr, |
---|
778 | 1185 | }; |
---|
779 | 1186 | |
---|
| 1187 | +#ifdef CONFIG_STMMAC_FULL |
---|
780 | 1188 | const struct stmmac_ops dwmac510_ops = { |
---|
781 | 1189 | .core_init = dwmac4_core_init, |
---|
782 | 1190 | .set_mac = stmmac_dwmac4_set_mac, |
---|
.. | .. |
---|
811 | 1219 | .safety_feat_dump = dwmac5_safety_feat_dump, |
---|
812 | 1220 | .rxp_config = dwmac5_rxp_config, |
---|
813 | 1221 | .flex_pps_config = dwmac5_flex_pps_config, |
---|
| 1222 | + .set_mac_loopback = dwmac4_set_mac_loopback, |
---|
| 1223 | + .update_vlan_hash = dwmac4_update_vlan_hash, |
---|
| 1224 | + .sarc_configure = dwmac4_sarc_configure, |
---|
| 1225 | + .enable_vlan = dwmac4_enable_vlan, |
---|
| 1226 | + .set_arp_offload = dwmac4_set_arp_offload, |
---|
| 1227 | + .config_l3_filter = dwmac4_config_l3_filter, |
---|
| 1228 | + .config_l4_filter = dwmac4_config_l4_filter, |
---|
| 1229 | + .est_configure = dwmac5_est_configure, |
---|
| 1230 | + .fpe_configure = dwmac5_fpe_configure, |
---|
| 1231 | + .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, |
---|
| 1232 | + .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr, |
---|
| 1233 | + .restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr, |
---|
814 | 1234 | }; |
---|
| 1235 | +#endif |
---|
| 1236 | + |
---|
| 1237 | +static u32 dwmac4_get_num_vlan(void __iomem *ioaddr) |
---|
| 1238 | +{ |
---|
| 1239 | + u32 val, num_vlan; |
---|
| 1240 | + |
---|
| 1241 | + val = readl(ioaddr + GMAC_HW_FEATURE3); |
---|
| 1242 | + switch (val & GMAC_HW_FEAT_NRVF) { |
---|
| 1243 | + case 0: |
---|
| 1244 | + num_vlan = 1; |
---|
| 1245 | + break; |
---|
| 1246 | + case 1: |
---|
| 1247 | + num_vlan = 4; |
---|
| 1248 | + break; |
---|
| 1249 | + case 2: |
---|
| 1250 | + num_vlan = 8; |
---|
| 1251 | + break; |
---|
| 1252 | + case 3: |
---|
| 1253 | + num_vlan = 16; |
---|
| 1254 | + break; |
---|
| 1255 | + case 4: |
---|
| 1256 | + num_vlan = 24; |
---|
| 1257 | + break; |
---|
| 1258 | + case 5: |
---|
| 1259 | + num_vlan = 32; |
---|
| 1260 | + break; |
---|
| 1261 | + default: |
---|
| 1262 | + num_vlan = 1; |
---|
| 1263 | + } |
---|
| 1264 | + |
---|
| 1265 | + return num_vlan; |
---|
| 1266 | +} |
---|
815 | 1267 | |
---|
816 | 1268 | int dwmac4_setup(struct stmmac_priv *priv) |
---|
817 | 1269 | { |
---|
.. | .. |
---|
841 | 1293 | mac->mii.reg_mask = GENMASK(20, 16); |
---|
842 | 1294 | mac->mii.clk_csr_shift = 8; |
---|
843 | 1295 | mac->mii.clk_csr_mask = GENMASK(11, 8); |
---|
| 1296 | + mac->num_vlan = dwmac4_get_num_vlan(priv->ioaddr); |
---|
844 | 1297 | |
---|
845 | 1298 | return 0; |
---|
846 | 1299 | } |
---|