ldpaa_eth.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. /*
  2. * Copyright (C) 2014 Freescale Semiconductor
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. #include <common.h>
  7. #include <asm/io.h>
  8. #include <asm/types.h>
  9. #include <malloc.h>
  10. #include <net.h>
  11. #include <hwconfig.h>
  12. #include <phy.h>
  13. #include <linux/compat.h>
  14. #include "ldpaa_eth.h"
  15. #undef CONFIG_PHYLIB
  16. static int init_phy(struct eth_device *dev)
  17. {
  18. /*TODO for external PHY */
  19. return 0;
  20. }
  21. static void ldpaa_eth_rx(struct ldpaa_eth_priv *priv,
  22. const struct dpaa_fd *fd)
  23. {
  24. u64 fd_addr;
  25. uint16_t fd_offset;
  26. uint32_t fd_length;
  27. struct ldpaa_fas *fas;
  28. uint32_t status, err;
  29. u32 timeo = (CONFIG_SYS_HZ * 2) / 1000;
  30. u32 time_start;
  31. struct qbman_release_desc releasedesc;
  32. struct qbman_swp *swp = dflt_dpio->sw_portal;
  33. fd_addr = ldpaa_fd_get_addr(fd);
  34. fd_offset = ldpaa_fd_get_offset(fd);
  35. fd_length = ldpaa_fd_get_len(fd);
  36. debug("Rx frame:data addr=0x%p size=0x%x\n", (u64 *)fd_addr, fd_length);
  37. if (fd->simple.frc & LDPAA_FD_FRC_FASV) {
  38. /* Read the frame annotation status word and check for errors */
  39. fas = (struct ldpaa_fas *)
  40. ((uint8_t *)(fd_addr) +
  41. priv->buf_layout.private_data_size);
  42. status = le32_to_cpu(fas->status);
  43. if (status & LDPAA_ETH_RX_ERR_MASK) {
  44. printf("Rx frame error(s): 0x%08x\n",
  45. status & LDPAA_ETH_RX_ERR_MASK);
  46. goto error;
  47. } else if (status & LDPAA_ETH_RX_UNSUPP_MASK) {
  48. printf("Unsupported feature in bitmask: 0x%08x\n",
  49. status & LDPAA_ETH_RX_UNSUPP_MASK);
  50. goto error;
  51. }
  52. }
  53. debug("Rx frame: To Upper layer\n");
  54. net_process_received_packet((uint8_t *)(fd_addr) + fd_offset,
  55. fd_length);
  56. error:
  57. flush_dcache_range(fd_addr, fd_addr + LDPAA_ETH_RX_BUFFER_SIZE);
  58. qbman_release_desc_clear(&releasedesc);
  59. qbman_release_desc_set_bpid(&releasedesc, dflt_dpbp->dpbp_attr.bpid);
  60. time_start = get_timer(0);
  61. do {
  62. /* Release buffer into the QBMAN */
  63. err = qbman_swp_release(swp, &releasedesc, &fd_addr, 1);
  64. } while (get_timer(time_start) < timeo && err == -EBUSY);
  65. if (err == -EBUSY)
  66. printf("Rx frame: QBMAN buffer release fails\n");
  67. return;
  68. }
  69. static int ldpaa_eth_pull_dequeue_rx(struct eth_device *dev)
  70. {
  71. struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)dev->priv;
  72. const struct ldpaa_dq *dq;
  73. const struct dpaa_fd *fd;
  74. int i = 5, err = 0, status;
  75. u32 timeo = (CONFIG_SYS_HZ * 2) / 1000;
  76. u32 time_start;
  77. static struct qbman_pull_desc pulldesc;
  78. struct qbman_swp *swp = dflt_dpio->sw_portal;
  79. while (--i) {
  80. qbman_pull_desc_clear(&pulldesc);
  81. qbman_pull_desc_set_numframes(&pulldesc, 1);
  82. qbman_pull_desc_set_fq(&pulldesc, priv->rx_dflt_fqid);
  83. err = qbman_swp_pull(swp, &pulldesc);
  84. if (err < 0) {
  85. printf("Dequeue frames error:0x%08x\n", err);
  86. continue;
  87. }
  88. time_start = get_timer(0);
  89. do {
  90. dq = qbman_swp_dqrr_next(swp);
  91. } while (get_timer(time_start) < timeo && !dq);
  92. if (dq) {
  93. /* Check for valid frame. If not sent a consume
  94. * confirmation to QBMAN otherwise give it to NADK
  95. * application and then send consume confirmation to
  96. * QBMAN.
  97. */
  98. status = (uint8_t)ldpaa_dq_flags(dq);
  99. if ((status & LDPAA_DQ_STAT_VALIDFRAME) == 0) {
  100. debug("Dequeue RX frames:");
  101. debug("No frame delivered\n");
  102. qbman_swp_dqrr_consume(swp, dq);
  103. continue;
  104. }
  105. fd = ldpaa_dq_fd(dq);
  106. /* Obtain FD and process it */
  107. ldpaa_eth_rx(priv, fd);
  108. qbman_swp_dqrr_consume(swp, dq);
  109. break;
  110. } else {
  111. err = -ENODATA;
  112. debug("No DQRR entries\n");
  113. break;
  114. }
  115. }
  116. return err;
  117. }
  118. static int ldpaa_eth_tx(struct eth_device *net_dev, void *buf, int len)
  119. {
  120. struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
  121. struct dpaa_fd fd;
  122. u64 buffer_start;
  123. int data_offset, err;
  124. u32 timeo = (CONFIG_SYS_HZ * 10) / 1000;
  125. u32 time_start;
  126. struct qbman_swp *swp = dflt_dpio->sw_portal;
  127. struct qbman_eq_desc ed;
  128. struct qbman_release_desc releasedesc;
  129. /* Setup the FD fields */
  130. memset(&fd, 0, sizeof(fd));
  131. data_offset = priv->tx_data_offset;
  132. do {
  133. err = qbman_swp_acquire(dflt_dpio->sw_portal,
  134. dflt_dpbp->dpbp_attr.bpid,
  135. &buffer_start, 1);
  136. } while (err == -EBUSY);
  137. if (err < 0) {
  138. printf("qbman_swp_acquire() failed\n");
  139. return -ENOMEM;
  140. }
  141. debug("TX data: malloc buffer start=0x%p\n", (u64 *)buffer_start);
  142. memcpy(((uint8_t *)(buffer_start) + data_offset), buf, len);
  143. flush_dcache_range(buffer_start, buffer_start +
  144. LDPAA_ETH_RX_BUFFER_SIZE);
  145. ldpaa_fd_set_addr(&fd, (u64)buffer_start);
  146. ldpaa_fd_set_offset(&fd, (uint16_t)(data_offset));
  147. ldpaa_fd_set_bpid(&fd, dflt_dpbp->dpbp_attr.bpid);
  148. ldpaa_fd_set_len(&fd, len);
  149. fd.simple.ctrl = LDPAA_FD_CTRL_ASAL | LDPAA_FD_CTRL_PTA |
  150. LDPAA_FD_CTRL_PTV1;
  151. qbman_eq_desc_clear(&ed);
  152. qbman_eq_desc_set_no_orp(&ed, 0);
  153. qbman_eq_desc_set_qd(&ed, priv->tx_qdid, priv->tx_flow_id, 0);
  154. time_start = get_timer(0);
  155. while (get_timer(time_start) < timeo) {
  156. err = qbman_swp_enqueue(swp, &ed,
  157. (const struct qbman_fd *)(&fd));
  158. if (err != -EBUSY)
  159. break;
  160. }
  161. if (err < 0) {
  162. printf("error enqueueing Tx frame\n");
  163. goto error;
  164. }
  165. return err;
  166. error:
  167. qbman_release_desc_clear(&releasedesc);
  168. qbman_release_desc_set_bpid(&releasedesc, dflt_dpbp->dpbp_attr.bpid);
  169. time_start = get_timer(0);
  170. do {
  171. /* Release buffer into the QBMAN */
  172. err = qbman_swp_release(swp, &releasedesc, &buffer_start, 1);
  173. } while (get_timer(time_start) < timeo && err == -EBUSY);
  174. if (err == -EBUSY)
  175. printf("TX data: QBMAN buffer release fails\n");
  176. return err;
  177. }
  178. static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd)
  179. {
  180. struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
  181. struct dpni_queue_attr rx_queue_attr;
  182. uint8_t mac_addr[6];
  183. int err;
  184. if (net_dev->state == ETH_STATE_ACTIVE)
  185. return 0;
  186. /* DPNI initialization */
  187. err = ldpaa_dpni_setup(priv);
  188. if (err < 0)
  189. goto err_dpni_setup;
  190. err = ldpaa_dpbp_setup();
  191. if (err < 0)
  192. goto err_dpbp_setup;
  193. /* DPNI binding DPBP */
  194. err = ldpaa_dpni_bind(priv);
  195. if (err)
  196. goto err_bind;
  197. err = dpni_get_primary_mac_addr(dflt_mc_io, priv->dpni_handle,
  198. mac_addr);
  199. if (err) {
  200. printf("dpni_get_primary_mac_addr() failed\n");
  201. return err;
  202. }
  203. memcpy(net_dev->enetaddr, mac_addr, 0x6);
  204. /* setup the MAC address */
  205. if (net_dev->enetaddr[0] & 0x01) {
  206. printf("%s: MacAddress is multcast address\n", __func__);
  207. return 1;
  208. }
  209. #ifdef CONFIG_PHYLIB
  210. /* TODO Check this path */
  211. err = phy_startup(priv->phydev);
  212. if (err) {
  213. printf("%s: Could not initialize\n", priv->phydev->dev->name);
  214. return err;
  215. }
  216. #else
  217. priv->phydev->speed = SPEED_1000;
  218. priv->phydev->link = 1;
  219. priv->phydev->duplex = DUPLEX_FULL;
  220. #endif
  221. err = dpni_enable(dflt_mc_io, priv->dpni_handle);
  222. if (err < 0) {
  223. printf("dpni_enable() failed\n");
  224. return err;
  225. }
  226. /* TODO: support multiple Rx flows */
  227. err = dpni_get_rx_flow(dflt_mc_io, priv->dpni_handle, 0, 0,
  228. &rx_queue_attr);
  229. if (err) {
  230. printf("dpni_get_rx_flow() failed\n");
  231. goto err_rx_flow;
  232. }
  233. priv->rx_dflt_fqid = rx_queue_attr.fqid;
  234. err = dpni_get_qdid(dflt_mc_io, priv->dpni_handle, &priv->tx_qdid);
  235. if (err) {
  236. printf("dpni_get_qdid() failed\n");
  237. goto err_qdid;
  238. }
  239. if (!priv->phydev->link)
  240. printf("%s: No link.\n", priv->phydev->dev->name);
  241. return priv->phydev->link ? 0 : -1;
  242. err_qdid:
  243. err_rx_flow:
  244. dpni_disable(dflt_mc_io, priv->dpni_handle);
  245. err_bind:
  246. ldpaa_dpbp_free();
  247. err_dpbp_setup:
  248. dpni_close(dflt_mc_io, priv->dpni_handle);
  249. err_dpni_setup:
  250. return err;
  251. }
  252. static void ldpaa_eth_stop(struct eth_device *net_dev)
  253. {
  254. struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
  255. int err = 0;
  256. if ((net_dev->state == ETH_STATE_PASSIVE) ||
  257. (net_dev->state == ETH_STATE_INIT))
  258. return;
  259. /* Stop Tx and Rx traffic */
  260. err = dpni_disable(dflt_mc_io, priv->dpni_handle);
  261. if (err < 0)
  262. printf("dpni_disable() failed\n");
  263. #ifdef CONFIG_PHYLIB
  264. phy_shutdown(priv->phydev);
  265. #endif
  266. ldpaa_dpbp_free();
  267. dpni_reset(dflt_mc_io, priv->dpni_handle);
  268. dpni_close(dflt_mc_io, priv->dpni_handle);
  269. }
  270. static void ldpaa_dpbp_drain_cnt(int count)
  271. {
  272. uint64_t buf_array[7];
  273. void *addr;
  274. int ret, i;
  275. BUG_ON(count > 7);
  276. do {
  277. ret = qbman_swp_acquire(dflt_dpio->sw_portal,
  278. dflt_dpbp->dpbp_attr.bpid,
  279. buf_array, count);
  280. if (ret < 0) {
  281. printf("qbman_swp_acquire() failed\n");
  282. return;
  283. }
  284. for (i = 0; i < ret; i++) {
  285. addr = (void *)buf_array[i];
  286. debug("Free: buffer addr =0x%p\n", addr);
  287. free(addr);
  288. }
  289. } while (ret);
  290. }
  291. static void ldpaa_dpbp_drain(void)
  292. {
  293. int i;
  294. for (i = 0; i < LDPAA_ETH_NUM_BUFS; i += 7)
  295. ldpaa_dpbp_drain_cnt(7);
  296. }
  297. static int ldpaa_bp_add_7(uint16_t bpid)
  298. {
  299. uint64_t buf_array[7];
  300. u8 *addr;
  301. int i;
  302. struct qbman_release_desc rd;
  303. for (i = 0; i < 7; i++) {
  304. addr = memalign(L1_CACHE_BYTES, LDPAA_ETH_RX_BUFFER_SIZE);
  305. if (!addr) {
  306. printf("addr allocation failed\n");
  307. goto err_alloc;
  308. }
  309. memset(addr, 0x00, LDPAA_ETH_RX_BUFFER_SIZE);
  310. flush_dcache_range((u64)addr,
  311. (u64)(addr + LDPAA_ETH_RX_BUFFER_SIZE));
  312. buf_array[i] = (uint64_t)addr;
  313. debug("Release: buffer addr =0x%p\n", addr);
  314. }
  315. release_bufs:
  316. /* In case the portal is busy, retry until successful.
  317. * This function is guaranteed to succeed in a reasonable amount
  318. * of time.
  319. */
  320. do {
  321. mdelay(1);
  322. qbman_release_desc_clear(&rd);
  323. qbman_release_desc_set_bpid(&rd, bpid);
  324. } while (qbman_swp_release(dflt_dpio->sw_portal, &rd, buf_array, i));
  325. return i;
  326. err_alloc:
  327. if (i)
  328. goto release_bufs;
  329. return 0;
  330. }
  331. static int ldpaa_dpbp_seed(uint16_t bpid)
  332. {
  333. int i;
  334. int count;
  335. for (i = 0; i < LDPAA_ETH_NUM_BUFS; i += 7) {
  336. count = ldpaa_bp_add_7(bpid);
  337. if (count < 7)
  338. printf("Buffer Seed= %d\n", count);
  339. }
  340. return 0;
  341. }
  342. static int ldpaa_dpbp_setup(void)
  343. {
  344. int err;
  345. err = dpbp_open(dflt_mc_io, dflt_dpbp->dpbp_attr.id,
  346. &dflt_dpbp->dpbp_handle);
  347. if (err) {
  348. printf("dpbp_open() failed\n");
  349. goto err_open;
  350. }
  351. err = dpbp_enable(dflt_mc_io, dflt_dpbp->dpbp_handle);
  352. if (err) {
  353. printf("dpbp_enable() failed\n");
  354. goto err_enable;
  355. }
  356. err = dpbp_get_attributes(dflt_mc_io, dflt_dpbp->dpbp_handle,
  357. &dflt_dpbp->dpbp_attr);
  358. if (err) {
  359. printf("dpbp_get_attributes() failed\n");
  360. goto err_get_attr;
  361. }
  362. err = ldpaa_dpbp_seed(dflt_dpbp->dpbp_attr.bpid);
  363. if (err) {
  364. printf("Buffer seeding failed for DPBP %d (bpid=%d)\n",
  365. dflt_dpbp->dpbp_attr.id, dflt_dpbp->dpbp_attr.bpid);
  366. goto err_seed;
  367. }
  368. return 0;
  369. err_seed:
  370. err_get_attr:
  371. dpbp_disable(dflt_mc_io, dflt_dpbp->dpbp_handle);
  372. err_enable:
  373. dpbp_close(dflt_mc_io, dflt_dpbp->dpbp_handle);
  374. err_open:
  375. return err;
  376. }
  377. static void ldpaa_dpbp_free(void)
  378. {
  379. ldpaa_dpbp_drain();
  380. dpbp_disable(dflt_mc_io, dflt_dpbp->dpbp_handle);
  381. dpbp_reset(dflt_mc_io, dflt_dpbp->dpbp_handle);
  382. dpbp_close(dflt_mc_io, dflt_dpbp->dpbp_handle);
  383. }
  384. static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv)
  385. {
  386. int err;
  387. /* and get a handle for the DPNI this interface is associate with */
  388. err = dpni_open(dflt_mc_io, priv->dpni_id, &priv->dpni_handle);
  389. if (err) {
  390. printf("dpni_open() failed\n");
  391. goto err_open;
  392. }
  393. err = dpni_get_attributes(dflt_mc_io, priv->dpni_handle,
  394. &priv->dpni_attrs);
  395. if (err) {
  396. printf("dpni_get_attributes() failed (err=%d)\n", err);
  397. goto err_get_attr;
  398. }
  399. /* Configure our buffers' layout */
  400. priv->buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT |
  401. DPNI_BUF_LAYOUT_OPT_FRAME_STATUS |
  402. DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE;
  403. priv->buf_layout.pass_parser_result = true;
  404. priv->buf_layout.pass_frame_status = true;
  405. priv->buf_layout.private_data_size = LDPAA_ETH_SWA_SIZE;
  406. /* ...rx, ... */
  407. err = dpni_set_rx_buffer_layout(dflt_mc_io, priv->dpni_handle,
  408. &priv->buf_layout);
  409. if (err) {
  410. printf("dpni_set_rx_buffer_layout() failed");
  411. goto err_buf_layout;
  412. }
  413. /* ... tx, ... */
  414. priv->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PARSER_RESULT;
  415. err = dpni_set_tx_buffer_layout(dflt_mc_io, priv->dpni_handle,
  416. &priv->buf_layout);
  417. if (err) {
  418. printf("dpni_set_tx_buffer_layout() failed");
  419. goto err_buf_layout;
  420. }
  421. /* ... tx-confirm. */
  422. priv->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE;
  423. err = dpni_set_tx_conf_buffer_layout(dflt_mc_io, priv->dpni_handle,
  424. &priv->buf_layout);
  425. if (err) {
  426. printf("dpni_set_tx_conf_buffer_layout() failed");
  427. goto err_buf_layout;
  428. }
  429. /* Now that we've set our tx buffer layout, retrieve the minimum
  430. * required tx data offset.
  431. */
  432. err = dpni_get_tx_data_offset(dflt_mc_io, priv->dpni_handle,
  433. &priv->tx_data_offset);
  434. if (err) {
  435. printf("dpni_get_tx_data_offset() failed\n");
  436. goto err_data_offset;
  437. }
  438. /* Warn in case TX data offset is not multiple of 64 bytes. */
  439. WARN_ON(priv->tx_data_offset % 64);
  440. /* Accomodate SWA space. */
  441. priv->tx_data_offset += LDPAA_ETH_SWA_SIZE;
  442. debug("priv->tx_data_offset=%d\n", priv->tx_data_offset);
  443. return 0;
  444. err_data_offset:
  445. err_buf_layout:
  446. err_get_attr:
  447. dpni_close(dflt_mc_io, priv->dpni_handle);
  448. err_open:
  449. return err;
  450. }
  451. static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv)
  452. {
  453. struct dpni_pools_cfg pools_params;
  454. struct dpni_tx_flow_cfg dflt_tx_flow;
  455. int err = 0;
  456. pools_params.num_dpbp = 1;
  457. pools_params.pools[0].dpbp_id = (uint16_t)dflt_dpbp->dpbp_attr.id;
  458. pools_params.pools[0].buffer_size = LDPAA_ETH_RX_BUFFER_SIZE;
  459. err = dpni_set_pools(dflt_mc_io, priv->dpni_handle, &pools_params);
  460. if (err) {
  461. printf("dpni_set_pools() failed\n");
  462. return err;
  463. }
  464. priv->tx_flow_id = DPNI_NEW_FLOW_ID;
  465. memset(&dflt_tx_flow, 0, sizeof(dflt_tx_flow));
  466. dflt_tx_flow.options = DPNI_TX_FLOW_OPT_ONLY_TX_ERROR;
  467. dflt_tx_flow.conf_err_cfg.use_default_queue = 0;
  468. dflt_tx_flow.conf_err_cfg.errors_only = 1;
  469. err = dpni_set_tx_flow(dflt_mc_io, priv->dpni_handle,
  470. &priv->tx_flow_id, &dflt_tx_flow);
  471. if (err) {
  472. printf("dpni_set_tx_flow() failed\n");
  473. return err;
  474. }
  475. return 0;
  476. }
  477. static int ldpaa_eth_netdev_init(struct eth_device *net_dev)
  478. {
  479. int err;
  480. struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
  481. sprintf(net_dev->name, "DPNI%d", priv->dpni_id);
  482. net_dev->iobase = 0;
  483. net_dev->init = ldpaa_eth_open;
  484. net_dev->halt = ldpaa_eth_stop;
  485. net_dev->send = ldpaa_eth_tx;
  486. net_dev->recv = ldpaa_eth_pull_dequeue_rx;
  487. /*
  488. TODO: PHY MDIO information
  489. priv->bus = info->bus;
  490. priv->phyaddr = info->phy_addr;
  491. priv->enet_if = info->enet_if;
  492. */
  493. if (init_phy(net_dev))
  494. return 0;
  495. err = eth_register(net_dev);
  496. if (err < 0) {
  497. printf("eth_register() = %d\n", err);
  498. return err;
  499. }
  500. return 0;
  501. }
  502. int ldpaa_eth_init(struct dprc_obj_desc obj_desc)
  503. {
  504. struct eth_device *net_dev = NULL;
  505. struct ldpaa_eth_priv *priv = NULL;
  506. int err = 0;
  507. /* Net device */
  508. net_dev = (struct eth_device *)malloc(sizeof(struct eth_device));
  509. if (!net_dev) {
  510. printf("eth_device malloc() failed\n");
  511. return -ENOMEM;
  512. }
  513. memset(net_dev, 0, sizeof(struct eth_device));
  514. /* alloc the ldpaa ethernet private struct */
  515. priv = (struct ldpaa_eth_priv *)malloc(sizeof(struct ldpaa_eth_priv));
  516. if (!priv) {
  517. printf("ldpaa_eth_priv malloc() failed\n");
  518. return -ENOMEM;
  519. }
  520. memset(priv, 0, sizeof(struct ldpaa_eth_priv));
  521. net_dev->priv = (void *)priv;
  522. priv->net_dev = (struct eth_device *)net_dev;
  523. priv->dpni_id = obj_desc.id;
  524. err = ldpaa_eth_netdev_init(net_dev);
  525. if (err)
  526. goto err_netdev_init;
  527. debug("ldpaa ethernet: Probed interface %s\n", net_dev->name);
  528. return 0;
  529. err_netdev_init:
  530. free(priv);
  531. net_dev->priv = NULL;
  532. free(net_dev);
  533. return err;
  534. }