Changeset cc3929b8 in rtems


Ignore:
Timestamp:
Jun 10, 2011, 7:06:14 AM (8 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
4.11, master
Children:
fa2f4708
Parents:
77199b75
Message:

2011-06-10 Sebastian Huber <sebastian.huber@…>

  • network/smsc9218i.c: Optimizations.
Location:
c/src/lib/libbsp/powerpc/mpc55xxevb
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • c/src/lib/libbsp/powerpc/mpc55xxevb/ChangeLog

    r77199b75 rcc3929b8  
     12011-06-10      Sebastian Huber <sebastian.huber@embedded-brains.de>
     2
     3        * network/smsc9218i.c: Optimizations.
     4
    152011-06-07      Sebastian Huber <sebastian.huber@embedded-brains.de>
    26
  • c/src/lib/libbsp/powerpc/mpc55xxevb/network/smsc9218i.c

    r77199b75 rcc3929b8  
    2929
    3030#include <errno.h>
     31#include <assert.h>
    3132#include <stdlib.h>
    3233#include <stdio.h>
     
    5859#include <bsp/smsc9218i.h>
    5960
    60 #include <rtems/status-checks.h>
    61 
    6261#if MCLBYTES != 2048
    6362  #warning "unexpected MCLBYTES value"
    6463#endif
    6564
     65#define ASSERT_SC(sc) assert((sc) == RTEMS_SUCCESSFUL)
     66
    6667#define SMSC9218I_EVENT_TX RTEMS_EVENT_1
    6768
     
    7677#define SMSC9218I_EVENT_PHY RTEMS_EVENT_6
    7778
    78 #define SMSC9218I_EVENT_EDMA RTEMS_EVENT_7
    79 
    80 #define SMSC9218I_EVENT_EDMA_ERROR RTEMS_EVENT_8
     79#define SMSC9218I_EVENT_DMA RTEMS_EVENT_7
     80
     81#define SMSC9218I_EVENT_DMA_ERROR RTEMS_EVENT_8
    8182
    8283/* Adjust by two bytes for proper IP header alignment */
    8384#define SMSC9218I_RX_DATA_OFFSET 2
    8485
    85 #define SMSC9218I_TX_JOBS 128U
    86 
    87 #define SMSC9218I_TX_JOBS_MAX (SMSC9218I_TX_JOBS - 1U)
     86#define SMSC9218I_RX_JOBS 32
     87
     88#define SMSC9218I_TX_JOBS 64
    8889
    8990/* Maximum number of fragments per frame, see manual section 3.11.3.2 */
    9091#define SMSC9218I_TX_FRAGMENT_MAX 86
    9192
     93#if SMSC9218I_TX_JOBS > SMSC9218I_TX_FRAGMENT_MAX
     94  #error "too many TX jobs"
     95#endif
     96
    9297#define SMSC9218I_IRQ_CFG_GLOBAL_ENABLE \
    9398  (SMSC9218I_IRQ_CFG_IRQ_EN | SMSC9218I_IRQ_CFG_IRQ_TYPE)
     
    103108#define SMSC9218I_EDMA_TX_CHANNEL 48
    104109
    105 #define SMSC9218I_EDMA_TX_TCD_BMF_LINK 0x10011
    106 
    107 #define SMSC9218I_EDMA_TX_TCD_BMF_INTERRUPT 0x10003
    108 
    109 #define SMSC9218I_EDMA_TX_TCD_BMF_CLEAR 0x10000
     110#define SMSC9218I_TCD_BMF_LINK 0x10011
     111
     112#define SMSC9218I_TCD_BMF_LAST 0x10003
     113
     114#define SMSC9218I_TCD_BMF_CLEAR 0x10000
    110115
    111116#define SMSC9218I_ERROR_INTERRUPTS \
     
    114119     | SMSC9218I_INT_RXE \
    115120     | SMSC9218I_INT_TXE)
     121
     122#define SMSC9218I_UNLIKELY(x) __builtin_expect((x), 0)
    116123
    117124#ifdef DEBUG
     
    138145  mpc55xx_edma_channel_entry edma_receive;
    139146  mpc55xx_edma_channel_entry edma_transmit;
     147  unsigned phy_interrupts;
    140148  unsigned received_frames;
     149  unsigned receiver_errors;
    141150  unsigned receive_interrupts;
    142   unsigned transmitted_frames;
    143   unsigned transmit_interrupts;
    144   unsigned receiver_errors;
     151  unsigned receive_dma_interrupts;
    145152  unsigned receive_too_long_errors;
    146153  unsigned receive_collision_errors;
    147154  unsigned receive_crc_errors;
    148   unsigned receive_edma_errors;
     155  unsigned receive_dma_errors;
    149156  unsigned receive_drop;
    150157  unsigned receive_watchdog_timeouts;
     158  unsigned transmitted_frames;
    151159  unsigned transmitter_errors;
     160  unsigned transmit_interrupts;
     161  unsigned transmit_dma_interrupts;
    152162  unsigned transmit_status_overflows;
    153163  unsigned transmit_frame_errors;
    154   unsigned transmit_edma_errors;
     164  unsigned transmit_dma_errors;
    155165} smsc9218i_driver_entry;
    156166
     
    167177  struct mbuf *frame;
    168178  struct mbuf *next_fragment;
    169   unsigned empty_index;
    170   unsigned transfer_index;
    171   unsigned transfer_last_index;
    172   unsigned todo_index;
    173   unsigned empty;
    174   unsigned transfer;
    175   unsigned todo;
     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;
    176186  uint32_t frame_length;
    177187  uint32_t command_b;
    178188  uint16_t tag;
    179189  bool done;
    180   unsigned fixme_tiny_fragments;
    181   unsigned fixme_too_many;
     190  unsigned frame_compact_count;
    182191} smsc9218i_transmit_job_control;
    183192
    184 static void smsc9218i_edma_done(
     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(
    185209  mpc55xx_edma_channel_entry *e,
    186210  uint32_t error_status
    187 )
    188 {
    189   rtems_event_set event = error_status == 0 ?
    190     SMSC9218I_EVENT_EDMA : SMSC9218I_EVENT_EDMA_ERROR;
    191 
    192   SMSC9218I_PRINTK(
    193     "edma: id = 0x%08x, error status = 0x%08x\n",
    194     e->id,
    195     error_status
    196   );
    197 
    198   rtems_event_send(e->id, event);
    199 }
     211);
    200212
    201213static smsc9218i_driver_entry smsc9218i_driver_data = {
     
    205217  .edma_receive = {
    206218    .channel = SMSC9218I_EDMA_RX_CHANNEL,
    207     .done = smsc9218i_edma_done,
     219    .done = smsc9218i_receive_dma_done,
    208220    .id = RTEMS_ID_NONE
    209221  },
    210222  .edma_transmit = {
    211223    .channel = SMSC9218I_EDMA_TX_CHANNEL,
    212     .done = smsc9218i_edma_done,
     224    .done = smsc9218i_transmit_dma_done,
    213225    .id = RTEMS_ID_NONE
    214226  }
     
    357369  reg = regs->rx_fifo_inf;
    358370  printf(
    359     "rx_fifo_inf: 0x%08" PRIx32 " (status unused = %" PRIu32
    360       ", data unused = %" PRIu32 ")\n",
     371    "rx_fifo_inf: 0x%08" PRIx32 " (status used = %" PRIu32
     372      ", data used = %" PRIu32 ")\n",
    361373    SMSC9218I_SWAP(reg),
    362374    SMSC9218I_RX_FIFO_INF_GET_SUSED(reg),
     
    426438#endif
    427439
     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
    428615static void smsc9218i_interrupt_handler(void *arg)
    429616{
     617  rtems_status_code sc = RTEMS_SUCCESSFUL;
    430618  smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg;
    431619  volatile smsc9218i_registers *const regs = smsc9218i;
    432   rtems_event_set re = 0;
    433   rtems_event_set te = 0;
    434620  uint32_t int_en = regs->int_en;
    435621  uint32_t int_sts = regs->int_sts & int_en;
     
    456642
    457643  /* Error interrupts */
    458   if ((int_sts & SMSC9218I_ERROR_INTERRUPTS) != 0) {
     644  if (SMSC9218I_UNLIKELY((int_sts & SMSC9218I_ERROR_INTERRUPTS) != 0)) {
    459645    if ((int_sts & SMSC9218I_INT_TXSO) != 0) {
    460646      ++e->transmit_status_overflows;
     
    473659  /* Check receive interrupts */
    474660  if ((int_sts & SMSC9218I_INT_RSFL) != 0) {
     661    smsc9218i_receive_job_control *jc = &smsc_rx_jc;
     662
    475663    int_en &= ~SMSC9218I_INT_RSFL;
    476     re = SMSC9218I_EVENT_RX;
     664    ++e->receive_interrupts;
     665    smsc9218i_setup_receive_dma(e, regs, jc);
    477666  }
    478667
    479668  /* Check PHY interrupts */
    480   if ((int_sts & SMSC9218I_INT_PHY) != 0) {
     669  if (SMSC9218I_UNLIKELY((int_sts & SMSC9218I_INT_PHY) != 0)) {
     670    SMSC9218I_PRINTK("interrupt: phy\n");
    481671    int_en &= ~SMSC9218I_INT_PHY;
    482     re |= SMSC9218I_EVENT_PHY;
    483   }
    484 
    485   /* Send events to receive task */
    486   if (re != 0) {
    487     SMSC9218I_PRINTK("interrupt: receive: 0x%08x\n", re);
    488     ++e->receive_interrupts;
    489     (void) rtems_event_send(e->receive_task, re);
     672    ++e->phy_interrupts;
     673    sc = rtems_event_send(e->receive_task, SMSC9218I_EVENT_PHY);
     674    ASSERT_SC(sc);
    490675  }
    491676
    492677  /* Check transmit interrupts */
    493678  if ((int_sts & SMSC9218I_INT_TDFA) != 0) {
     679    SMSC9218I_PRINTK("interrupt: transmit\n");
    494680    int_en &= ~SMSC9218I_INT_TDFA;
    495     te = SMSC9218I_EVENT_TX;
    496   }
    497 
    498   /* Send events to transmit task */
    499   if (te != 0) {
    500     SMSC9218I_PRINTK("interrupt: transmit: 0x%08x\n", te);
    501681    ++e->transmit_interrupts;
    502     (void) rtems_event_send(e->transmit_task, te);
     682    sc = rtems_event_send(e->transmit_task, SMSC9218I_EVENT_TX);
     683    ASSERT_SC(sc);
    503684  }
    504685
     
    508689  /* Enable module interrupts */
    509690  regs->irq_cfg = SMSC9218I_IRQ_CFG_GLOBAL_ENABLE;
    510 }
    511 
    512 static void smsc9218i_enable_receive_interrupts(
    513   volatile smsc9218i_registers *regs
    514 )
    515 {
    516   rtems_interrupt_level level;
    517 
    518   rtems_interrupt_disable(level);
    519   regs->int_en |= SMSC9218I_INT_RSFL;
    520   rtems_interrupt_enable(level);
    521691}
    522692
     
    581751}
    582752
    583 static struct mbuf *smsc9218i_new_mbuf(struct ifnet *ifp)
     753static void smsc9218i_new_mbuf(
     754  struct ifnet *ifp,
     755  smsc9218i_receive_job_control *jc,
     756  int i
     757)
    584758{
    585759  struct mbuf *m = m_gethdr(M_WAIT, MT_DATA);
     760  struct tcd_t *tcd = &jc->tcd_table [i];
     761  char *data = NULL;
    586762
    587763  m->m_pkthdr.rcvif = ifp;
    588764  MCLGET(m, M_WAIT);
    589765
    590   return m;
    591 }
    592 
    593 static void smsc9218i_receive_task(void *arg)
     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)
    594786{
    595787  rtems_status_code sc = RTEMS_SUCCESSFUL;
    596   rtems_event_set events = 0;
    597   smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg;
    598788  struct ifnet *ifp = &e->arpcom.ac_if;
    599   volatile smsc9218i_registers *const regs = smsc9218i;
    600   volatile struct tcd_t *tcd = &EDMA.TCD [e->edma_receive.channel];
    601   struct tcd_t tcd_init = EDMA_TCD_DEFAULT;
    602   uint32_t mac_cr = 0;
    603 
    604   SMSC9218I_PRINTF("%s\n", __func__);
     789  int i = 0;
    605790
    606791  /* Obtain receive eDMA channel */
    607792  e->edma_receive.id = e->receive_task;
    608793  sc = mpc55xx_edma_obtain_channel(&e->edma_receive);
    609   RTEMS_CLEANUP_SC(sc, cleanup, "obtain receive eDMA channel");
    610 
    611   /* Setup receive eDMA channel */
    612   tcd_init.SDF.B.SSIZE = 2;
    613   tcd_init.SDF.B.DSIZE = 2;
    614   tcd_init.SADDR = (uint32_t) &regs->rx_fifo_data;
    615   *tcd = tcd_init;
     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);
    616854
    617855  /* Configure receiver */
     
    620858
    621859  /* Enable MAC receiver */
    622   mac_cr = smsc9218i_mac_read(regs, SMSC9218I_MAC_CR) | SMSC9218I_MAC_CR_RXEN;
     860  mac_cr = smsc9218i_mac_read(regs, SMSC9218I_MAC_CR);
     861  mac_cr |= SMSC9218I_MAC_CR_RXEN;
    623862  smsc9218i_mac_write(regs, SMSC9218I_MAC_CR, mac_cr);
    624863
    625864  /* Enable receive interrupts */
    626   smsc9218i_enable_receive_interrupts(regs);
     865  rtems_interrupt_disable(level);
     866  regs->int_en |= SMSC9218I_INT_RSFL;
     867  rtems_interrupt_enable(level);
    627868
    628869  /* Enable PHY interrupts */
     
    634875  smsc9218i_enable_phy_interrupts(regs);
    635876
    636   SMSC9218I_PRINTF(
    637     "rx: phy_isr = 0x%08" PRIx32 ", phy_imr = 0x%08" PRIx32 "\n",
    638     smsc9218i_phy_read(regs, SMSC9218I_PHY_ISR),
    639     smsc9218i_phy_read(regs, SMSC9218I_PHY_IMR)
    640   );
    641 
    642   /* Main event loop */
    643877  while (true) {
    644     uint32_t rx_fifo_inf = 0;
    645     uint32_t status_used = 0;
    646 
    647     /* Wait for events */
     878    rtems_event_set events;
     879
    648880    sc = rtems_bsdnet_event_receive(
    649       SMSC9218I_EVENT_RX | SMSC9218I_EVENT_PHY,
     881      SMSC9218I_EVENT_DMA | SMSC9218I_EVENT_PHY,
    650882      RTEMS_EVENT_ANY | RTEMS_WAIT,
    651883      RTEMS_NO_TIMEOUT,
    652884      &events
    653885    );
    654     RTEMS_CLEANUP_SC(sc, cleanup, "wait for events");
     886    ASSERT_SC(sc);
     887
     888    if ((events & SMSC9218I_EVENT_DMA) != 0) {
     889      smsc9218i_ether_input(e, regs, jc);
     890    }
    655891
    656892    if ((events & SMSC9218I_EVENT_PHY) != 0) {
    657893      smsc9218i_media_status_change(e, regs);
    658894    }
    659 
    660     rx_fifo_inf = regs->rx_fifo_inf;
    661     status_used = SMSC9218I_RX_FIFO_INF_GET_SUSED(rx_fifo_inf);
    662 
    663     SMSC9218I_PRINTF(
    664       "rx: wake up: events = 0x%08" PRIx32 ", status used = %" PRIu32 "\n",
    665       events,
    666       status_used
    667     );
    668 
    669     while (status_used > 0) {
    670       uint32_t rx_fifo_status = regs->rx_fifo_status;
    671       uint32_t frame_length = SMSC9218I_RX_STS_GET_LENGTH(rx_fifo_status);
    672       uint32_t data_length = frame_length + SMSC9218I_RX_DATA_OFFSET;
    673       uint32_t data_misalign = data_length % 4;
    674 
    675       /* Align data length on four byte boundary */
    676       if (data_misalign > 0) {
    677         data_length += 4 - data_misalign;
    678       }
    679 
    680       SMSC9218I_PRINTF(
    681         "rx: status = 0x%08" PRIx32 ", frame length = %" PRIu32
    682           ", data length = %" PRIu32 ", data used = %" PRIu32 "\n",
    683         SMSC9218I_SWAP(rx_fifo_status),
    684         frame_length,
    685         data_length,
    686         SMSC9218I_RX_FIFO_INF_GET_DUSED(rx_fifo_inf)
    687       );
    688 
    689       if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR) == 0) {
    690         struct mbuf *m = smsc9218i_new_mbuf(ifp);
    691         struct ether_header *eh = (struct ether_header *)
    692           (mtod(m, char *) + SMSC9218I_RX_DATA_OFFSET);
    693         int mbuf_length = (int) frame_length - ETHER_HDR_LEN - ETHER_CRC_LEN;
    694         char *data = mtod(m, char *);
    695 
    696         /* Update mbuf */
    697         m->m_len = mbuf_length;
    698         m->m_pkthdr.len = mbuf_length;
    699         m->m_data = data + ETHER_HDR_LEN + SMSC9218I_RX_DATA_OFFSET;
    700 
    701         /* Invalidate data cache */
    702         rtems_cache_invalidate_multiple_data_lines(data, data_length);
    703 
    704         /* Start eDMA transfer */
    705         tcd->DADDR = (uint32_t) data;
    706         tcd->NBYTES = data_length;
    707         tcd->CDF.R = SMSC9218I_EDMA_RX_TCD_CDF;
    708         tcd->BMF.R = SMSC9218I_EDMA_RX_TCD_BMF;
    709 
    710         /* Wait for eDMA events */
    711         sc = rtems_bsdnet_event_receive(
    712           SMSC9218I_EVENT_EDMA | SMSC9218I_EVENT_EDMA_ERROR,
    713           RTEMS_EVENT_ANY | RTEMS_WAIT,
    714           RTEMS_NO_TIMEOUT,
    715           &events
    716         );
    717         RTEMS_CHECK_SC_TASK(sc, "wait for eDMA events");
    718 
    719         if ((events & SMSC9218I_EVENT_EDMA_ERROR) == 0) {
    720           /* Hand over */
    721           ether_input(ifp, eh, m);
    722 
    723           /* Increment received frames counter */
    724           ++e->received_frames;
    725         } else {
    726           /* Increment receive eDMA error counter */
    727           ++e->receive_edma_errors;
    728         }
    729 
    730         SMSC9218I_PRINTF("rx: eDMA done\n");
    731       } else {
    732         SMSC9218I_PRINTF("rx: error\n");
    733 
    734         /* Update error counters */
    735         if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR_TOO_LONG) != 0) {
    736           ++e->receive_too_long_errors;
    737         }
    738         if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR_COLLISION) != 0) {
    739           ++e->receive_collision_errors;
    740         }
    741         if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR_CRC) != 0) {
    742           ++e->receive_crc_errors;
    743         }
    744 
    745         /* Discard frame */
    746         if (frame_length > 16) {
    747           /* Fast forward */
    748           regs->rx_dp_ctl = SMSC9218I_RX_DP_CTRL_FFWD;
    749 
    750           while ((regs->rx_dp_ctl & SMSC9218I_RX_DP_CTRL_FFWD) != 0) {
    751             /* Wait */
    752           }
    753         } else {
    754           uint32_t len = data_length / 4;
    755           uint32_t i = 0;
    756 
    757           /* Discard data */
    758           for (i = 0; i < len; ++i) {
    759             regs->rx_fifo_data;
    760           }
    761         }
    762       }
    763 
    764       /* Clear FIFO level status */
    765       regs->int_sts = SMSC9218I_INT_RSFL;
    766 
    767       /* Next FIFO status */
    768       rx_fifo_inf = regs->rx_fifo_inf;
    769       status_used = SMSC9218I_RX_FIFO_INF_GET_SUSED(rx_fifo_inf);
    770     }
    771 
    772     SMSC9218I_PRINTF("rx: done\n");
    773 
    774     /* Nothing to do, enable receive interrupts */
    775     smsc9218i_enable_receive_interrupts(regs);
    776   }
    777 
    778 cleanup:
    779 
    780   /* Release network semaphore */
    781   rtems_bsdnet_semaphore_release();
    782 
    783   /* Terminate self */
    784   (void) rtems_task_delete(RTEMS_SELF);
     895  }
    785896}
    786897
     
    792903{
    793904  char out [SMSC9218I_TX_JOBS + 1];
    794   unsigned c = 0;
    795   unsigned s = 0;
     905  int c = 0;
     906  int s = 0;
    796907
    797908  out [SMSC9218I_TX_JOBS] = '\0';
     
    804915    out [c] = 'E';
    805916    --s;
    806     if (c < SMSC9218I_TX_JOBS_MAX) {
    807       ++c;
    808     } else {
    809       c = 0;
    810     }
     917    c = (c + 1) % SMSC9218I_TX_JOBS;
    811918  }
    812919
     
    816923    out [c] = 'T';
    817924    --s;
    818     if (c < SMSC9218I_TX_JOBS_MAX) {
    819       ++c;
    820     } else {
    821       c = 0;
    822     }
     925    c = (c + 1) % SMSC9218I_TX_JOBS;
    823926  }
    824927
     
    828931    out [c] = 'D';
    829932    --s;
    830     if (c < SMSC9218I_TX_JOBS_MAX) {
    831       ++c;
    832     } else {
    833       c = 0;
    834     }
     933    c = (c + 1) % SMSC9218I_TX_JOBS;
    835934  }
    836935
     
    846945#endif /* defined(DEBUG) */
    847946
     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
    848976static struct mbuf *smsc9218i_next_transmit_fragment(
    849977  struct ifnet *ifp,
     
    868996      uint32_t frame_length = 0;
    869997      unsigned fragments = 0;
     998      bool tiny = false;
    870999
    8711000      /* Calculate frame length and fragment number */
     
    8761005          ++fragments;
    8771006          frame_length += (uint32_t) len;
    878 
    879           if (len < 4) {
    880             ++jc->fixme_tiny_fragments;
    881           }
     1007          tiny = tiny || len < 4;
    8821008
    8831009          /* Next fragment */
     
    8971023      } while (n != NULL);
    8981024
    899       if (fragments > SMSC9218I_TX_FRAGMENT_MAX) {
    900         ++jc->fixme_too_many;
     1025      if (SMSC9218I_UNLIKELY(tiny || fragments > SMSC9218I_TX_JOBS)) {
     1026        fragments = 1;
     1027        m = smsc9218i_compact_frame(jc, frame_length);
    9011028      }
    9021029
     
    9111038
    9121039      /* Command B */
    913       jc->command_b = SMSC9218I_TX_B_TAG(jc->tag)
     1040      jc->command_b = ((uint32_t) SMSC9218I_TX_B_TAG(jc->tag))
    9141041        | SMSC9218I_TX_B_FRAME_LENGTH(jc->frame_length);
    9151042
    9161043      SMSC9218I_PRINTF(
    917         "tx: next frame: tag = %u, frame length = %" PRIu32
     1044        "tx: next frame: tag = %i, frame length = %" PRIu32
    9181045          ", fragments = %u\n",
    919         (unsigned) jc->tag,
     1046        jc->tag,
    9201047        frame_length,
    9211048        fragments
     
    9441071)
    9451072{
    946   unsigned n = jc->empty;
     1073  int n = jc->empty;
    9471074
    9481075  if (n > 0) {
    949     unsigned c = jc->todo_index;
    950     unsigned i = 0;
     1076    int c = jc->todo_index;
     1077    int i = 0;
    9511078
    9521079    #ifdef DEBUG
     
    9981125      }
    9991126
    1000       if (c < SMSC9218I_TX_JOBS_MAX) {
    1001         ++c;
    1002       } else {
    1003         c = 0;
    1004       }
     1127      c = (c + 1) % SMSC9218I_TX_JOBS;
    10051128    }
    10061129
     
    10321155    uint32_t tx_fifo_inf = regs->tx_fifo_inf;
    10331156    uint32_t data_free = SMSC9218I_TX_FIFO_INF_GET_FREE(tx_fifo_inf);
    1034     unsigned c = jc->transfer_index;
    1035     unsigned last_index = c;
    1036     unsigned i = 0;
    1037     unsigned n = jc->todo;
    1038     struct tcd_t *p = NULL;
     1157    int c = jc->transfer_index;
     1158    int last_index = c;
     1159    int i = 0;
     1160    int n = jc->todo;
    10391161
    10401162    #ifdef DEBUG
     
    10531175        last_index = c;
    10541176
    1055         /* Cache flush for previous data TCD */
    1056         if (p != NULL) {
    1057           rtems_cache_flush_multiple_data_lines(p, sizeof(*p));
    1058         }
     1177        /* Cache flush for data TCD */
     1178        smsc9218i_flush_tcd(tcd);
    10591179      } else {
    10601180        break;
    10611181      }
    10621182
    1063       p = tcd;
    1064       if (c < SMSC9218I_TX_JOBS_MAX) {
    1065         ++c;
    1066       } else {
    1067         c = 0;
    1068       }
     1183      c = (c + 1) % SMSC9218I_TX_JOBS;
    10691184    }
    10701185
     
    10931208
    10941209      /* Enable interrupt for last data TCD */
    1095       last->BMF.R = SMSC9218I_EDMA_TX_TCD_BMF_INTERRUPT;
    1096 
    1097       /* Cache flush for last data TCD */
    1098       rtems_cache_flush_multiple_data_lines(last, sizeof(*last));
     1210      last->BMF.R = SMSC9218I_TCD_BMF_LAST;
     1211      smsc9218i_flush_tcd(last);
    10991212      ppc_synchronize_data();
    11001213
     
    11071220      channel->CDF.R = start->CDF.R;
    11081221      channel->DLAST_SGA = start->DLAST_SGA;
    1109       channel->BMF.R = SMSC9218I_EDMA_TX_TCD_BMF_CLEAR;
     1222      channel->BMF.R = SMSC9218I_TCD_BMF_CLEAR;
    11101223      channel->BMF.R = start->BMF.R;
    11111224
     
    11361249  uint32_t status_used = SMSC9218I_TX_FIFO_INF_GET_SUSED(tx_fifo_inf);
    11371250  uint32_t s = 0;
    1138   unsigned n = jc->transfer;
     1251  int n = jc->transfer;
    11391252
    11401253  for (s = 0; s < status_used; ++s) {
     
    11551268
    11561269  if (
    1157     (events & (SMSC9218I_EVENT_EDMA | SMSC9218I_EVENT_EDMA_ERROR)) != 0
     1270    (events & (SMSC9218I_EVENT_DMA | SMSC9218I_EVENT_DMA_ERROR)) != 0
    11581271      && n > 0
    11591272  ) {
    1160     unsigned c = jc->empty_index;
    1161     unsigned i = 0;
     1273    int c = jc->empty_index;
     1274    int i = 0;
    11621275
    11631276    #ifdef DEBUG
     
    11651278    #endif
    11661279
    1167     if ((events & SMSC9218I_EVENT_EDMA_ERROR) != 0) {
    1168       ++e->transmit_edma_errors;
     1280    if ((events & SMSC9218I_EVENT_DMA_ERROR) != 0) {
     1281      ++e->transmit_dma_errors;
    11691282    }
    11701283
    11711284    /* Restore last data TCD */
    11721285    jc->data_tcd_table [jc->transfer_last_index].BMF.R =
    1173       SMSC9218I_EDMA_TX_TCD_BMF_LINK;
     1286      SMSC9218I_TCD_BMF_LINK;
    11741287
    11751288    for (i = 0; i < n; ++i) {
     
    11771290      m_free(jc->fragment_table [c]);
    11781291
    1179       if (c < SMSC9218I_TX_JOBS_MAX) {
    1180         ++c;
    1181       } else {
    1182         c = 0;
    1183       }
     1292      c = (c + 1) % SMSC9218I_TX_JOBS;
    11841293    }
    11851294
     
    12031312
    12041313/* FIXME */
    1205 static smsc9218i_transmit_job_control smsc_jc  __attribute__ ((aligned (32))) = {
     1314static smsc9218i_transmit_job_control smsc_tx_jc __attribute__((aligned (32))) = {
    12061315  .frame = NULL,
    12071316  .next_fragment = NULL,
     
    12261335  volatile smsc9218i_registers *const regs = smsc9218i;
    12271336  uint32_t mac_cr = 0;
    1228   smsc9218i_transmit_job_control *jc = &smsc_jc;
     1337  smsc9218i_transmit_job_control *jc = &smsc_tx_jc;
    12291338  unsigned i = 0;
    12301339
     
    12341343  e->edma_transmit.id = e->transmit_task;
    12351344  sc = mpc55xx_edma_obtain_channel(&e->edma_transmit);
    1236   RTEMS_CLEANUP_SC(sc, cleanup, "obtain transmit eDMA channel");
     1345  ASSERT_SC(sc);
    12371346
    12381347  /* Setup transmit eDMA descriptors */
    12391348  for (i = 0; i < SMSC9218I_TX_JOBS; ++i) {
    1240     unsigned ii = i < SMSC9218I_TX_JOBS_MAX ? i + 1 : 0;
     1349    unsigned ii = (i + 1) % SMSC9218I_TX_JOBS;
    12411350    struct tcd_t tcd = EDMA_TCD_DEFAULT;
    12421351    struct tcd_t *command_tcd = &jc->command_tcd_table [i];
     
    12481357    tcd.SDF.B.DSIZE = 2;
    12491358    tcd.CDF.B.CITER = 1;
    1250     tcd.BMF.R = SMSC9218I_EDMA_TX_TCD_BMF_LINK;
     1359    tcd.BMF.R = SMSC9218I_TCD_BMF_LINK;
    12511360    tcd.DADDR = (uint32_t) &regs->tx_fifo_data;
    12521361
    1253     tcd.DLAST_SGA = (uint32_t) next_command_tcd;
     1362    tcd.DLAST_SGA = (int32_t) next_command_tcd;
    12541363    *data_tcd = tcd;
    12551364
    12561365    tcd.SADDR = (uint32_t) &jc->command_table [i].a;
    12571366    tcd.NBYTES = 8;
    1258     tcd.DLAST_SGA = (uint32_t) data_tcd;
     1367    tcd.DLAST_SGA = (int32_t) data_tcd;
    12591368    *command_tcd = tcd;
    12601369  }
     
    12821391      SMSC9218I_EVENT_TX
    12831392        | SMSC9218I_EVENT_TX_START
    1284         | SMSC9218I_EVENT_EDMA
    1285         | SMSC9218I_EVENT_EDMA_ERROR,
     1393        | SMSC9218I_EVENT_DMA
     1394        | SMSC9218I_EVENT_DMA_ERROR,
    12861395      RTEMS_EVENT_ANY | RTEMS_WAIT,
    12871396      RTEMS_NO_TIMEOUT,
    12881397      &events
    12891398    );
    1290     RTEMS_CLEANUP_SC(sc, cleanup, "wait for events");
     1399    ASSERT_SC(sc);
    12911400
    12921401    SMSC9218I_PRINTF("tx: wake up: events = 0x%08" PRIx32 "\n", events);
     
    14761585    e
    14771586  );
    1478   RTEMS_SYSLOG_ERROR_SC(sc, "install interrupt handler\n");
     1587  ASSERT_SC(sc);
    14791588
    14801589  /* Enable interrupts and use push-pull driver (active low) */
     
    16391748{
    16401749  volatile smsc9218i_registers *const regs = smsc9218i;
    1641   smsc9218i_transmit_job_control *jc = &smsc_jc;
     1750  smsc9218i_transmit_job_control *jc = &smsc_tx_jc;
    16421751  int media = 0;
    16431752  bool media_ok = smsc9218i_media_status(e, &media);
     
    16521761  e->receive_drop += SMSC9218I_SWAP(regs->rx_drop);
    16531762
     1763  printf("PHY interrupts:            %u\n", e->phy_interrupts);
    16541764  printf("received frames:           %u\n", e->received_frames);
     1765  printf("receiver errors:           %u\n", e->receiver_errors);
    16551766  printf("receive interrupts:        %u\n", e->receive_interrupts);
    1656   printf("transmitted frames:        %u\n", e->transmitted_frames);
    1657   printf("transmit interrupts:       %u\n", e->transmit_interrupts);
    1658   printf("receiver errors:           %u\n", e->receiver_errors);
     1767  printf("receive DMA interrupts:    %u\n", e->receive_dma_interrupts);
    16591768  printf("receive to long errors:    %u\n", e->receive_too_long_errors);
    16601769  printf("receive collision errors:  %u\n", e->receive_collision_errors);
    16611770  printf("receive CRC errors:        %u\n", e->receive_crc_errors);
    1662   printf("receive eDMA errors:       %u\n", e->receive_edma_errors);
     1771  printf("receive DMA errors:        %u\n", e->receive_dma_errors);
    16631772  printf("receive drops:             %u\n", e->receive_drop);
    16641773  printf("receive watchdog timeouts: %u\n", e->receive_watchdog_timeouts);
     1774  printf("transmitted frames:        %u\n", e->transmitted_frames);
    16651775  printf("transmitter errors:        %u\n", e->transmitter_errors);
     1776  printf("transmit interrupts:       %u\n", e->transmit_interrupts);
     1777  printf("transmit DMA interrupts:   %u\n", e->transmit_dma_interrupts);
    16661778  printf("transmit status overflows: %u\n", e->transmit_status_overflows);
    16671779  printf("transmit frame errors:     %u\n", e->transmit_frame_errors);
    1668   printf("transmit eDMA errors:      %u\n", e->transmit_edma_errors);
    1669   printf("fixme tiny fragments:      %u\n", jc->fixme_tiny_fragments);
    1670   printf("fixme too many:            %u\n", jc->fixme_too_many);
     1780  printf("transmit DMA errors:       %u\n", e->transmit_dma_errors);
     1781  printf("frame compact count:       %u\n", jc->frame_compact_count);
    16711782}
    16721783
     
    16841795    case SIOCGIFMEDIA:
    16851796    case SIOCSIFMEDIA:
    1686       rtems_mii_ioctl(&e->mdio, e, (int) command, (int *) data);
     1797      rtems_mii_ioctl(&e->mdio, e, command, (int *) data);
    16871798      break;
    16881799    case SIOCGIFADDR:
     
    17191830
    17201831  sc = rtems_event_send(e->transmit_task, SMSC9218I_EVENT_TX_START);
    1721   RTEMS_SYSLOG_ERROR_SC(sc, "send transmit start event");
     1832  ASSERT_SC(sc);
    17221833}
    17231834
     
    17271838}
    17281839
    1729 static int smsc9218i_attach(struct rtems_bsdnet_ifconfig *config)
     1840static void smsc9218i_attach(struct rtems_bsdnet_ifconfig *config)
    17301841{
    17311842  smsc9218i_driver_entry *e = &smsc9218i_driver_data;
     
    17351846
    17361847  /* Check parameter */
    1737   if (unit_number < 0) {
    1738     RTEMS_SYSLOG_ERROR("parse error for interface name\n");
    1739     return 0;
    1740   }
    1741   if (unit_number != 0) {
    1742     RTEMS_DO_CLEANUP(smsc9218i_attach_cleanup, "unexpected unit number");
    1743   }
    1744   if (config->hardware_address == NULL) {
    1745     RTEMS_DO_CLEANUP(smsc9218i_attach_cleanup, "MAC address missing");
    1746   }
    1747   if (e->state != SMSC9218I_NOT_INITIALIZED) {
    1748     RTEMS_DO_CLEANUP(smsc9218i_attach_cleanup, "already attached");
    1749   }
     1848  assert(unit_number == 0);
     1849  assert(config->hardware_address != NULL);
     1850  assert(e->state == SMSC9218I_NOT_INITIALIZED);
    17501851
    17511852  /* Interrupt number */
     
    17881889  if_attach(ifp);
    17891890  ether_ifattach(ifp);
    1790 
    1791   return 1;
    1792 
    1793 smsc9218i_attach_cleanup:
    1794 
    1795   /* FIXME: Type */
    1796   free(unit_name, (int) 0xdeadbeef);
    1797 
    1798   return 0;
    17991891}
    18001892
     
    18031895  int attaching
    18041896) {
    1805   /* FIXME: Return value */
    1806 
    18071897  if (attaching) {
    1808     return smsc9218i_attach(config);
     1898    smsc9218i_attach(config);
    18091899  } else {
    18101900    /* TODO */
    1811     return 0;
    1812   }
    1813 }
     1901  }
     1902
     1903  /* FIXME: Return value */
     1904  return 0;
     1905}
Note: See TracChangeset for help on using the changeset viewer.