source: rtems/c/src/lib/libbsp/powerpc/mpc55xxevb/network/smsc9218i.c @ 9b4422a2

4.115
Last change on this file since 9b4422a2 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 15:09:24

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

  • Property mode set to 100644
File size: 47.8 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup mpc55xx
5 *
6 * @brief SMSC - LAN9218i
7 */
8
9/*
10 * Copyright (c) 2009-2012 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Obere Lagerstr. 30
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.com/license/LICENSE.
21 */
22
23#include <rtems.h>
24
25#include <mpc55xx/regs.h>
26
27#if defined(RTEMS_NETWORKING) && defined(MPC55XX_HAS_SIU)
28
29#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ 1
30#define __BSD_VISIBLE 1
31
32#include <errno.h>
33#include <assert.h>
34#include <stdlib.h>
35#include <stdio.h>
36#include <string.h>
37#include <inttypes.h>
38
39#include <rtems/rtems_bsdnet.h>
40#include <rtems/rtems_mii_ioctl.h>
41
42#include <sys/param.h>
43#include <sys/socket.h>
44#include <sys/sockio.h>
45#include <sys/mbuf.h>
46
47#include <net/if.h>
48#include <net/if_arp.h>
49#include <netinet/in.h>
50#include <netinet/if_ether.h>
51#include <netinet/in_systm.h>
52#include <netinet/ip.h>
53
54#include <mpc55xx/edma.h>
55
56#include <bsp.h>
57#include <bsp/irq.h>
58#include <bsp/utility.h>
59#include <libcpu/powerpc-utility.h>
60#include <bsp/smsc9218i.h>
61
62#if MCLBYTES != 2048
63  #warning "unexpected MCLBYTES value"
64#endif
65
66#define ASSERT_SC(sc) assert((sc) == RTEMS_SUCCESSFUL)
67
68#define SMSC9218I_EVENT_TX RTEMS_EVENT_1
69
70#define SMSC9218I_EVENT_TX_START RTEMS_EVENT_2
71
72#define SMSC9218I_EVENT_TX_ERROR RTEMS_EVENT_3
73
74#define SMSC9218I_EVENT_RX RTEMS_EVENT_4
75
76#define SMSC9218I_EVENT_RX_ERROR RTEMS_EVENT_5
77
78#define SMSC9218I_EVENT_PHY RTEMS_EVENT_6
79
80#define SMSC9218I_EVENT_DMA RTEMS_EVENT_7
81
82#define SMSC9218I_EVENT_DMA_ERROR RTEMS_EVENT_8
83
84/* Adjust by two bytes for proper IP header alignment */
85#define SMSC9218I_RX_DATA_OFFSET 2
86
87#define SMSC9218I_RX_JOBS 32
88
89#define SMSC9218I_TX_JOBS 64
90
91/* Maximum number of fragments per frame, see manual section 3.11.3.2 */
92#define SMSC9218I_TX_FRAGMENT_MAX 86
93
94#if SMSC9218I_TX_JOBS > SMSC9218I_TX_FRAGMENT_MAX
95  #error "too many TX jobs"
96#endif
97
98#define SMSC9218I_IRQ_CFG_GLOBAL_ENABLE \
99  (SMSC9218I_IRQ_CFG_IRQ_EN | SMSC9218I_IRQ_CFG_IRQ_TYPE)
100
101#define SMSC9218I_IRQ_CFG_GLOBAL_DISABLE SMSC9218I_IRQ_CFG_IRQ_TYPE
102
103#define SMSC9218I_EDMA_RX_TCD_CDF 0x10004
104
105#define SMSC9218I_EDMA_RX_TCD_BMF 0x10003
106
107#define SMSC9218I_TCD_BMF_LINK 0x10011
108
109#define SMSC9218I_TCD_BMF_LAST 0x10003
110
111#define SMSC9218I_TCD_BMF_CLEAR 0x10000
112
113#define SMSC9218I_ERROR_INTERRUPTS \
114  (SMSC9218I_INT_TXSO \
115     | SMSC9218I_INT_RWT \
116     | SMSC9218I_INT_RXE \
117     | SMSC9218I_INT_TXE)
118
119#define SMSC9218I_UNLIKELY(x) __builtin_expect((x), 0)
120
121#ifdef DEBUG
122  #define SMSC9218I_PRINTF(...) printf(__VA_ARGS__)
123  #define SMSC9218I_PRINTK(...) printk(__VA_ARGS__)
124#else
125  #define SMSC9218I_PRINTF(...)
126  #define SMSC9218I_PRINTK(...)
127#endif
128
129typedef enum {
130  SMSC9218I_NOT_INITIALIZED,
131  SMSC9218I_CONFIGURED,
132  SMSC9218I_STARTED,
133  SMSC9218I_RUNNING
134} smsc9218i_state;
135
136typedef struct {
137  struct arpcom arpcom;
138  struct rtems_mdio_info mdio;
139  smsc9218i_state state;
140  rtems_id receive_task;
141  rtems_id transmit_task;
142  mpc55xx_edma_channel_entry edma_receive;
143  mpc55xx_edma_channel_entry edma_transmit;
144  unsigned phy_interrupts;
145  unsigned received_frames;
146  unsigned receiver_errors;
147  unsigned receive_interrupts;
148  unsigned receive_dma_interrupts;
149  unsigned receive_too_long_errors;
150  unsigned receive_collision_errors;
151  unsigned receive_crc_errors;
152  unsigned receive_dma_errors;
153  unsigned receive_drop;
154  unsigned receive_watchdog_timeouts;
155  unsigned transmitted_frames;
156  unsigned transmitter_errors;
157  unsigned transmit_interrupts;
158  unsigned transmit_dma_interrupts;
159  unsigned transmit_status_overflows;
160  unsigned transmit_frame_errors;
161  unsigned transmit_dma_errors;
162} smsc9218i_driver_entry;
163
164typedef struct {
165  uint32_t a;
166  uint32_t b;
167} smsc9218i_transmit_command;
168
169typedef struct {
170  struct tcd_t command_tcd_table [SMSC9218I_TX_JOBS];
171  struct tcd_t data_tcd_table [SMSC9218I_TX_JOBS];
172  smsc9218i_transmit_command command_table [SMSC9218I_TX_JOBS];
173  struct mbuf *fragment_table [SMSC9218I_TX_JOBS];
174  struct mbuf *frame;
175  struct mbuf *next_fragment;
176  int empty_index;
177  int transfer_index;
178  int transfer_last_index;
179  int todo_index;
180  int empty;
181  int transfer;
182  int todo;
183  uint32_t frame_length;
184  uint32_t command_b;
185  uint16_t tag;
186  bool done;
187  unsigned frame_compact_count;
188} smsc9218i_transmit_job_control;
189
190typedef struct {
191  struct tcd_t tcd_table [SMSC9218I_RX_JOBS];
192  struct mbuf *mbuf_table [SMSC9218I_RX_JOBS];
193  int consume;
194  int done;
195  int produce;
196} smsc9218i_receive_job_control;
197
198static smsc9218i_receive_job_control smsc_rx_jc __attribute__((aligned (32)));
199
200static void smsc9218i_transmit_dma_done(
201  mpc55xx_edma_channel_entry *channel_entry,
202  uint32_t error_status
203);
204
205static void smsc9218i_receive_dma_done(
206  mpc55xx_edma_channel_entry *e,
207  uint32_t error_status
208);
209
210static smsc9218i_driver_entry smsc9218i_driver_data = {
211  .state = SMSC9218I_NOT_INITIALIZED,
212  .receive_task = RTEMS_ID_NONE,
213  .transmit_task = RTEMS_ID_NONE,
214  .edma_receive = {
215    .channel = SMSC9218I_EDMA_RX_CHANNEL,
216    .done = smsc9218i_receive_dma_done,
217    .id = RTEMS_ID_NONE
218  },
219  .edma_transmit = {
220    .channel = SMSC9218I_EDMA_TX_CHANNEL,
221    .done = smsc9218i_transmit_dma_done,
222    .id = RTEMS_ID_NONE
223  }
224};
225
226static void smsc9218i_mac_wait(volatile smsc9218i_registers *regs)
227{
228  while ((regs->mac_csr_cmd & SMSC9218I_MAC_CSR_CMD_BUSY) != 0) {
229    /* Wait */
230  }
231}
232
233static void smsc9218i_mac_write(
234  volatile smsc9218i_registers *regs,
235  uint32_t address,
236  uint32_t data
237)
238{
239  smsc9218i_mac_wait(regs);
240  regs->mac_csr_data = SMSC9218I_SWAP(data);
241  regs->mac_csr_cmd = SMSC9218I_MAC_CSR_CMD_BUSY
242    | SMSC9218I_MAC_CSR_CMD_ADDR(address);
243  smsc9218i_mac_wait(regs);
244}
245
246static uint32_t smsc9218i_mac_read(
247  volatile smsc9218i_registers *regs,
248  uint32_t address
249)
250{
251  uint32_t mac_csr_data = 0;
252
253  smsc9218i_mac_wait(regs);
254  regs->mac_csr_cmd = SMSC9218I_MAC_CSR_CMD_BUSY
255    | SMSC9218I_MAC_CSR_CMD_READ
256    | SMSC9218I_MAC_CSR_CMD_ADDR(address);
257  smsc9218i_mac_wait(regs);
258  mac_csr_data = regs->mac_csr_data;
259
260  return SMSC9218I_SWAP(mac_csr_data);
261}
262
263static void smsc9218i_phy_wait(volatile smsc9218i_registers *regs)
264{
265  uint32_t mac_mii_acc = 0;
266
267  do {
268    mac_mii_acc = smsc9218i_mac_read(regs, SMSC9218I_MAC_MII_ACC);
269  } while ((mac_mii_acc & SMSC9218I_MAC_MII_ACC_BUSY) != 0);
270}
271
272static void smsc9218i_phy_write(
273  volatile smsc9218i_registers *regs,
274  uint32_t address,
275  uint32_t data
276)
277{
278  smsc9218i_phy_wait(regs);
279  smsc9218i_mac_write(regs, SMSC9218I_MAC_MII_DATA, data);
280  smsc9218i_mac_write(
281    regs,
282    SMSC9218I_MAC_MII_ACC,
283    SMSC9218I_MAC_MII_ACC_PHY_DEFAULT
284      | SMSC9218I_MAC_MII_ACC_BUSY
285      | SMSC9218I_MAC_MII_ACC_WRITE
286      | SMSC9218I_MAC_MII_ACC_ADDR(address)
287  );
288  smsc9218i_phy_wait(regs);
289}
290
291static uint32_t smsc9218i_phy_read(
292  volatile smsc9218i_registers *regs,
293  uint32_t address
294)
295{
296  smsc9218i_phy_wait(regs);
297  smsc9218i_mac_write(
298    regs,
299    SMSC9218I_MAC_MII_ACC,
300    SMSC9218I_MAC_MII_ACC_PHY_DEFAULT
301      | SMSC9218I_MAC_MII_ACC_BUSY
302      | SMSC9218I_MAC_MII_ACC_ADDR(address)
303  );
304  smsc9218i_phy_wait(regs);
305  return smsc9218i_mac_read(regs, SMSC9218I_MAC_MII_DATA);
306}
307
308static void smsc9218i_enable_promiscous_mode(
309  volatile smsc9218i_registers *regs,
310  bool enable
311)
312{
313  uint32_t flags = SMSC9218I_MAC_CR_RXALL | SMSC9218I_MAC_CR_PRMS;
314  uint32_t mac_cr = smsc9218i_mac_read(regs, SMSC9218I_MAC_CR);
315
316  if (enable) {
317    mac_cr |= flags;
318  } else {
319    mac_cr &= ~flags;
320  }
321
322  smsc9218i_mac_write(regs, SMSC9218I_MAC_CR, mac_cr);
323}
324
325#if defined(DEBUG)
326static void smsc9218i_register_dump(volatile smsc9218i_registers *regs)
327{
328  uint32_t reg = 0;
329
330  reg = regs->id_rev;
331  printf(
332    "id_rev: 0x%08" PRIx32 " (ID = 0x%04" PRIx32
333      ", revision = 0x%04" PRIx32 ")\n",
334    SMSC9218I_SWAP(reg),
335    SMSC9218I_ID_REV_GET_ID(reg),
336    SMSC9218I_ID_REV_GET_REV(reg)
337  );
338
339  reg = regs->irq_cfg;
340  printf("irq_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
341
342  reg = regs->int_sts;
343  printf("int_sts: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
344
345  reg = regs->int_en;
346  printf("int_en: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
347
348  reg = regs->byte_test;
349  printf("byte_test: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
350
351  reg = regs->fifo_int;
352  printf("fifo_int: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
353
354  reg = regs->rx_cfg;
355  printf("rx_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
356
357  reg = regs->tx_cfg;
358  printf("tx_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
359
360  reg = regs->hw_cfg;
361  printf("hw_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
362
363  reg = regs->rx_dp_ctl;
364  printf("rx_dp_ctl: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
365
366  reg = regs->rx_fifo_inf;
367  printf(
368    "rx_fifo_inf: 0x%08" PRIx32 " (status used = %" PRIu32
369      ", data used = %" PRIu32 ")\n",
370    SMSC9218I_SWAP(reg),
371    SMSC9218I_RX_FIFO_INF_GET_SUSED(reg),
372    SMSC9218I_RX_FIFO_INF_GET_DUSED(reg)
373  );
374
375  reg = regs->tx_fifo_inf;
376  printf(
377    "tx_fifo_inf: 0x%08" PRIx32 " (status unused = %" PRIu32
378      ", free = %" PRIu32 ")\n",
379    SMSC9218I_SWAP(reg),
380    SMSC9218I_TX_FIFO_INF_GET_SUSED(reg),
381    SMSC9218I_TX_FIFO_INF_GET_FREE(reg)
382  );
383
384  reg = regs->pmt_ctrl;
385  printf("pmt_ctrl: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
386
387  reg = regs->gpio_cfg;
388  printf("gpio_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
389
390  reg = regs->gpt_cfg;
391  printf("gpt_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
392
393  reg = regs->gpt_cnt;
394  printf("gpt_cnt: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
395
396  reg = regs->word_swap;
397  printf("word_swap: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
398
399  reg = regs->free_run;
400  printf("free_run: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
401
402  reg = regs->rx_drop;
403  printf("rx_drop: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
404
405  reg = regs->afc_cfg;
406  printf("afc_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg));
407
408  printf("mac: cr: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_CR));
409  printf("mac: addrh: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_ADDRH));
410  printf("mac: addrl: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_ADDRL));
411  printf("mac: hashh: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_HASHH));
412  printf("mac: hashl: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_HASHL));
413  printf("mac: mii_acc: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_MII_ACC));
414  printf("mac: mii_data: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_MII_DATA));
415  printf("mac: flow: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_FLOW));
416  printf("mac: vlan1: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_VLAN1));
417  printf("mac: vlan2: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_VLAN2));
418  printf("mac: wuff: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_WUFF));
419  printf("mac: wucsr: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_WUCSR));
420
421  printf("phy: bcr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, MII_BMCR));
422  printf("phy: bsr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, MII_BMSR));
423  printf("phy: id1: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, MII_PHYIDR1));
424  printf("phy: id2: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, MII_PHYIDR2));
425  printf("phy: anar: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, MII_ANAR));
426  printf("phy: anlpar: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, MII_ANLPAR));
427  printf("phy: anexpr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, MII_ANER));
428  printf("phy: mcsr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_MCSR));
429  printf("phy: spmodes: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_SPMODES));
430  printf("phy: cisr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_CSIR));
431  printf("phy: isr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_ISR));
432  printf("phy: imr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_IMR));
433  printf("phy: physcsr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_PHYSCSR));
434}
435#endif
436
437static void smsc9218i_flush_tcd(struct tcd_t *tcd)
438{
439  ppc_data_cache_block_store(tcd);
440}
441
442static uint32_t smsc9218i_align_up(uint32_t val)
443{
444  return 4U + ((val - 1U) & ~0x3U);
445}
446
447static void smsc9218i_discard_frame(
448  smsc9218i_driver_entry *e,
449  volatile smsc9218i_registers *regs,
450  uint32_t rx_fifo_status,
451  uint32_t frame_length,
452  uint32_t data_length
453)
454{
455  /* Update error counters */
456  if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR_TOO_LONG) != 0) {
457    ++e->receive_too_long_errors;
458  }
459  if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR_COLLISION) != 0) {
460    ++e->receive_collision_errors;
461  }
462  if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR_CRC) != 0) {
463    ++e->receive_crc_errors;
464  }
465
466  /* Discard frame */
467  if (frame_length > 16) {
468    /* Fast forward */
469    regs->rx_dp_ctl = SMSC9218I_RX_DP_CTRL_FFWD;
470
471    while ((regs->rx_dp_ctl & SMSC9218I_RX_DP_CTRL_FFWD) != 0) {
472      /* Wait */
473    }
474  } else {
475    uint32_t len = data_length / 4;
476    uint32_t i = 0;
477
478    /* Discard data */
479    for (i = 0; i < len; ++i) {
480      regs->rx_fifo_data;
481    }
482  }
483}
484
485static void smsc9218i_setup_receive_dma(
486  smsc9218i_driver_entry *e,
487  volatile smsc9218i_registers *regs,
488  smsc9218i_receive_job_control *jc
489)
490{
491  int c = jc->consume;
492  int p = jc->produce;
493  int np = (p + 1) % SMSC9218I_RX_JOBS;
494  struct tcd_t *first = &jc->tcd_table [p];
495  struct tcd_t *last = NULL;
496
497  while (np != c) {
498    uint32_t rx_fifo_inf = 0;
499    uint32_t status_used = 0;
500
501    /* Clear FIFO level status */
502    regs->int_sts = SMSC9218I_INT_RSFL;
503
504    /* Next FIFO status */
505    rx_fifo_inf = regs->rx_fifo_inf;
506    status_used = SMSC9218I_RX_FIFO_INF_GET_SUSED(rx_fifo_inf);
507
508    if (status_used > 0) {
509      uint32_t status = regs->rx_fifo_status;
510      uint32_t frame_length = SMSC9218I_RX_STS_GET_LENGTH(status);
511      uint32_t data_length = smsc9218i_align_up(
512        SMSC9218I_RX_DATA_OFFSET + frame_length
513      );
514      bool frame_ok = (status & SMSC9218I_RX_STS_ERROR) == 0;
515
516      if (frame_ok) {
517        struct mbuf *m = jc->mbuf_table [p];
518        int mbuf_length = (int) frame_length - ETHER_HDR_LEN - ETHER_CRC_LEN;
519        struct tcd_t *current = &jc->tcd_table [p];
520
521        m->m_len = mbuf_length;
522        m->m_pkthdr.len = mbuf_length;
523
524        current->NBYTES = data_length;
525        smsc9218i_flush_tcd(current);
526
527        last = current;
528        p = np;
529        np = (p + 1) % SMSC9218I_RX_JOBS;
530      } else {
531        smsc9218i_discard_frame(e, regs, status, frame_length, data_length);
532      }
533    } else {
534      break;
535    }
536  }
537
538  jc->produce = p;
539
540  if (last != NULL) {
541    volatile struct tcd_t *channel = &EDMA.TCD [e->edma_receive.channel];
542
543    /* Setup last TCD */
544    last->BMF.R = SMSC9218I_TCD_BMF_LAST;
545    smsc9218i_flush_tcd(last);
546    ppc_synchronize_data();
547
548    /* Start eDMA transfer */
549    channel->SADDR = first->SADDR;
550    channel->SDF.R = first->SDF.R;
551    channel->NBYTES = first->NBYTES;
552    channel->SLAST = first->SLAST;
553    channel->DADDR = first->DADDR;
554    channel->CDF.R = first->CDF.R;
555    channel->DLAST_SGA = first->DLAST_SGA;
556    channel->BMF.R = SMSC9218I_TCD_BMF_CLEAR;
557    channel->BMF.R = first->BMF.R;
558  }
559}
560
561static void smsc9218i_receive_dma_done(
562  mpc55xx_edma_channel_entry *channel_entry,
563  uint32_t error_status
564)
565{
566  rtems_status_code sc = RTEMS_SUCCESSFUL;
567  smsc9218i_driver_entry *e = &smsc9218i_driver_data;
568  volatile smsc9218i_registers *const regs = smsc9218i;
569  smsc9218i_receive_job_control *jc = &smsc_rx_jc;
570
571  SMSC9218I_PRINTK(
572    "edma: id = 0x%08x, error status = 0x%08x\n",
573    channel_entry->id,
574    error_status
575  );
576
577  ++e->receive_dma_interrupts;
578  if (SMSC9218I_UNLIKELY(error_status != 0)) {
579    ++e->receive_dma_errors;
580  }
581
582  sc = rtems_event_send(channel_entry->id, SMSC9218I_EVENT_DMA);
583  ASSERT_SC(sc);
584
585  jc->done = jc->produce;
586
587  smsc9218i_setup_receive_dma(e, regs, jc);
588}
589
590static void smsc9218i_transmit_dma_done(
591  mpc55xx_edma_channel_entry *channel_entry,
592  uint32_t error_status
593)
594{
595  rtems_status_code sc = RTEMS_SUCCESSFUL;
596  smsc9218i_driver_entry *e = &smsc9218i_driver_data;
597  rtems_event_set event = error_status == 0 ?
598    SMSC9218I_EVENT_DMA : SMSC9218I_EVENT_DMA_ERROR;
599
600  SMSC9218I_PRINTK(
601    "edma: id = 0x%08x, error status = 0x%08x\n",
602    channel_entry->id,
603    error_status
604  );
605
606  ++e->transmit_dma_interrupts;
607
608  sc = rtems_event_send(channel_entry->id, event);
609  ASSERT_SC(sc);
610}
611
612static void smsc9218i_interrupt_handler(void *arg)
613{
614  rtems_status_code sc = RTEMS_SUCCESSFUL;
615  smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg;
616  volatile smsc9218i_registers *const regs = smsc9218i;
617  uint32_t int_en = regs->int_en;
618  uint32_t int_sts = regs->int_sts & int_en;
619  #ifdef DEBUG
620    uint32_t irq_cfg = regs->irq_cfg;
621  #endif
622
623  /* Get interrupt status */
624  SMSC9218I_PRINTK(
625    "interrupt: irq_cfg = 0x%08x, int_sts = 0x%08x, int_en = 0x%08x\n",
626    SMSC9218I_SWAP(irq_cfg),
627    SMSC9218I_SWAP(int_sts),
628    SMSC9218I_SWAP(int_en)
629  );
630
631  /* Disable module interrupts */
632  regs->irq_cfg = SMSC9218I_IRQ_CFG_GLOBAL_DISABLE;
633
634  /* Clear external interrupt status */
635  SIU.EISR.R = 1;
636
637  /* Clear interrupts */
638  regs->int_sts = int_sts;
639
640  /* Error interrupts */
641  if (SMSC9218I_UNLIKELY((int_sts & SMSC9218I_ERROR_INTERRUPTS) != 0)) {
642    if ((int_sts & SMSC9218I_INT_TXSO) != 0) {
643      ++e->transmit_status_overflows;
644    }
645    if ((int_sts & SMSC9218I_INT_RWT) != 0) {
646      ++e->receive_watchdog_timeouts;
647    }
648    if ((int_sts & SMSC9218I_INT_RXE) != 0) {
649      ++e->receiver_errors;
650    }
651    if ((int_sts & SMSC9218I_INT_TXE) != 0) {
652      ++e->transmitter_errors;
653    }
654  }
655
656  /* Check receive interrupts */
657  if ((int_sts & SMSC9218I_INT_RSFL) != 0) {
658    smsc9218i_receive_job_control *jc = &smsc_rx_jc;
659
660    int_en &= ~SMSC9218I_INT_RSFL;
661    ++e->receive_interrupts;
662    smsc9218i_setup_receive_dma(e, regs, jc);
663  }
664
665  /* Check PHY interrupts */
666  if (SMSC9218I_UNLIKELY((int_sts & SMSC9218I_INT_PHY) != 0)) {
667    SMSC9218I_PRINTK("interrupt: phy\n");
668    int_en &= ~SMSC9218I_INT_PHY;
669    ++e->phy_interrupts;
670    sc = rtems_event_send(e->receive_task, SMSC9218I_EVENT_PHY);
671    ASSERT_SC(sc);
672  }
673
674  /* Check transmit interrupts */
675  if ((int_sts & SMSC9218I_INT_TDFA) != 0) {
676    SMSC9218I_PRINTK("interrupt: transmit\n");
677    int_en &= ~SMSC9218I_INT_TDFA;
678    ++e->transmit_interrupts;
679    sc = rtems_event_send(e->transmit_task, SMSC9218I_EVENT_TX);
680    ASSERT_SC(sc);
681  }
682
683  /* Update interrupt enable */
684  regs->int_en = int_en;
685
686  /* Enable module interrupts */
687  regs->irq_cfg = SMSC9218I_IRQ_CFG_GLOBAL_ENABLE;
688}
689
690static void smsc9218i_enable_transmit_interrupts(
691  volatile smsc9218i_registers *regs
692)
693{
694  rtems_interrupt_level level;
695
696  rtems_interrupt_disable(level);
697  regs->int_en |= SMSC9218I_INT_TDFA;
698  rtems_interrupt_enable(level);
699}
700
701static void smsc9218i_enable_phy_interrupts(
702  volatile smsc9218i_registers *regs
703)
704{
705  rtems_interrupt_level level;
706
707  rtems_interrupt_disable(level);
708  regs->int_en |= SMSC9218I_INT_PHY;
709  rtems_interrupt_enable(level);
710}
711
712static void smsc9218i_phy_clear_interrupts(
713  volatile smsc9218i_registers *regs
714)
715{
716  smsc9218i_phy_read(regs, SMSC9218I_PHY_ISR);
717}
718
719static bool smsc9218i_media_status(smsc9218i_driver_entry *e, int *media)
720{
721  struct ifnet *ifp = &e->arpcom.ac_if;
722
723  *media = IFM_MAKEWORD(0, 0, 0, SMSC9218I_MAC_MII_ACC_PHY_DEFAULT);
724
725  return (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t) media) == 0;
726}
727
728static void smsc9218i_media_status_change(
729  smsc9218i_driver_entry *e,
730  volatile smsc9218i_registers *regs
731)
732{
733  int media = 0;
734  bool media_ok = false;
735  uint32_t mac_cr = 0;
736
737  smsc9218i_phy_clear_interrupts(regs);
738  smsc9218i_enable_phy_interrupts(regs);
739
740  media_ok = smsc9218i_media_status(e, &media);
741  mac_cr = smsc9218i_mac_read(regs, SMSC9218I_MAC_CR);
742  if (media_ok && (IFM_OPTIONS(media) & IFM_FDX) == 0) {
743    mac_cr &= ~SMSC9218I_MAC_CR_FDPX;
744  } else {
745    mac_cr |= SMSC9218I_MAC_CR_FDPX;
746  }
747  smsc9218i_mac_write(regs, SMSC9218I_MAC_CR, mac_cr);
748}
749
750static void smsc9218i_new_mbuf(
751  struct ifnet *ifp,
752  smsc9218i_receive_job_control *jc,
753  int i
754)
755{
756  struct mbuf *m = m_gethdr(M_WAIT, MT_DATA);
757  struct tcd_t *tcd = &jc->tcd_table [i];
758  char *data = NULL;
759
760  m->m_pkthdr.rcvif = ifp;
761  MCLGET(m, M_WAIT);
762
763  data = mtod(m, char *);
764  m->m_data = data + SMSC9218I_RX_DATA_OFFSET + ETHER_HDR_LEN;
765
766  jc->mbuf_table [i] = m;
767
768  tcd->DADDR = (uint32_t) data;
769  tcd->BMF.R = SMSC9218I_TCD_BMF_LINK;
770
771  /* FIXME: This is maybe a problem in case of a lot of small frames */
772  rtems_cache_invalidate_multiple_data_lines(
773    data,
774    SMSC9218I_RX_DATA_OFFSET + ETHER_HDR_LEN + ETHERMTU + ETHER_CRC_LEN
775  );
776}
777
778static void smsc9218i_init_receive_jobs(
779  smsc9218i_driver_entry *e,
780  volatile smsc9218i_registers *regs,
781  smsc9218i_receive_job_control *jc
782)
783{
784  rtems_status_code sc = RTEMS_SUCCESSFUL;
785  struct ifnet *ifp = &e->arpcom.ac_if;
786  int i = 0;
787
788  /* Obtain receive eDMA channel */
789  e->edma_receive.id = e->receive_task;
790  sc = mpc55xx_edma_obtain_channel(
791    &e->edma_receive,
792    MPC55XX_INTC_DEFAULT_PRIORITY
793  );
794  ASSERT_SC(sc);
795
796  for (i = 0; i < SMSC9218I_RX_JOBS; ++i) {
797    struct tcd_t *tcd = &jc->tcd_table [i];
798    struct tcd_t *next_tcd = &jc->tcd_table [(i + 1) % SMSC9218I_RX_JOBS];
799
800    tcd->SADDR = (uint32_t) &regs->rx_fifo_data;
801    tcd->SDF.B.SSIZE = 0x2;
802    tcd->SDF.B.DSIZE = 0x2;
803    tcd->CDF.B.CITER = 1;
804    tcd->CDF.B.DOFF = 4;
805    tcd->DLAST_SGA = (int32_t) next_tcd;
806
807    smsc9218i_new_mbuf(ifp, jc, i);
808  }
809}
810
811static void smsc9218i_ether_input(
812  smsc9218i_driver_entry *e,
813  volatile smsc9218i_registers *regs,
814  smsc9218i_receive_job_control *jc
815)
816{
817  rtems_interrupt_level level;
818  struct ifnet *ifp = &e->arpcom.ac_if;
819  int c = jc->consume;
820  int d = jc->done;
821
822  while (c != d) {
823    struct mbuf *m = jc->mbuf_table [c];
824    struct ether_header *eh = (struct ether_header *)
825      (mtod(m, char *) - ETHER_HDR_LEN);
826
827    ++e->received_frames;
828    ether_input(ifp, eh, m);
829    smsc9218i_new_mbuf(ifp, jc, c);
830
831    c = (c + 1) % SMSC9218I_RX_JOBS;
832  }
833
834  jc->consume = c;
835
836  rtems_interrupt_disable(level);
837  /* Enabling the receive interrupts while the DMA is active leads to chaos */
838  if (c == jc->produce) {
839    regs->int_en |= SMSC9218I_INT_RSFL;
840  }
841  rtems_interrupt_enable(level);
842}
843
844static void smsc9218i_receive_task(void *arg)
845{
846  rtems_status_code sc = RTEMS_SUCCESSFUL;
847  rtems_interrupt_level level;
848  smsc9218i_receive_job_control *jc = &smsc_rx_jc;
849  smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg;
850  volatile smsc9218i_registers *const regs = smsc9218i;
851  uint32_t mac_cr = 0;
852
853  smsc9218i_init_receive_jobs(e, regs, jc);
854
855  /* Configure receiver */
856  regs->rx_cfg = SMSC9218I_RX_CFG_END_ALIGN_4
857    | SMSC9218I_RX_CFG_DOFF(SMSC9218I_RX_DATA_OFFSET);
858
859  /* Enable MAC receiver */
860  mac_cr = smsc9218i_mac_read(regs, SMSC9218I_MAC_CR);
861  mac_cr |= SMSC9218I_MAC_CR_RXEN;
862  smsc9218i_mac_write(regs, SMSC9218I_MAC_CR, mac_cr);
863
864  /* Enable receive interrupts */
865  rtems_interrupt_disable(level);
866  regs->int_en |= SMSC9218I_INT_RSFL;
867  rtems_interrupt_enable(level);
868
869  /* Enable PHY interrupts */
870  smsc9218i_phy_write(
871    regs,
872    SMSC9218I_PHY_IMR,
873    SMSC9218I_PHY_IMR_INT4 | SMSC9218I_PHY_IMR_INT6
874  );
875  smsc9218i_enable_phy_interrupts(regs);
876
877  while (true) {
878    rtems_event_set events;
879
880    sc = rtems_bsdnet_event_receive(
881      SMSC9218I_EVENT_DMA | SMSC9218I_EVENT_PHY,
882      RTEMS_EVENT_ANY | RTEMS_WAIT,
883      RTEMS_NO_TIMEOUT,
884      &events
885    );
886    ASSERT_SC(sc);
887
888    if ((events & SMSC9218I_EVENT_DMA) != 0) {
889      smsc9218i_ether_input(e, regs, jc);
890    }
891
892    if ((events & SMSC9218I_EVENT_PHY) != 0) {
893      smsc9218i_media_status_change(e, regs);
894    }
895  }
896}
897
898#if defined(DEBUG)
899static void smsc9218i_transmit_job_dump(
900  smsc9218i_transmit_job_control *jc,
901  const char *msg
902)
903{
904  char out [SMSC9218I_TX_JOBS + 1];
905  int c = 0;
906  int s = 0;
907
908  out [SMSC9218I_TX_JOBS] = '\0';
909
910  memset(out, '?', SMSC9218I_TX_JOBS);
911
912  c = jc->todo_index;
913  s = jc->empty;
914  while (s > 0) {
915    out [c] = 'E';
916    --s;
917    c = (c + 1) % SMSC9218I_TX_JOBS;
918  }
919
920  c = jc->transfer_index;
921  s = jc->todo;
922  while (s > 0) {
923    out [c] = 'T';
924    --s;
925    c = (c + 1) % SMSC9218I_TX_JOBS;
926  }
927
928  c = jc->empty_index;
929  s = jc->transfer;
930  while (s > 0) {
931    out [c] = 'D';
932    --s;
933    c = (c + 1) % SMSC9218I_TX_JOBS;
934  }
935
936  printf(
937    "tx: %s: %02u:%02u:%02u %s\n",
938    msg,
939    jc->empty,
940    jc->todo,
941    jc->transfer,
942    out
943  );
944}
945#endif /* defined(DEBUG) */
946
947static struct mbuf *smsc9218i_compact_frame(
948  smsc9218i_transmit_job_control *jc,
949  uint32_t frame_length
950)
951{
952  struct mbuf *old_m = jc->frame;
953  struct mbuf *new_m = m_gethdr(M_WAIT, MT_DATA);
954  char *data = NULL;
955
956  ++jc->frame_compact_count;
957
958  MCLGET(new_m, M_WAIT);
959  data = mtod(new_m, char *);
960
961  new_m->m_len = (int) frame_length;
962  new_m->m_pkthdr.len = (int) frame_length;
963
964  while (old_m != NULL) {
965    size_t len = (size_t) old_m->m_len;
966    memcpy(data, mtod(old_m, void *), len);
967    data += len;
968    old_m = m_free(old_m);
969  }
970
971  jc->frame = new_m;
972
973  return new_m;
974}
975
976static struct mbuf *smsc9218i_next_transmit_fragment(
977  struct ifnet *ifp,
978  smsc9218i_transmit_job_control *jc
979)
980{
981  struct mbuf *m = jc->next_fragment;
982
983  if (m != NULL) {
984    /* Next fragment is from the current frame */
985    jc->next_fragment = m->m_next;
986  } else {
987    /* Dequeue first fragment of the next frame */
988    IF_DEQUEUE(&ifp->if_snd, m);
989
990    /* Update frame head */
991    jc->frame = m;
992
993    if (m != NULL) {
994      struct mbuf *n = m;
995      struct mbuf *p = NULL;
996      uint32_t frame_length = 0;
997      unsigned fragments = 0;
998      bool tiny = false;
999
1000      /* Calculate frame length and fragment number */
1001      do {
1002        int len = n->m_len;
1003
1004        if (len > 0) {
1005          ++fragments;
1006          frame_length += (uint32_t) len;
1007          tiny = tiny || len < 4;
1008
1009          /* Next fragment */
1010          p = n;
1011          n = n->m_next;
1012        } else {
1013          /* Discard empty fragment and get next */
1014          n = m_free(n);
1015
1016          /* Remove fragment from list */
1017          if (p != NULL) {
1018            p->m_next = n;
1019          } else {
1020            jc->frame = n;
1021          }
1022        }
1023      } while (n != NULL);
1024
1025      if (SMSC9218I_UNLIKELY(tiny || fragments > SMSC9218I_TX_JOBS)) {
1026        fragments = 1;
1027        m = smsc9218i_compact_frame(jc, frame_length);
1028      }
1029
1030      /* Set frame length */
1031      jc->frame_length = frame_length;
1032
1033      /* Update next fragment */
1034      jc->next_fragment = jc->frame->m_next;
1035
1036      /* Update tag */
1037      ++jc->tag;
1038
1039      /* Command B */
1040      jc->command_b = ((uint32_t) SMSC9218I_TX_B_TAG(jc->tag))
1041        | SMSC9218I_TX_B_FRAME_LENGTH(jc->frame_length);
1042
1043      SMSC9218I_PRINTF(
1044        "tx: next frame: tag = %i, frame length = %" PRIu32
1045          ", fragments = %u\n",
1046        jc->tag,
1047        frame_length,
1048        fragments
1049      );
1050    } else {
1051      /* The transmit queue is empty, we have no next fragment */
1052      jc->next_fragment = NULL;
1053
1054      /* Interface is now inactive */
1055      ifp->if_flags &= ~IFF_OACTIVE;
1056
1057      /* Transmit task may wait for events */
1058      jc->done = true;
1059
1060      SMSC9218I_PRINTF("tx: inactive\n");
1061    }
1062  }
1063
1064  return m;
1065}
1066
1067static void smsc9218i_transmit_create_jobs(
1068  smsc9218i_transmit_job_control *jc,
1069  volatile smsc9218i_registers *const regs,
1070  struct ifnet *ifp
1071)
1072{
1073  int n = jc->empty;
1074
1075  if (n > 0) {
1076    int c = jc->todo_index;
1077    int i = 0;
1078
1079    #ifdef DEBUG
1080      smsc9218i_transmit_job_dump(jc, "create");
1081    #endif
1082
1083    for (i = 0; i < n; ++i) {
1084      struct mbuf *m = smsc9218i_next_transmit_fragment(ifp, jc);
1085
1086      if (m != NULL) {
1087        uint32_t first = m == jc->frame ? SMSC9218I_TX_A_FIRST : 0;
1088        uint32_t last = m->m_next == NULL ? SMSC9218I_TX_A_LAST : 0;
1089        uint32_t fragment_length = (uint32_t) m->m_len;
1090        uint32_t fragment_misalign = (uint32_t) (mtod(m, uintptr_t) % 4);
1091        uint32_t data_length = fragment_misalign + fragment_length;
1092        uint32_t data_misalign = data_length % 4;
1093        uint32_t data = (uint32_t) (mtod(m, char *) - fragment_misalign);
1094
1095        /* Align data length on four byte boundary */
1096        if (data_misalign > 0) {
1097          data_length += 4 - data_misalign;
1098        }
1099
1100        /* Cache flush for fragment data */
1101        rtems_cache_flush_multiple_data_lines(
1102          (const void *) data,
1103          data_length
1104        );
1105
1106        /* Remember fragement */
1107        jc->fragment_table [c] = m;
1108
1109        /* Command A and B */
1110        jc->command_table [c].a = SMSC9218I_TX_A_END_ALIGN_4
1111          | SMSC9218I_TX_A_DOFF(fragment_misalign)
1112          | SMSC9218I_TX_A_FRAGMENT_LENGTH(fragment_length)
1113          | first
1114          | last;
1115        jc->command_table [c].b = jc->command_b;
1116
1117        /* Data TCD */
1118        jc->data_tcd_table [c].SADDR = data;
1119        jc->data_tcd_table [c].NBYTES = data_length;
1120
1121        SMSC9218I_PRINTF("tx: create: index = %u\n", c);
1122      } else {
1123        /* Nothing to do */
1124        break;
1125      }
1126
1127      c = (c + 1) % SMSC9218I_TX_JOBS;
1128    }
1129
1130    /* Increment jobs to do */
1131    jc->todo += i;
1132
1133    /* Decrement empty count */
1134    jc->empty -= i;
1135
1136    /* Update todo index */
1137    jc->todo_index = c;
1138
1139    #ifdef DEBUG
1140      smsc9218i_transmit_job_dump(jc, "create done");
1141    #endif
1142  } else {
1143    /* Transmit task may wait for events */
1144    jc->done = true;
1145  }
1146}
1147
1148static void smsc9218i_transmit_do_jobs(
1149  smsc9218i_transmit_job_control *jc,
1150  volatile smsc9218i_registers *const regs,
1151  smsc9218i_driver_entry *e
1152)
1153{
1154  if (jc->transfer == 0) {
1155    uint32_t tx_fifo_inf = regs->tx_fifo_inf;
1156    uint32_t data_free = SMSC9218I_TX_FIFO_INF_GET_FREE(tx_fifo_inf);
1157    int c = jc->transfer_index;
1158    int last_index = c;
1159    int i = 0;
1160    int n = jc->todo;
1161
1162    #ifdef DEBUG
1163      smsc9218i_transmit_job_dump(jc, "transfer");
1164    #endif
1165
1166    for (i = 0; i < n; ++i) {
1167      struct tcd_t *tcd = &jc->data_tcd_table [c];
1168      uint32_t data_length = tcd->NBYTES + 14;
1169
1170      if (data_length <= data_free) {
1171        /* Reduce free FIFO space */
1172        data_free -= data_length;
1173
1174        /* Index of last TCD */
1175        last_index = c;
1176
1177        /* Cache flush for data TCD */
1178        smsc9218i_flush_tcd(tcd);
1179      } else {
1180        break;
1181      }
1182
1183      c = (c + 1) % SMSC9218I_TX_JOBS;
1184    }
1185
1186    if (i > 0) {
1187      volatile struct tcd_t *channel = &EDMA.TCD [e->edma_transmit.channel];
1188      struct tcd_t *start = &jc->command_tcd_table [jc->transfer_index];
1189      struct tcd_t *last = &jc->data_tcd_table [last_index];
1190
1191      /* New transfer index */
1192      jc->transfer_index = c;
1193
1194      /* New last transfer index */
1195      jc->transfer_last_index = last_index;
1196
1197      /* Set jobs in transfer */
1198      jc->transfer = i;
1199
1200      /* Decrement jobs to do */
1201      jc->todo -= i;
1202
1203      /* Cache flush for command table */
1204      rtems_cache_flush_multiple_data_lines(
1205        jc->command_table,
1206        sizeof(jc->command_table)
1207      );
1208
1209      /* Enable interrupt for last data TCD */
1210      last->BMF.R = SMSC9218I_TCD_BMF_LAST;
1211      smsc9218i_flush_tcd(last);
1212      ppc_synchronize_data();
1213
1214      /* Start eDMA transfer */
1215      channel->SADDR = start->SADDR;
1216      channel->SDF.R = start->SDF.R;
1217      channel->NBYTES = start->NBYTES;
1218      channel->SLAST = start->SLAST;
1219      channel->DADDR = start->DADDR;
1220      channel->CDF.R = start->CDF.R;
1221      channel->DLAST_SGA = start->DLAST_SGA;
1222      channel->BMF.R = SMSC9218I_TCD_BMF_CLEAR;
1223      channel->BMF.R = start->BMF.R;
1224
1225      /* Transmit task may wait for events */
1226      jc->done = true;
1227    } else if (n > 0) {
1228      /* We need to wait until the FIFO has more free space */
1229      smsc9218i_enable_transmit_interrupts(regs);
1230
1231      /* Transmit task may wait for events */
1232      jc->done = true;
1233    }
1234
1235    #ifdef DEBUG
1236      smsc9218i_transmit_job_dump(jc, "transfer done");
1237    #endif
1238  }
1239}
1240
1241static void smsc9218i_transmit_finish_jobs(
1242  smsc9218i_transmit_job_control *jc,
1243  volatile smsc9218i_registers *const regs,
1244  smsc9218i_driver_entry *e,
1245  rtems_event_set events
1246)
1247{
1248  uint32_t tx_fifo_inf = regs->tx_fifo_inf;
1249  uint32_t status_used = SMSC9218I_TX_FIFO_INF_GET_SUSED(tx_fifo_inf);
1250  uint32_t s = 0;
1251  int n = jc->transfer;
1252
1253  for (s = 0; s < status_used; ++s) {
1254    uint32_t tx_fifo_status = regs->tx_fifo_status;
1255
1256    if ((tx_fifo_status & SMSC9218I_TX_STS_ERROR) == 0) {
1257      ++e->transmitted_frames;
1258    } else {
1259      ++e->transmit_frame_errors;
1260    }
1261
1262    SMSC9218I_PRINTF(
1263      "tx: transmit status: tag = %" PRIu32 ", status = 0x%08" PRIx32 "\n",
1264      SMSC9218I_TX_STS_GET_TAG(tx_fifo_status),
1265      SMSC9218I_SWAP(tx_fifo_status)
1266    );
1267  }
1268
1269  if (
1270    (events & (SMSC9218I_EVENT_DMA | SMSC9218I_EVENT_DMA_ERROR)) != 0
1271      && n > 0
1272  ) {
1273    int c = jc->empty_index;
1274    int i = 0;
1275
1276    #ifdef DEBUG
1277      smsc9218i_transmit_job_dump(jc, "finish");
1278    #endif
1279
1280    if ((events & SMSC9218I_EVENT_DMA_ERROR) != 0) {
1281      ++e->transmit_dma_errors;
1282    }
1283
1284    /* Restore last data TCD */
1285    jc->data_tcd_table [jc->transfer_last_index].BMF.R =
1286      SMSC9218I_TCD_BMF_LINK;
1287
1288    for (i = 0; i < n; ++i) {
1289      /* Free fragment buffer */
1290      m_free(jc->fragment_table [c]);
1291
1292      c = (c + 1) % SMSC9218I_TX_JOBS;
1293    }
1294
1295    /* Increment empty count */
1296    jc->empty += n;
1297
1298    /* New empty index */
1299    jc->empty_index = jc->transfer_index;
1300
1301    /* Clear jobs in transfer */
1302    jc->transfer = 0;
1303
1304    /* Update empty index */
1305    jc->empty_index = c;
1306
1307    #ifdef DEBUG
1308      smsc9218i_transmit_job_dump(jc, "finish done");
1309    #endif
1310  }
1311}
1312
1313/* FIXME */
1314static smsc9218i_transmit_job_control smsc_tx_jc __attribute__((aligned (32))) = {
1315  .frame = NULL,
1316  .next_fragment = NULL,
1317  .frame_length = 0,
1318  .tag = 0,
1319  .command_b = 0,
1320  .done = false,
1321  .empty_index = 0,
1322  .transfer_index = 0,
1323  .todo_index = 0,
1324  .empty = SMSC9218I_TX_JOBS,
1325  .transfer = 0,
1326  .todo = 0
1327};
1328
1329static void smsc9218i_transmit_task(void *arg)
1330{
1331  rtems_status_code sc = RTEMS_SUCCESSFUL;
1332  rtems_event_set events = 0;
1333  smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg;
1334  struct ifnet *ifp = &e->arpcom.ac_if;
1335  volatile smsc9218i_registers *const regs = smsc9218i;
1336  uint32_t mac_cr = 0;
1337  smsc9218i_transmit_job_control *jc = &smsc_tx_jc;
1338  unsigned i = 0;
1339
1340  SMSC9218I_PRINTF("%s\n", __func__);
1341
1342  /* Obtain transmit eDMA channel */
1343  e->edma_transmit.id = e->transmit_task;
1344  sc = mpc55xx_edma_obtain_channel(
1345    &e->edma_transmit,
1346    MPC55XX_INTC_DEFAULT_PRIORITY
1347  );
1348  ASSERT_SC(sc);
1349
1350  /* Setup transmit eDMA descriptors */
1351  for (i = 0; i < SMSC9218I_TX_JOBS; ++i) {
1352    unsigned ii = (i + 1) % SMSC9218I_TX_JOBS;
1353    struct tcd_t tcd = EDMA_TCD_DEFAULT;
1354    struct tcd_t *command_tcd = &jc->command_tcd_table [i];
1355    struct tcd_t *data_tcd = &jc->data_tcd_table [i];
1356    struct tcd_t *next_command_tcd = &jc->command_tcd_table [ii];
1357
1358    tcd.SDF.B.SSIZE = 2;
1359    tcd.SDF.B.SOFF = 4;
1360    tcd.SDF.B.DSIZE = 2;
1361    tcd.CDF.B.CITER = 1;
1362    tcd.BMF.R = SMSC9218I_TCD_BMF_LINK;
1363    tcd.DADDR = (uint32_t) &regs->tx_fifo_data;
1364
1365    tcd.DLAST_SGA = (int32_t) next_command_tcd;
1366    *data_tcd = tcd;
1367
1368    tcd.SADDR = (uint32_t) &jc->command_table [i].a;
1369    tcd.NBYTES = 8;
1370    tcd.DLAST_SGA = (int32_t) data_tcd;
1371    *command_tcd = tcd;
1372  }
1373
1374  /*
1375   * Cache flush for command TCD.  The content of the command TCD remains
1376   * invariant.
1377   */
1378  rtems_cache_flush_multiple_data_lines(
1379    jc->command_tcd_table,
1380    sizeof(jc->command_tcd_table)
1381  );
1382
1383  /* Configure transmitter */
1384  regs->tx_cfg = SMSC9218I_TX_CFG_SAO | SMSC9218I_TX_CFG_ON;
1385
1386  /* Enable MAC transmitter */
1387  mac_cr = smsc9218i_mac_read(regs, SMSC9218I_MAC_CR) | SMSC9218I_MAC_CR_TXEN;
1388  smsc9218i_mac_write(regs, SMSC9218I_MAC_CR, mac_cr);
1389
1390  /* Main event loop */
1391  while (true) {
1392    /* Wait for events */
1393    sc = rtems_bsdnet_event_receive(
1394      SMSC9218I_EVENT_TX
1395        | SMSC9218I_EVENT_TX_START
1396        | SMSC9218I_EVENT_DMA
1397        | SMSC9218I_EVENT_DMA_ERROR,
1398      RTEMS_EVENT_ANY | RTEMS_WAIT,
1399      RTEMS_NO_TIMEOUT,
1400      &events
1401    );
1402    ASSERT_SC(sc);
1403
1404    SMSC9218I_PRINTF("tx: wake up: events = 0x%08" PRIx32 "\n", events);
1405
1406    do {
1407      jc->done = false;
1408      smsc9218i_transmit_finish_jobs(jc, regs, e, events);
1409      smsc9218i_transmit_create_jobs(jc, regs, ifp);
1410      smsc9218i_transmit_do_jobs(jc, regs, e);
1411    } while (!jc->done);
1412
1413    SMSC9218I_PRINTF("tx: done\n");
1414  }
1415
1416  /* Release network semaphore */
1417  rtems_bsdnet_semaphore_release();
1418
1419  /* Terminate self */
1420  (void) rtems_task_delete(RTEMS_SELF);
1421}
1422
1423#if defined(DEBUG)
1424static void smsc9218i_test_macros(void)
1425{
1426  unsigned i = 0;
1427  unsigned byte_test = 0x87654321U;
1428  unsigned val8 = 0xa5;
1429  unsigned val16 = 0xa55a;
1430  int r = 0;
1431
1432  r = SMSC9218I_SWAP(SMSC9218I_BYTE_TEST) == byte_test;
1433  printf("[%i] SMSC9218I_SWAP\n", r);
1434
1435  for (i = 0; i < 32; ++i) {
1436    r = SMSC9218I_SWAP(SMSC9218I_FLAG(i)) == (1U << i);
1437    printf("[%i] flag: %u\n", r, i);
1438  }
1439
1440  for (i = 0; i < 32; i += 8) {
1441    r = SMSC9218I_SWAP(SMSC9218I_FIELD_8(val8, i)) == (val8 << i);
1442    printf("[%i] field 8: %u\n", r, i);
1443  }
1444
1445  for (i = 0; i < 32; i += 16) {
1446    r = SMSC9218I_SWAP(SMSC9218I_FIELD_16(val16, i)) == (val16 << i);
1447    printf("[%i] field 16: %u\n", r, i);
1448  }
1449
1450  for (i = 0; i < 32; i += 8) {
1451    r = SMSC9218I_GET_FIELD_8(SMSC9218I_BYTE_TEST, i)
1452      == ((byte_test >> i) & 0xffU);
1453    printf("[%i] get field 8: %u\n", r, i);
1454  }
1455
1456  for (i = 0; i < 32; i += 16) {
1457    r = SMSC9218I_GET_FIELD_16(SMSC9218I_BYTE_TEST, i)
1458      == ((byte_test >> i) & 0xffffU);
1459    printf("[%i] get field 16: %u\n", r, i);
1460  }
1461}
1462#endif
1463
1464static void smsc9218i_wait_for_eeprom_access(volatile smsc9218i_registers *regs)
1465{
1466  while ((regs->e2p_cmd & SMSC9218I_E2P_CMD_EPC_BUSY) != 0) {
1467    /* Wait */
1468  }
1469}
1470
1471static void smsc9218i_set_mac_address(
1472  volatile smsc9218i_registers *regs,
1473  unsigned char address [6]
1474)
1475{
1476  smsc9218i_mac_write(
1477    regs,
1478    SMSC9218I_MAC_ADDRL,
1479    ((uint32_t) address [3] << 24) | ((uint32_t) address [2] << 16)
1480      | ((uint32_t) address [1] << 8) | (uint32_t) address [0]
1481  );
1482  smsc9218i_mac_write(
1483    regs,
1484    SMSC9218I_MAC_ADDRH,
1485    ((uint32_t) address [5] << 8) | (uint32_t) address [4]
1486  );
1487}
1488
1489#if defined(DEBUG)
1490static void smsc9218i_mac_address_dump(volatile smsc9218i_registers *regs)
1491{
1492  uint32_t low = smsc9218i_mac_read(regs, SMSC9218I_MAC_ADDRL);
1493  uint32_t high = smsc9218i_mac_read(regs, SMSC9218I_MAC_ADDRH);
1494
1495  printf(
1496    "MAC address: %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32
1497      ":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\n",
1498    low & 0xff,
1499    (low >> 8) & 0xff,
1500    (low >> 16) & 0xff,
1501    (low >> 24) & 0xff,
1502    high & 0xff,
1503    (high >> 8) & 0xff
1504  );
1505}
1506#endif
1507
1508static void smsc9218i_interrupt_init(
1509  smsc9218i_driver_entry *e,
1510  volatile smsc9218i_registers *regs
1511)
1512{
1513  rtems_status_code sc = RTEMS_SUCCESSFUL;
1514  union SIU_PCR_tag pcr = MPC55XX_ZERO_FLAGS;
1515  union SIU_DIRER_tag direr = MPC55XX_ZERO_FLAGS;
1516  union SIU_DIRSR_tag dirsr = MPC55XX_ZERO_FLAGS;
1517  union SIU_ORER_tag orer = MPC55XX_ZERO_FLAGS;
1518  union SIU_IREER_tag ireer = MPC55XX_ZERO_FLAGS;
1519  union SIU_IFEER_tag ifeer = MPC55XX_ZERO_FLAGS;
1520  union SIU_IDFR_tag idfr = MPC55XX_ZERO_FLAGS;
1521  rtems_interrupt_level level;
1522
1523  /* Configure IRQ input pin */
1524  pcr.B.PA = 2;
1525  pcr.B.OBE = 0;
1526  pcr.B.IBE = 1;
1527#if MPC55XX_CHIP_TYPE / 10 != 551
1528  pcr.B.DSC = 0;
1529#endif
1530  pcr.B.ODE = 0;
1531  pcr.B.HYS = 0;
1532  pcr.B.SRC = 3;
1533  pcr.B.WPE = 0;
1534  pcr.B.WPS = 1;
1535  SIU.PCR [193].R = pcr.R;
1536
1537  /* DMA/Interrupt Request Select */
1538  rtems_interrupt_disable(level);
1539  dirsr.R = SIU.DIRSR.R;
1540#if MPC55XX_CHIP_TYPE / 10 != 551
1541  dirsr.B.DIRS0 = 0;
1542#endif
1543  SIU.DIRSR.R = dirsr.R;
1544  rtems_interrupt_enable(level);
1545
1546  /* Overrun Request Enable */
1547  rtems_interrupt_disable(level);
1548  orer.R = SIU.ORER.R;
1549  orer.B.ORE0 = 0;
1550  SIU.ORER.R = orer.R;
1551  rtems_interrupt_enable(level);
1552
1553  /* IRQ Rising-Edge Enable */
1554  rtems_interrupt_disable(level);
1555  ireer.R = SIU.IREER.R;
1556  ireer.B.IREE0 = 0;
1557  SIU.IREER.R = ireer.R;
1558  rtems_interrupt_enable(level);
1559
1560  /* IRQ Falling-Edge Enable */
1561  rtems_interrupt_disable(level);
1562  ifeer.R = SIU.IFEER.R;
1563  ifeer.B.IFEE0 = 1;
1564  SIU.IFEER.R = ifeer.R;
1565  rtems_interrupt_enable(level);
1566
1567  /* IRQ Digital Filter */
1568  rtems_interrupt_disable(level);
1569  idfr.R = SIU.IDFR.R;
1570  idfr.B.DFL = 0;
1571  SIU.IDFR.R = idfr.R;
1572  rtems_interrupt_enable(level);
1573
1574  /* Clear external interrupt status */
1575  SIU.EISR.R = 1;
1576
1577  /* DMA/Interrupt Request Enable */
1578  rtems_interrupt_disable(level);
1579  direr.R = SIU.DIRER.R;
1580  direr.B.EIRE0 = 1;
1581  SIU.DIRER.R = direr.R;
1582  rtems_interrupt_enable(level);
1583
1584  /* Install interrupt handler */
1585  sc = rtems_interrupt_handler_install(
1586    MPC55XX_IRQ_SIU_EXTERNAL_0,
1587    "SMSC9218i",
1588    RTEMS_INTERRUPT_UNIQUE,
1589    smsc9218i_interrupt_handler,
1590    e
1591  );
1592  ASSERT_SC(sc);
1593
1594  /* Enable interrupts and use push-pull driver (active low) */
1595  regs->irq_cfg = SMSC9218I_IRQ_CFG_GLOBAL_ENABLE;
1596
1597  /* Enable error interrupts */
1598  regs->int_en = SMSC9218I_ERROR_INTERRUPTS;
1599}
1600
1601static void smsc9218i_reset_signal(bool signal)
1602{
1603  SIU.GPDO [186].R = signal ? 1 : 0;
1604}
1605
1606static void smsc9218i_reset_signal_init(void)
1607{
1608  union SIU_PCR_tag pcr = MPC55XX_ZERO_FLAGS;
1609
1610  smsc9218i_reset_signal(true);
1611
1612  pcr.B.PA = 0;
1613  pcr.B.OBE = 1;
1614  pcr.B.IBE = 0;
1615#if MPC55XX_CHIP_TYPE / 10 != 551
1616  pcr.B.DSC = 0;
1617#endif
1618  pcr.B.ODE = 0;
1619  pcr.B.HYS = 0;
1620  pcr.B.SRC = 3;
1621  pcr.B.WPE = 1;
1622  pcr.B.WPS = 1;
1623
1624  SIU.PCR [186].R = pcr.R;
1625}
1626
1627static void smsc9218i_hardware_reset(volatile smsc9218i_registers *regs)
1628{
1629  smsc9218i_reset_signal_init();
1630  smsc9218i_reset_signal(false);
1631  rtems_bsp_delay(200);
1632  smsc9218i_reset_signal(true);
1633
1634  while ((regs->pmt_ctrl & SMSC9218I_PMT_CTRL_READY) == 0) {
1635    /* Wait */
1636  }
1637}
1638
1639static void smsc9218i_interface_init(void *arg)
1640{
1641  smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg;
1642  struct ifnet *ifp = &e->arpcom.ac_if;
1643  volatile smsc9218i_registers *const regs = smsc9218i;
1644
1645  SMSC9218I_PRINTF("%s\n", __func__);
1646
1647  if (e->state == SMSC9218I_CONFIGURED) {
1648    smsc9218i_hardware_reset(regs);
1649
1650#if defined(DEBUG)
1651    /* Register dump */
1652    smsc9218i_register_dump(regs);
1653#endif
1654
1655    /* Set hardware configuration */
1656    regs->hw_cfg = SMSC9218I_HW_CFG_MBO | SMSC9218I_HW_CFG_TX_FIF_SZ(5);
1657
1658    /* MAC address */
1659    smsc9218i_wait_for_eeprom_access(regs);
1660    smsc9218i_set_mac_address(regs, e->arpcom.ac_enaddr);
1661#if defined(DEBUG)
1662    smsc9218i_mac_address_dump(regs);
1663#endif
1664
1665    /* Auto-negotiation advertisment */
1666    smsc9218i_phy_write(
1667      regs,
1668      MII_ANAR,
1669      ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA
1670    );
1671
1672    /* Initialize interrupts */
1673    smsc9218i_interrupt_init(e, regs);
1674
1675    /* Set MAC control */
1676    smsc9218i_mac_write(regs, SMSC9218I_MAC_CR, SMSC9218I_MAC_CR_FDPX);
1677
1678    /* Set FIFO interrupts */
1679    regs->fifo_int = SMSC9218I_FIFO_INT_TDAL(32);
1680
1681    /* Clear receive drop counter */
1682    regs->rx_drop;
1683
1684    /* Start receive task */
1685    if (e->receive_task == RTEMS_ID_NONE) {
1686      e->receive_task = rtems_bsdnet_newproc(
1687        "ntrx",
1688        4096,
1689        smsc9218i_receive_task,
1690        e
1691      );
1692    }
1693
1694    /* Start transmit task */
1695    if (e->transmit_task == RTEMS_ID_NONE) {
1696      e->transmit_task = rtems_bsdnet_newproc(
1697        "nttx",
1698        4096,
1699        smsc9218i_transmit_task,
1700        e
1701      );
1702    }
1703
1704    /* Change state */
1705    if (e->receive_task != RTEMS_ID_NONE
1706      && e->transmit_task != RTEMS_ID_NONE) {
1707      e->state = SMSC9218I_STARTED;
1708    }
1709  }
1710
1711  if (e->state == SMSC9218I_STARTED) {
1712    /* Enable promiscous mode */
1713    smsc9218i_enable_promiscous_mode(
1714      regs,
1715      (ifp->if_flags & IFF_PROMISC) != 0
1716    );
1717
1718    /* Set interface to running state */
1719    ifp->if_flags |= IFF_RUNNING;
1720
1721    /* Change state */
1722    e->state = SMSC9218I_RUNNING;
1723  }
1724}
1725
1726static int smsc9218i_mdio_read(
1727  int phy,
1728  void *arg,
1729  unsigned phy_reg,
1730  uint32_t *val
1731)
1732{
1733  volatile smsc9218i_registers *const regs = smsc9218i;
1734
1735  *val = smsc9218i_phy_read(regs, phy_reg);
1736
1737  return 0;
1738}
1739
1740static int smsc9218i_mdio_write(
1741  int phy,
1742  void *arg,
1743  unsigned phy_reg,
1744  uint32_t data
1745)
1746{
1747  volatile smsc9218i_registers *const regs = smsc9218i;
1748
1749  smsc9218i_phy_write(regs, phy_reg, data);
1750
1751  return 0;
1752}
1753
1754static void smsc9218i_interface_stats(smsc9218i_driver_entry *e)
1755{
1756  volatile smsc9218i_registers *const regs = smsc9218i;
1757  smsc9218i_transmit_job_control *jc = &smsc_tx_jc;
1758  int media = 0;
1759  bool media_ok = smsc9218i_media_status(e, &media);
1760
1761  if (media_ok) {
1762    rtems_ifmedia2str(media, NULL, 0);
1763    printf ("\n");
1764  } else {
1765    printf ("PHY communication error\n");
1766  }
1767
1768  e->receive_drop += SMSC9218I_SWAP(regs->rx_drop);
1769
1770  printf("PHY interrupts:            %u\n", e->phy_interrupts);
1771  printf("received frames:           %u\n", e->received_frames);
1772  printf("receiver errors:           %u\n", e->receiver_errors);
1773  printf("receive interrupts:        %u\n", e->receive_interrupts);
1774  printf("receive DMA interrupts:    %u\n", e->receive_dma_interrupts);
1775  printf("receive to long errors:    %u\n", e->receive_too_long_errors);
1776  printf("receive collision errors:  %u\n", e->receive_collision_errors);
1777  printf("receive CRC errors:        %u\n", e->receive_crc_errors);
1778  printf("receive DMA errors:        %u\n", e->receive_dma_errors);
1779  printf("receive drops:             %u\n", e->receive_drop);
1780  printf("receive watchdog timeouts: %u\n", e->receive_watchdog_timeouts);
1781  printf("transmitted frames:        %u\n", e->transmitted_frames);
1782  printf("transmitter errors:        %u\n", e->transmitter_errors);
1783  printf("transmit interrupts:       %u\n", e->transmit_interrupts);
1784  printf("transmit DMA interrupts:   %u\n", e->transmit_dma_interrupts);
1785  printf("transmit status overflows: %u\n", e->transmit_status_overflows);
1786  printf("transmit frame errors:     %u\n", e->transmit_frame_errors);
1787  printf("transmit DMA errors:       %u\n", e->transmit_dma_errors);
1788  printf("frame compact count:       %u\n", jc->frame_compact_count);
1789}
1790
1791static int smsc9218i_interface_ioctl(
1792  struct ifnet *ifp,
1793  ioctl_command_t command,
1794  caddr_t data
1795) {
1796  smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) ifp->if_softc;
1797  int rv = 0;
1798
1799  SMSC9218I_PRINTF("%s\n", __func__);
1800
1801  switch (command)  {
1802    case SIOCGIFMEDIA:
1803    case SIOCSIFMEDIA:
1804      rtems_mii_ioctl(&e->mdio, e, command, (int *) data);
1805      break;
1806    case SIOCGIFADDR:
1807    case SIOCSIFADDR:
1808      ether_ioctl(ifp, command, data);
1809      break;
1810    case SIOCSIFFLAGS:
1811      if (ifp->if_flags & IFF_RUNNING) {
1812        /* TODO: off */
1813      }
1814      if (ifp->if_flags & IFF_UP) {
1815        ifp->if_flags |= IFF_RUNNING;
1816        /* TODO: init */
1817      }
1818      break;
1819    case SIO_RTEMS_SHOW_STATS:
1820      smsc9218i_interface_stats(e);
1821      break;
1822    default:
1823      rv = EINVAL;
1824      break;
1825  }
1826
1827  return rv;
1828}
1829
1830static void smsc9218i_interface_start(struct ifnet *ifp)
1831{
1832  rtems_status_code sc = RTEMS_SUCCESSFUL;
1833  smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) ifp->if_softc;
1834
1835  /* Interface is now active */
1836  ifp->if_flags |= IFF_OACTIVE;
1837
1838  sc = rtems_event_send(e->transmit_task, SMSC9218I_EVENT_TX_START);
1839  ASSERT_SC(sc);
1840}
1841
1842static void smsc9218i_interface_watchdog(struct ifnet *ifp)
1843{
1844  SMSC9218I_PRINTF("%s\n", __func__);
1845}
1846
1847static void smsc9218i_attach(struct rtems_bsdnet_ifconfig *config)
1848{
1849  smsc9218i_driver_entry *e = &smsc9218i_driver_data;
1850  struct ifnet *ifp = &e->arpcom.ac_if;
1851  char *unit_name = NULL;
1852  int unit_number = rtems_bsdnet_parse_driver_name(config, &unit_name);
1853
1854  /* Check parameter */
1855  assert(unit_number == 0);
1856  assert(config->hardware_address != NULL);
1857  assert(e->state == SMSC9218I_NOT_INITIALIZED);
1858
1859  /* Interrupt number */
1860  config->irno = MPC55XX_IRQ_SIU_EXTERNAL_0;
1861
1862  /* Device control */
1863  config->drv_ctrl = e;
1864
1865  /* Receive unit number */
1866  config->rbuf_count = 0;
1867
1868  /* Transmit unit number */
1869  config->xbuf_count = 0;
1870
1871  /* Copy MAC address */
1872  memcpy(e->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1873
1874  /* Set interface data */
1875  ifp->if_softc = e;
1876  ifp->if_unit = (short) unit_number;
1877  ifp->if_name = unit_name;
1878  ifp->if_mtu = config->mtu > 0 ? (u_long) config->mtu : ETHERMTU;
1879  ifp->if_init = smsc9218i_interface_init;
1880  ifp->if_ioctl = smsc9218i_interface_ioctl;
1881  ifp->if_start = smsc9218i_interface_start;
1882  ifp->if_output = ether_output;
1883  ifp->if_watchdog = smsc9218i_interface_watchdog;
1884  ifp->if_flags = config->ignore_broadcast ? 0 : IFF_BROADCAST;
1885  ifp->if_snd.ifq_maxlen = ifqmaxlen;
1886  ifp->if_timer = 0;
1887
1888  /* MDIO */
1889  e->mdio.mdio_r = smsc9218i_mdio_read;
1890  e->mdio.mdio_w = smsc9218i_mdio_write;
1891
1892  /* Change status */
1893  e->state = SMSC9218I_CONFIGURED;
1894
1895  /* Attach the interface */
1896  if_attach(ifp);
1897  ether_ifattach(ifp);
1898}
1899
1900int smsc9218i_attach_detach(
1901  struct rtems_bsdnet_ifconfig *config,
1902  int attaching
1903) {
1904  if (attaching) {
1905    smsc9218i_attach(config);
1906  } else {
1907    /* TODO */
1908  }
1909
1910  /* FIXME: Return value */
1911  return 0;
1912}
1913
1914#endif /* defined(RTEMS_NETWORKING) && defined(MPC55XX_HAS_SIU) */
Note: See TracBrowser for help on using the repository browser.