diff options
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r-- | drivers/net/sky2.c | 115 |
1 files changed, 103 insertions, 12 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index f2f8f60a0911..0ab376845e39 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -24,9 +24,6 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | /* | 26 | /* |
27 | * TODO | ||
28 | * - coalescing setting? | ||
29 | * | ||
30 | * TOTEST | 27 | * TOTEST |
31 | * - speed setting | 28 | * - speed setting |
32 | * - suspend/resume | 29 | * - suspend/resume |
@@ -2019,29 +2016,30 @@ static void sky2_netpoll(struct net_device *dev) | |||
2019 | #endif | 2016 | #endif |
2020 | 2017 | ||
2021 | /* Chip internal frequency for clock calculations */ | 2018 | /* Chip internal frequency for clock calculations */ |
2022 | static inline u32 sky2_khz(const struct sky2_hw *hw) | 2019 | static inline u32 sky2_mhz(const struct sky2_hw *hw) |
2023 | { | 2020 | { |
2024 | switch (hw->chip_id) { | 2021 | switch (hw->chip_id) { |
2025 | case CHIP_ID_YUKON_EC: | 2022 | case CHIP_ID_YUKON_EC: |
2026 | case CHIP_ID_YUKON_EC_U: | 2023 | case CHIP_ID_YUKON_EC_U: |
2027 | return 125000; /* 125 Mhz */ | 2024 | return 125; /* 125 Mhz */ |
2028 | case CHIP_ID_YUKON_FE: | 2025 | case CHIP_ID_YUKON_FE: |
2029 | return 100000; /* 100 Mhz */ | 2026 | return 100; /* 100 Mhz */ |
2030 | default: /* YUKON_XL */ | 2027 | default: /* YUKON_XL */ |
2031 | return 156000; /* 156 Mhz */ | 2028 | return 156; /* 156 Mhz */ |
2032 | } | 2029 | } |
2033 | } | 2030 | } |
2034 | 2031 | ||
2035 | static inline u32 sky2_ms2clk(const struct sky2_hw *hw, u32 ms) | 2032 | static inline u32 sky2_us2clk(const struct sky2_hw *hw, u32 us) |
2036 | { | 2033 | { |
2037 | return sky2_khz(hw) * ms; | 2034 | return sky2_mhz(hw) * us; |
2038 | } | 2035 | } |
2039 | 2036 | ||
2040 | static inline u32 sky2_us2clk(const struct sky2_hw *hw, u32 us) | 2037 | static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk) |
2041 | { | 2038 | { |
2042 | return (sky2_khz(hw) * us) / 1000; | 2039 | return clk / sky2_mhz(hw); |
2043 | } | 2040 | } |
2044 | 2041 | ||
2042 | |||
2045 | static int sky2_reset(struct sky2_hw *hw) | 2043 | static int sky2_reset(struct sky2_hw *hw) |
2046 | { | 2044 | { |
2047 | u32 ctst; | 2045 | u32 ctst; |
@@ -2169,7 +2167,7 @@ static int sky2_reset(struct sky2_hw *hw) | |||
2169 | /* Set the list last index */ | 2167 | /* Set the list last index */ |
2170 | sky2_write16(hw, STAT_LAST_IDX, STATUS_RING_SIZE - 1); | 2168 | sky2_write16(hw, STAT_LAST_IDX, STATUS_RING_SIZE - 1); |
2171 | 2169 | ||
2172 | sky2_write32(hw, STAT_TX_TIMER_INI, sky2_ms2clk(hw, 10)); | 2170 | sky2_write32(hw, STAT_TX_TIMER_INI, sky2_us2clk(hw, 1000)); |
2173 | 2171 | ||
2174 | /* These status setup values are copied from SysKonnect's driver */ | 2172 | /* These status setup values are copied from SysKonnect's driver */ |
2175 | if (is_ec_a1(hw)) { | 2173 | if (is_ec_a1(hw)) { |
@@ -2680,6 +2678,97 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | |||
2680 | } | 2678 | } |
2681 | #endif | 2679 | #endif |
2682 | 2680 | ||
2681 | static int sky2_get_coalesce(struct net_device *dev, | ||
2682 | struct ethtool_coalesce *ecmd) | ||
2683 | { | ||
2684 | struct sky2_port *sky2 = netdev_priv(dev); | ||
2685 | struct sky2_hw *hw = sky2->hw; | ||
2686 | |||
2687 | if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_STOP) | ||
2688 | ecmd->tx_coalesce_usecs = 0; | ||
2689 | else { | ||
2690 | u32 clks = sky2_read32(hw, STAT_TX_TIMER_INI); | ||
2691 | ecmd->tx_coalesce_usecs = sky2_clk2us(hw, clks); | ||
2692 | } | ||
2693 | ecmd->tx_max_coalesced_frames = sky2_read16(hw, STAT_TX_IDX_TH); | ||
2694 | |||
2695 | if (sky2_read8(hw, STAT_LEV_TIMER_CTRL) == TIM_STOP) | ||
2696 | ecmd->rx_coalesce_usecs = 0; | ||
2697 | else { | ||
2698 | u32 clks = sky2_read32(hw, STAT_LEV_TIMER_INI); | ||
2699 | ecmd->rx_coalesce_usecs = sky2_clk2us(hw, clks); | ||
2700 | } | ||
2701 | ecmd->rx_max_coalesced_frames = sky2_read8(hw, STAT_FIFO_WM); | ||
2702 | |||
2703 | if (sky2_read8(hw, STAT_ISR_TIMER_CTRL) == TIM_STOP) | ||
2704 | ecmd->rx_coalesce_usecs_irq = 0; | ||
2705 | else { | ||
2706 | u32 clks = sky2_read32(hw, STAT_ISR_TIMER_INI); | ||
2707 | ecmd->rx_coalesce_usecs_irq = sky2_clk2us(hw, clks); | ||
2708 | } | ||
2709 | |||
2710 | ecmd->rx_max_coalesced_frames_irq = sky2_read8(hw, STAT_FIFO_ISR_WM); | ||
2711 | |||
2712 | return 0; | ||
2713 | } | ||
2714 | |||
2715 | /* Note: this affect both ports */ | ||
2716 | static int sky2_set_coalesce(struct net_device *dev, | ||
2717 | struct ethtool_coalesce *ecmd) | ||
2718 | { | ||
2719 | struct sky2_port *sky2 = netdev_priv(dev); | ||
2720 | struct sky2_hw *hw = sky2->hw; | ||
2721 | const u32 tmin = sky2_clk2us(hw, 1); | ||
2722 | const u32 tmax = 5000; | ||
2723 | |||
2724 | if (ecmd->tx_coalesce_usecs != 0 && | ||
2725 | (ecmd->tx_coalesce_usecs < tmin || ecmd->tx_coalesce_usecs > tmax)) | ||
2726 | return -EINVAL; | ||
2727 | |||
2728 | if (ecmd->rx_coalesce_usecs != 0 && | ||
2729 | (ecmd->rx_coalesce_usecs < tmin || ecmd->rx_coalesce_usecs > tmax)) | ||
2730 | return -EINVAL; | ||
2731 | |||
2732 | if (ecmd->rx_coalesce_usecs_irq != 0 && | ||
2733 | (ecmd->rx_coalesce_usecs_irq < tmin || ecmd->rx_coalesce_usecs_irq > tmax)) | ||
2734 | return -EINVAL; | ||
2735 | |||
2736 | if (ecmd->tx_max_coalesced_frames > 0xffff) | ||
2737 | return -EINVAL; | ||
2738 | if (ecmd->rx_max_coalesced_frames > 0xff) | ||
2739 | return -EINVAL; | ||
2740 | if (ecmd->rx_max_coalesced_frames_irq > 0xff) | ||
2741 | return -EINVAL; | ||
2742 | |||
2743 | if (ecmd->tx_coalesce_usecs == 0) | ||
2744 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); | ||
2745 | else { | ||
2746 | sky2_write32(hw, STAT_TX_TIMER_INI, | ||
2747 | sky2_us2clk(hw, ecmd->tx_coalesce_usecs)); | ||
2748 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); | ||
2749 | } | ||
2750 | sky2_write16(hw, STAT_TX_IDX_TH, ecmd->tx_max_coalesced_frames); | ||
2751 | |||
2752 | if (ecmd->rx_coalesce_usecs == 0) | ||
2753 | sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_STOP); | ||
2754 | else { | ||
2755 | sky2_write32(hw, STAT_LEV_TIMER_INI, | ||
2756 | sky2_us2clk(hw, ecmd->rx_coalesce_usecs)); | ||
2757 | sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START); | ||
2758 | } | ||
2759 | sky2_write8(hw, STAT_FIFO_WM, ecmd->rx_max_coalesced_frames); | ||
2760 | |||
2761 | if (ecmd->rx_coalesce_usecs_irq == 0) | ||
2762 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_STOP); | ||
2763 | else { | ||
2764 | sky2_write32(hw, STAT_TX_TIMER_INI, | ||
2765 | sky2_us2clk(hw, ecmd->rx_coalesce_usecs_irq)); | ||
2766 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); | ||
2767 | } | ||
2768 | sky2_write8(hw, STAT_FIFO_ISR_WM, ecmd->rx_max_coalesced_frames_irq); | ||
2769 | return 0; | ||
2770 | } | ||
2771 | |||
2683 | static void sky2_get_ringparam(struct net_device *dev, | 2772 | static void sky2_get_ringparam(struct net_device *dev, |
2684 | struct ethtool_ringparam *ering) | 2773 | struct ethtool_ringparam *ering) |
2685 | { | 2774 | { |
@@ -2765,6 +2854,8 @@ static struct ethtool_ops sky2_ethtool_ops = { | |||
2765 | .get_rx_csum = sky2_get_rx_csum, | 2854 | .get_rx_csum = sky2_get_rx_csum, |
2766 | .set_rx_csum = sky2_set_rx_csum, | 2855 | .set_rx_csum = sky2_set_rx_csum, |
2767 | .get_strings = sky2_get_strings, | 2856 | .get_strings = sky2_get_strings, |
2857 | .get_coalesce = sky2_get_coalesce, | ||
2858 | .set_coalesce = sky2_set_coalesce, | ||
2768 | .get_ringparam = sky2_get_ringparam, | 2859 | .get_ringparam = sky2_get_ringparam, |
2769 | .set_ringparam = sky2_set_ringparam, | 2860 | .set_ringparam = sky2_set_ringparam, |
2770 | .get_pauseparam = sky2_get_pauseparam, | 2861 | .get_pauseparam = sky2_get_pauseparam, |