Merge tag 'pwm/for-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry...
[linux-2.6-microblaze.git] / drivers / net / ethernet / marvell / octeontx2 / af / rpm.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*  Marvell OcteonTx2 RPM driver
3  *
4  * Copyright (C) 2020 Marvell.
5  *
6  */
7
8 #include "cgx.h"
9 #include "lmac_common.h"
10
11 static struct mac_ops   rpm_mac_ops   = {
12         .name           =       "rpm",
13         .csr_offset     =       0x4e00,
14         .lmac_offset    =       20,
15         .int_register   =       RPMX_CMRX_SW_INT,
16         .int_set_reg    =       RPMX_CMRX_SW_INT_ENA_W1S,
17         .irq_offset     =       1,
18         .int_ena_bit    =       BIT_ULL(0),
19         .lmac_fwi       =       RPM_LMAC_FWI,
20         .non_contiguous_serdes_lane = true,
21         .rx_stats_cnt   =       43,
22         .tx_stats_cnt   =       34,
23         .get_nr_lmacs   =       rpm_get_nr_lmacs,
24         .get_lmac_type  =       rpm_get_lmac_type,
25         .mac_lmac_intl_lbk =    rpm_lmac_internal_loopback,
26         .mac_get_rx_stats  =    rpm_get_rx_stats,
27         .mac_get_tx_stats  =    rpm_get_tx_stats,
28         .mac_enadis_rx_pause_fwding =   rpm_lmac_enadis_rx_pause_fwding,
29         .mac_get_pause_frm_status =     rpm_lmac_get_pause_frm_status,
30         .mac_enadis_pause_frm =         rpm_lmac_enadis_pause_frm,
31         .mac_pause_frm_config =         rpm_lmac_pause_frm_config,
32 };
33
34 struct mac_ops *rpm_get_mac_ops(void)
35 {
36         return &rpm_mac_ops;
37 }
38
39 static void rpm_write(rpm_t *rpm, u64 lmac, u64 offset, u64 val)
40 {
41         cgx_write(rpm, lmac, offset, val);
42 }
43
44 static u64 rpm_read(rpm_t *rpm, u64 lmac, u64 offset)
45 {
46         return  cgx_read(rpm, lmac, offset);
47 }
48
49 int rpm_get_nr_lmacs(void *rpmd)
50 {
51         rpm_t *rpm = rpmd;
52
53         return hweight8(rpm_read(rpm, 0, CGXX_CMRX_RX_LMACS) & 0xFULL);
54 }
55
56 void rpm_lmac_enadis_rx_pause_fwding(void *rpmd, int lmac_id, bool enable)
57 {
58         rpm_t *rpm = rpmd;
59         u64 cfg;
60
61         if (!rpm)
62                 return;
63
64         if (enable) {
65                 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
66                 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
67                 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
68         } else {
69                 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
70                 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
71                 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
72         }
73 }
74
75 int rpm_lmac_get_pause_frm_status(void *rpmd, int lmac_id,
76                                   u8 *tx_pause, u8 *rx_pause)
77 {
78         rpm_t *rpm = rpmd;
79         u64 cfg;
80
81         if (!is_lmac_valid(rpm, lmac_id))
82                 return -ENODEV;
83
84         cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
85         *rx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE);
86
87         cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
88         *tx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE);
89         return 0;
90 }
91
92 int rpm_lmac_enadis_pause_frm(void *rpmd, int lmac_id, u8 tx_pause,
93                               u8 rx_pause)
94 {
95         rpm_t *rpm = rpmd;
96         u64 cfg;
97
98         if (!is_lmac_valid(rpm, lmac_id))
99                 return -ENODEV;
100
101         cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
102         cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE;
103         cfg |= rx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE;
104         cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
105         cfg |= rx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
106         rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
107
108         cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
109         cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
110         cfg |= tx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
111         rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
112
113         cfg = rpm_read(rpm, 0, RPMX_CMR_RX_OVR_BP);
114         if (tx_pause) {
115                 cfg &= ~RPMX_CMR_RX_OVR_BP_EN(lmac_id);
116         } else {
117                 cfg |= RPMX_CMR_RX_OVR_BP_EN(lmac_id);
118                 cfg &= ~RPMX_CMR_RX_OVR_BP_BP(lmac_id);
119         }
120         rpm_write(rpm, 0, RPMX_CMR_RX_OVR_BP, cfg);
121         return 0;
122 }
123
124 void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable)
125 {
126         rpm_t *rpm = rpmd;
127         u64 cfg;
128
129         if (enable) {
130                 /* Enable 802.3 pause frame mode */
131                 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
132                 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE;
133                 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
134
135                 /* Enable receive pause frames */
136                 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
137                 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE;
138                 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
139
140                 /* Enable forward pause to TX block */
141                 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
142                 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
143                 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
144
145                 /* Enable pause frames transmission */
146                 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
147                 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
148                 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
149
150                 /* Set pause time and interval */
151                 cfg = rpm_read(rpm, lmac_id,
152                                RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA);
153                 cfg &= ~0xFFFFULL;
154                 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA,
155                           cfg | RPM_DEFAULT_PAUSE_TIME);
156                 /* Set pause interval as the hardware default is too short */
157                 cfg = rpm_read(rpm, lmac_id,
158                                RPMX_MTI_MAC100X_CL01_QUANTA_THRESH);
159                 cfg &= ~0xFFFFULL;
160                 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_CL01_QUANTA_THRESH,
161                           cfg | (RPM_DEFAULT_PAUSE_TIME / 2));
162
163         } else {
164                 /* ALL pause frames received are completely ignored */
165                 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
166                 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE;
167                 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
168
169                 /* Disable forward pause to TX block */
170                 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
171                 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
172                 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
173
174                 /* Disable pause frames transmission */
175                 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
176                 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
177                 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
178         }
179 }
180
181 int rpm_get_rx_stats(void *rpmd, int lmac_id, int idx, u64 *rx_stat)
182 {
183         rpm_t *rpm = rpmd;
184         u64 val_lo, val_hi;
185
186         if (!rpm || lmac_id >= rpm->lmac_count)
187                 return -ENODEV;
188
189         mutex_lock(&rpm->lock);
190
191         /* Update idx to point per lmac Rx statistics page */
192         idx += lmac_id * rpm->mac_ops->rx_stats_cnt;
193
194         /* Read lower 32 bits of counter */
195         val_lo = rpm_read(rpm, 0, RPMX_MTI_STAT_RX_STAT_PAGES_COUNTERX +
196                           (idx * 8));
197
198         /* upon read of lower 32 bits, higher 32 bits are written
199          * to RPMX_MTI_STAT_DATA_HI_CDC
200          */
201         val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC);
202
203         *rx_stat = (val_hi << 32 | val_lo);
204
205         mutex_unlock(&rpm->lock);
206         return 0;
207 }
208
209 int rpm_get_tx_stats(void *rpmd, int lmac_id, int idx, u64 *tx_stat)
210 {
211         rpm_t *rpm = rpmd;
212         u64 val_lo, val_hi;
213
214         if (!rpm || lmac_id >= rpm->lmac_count)
215                 return -ENODEV;
216
217         mutex_lock(&rpm->lock);
218
219         /* Update idx to point per lmac Tx statistics page */
220         idx += lmac_id * rpm->mac_ops->tx_stats_cnt;
221
222         val_lo = rpm_read(rpm, 0, RPMX_MTI_STAT_TX_STAT_PAGES_COUNTERX +
223                             (idx * 8));
224         val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC);
225
226         *tx_stat = (val_hi << 32 | val_lo);
227
228         mutex_unlock(&rpm->lock);
229         return 0;
230 }
231
232 u8 rpm_get_lmac_type(void *rpmd, int lmac_id)
233 {
234         rpm_t *rpm = rpmd;
235         u64 req = 0, resp;
236         int err;
237
238         req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_LINK_STS, req);
239         err = cgx_fwi_cmd_generic(req, &resp, rpm, 0);
240         if (!err)
241                 return FIELD_GET(RESP_LINKSTAT_LMAC_TYPE, resp);
242         return err;
243 }
244
245 int rpm_lmac_internal_loopback(void *rpmd, int lmac_id, bool enable)
246 {
247         rpm_t *rpm = rpmd;
248         u8 lmac_type;
249         u64 cfg;
250
251         if (!rpm || lmac_id >= rpm->lmac_count)
252                 return -ENODEV;
253         lmac_type = rpm->mac_ops->get_lmac_type(rpm, lmac_id);
254         if (lmac_type == LMAC_MODE_100G_R) {
255                 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1);
256
257                 if (enable)
258                         cfg |= RPMX_MTI_PCS_LBK;
259                 else
260                         cfg &= ~RPMX_MTI_PCS_LBK;
261                 rpm_write(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1, cfg);
262         } else {
263                 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_LPCSX_CONTROL1);
264                 if (enable)
265                         cfg |= RPMX_MTI_PCS_LBK;
266                 else
267                         cfg &= ~RPMX_MTI_PCS_LBK;
268                 rpm_write(rpm, lmac_id, RPMX_MTI_LPCSX_CONTROL1, cfg);
269         }
270
271         return 0;
272 }