| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Broadcom GENET (Gigabit Ethernet) controller driver |
|---|
| 3 | 4 | * |
|---|
| 4 | | - * Copyright (c) 2014-2017 Broadcom |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 8 | | - * published by the Free Software Foundation. |
|---|
| 5 | + * Copyright (c) 2014-2020 Broadcom |
|---|
| 9 | 6 | */ |
|---|
| 10 | 7 | |
|---|
| 11 | 8 | #define pr_fmt(fmt) "bcmgenet: " fmt |
|---|
| 12 | 9 | |
|---|
| 10 | +#include <linux/acpi.h> |
|---|
| 13 | 11 | #include <linux/kernel.h> |
|---|
| 14 | 12 | #include <linux/module.h> |
|---|
| 15 | 13 | #include <linux/sched.h> |
|---|
| .. | .. |
|---|
| 25 | 23 | #include <linux/dma-mapping.h> |
|---|
| 26 | 24 | #include <linux/pm.h> |
|---|
| 27 | 25 | #include <linux/clk.h> |
|---|
| 28 | | -#include <linux/of.h> |
|---|
| 29 | | -#include <linux/of_address.h> |
|---|
| 30 | | -#include <linux/of_irq.h> |
|---|
| 31 | | -#include <linux/of_net.h> |
|---|
| 32 | | -#include <linux/of_platform.h> |
|---|
| 33 | 26 | #include <net/arp.h> |
|---|
| 34 | 27 | |
|---|
| 35 | 28 | #include <linux/mii.h> |
|---|
| .. | .. |
|---|
| 98 | 91 | void __iomem *d, u32 value) |
|---|
| 99 | 92 | { |
|---|
| 100 | 93 | bcmgenet_writel(value, d + DMA_DESC_LENGTH_STATUS); |
|---|
| 101 | | -} |
|---|
| 102 | | - |
|---|
| 103 | | -static inline u32 dmadesc_get_length_status(struct bcmgenet_priv *priv, |
|---|
| 104 | | - void __iomem *d) |
|---|
| 105 | | -{ |
|---|
| 106 | | - return bcmgenet_readl(d + DMA_DESC_LENGTH_STATUS); |
|---|
| 107 | 94 | } |
|---|
| 108 | 95 | |
|---|
| 109 | 96 | static inline void dmadesc_set_addr(struct bcmgenet_priv *priv, |
|---|
| .. | .. |
|---|
| 472 | 459 | genet_dma_ring_regs[r]); |
|---|
| 473 | 460 | } |
|---|
| 474 | 461 | |
|---|
| 462 | +static void bcmgenet_hfb_enable_filter(struct bcmgenet_priv *priv, u32 f_index) |
|---|
| 463 | +{ |
|---|
| 464 | + u32 offset; |
|---|
| 465 | + u32 reg; |
|---|
| 466 | + |
|---|
| 467 | + offset = HFB_FLT_ENABLE_V3PLUS + (f_index < 32) * sizeof(u32); |
|---|
| 468 | + reg = bcmgenet_hfb_reg_readl(priv, offset); |
|---|
| 469 | + reg |= (1 << (f_index % 32)); |
|---|
| 470 | + bcmgenet_hfb_reg_writel(priv, reg, offset); |
|---|
| 471 | + reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL); |
|---|
| 472 | + reg |= RBUF_HFB_EN; |
|---|
| 473 | + bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL); |
|---|
| 474 | +} |
|---|
| 475 | + |
|---|
| 476 | +static void bcmgenet_hfb_disable_filter(struct bcmgenet_priv *priv, u32 f_index) |
|---|
| 477 | +{ |
|---|
| 478 | + u32 offset, reg, reg1; |
|---|
| 479 | + |
|---|
| 480 | + offset = HFB_FLT_ENABLE_V3PLUS; |
|---|
| 481 | + reg = bcmgenet_hfb_reg_readl(priv, offset); |
|---|
| 482 | + reg1 = bcmgenet_hfb_reg_readl(priv, offset + sizeof(u32)); |
|---|
| 483 | + if (f_index < 32) { |
|---|
| 484 | + reg1 &= ~(1 << (f_index % 32)); |
|---|
| 485 | + bcmgenet_hfb_reg_writel(priv, reg1, offset + sizeof(u32)); |
|---|
| 486 | + } else { |
|---|
| 487 | + reg &= ~(1 << (f_index % 32)); |
|---|
| 488 | + bcmgenet_hfb_reg_writel(priv, reg, offset); |
|---|
| 489 | + } |
|---|
| 490 | + if (!reg && !reg1) { |
|---|
| 491 | + reg = bcmgenet_hfb_reg_readl(priv, HFB_CTRL); |
|---|
| 492 | + reg &= ~RBUF_HFB_EN; |
|---|
| 493 | + bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL); |
|---|
| 494 | + } |
|---|
| 495 | +} |
|---|
| 496 | + |
|---|
| 497 | +static void bcmgenet_hfb_set_filter_rx_queue_mapping(struct bcmgenet_priv *priv, |
|---|
| 498 | + u32 f_index, u32 rx_queue) |
|---|
| 499 | +{ |
|---|
| 500 | + u32 offset; |
|---|
| 501 | + u32 reg; |
|---|
| 502 | + |
|---|
| 503 | + offset = f_index / 8; |
|---|
| 504 | + reg = bcmgenet_rdma_readl(priv, DMA_INDEX2RING_0 + offset); |
|---|
| 505 | + reg &= ~(0xF << (4 * (f_index % 8))); |
|---|
| 506 | + reg |= ((rx_queue & 0xF) << (4 * (f_index % 8))); |
|---|
| 507 | + bcmgenet_rdma_writel(priv, reg, DMA_INDEX2RING_0 + offset); |
|---|
| 508 | +} |
|---|
| 509 | + |
|---|
| 510 | +static void bcmgenet_hfb_set_filter_length(struct bcmgenet_priv *priv, |
|---|
| 511 | + u32 f_index, u32 f_length) |
|---|
| 512 | +{ |
|---|
| 513 | + u32 offset; |
|---|
| 514 | + u32 reg; |
|---|
| 515 | + |
|---|
| 516 | + offset = HFB_FLT_LEN_V3PLUS + |
|---|
| 517 | + ((priv->hw_params->hfb_filter_cnt - 1 - f_index) / 4) * |
|---|
| 518 | + sizeof(u32); |
|---|
| 519 | + reg = bcmgenet_hfb_reg_readl(priv, offset); |
|---|
| 520 | + reg &= ~(0xFF << (8 * (f_index % 4))); |
|---|
| 521 | + reg |= ((f_length & 0xFF) << (8 * (f_index % 4))); |
|---|
| 522 | + bcmgenet_hfb_reg_writel(priv, reg, offset); |
|---|
| 523 | +} |
|---|
| 524 | + |
|---|
| 525 | +static int bcmgenet_hfb_validate_mask(void *mask, size_t size) |
|---|
| 526 | +{ |
|---|
| 527 | + while (size) { |
|---|
| 528 | + switch (*(unsigned char *)mask++) { |
|---|
| 529 | + case 0x00: |
|---|
| 530 | + case 0x0f: |
|---|
| 531 | + case 0xf0: |
|---|
| 532 | + case 0xff: |
|---|
| 533 | + size--; |
|---|
| 534 | + continue; |
|---|
| 535 | + default: |
|---|
| 536 | + return -EINVAL; |
|---|
| 537 | + } |
|---|
| 538 | + } |
|---|
| 539 | + |
|---|
| 540 | + return 0; |
|---|
| 541 | +} |
|---|
| 542 | + |
|---|
| 543 | +#define VALIDATE_MASK(x) \ |
|---|
| 544 | + bcmgenet_hfb_validate_mask(&(x), sizeof(x)) |
|---|
| 545 | + |
|---|
| 546 | +static int bcmgenet_hfb_insert_data(struct bcmgenet_priv *priv, u32 f_index, |
|---|
| 547 | + u32 offset, void *val, void *mask, |
|---|
| 548 | + size_t size) |
|---|
| 549 | +{ |
|---|
| 550 | + u32 index, tmp; |
|---|
| 551 | + |
|---|
| 552 | + index = f_index * priv->hw_params->hfb_filter_size + offset / 2; |
|---|
| 553 | + tmp = bcmgenet_hfb_readl(priv, index * sizeof(u32)); |
|---|
| 554 | + |
|---|
| 555 | + while (size--) { |
|---|
| 556 | + if (offset++ & 1) { |
|---|
| 557 | + tmp &= ~0x300FF; |
|---|
| 558 | + tmp |= (*(unsigned char *)val++); |
|---|
| 559 | + switch ((*(unsigned char *)mask++)) { |
|---|
| 560 | + case 0xFF: |
|---|
| 561 | + tmp |= 0x30000; |
|---|
| 562 | + break; |
|---|
| 563 | + case 0xF0: |
|---|
| 564 | + tmp |= 0x20000; |
|---|
| 565 | + break; |
|---|
| 566 | + case 0x0F: |
|---|
| 567 | + tmp |= 0x10000; |
|---|
| 568 | + break; |
|---|
| 569 | + } |
|---|
| 570 | + bcmgenet_hfb_writel(priv, tmp, index++ * sizeof(u32)); |
|---|
| 571 | + if (size) |
|---|
| 572 | + tmp = bcmgenet_hfb_readl(priv, |
|---|
| 573 | + index * sizeof(u32)); |
|---|
| 574 | + } else { |
|---|
| 575 | + tmp &= ~0xCFF00; |
|---|
| 576 | + tmp |= (*(unsigned char *)val++) << 8; |
|---|
| 577 | + switch ((*(unsigned char *)mask++)) { |
|---|
| 578 | + case 0xFF: |
|---|
| 579 | + tmp |= 0xC0000; |
|---|
| 580 | + break; |
|---|
| 581 | + case 0xF0: |
|---|
| 582 | + tmp |= 0x80000; |
|---|
| 583 | + break; |
|---|
| 584 | + case 0x0F: |
|---|
| 585 | + tmp |= 0x40000; |
|---|
| 586 | + break; |
|---|
| 587 | + } |
|---|
| 588 | + if (!size) |
|---|
| 589 | + bcmgenet_hfb_writel(priv, tmp, index * sizeof(u32)); |
|---|
| 590 | + } |
|---|
| 591 | + } |
|---|
| 592 | + |
|---|
| 593 | + return 0; |
|---|
| 594 | +} |
|---|
| 595 | + |
|---|
| 596 | +static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv, |
|---|
| 597 | + struct bcmgenet_rxnfc_rule *rule) |
|---|
| 598 | +{ |
|---|
| 599 | + struct ethtool_rx_flow_spec *fs = &rule->fs; |
|---|
| 600 | + u32 offset = 0, f_length = 0, f; |
|---|
| 601 | + u8 val_8, mask_8; |
|---|
| 602 | + __be16 val_16; |
|---|
| 603 | + u16 mask_16; |
|---|
| 604 | + size_t size; |
|---|
| 605 | + |
|---|
| 606 | + f = fs->location; |
|---|
| 607 | + if (fs->flow_type & FLOW_MAC_EXT) { |
|---|
| 608 | + bcmgenet_hfb_insert_data(priv, f, 0, |
|---|
| 609 | + &fs->h_ext.h_dest, &fs->m_ext.h_dest, |
|---|
| 610 | + sizeof(fs->h_ext.h_dest)); |
|---|
| 611 | + } |
|---|
| 612 | + |
|---|
| 613 | + if (fs->flow_type & FLOW_EXT) { |
|---|
| 614 | + if (fs->m_ext.vlan_etype || |
|---|
| 615 | + fs->m_ext.vlan_tci) { |
|---|
| 616 | + bcmgenet_hfb_insert_data(priv, f, 12, |
|---|
| 617 | + &fs->h_ext.vlan_etype, |
|---|
| 618 | + &fs->m_ext.vlan_etype, |
|---|
| 619 | + sizeof(fs->h_ext.vlan_etype)); |
|---|
| 620 | + bcmgenet_hfb_insert_data(priv, f, 14, |
|---|
| 621 | + &fs->h_ext.vlan_tci, |
|---|
| 622 | + &fs->m_ext.vlan_tci, |
|---|
| 623 | + sizeof(fs->h_ext.vlan_tci)); |
|---|
| 624 | + offset += VLAN_HLEN; |
|---|
| 625 | + f_length += DIV_ROUND_UP(VLAN_HLEN, 2); |
|---|
| 626 | + } |
|---|
| 627 | + } |
|---|
| 628 | + |
|---|
| 629 | + switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { |
|---|
| 630 | + case ETHER_FLOW: |
|---|
| 631 | + f_length += DIV_ROUND_UP(ETH_HLEN, 2); |
|---|
| 632 | + bcmgenet_hfb_insert_data(priv, f, 0, |
|---|
| 633 | + &fs->h_u.ether_spec.h_dest, |
|---|
| 634 | + &fs->m_u.ether_spec.h_dest, |
|---|
| 635 | + sizeof(fs->h_u.ether_spec.h_dest)); |
|---|
| 636 | + bcmgenet_hfb_insert_data(priv, f, ETH_ALEN, |
|---|
| 637 | + &fs->h_u.ether_spec.h_source, |
|---|
| 638 | + &fs->m_u.ether_spec.h_source, |
|---|
| 639 | + sizeof(fs->h_u.ether_spec.h_source)); |
|---|
| 640 | + bcmgenet_hfb_insert_data(priv, f, (2 * ETH_ALEN) + offset, |
|---|
| 641 | + &fs->h_u.ether_spec.h_proto, |
|---|
| 642 | + &fs->m_u.ether_spec.h_proto, |
|---|
| 643 | + sizeof(fs->h_u.ether_spec.h_proto)); |
|---|
| 644 | + break; |
|---|
| 645 | + case IP_USER_FLOW: |
|---|
| 646 | + f_length += DIV_ROUND_UP(ETH_HLEN + 20, 2); |
|---|
| 647 | + /* Specify IP Ether Type */ |
|---|
| 648 | + val_16 = htons(ETH_P_IP); |
|---|
| 649 | + mask_16 = 0xFFFF; |
|---|
| 650 | + bcmgenet_hfb_insert_data(priv, f, (2 * ETH_ALEN) + offset, |
|---|
| 651 | + &val_16, &mask_16, sizeof(val_16)); |
|---|
| 652 | + bcmgenet_hfb_insert_data(priv, f, 15 + offset, |
|---|
| 653 | + &fs->h_u.usr_ip4_spec.tos, |
|---|
| 654 | + &fs->m_u.usr_ip4_spec.tos, |
|---|
| 655 | + sizeof(fs->h_u.usr_ip4_spec.tos)); |
|---|
| 656 | + bcmgenet_hfb_insert_data(priv, f, 23 + offset, |
|---|
| 657 | + &fs->h_u.usr_ip4_spec.proto, |
|---|
| 658 | + &fs->m_u.usr_ip4_spec.proto, |
|---|
| 659 | + sizeof(fs->h_u.usr_ip4_spec.proto)); |
|---|
| 660 | + bcmgenet_hfb_insert_data(priv, f, 26 + offset, |
|---|
| 661 | + &fs->h_u.usr_ip4_spec.ip4src, |
|---|
| 662 | + &fs->m_u.usr_ip4_spec.ip4src, |
|---|
| 663 | + sizeof(fs->h_u.usr_ip4_spec.ip4src)); |
|---|
| 664 | + bcmgenet_hfb_insert_data(priv, f, 30 + offset, |
|---|
| 665 | + &fs->h_u.usr_ip4_spec.ip4dst, |
|---|
| 666 | + &fs->m_u.usr_ip4_spec.ip4dst, |
|---|
| 667 | + sizeof(fs->h_u.usr_ip4_spec.ip4dst)); |
|---|
| 668 | + if (!fs->m_u.usr_ip4_spec.l4_4_bytes) |
|---|
| 669 | + break; |
|---|
| 670 | + |
|---|
| 671 | + /* Only supports 20 byte IPv4 header */ |
|---|
| 672 | + val_8 = 0x45; |
|---|
| 673 | + mask_8 = 0xFF; |
|---|
| 674 | + bcmgenet_hfb_insert_data(priv, f, ETH_HLEN + offset, |
|---|
| 675 | + &val_8, &mask_8, |
|---|
| 676 | + sizeof(val_8)); |
|---|
| 677 | + size = sizeof(fs->h_u.usr_ip4_spec.l4_4_bytes); |
|---|
| 678 | + bcmgenet_hfb_insert_data(priv, f, |
|---|
| 679 | + ETH_HLEN + 20 + offset, |
|---|
| 680 | + &fs->h_u.usr_ip4_spec.l4_4_bytes, |
|---|
| 681 | + &fs->m_u.usr_ip4_spec.l4_4_bytes, |
|---|
| 682 | + size); |
|---|
| 683 | + f_length += DIV_ROUND_UP(size, 2); |
|---|
| 684 | + break; |
|---|
| 685 | + } |
|---|
| 686 | + |
|---|
| 687 | + bcmgenet_hfb_set_filter_length(priv, f, 2 * f_length); |
|---|
| 688 | + if (!fs->ring_cookie || fs->ring_cookie == RX_CLS_FLOW_WAKE) { |
|---|
| 689 | + /* Ring 0 flows can be handled by the default Descriptor Ring |
|---|
| 690 | + * We'll map them to ring 0, but don't enable the filter |
|---|
| 691 | + */ |
|---|
| 692 | + bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, 0); |
|---|
| 693 | + rule->state = BCMGENET_RXNFC_STATE_DISABLED; |
|---|
| 694 | + } else { |
|---|
| 695 | + /* Other Rx rings are direct mapped here */ |
|---|
| 696 | + bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, |
|---|
| 697 | + fs->ring_cookie); |
|---|
| 698 | + bcmgenet_hfb_enable_filter(priv, f); |
|---|
| 699 | + rule->state = BCMGENET_RXNFC_STATE_ENABLED; |
|---|
| 700 | + } |
|---|
| 701 | +} |
|---|
| 702 | + |
|---|
| 703 | +/* bcmgenet_hfb_clear |
|---|
| 704 | + * |
|---|
| 705 | + * Clear Hardware Filter Block and disable all filtering. |
|---|
| 706 | + */ |
|---|
| 707 | +static void bcmgenet_hfb_clear_filter(struct bcmgenet_priv *priv, u32 f_index) |
|---|
| 708 | +{ |
|---|
| 709 | + u32 base, i; |
|---|
| 710 | + |
|---|
| 711 | + base = f_index * priv->hw_params->hfb_filter_size; |
|---|
| 712 | + for (i = 0; i < priv->hw_params->hfb_filter_size; i++) |
|---|
| 713 | + bcmgenet_hfb_writel(priv, 0x0, (base + i) * sizeof(u32)); |
|---|
| 714 | +} |
|---|
| 715 | + |
|---|
| 716 | +static void bcmgenet_hfb_clear(struct bcmgenet_priv *priv) |
|---|
| 717 | +{ |
|---|
| 718 | + u32 i; |
|---|
| 719 | + |
|---|
| 720 | + if (GENET_IS_V1(priv) || GENET_IS_V2(priv)) |
|---|
| 721 | + return; |
|---|
| 722 | + |
|---|
| 723 | + bcmgenet_hfb_reg_writel(priv, 0x0, HFB_CTRL); |
|---|
| 724 | + bcmgenet_hfb_reg_writel(priv, 0x0, HFB_FLT_ENABLE_V3PLUS); |
|---|
| 725 | + bcmgenet_hfb_reg_writel(priv, 0x0, HFB_FLT_ENABLE_V3PLUS + 4); |
|---|
| 726 | + |
|---|
| 727 | + for (i = DMA_INDEX2RING_0; i <= DMA_INDEX2RING_7; i++) |
|---|
| 728 | + bcmgenet_rdma_writel(priv, 0x0, i); |
|---|
| 729 | + |
|---|
| 730 | + for (i = 0; i < (priv->hw_params->hfb_filter_cnt / 4); i++) |
|---|
| 731 | + bcmgenet_hfb_reg_writel(priv, 0x0, |
|---|
| 732 | + HFB_FLT_LEN_V3PLUS + i * sizeof(u32)); |
|---|
| 733 | + |
|---|
| 734 | + for (i = 0; i < priv->hw_params->hfb_filter_cnt; i++) |
|---|
| 735 | + bcmgenet_hfb_clear_filter(priv, i); |
|---|
| 736 | +} |
|---|
| 737 | + |
|---|
| 738 | +static void bcmgenet_hfb_init(struct bcmgenet_priv *priv) |
|---|
| 739 | +{ |
|---|
| 740 | + int i; |
|---|
| 741 | + |
|---|
| 742 | + INIT_LIST_HEAD(&priv->rxnfc_list); |
|---|
| 743 | + if (GENET_IS_V1(priv) || GENET_IS_V2(priv)) |
|---|
| 744 | + return; |
|---|
| 745 | + |
|---|
| 746 | + for (i = 0; i < MAX_NUM_OF_FS_RULES; i++) { |
|---|
| 747 | + INIT_LIST_HEAD(&priv->rxnfc_rules[i].list); |
|---|
| 748 | + priv->rxnfc_rules[i].state = BCMGENET_RXNFC_STATE_UNUSED; |
|---|
| 749 | + } |
|---|
| 750 | + |
|---|
| 751 | + bcmgenet_hfb_clear(priv); |
|---|
| 752 | +} |
|---|
| 753 | + |
|---|
| 475 | 754 | static int bcmgenet_begin(struct net_device *dev) |
|---|
| 476 | 755 | { |
|---|
| 477 | 756 | struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| .. | .. |
|---|
| 514 | 793 | return phy_ethtool_ksettings_set(dev->phydev, cmd); |
|---|
| 515 | 794 | } |
|---|
| 516 | 795 | |
|---|
| 517 | | -static int bcmgenet_set_rx_csum(struct net_device *dev, |
|---|
| 518 | | - netdev_features_t wanted) |
|---|
| 519 | | -{ |
|---|
| 520 | | - struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 521 | | - u32 rbuf_chk_ctrl; |
|---|
| 522 | | - bool rx_csum_en; |
|---|
| 523 | | - |
|---|
| 524 | | - rx_csum_en = !!(wanted & NETIF_F_RXCSUM); |
|---|
| 525 | | - |
|---|
| 526 | | - rbuf_chk_ctrl = bcmgenet_rbuf_readl(priv, RBUF_CHK_CTRL); |
|---|
| 527 | | - |
|---|
| 528 | | - /* enable rx checksumming */ |
|---|
| 529 | | - if (rx_csum_en) |
|---|
| 530 | | - rbuf_chk_ctrl |= RBUF_RXCHK_EN; |
|---|
| 531 | | - else |
|---|
| 532 | | - rbuf_chk_ctrl &= ~RBUF_RXCHK_EN; |
|---|
| 533 | | - priv->desc_rxchk_en = rx_csum_en; |
|---|
| 534 | | - |
|---|
| 535 | | - /* If UniMAC forwards CRC, we need to skip over it to get |
|---|
| 536 | | - * a valid CHK bit to be set in the per-packet status word |
|---|
| 537 | | - */ |
|---|
| 538 | | - if (rx_csum_en && priv->crc_fwd_en) |
|---|
| 539 | | - rbuf_chk_ctrl |= RBUF_SKIP_FCS; |
|---|
| 540 | | - else |
|---|
| 541 | | - rbuf_chk_ctrl &= ~RBUF_SKIP_FCS; |
|---|
| 542 | | - |
|---|
| 543 | | - bcmgenet_rbuf_writel(priv, rbuf_chk_ctrl, RBUF_CHK_CTRL); |
|---|
| 544 | | - |
|---|
| 545 | | - return 0; |
|---|
| 546 | | -} |
|---|
| 547 | | - |
|---|
| 548 | | -static int bcmgenet_set_tx_csum(struct net_device *dev, |
|---|
| 549 | | - netdev_features_t wanted) |
|---|
| 550 | | -{ |
|---|
| 551 | | - struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 552 | | - bool desc_64b_en; |
|---|
| 553 | | - u32 tbuf_ctrl, rbuf_ctrl; |
|---|
| 554 | | - |
|---|
| 555 | | - tbuf_ctrl = bcmgenet_tbuf_ctrl_get(priv); |
|---|
| 556 | | - rbuf_ctrl = bcmgenet_rbuf_readl(priv, RBUF_CTRL); |
|---|
| 557 | | - |
|---|
| 558 | | - desc_64b_en = !!(wanted & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)); |
|---|
| 559 | | - |
|---|
| 560 | | - /* enable 64 bytes descriptor in both directions (RBUF and TBUF) */ |
|---|
| 561 | | - if (desc_64b_en) { |
|---|
| 562 | | - tbuf_ctrl |= RBUF_64B_EN; |
|---|
| 563 | | - rbuf_ctrl |= RBUF_64B_EN; |
|---|
| 564 | | - } else { |
|---|
| 565 | | - tbuf_ctrl &= ~RBUF_64B_EN; |
|---|
| 566 | | - rbuf_ctrl &= ~RBUF_64B_EN; |
|---|
| 567 | | - } |
|---|
| 568 | | - priv->desc_64b_en = desc_64b_en; |
|---|
| 569 | | - |
|---|
| 570 | | - bcmgenet_tbuf_ctrl_set(priv, tbuf_ctrl); |
|---|
| 571 | | - bcmgenet_rbuf_writel(priv, rbuf_ctrl, RBUF_CTRL); |
|---|
| 572 | | - |
|---|
| 573 | | - return 0; |
|---|
| 574 | | -} |
|---|
| 575 | | - |
|---|
| 576 | 796 | static int bcmgenet_set_features(struct net_device *dev, |
|---|
| 577 | 797 | netdev_features_t features) |
|---|
| 578 | 798 | { |
|---|
| 579 | | - netdev_features_t changed = features ^ dev->features; |
|---|
| 580 | | - netdev_features_t wanted = dev->wanted_features; |
|---|
| 581 | | - int ret = 0; |
|---|
| 799 | + struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 800 | + u32 reg; |
|---|
| 801 | + int ret; |
|---|
| 582 | 802 | |
|---|
| 583 | | - if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) |
|---|
| 584 | | - ret = bcmgenet_set_tx_csum(dev, wanted); |
|---|
| 585 | | - if (changed & (NETIF_F_RXCSUM)) |
|---|
| 586 | | - ret = bcmgenet_set_rx_csum(dev, wanted); |
|---|
| 803 | + ret = clk_prepare_enable(priv->clk); |
|---|
| 804 | + if (ret) |
|---|
| 805 | + return ret; |
|---|
| 806 | + |
|---|
| 807 | + /* Make sure we reflect the value of CRC_CMD_FWD */ |
|---|
| 808 | + reg = bcmgenet_umac_readl(priv, UMAC_CMD); |
|---|
| 809 | + priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); |
|---|
| 810 | + |
|---|
| 811 | + clk_disable_unprepare(priv->clk); |
|---|
| 587 | 812 | |
|---|
| 588 | 813 | return ret; |
|---|
| 589 | 814 | } |
|---|
| .. | .. |
|---|
| 646 | 871 | static void bcmgenet_set_ring_rx_coalesce(struct bcmgenet_rx_ring *ring, |
|---|
| 647 | 872 | struct ethtool_coalesce *ec) |
|---|
| 648 | 873 | { |
|---|
| 649 | | - struct net_dim_cq_moder moder; |
|---|
| 874 | + struct dim_cq_moder moder; |
|---|
| 650 | 875 | u32 usecs, pkts; |
|---|
| 651 | 876 | |
|---|
| 652 | 877 | ring->rx_coalesce_usecs = ec->rx_coalesce_usecs; |
|---|
| .. | .. |
|---|
| 687 | 912 | * always generate an interrupt either after MBDONE packets have been |
|---|
| 688 | 913 | * transmitted, or when the ring is empty. |
|---|
| 689 | 914 | */ |
|---|
| 690 | | - if (ec->tx_coalesce_usecs || ec->tx_coalesce_usecs_high || |
|---|
| 691 | | - ec->tx_coalesce_usecs_irq || ec->tx_coalesce_usecs_low || |
|---|
| 692 | | - ec->use_adaptive_tx_coalesce) |
|---|
| 693 | | - return -EOPNOTSUPP; |
|---|
| 694 | 915 | |
|---|
| 695 | 916 | /* Program all TX queues with the same values, as there is no |
|---|
| 696 | 917 | * ethtool knob to do coalescing on a per-queue basis |
|---|
| .. | .. |
|---|
| 863 | 1084 | STAT_GENET_SOFT_MIB("alloc_rx_buff_failed", mib.alloc_rx_buff_failed), |
|---|
| 864 | 1085 | STAT_GENET_SOFT_MIB("rx_dma_failed", mib.rx_dma_failed), |
|---|
| 865 | 1086 | STAT_GENET_SOFT_MIB("tx_dma_failed", mib.tx_dma_failed), |
|---|
| 1087 | + STAT_GENET_SOFT_MIB("tx_realloc_tsb", mib.tx_realloc_tsb), |
|---|
| 1088 | + STAT_GENET_SOFT_MIB("tx_realloc_tsb_failed", |
|---|
| 1089 | + mib.tx_realloc_tsb_failed), |
|---|
| 866 | 1090 | /* Per TX queues */ |
|---|
| 867 | 1091 | STAT_GENET_Q(0), |
|---|
| 868 | 1092 | STAT_GENET_Q(1), |
|---|
| .. | .. |
|---|
| 877 | 1101 | struct ethtool_drvinfo *info) |
|---|
| 878 | 1102 | { |
|---|
| 879 | 1103 | strlcpy(info->driver, "bcmgenet", sizeof(info->driver)); |
|---|
| 880 | | - strlcpy(info->version, "v2.0", sizeof(info->version)); |
|---|
| 881 | 1104 | } |
|---|
| 882 | 1105 | |
|---|
| 883 | 1106 | static int bcmgenet_get_sset_count(struct net_device *dev, int string_set) |
|---|
| .. | .. |
|---|
| 962 | 1185 | continue; |
|---|
| 963 | 1186 | case BCMGENET_STAT_RUNT: |
|---|
| 964 | 1187 | offset += BCMGENET_STAT_OFFSET; |
|---|
| 965 | | - /* fall through */ |
|---|
| 1188 | + fallthrough; |
|---|
| 966 | 1189 | case BCMGENET_STAT_MIB_TX: |
|---|
| 967 | 1190 | offset += BCMGENET_STAT_OFFSET; |
|---|
| 968 | | - /* fall through */ |
|---|
| 1191 | + fallthrough; |
|---|
| 969 | 1192 | case BCMGENET_STAT_MIB_RX: |
|---|
| 970 | 1193 | val = bcmgenet_umac_readl(priv, |
|---|
| 971 | 1194 | UMAC_MIB_START + j + offset); |
|---|
| .. | .. |
|---|
| 1112 | 1335 | return phy_ethtool_set_eee(dev->phydev, e); |
|---|
| 1113 | 1336 | } |
|---|
| 1114 | 1337 | |
|---|
| 1338 | +static int bcmgenet_validate_flow(struct net_device *dev, |
|---|
| 1339 | + struct ethtool_rxnfc *cmd) |
|---|
| 1340 | +{ |
|---|
| 1341 | + struct ethtool_usrip4_spec *l4_mask; |
|---|
| 1342 | + struct ethhdr *eth_mask; |
|---|
| 1343 | + |
|---|
| 1344 | + if (cmd->fs.location >= MAX_NUM_OF_FS_RULES) { |
|---|
| 1345 | + netdev_err(dev, "rxnfc: Invalid location (%d)\n", |
|---|
| 1346 | + cmd->fs.location); |
|---|
| 1347 | + return -EINVAL; |
|---|
| 1348 | + } |
|---|
| 1349 | + |
|---|
| 1350 | + switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { |
|---|
| 1351 | + case IP_USER_FLOW: |
|---|
| 1352 | + l4_mask = &cmd->fs.m_u.usr_ip4_spec; |
|---|
| 1353 | + /* don't allow mask which isn't valid */ |
|---|
| 1354 | + if (VALIDATE_MASK(l4_mask->ip4src) || |
|---|
| 1355 | + VALIDATE_MASK(l4_mask->ip4dst) || |
|---|
| 1356 | + VALIDATE_MASK(l4_mask->l4_4_bytes) || |
|---|
| 1357 | + VALIDATE_MASK(l4_mask->proto) || |
|---|
| 1358 | + VALIDATE_MASK(l4_mask->ip_ver) || |
|---|
| 1359 | + VALIDATE_MASK(l4_mask->tos)) { |
|---|
| 1360 | + netdev_err(dev, "rxnfc: Unsupported mask\n"); |
|---|
| 1361 | + return -EINVAL; |
|---|
| 1362 | + } |
|---|
| 1363 | + break; |
|---|
| 1364 | + case ETHER_FLOW: |
|---|
| 1365 | + eth_mask = &cmd->fs.m_u.ether_spec; |
|---|
| 1366 | + /* don't allow mask which isn't valid */ |
|---|
| 1367 | + if (VALIDATE_MASK(eth_mask->h_dest) || |
|---|
| 1368 | + VALIDATE_MASK(eth_mask->h_source) || |
|---|
| 1369 | + VALIDATE_MASK(eth_mask->h_proto)) { |
|---|
| 1370 | + netdev_err(dev, "rxnfc: Unsupported mask\n"); |
|---|
| 1371 | + return -EINVAL; |
|---|
| 1372 | + } |
|---|
| 1373 | + break; |
|---|
| 1374 | + default: |
|---|
| 1375 | + netdev_err(dev, "rxnfc: Unsupported flow type (0x%x)\n", |
|---|
| 1376 | + cmd->fs.flow_type); |
|---|
| 1377 | + return -EINVAL; |
|---|
| 1378 | + } |
|---|
| 1379 | + |
|---|
| 1380 | + if ((cmd->fs.flow_type & FLOW_EXT)) { |
|---|
| 1381 | + /* don't allow mask which isn't valid */ |
|---|
| 1382 | + if (VALIDATE_MASK(cmd->fs.m_ext.vlan_etype) || |
|---|
| 1383 | + VALIDATE_MASK(cmd->fs.m_ext.vlan_tci)) { |
|---|
| 1384 | + netdev_err(dev, "rxnfc: Unsupported mask\n"); |
|---|
| 1385 | + return -EINVAL; |
|---|
| 1386 | + } |
|---|
| 1387 | + if (cmd->fs.m_ext.data[0] || cmd->fs.m_ext.data[1]) { |
|---|
| 1388 | + netdev_err(dev, "rxnfc: user-def not supported\n"); |
|---|
| 1389 | + return -EINVAL; |
|---|
| 1390 | + } |
|---|
| 1391 | + } |
|---|
| 1392 | + |
|---|
| 1393 | + if ((cmd->fs.flow_type & FLOW_MAC_EXT)) { |
|---|
| 1394 | + /* don't allow mask which isn't valid */ |
|---|
| 1395 | + if (VALIDATE_MASK(cmd->fs.m_ext.h_dest)) { |
|---|
| 1396 | + netdev_err(dev, "rxnfc: Unsupported mask\n"); |
|---|
| 1397 | + return -EINVAL; |
|---|
| 1398 | + } |
|---|
| 1399 | + } |
|---|
| 1400 | + |
|---|
| 1401 | + return 0; |
|---|
| 1402 | +} |
|---|
| 1403 | + |
|---|
| 1404 | +static int bcmgenet_insert_flow(struct net_device *dev, |
|---|
| 1405 | + struct ethtool_rxnfc *cmd) |
|---|
| 1406 | +{ |
|---|
| 1407 | + struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 1408 | + struct bcmgenet_rxnfc_rule *loc_rule; |
|---|
| 1409 | + int err; |
|---|
| 1410 | + |
|---|
| 1411 | + if (priv->hw_params->hfb_filter_size < 128) { |
|---|
| 1412 | + netdev_err(dev, "rxnfc: Not supported by this device\n"); |
|---|
| 1413 | + return -EINVAL; |
|---|
| 1414 | + } |
|---|
| 1415 | + |
|---|
| 1416 | + if (cmd->fs.ring_cookie > priv->hw_params->rx_queues && |
|---|
| 1417 | + cmd->fs.ring_cookie != RX_CLS_FLOW_WAKE) { |
|---|
| 1418 | + netdev_err(dev, "rxnfc: Unsupported action (%llu)\n", |
|---|
| 1419 | + cmd->fs.ring_cookie); |
|---|
| 1420 | + return -EINVAL; |
|---|
| 1421 | + } |
|---|
| 1422 | + |
|---|
| 1423 | + err = bcmgenet_validate_flow(dev, cmd); |
|---|
| 1424 | + if (err) |
|---|
| 1425 | + return err; |
|---|
| 1426 | + |
|---|
| 1427 | + loc_rule = &priv->rxnfc_rules[cmd->fs.location]; |
|---|
| 1428 | + if (loc_rule->state == BCMGENET_RXNFC_STATE_ENABLED) |
|---|
| 1429 | + bcmgenet_hfb_disable_filter(priv, cmd->fs.location); |
|---|
| 1430 | + if (loc_rule->state != BCMGENET_RXNFC_STATE_UNUSED) { |
|---|
| 1431 | + list_del(&loc_rule->list); |
|---|
| 1432 | + bcmgenet_hfb_clear_filter(priv, cmd->fs.location); |
|---|
| 1433 | + } |
|---|
| 1434 | + loc_rule->state = BCMGENET_RXNFC_STATE_UNUSED; |
|---|
| 1435 | + memcpy(&loc_rule->fs, &cmd->fs, |
|---|
| 1436 | + sizeof(struct ethtool_rx_flow_spec)); |
|---|
| 1437 | + |
|---|
| 1438 | + bcmgenet_hfb_create_rxnfc_filter(priv, loc_rule); |
|---|
| 1439 | + |
|---|
| 1440 | + list_add_tail(&loc_rule->list, &priv->rxnfc_list); |
|---|
| 1441 | + |
|---|
| 1442 | + return 0; |
|---|
| 1443 | +} |
|---|
| 1444 | + |
|---|
| 1445 | +static int bcmgenet_delete_flow(struct net_device *dev, |
|---|
| 1446 | + struct ethtool_rxnfc *cmd) |
|---|
| 1447 | +{ |
|---|
| 1448 | + struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 1449 | + struct bcmgenet_rxnfc_rule *rule; |
|---|
| 1450 | + int err = 0; |
|---|
| 1451 | + |
|---|
| 1452 | + if (cmd->fs.location >= MAX_NUM_OF_FS_RULES) |
|---|
| 1453 | + return -EINVAL; |
|---|
| 1454 | + |
|---|
| 1455 | + rule = &priv->rxnfc_rules[cmd->fs.location]; |
|---|
| 1456 | + if (rule->state == BCMGENET_RXNFC_STATE_UNUSED) { |
|---|
| 1457 | + err = -ENOENT; |
|---|
| 1458 | + goto out; |
|---|
| 1459 | + } |
|---|
| 1460 | + |
|---|
| 1461 | + if (rule->state == BCMGENET_RXNFC_STATE_ENABLED) |
|---|
| 1462 | + bcmgenet_hfb_disable_filter(priv, cmd->fs.location); |
|---|
| 1463 | + if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) { |
|---|
| 1464 | + list_del(&rule->list); |
|---|
| 1465 | + bcmgenet_hfb_clear_filter(priv, cmd->fs.location); |
|---|
| 1466 | + } |
|---|
| 1467 | + rule->state = BCMGENET_RXNFC_STATE_UNUSED; |
|---|
| 1468 | + memset(&rule->fs, 0, sizeof(struct ethtool_rx_flow_spec)); |
|---|
| 1469 | + |
|---|
| 1470 | +out: |
|---|
| 1471 | + return err; |
|---|
| 1472 | +} |
|---|
| 1473 | + |
|---|
| 1474 | +static int bcmgenet_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) |
|---|
| 1475 | +{ |
|---|
| 1476 | + struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 1477 | + int err = 0; |
|---|
| 1478 | + |
|---|
| 1479 | + switch (cmd->cmd) { |
|---|
| 1480 | + case ETHTOOL_SRXCLSRLINS: |
|---|
| 1481 | + err = bcmgenet_insert_flow(dev, cmd); |
|---|
| 1482 | + break; |
|---|
| 1483 | + case ETHTOOL_SRXCLSRLDEL: |
|---|
| 1484 | + err = bcmgenet_delete_flow(dev, cmd); |
|---|
| 1485 | + break; |
|---|
| 1486 | + default: |
|---|
| 1487 | + netdev_warn(priv->dev, "Unsupported ethtool command. (%d)\n", |
|---|
| 1488 | + cmd->cmd); |
|---|
| 1489 | + return -EINVAL; |
|---|
| 1490 | + } |
|---|
| 1491 | + |
|---|
| 1492 | + return err; |
|---|
| 1493 | +} |
|---|
| 1494 | + |
|---|
| 1495 | +static int bcmgenet_get_flow(struct net_device *dev, struct ethtool_rxnfc *cmd, |
|---|
| 1496 | + int loc) |
|---|
| 1497 | +{ |
|---|
| 1498 | + struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 1499 | + struct bcmgenet_rxnfc_rule *rule; |
|---|
| 1500 | + int err = 0; |
|---|
| 1501 | + |
|---|
| 1502 | + if (loc < 0 || loc >= MAX_NUM_OF_FS_RULES) |
|---|
| 1503 | + return -EINVAL; |
|---|
| 1504 | + |
|---|
| 1505 | + rule = &priv->rxnfc_rules[loc]; |
|---|
| 1506 | + if (rule->state == BCMGENET_RXNFC_STATE_UNUSED) |
|---|
| 1507 | + err = -ENOENT; |
|---|
| 1508 | + else |
|---|
| 1509 | + memcpy(&cmd->fs, &rule->fs, |
|---|
| 1510 | + sizeof(struct ethtool_rx_flow_spec)); |
|---|
| 1511 | + |
|---|
| 1512 | + return err; |
|---|
| 1513 | +} |
|---|
| 1514 | + |
|---|
| 1515 | +static int bcmgenet_get_num_flows(struct bcmgenet_priv *priv) |
|---|
| 1516 | +{ |
|---|
| 1517 | + struct list_head *pos; |
|---|
| 1518 | + int res = 0; |
|---|
| 1519 | + |
|---|
| 1520 | + list_for_each(pos, &priv->rxnfc_list) |
|---|
| 1521 | + res++; |
|---|
| 1522 | + |
|---|
| 1523 | + return res; |
|---|
| 1524 | +} |
|---|
| 1525 | + |
|---|
| 1526 | +static int bcmgenet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, |
|---|
| 1527 | + u32 *rule_locs) |
|---|
| 1528 | +{ |
|---|
| 1529 | + struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 1530 | + struct bcmgenet_rxnfc_rule *rule; |
|---|
| 1531 | + int err = 0; |
|---|
| 1532 | + int i = 0; |
|---|
| 1533 | + |
|---|
| 1534 | + switch (cmd->cmd) { |
|---|
| 1535 | + case ETHTOOL_GRXRINGS: |
|---|
| 1536 | + cmd->data = priv->hw_params->rx_queues ?: 1; |
|---|
| 1537 | + break; |
|---|
| 1538 | + case ETHTOOL_GRXCLSRLCNT: |
|---|
| 1539 | + cmd->rule_cnt = bcmgenet_get_num_flows(priv); |
|---|
| 1540 | + cmd->data = MAX_NUM_OF_FS_RULES; |
|---|
| 1541 | + break; |
|---|
| 1542 | + case ETHTOOL_GRXCLSRULE: |
|---|
| 1543 | + err = bcmgenet_get_flow(dev, cmd, cmd->fs.location); |
|---|
| 1544 | + break; |
|---|
| 1545 | + case ETHTOOL_GRXCLSRLALL: |
|---|
| 1546 | + list_for_each_entry(rule, &priv->rxnfc_list, list) |
|---|
| 1547 | + if (i < cmd->rule_cnt) |
|---|
| 1548 | + rule_locs[i++] = rule->fs.location; |
|---|
| 1549 | + cmd->rule_cnt = i; |
|---|
| 1550 | + cmd->data = MAX_NUM_OF_FS_RULES; |
|---|
| 1551 | + break; |
|---|
| 1552 | + default: |
|---|
| 1553 | + err = -EOPNOTSUPP; |
|---|
| 1554 | + break; |
|---|
| 1555 | + } |
|---|
| 1556 | + |
|---|
| 1557 | + return err; |
|---|
| 1558 | +} |
|---|
| 1559 | + |
|---|
| 1115 | 1560 | /* standard ethtool support functions. */ |
|---|
| 1116 | 1561 | static const struct ethtool_ops bcmgenet_ethtool_ops = { |
|---|
| 1562 | + .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS | |
|---|
| 1563 | + ETHTOOL_COALESCE_MAX_FRAMES | |
|---|
| 1564 | + ETHTOOL_COALESCE_USE_ADAPTIVE_RX, |
|---|
| 1117 | 1565 | .begin = bcmgenet_begin, |
|---|
| 1118 | 1566 | .complete = bcmgenet_complete, |
|---|
| 1119 | 1567 | .get_strings = bcmgenet_get_strings, |
|---|
| .. | .. |
|---|
| 1132 | 1580 | .set_coalesce = bcmgenet_set_coalesce, |
|---|
| 1133 | 1581 | .get_link_ksettings = bcmgenet_get_link_ksettings, |
|---|
| 1134 | 1582 | .set_link_ksettings = bcmgenet_set_link_ksettings, |
|---|
| 1583 | + .get_ts_info = ethtool_op_get_ts_info, |
|---|
| 1584 | + .get_rxnfc = bcmgenet_get_rxnfc, |
|---|
| 1585 | + .set_rxnfc = bcmgenet_set_rxnfc, |
|---|
| 1135 | 1586 | }; |
|---|
| 1136 | 1587 | |
|---|
| 1137 | 1588 | /* Power down the unimac, based on mode. */ |
|---|
| .. | .. |
|---|
| 1224 | 1675 | default: |
|---|
| 1225 | 1676 | break; |
|---|
| 1226 | 1677 | } |
|---|
| 1227 | | -} |
|---|
| 1228 | | - |
|---|
| 1229 | | -/* ioctl handle special commands that are not present in ethtool. */ |
|---|
| 1230 | | -static int bcmgenet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
|---|
| 1231 | | -{ |
|---|
| 1232 | | - if (!netif_running(dev)) |
|---|
| 1233 | | - return -EINVAL; |
|---|
| 1234 | | - |
|---|
| 1235 | | - if (!dev->phydev) |
|---|
| 1236 | | - return -ENODEV; |
|---|
| 1237 | | - |
|---|
| 1238 | | - return phy_mii_ioctl(dev->phydev, rq, cmd); |
|---|
| 1239 | 1678 | } |
|---|
| 1240 | 1679 | |
|---|
| 1241 | 1680 | static struct enet_cb *bcmgenet_get_txcb(struct bcmgenet_priv *priv, |
|---|
| .. | .. |
|---|
| 1488 | 1927 | /* Reallocate the SKB to put enough headroom in front of it and insert |
|---|
| 1489 | 1928 | * the transmit checksum offsets in the descriptors |
|---|
| 1490 | 1929 | */ |
|---|
| 1491 | | -static struct sk_buff *bcmgenet_put_tx_csum(struct net_device *dev, |
|---|
| 1492 | | - struct sk_buff *skb) |
|---|
| 1930 | +static struct sk_buff *bcmgenet_add_tsb(struct net_device *dev, |
|---|
| 1931 | + struct sk_buff *skb) |
|---|
| 1493 | 1932 | { |
|---|
| 1933 | + struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 1494 | 1934 | struct status_64 *status = NULL; |
|---|
| 1495 | 1935 | struct sk_buff *new_skb; |
|---|
| 1496 | 1936 | u16 offset; |
|---|
| .. | .. |
|---|
| 1503 | 1943 | * enough headroom for us to insert 64B status block. |
|---|
| 1504 | 1944 | */ |
|---|
| 1505 | 1945 | new_skb = skb_realloc_headroom(skb, sizeof(*status)); |
|---|
| 1506 | | - dev_kfree_skb(skb); |
|---|
| 1507 | 1946 | if (!new_skb) { |
|---|
| 1947 | + dev_kfree_skb_any(skb); |
|---|
| 1948 | + priv->mib.tx_realloc_tsb_failed++; |
|---|
| 1508 | 1949 | dev->stats.tx_dropped++; |
|---|
| 1509 | 1950 | return NULL; |
|---|
| 1510 | 1951 | } |
|---|
| 1952 | + dev_consume_skb_any(skb); |
|---|
| 1511 | 1953 | skb = new_skb; |
|---|
| 1954 | + priv->mib.tx_realloc_tsb++; |
|---|
| 1512 | 1955 | } |
|---|
| 1513 | 1956 | |
|---|
| 1514 | 1957 | skb_push(skb, sizeof(*status)); |
|---|
| .. | .. |
|---|
| 1524 | 1967 | ip_proto = ipv6_hdr(skb)->nexthdr; |
|---|
| 1525 | 1968 | break; |
|---|
| 1526 | 1969 | default: |
|---|
| 1527 | | - return skb; |
|---|
| 1970 | + /* don't use UDP flag */ |
|---|
| 1971 | + ip_proto = 0; |
|---|
| 1972 | + break; |
|---|
| 1528 | 1973 | } |
|---|
| 1529 | 1974 | |
|---|
| 1530 | 1975 | offset = skb_checksum_start_offset(skb) - sizeof(*status); |
|---|
| 1531 | 1976 | tx_csum_info = (offset << STATUS_TX_CSUM_START_SHIFT) | |
|---|
| 1532 | | - (offset + skb->csum_offset); |
|---|
| 1977 | + (offset + skb->csum_offset) | |
|---|
| 1978 | + STATUS_TX_CSUM_LV; |
|---|
| 1533 | 1979 | |
|---|
| 1534 | | - /* Set the length valid bit for TCP and UDP and just set |
|---|
| 1535 | | - * the special UDP flag for IPv4, else just set to 0. |
|---|
| 1536 | | - */ |
|---|
| 1537 | | - if (ip_proto == IPPROTO_TCP || ip_proto == IPPROTO_UDP) { |
|---|
| 1538 | | - tx_csum_info |= STATUS_TX_CSUM_LV; |
|---|
| 1539 | | - if (ip_proto == IPPROTO_UDP && |
|---|
| 1540 | | - ip_ver == htons(ETH_P_IP)) |
|---|
| 1541 | | - tx_csum_info |= STATUS_TX_CSUM_PROTO_UDP; |
|---|
| 1542 | | - } else { |
|---|
| 1543 | | - tx_csum_info = 0; |
|---|
| 1544 | | - } |
|---|
| 1980 | + /* Set the special UDP flag for UDP */ |
|---|
| 1981 | + if (ip_proto == IPPROTO_UDP) |
|---|
| 1982 | + tx_csum_info |= STATUS_TX_CSUM_PROTO_UDP; |
|---|
| 1545 | 1983 | |
|---|
| 1546 | 1984 | status->tx_csum_info = tx_csum_info; |
|---|
| 1547 | 1985 | } |
|---|
| 1548 | 1986 | |
|---|
| 1549 | 1987 | return skb; |
|---|
| 1988 | +} |
|---|
| 1989 | + |
|---|
| 1990 | +static void bcmgenet_hide_tsb(struct sk_buff *skb) |
|---|
| 1991 | +{ |
|---|
| 1992 | + __skb_pull(skb, sizeof(struct status_64)); |
|---|
| 1550 | 1993 | } |
|---|
| 1551 | 1994 | |
|---|
| 1552 | 1995 | static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) |
|---|
| .. | .. |
|---|
| 1599 | 2042 | */ |
|---|
| 1600 | 2043 | GENET_CB(skb)->bytes_sent = skb->len; |
|---|
| 1601 | 2044 | |
|---|
| 1602 | | - /* set the SKB transmit checksum */ |
|---|
| 1603 | | - if (priv->desc_64b_en) { |
|---|
| 1604 | | - skb = bcmgenet_put_tx_csum(dev, skb); |
|---|
| 1605 | | - if (!skb) { |
|---|
| 1606 | | - ret = NETDEV_TX_OK; |
|---|
| 1607 | | - goto out; |
|---|
| 1608 | | - } |
|---|
| 2045 | + /* add the Transmit Status Block */ |
|---|
| 2046 | + skb = bcmgenet_add_tsb(dev, skb); |
|---|
| 2047 | + if (!skb) { |
|---|
| 2048 | + ret = NETDEV_TX_OK; |
|---|
| 2049 | + goto out; |
|---|
| 1609 | 2050 | } |
|---|
| 1610 | 2051 | |
|---|
| 1611 | 2052 | for (i = 0; i <= nr_frags; i++) { |
|---|
| .. | .. |
|---|
| 1657 | 2098 | } |
|---|
| 1658 | 2099 | |
|---|
| 1659 | 2100 | GENET_CB(skb)->last_cb = tx_cb_ptr; |
|---|
| 2101 | + |
|---|
| 2102 | + bcmgenet_hide_tsb(skb); |
|---|
| 1660 | 2103 | skb_tx_timestamp(skb); |
|---|
| 1661 | 2104 | |
|---|
| 1662 | 2105 | /* Decrement total BD count and advance our write pointer */ |
|---|
| .. | .. |
|---|
| 1669 | 2112 | if (ring->free_bds <= (MAX_SKB_FRAGS + 1)) |
|---|
| 1670 | 2113 | netif_tx_stop_queue(txq); |
|---|
| 1671 | 2114 | |
|---|
| 1672 | | - if (!skb->xmit_more || netif_xmit_stopped(txq)) |
|---|
| 2115 | + if (!netdev_xmit_more() || netif_xmit_stopped(txq)) |
|---|
| 1673 | 2116 | /* Packets are ready, update producer index */ |
|---|
| 1674 | 2117 | bcmgenet_tdma_ring_writel(priv, ring->index, |
|---|
| 1675 | 2118 | ring->prod_index, TDMA_PROD_INDEX); |
|---|
| .. | .. |
|---|
| 1751 | 2194 | unsigned int bytes_processed = 0; |
|---|
| 1752 | 2195 | unsigned int p_index, mask; |
|---|
| 1753 | 2196 | unsigned int discards; |
|---|
| 1754 | | - unsigned int chksum_ok = 0; |
|---|
| 1755 | 2197 | |
|---|
| 1756 | 2198 | /* Clear status before servicing to reduce spurious interrupts */ |
|---|
| 1757 | 2199 | if (ring->index == DESC_INDEX) { |
|---|
| .. | .. |
|---|
| 1789 | 2231 | |
|---|
| 1790 | 2232 | while ((rxpktprocessed < rxpkttoprocess) && |
|---|
| 1791 | 2233 | (rxpktprocessed < budget)) { |
|---|
| 2234 | + struct status_64 *status; |
|---|
| 2235 | + __be16 rx_csum; |
|---|
| 2236 | + |
|---|
| 1792 | 2237 | cb = &priv->rx_cbs[ring->read_ptr]; |
|---|
| 1793 | 2238 | skb = bcmgenet_rx_refill(priv, cb); |
|---|
| 1794 | 2239 | |
|---|
| .. | .. |
|---|
| 1797 | 2242 | goto next; |
|---|
| 1798 | 2243 | } |
|---|
| 1799 | 2244 | |
|---|
| 1800 | | - if (!priv->desc_64b_en) { |
|---|
| 1801 | | - dma_length_status = |
|---|
| 1802 | | - dmadesc_get_length_status(priv, cb->bd_addr); |
|---|
| 1803 | | - } else { |
|---|
| 1804 | | - struct status_64 *status; |
|---|
| 1805 | | - |
|---|
| 1806 | | - status = (struct status_64 *)skb->data; |
|---|
| 1807 | | - dma_length_status = status->length_status; |
|---|
| 2245 | + status = (struct status_64 *)skb->data; |
|---|
| 2246 | + dma_length_status = status->length_status; |
|---|
| 2247 | + if (dev->features & NETIF_F_RXCSUM) { |
|---|
| 2248 | + rx_csum = (__force __be16)(status->rx_csum & 0xffff); |
|---|
| 2249 | + if (rx_csum) { |
|---|
| 2250 | + skb->csum = (__force __wsum)ntohs(rx_csum); |
|---|
| 2251 | + skb->ip_summed = CHECKSUM_COMPLETE; |
|---|
| 2252 | + } |
|---|
| 1808 | 2253 | } |
|---|
| 1809 | 2254 | |
|---|
| 1810 | 2255 | /* DMA flags and length are still valid no matter how |
|---|
| .. | .. |
|---|
| 1817 | 2262 | "%s:p_ind=%d c_ind=%d read_ptr=%d len_stat=0x%08x\n", |
|---|
| 1818 | 2263 | __func__, p_index, ring->c_index, |
|---|
| 1819 | 2264 | ring->read_ptr, dma_length_status); |
|---|
| 2265 | + |
|---|
| 2266 | + if (unlikely(len > RX_BUF_LENGTH)) { |
|---|
| 2267 | + netif_err(priv, rx_status, dev, "oversized packet\n"); |
|---|
| 2268 | + dev->stats.rx_length_errors++; |
|---|
| 2269 | + dev->stats.rx_errors++; |
|---|
| 2270 | + dev_kfree_skb_any(skb); |
|---|
| 2271 | + goto next; |
|---|
| 2272 | + } |
|---|
| 1820 | 2273 | |
|---|
| 1821 | 2274 | if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) { |
|---|
| 1822 | 2275 | netif_err(priv, rx_status, dev, |
|---|
| .. | .. |
|---|
| 1847 | 2300 | goto next; |
|---|
| 1848 | 2301 | } /* error packet */ |
|---|
| 1849 | 2302 | |
|---|
| 1850 | | - chksum_ok = (dma_flag & priv->dma_rx_chk_bit) && |
|---|
| 1851 | | - priv->desc_rxchk_en; |
|---|
| 1852 | | - |
|---|
| 1853 | 2303 | skb_put(skb, len); |
|---|
| 1854 | | - if (priv->desc_64b_en) { |
|---|
| 1855 | | - skb_pull(skb, 64); |
|---|
| 1856 | | - len -= 64; |
|---|
| 1857 | | - } |
|---|
| 1858 | 2304 | |
|---|
| 1859 | | - if (likely(chksum_ok)) |
|---|
| 1860 | | - skb->ip_summed = CHECKSUM_UNNECESSARY; |
|---|
| 1861 | | - |
|---|
| 1862 | | - /* remove hardware 2bytes added for IP alignment */ |
|---|
| 1863 | | - skb_pull(skb, 2); |
|---|
| 1864 | | - len -= 2; |
|---|
| 2305 | + /* remove RSB and hardware 2bytes added for IP alignment */ |
|---|
| 2306 | + skb_pull(skb, 66); |
|---|
| 2307 | + len -= 66; |
|---|
| 1865 | 2308 | |
|---|
| 1866 | 2309 | if (priv->crc_fwd_en) { |
|---|
| 1867 | 2310 | skb_trim(skb, len - ETH_FCS_LEN); |
|---|
| .. | .. |
|---|
| 1903 | 2346 | { |
|---|
| 1904 | 2347 | struct bcmgenet_rx_ring *ring = container_of(napi, |
|---|
| 1905 | 2348 | struct bcmgenet_rx_ring, napi); |
|---|
| 1906 | | - struct net_dim_sample dim_sample; |
|---|
| 2349 | + struct dim_sample dim_sample = {}; |
|---|
| 1907 | 2350 | unsigned int work_done; |
|---|
| 1908 | 2351 | |
|---|
| 1909 | 2352 | work_done = bcmgenet_desc_rx(ring, budget); |
|---|
| .. | .. |
|---|
| 1914 | 2357 | } |
|---|
| 1915 | 2358 | |
|---|
| 1916 | 2359 | if (ring->dim.use_dim) { |
|---|
| 1917 | | - net_dim_sample(ring->dim.event_ctr, ring->dim.packets, |
|---|
| 1918 | | - ring->dim.bytes, &dim_sample); |
|---|
| 2360 | + dim_update_sample(ring->dim.event_ctr, ring->dim.packets, |
|---|
| 2361 | + ring->dim.bytes, &dim_sample); |
|---|
| 1919 | 2362 | net_dim(&ring->dim.dim, dim_sample); |
|---|
| 1920 | 2363 | } |
|---|
| 1921 | 2364 | |
|---|
| .. | .. |
|---|
| 1924 | 2367 | |
|---|
| 1925 | 2368 | static void bcmgenet_dim_work(struct work_struct *work) |
|---|
| 1926 | 2369 | { |
|---|
| 1927 | | - struct net_dim *dim = container_of(work, struct net_dim, work); |
|---|
| 2370 | + struct dim *dim = container_of(work, struct dim, work); |
|---|
| 1928 | 2371 | struct bcmgenet_net_dim *ndim = |
|---|
| 1929 | 2372 | container_of(dim, struct bcmgenet_net_dim, dim); |
|---|
| 1930 | 2373 | struct bcmgenet_rx_ring *ring = |
|---|
| 1931 | 2374 | container_of(ndim, struct bcmgenet_rx_ring, dim); |
|---|
| 1932 | | - struct net_dim_cq_moder cur_profile = |
|---|
| 2375 | + struct dim_cq_moder cur_profile = |
|---|
| 1933 | 2376 | net_dim_get_rx_moderation(dim->mode, dim->profile_ix); |
|---|
| 1934 | 2377 | |
|---|
| 1935 | 2378 | bcmgenet_set_rx_coalesce(ring, cur_profile.usec, cur_profile.pkts); |
|---|
| 1936 | | - dim->state = NET_DIM_START_MEASURE; |
|---|
| 2379 | + dim->state = DIM_START_MEASURE; |
|---|
| 1937 | 2380 | } |
|---|
| 1938 | 2381 | |
|---|
| 1939 | 2382 | /* Assign skb to RX DMA descriptor. */ |
|---|
| .. | .. |
|---|
| 1979 | 2422 | u32 reg; |
|---|
| 1980 | 2423 | |
|---|
| 1981 | 2424 | reg = bcmgenet_umac_readl(priv, UMAC_CMD); |
|---|
| 2425 | + if (reg & CMD_SW_RESET) |
|---|
| 2426 | + return; |
|---|
| 1982 | 2427 | if (enable) |
|---|
| 1983 | 2428 | reg |= mask; |
|---|
| 1984 | 2429 | else |
|---|
| .. | .. |
|---|
| 1998 | 2443 | bcmgenet_rbuf_ctrl_set(priv, 0); |
|---|
| 1999 | 2444 | udelay(10); |
|---|
| 2000 | 2445 | |
|---|
| 2001 | | - /* disable MAC while updating its registers */ |
|---|
| 2002 | | - bcmgenet_umac_writel(priv, 0, UMAC_CMD); |
|---|
| 2003 | | - |
|---|
| 2004 | | - /* issue soft reset with (rg)mii loopback to ensure a stable rxclk */ |
|---|
| 2005 | | - bcmgenet_umac_writel(priv, CMD_SW_RESET | CMD_LCL_LOOP_EN, UMAC_CMD); |
|---|
| 2446 | + /* issue soft reset and disable MAC while updating its registers */ |
|---|
| 2447 | + bcmgenet_umac_writel(priv, CMD_SW_RESET, UMAC_CMD); |
|---|
| 2448 | + udelay(2); |
|---|
| 2006 | 2449 | } |
|---|
| 2007 | 2450 | |
|---|
| 2008 | 2451 | static void bcmgenet_intr_disable(struct bcmgenet_priv *priv) |
|---|
| .. | .. |
|---|
| 2052 | 2495 | |
|---|
| 2053 | 2496 | bcmgenet_umac_writel(priv, ENET_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN); |
|---|
| 2054 | 2497 | |
|---|
| 2055 | | - /* init rx registers, enable ip header optimization */ |
|---|
| 2498 | + /* init tx registers, enable TSB */ |
|---|
| 2499 | + reg = bcmgenet_tbuf_ctrl_get(priv); |
|---|
| 2500 | + reg |= TBUF_64B_EN; |
|---|
| 2501 | + bcmgenet_tbuf_ctrl_set(priv, reg); |
|---|
| 2502 | + |
|---|
| 2503 | + /* init rx registers, enable ip header optimization and RSB */ |
|---|
| 2056 | 2504 | reg = bcmgenet_rbuf_readl(priv, RBUF_CTRL); |
|---|
| 2057 | | - reg |= RBUF_ALIGN_2B; |
|---|
| 2505 | + reg |= RBUF_ALIGN_2B | RBUF_64B_EN; |
|---|
| 2058 | 2506 | bcmgenet_rbuf_writel(priv, reg, RBUF_CTRL); |
|---|
| 2507 | + |
|---|
| 2508 | + /* enable rx checksumming */ |
|---|
| 2509 | + reg = bcmgenet_rbuf_readl(priv, RBUF_CHK_CTRL); |
|---|
| 2510 | + reg |= RBUF_RXCHK_EN | RBUF_L3_PARSE_DIS; |
|---|
| 2511 | + /* If UniMAC forwards CRC, we need to skip over it to get |
|---|
| 2512 | + * a valid CHK bit to be set in the per-packet status word |
|---|
| 2513 | + */ |
|---|
| 2514 | + if (priv->crc_fwd_en) |
|---|
| 2515 | + reg |= RBUF_SKIP_FCS; |
|---|
| 2516 | + else |
|---|
| 2517 | + reg &= ~RBUF_SKIP_FCS; |
|---|
| 2518 | + bcmgenet_rbuf_writel(priv, reg, RBUF_CHK_CTRL); |
|---|
| 2059 | 2519 | |
|---|
| 2060 | 2520 | if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv)) |
|---|
| 2061 | 2521 | bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL); |
|---|
| .. | .. |
|---|
| 2090 | 2550 | struct bcmgenet_net_dim *dim = &ring->dim; |
|---|
| 2091 | 2551 | |
|---|
| 2092 | 2552 | INIT_WORK(&dim->dim.work, cb); |
|---|
| 2093 | | - dim->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE; |
|---|
| 2553 | + dim->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; |
|---|
| 2094 | 2554 | dim->event_ctr = 0; |
|---|
| 2095 | 2555 | dim->packets = 0; |
|---|
| 2096 | 2556 | dim->bytes = 0; |
|---|
| .. | .. |
|---|
| 2099 | 2559 | static void bcmgenet_init_rx_coalesce(struct bcmgenet_rx_ring *ring) |
|---|
| 2100 | 2560 | { |
|---|
| 2101 | 2561 | struct bcmgenet_net_dim *dim = &ring->dim; |
|---|
| 2102 | | - struct net_dim_cq_moder moder; |
|---|
| 2562 | + struct dim_cq_moder moder; |
|---|
| 2103 | 2563 | u32 usecs, pkts; |
|---|
| 2104 | 2564 | |
|---|
| 2105 | 2565 | usecs = ring->rx_coalesce_usecs; |
|---|
| .. | .. |
|---|
| 2523 | 2983 | static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) |
|---|
| 2524 | 2984 | { |
|---|
| 2525 | 2985 | struct netdev_queue *txq; |
|---|
| 2526 | | - struct sk_buff *skb; |
|---|
| 2527 | | - struct enet_cb *cb; |
|---|
| 2528 | 2986 | int i; |
|---|
| 2529 | 2987 | |
|---|
| 2530 | 2988 | bcmgenet_fini_rx_napi(priv); |
|---|
| 2531 | 2989 | bcmgenet_fini_tx_napi(priv); |
|---|
| 2532 | 2990 | |
|---|
| 2533 | | - for (i = 0; i < priv->num_tx_bds; i++) { |
|---|
| 2534 | | - cb = priv->tx_cbs + i; |
|---|
| 2535 | | - skb = bcmgenet_free_tx_cb(&priv->pdev->dev, cb); |
|---|
| 2536 | | - if (skb) |
|---|
| 2537 | | - dev_kfree_skb(skb); |
|---|
| 2538 | | - } |
|---|
| 2991 | + for (i = 0; i < priv->num_tx_bds; i++) |
|---|
| 2992 | + dev_kfree_skb(bcmgenet_free_tx_cb(&priv->pdev->dev, |
|---|
| 2993 | + priv->tx_cbs + i)); |
|---|
| 2539 | 2994 | |
|---|
| 2540 | 2995 | for (i = 0; i < priv->hw_params->tx_queues; i++) { |
|---|
| 2541 | 2996 | txq = netdev_get_tx_queue(priv->dev, priv->tx_rings[i].queue); |
|---|
| .. | .. |
|---|
| 2588 | 3043 | } |
|---|
| 2589 | 3044 | |
|---|
| 2590 | 3045 | /* Init rDma */ |
|---|
| 2591 | | - bcmgenet_rdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE); |
|---|
| 3046 | + bcmgenet_rdma_writel(priv, priv->dma_max_burst_length, |
|---|
| 3047 | + DMA_SCB_BURST_SIZE); |
|---|
| 2592 | 3048 | |
|---|
| 2593 | 3049 | /* Initialize Rx queues */ |
|---|
| 2594 | 3050 | ret = bcmgenet_init_rx_queues(priv->dev); |
|---|
| .. | .. |
|---|
| 2601 | 3057 | } |
|---|
| 2602 | 3058 | |
|---|
| 2603 | 3059 | /* Init tDma */ |
|---|
| 2604 | | - bcmgenet_tdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE); |
|---|
| 3060 | + bcmgenet_tdma_writel(priv, priv->dma_max_burst_length, |
|---|
| 3061 | + DMA_SCB_BURST_SIZE); |
|---|
| 2605 | 3062 | |
|---|
| 2606 | 3063 | /* Initialize Tx queues */ |
|---|
| 2607 | 3064 | bcmgenet_init_tx_queues(priv->dev); |
|---|
| .. | .. |
|---|
| 2742 | 3199 | |
|---|
| 2743 | 3200 | static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id) |
|---|
| 2744 | 3201 | { |
|---|
| 2745 | | - struct bcmgenet_priv *priv = dev_id; |
|---|
| 2746 | | - |
|---|
| 2747 | | - pm_wakeup_event(&priv->pdev->dev, 0); |
|---|
| 2748 | | - |
|---|
| 3202 | + /* Acknowledge the interrupt */ |
|---|
| 2749 | 3203 | return IRQ_HANDLED; |
|---|
| 2750 | 3204 | } |
|---|
| 2751 | 3205 | |
|---|
| .. | .. |
|---|
| 2783 | 3237 | static void bcmgenet_set_hw_addr(struct bcmgenet_priv *priv, |
|---|
| 2784 | 3238 | unsigned char *addr) |
|---|
| 2785 | 3239 | { |
|---|
| 2786 | | - bcmgenet_umac_writel(priv, (addr[0] << 24) | (addr[1] << 16) | |
|---|
| 2787 | | - (addr[2] << 8) | addr[3], UMAC_MAC0); |
|---|
| 2788 | | - bcmgenet_umac_writel(priv, (addr[4] << 8) | addr[5], UMAC_MAC1); |
|---|
| 3240 | + bcmgenet_umac_writel(priv, get_unaligned_be32(&addr[0]), UMAC_MAC0); |
|---|
| 3241 | + bcmgenet_umac_writel(priv, get_unaligned_be16(&addr[4]), UMAC_MAC1); |
|---|
| 3242 | +} |
|---|
| 3243 | + |
|---|
| 3244 | +static void bcmgenet_get_hw_addr(struct bcmgenet_priv *priv, |
|---|
| 3245 | + unsigned char *addr) |
|---|
| 3246 | +{ |
|---|
| 3247 | + u32 addr_tmp; |
|---|
| 3248 | + |
|---|
| 3249 | + addr_tmp = bcmgenet_umac_readl(priv, UMAC_MAC0); |
|---|
| 3250 | + put_unaligned_be32(addr_tmp, &addr[0]); |
|---|
| 3251 | + addr_tmp = bcmgenet_umac_readl(priv, UMAC_MAC1); |
|---|
| 3252 | + put_unaligned_be16(addr_tmp, &addr[4]); |
|---|
| 2789 | 3253 | } |
|---|
| 2790 | 3254 | |
|---|
| 2791 | 3255 | /* Returns a reusable dma control register value */ |
|---|
| .. | .. |
|---|
| 2830 | 3294 | bcmgenet_tdma_writel(priv, reg, DMA_CTRL); |
|---|
| 2831 | 3295 | } |
|---|
| 2832 | 3296 | |
|---|
| 2833 | | -/* bcmgenet_hfb_clear |
|---|
| 2834 | | - * |
|---|
| 2835 | | - * Clear Hardware Filter Block and disable all filtering. |
|---|
| 2836 | | - */ |
|---|
| 2837 | | -static void bcmgenet_hfb_clear(struct bcmgenet_priv *priv) |
|---|
| 2838 | | -{ |
|---|
| 2839 | | - u32 i; |
|---|
| 2840 | | - |
|---|
| 2841 | | - bcmgenet_hfb_reg_writel(priv, 0x0, HFB_CTRL); |
|---|
| 2842 | | - bcmgenet_hfb_reg_writel(priv, 0x0, HFB_FLT_ENABLE_V3PLUS); |
|---|
| 2843 | | - bcmgenet_hfb_reg_writel(priv, 0x0, HFB_FLT_ENABLE_V3PLUS + 4); |
|---|
| 2844 | | - |
|---|
| 2845 | | - for (i = DMA_INDEX2RING_0; i <= DMA_INDEX2RING_7; i++) |
|---|
| 2846 | | - bcmgenet_rdma_writel(priv, 0x0, i); |
|---|
| 2847 | | - |
|---|
| 2848 | | - for (i = 0; i < (priv->hw_params->hfb_filter_cnt / 4); i++) |
|---|
| 2849 | | - bcmgenet_hfb_reg_writel(priv, 0x0, |
|---|
| 2850 | | - HFB_FLT_LEN_V3PLUS + i * sizeof(u32)); |
|---|
| 2851 | | - |
|---|
| 2852 | | - for (i = 0; i < priv->hw_params->hfb_filter_cnt * |
|---|
| 2853 | | - priv->hw_params->hfb_filter_size; i++) |
|---|
| 2854 | | - bcmgenet_hfb_writel(priv, 0x0, i * sizeof(u32)); |
|---|
| 2855 | | -} |
|---|
| 2856 | | - |
|---|
| 2857 | | -static void bcmgenet_hfb_init(struct bcmgenet_priv *priv) |
|---|
| 2858 | | -{ |
|---|
| 2859 | | - if (GENET_IS_V1(priv) || GENET_IS_V2(priv)) |
|---|
| 2860 | | - return; |
|---|
| 2861 | | - |
|---|
| 2862 | | - bcmgenet_hfb_clear(priv); |
|---|
| 2863 | | -} |
|---|
| 2864 | | - |
|---|
| 2865 | 3297 | static void bcmgenet_netif_start(struct net_device *dev) |
|---|
| 2866 | 3298 | { |
|---|
| 2867 | 3299 | struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| .. | .. |
|---|
| 2884 | 3316 | { |
|---|
| 2885 | 3317 | struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 2886 | 3318 | unsigned long dma_ctrl; |
|---|
| 2887 | | - u32 reg; |
|---|
| 2888 | 3319 | int ret; |
|---|
| 2889 | 3320 | |
|---|
| 2890 | 3321 | netif_dbg(priv, ifup, dev, "bcmgenet_open\n"); |
|---|
| .. | .. |
|---|
| 2903 | 3334 | |
|---|
| 2904 | 3335 | init_umac(priv); |
|---|
| 2905 | 3336 | |
|---|
| 2906 | | - /* Make sure we reflect the value of CRC_CMD_FWD */ |
|---|
| 2907 | | - reg = bcmgenet_umac_readl(priv, UMAC_CMD); |
|---|
| 2908 | | - priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); |
|---|
| 3337 | + /* Apply features again in case we changed them while interface was |
|---|
| 3338 | + * down |
|---|
| 3339 | + */ |
|---|
| 3340 | + bcmgenet_set_features(dev, dev->features); |
|---|
| 2909 | 3341 | |
|---|
| 2910 | 3342 | bcmgenet_set_hw_addr(priv, dev->dev_addr); |
|---|
| 2911 | 3343 | |
|---|
| .. | .. |
|---|
| 2965 | 3397 | return ret; |
|---|
| 2966 | 3398 | } |
|---|
| 2967 | 3399 | |
|---|
| 2968 | | -static void bcmgenet_netif_stop(struct net_device *dev) |
|---|
| 3400 | +static void bcmgenet_netif_stop(struct net_device *dev, bool stop_phy) |
|---|
| 2969 | 3401 | { |
|---|
| 2970 | 3402 | struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 2971 | 3403 | |
|---|
| .. | .. |
|---|
| 2980 | 3412 | /* Disable MAC transmit. TX DMA disabled must be done before this */ |
|---|
| 2981 | 3413 | umac_enable_set(priv, CMD_TX_EN, false); |
|---|
| 2982 | 3414 | |
|---|
| 2983 | | - phy_stop(dev->phydev); |
|---|
| 3415 | + if (stop_phy) |
|---|
| 3416 | + phy_stop(dev->phydev); |
|---|
| 2984 | 3417 | bcmgenet_disable_rx_napi(priv); |
|---|
| 2985 | 3418 | bcmgenet_intr_disable(priv); |
|---|
| 2986 | 3419 | |
|---|
| .. | .. |
|---|
| 3006 | 3439 | |
|---|
| 3007 | 3440 | netif_dbg(priv, ifdown, dev, "bcmgenet_close\n"); |
|---|
| 3008 | 3441 | |
|---|
| 3009 | | - bcmgenet_netif_stop(dev); |
|---|
| 3442 | + bcmgenet_netif_stop(dev, false); |
|---|
| 3010 | 3443 | |
|---|
| 3011 | 3444 | /* Really kill the PHY state machine and disconnect from it */ |
|---|
| 3012 | 3445 | phy_disconnect(dev->phydev); |
|---|
| .. | .. |
|---|
| 3066 | 3499 | ring->cb_ptr, ring->end_ptr); |
|---|
| 3067 | 3500 | } |
|---|
| 3068 | 3501 | |
|---|
| 3069 | | -static void bcmgenet_timeout(struct net_device *dev) |
|---|
| 3502 | +static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) |
|---|
| 3070 | 3503 | { |
|---|
| 3071 | 3504 | struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 3072 | 3505 | u32 int0_enable = 0; |
|---|
| .. | .. |
|---|
| 3221 | 3654 | return &dev->stats; |
|---|
| 3222 | 3655 | } |
|---|
| 3223 | 3656 | |
|---|
| 3657 | +static int bcmgenet_change_carrier(struct net_device *dev, bool new_carrier) |
|---|
| 3658 | +{ |
|---|
| 3659 | + struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 3660 | + |
|---|
| 3661 | + if (!dev->phydev || !phy_is_pseudo_fixed_link(dev->phydev) || |
|---|
| 3662 | + priv->phy_interface != PHY_INTERFACE_MODE_MOCA) |
|---|
| 3663 | + return -EOPNOTSUPP; |
|---|
| 3664 | + |
|---|
| 3665 | + if (new_carrier) |
|---|
| 3666 | + netif_carrier_on(dev); |
|---|
| 3667 | + else |
|---|
| 3668 | + netif_carrier_off(dev); |
|---|
| 3669 | + |
|---|
| 3670 | + return 0; |
|---|
| 3671 | +} |
|---|
| 3672 | + |
|---|
| 3224 | 3673 | static const struct net_device_ops bcmgenet_netdev_ops = { |
|---|
| 3225 | 3674 | .ndo_open = bcmgenet_open, |
|---|
| 3226 | 3675 | .ndo_stop = bcmgenet_close, |
|---|
| .. | .. |
|---|
| 3228 | 3677 | .ndo_tx_timeout = bcmgenet_timeout, |
|---|
| 3229 | 3678 | .ndo_set_rx_mode = bcmgenet_set_rx_mode, |
|---|
| 3230 | 3679 | .ndo_set_mac_address = bcmgenet_set_mac_addr, |
|---|
| 3231 | | - .ndo_do_ioctl = bcmgenet_ioctl, |
|---|
| 3680 | + .ndo_do_ioctl = phy_do_ioctl_running, |
|---|
| 3232 | 3681 | .ndo_set_features = bcmgenet_set_features, |
|---|
| 3233 | 3682 | #ifdef CONFIG_NET_POLL_CONTROLLER |
|---|
| 3234 | 3683 | .ndo_poll_controller = bcmgenet_poll_controller, |
|---|
| 3235 | 3684 | #endif |
|---|
| 3236 | 3685 | .ndo_get_stats = bcmgenet_get_stats, |
|---|
| 3686 | + .ndo_change_carrier = bcmgenet_change_carrier, |
|---|
| 3237 | 3687 | }; |
|---|
| 3238 | 3688 | |
|---|
| 3239 | 3689 | /* Array of GENET hardware parameters/characteristics */ |
|---|
| .. | .. |
|---|
| 3339 | 3789 | if (GENET_IS_V5(priv) || GENET_IS_V4(priv)) { |
|---|
| 3340 | 3790 | bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus; |
|---|
| 3341 | 3791 | genet_dma_ring_regs = genet_dma_ring_regs_v4; |
|---|
| 3342 | | - priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS; |
|---|
| 3343 | 3792 | } else if (GENET_IS_V3(priv)) { |
|---|
| 3344 | 3793 | bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus; |
|---|
| 3345 | 3794 | genet_dma_ring_regs = genet_dma_ring_regs_v123; |
|---|
| 3346 | | - priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS; |
|---|
| 3347 | 3795 | } else if (GENET_IS_V2(priv)) { |
|---|
| 3348 | 3796 | bcmgenet_dma_regs = bcmgenet_dma_regs_v2; |
|---|
| 3349 | 3797 | genet_dma_ring_regs = genet_dma_ring_regs_v123; |
|---|
| 3350 | | - priv->dma_rx_chk_bit = DMA_RX_CHK_V12; |
|---|
| 3351 | 3798 | } else if (GENET_IS_V1(priv)) { |
|---|
| 3352 | 3799 | bcmgenet_dma_regs = bcmgenet_dma_regs_v1; |
|---|
| 3353 | 3800 | genet_dma_ring_regs = genet_dma_ring_regs_v123; |
|---|
| 3354 | | - priv->dma_rx_chk_bit = DMA_RX_CHK_V12; |
|---|
| 3355 | 3801 | } |
|---|
| 3356 | 3802 | |
|---|
| 3357 | 3803 | /* enum genet_version starts at 1 */ |
|---|
| .. | .. |
|---|
| 3434 | 3880 | params->words_per_bd); |
|---|
| 3435 | 3881 | } |
|---|
| 3436 | 3882 | |
|---|
| 3883 | +struct bcmgenet_plat_data { |
|---|
| 3884 | + enum bcmgenet_version version; |
|---|
| 3885 | + u32 dma_max_burst_length; |
|---|
| 3886 | +}; |
|---|
| 3887 | + |
|---|
| 3888 | +static const struct bcmgenet_plat_data v1_plat_data = { |
|---|
| 3889 | + .version = GENET_V1, |
|---|
| 3890 | + .dma_max_burst_length = DMA_MAX_BURST_LENGTH, |
|---|
| 3891 | +}; |
|---|
| 3892 | + |
|---|
| 3893 | +static const struct bcmgenet_plat_data v2_plat_data = { |
|---|
| 3894 | + .version = GENET_V2, |
|---|
| 3895 | + .dma_max_burst_length = DMA_MAX_BURST_LENGTH, |
|---|
| 3896 | +}; |
|---|
| 3897 | + |
|---|
| 3898 | +static const struct bcmgenet_plat_data v3_plat_data = { |
|---|
| 3899 | + .version = GENET_V3, |
|---|
| 3900 | + .dma_max_burst_length = DMA_MAX_BURST_LENGTH, |
|---|
| 3901 | +}; |
|---|
| 3902 | + |
|---|
| 3903 | +static const struct bcmgenet_plat_data v4_plat_data = { |
|---|
| 3904 | + .version = GENET_V4, |
|---|
| 3905 | + .dma_max_burst_length = DMA_MAX_BURST_LENGTH, |
|---|
| 3906 | +}; |
|---|
| 3907 | + |
|---|
| 3908 | +static const struct bcmgenet_plat_data v5_plat_data = { |
|---|
| 3909 | + .version = GENET_V5, |
|---|
| 3910 | + .dma_max_burst_length = DMA_MAX_BURST_LENGTH, |
|---|
| 3911 | +}; |
|---|
| 3912 | + |
|---|
| 3913 | +static const struct bcmgenet_plat_data bcm2711_plat_data = { |
|---|
| 3914 | + .version = GENET_V5, |
|---|
| 3915 | + .dma_max_burst_length = 0x08, |
|---|
| 3916 | +}; |
|---|
| 3917 | + |
|---|
| 3437 | 3918 | static const struct of_device_id bcmgenet_match[] = { |
|---|
| 3438 | | - { .compatible = "brcm,genet-v1", .data = (void *)GENET_V1 }, |
|---|
| 3439 | | - { .compatible = "brcm,genet-v2", .data = (void *)GENET_V2 }, |
|---|
| 3440 | | - { .compatible = "brcm,genet-v3", .data = (void *)GENET_V3 }, |
|---|
| 3441 | | - { .compatible = "brcm,genet-v4", .data = (void *)GENET_V4 }, |
|---|
| 3442 | | - { .compatible = "brcm,genet-v5", .data = (void *)GENET_V5 }, |
|---|
| 3919 | + { .compatible = "brcm,genet-v1", .data = &v1_plat_data }, |
|---|
| 3920 | + { .compatible = "brcm,genet-v2", .data = &v2_plat_data }, |
|---|
| 3921 | + { .compatible = "brcm,genet-v3", .data = &v3_plat_data }, |
|---|
| 3922 | + { .compatible = "brcm,genet-v4", .data = &v4_plat_data }, |
|---|
| 3923 | + { .compatible = "brcm,genet-v5", .data = &v5_plat_data }, |
|---|
| 3924 | + { .compatible = "brcm,bcm2711-genet-v5", .data = &bcm2711_plat_data }, |
|---|
| 3443 | 3925 | { }, |
|---|
| 3444 | 3926 | }; |
|---|
| 3445 | 3927 | MODULE_DEVICE_TABLE(of, bcmgenet_match); |
|---|
| .. | .. |
|---|
| 3447 | 3929 | static int bcmgenet_probe(struct platform_device *pdev) |
|---|
| 3448 | 3930 | { |
|---|
| 3449 | 3931 | struct bcmgenet_platform_data *pd = pdev->dev.platform_data; |
|---|
| 3450 | | - struct device_node *dn = pdev->dev.of_node; |
|---|
| 3451 | | - const struct of_device_id *of_id = NULL; |
|---|
| 3932 | + const struct bcmgenet_plat_data *pdata; |
|---|
| 3452 | 3933 | struct bcmgenet_priv *priv; |
|---|
| 3453 | 3934 | struct net_device *dev; |
|---|
| 3454 | | - const void *macaddr; |
|---|
| 3455 | | - struct resource *r; |
|---|
| 3456 | 3935 | unsigned int i; |
|---|
| 3457 | 3936 | int err = -EIO; |
|---|
| 3458 | | - const char *phy_mode_str; |
|---|
| 3459 | 3937 | |
|---|
| 3460 | 3938 | /* Up to GENET_MAX_MQ_CNT + 1 TX queues and RX queues */ |
|---|
| 3461 | 3939 | dev = alloc_etherdev_mqs(sizeof(*priv), GENET_MAX_MQ_CNT + 1, |
|---|
| .. | .. |
|---|
| 3465 | 3943 | return -ENOMEM; |
|---|
| 3466 | 3944 | } |
|---|
| 3467 | 3945 | |
|---|
| 3468 | | - if (dn) { |
|---|
| 3469 | | - of_id = of_match_node(bcmgenet_match, dn); |
|---|
| 3470 | | - if (!of_id) |
|---|
| 3471 | | - return -EINVAL; |
|---|
| 3472 | | - } |
|---|
| 3473 | | - |
|---|
| 3474 | 3946 | priv = netdev_priv(dev); |
|---|
| 3475 | 3947 | priv->irq0 = platform_get_irq(pdev, 0); |
|---|
| 3948 | + if (priv->irq0 < 0) { |
|---|
| 3949 | + err = priv->irq0; |
|---|
| 3950 | + goto err; |
|---|
| 3951 | + } |
|---|
| 3476 | 3952 | priv->irq1 = platform_get_irq(pdev, 1); |
|---|
| 3477 | | - priv->wol_irq = platform_get_irq(pdev, 2); |
|---|
| 3478 | | - if (!priv->irq0 || !priv->irq1) { |
|---|
| 3479 | | - dev_err(&pdev->dev, "can't find IRQs\n"); |
|---|
| 3480 | | - err = -EINVAL; |
|---|
| 3953 | + if (priv->irq1 < 0) { |
|---|
| 3954 | + err = priv->irq1; |
|---|
| 3955 | + goto err; |
|---|
| 3956 | + } |
|---|
| 3957 | + priv->wol_irq = platform_get_irq_optional(pdev, 2); |
|---|
| 3958 | + if (priv->wol_irq == -EPROBE_DEFER) { |
|---|
| 3959 | + err = priv->wol_irq; |
|---|
| 3481 | 3960 | goto err; |
|---|
| 3482 | 3961 | } |
|---|
| 3483 | 3962 | |
|---|
| 3484 | | - if (dn) { |
|---|
| 3485 | | - macaddr = of_get_mac_address(dn); |
|---|
| 3486 | | - if (!macaddr) { |
|---|
| 3487 | | - dev_err(&pdev->dev, "can't find MAC address\n"); |
|---|
| 3488 | | - err = -EINVAL; |
|---|
| 3489 | | - goto err; |
|---|
| 3490 | | - } |
|---|
| 3491 | | - } else { |
|---|
| 3492 | | - macaddr = pd->mac_address; |
|---|
| 3493 | | - } |
|---|
| 3494 | | - |
|---|
| 3495 | | - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 3496 | | - priv->base = devm_ioremap_resource(&pdev->dev, r); |
|---|
| 3963 | + priv->base = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 3497 | 3964 | if (IS_ERR(priv->base)) { |
|---|
| 3498 | 3965 | err = PTR_ERR(priv->base); |
|---|
| 3499 | 3966 | goto err; |
|---|
| .. | .. |
|---|
| 3503 | 3970 | |
|---|
| 3504 | 3971 | SET_NETDEV_DEV(dev, &pdev->dev); |
|---|
| 3505 | 3972 | dev_set_drvdata(&pdev->dev, dev); |
|---|
| 3506 | | - ether_addr_copy(dev->dev_addr, macaddr); |
|---|
| 3507 | 3973 | dev->watchdog_timeo = 2 * HZ; |
|---|
| 3508 | 3974 | dev->ethtool_ops = &bcmgenet_ethtool_ops; |
|---|
| 3509 | 3975 | dev->netdev_ops = &bcmgenet_netdev_ops; |
|---|
| 3510 | 3976 | |
|---|
| 3511 | 3977 | priv->msg_enable = netif_msg_init(-1, GENET_MSG_DEFAULT); |
|---|
| 3512 | 3978 | |
|---|
| 3513 | | - /* Set hardware features */ |
|---|
| 3514 | | - dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | |
|---|
| 3515 | | - NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; |
|---|
| 3979 | + /* Set default features */ |
|---|
| 3980 | + dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | |
|---|
| 3981 | + NETIF_F_RXCSUM; |
|---|
| 3982 | + dev->hw_features |= dev->features; |
|---|
| 3983 | + dev->vlan_features |= dev->features; |
|---|
| 3516 | 3984 | |
|---|
| 3517 | 3985 | /* Request the WOL interrupt and advertise suspend if available */ |
|---|
| 3518 | 3986 | priv->wol_irq_disabled = true; |
|---|
| .. | .. |
|---|
| 3532 | 4000 | |
|---|
| 3533 | 4001 | priv->dev = dev; |
|---|
| 3534 | 4002 | priv->pdev = pdev; |
|---|
| 3535 | | - if (of_id) |
|---|
| 3536 | | - priv->version = (enum bcmgenet_version)of_id->data; |
|---|
| 3537 | | - else |
|---|
| 3538 | | - priv->version = pd->genet_version; |
|---|
| 3539 | 4003 | |
|---|
| 3540 | | - priv->clk = devm_clk_get(&priv->pdev->dev, "enet"); |
|---|
| 3541 | | - if (IS_ERR(priv->clk)) { |
|---|
| 3542 | | - dev_warn(&priv->pdev->dev, "failed to get enet clock\n"); |
|---|
| 3543 | | - priv->clk = NULL; |
|---|
| 4004 | + pdata = device_get_match_data(&pdev->dev); |
|---|
| 4005 | + if (pdata) { |
|---|
| 4006 | + priv->version = pdata->version; |
|---|
| 4007 | + priv->dma_max_burst_length = pdata->dma_max_burst_length; |
|---|
| 4008 | + } else { |
|---|
| 4009 | + priv->version = pd->genet_version; |
|---|
| 4010 | + priv->dma_max_burst_length = DMA_MAX_BURST_LENGTH; |
|---|
| 3544 | 4011 | } |
|---|
| 3545 | 4012 | |
|---|
| 3546 | | - clk_prepare_enable(priv->clk); |
|---|
| 4013 | + priv->clk = devm_clk_get_optional(&priv->pdev->dev, "enet"); |
|---|
| 4014 | + if (IS_ERR(priv->clk)) { |
|---|
| 4015 | + dev_dbg(&priv->pdev->dev, "failed to get enet clock\n"); |
|---|
| 4016 | + err = PTR_ERR(priv->clk); |
|---|
| 4017 | + goto err; |
|---|
| 4018 | + } |
|---|
| 4019 | + |
|---|
| 4020 | + err = clk_prepare_enable(priv->clk); |
|---|
| 4021 | + if (err) |
|---|
| 4022 | + goto err; |
|---|
| 3547 | 4023 | |
|---|
| 3548 | 4024 | bcmgenet_set_hw_params(priv); |
|---|
| 4025 | + |
|---|
| 4026 | + err = -EIO; |
|---|
| 4027 | + if (priv->hw_params->flags & GENET_HAS_40BITS) |
|---|
| 4028 | + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); |
|---|
| 4029 | + if (err) |
|---|
| 4030 | + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); |
|---|
| 4031 | + if (err) |
|---|
| 4032 | + goto err_clk_disable; |
|---|
| 3549 | 4033 | |
|---|
| 3550 | 4034 | /* Mii wait queue */ |
|---|
| 3551 | 4035 | init_waitqueue_head(&priv->wq); |
|---|
| .. | .. |
|---|
| 3553 | 4037 | priv->rx_buf_len = RX_BUF_LENGTH; |
|---|
| 3554 | 4038 | INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task); |
|---|
| 3555 | 4039 | |
|---|
| 3556 | | - priv->clk_wol = devm_clk_get(&priv->pdev->dev, "enet-wol"); |
|---|
| 4040 | + priv->clk_wol = devm_clk_get_optional(&priv->pdev->dev, "enet-wol"); |
|---|
| 3557 | 4041 | if (IS_ERR(priv->clk_wol)) { |
|---|
| 3558 | | - dev_warn(&priv->pdev->dev, "failed to get enet-wol clock\n"); |
|---|
| 3559 | | - priv->clk_wol = NULL; |
|---|
| 4042 | + dev_dbg(&priv->pdev->dev, "failed to get enet-wol clock\n"); |
|---|
| 4043 | + err = PTR_ERR(priv->clk_wol); |
|---|
| 4044 | + goto err_clk_disable; |
|---|
| 3560 | 4045 | } |
|---|
| 3561 | 4046 | |
|---|
| 3562 | | - priv->clk_eee = devm_clk_get(&priv->pdev->dev, "enet-eee"); |
|---|
| 4047 | + priv->clk_eee = devm_clk_get_optional(&priv->pdev->dev, "enet-eee"); |
|---|
| 3563 | 4048 | if (IS_ERR(priv->clk_eee)) { |
|---|
| 3564 | | - dev_warn(&priv->pdev->dev, "failed to get enet-eee clock\n"); |
|---|
| 3565 | | - priv->clk_eee = NULL; |
|---|
| 4049 | + dev_dbg(&priv->pdev->dev, "failed to get enet-eee clock\n"); |
|---|
| 4050 | + err = PTR_ERR(priv->clk_eee); |
|---|
| 4051 | + goto err_clk_disable; |
|---|
| 3566 | 4052 | } |
|---|
| 3567 | 4053 | |
|---|
| 3568 | 4054 | /* If this is an internal GPHY, power it on now, before UniMAC is |
|---|
| 3569 | 4055 | * brought out of reset as absolutely no UniMAC activity is allowed |
|---|
| 3570 | 4056 | */ |
|---|
| 3571 | | - if (dn && !of_property_read_string(dn, "phy-mode", &phy_mode_str) && |
|---|
| 3572 | | - !strcasecmp(phy_mode_str, "internal")) |
|---|
| 4057 | + if (device_get_phy_mode(&pdev->dev) == PHY_INTERFACE_MODE_INTERNAL) |
|---|
| 3573 | 4058 | bcmgenet_power_up(priv, GENET_POWER_PASSIVE); |
|---|
| 4059 | + |
|---|
| 4060 | + if (pd && !IS_ERR_OR_NULL(pd->mac_address)) |
|---|
| 4061 | + ether_addr_copy(dev->dev_addr, pd->mac_address); |
|---|
| 4062 | + else |
|---|
| 4063 | + if (!device_get_mac_address(&pdev->dev, dev->dev_addr, ETH_ALEN)) |
|---|
| 4064 | + if (has_acpi_companion(&pdev->dev)) |
|---|
| 4065 | + bcmgenet_get_hw_addr(priv, dev->dev_addr); |
|---|
| 4066 | + |
|---|
| 4067 | + if (!is_valid_ether_addr(dev->dev_addr)) { |
|---|
| 4068 | + dev_warn(&pdev->dev, "using random Ethernet MAC\n"); |
|---|
| 4069 | + eth_hw_addr_random(dev); |
|---|
| 4070 | + } |
|---|
| 3574 | 4071 | |
|---|
| 3575 | 4072 | reset_umac(priv); |
|---|
| 3576 | 4073 | |
|---|
| .. | .. |
|---|
| 3622 | 4119 | return 0; |
|---|
| 3623 | 4120 | } |
|---|
| 3624 | 4121 | |
|---|
| 4122 | +static void bcmgenet_shutdown(struct platform_device *pdev) |
|---|
| 4123 | +{ |
|---|
| 4124 | + bcmgenet_remove(pdev); |
|---|
| 4125 | +} |
|---|
| 4126 | + |
|---|
| 3625 | 4127 | #ifdef CONFIG_PM_SLEEP |
|---|
| 3626 | | -static int bcmgenet_resume(struct device *d) |
|---|
| 4128 | +static int bcmgenet_resume_noirq(struct device *d) |
|---|
| 3627 | 4129 | { |
|---|
| 3628 | 4130 | struct net_device *dev = dev_get_drvdata(d); |
|---|
| 3629 | 4131 | struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 3630 | | - unsigned long dma_ctrl; |
|---|
| 3631 | 4132 | int ret; |
|---|
| 4133 | + u32 reg; |
|---|
| 3632 | 4134 | |
|---|
| 3633 | 4135 | if (!netif_running(dev)) |
|---|
| 3634 | 4136 | return 0; |
|---|
| .. | .. |
|---|
| 3637 | 4139 | ret = clk_prepare_enable(priv->clk); |
|---|
| 3638 | 4140 | if (ret) |
|---|
| 3639 | 4141 | return ret; |
|---|
| 4142 | + |
|---|
| 4143 | + if (device_may_wakeup(d) && priv->wolopts) { |
|---|
| 4144 | + /* Account for Wake-on-LAN events and clear those events |
|---|
| 4145 | + * (Some devices need more time between enabling the clocks |
|---|
| 4146 | + * and the interrupt register reflecting the wake event so |
|---|
| 4147 | + * read the register twice) |
|---|
| 4148 | + */ |
|---|
| 4149 | + reg = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT); |
|---|
| 4150 | + reg = bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT); |
|---|
| 4151 | + if (reg & UMAC_IRQ_WAKE_EVENT) |
|---|
| 4152 | + pm_wakeup_event(&priv->pdev->dev, 0); |
|---|
| 4153 | + } |
|---|
| 4154 | + |
|---|
| 4155 | + bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_WAKE_EVENT, INTRL2_CPU_CLEAR); |
|---|
| 4156 | + |
|---|
| 4157 | + return 0; |
|---|
| 4158 | +} |
|---|
| 4159 | + |
|---|
| 4160 | +static int bcmgenet_resume(struct device *d) |
|---|
| 4161 | +{ |
|---|
| 4162 | + struct net_device *dev = dev_get_drvdata(d); |
|---|
| 4163 | + struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 4164 | + struct bcmgenet_rxnfc_rule *rule; |
|---|
| 4165 | + unsigned long dma_ctrl; |
|---|
| 4166 | + int ret; |
|---|
| 4167 | + |
|---|
| 4168 | + if (!netif_running(dev)) |
|---|
| 4169 | + return 0; |
|---|
| 4170 | + |
|---|
| 4171 | + /* From WOL-enabled suspend, switch to regular clock */ |
|---|
| 4172 | + if (device_may_wakeup(d) && priv->wolopts) |
|---|
| 4173 | + bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC); |
|---|
| 3640 | 4174 | |
|---|
| 3641 | 4175 | /* If this is an internal GPHY, power it back on now, before UniMAC is |
|---|
| 3642 | 4176 | * brought out of reset as absolutely no UniMAC activity is allowed |
|---|
| .. | .. |
|---|
| 3648 | 4182 | |
|---|
| 3649 | 4183 | init_umac(priv); |
|---|
| 3650 | 4184 | |
|---|
| 3651 | | - /* From WOL-enabled suspend, switch to regular clock */ |
|---|
| 3652 | | - if (priv->wolopts) |
|---|
| 3653 | | - clk_disable_unprepare(priv->clk_wol); |
|---|
| 3654 | | - |
|---|
| 3655 | 4185 | phy_init_hw(dev->phydev); |
|---|
| 3656 | 4186 | |
|---|
| 3657 | 4187 | /* Speed settings must be restored */ |
|---|
| 3658 | 4188 | genphy_config_aneg(dev->phydev); |
|---|
| 3659 | 4189 | bcmgenet_mii_config(priv->dev, false); |
|---|
| 3660 | 4190 | |
|---|
| 4191 | + /* Restore enabled features */ |
|---|
| 4192 | + bcmgenet_set_features(dev, dev->features); |
|---|
| 4193 | + |
|---|
| 3661 | 4194 | bcmgenet_set_hw_addr(priv, dev->dev_addr); |
|---|
| 3662 | 4195 | |
|---|
| 3663 | | - if (priv->wolopts) |
|---|
| 3664 | | - bcmgenet_power_up(priv, GENET_POWER_WOL_MAGIC); |
|---|
| 4196 | + /* Restore hardware filters */ |
|---|
| 4197 | + bcmgenet_hfb_clear(priv); |
|---|
| 4198 | + list_for_each_entry(rule, &priv->rxnfc_list, list) |
|---|
| 4199 | + if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) |
|---|
| 4200 | + bcmgenet_hfb_create_rxnfc_filter(priv, rule); |
|---|
| 3665 | 4201 | |
|---|
| 3666 | 4202 | /* Disable RX/TX DMA and flush TX queues */ |
|---|
| 3667 | 4203 | dma_ctrl = bcmgenet_dma_disable(priv); |
|---|
| .. | .. |
|---|
| 3699 | 4235 | { |
|---|
| 3700 | 4236 | struct net_device *dev = dev_get_drvdata(d); |
|---|
| 3701 | 4237 | struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 3702 | | - int ret = 0; |
|---|
| 3703 | 4238 | |
|---|
| 3704 | 4239 | if (!netif_running(dev)) |
|---|
| 3705 | 4240 | return 0; |
|---|
| 3706 | 4241 | |
|---|
| 3707 | 4242 | netif_device_detach(dev); |
|---|
| 3708 | 4243 | |
|---|
| 3709 | | - bcmgenet_netif_stop(dev); |
|---|
| 4244 | + bcmgenet_netif_stop(dev, true); |
|---|
| 3710 | 4245 | |
|---|
| 3711 | 4246 | if (!device_may_wakeup(d)) |
|---|
| 3712 | 4247 | phy_suspend(dev->phydev); |
|---|
| 3713 | 4248 | |
|---|
| 4249 | + /* Disable filtering */ |
|---|
| 4250 | + bcmgenet_hfb_reg_writel(priv, 0, HFB_CTRL); |
|---|
| 4251 | + |
|---|
| 4252 | + return 0; |
|---|
| 4253 | +} |
|---|
| 4254 | + |
|---|
| 4255 | +static int bcmgenet_suspend_noirq(struct device *d) |
|---|
| 4256 | +{ |
|---|
| 4257 | + struct net_device *dev = dev_get_drvdata(d); |
|---|
| 4258 | + struct bcmgenet_priv *priv = netdev_priv(dev); |
|---|
| 4259 | + int ret = 0; |
|---|
| 4260 | + |
|---|
| 4261 | + if (!netif_running(dev)) |
|---|
| 4262 | + return 0; |
|---|
| 4263 | + |
|---|
| 3714 | 4264 | /* Prepare the device for Wake-on-LAN and switch to the slow clock */ |
|---|
| 3715 | | - if (device_may_wakeup(d) && priv->wolopts) { |
|---|
| 4265 | + if (device_may_wakeup(d) && priv->wolopts) |
|---|
| 3716 | 4266 | ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC); |
|---|
| 3717 | | - clk_prepare_enable(priv->clk_wol); |
|---|
| 3718 | | - } else if (priv->internal_phy) { |
|---|
| 4267 | + else if (priv->internal_phy) |
|---|
| 3719 | 4268 | ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE); |
|---|
| 3720 | | - } |
|---|
| 4269 | + |
|---|
| 4270 | + /* Let the framework handle resumption and leave the clocks on */ |
|---|
| 4271 | + if (ret) |
|---|
| 4272 | + return ret; |
|---|
| 3721 | 4273 | |
|---|
| 3722 | 4274 | /* Turn off the clocks */ |
|---|
| 3723 | 4275 | clk_disable_unprepare(priv->clk); |
|---|
| 3724 | 4276 | |
|---|
| 3725 | | - if (ret) |
|---|
| 3726 | | - bcmgenet_resume(d); |
|---|
| 3727 | | - |
|---|
| 3728 | | - return ret; |
|---|
| 4277 | + return 0; |
|---|
| 3729 | 4278 | } |
|---|
| 4279 | +#else |
|---|
| 4280 | +#define bcmgenet_suspend NULL |
|---|
| 4281 | +#define bcmgenet_suspend_noirq NULL |
|---|
| 4282 | +#define bcmgenet_resume NULL |
|---|
| 4283 | +#define bcmgenet_resume_noirq NULL |
|---|
| 3730 | 4284 | #endif /* CONFIG_PM_SLEEP */ |
|---|
| 3731 | 4285 | |
|---|
| 3732 | | -static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, bcmgenet_suspend, bcmgenet_resume); |
|---|
| 4286 | +static const struct dev_pm_ops bcmgenet_pm_ops = { |
|---|
| 4287 | + .suspend = bcmgenet_suspend, |
|---|
| 4288 | + .suspend_noirq = bcmgenet_suspend_noirq, |
|---|
| 4289 | + .resume = bcmgenet_resume, |
|---|
| 4290 | + .resume_noirq = bcmgenet_resume_noirq, |
|---|
| 4291 | +}; |
|---|
| 4292 | + |
|---|
| 4293 | +static const struct acpi_device_id genet_acpi_match[] = { |
|---|
| 4294 | + { "BCM6E4E", (kernel_ulong_t)&bcm2711_plat_data }, |
|---|
| 4295 | + { }, |
|---|
| 4296 | +}; |
|---|
| 4297 | +MODULE_DEVICE_TABLE(acpi, genet_acpi_match); |
|---|
| 3733 | 4298 | |
|---|
| 3734 | 4299 | static struct platform_driver bcmgenet_driver = { |
|---|
| 3735 | 4300 | .probe = bcmgenet_probe, |
|---|
| 3736 | 4301 | .remove = bcmgenet_remove, |
|---|
| 4302 | + .shutdown = bcmgenet_shutdown, |
|---|
| 3737 | 4303 | .driver = { |
|---|
| 3738 | 4304 | .name = "bcmgenet", |
|---|
| 3739 | 4305 | .of_match_table = bcmgenet_match, |
|---|
| 3740 | 4306 | .pm = &bcmgenet_pm_ops, |
|---|
| 4307 | + .acpi_match_table = genet_acpi_match, |
|---|
| 3741 | 4308 | }, |
|---|
| 3742 | 4309 | }; |
|---|
| 3743 | 4310 | module_platform_driver(bcmgenet_driver); |
|---|