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

4.115
Last change on this file since 9e7758b was 9e7758b, checked in by Sebastian Huber <sebastian.huber@…>, on 08/31/11 at 16:03:10

2011-08-31 Sebastian Huber <sebastian.huber@…>

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