common/cnxk: enable and disable BPHY internal loopback
[dpdk.git] / drivers / common / cnxk / roc_bphy_cgx.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4
5 #include <pthread.h>
6
7 #include "roc_api.h"
8 #include "roc_priv.h"
9
10 #define CGX_CMRX_INT                   0x40
11 #define CGX_CMRX_INT_OVERFLW           BIT_ULL(1)
12 /*
13  * CN10K stores number of lmacs in 4 bit filed
14  * in contraty to CN9K which uses only 3 bits.
15  *
16  * In theory masks should differ yet on CN9K
17  * bits beyond specified range contain zeros.
18  *
19  * Hence common longer mask may be used.
20  */
21 #define CGX_CMRX_RX_LMACS       0x128
22 #define CGX_CMRX_RX_LMACS_LMACS GENMASK_ULL(3, 0)
23 #define CGX_CMRX_SCRATCH0       0x1050
24 #define CGX_CMRX_SCRATCH1       0x1058
25
26 static uint64_t
27 roc_bphy_cgx_read(struct roc_bphy_cgx *roc_cgx, uint64_t lmac, uint64_t offset)
28 {
29         int shift = roc_model_is_cn10k() ? 20 : 18;
30         uint64_t base = (uint64_t)roc_cgx->bar0_va;
31
32         return plt_read64(base + (lmac << shift) + offset);
33 }
34
35 static void
36 roc_bphy_cgx_write(struct roc_bphy_cgx *roc_cgx, uint64_t lmac, uint64_t offset,
37                    uint64_t value)
38 {
39         int shift = roc_model_is_cn10k() ? 20 : 18;
40         uint64_t base = (uint64_t)roc_cgx->bar0_va;
41
42         plt_write64(value, base + (lmac << shift) + offset);
43 }
44
45 static void
46 roc_bphy_cgx_ack(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
47                  uint64_t *scr0)
48 {
49         uint64_t val;
50
51         /* clear interrupt */
52         val = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_INT);
53         val |= FIELD_PREP(CGX_CMRX_INT_OVERFLW, 1);
54         roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_INT, val);
55
56         /* ack fw response */
57         *scr0 &= ~SCR0_ETH_EVT_STS_S_ACK;
58         roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_SCRATCH0, *scr0);
59 }
60
61 static int
62 roc_bphy_cgx_wait_for_ownership(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
63                                 uint64_t *scr0)
64 {
65         int tries = 5000;
66         uint64_t scr1;
67
68         do {
69                 *scr0 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH0);
70                 scr1 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH1);
71
72                 if (FIELD_GET(SCR1_OWN_STATUS, scr1) == ETH_OWN_NON_SECURE_SW &&
73                     FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0) == 0)
74                         break;
75
76                 /* clear async events if any */
77                 if (FIELD_GET(SCR0_ETH_EVT_STS_S_EVT_TYPE, *scr0) ==
78                     ETH_EVT_ASYNC &&
79                     FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0))
80                         roc_bphy_cgx_ack(roc_cgx, lmac, scr0);
81
82                 plt_delay_ms(1);
83         } while (--tries);
84
85         return tries ? 0 : -ETIMEDOUT;
86 }
87
88 static int
89 roc_bphy_cgx_wait_for_ack(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
90                           uint64_t *scr0)
91 {
92         int tries = 5000;
93         uint64_t scr1;
94
95         do {
96                 *scr0 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH0);
97                 scr1 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH1);
98
99                 if (FIELD_GET(SCR1_OWN_STATUS, scr1) == ETH_OWN_NON_SECURE_SW &&
100                     FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0))
101                         break;
102
103                 plt_delay_ms(1);
104         } while (--tries);
105
106         return tries ? 0 : -ETIMEDOUT;
107 }
108
109 static int
110 roc_bphy_cgx_intf_req(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
111                       uint64_t scr1, uint64_t *scr0)
112 {
113         uint8_t cmd_id = FIELD_GET(SCR1_ETH_CMD_ID, scr1);
114         int ret;
115
116         pthread_mutex_lock(&roc_cgx->lock);
117
118         /* wait for ownership */
119         ret = roc_bphy_cgx_wait_for_ownership(roc_cgx, lmac, scr0);
120         if (ret) {
121                 plt_err("timed out waiting for ownership");
122                 goto out;
123         }
124
125         /* write command */
126         scr1 |= FIELD_PREP(SCR1_OWN_STATUS, ETH_OWN_FIRMWARE);
127         roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_SCRATCH1, scr1);
128
129         /* wait for command ack */
130         ret = roc_bphy_cgx_wait_for_ack(roc_cgx, lmac, scr0);
131         if (ret) {
132                 plt_err("timed out waiting for response");
133                 goto out;
134         }
135
136         if (cmd_id == ETH_CMD_INTF_SHUTDOWN)
137                 goto out;
138
139         if (FIELD_GET(SCR0_ETH_EVT_STS_S_EVT_TYPE, *scr0) != ETH_EVT_CMD_RESP) {
140                 plt_err("received async event instead of cmd resp event");
141                 ret = -EIO;
142                 goto out;
143         }
144
145         if (FIELD_GET(SCR0_ETH_EVT_STS_S_ID, *scr0) != cmd_id) {
146                 plt_err("received resp for cmd %d expected for cmd %d",
147                         (int)FIELD_GET(SCR0_ETH_EVT_STS_S_ID, *scr0), cmd_id);
148                 ret = -EIO;
149                 goto out;
150         }
151
152         if (FIELD_GET(SCR0_ETH_EVT_STS_S_STAT, *scr0) != ETH_STAT_SUCCESS) {
153                 plt_err("cmd %d failed on cgx%u lmac%u with errcode %d", cmd_id,
154                         roc_cgx->id, lmac,
155                         (int)FIELD_GET(SCR0_ETH_LNK_STS_S_ERR_TYPE, *scr0));
156                 ret = -EIO;
157         }
158
159 out:
160         roc_bphy_cgx_ack(roc_cgx, lmac, scr0);
161
162         pthread_mutex_unlock(&roc_cgx->lock);
163
164         return ret;
165 }
166
167 static unsigned int
168 roc_bphy_cgx_dev_id(struct roc_bphy_cgx *roc_cgx)
169 {
170         uint64_t cgx_id = roc_model_is_cn10k() ? GENMASK_ULL(26, 24) :
171                                                  GENMASK_ULL(25, 24);
172
173         return FIELD_GET(cgx_id, roc_cgx->bar0_pa);
174 }
175
176 int
177 roc_bphy_cgx_dev_init(struct roc_bphy_cgx *roc_cgx)
178 {
179         uint64_t val;
180         int ret;
181
182         if (!roc_cgx || !roc_cgx->bar0_va || !roc_cgx->bar0_pa)
183                 return -EINVAL;
184
185         ret = pthread_mutex_init(&roc_cgx->lock, NULL);
186         if (ret)
187                 return ret;
188
189         val = roc_bphy_cgx_read(roc_cgx, 0, CGX_CMRX_RX_LMACS);
190         val = FIELD_GET(CGX_CMRX_RX_LMACS_LMACS, val);
191         if (roc_model_is_cn9k())
192                 val = GENMASK_ULL(val - 1, 0);
193         roc_cgx->lmac_bmap = val;
194         roc_cgx->id = roc_bphy_cgx_dev_id(roc_cgx);
195
196         return 0;
197 }
198
199 int
200 roc_bphy_cgx_dev_fini(struct roc_bphy_cgx *roc_cgx)
201 {
202         if (!roc_cgx)
203                 return -EINVAL;
204
205         pthread_mutex_destroy(&roc_cgx->lock);
206
207         return 0;
208 }
209
210 static bool
211 roc_bphy_cgx_lmac_exists(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
212 {
213         return (lmac < MAX_LMACS_PER_CGX) &&
214                (roc_cgx->lmac_bmap & BIT_ULL(lmac));
215 }
216
217 static int
218 roc_bphy_cgx_intlbk_ena_dis(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
219                             bool enable)
220 {
221         uint64_t scr1, scr0;
222
223         if (!roc_cgx)
224                 return -EINVAL;
225
226         if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
227                 return -ENODEV;
228
229         scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_INTERNAL_LBK) |
230                FIELD_PREP(SCR1_ETH_CTL_ARGS_ENABLE, enable);
231
232         return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
233 }
234
235 int
236 roc_bphy_cgx_get_linkinfo(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
237                           struct roc_bphy_cgx_link_info *info)
238 {
239         uint64_t scr1, scr0;
240         int ret;
241
242         if (!roc_cgx)
243                 return -EINVAL;
244
245         if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
246                 return -ENODEV;
247
248         if (!info)
249                 return -EINVAL;
250
251         scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_GET_LINK_STS);
252         ret = roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
253         if (ret)
254                 return ret;
255
256         info->link_up = FIELD_GET(SCR0_ETH_LNK_STS_S_LINK_UP, scr0);
257         info->full_duplex = FIELD_GET(SCR0_ETH_LNK_STS_S_FULL_DUPLEX, scr0);
258         info->speed = FIELD_GET(SCR0_ETH_LNK_STS_S_SPEED, scr0);
259         info->an = FIELD_GET(SCR0_ETH_LNK_STS_S_AN, scr0);
260         info->fec = FIELD_GET(SCR0_ETH_LNK_STS_S_FEC, scr0);
261         info->mode = FIELD_GET(SCR0_ETH_LNK_STS_S_MODE, scr0);
262
263         return 0;
264 }
265
266 int
267 roc_bphy_cgx_intlbk_enable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
268 {
269         return roc_bphy_cgx_intlbk_ena_dis(roc_cgx, lmac, true);
270 }
271
272 int
273 roc_bphy_cgx_intlbk_disable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
274 {
275         return roc_bphy_cgx_intlbk_ena_dis(roc_cgx, lmac, false);
276 }