]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
c517771a | 2 | /* |
a6f2a6ea | 3 | * Copyright 2014-2016 Freescale Semiconductor, Inc. |
3f1983d4 | 4 | * Copyright 2017, 2023 NXP |
c517771a PK |
5 | */ |
6 | ||
1eb69ae4 | 7 | #include <cpu_func.h> |
d878ef73 SA |
8 | #include <dm/device_compat.h> |
9 | #include <fsl-mc/fsl_dpmac.h> | |
10 | #include <fsl-mc/ldpaa_wriop.h> | |
11 | #include <hwconfig.h> | |
f7ae49fc | 12 | #include <log.h> |
c517771a | 13 | #include <malloc.h> |
d878ef73 | 14 | #include <miiphy.h> |
c517771a | 15 | #include <net.h> |
c517771a | 16 | #include <phy.h> |
d878ef73 SA |
17 | #include <asm/io.h> |
18 | #include <asm/types.h> | |
eb41d8a1 | 19 | #include <linux/bug.h> |
c517771a | 20 | #include <linux/compat.h> |
c05ed00a | 21 | #include <linux/delay.h> |
401d1c4f | 22 | #include <asm/global_data.h> |
3f1983d4 | 23 | #include <net/ldpaa_eth.h> |
c517771a PK |
24 | #include "ldpaa_eth.h" |
25 | ||
6c2b520a | 26 | #ifdef CONFIG_PHYLIB |
267c5146 IC |
27 | static void init_phy(struct udevice *dev) |
28 | { | |
29 | struct ldpaa_eth_priv *priv = dev_get_priv(dev); | |
30 | ||
31 | priv->phy = dm_eth_phy_connect(dev); | |
32 | ||
33 | if (!priv->phy) | |
34 | return; | |
35 | ||
36 | phy_config(priv->phy); | |
37 | } | |
267c5146 | 38 | #endif |
c517771a | 39 | |
308d67e7 IC |
40 | static void ldpaa_eth_collect_dpni_stats(struct udevice *dev, u64 *data) |
41 | { | |
42 | union dpni_statistics dpni_stats; | |
43 | int dpni_stats_page_size[DPNI_STATISTICS_CNT] = { | |
44 | sizeof(dpni_stats.page_0), | |
45 | sizeof(dpni_stats.page_1), | |
46 | sizeof(dpni_stats.page_2), | |
47 | sizeof(dpni_stats.page_3), | |
48 | sizeof(dpni_stats.page_4), | |
49 | sizeof(dpni_stats.page_5), | |
50 | sizeof(dpni_stats.page_6), | |
51 | }; | |
52 | int j, k, num_cnt, err, i = 0; | |
53 | ||
54 | for (j = 0; j <= 6; j++) { | |
55 | /* We're not interested in pages 4 & 5 for now */ | |
56 | if (j == 4 || j == 5) | |
57 | continue; | |
58 | err = dpni_get_statistics(dflt_mc_io, MC_CMD_NO_FLAGS, | |
59 | dflt_dpni->dpni_handle, | |
207c8157 | 60 | j, 0, &dpni_stats); |
308d67e7 IC |
61 | if (err) { |
62 | memset(&dpni_stats, 0, sizeof(dpni_stats)); | |
63 | printf("dpni_get_stats(%d) failed\n", j); | |
64 | } | |
5038d3e5 | 65 | |
308d67e7 IC |
66 | num_cnt = dpni_stats_page_size[j] / sizeof(u64); |
67 | for (k = 0; k < num_cnt; k++) | |
68 | *(data + i++) = dpni_stats.raw.counter[k]; | |
69 | } | |
70 | } | |
71 | ||
72 | static void ldpaa_eth_add_dpni_stats(struct udevice *dev, u64 *data) | |
2557c5a9 | 73 | { |
308d67e7 | 74 | struct ldpaa_eth_priv *priv = dev_get_priv(dev); |
2557c5a9 | 75 | int i; |
5038d3e5 | 76 | |
308d67e7 IC |
77 | for (i = 0; i < LDPAA_ETH_DPNI_NUM_STATS; i++) |
78 | priv->dpni_stats[i] += data[i]; | |
2557c5a9 | 79 | } |
5038d3e5 | 80 | |
22df08d8 IC |
81 | static void ldpaa_eth_collect_dpmac_stats(struct udevice *dev, u64 *data) |
82 | { | |
83 | struct ldpaa_eth_priv *priv = dev_get_priv(dev); | |
84 | int err, i; | |
85 | u64 value; | |
308d67e7 | 86 | |
22df08d8 IC |
87 | for (i = 0; i < LDPAA_ETH_DPMAC_NUM_STATS; i++) { |
88 | err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, | |
89 | priv->dpmac_handle, i, | |
90 | &value); | |
91 | if (err) | |
92 | printf("dpmac_get_counter(%d) failed\n", i); | |
93 | ||
94 | *(data + i) = value; | |
95 | } | |
96 | } | |
97 | ||
98 | static void ldpaa_eth_add_dpmac_stats(struct udevice *dev, u64 *data) | |
99 | { | |
100 | struct ldpaa_eth_priv *priv = dev_get_priv(dev); | |
101 | int i; | |
102 | ||
103 | for (i = 0; i < LDPAA_ETH_DPMAC_NUM_STATS; i++) | |
104 | priv->dpmac_stats[i] += data[i]; | |
105 | } | |
106 | ||
107 | #ifdef DEBUG | |
308d67e7 | 108 | static void ldpaa_eth_dump_dpni_stats(struct udevice *dev, u64 *data) |
2557c5a9 | 109 | { |
308d67e7 | 110 | int i; |
2557c5a9 | 111 | |
308d67e7 IC |
112 | printf("DPNI counters:\n"); |
113 | for (i = 0; i < LDPAA_ETH_DPNI_NUM_STATS; i++) | |
114 | printf(" %s: %llu\n", ldpaa_eth_dpni_stat_strings[i], data[i]); | |
5038d3e5 | 115 | } |
44b2036e | 116 | |
22df08d8 | 117 | static void ldpaa_eth_dump_dpmac_stats(struct udevice *dev, u64 *data) |
267c5146 | 118 | { |
22df08d8 | 119 | int i; |
44b2036e | 120 | |
22df08d8 IC |
121 | printf("DPMAC counters:\n"); |
122 | for (i = 0; i < LDPAA_ETH_DPMAC_NUM_STATS; i++) | |
123 | printf(" %s: %llu\n", ldpaa_eth_dpmac_stat_strings[i], data[i]); | |
44b2036e | 124 | } |
5038d3e5 PK |
125 | #endif |
126 | ||
c517771a PK |
127 | static void ldpaa_eth_rx(struct ldpaa_eth_priv *priv, |
128 | const struct dpaa_fd *fd) | |
129 | { | |
130 | u64 fd_addr; | |
131 | uint16_t fd_offset; | |
132 | uint32_t fd_length; | |
133 | struct ldpaa_fas *fas; | |
134 | uint32_t status, err; | |
56c57cf7 PK |
135 | u32 timeo = (CONFIG_SYS_HZ * 2) / 1000; |
136 | u32 time_start; | |
c517771a PK |
137 | struct qbman_release_desc releasedesc; |
138 | struct qbman_swp *swp = dflt_dpio->sw_portal; | |
139 | ||
c517771a PK |
140 | fd_addr = ldpaa_fd_get_addr(fd); |
141 | fd_offset = ldpaa_fd_get_offset(fd); | |
142 | fd_length = ldpaa_fd_get_len(fd); | |
143 | ||
144 | debug("Rx frame:data addr=0x%p size=0x%x\n", (u64 *)fd_addr, fd_length); | |
145 | ||
146 | if (fd->simple.frc & LDPAA_FD_FRC_FASV) { | |
147 | /* Read the frame annotation status word and check for errors */ | |
148 | fas = (struct ldpaa_fas *) | |
149 | ((uint8_t *)(fd_addr) + | |
c919ab9e | 150 | dflt_dpni->buf_layout.private_data_size); |
c517771a PK |
151 | status = le32_to_cpu(fas->status); |
152 | if (status & LDPAA_ETH_RX_ERR_MASK) { | |
153 | printf("Rx frame error(s): 0x%08x\n", | |
154 | status & LDPAA_ETH_RX_ERR_MASK); | |
155 | goto error; | |
156 | } else if (status & LDPAA_ETH_RX_UNSUPP_MASK) { | |
157 | printf("Unsupported feature in bitmask: 0x%08x\n", | |
158 | status & LDPAA_ETH_RX_UNSUPP_MASK); | |
159 | goto error; | |
160 | } | |
161 | } | |
162 | ||
163 | debug("Rx frame: To Upper layer\n"); | |
164 | net_process_received_packet((uint8_t *)(fd_addr) + fd_offset, | |
165 | fd_length); | |
166 | ||
167 | error: | |
5753b0f1 | 168 | flush_dcache_range(fd_addr, fd_addr + LDPAA_ETH_RX_BUFFER_SIZE); |
c517771a PK |
169 | qbman_release_desc_clear(&releasedesc); |
170 | qbman_release_desc_set_bpid(&releasedesc, dflt_dpbp->dpbp_attr.bpid); | |
56c57cf7 | 171 | time_start = get_timer(0); |
c517771a PK |
172 | do { |
173 | /* Release buffer into the QBMAN */ | |
174 | err = qbman_swp_release(swp, &releasedesc, &fd_addr, 1); | |
56c57cf7 PK |
175 | } while (get_timer(time_start) < timeo && err == -EBUSY); |
176 | ||
177 | if (err == -EBUSY) | |
178 | printf("Rx frame: QBMAN buffer release fails\n"); | |
179 | ||
c517771a PK |
180 | return; |
181 | } | |
182 | ||
267c5146 IC |
183 | static int ldpaa_eth_pull_dequeue_rx(struct udevice *dev, |
184 | int flags, uchar **packetp) | |
185 | { | |
186 | struct ldpaa_eth_priv *priv = dev_get_priv(dev); | |
c517771a PK |
187 | const struct ldpaa_dq *dq; |
188 | const struct dpaa_fd *fd; | |
b4c3a35d PK |
189 | int i = 5, err = 0, status; |
190 | u32 timeo = (CONFIG_SYS_HZ * 2) / 1000; | |
191 | u32 time_start; | |
c517771a PK |
192 | static struct qbman_pull_desc pulldesc; |
193 | struct qbman_swp *swp = dflt_dpio->sw_portal; | |
194 | ||
c517771a | 195 | while (--i) { |
5753b0f1 PK |
196 | qbman_pull_desc_clear(&pulldesc); |
197 | qbman_pull_desc_set_numframes(&pulldesc, 1); | |
198 | qbman_pull_desc_set_fq(&pulldesc, priv->rx_dflt_fqid); | |
199 | ||
c517771a PK |
200 | err = qbman_swp_pull(swp, &pulldesc); |
201 | if (err < 0) { | |
202 | printf("Dequeue frames error:0x%08x\n", err); | |
203 | continue; | |
204 | } | |
205 | ||
b4c3a35d | 206 | time_start = get_timer(0); |
5753b0f1 | 207 | |
b4c3a35d PK |
208 | do { |
209 | dq = qbman_swp_dqrr_next(swp); | |
210 | } while (get_timer(time_start) < timeo && !dq); | |
5753b0f1 | 211 | |
c517771a PK |
212 | if (dq) { |
213 | /* Check for valid frame. If not sent a consume | |
214 | * confirmation to QBMAN otherwise give it to NADK | |
215 | * application and then send consume confirmation to | |
216 | * QBMAN. | |
217 | */ | |
218 | status = (uint8_t)ldpaa_dq_flags(dq); | |
219 | if ((status & LDPAA_DQ_STAT_VALIDFRAME) == 0) { | |
220 | debug("Dequeue RX frames:"); | |
221 | debug("No frame delivered\n"); | |
222 | ||
223 | qbman_swp_dqrr_consume(swp, dq); | |
0c7c87a4 | 224 | continue; |
c517771a PK |
225 | } |
226 | ||
227 | fd = ldpaa_dq_fd(dq); | |
228 | ||
229 | /* Obtain FD and process it */ | |
230 | ldpaa_eth_rx(priv, fd); | |
231 | qbman_swp_dqrr_consume(swp, dq); | |
232 | break; | |
b4c3a35d PK |
233 | } else { |
234 | err = -ENODATA; | |
235 | debug("No DQRR entries\n"); | |
236 | break; | |
c517771a PK |
237 | } |
238 | } | |
239 | ||
240 | return err; | |
241 | } | |
242 | ||
267c5146 IC |
243 | static int ldpaa_eth_tx(struct udevice *dev, void *buf, int len) |
244 | { | |
245 | struct ldpaa_eth_priv *priv = dev_get_priv(dev); | |
c517771a PK |
246 | struct dpaa_fd fd; |
247 | u64 buffer_start; | |
248 | int data_offset, err; | |
e48df52b PK |
249 | u32 timeo = (CONFIG_SYS_HZ * 10) / 1000; |
250 | u32 time_start; | |
c517771a PK |
251 | struct qbman_swp *swp = dflt_dpio->sw_portal; |
252 | struct qbman_eq_desc ed; | |
e48df52b | 253 | struct qbman_release_desc releasedesc; |
c517771a PK |
254 | |
255 | /* Setup the FD fields */ | |
256 | memset(&fd, 0, sizeof(fd)); | |
257 | ||
258 | data_offset = priv->tx_data_offset; | |
259 | ||
260 | do { | |
261 | err = qbman_swp_acquire(dflt_dpio->sw_portal, | |
262 | dflt_dpbp->dpbp_attr.bpid, | |
263 | &buffer_start, 1); | |
264 | } while (err == -EBUSY); | |
265 | ||
5e9445da | 266 | if (err <= 0) { |
c517771a PK |
267 | printf("qbman_swp_acquire() failed\n"); |
268 | return -ENOMEM; | |
269 | } | |
270 | ||
271 | debug("TX data: malloc buffer start=0x%p\n", (u64 *)buffer_start); | |
272 | ||
273 | memcpy(((uint8_t *)(buffer_start) + data_offset), buf, len); | |
274 | ||
5753b0f1 PK |
275 | flush_dcache_range(buffer_start, buffer_start + |
276 | LDPAA_ETH_RX_BUFFER_SIZE); | |
c517771a PK |
277 | |
278 | ldpaa_fd_set_addr(&fd, (u64)buffer_start); | |
279 | ldpaa_fd_set_offset(&fd, (uint16_t)(data_offset)); | |
280 | ldpaa_fd_set_bpid(&fd, dflt_dpbp->dpbp_attr.bpid); | |
281 | ldpaa_fd_set_len(&fd, len); | |
282 | ||
283 | fd.simple.ctrl = LDPAA_FD_CTRL_ASAL | LDPAA_FD_CTRL_PTA | | |
284 | LDPAA_FD_CTRL_PTV1; | |
285 | ||
286 | qbman_eq_desc_clear(&ed); | |
287 | qbman_eq_desc_set_no_orp(&ed, 0); | |
288 | qbman_eq_desc_set_qd(&ed, priv->tx_qdid, priv->tx_flow_id, 0); | |
e48df52b PK |
289 | |
290 | time_start = get_timer(0); | |
291 | ||
292 | while (get_timer(time_start) < timeo) { | |
293 | err = qbman_swp_enqueue(swp, &ed, | |
294 | (const struct qbman_fd *)(&fd)); | |
295 | if (err != -EBUSY) | |
296 | break; | |
297 | } | |
298 | ||
299 | if (err < 0) { | |
c517771a | 300 | printf("error enqueueing Tx frame\n"); |
e48df52b PK |
301 | goto error; |
302 | } | |
c517771a | 303 | |
c517771a | 304 | return err; |
e48df52b PK |
305 | |
306 | error: | |
307 | qbman_release_desc_clear(&releasedesc); | |
308 | qbman_release_desc_set_bpid(&releasedesc, dflt_dpbp->dpbp_attr.bpid); | |
309 | time_start = get_timer(0); | |
310 | do { | |
311 | /* Release buffer into the QBMAN */ | |
312 | err = qbman_swp_release(swp, &releasedesc, &buffer_start, 1); | |
313 | } while (get_timer(time_start) < timeo && err == -EBUSY); | |
314 | ||
315 | if (err == -EBUSY) | |
316 | printf("TX data: QBMAN buffer release fails\n"); | |
317 | ||
318 | return err; | |
c517771a PK |
319 | } |
320 | ||
a3cb5340 PB |
321 | static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv, |
322 | struct dpmac_link_state *state) | |
323 | { | |
a3cb5340 | 324 | phy_interface_t enet_if; |
15f22ac2 | 325 | struct phy_device *phydev = NULL; |
267c5146 | 326 | int err; |
a3cb5340 | 327 | |
1a048cd6 | 328 | /* let's start off with maximum capabilities */ |
a3cb5340 PB |
329 | enet_if = wriop_get_enet_if(priv->dpmac_id); |
330 | switch (enet_if) { | |
331 | case PHY_INTERFACE_MODE_XGMII: | |
332 | state->rate = SPEED_10000; | |
333 | break; | |
334 | default: | |
335 | state->rate = SPEED_1000; | |
336 | break; | |
337 | } | |
a3cb5340 | 338 | |
267c5146 | 339 | state->up = 1; |
a3cb5340 | 340 | state->options |= DPMAC_LINK_OPT_AUTONEG; |
cde5a844 | 341 | phydev = priv->phy; |
a3cb5340 | 342 | |
267c5146 | 343 | if (phydev) { |
a3cb5340 PB |
344 | err = phy_startup(phydev); |
345 | if (err) { | |
346 | printf("%s: Could not initialize\n", phydev->dev->name); | |
347 | state->up = 0; | |
267c5146 | 348 | } else if (phydev->link) { |
a3cb5340 PB |
349 | state->rate = min(state->rate, (uint32_t)phydev->speed); |
350 | if (!phydev->duplex) | |
351 | state->options |= DPMAC_LINK_OPT_HALF_DUPLEX; | |
352 | if (!phydev->autoneg) | |
353 | state->options &= ~DPMAC_LINK_OPT_AUTONEG; | |
354 | } else { | |
355 | state->up = 0; | |
356 | } | |
357 | } | |
267c5146 IC |
358 | |
359 | if (!phydev) | |
a3cb5340 PB |
360 | state->options &= ~DPMAC_LINK_OPT_AUTONEG; |
361 | ||
362 | if (!state->up) { | |
363 | state->rate = 0; | |
364 | state->options = 0; | |
365 | return -ENOLINK; | |
366 | } | |
367 | ||
368 | return 0; | |
369 | } | |
370 | ||
267c5146 IC |
371 | static int ldpaa_eth_open(struct udevice *dev) |
372 | { | |
c69cda25 | 373 | struct eth_pdata *plat = dev_get_plat(dev); |
267c5146 | 374 | struct ldpaa_eth_priv *priv = dev_get_priv(dev); |
c919ab9e | 375 | struct dpmac_link_state dpmac_link_state = { 0 }; |
5038d3e5 PK |
376 | #ifdef DEBUG |
377 | struct dpni_link_state link_state; | |
378 | #endif | |
6c2b520a | 379 | int err = 0; |
207c8157 IC |
380 | struct dpni_queue d_queue_cfg = { 0 }; |
381 | struct dpni_queue_id d_queue; | |
c517771a | 382 | |
267c5146 IC |
383 | if (eth_is_active(dev)) |
384 | return 0; | |
c517771a | 385 | |
c919ab9e PK |
386 | if (get_mc_boot_status() != 0) { |
387 | printf("ERROR (MC is not booted)\n"); | |
388 | return -ENODEV; | |
389 | } | |
390 | ||
391 | if (get_dpl_apply_status() == 0) { | |
392 | printf("ERROR (DPL is deployed. No device available)\n"); | |
393 | return -ENODEV; | |
394 | } | |
6c2b520a | 395 | |
c919ab9e PK |
396 | /* DPMAC initialization */ |
397 | err = ldpaa_dpmac_setup(priv); | |
398 | if (err < 0) | |
399 | goto err_dpmac_setup; | |
400 | ||
a3cb5340 PB |
401 | err = ldpaa_get_dpmac_state(priv, &dpmac_link_state); |
402 | if (err < 0) | |
afd6c6b4 | 403 | goto err_dpmac_bind; |
6c2b520a | 404 | |
c919ab9e PK |
405 | /* DPMAC binding DPNI */ |
406 | err = ldpaa_dpmac_bind(priv); | |
407 | if (err) | |
afd6c6b4 | 408 | goto err_dpmac_bind; |
c919ab9e | 409 | |
c517771a PK |
410 | /* DPNI initialization */ |
411 | err = ldpaa_dpni_setup(priv); | |
412 | if (err < 0) | |
413 | goto err_dpni_setup; | |
414 | ||
415 | err = ldpaa_dpbp_setup(); | |
416 | if (err < 0) | |
417 | goto err_dpbp_setup; | |
418 | ||
419 | /* DPNI binding DPBP */ | |
420 | err = ldpaa_dpni_bind(priv); | |
421 | if (err) | |
c919ab9e | 422 | goto err_dpni_bind; |
c517771a | 423 | |
267c5146 | 424 | err = dpni_add_mac_addr(dflt_mc_io, MC_CMD_NO_FLAGS, |
207c8157 | 425 | dflt_dpni->dpni_handle, plat->enetaddr, 0, 0, 0); |
c517771a | 426 | if (err) { |
7b2edb8b | 427 | printf("dpni_add_mac_addr() failed\n"); |
c517771a PK |
428 | return err; |
429 | } | |
430 | ||
c919ab9e | 431 | err = dpni_enable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); |
c517771a PK |
432 | if (err < 0) { |
433 | printf("dpni_enable() failed\n"); | |
434 | return err; | |
435 | } | |
436 | ||
c919ab9e PK |
437 | err = dpmac_set_link_state(dflt_mc_io, MC_CMD_NO_FLAGS, |
438 | priv->dpmac_handle, &dpmac_link_state); | |
439 | if (err < 0) { | |
440 | printf("dpmac_set_link_state() failed\n"); | |
441 | return err; | |
442 | } | |
5038d3e5 PK |
443 | |
444 | #ifdef DEBUG | |
2557c5a9 YG |
445 | printf("DPMAC link status: %d - ", dpmac_link_state.up); |
446 | dpmac_link_state.up == 0 ? printf("down\n") : | |
447 | dpmac_link_state.up == 1 ? printf("up\n") : printf("error state\n"); | |
448 | ||
5038d3e5 PK |
449 | err = dpni_get_link_state(dflt_mc_io, MC_CMD_NO_FLAGS, |
450 | dflt_dpni->dpni_handle, &link_state); | |
451 | if (err < 0) { | |
452 | printf("dpni_get_link_state() failed\n"); | |
453 | return err; | |
454 | } | |
455 | ||
2557c5a9 | 456 | printf("DPNI link status: %d - ", link_state.up); |
5038d3e5 PK |
457 | link_state.up == 0 ? printf("down\n") : |
458 | link_state.up == 1 ? printf("up\n") : printf("error state\n"); | |
459 | #endif | |
460 | ||
2557c5a9 YG |
461 | memset(&d_queue, 0, sizeof(struct dpni_queue)); |
462 | err = dpni_get_queue(dflt_mc_io, MC_CMD_NO_FLAGS, | |
463 | dflt_dpni->dpni_handle, DPNI_QUEUE_RX, | |
207c8157 | 464 | 0, 0, &d_queue_cfg, &d_queue); |
c517771a | 465 | if (err) { |
2557c5a9 YG |
466 | printf("dpni_get_queue failed\n"); |
467 | goto err_get_queue; | |
c517771a PK |
468 | } |
469 | ||
2557c5a9 | 470 | priv->rx_dflt_fqid = d_queue.fqid; |
c517771a | 471 | |
c919ab9e | 472 | err = dpni_get_qdid(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle, |
207c8157 | 473 | DPNI_QUEUE_TX, &priv->tx_qdid); |
c517771a PK |
474 | if (err) { |
475 | printf("dpni_get_qdid() failed\n"); | |
476 | goto err_qdid; | |
477 | } | |
478 | ||
a3cb5340 | 479 | return dpmac_link_state.up; |
c517771a | 480 | |
c517771a | 481 | err_qdid: |
2557c5a9 | 482 | err_get_queue: |
c919ab9e PK |
483 | dpni_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); |
484 | err_dpni_bind: | |
c517771a PK |
485 | ldpaa_dpbp_free(); |
486 | err_dpbp_setup: | |
c919ab9e | 487 | dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); |
c517771a | 488 | err_dpni_setup: |
afd6c6b4 | 489 | err_dpmac_bind: |
2557c5a9 YG |
490 | dpmac_close(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpmac_handle); |
491 | dpmac_destroy(dflt_mc_io, | |
492 | dflt_dprc_handle, | |
493 | MC_CMD_NO_FLAGS, priv->dpmac_id); | |
c919ab9e | 494 | err_dpmac_setup: |
c517771a PK |
495 | return err; |
496 | } | |
497 | ||
267c5146 IC |
498 | static void ldpaa_eth_stop(struct udevice *dev) |
499 | { | |
500 | struct ldpaa_eth_priv *priv = dev_get_priv(dev); | |
267c5146 IC |
501 | struct phy_device *phydev = NULL; |
502 | int err = 0; | |
308d67e7 | 503 | u64 *data; |
c517771a | 504 | |
267c5146 IC |
505 | if (!eth_is_active(dev)) |
506 | return; | |
c919ab9e | 507 | |
308d67e7 IC |
508 | data = kzalloc(sizeof(u64) * LDPAA_ETH_DPNI_NUM_STATS, GFP_KERNEL); |
509 | if (data) { | |
510 | ldpaa_eth_collect_dpni_stats(dev, data); | |
511 | ldpaa_eth_add_dpni_stats(dev, data); | |
512 | #ifdef DEBUG | |
513 | ldpaa_eth_dump_dpni_stats(dev, data); | |
514 | #endif | |
515 | } | |
516 | kfree(data); | |
517 | ||
22df08d8 IC |
518 | data = kzalloc(sizeof(u64) * LDPAA_ETH_DPMAC_NUM_STATS, GFP_KERNEL); |
519 | if (data) { | |
520 | ldpaa_eth_collect_dpmac_stats(dev, data); | |
521 | ldpaa_eth_add_dpmac_stats(dev, data); | |
5038d3e5 | 522 | #ifdef DEBUG |
22df08d8 | 523 | ldpaa_eth_dump_dpmac_stats(dev, data); |
5038d3e5 | 524 | #endif |
22df08d8 IC |
525 | } |
526 | kfree(data); | |
5038d3e5 | 527 | |
c919ab9e PK |
528 | err = dprc_disconnect(dflt_mc_io, MC_CMD_NO_FLAGS, |
529 | dflt_dprc_handle, &dpmac_endpoint); | |
530 | if (err < 0) | |
531 | printf("dprc_disconnect() failed dpmac_endpoint\n"); | |
532 | ||
2557c5a9 YG |
533 | err = dpmac_close(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpmac_handle); |
534 | if (err < 0) | |
535 | printf("dpmac_close() failed\n"); | |
536 | ||
537 | err = dpmac_destroy(dflt_mc_io, | |
538 | dflt_dprc_handle, | |
539 | MC_CMD_NO_FLAGS, | |
540 | priv->dpmac_id); | |
c919ab9e PK |
541 | if (err < 0) |
542 | printf("dpmac_destroy() failed\n"); | |
543 | ||
c517771a | 544 | /* Stop Tx and Rx traffic */ |
c919ab9e | 545 | err = dpni_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); |
c517771a PK |
546 | if (err < 0) |
547 | printf("dpni_disable() failed\n"); | |
548 | ||
cde5a844 | 549 | phydev = priv->phy; |
267c5146 IC |
550 | if (phydev) |
551 | phy_shutdown(phydev); | |
c517771a | 552 | |
2557c5a9 | 553 | /* Free DPBP handle and reset. */ |
c517771a | 554 | ldpaa_dpbp_free(); |
2557c5a9 | 555 | |
c919ab9e | 556 | dpni_reset(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); |
2557c5a9 YG |
557 | if (err < 0) |
558 | printf("dpni_reset() failed\n"); | |
559 | ||
c919ab9e | 560 | dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); |
2557c5a9 YG |
561 | if (err < 0) |
562 | printf("dpni_close() failed\n"); | |
c517771a PK |
563 | } |
564 | ||
565 | static void ldpaa_dpbp_drain_cnt(int count) | |
566 | { | |
567 | uint64_t buf_array[7]; | |
568 | void *addr; | |
569 | int ret, i; | |
570 | ||
571 | BUG_ON(count > 7); | |
572 | ||
573 | do { | |
574 | ret = qbman_swp_acquire(dflt_dpio->sw_portal, | |
575 | dflt_dpbp->dpbp_attr.bpid, | |
576 | buf_array, count); | |
577 | if (ret < 0) { | |
578 | printf("qbman_swp_acquire() failed\n"); | |
579 | return; | |
580 | } | |
581 | for (i = 0; i < ret; i++) { | |
582 | addr = (void *)buf_array[i]; | |
583 | debug("Free: buffer addr =0x%p\n", addr); | |
584 | free(addr); | |
585 | } | |
586 | } while (ret); | |
587 | } | |
588 | ||
589 | static void ldpaa_dpbp_drain(void) | |
590 | { | |
591 | int i; | |
592 | for (i = 0; i < LDPAA_ETH_NUM_BUFS; i += 7) | |
593 | ldpaa_dpbp_drain_cnt(7); | |
594 | } | |
595 | ||
596 | static int ldpaa_bp_add_7(uint16_t bpid) | |
597 | { | |
598 | uint64_t buf_array[7]; | |
599 | u8 *addr; | |
600 | int i; | |
601 | struct qbman_release_desc rd; | |
602 | ||
603 | for (i = 0; i < 7; i++) { | |
14480454 | 604 | addr = memalign(LDPAA_ETH_BUF_ALIGN, LDPAA_ETH_RX_BUFFER_SIZE); |
c517771a PK |
605 | if (!addr) { |
606 | printf("addr allocation failed\n"); | |
607 | goto err_alloc; | |
608 | } | |
609 | memset(addr, 0x00, LDPAA_ETH_RX_BUFFER_SIZE); | |
5753b0f1 PK |
610 | flush_dcache_range((u64)addr, |
611 | (u64)(addr + LDPAA_ETH_RX_BUFFER_SIZE)); | |
c517771a PK |
612 | |
613 | buf_array[i] = (uint64_t)addr; | |
614 | debug("Release: buffer addr =0x%p\n", addr); | |
615 | } | |
616 | ||
617 | release_bufs: | |
618 | /* In case the portal is busy, retry until successful. | |
619 | * This function is guaranteed to succeed in a reasonable amount | |
620 | * of time. | |
621 | */ | |
622 | ||
623 | do { | |
624 | mdelay(1); | |
625 | qbman_release_desc_clear(&rd); | |
626 | qbman_release_desc_set_bpid(&rd, bpid); | |
627 | } while (qbman_swp_release(dflt_dpio->sw_portal, &rd, buf_array, i)); | |
628 | ||
629 | return i; | |
630 | ||
631 | err_alloc: | |
632 | if (i) | |
633 | goto release_bufs; | |
634 | ||
635 | return 0; | |
636 | } | |
637 | ||
638 | static int ldpaa_dpbp_seed(uint16_t bpid) | |
639 | { | |
640 | int i; | |
641 | int count; | |
642 | ||
643 | for (i = 0; i < LDPAA_ETH_NUM_BUFS; i += 7) { | |
644 | count = ldpaa_bp_add_7(bpid); | |
645 | if (count < 7) | |
646 | printf("Buffer Seed= %d\n", count); | |
647 | } | |
648 | ||
649 | return 0; | |
650 | } | |
651 | ||
652 | static int ldpaa_dpbp_setup(void) | |
653 | { | |
654 | int err; | |
655 | ||
87457d11 | 656 | err = dpbp_open(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_attr.id, |
c517771a PK |
657 | &dflt_dpbp->dpbp_handle); |
658 | if (err) { | |
659 | printf("dpbp_open() failed\n"); | |
660 | goto err_open; | |
661 | } | |
662 | ||
87457d11 | 663 | err = dpbp_enable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle); |
c517771a PK |
664 | if (err) { |
665 | printf("dpbp_enable() failed\n"); | |
666 | goto err_enable; | |
667 | } | |
668 | ||
87457d11 PK |
669 | err = dpbp_get_attributes(dflt_mc_io, MC_CMD_NO_FLAGS, |
670 | dflt_dpbp->dpbp_handle, | |
c517771a PK |
671 | &dflt_dpbp->dpbp_attr); |
672 | if (err) { | |
673 | printf("dpbp_get_attributes() failed\n"); | |
674 | goto err_get_attr; | |
675 | } | |
676 | ||
677 | err = ldpaa_dpbp_seed(dflt_dpbp->dpbp_attr.bpid); | |
2557c5a9 | 678 | |
c517771a PK |
679 | if (err) { |
680 | printf("Buffer seeding failed for DPBP %d (bpid=%d)\n", | |
681 | dflt_dpbp->dpbp_attr.id, dflt_dpbp->dpbp_attr.bpid); | |
682 | goto err_seed; | |
683 | } | |
684 | ||
685 | return 0; | |
686 | ||
687 | err_seed: | |
688 | err_get_attr: | |
87457d11 | 689 | dpbp_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle); |
c517771a | 690 | err_enable: |
87457d11 | 691 | dpbp_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle); |
c517771a PK |
692 | err_open: |
693 | return err; | |
694 | } | |
695 | ||
696 | static void ldpaa_dpbp_free(void) | |
697 | { | |
698 | ldpaa_dpbp_drain(); | |
87457d11 PK |
699 | dpbp_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle); |
700 | dpbp_reset(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle); | |
701 | dpbp_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle); | |
c517771a PK |
702 | } |
703 | ||
9a696f56 PK |
704 | static int ldpaa_dpmac_version_check(struct fsl_mc_io *mc_io, |
705 | struct ldpaa_eth_priv *priv) | |
706 | { | |
9a696f56 | 707 | int error; |
2557c5a9 YG |
708 | uint16_t major_ver, minor_ver; |
709 | ||
710 | error = dpmac_get_api_version(dflt_mc_io, 0, | |
711 | &major_ver, | |
712 | &minor_ver); | |
713 | if ((major_ver < DPMAC_VER_MAJOR) || | |
714 | (major_ver == DPMAC_VER_MAJOR && minor_ver < DPMAC_VER_MINOR)) { | |
715 | printf("DPMAC version mismatch found %u.%u,", | |
716 | major_ver, minor_ver); | |
717 | printf("supported version is %u.%u\n", | |
718 | DPMAC_VER_MAJOR, DPMAC_VER_MINOR); | |
719 | return error; | |
9a696f56 PK |
720 | } |
721 | ||
722 | return error; | |
723 | } | |
724 | ||
c919ab9e PK |
725 | static int ldpaa_dpmac_setup(struct ldpaa_eth_priv *priv) |
726 | { | |
727 | int err = 0; | |
728 | struct dpmac_cfg dpmac_cfg; | |
729 | ||
730 | dpmac_cfg.mac_id = priv->dpmac_id; | |
2557c5a9 YG |
731 | |
732 | err = dpmac_create(dflt_mc_io, | |
733 | dflt_dprc_handle, | |
734 | MC_CMD_NO_FLAGS, &dpmac_cfg, | |
735 | &priv->dpmac_id); | |
c919ab9e PK |
736 | if (err) |
737 | printf("dpmac_create() failed\n"); | |
9a696f56 PK |
738 | |
739 | err = ldpaa_dpmac_version_check(dflt_mc_io, priv); | |
2557c5a9 | 740 | if (err < 0) { |
9a696f56 | 741 | printf("ldpaa_dpmac_version_check() failed: %d\n", err); |
2557c5a9 YG |
742 | goto err_version_check; |
743 | } | |
744 | ||
745 | err = dpmac_open(dflt_mc_io, | |
746 | MC_CMD_NO_FLAGS, | |
747 | priv->dpmac_id, | |
748 | &priv->dpmac_handle); | |
749 | if (err < 0) { | |
750 | printf("dpmac_open() failed: %d\n", err); | |
751 | goto err_open; | |
752 | } | |
753 | ||
754 | return err; | |
755 | ||
756 | err_open: | |
757 | err_version_check: | |
758 | dpmac_destroy(dflt_mc_io, | |
759 | dflt_dprc_handle, | |
760 | MC_CMD_NO_FLAGS, priv->dpmac_id); | |
9a696f56 | 761 | |
c919ab9e PK |
762 | return err; |
763 | } | |
764 | ||
765 | static int ldpaa_dpmac_bind(struct ldpaa_eth_priv *priv) | |
766 | { | |
767 | int err = 0; | |
768 | struct dprc_connection_cfg dprc_connection_cfg = { | |
769 | /* If both rates are zero the connection */ | |
770 | /* will be configured in "best effort" mode. */ | |
771 | .committed_rate = 0, | |
772 | .max_rate = 0 | |
773 | }; | |
774 | ||
5038d3e5 PK |
775 | #ifdef DEBUG |
776 | struct dprc_endpoint dbg_endpoint; | |
777 | int state = 0; | |
778 | #endif | |
779 | ||
c919ab9e | 780 | memset(&dpmac_endpoint, 0, sizeof(struct dprc_endpoint)); |
192bc694 | 781 | strcpy(dpmac_endpoint.type, "dpmac"); |
c919ab9e PK |
782 | dpmac_endpoint.id = priv->dpmac_id; |
783 | ||
784 | memset(&dpni_endpoint, 0, sizeof(struct dprc_endpoint)); | |
192bc694 | 785 | strcpy(dpni_endpoint.type, "dpni"); |
c919ab9e PK |
786 | dpni_endpoint.id = dflt_dpni->dpni_id; |
787 | ||
788 | err = dprc_connect(dflt_mc_io, MC_CMD_NO_FLAGS, | |
789 | dflt_dprc_handle, | |
790 | &dpmac_endpoint, | |
791 | &dpni_endpoint, | |
792 | &dprc_connection_cfg); | |
5038d3e5 PK |
793 | if (err) |
794 | printf("dprc_connect() failed\n"); | |
795 | ||
796 | #ifdef DEBUG | |
797 | err = dprc_get_connection(dflt_mc_io, MC_CMD_NO_FLAGS, | |
798 | dflt_dprc_handle, &dpni_endpoint, | |
799 | &dbg_endpoint, &state); | |
800 | printf("%s, DPMAC Type= %s\n", __func__, dbg_endpoint.type); | |
801 | printf("%s, DPMAC ID= %d\n", __func__, dbg_endpoint.id); | |
802 | printf("%s, DPMAC State= %d\n", __func__, state); | |
803 | ||
804 | memset(&dbg_endpoint, 0, sizeof(struct dprc_endpoint)); | |
805 | err = dprc_get_connection(dflt_mc_io, MC_CMD_NO_FLAGS, | |
806 | dflt_dprc_handle, &dpmac_endpoint, | |
807 | &dbg_endpoint, &state); | |
808 | printf("%s, DPNI Type= %s\n", __func__, dbg_endpoint.type); | |
809 | printf("%s, DPNI ID= %d\n", __func__, dbg_endpoint.id); | |
810 | printf("%s, DPNI State= %d\n", __func__, state); | |
811 | #endif | |
c919ab9e PK |
812 | return err; |
813 | } | |
814 | ||
c517771a PK |
815 | static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv) |
816 | { | |
817 | int err; | |
818 | ||
819 | /* and get a handle for the DPNI this interface is associate with */ | |
c919ab9e PK |
820 | err = dpni_open(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_id, |
821 | &dflt_dpni->dpni_handle); | |
c517771a PK |
822 | if (err) { |
823 | printf("dpni_open() failed\n"); | |
824 | goto err_open; | |
825 | } | |
87457d11 | 826 | err = dpni_get_attributes(dflt_mc_io, MC_CMD_NO_FLAGS, |
c919ab9e PK |
827 | dflt_dpni->dpni_handle, |
828 | &dflt_dpni->dpni_attrs); | |
c517771a PK |
829 | if (err) { |
830 | printf("dpni_get_attributes() failed (err=%d)\n", err); | |
831 | goto err_get_attr; | |
832 | } | |
833 | ||
834 | /* Configure our buffers' layout */ | |
c919ab9e | 835 | dflt_dpni->buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT | |
c517771a | 836 | DPNI_BUF_LAYOUT_OPT_FRAME_STATUS | |
14480454 PK |
837 | DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE | |
838 | DPNI_BUF_LAYOUT_OPT_DATA_ALIGN; | |
c919ab9e PK |
839 | dflt_dpni->buf_layout.pass_parser_result = true; |
840 | dflt_dpni->buf_layout.pass_frame_status = true; | |
841 | dflt_dpni->buf_layout.private_data_size = LDPAA_ETH_SWA_SIZE; | |
14480454 PK |
842 | /* HW erratum mandates data alignment in multiples of 256 */ |
843 | dflt_dpni->buf_layout.data_align = LDPAA_ETH_BUF_ALIGN; | |
2557c5a9 | 844 | |
c517771a | 845 | /* ...rx, ... */ |
2557c5a9 YG |
846 | err = dpni_set_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS, |
847 | dflt_dpni->dpni_handle, | |
207c8157 | 848 | DPNI_QUEUE_RX, &dflt_dpni->buf_layout); |
c517771a | 849 | if (err) { |
2557c5a9 | 850 | printf("dpni_set_buffer_layout() failed"); |
c517771a PK |
851 | goto err_buf_layout; |
852 | } | |
853 | ||
854 | /* ... tx, ... */ | |
14480454 PK |
855 | /* remove Rx-only options */ |
856 | dflt_dpni->buf_layout.options &= ~(DPNI_BUF_LAYOUT_OPT_DATA_ALIGN | | |
857 | DPNI_BUF_LAYOUT_OPT_PARSER_RESULT); | |
2557c5a9 YG |
858 | err = dpni_set_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS, |
859 | dflt_dpni->dpni_handle, | |
207c8157 | 860 | DPNI_QUEUE_TX, &dflt_dpni->buf_layout); |
c517771a | 861 | if (err) { |
2557c5a9 | 862 | printf("dpni_set_buffer_layout() failed"); |
c517771a PK |
863 | goto err_buf_layout; |
864 | } | |
865 | ||
866 | /* ... tx-confirm. */ | |
c919ab9e | 867 | dflt_dpni->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE; |
2557c5a9 YG |
868 | err = dpni_set_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS, |
869 | dflt_dpni->dpni_handle, | |
207c8157 | 870 | DPNI_QUEUE_TX_CONFIRM, &dflt_dpni->buf_layout); |
c517771a | 871 | if (err) { |
2557c5a9 | 872 | printf("dpni_set_buffer_layout() failed"); |
c517771a PK |
873 | goto err_buf_layout; |
874 | } | |
875 | ||
876 | /* Now that we've set our tx buffer layout, retrieve the minimum | |
877 | * required tx data offset. | |
878 | */ | |
87457d11 | 879 | err = dpni_get_tx_data_offset(dflt_mc_io, MC_CMD_NO_FLAGS, |
c919ab9e PK |
880 | dflt_dpni->dpni_handle, |
881 | &priv->tx_data_offset); | |
c517771a PK |
882 | if (err) { |
883 | printf("dpni_get_tx_data_offset() failed\n"); | |
884 | goto err_data_offset; | |
885 | } | |
886 | ||
887 | /* Warn in case TX data offset is not multiple of 64 bytes. */ | |
888 | WARN_ON(priv->tx_data_offset % 64); | |
889 | ||
890 | /* Accomodate SWA space. */ | |
891 | priv->tx_data_offset += LDPAA_ETH_SWA_SIZE; | |
892 | debug("priv->tx_data_offset=%d\n", priv->tx_data_offset); | |
893 | ||
894 | return 0; | |
895 | ||
896 | err_data_offset: | |
897 | err_buf_layout: | |
898 | err_get_attr: | |
c919ab9e | 899 | dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); |
c517771a PK |
900 | err_open: |
901 | return err; | |
902 | } | |
903 | ||
904 | static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv) | |
905 | { | |
906 | struct dpni_pools_cfg pools_params; | |
2557c5a9 | 907 | struct dpni_queue tx_queue; |
c517771a PK |
908 | int err = 0; |
909 | ||
31a48cf4 | 910 | memset(&pools_params, 0, sizeof(pools_params)); |
c517771a PK |
911 | pools_params.num_dpbp = 1; |
912 | pools_params.pools[0].dpbp_id = (uint16_t)dflt_dpbp->dpbp_attr.id; | |
913 | pools_params.pools[0].buffer_size = LDPAA_ETH_RX_BUFFER_SIZE; | |
c919ab9e PK |
914 | err = dpni_set_pools(dflt_mc_io, MC_CMD_NO_FLAGS, |
915 | dflt_dpni->dpni_handle, &pools_params); | |
c517771a PK |
916 | if (err) { |
917 | printf("dpni_set_pools() failed\n"); | |
918 | return err; | |
919 | } | |
920 | ||
2557c5a9 YG |
921 | memset(&tx_queue, 0, sizeof(struct dpni_queue)); |
922 | ||
923 | err = dpni_set_queue(dflt_mc_io, MC_CMD_NO_FLAGS, | |
924 | dflt_dpni->dpni_handle, | |
207c8157 | 925 | DPNI_QUEUE_TX, 0, 0, 0, &tx_queue); |
c517771a | 926 | |
c517771a | 927 | if (err) { |
2557c5a9 | 928 | printf("dpni_set_queue() failed\n"); |
c517771a PK |
929 | return err; |
930 | } | |
931 | ||
2557c5a9 YG |
932 | err = dpni_set_tx_confirmation_mode(dflt_mc_io, MC_CMD_NO_FLAGS, |
933 | dflt_dpni->dpni_handle, | |
207c8157 | 934 | 0, DPNI_CONF_DISABLE); |
6073548a | 935 | if (err) { |
2557c5a9 | 936 | printf("dpni_set_tx_confirmation_mode() failed\n"); |
6073548a PK |
937 | return err; |
938 | } | |
939 | ||
c517771a PK |
940 | return 0; |
941 | } | |
942 | ||
267c5146 IC |
943 | static int ldpaa_eth_probe(struct udevice *dev) |
944 | { | |
945 | struct ofnode_phandle_args phandle; | |
946 | ||
947 | /* Nothing to do if there is no "phy-handle" in the DTS node */ | |
948 | if (dev_read_phandle_with_args(dev, "phy-handle", NULL, | |
949 | 0, 0, &phandle)) { | |
950 | return 0; | |
951 | } | |
952 | ||
953 | init_phy(dev); | |
954 | ||
955 | return 0; | |
956 | } | |
957 | ||
3f1983d4 | 958 | uint32_t ldpaa_eth_get_dpmac_id(struct udevice *dev) |
267c5146 IC |
959 | { |
960 | int port_node = dev_of_offset(dev); | |
961 | ||
962 | return fdtdec_get_uint(gd->fdt_blob, port_node, "reg", -1); | |
963 | } | |
964 | ||
267c5146 IC |
965 | static int ldpaa_eth_bind(struct udevice *dev) |
966 | { | |
267c5146 IC |
967 | uint32_t dpmac_id; |
968 | char eth_name[16]; | |
969 | int phy_mode = -1; | |
970 | ||
123ca114 | 971 | phy_mode = dev_read_phy_mode(dev); |
ffb0f6f4 | 972 | if (phy_mode == PHY_INTERFACE_MODE_NA) { |
267c5146 IC |
973 | dev_err(dev, "incorrect phy mode\n"); |
974 | return -EINVAL; | |
975 | } | |
976 | ||
977 | dpmac_id = ldpaa_eth_get_dpmac_id(dev); | |
978 | if (dpmac_id == -1) { | |
979 | dev_err(dev, "missing reg field from the dpmac node\n"); | |
980 | return -EINVAL; | |
981 | } | |
982 | ||
123ca114 MB |
983 | sprintf(eth_name, "DPMAC%d@%s", dpmac_id, |
984 | phy_string_for_interface(phy_mode)); | |
267c5146 IC |
985 | device_set_name(dev, eth_name); |
986 | ||
987 | return 0; | |
988 | } | |
989 | ||
d1998a9f | 990 | static int ldpaa_eth_of_to_plat(struct udevice *dev) |
267c5146 IC |
991 | { |
992 | struct ldpaa_eth_priv *priv = dev_get_priv(dev); | |
267c5146 IC |
993 | |
994 | priv->dpmac_id = ldpaa_eth_get_dpmac_id(dev); | |
123ca114 | 995 | priv->phy_mode = dev_read_phy_mode(dev); |
267c5146 IC |
996 | |
997 | return 0; | |
998 | } | |
999 | ||
c6caaafe IC |
1000 | static int ldpaa_eth_get_sset_count(struct udevice *dev) |
1001 | { | |
1002 | return LDPAA_ETH_DPNI_NUM_STATS + LDPAA_ETH_DPMAC_NUM_STATS; | |
1003 | } | |
1004 | ||
1005 | static void ldpaa_eth_get_strings(struct udevice *dev, u8 *data) | |
1006 | { | |
1007 | u8 *p = data; | |
1008 | int i; | |
1009 | ||
1010 | for (i = 0; i < LDPAA_ETH_DPNI_NUM_STATS; i++) { | |
1011 | strlcpy(p, ldpaa_eth_dpni_stat_strings[i], ETH_GSTRING_LEN); | |
1012 | p += ETH_GSTRING_LEN; | |
1013 | } | |
1014 | ||
1015 | for (i = 0; i < LDPAA_ETH_DPMAC_NUM_STATS; i++) { | |
1016 | strlcpy(p, ldpaa_eth_dpmac_stat_strings[i], ETH_GSTRING_LEN); | |
1017 | p += ETH_GSTRING_LEN; | |
1018 | } | |
1019 | } | |
1020 | ||
1021 | static void ldpaa_eth_get_stats(struct udevice *dev, u64 *data) | |
1022 | { | |
1023 | struct ldpaa_eth_priv *priv = dev_get_priv(dev); | |
1024 | int i, j = 0; | |
1025 | ||
1026 | for (i = 0; i < LDPAA_ETH_DPNI_NUM_STATS; i++) | |
1027 | *(data + j++) = priv->dpni_stats[i]; | |
1028 | ||
1029 | for (i = 0; i < LDPAA_ETH_DPMAC_NUM_STATS; i++) | |
1030 | *(data + j++) = priv->dpmac_stats[i]; | |
1031 | } | |
1032 | ||
267c5146 | 1033 | static const struct eth_ops ldpaa_eth_ops = { |
c6caaafe IC |
1034 | .start = ldpaa_eth_open, |
1035 | .send = ldpaa_eth_tx, | |
1036 | .recv = ldpaa_eth_pull_dequeue_rx, | |
1037 | .stop = ldpaa_eth_stop, | |
1038 | .get_sset_count = ldpaa_eth_get_sset_count, | |
1039 | .get_strings = ldpaa_eth_get_strings, | |
1040 | .get_stats = ldpaa_eth_get_stats, | |
267c5146 IC |
1041 | }; |
1042 | ||
1043 | static const struct udevice_id ldpaa_eth_of_ids[] = { | |
1044 | { .compatible = "fsl,qoriq-mc-dpmac" }, | |
1045 | }; | |
1046 | ||
1047 | U_BOOT_DRIVER(ldpaa_eth) = { | |
3f1983d4 | 1048 | .name = LDPAA_ETH_DRIVER_NAME, |
267c5146 IC |
1049 | .id = UCLASS_ETH, |
1050 | .of_match = ldpaa_eth_of_ids, | |
d1998a9f | 1051 | .of_to_plat = ldpaa_eth_of_to_plat, |
267c5146 IC |
1052 | .bind = ldpaa_eth_bind, |
1053 | .probe = ldpaa_eth_probe, | |
1054 | .ops = &ldpaa_eth_ops, | |
41575d8e | 1055 | .priv_auto = sizeof(struct ldpaa_eth_priv), |
caa4daa2 | 1056 | .plat_auto = sizeof(struct eth_pdata), |
267c5146 | 1057 | }; |