⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 elnk.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 5 页
字号:
static void no_op(const rtems_irq_connect_data* irq){   return;}static int elnkIsOn(const rtems_irq_connect_data* irq){  return BSP_irq_enabled_at_i8259s (irq->name);}static void elnk_start_txchain( struct elnk_softc *sc, struct TXMD *chainhead ){   xl_wait(sc);   CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_STALL);   /* save the address of the TX list */   sc->last_txchain_head = chainhead;   sc->tx_idle = 0;   xl_wait(sc);   CSR_WRITE_4(sc, XL_DOWNLIST_PTR, phys_to_bus( sc->last_txchain_head ));   CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL);}/* * ELNK interrupt handler */static rtems_isrelnk_interrupt_handler ( struct elnk_softc *sc ){   struct ifnet		*ifp = &sc->arpcom.ac_if;   u_int16_t		status;   while( ((status = CSR_READ_2(sc, XL_STATUS)) & XL_INTRS) && status != 0xFFFF)   {      sc->xl_stats.device_interrupts++;      CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK | (status & XL_INTRS));#if 0      printk("etherlink : unit elnk%d intstatus %04x\n", sc->xl_unit, status  );#endif      if (status & XL_STAT_UP_COMPLETE)       {#if 0         printk("etherlink : unit elnk%d rx\n", sc->xl_unit );#endif         /* received packets */         rtems_event_send(rxDaemonTid, sc->ioevent);      }      if( (status & XL_STAT_DOWN_COMPLETE) || (status & XL_STAT_TX_COMPLETE) )      {         /* all packets uploaded to the device */         struct TXMD *chaintailmd = NULL;         if( status & XL_STAT_TX_COMPLETE )         {            /* if we got a tx complete error, count it, then reset the               transmitter.  Consider the entire chain lost.. */            ifp->if_oerrors++;            sc->xl_stats.txcomplete_ints++;            printk("etherlink : unit elnk%d transmit error\n", sc->xl_unit );            /* reset, re-enable fifo */            xl_wait(sc);            CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_DISABLE);            xl_wait(sc);            CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET | 1 );            xl_wait(sc);            CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE);            xl_wait(sc);         }         /* send the chain head to the tx task which will recover the            whole chain */         rtems_message_queue_send( chainRecoveryQueue, &sc->last_txchain_head, sizeof(struct TXMD *));         /* set up the next chain */         if( sc->last_txchain_head->chainptr )         {            /* check the head of the chain of packets we just finished,             * if != 0, either this is a chain of 2 or more packets or             * its a single packet chain and another chain is ready to             * send.             */            if( (int)sc->last_txchain_head->chainptr == -1 )            {               /*                ** single packet was sent so no indirection to the last               ** entry in the chain.  since chainptr is != 0, then               ** another chain is ready starting from the packet AFTER               ** the chain we just finished. - in this case the last               ** chain's head == its tail               */               chaintailmd = sc->last_txchain_head;            }            else            {               /*               ** otherwise, this is a pointer to the last packet in the               ** chain of 2 or more packets.  If the chain's last               ** packet's chainptr is != 0, then another chain is ready               ** to send.               */               chaintailmd = sc->last_txchain_head->chainptr;               if( !chaintailmd->chainptr ) chaintailmd = NULL;            }         }         if( chaintailmd )         {            /* the next MD is the start of another chain */            elnk_start_txchain(sc, chaintailmd->next_md );         }         else         {            /* otherwise nothing to send, so go idle */            sc->tx_idle = -1;            /* wake up the tx daemon once so we're sure this last chain               will be freed */            rtems_event_send( txDaemonTid, sc->ioevent );#if 0            printk("unit elnk%d tx done\n", sc->xl_unit );#endif         }      }      if (status & XL_STAT_ADFAIL)       {         printk("etherlink : unit elnk%d Catastrophic bus failure\n", sc->xl_unit );      }      if (status & XL_STAT_STATSOFLOW)       {         sc->xl_stats_no_timeout = 1;         xl_stats_update(sc->stat_timer_id,sc);         sc->xl_stats_no_timeout = 0;      }   }   #if 0   {      unsigned16 intstatus, intenable, indenable;      intstatus = CSR_READ_2(sc, XL_STATUS );      XL_SEL_WIN(5);      intenable = CSR_READ_2(sc, XL_W5_INTR_ENB );      indenable = CSR_READ_2(sc, XL_W5_STAT_ENB );      XL_SEL_WIN(7);      printk("etherlink : unit elnk%d istat %04x, ien %04x, ind %04x\n", sc->xl_unit, intstatus, intenable, indenable  );   }#endif}static rtems_isrelnk_interrupt_handler_entry(){   int i;   /*   ** Check all the initialized units for interrupt service   */   for(i=0; i< NUM_UNITS; i++ )   {      if( elnk_softc[i].ioaddr )         elnk_interrupt_handler( &elnk_softc[i] );   }}/* * Initialize the ethernet hardware */static voidelnk_initialize_hardware (struct elnk_softc *sc){   unsigned char *cp;   int i, j, rxsize, txsize, ringsize;   /*    * Init RX ring    */   cp = (unsigned char *)malloc( (ringsize = ((rxsize = (sc->numRxbuffers * sizeof(struct RXMD))) +                                               (txsize = (sc->numTxbuffers * sizeof(struct TXMD)))) ) +                                 + CPU_CACHE_ALIGNMENT_FOR_BUFFER);   sc->bufferBase = cp;   cp += (CPU_CACHE_ALIGNMENT_FOR_BUFFER - (int)cp) & (CPU_CACHE_ALIGNMENT_FOR_BUFFER - 1);#if defined(__i386__)#ifdef PCI_BRIDGE_DOES_NOT_ENSURE_CACHE_COHERENCY_FOR_DMA    if (_CPU_is_paging_enabled())      _CPU_change_memory_mapping_attribute         (NULL, cp, ringsize, PTE_CACHE_DISABLE | PTE_WRITABLE);#endif#endif   sc->ringBase = cp;   /* build tx and rx rings */   sc->rx_ring = (struct RXMD *)sc->ringBase;   sc->tx_ring = (struct TXMD *)&sc->ringBase[ rxsize ];   {      struct mbuf    *m;      struct RXMD    *nxtmd;      /*        * The rx ring is easy as its just an array of RXMD structs.  New       * mbuf entries are allocated from the stack whenever the rx       * daemon forwards an incoming packet into it.  Here, we       * pre-allocate the rx mbufs for the rx ring entries.       */      for(i=0 ; i<sc->numRxbuffers; i++)      {         if( ((unsigned32)&sc->rx_ring[i] & 0x7) )         {            rtems_panic ("etherlink : unit elnk%d rx ring entry %d not aligned to 8 bytes\n", sc->xl_unit, i );         }               /* allocate an mbuf for each receive descriptor */         MGETHDR (m, M_WAIT, MT_DATA);         MCLGET (m, M_WAIT);         m->m_pkthdr.rcvif = &sc->arpcom.ac_if;         if( i == sc->numRxbuffers-1 )            nxtmd = &sc->rx_ring[0];         else            nxtmd = &sc->rx_ring[i+1];         sc->rx_ring[i].next_md = nxtmd;         sc->rx_ring[i].mbuf = m;         st_le32( &sc->rx_ring[i].status, 0);         st_le32( &sc->rx_ring[i].next, (unsigned32)phys_to_bus( nxtmd ));         st_le32( &sc->rx_ring[i].addr, (unsigned32)phys_to_bus( mtod(m, void *) ));         st_le32( &sc->rx_ring[i].length, XL_LAST_FRAG | XL_PACKET_SIZE );      }      sc->curr_rx_md = &sc->rx_ring[0];   }   {      struct TXMD *thismd, *nxtmd;      /*        * The tx ring is more complex. Each MD has an array of fragment       * descriptors that are loaded from each packet as they arrive       * from the stack.  Each packet gets one ring entry, this allows       * the lanboard to efficiently assemble the piecemeal packets into       * a contiguous unit at transmit time, rather than spending       * cputime concatenating them first.  Although the next_md fields       * form a ring, the DPD next is filled only when packets are added       * to the tx chain, thus last entry of a series of packets has the       * requisite dpd->next value == 0 to terminate the dma.  mbuf       * holds the packet info so it can be freed once the packet has       * been sent.  chainptr is used to link the head & tail of a chain       * of 2 or more packets.  A chain is formed when the tx daemon       * gets 2 or more packets from the stack's queue in a service       * period, so higher outgoing loads are handled as efficiently as       * possible.       */      for(i=0 ; i<sc->numTxbuffers; i++)      {         if( ((unsigned32)&sc->tx_ring[i] & 0x7) )         {            rtems_panic ("etherlink : unit elnk%d tx ring entry %d not aligned to 8 bytes\n", sc->xl_unit, i );         }         if( i == sc->numTxbuffers-1 )            nxtmd = &sc->tx_ring[0];         else            nxtmd = &sc->tx_ring[i+1];         thismd = &sc->tx_ring[i];         thismd->next_md = nxtmd;         thismd->chainptr = NULL;         thismd->mbuf = NULL;         st_le32( &thismd->status, XL_TXSTAT_DL_COMPLETE );         st_le32( &thismd->next, 0);         for(j=0; j< NUM_FRAGS; j++)         {            st_le32( &thismd->txfrags[j].addr, 0 );            st_le32( &thismd->txfrags[j].length, 0 );         }      }      sc->last_tx_md = &sc->tx_ring[0];   }#ifdef ELNK_DEBUG   printk("etherlink : %02x:%02x:%02x:%02x:%02x:%02x   name 'elnk%d', io %x, int %d\n",          sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1],          sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3],          sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5],          sc->xl_unit,           (unsigned)sc->ioaddr, sc->irqInfo.name );#endif   sc->irqInfo.hdl  = (rtems_irq_hdl)elnk_interrupt_handler_entry;   sc->irqInfo.on   = no_op;   sc->irqInfo.off  = no_op;   sc->irqInfo.isOn = elnkIsOn;   if( sc->irqInfo.name != 255 )   {      int st;#ifdef BSP_SHARED_HANDLER_SUPPORT      st = BSP_install_rtems_shared_irq_handler( &sc->irqInfo );#else      st = BSP_install_rtems_irq_handler( &sc->irqInfo );#endif      if (!st)         rtems_panic ("etherlink : unit elnk%d Interrupt name %d already in use\n", sc->xl_unit, sc->irqInfo.name );   }   else   {      printk("etherlink : unit elnk%d Interrupt not specified by device\n", sc->xl_unit );   }}static voidelnk_rxDaemon (void *arg){   struct elnk_softc     *sc;   struct ether_header   *eh;   struct mbuf           *m;   struct RXMD           *rmd;   unsigned int          i,len, rxstat;   rtems_event_set       events;   for (;;)   {      rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS,                                  RTEMS_WAIT|RTEMS_EVENT_ANY,                                  RTEMS_NO_TIMEOUT,                                  &events);      for(;;)      {         for(i=0; i< NUM_UNITS; i++ )         {            sc = &elnk_softc[i];            if( sc->ioaddr )            {               if( events & sc->ioevent )               {                  struct ifnet *ifp = &sc->arpcom.ac_if;                  rmd   = sc->curr_rx_md;                  /*                  ** Read off all the packets we've received on this unit                  */                  while( (rxstat = ld_le32(&rmd->status)) )                  {                     if (rxstat & XL_RXSTAT_UP_ERROR)                      {                        printk("unit %i up error\n", sc->xl_unit );                        ifp->if_ierrors++;                     }                     if( (rxstat & XL_RXSTAT_UP_CMPLT) )                      {#if 0                        {                           char *pkt, *delim;                           int  i;                           pkt = mtod(rmd->mbuf, char *);                           printk("unit %i rx  pkt (%08x) ", sc->xl_unit, pkt );                           for(delim="", i=0; i < sizeof(struct ether_header)+8; i++, delim=":")                              printk("%s%02x", delim, (char) pkt[i] );                           printk("\n");                        }#endif                        /* pass on the packet in the mbuf */                        len = ( ld_le32(&rmd->status) & XL_RXSTAT_LENMASK);                        m = rmd->mbuf;                        m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);                        eh = mtod(m, struct ether_header *);                        m->m_data += sizeof(struct ether_header);                        ether_input(ifp, eh, m);                        /* get a new mbuf */                        MGETHDR (m, M_WAIT, MT_DATA);                        MCLGET (m, M_WAIT);                        m->m_pkthdr.rcvif = ifp;                        rmd->mbuf   = m;                        st_le32( &rmd->status, 0 );                        st_le32( &rmd->addr, (unsigned32)phys_to_bus(mtod(m, void *)) );                     }                     else                     {                        /* some kind of packet failure */                        printk("etherlink : unit elnk%d bad receive status -- packet dropped\n", sc->xl_unit);                        ifp->if_ierrors++;                     }                     /* clear descriptor status */                     rmd->status = 0;                           rmd = rmd->next_md;                  }                  sc->curr_rx_md = rmd;               }            }         }         /*         ** If more events are pending, service them befo

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -