enetc: Introduce basic PF and VF ENETC ethernet drivers
[linux-2.6-microblaze.git] / drivers / net / ethernet / freescale / enetc / enetc_ethtool.c
1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2 /* Copyright 2017-2019 NXP */
3
4 #include <linux/net_tstamp.h>
5 #include <linux/module.h>
6 #include "enetc.h"
7
8 static const u32 enetc_si_regs[] = {
9         ENETC_SIMR, ENETC_SIPMAR0, ENETC_SIPMAR1, ENETC_SICBDRMR,
10         ENETC_SICBDRSR, ENETC_SICBDRBAR0, ENETC_SICBDRBAR1, ENETC_SICBDRPIR,
11         ENETC_SICBDRCIR, ENETC_SICBDRLENR, ENETC_SICAPR0, ENETC_SICAPR1,
12         ENETC_SIUEFDCR
13 };
14
15 static const u32 enetc_txbdr_regs[] = {
16         ENETC_TBMR, ENETC_TBSR, ENETC_TBBAR0, ENETC_TBBAR1,
17         ENETC_TBPIR, ENETC_TBCIR, ENETC_TBLENR, ENETC_TBIER
18 };
19
20 static const u32 enetc_rxbdr_regs[] = {
21         ENETC_RBMR, ENETC_RBSR, ENETC_RBBSR, ENETC_RBCIR, ENETC_RBBAR0,
22         ENETC_RBBAR1, ENETC_RBPIR, ENETC_RBLENR, ENETC_RBICIR0, ENETC_RBIER
23 };
24
25 static const u32 enetc_port_regs[] = {
26         ENETC_PMR, ENETC_PSR, ENETC_PSIPMR, ENETC_PSIPMAR0(0),
27         ENETC_PSIPMAR1(0), ENETC_PTXMBAR, ENETC_PCAPR0, ENETC_PCAPR1,
28         ENETC_PSICFGR0(0), ENETC_PTCMSDUR(0), ENETC_PM0_CMD_CFG,
29         ENETC_PM0_MAXFRM, ENETC_PM0_IF_MODE
30 };
31
32 static int enetc_get_reglen(struct net_device *ndev)
33 {
34         struct enetc_ndev_priv *priv = netdev_priv(ndev);
35         struct enetc_hw *hw = &priv->si->hw;
36         int len;
37
38         len = ARRAY_SIZE(enetc_si_regs);
39         len += ARRAY_SIZE(enetc_txbdr_regs) * priv->num_tx_rings;
40         len += ARRAY_SIZE(enetc_rxbdr_regs) * priv->num_rx_rings;
41
42         if (hw->port)
43                 len += ARRAY_SIZE(enetc_port_regs);
44
45         len *= sizeof(u32) * 2; /* store 2 entries per reg: addr and value */
46
47         return len;
48 }
49
50 static void enetc_get_regs(struct net_device *ndev, struct ethtool_regs *regs,
51                            void *regbuf)
52 {
53         struct enetc_ndev_priv *priv = netdev_priv(ndev);
54         struct enetc_hw *hw = &priv->si->hw;
55         u32 *buf = (u32 *)regbuf;
56         int i, j;
57         u32 addr;
58
59         for (i = 0; i < ARRAY_SIZE(enetc_si_regs); i++) {
60                 *buf++ = enetc_si_regs[i];
61                 *buf++ = enetc_rd(hw, enetc_si_regs[i]);
62         }
63
64         for (i = 0; i < priv->num_tx_rings; i++) {
65                 for (j = 0; j < ARRAY_SIZE(enetc_txbdr_regs); j++) {
66                         addr = ENETC_BDR(TX, i, enetc_txbdr_regs[j]);
67
68                         *buf++ = addr;
69                         *buf++ = enetc_rd(hw, addr);
70                 }
71         }
72
73         for (i = 0; i < priv->num_rx_rings; i++) {
74                 for (j = 0; j < ARRAY_SIZE(enetc_rxbdr_regs); j++) {
75                         addr = ENETC_BDR(RX, i, enetc_rxbdr_regs[j]);
76
77                         *buf++ = addr;
78                         *buf++ = enetc_rd(hw, addr);
79                 }
80         }
81
82         if (!hw->port)
83                 return;
84
85         for (i = 0; i < ARRAY_SIZE(enetc_port_regs); i++) {
86                 addr = ENETC_PORT_BASE + enetc_port_regs[i];
87                 *buf++ = addr;
88                 *buf++ = enetc_rd(hw, addr);
89         }
90 }
91
92 static void enetc_get_ringparam(struct net_device *ndev,
93                                 struct ethtool_ringparam *ring)
94 {
95         struct enetc_ndev_priv *priv = netdev_priv(ndev);
96
97         ring->rx_pending = priv->rx_bd_count;
98         ring->tx_pending = priv->tx_bd_count;
99
100         /* do some h/w sanity checks for BDR length */
101         if (netif_running(ndev)) {
102                 struct enetc_hw *hw = &priv->si->hw;
103                 u32 val = enetc_rxbdr_rd(hw, 0, ENETC_RBLENR);
104
105                 if (val != priv->rx_bd_count)
106                         netif_err(priv, hw, ndev, "RxBDR[RBLENR] = %d!\n", val);
107
108                 val = enetc_txbdr_rd(hw, 0, ENETC_TBLENR);
109
110                 if (val != priv->tx_bd_count)
111                         netif_err(priv, hw, ndev, "TxBDR[TBLENR] = %d!\n", val);
112         }
113 }
114
115 static const struct ethtool_ops enetc_pf_ethtool_ops = {
116         .get_regs_len = enetc_get_reglen,
117         .get_regs = enetc_get_regs,
118         .get_ringparam = enetc_get_ringparam,
119         .get_link_ksettings = phy_ethtool_get_link_ksettings,
120         .set_link_ksettings = phy_ethtool_set_link_ksettings,
121 };
122
123 static const struct ethtool_ops enetc_vf_ethtool_ops = {
124         .get_regs_len = enetc_get_reglen,
125         .get_regs = enetc_get_regs,
126         .get_ringparam = enetc_get_ringparam,
127 };
128
129 void enetc_set_ethtool_ops(struct net_device *ndev)
130 {
131         struct enetc_ndev_priv *priv = netdev_priv(ndev);
132
133         if (enetc_si_is_pf(priv->si))
134                 ndev->ethtool_ops = &enetc_pf_ethtool_ops;
135         else
136                 ndev->ethtool_ops = &enetc_vf_ethtool_ops;
137 }