📄 sonic.c
字号:
}/* * Send packet */SONIC_STATIC void sonic_sendpacket (struct ifnet *ifp, struct mbuf *m){ struct sonic_softc *sc = ifp->if_softc; struct mbuf *l = NULL; TransmitDescriptorPointer_t tdp; volatile struct TransmitDescriptorFragLink *fp; unsigned int packetSize; int i; rtems_event_set events; static char padBuf[64]; /* printf( "sonic_sendpacket %p\n", m ); */ /* * Wait for transmit descriptor to become available. Only retire TDA's * if there are no more free buffers to minimize TX latency. Retire TDA'a * on the way out. */ while (sc->tdaHead->next->status != 0) { /* * Free up transmit descriptors */ sonic_retire_tda (sc); if (sc->tdaHead->next->status == 0) break;#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS) printf("blocking until TDAs are available\n");#endif /* * Enable PINT interrupts. sonic_clear_interrupts( sc, ISR_PINT ); sonic_enable_interrupts( sc, IMR_PINTEN ); */ /* * Wait for PINT TX interrupt. Every fourth TX buffer will raise PINT. */ rtems_bsdnet_event_receive (INTERRUPT_EVENT, RTEMS_WAIT|RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); sonic_disable_interrupts( sc, IMR_PINTEN ); sonic_retire_tda (sc); } /* * Fill in the transmit descriptor fragment descriptors. * ===CACHE=== * If data cache is operating in write-back mode, flush cached * data to memory. */ tdp = sc->tdaHead->next; tdp->mbufp = m; packetSize = 0; fp = tdp->frag; for (i = 0 ; i < MAXIMUM_FRAGS_PER_DESCRIPTOR ; i++, fp++) { /* * Throw away empty mbufs */ if (m->m_len) { void *p = mtod (m, void *); fp->frag_lsw = LSW(p); fp->frag_msw = MSW(p); fp->frag_size = m->m_len; packetSize += m->m_len;#if (SONIC_DEBUG & SONIC_DEBUG_FRAGMENTS) printf( "fp %p 0x%04x%04x %d=%d .. %d\n", fp, fp->frag_msw, fp->frag_lsw, fp->frag_size, m->m_len, packetSize );#endif#if (SONIC_DEBUG & SONIC_DEBUG_DUMP_TX_MBUFS) Dump_Buffer( p, (fp->frag_size > MAXIMUM_FRAME_SIZE) ? MAXIMUM_FRAME_SIZE : fp->frag_size );#endif l = m; m = m->m_next; } else { struct mbuf *n; MFREE (m, n); m = n; if (l != NULL) l->m_next = m; } /* * Break out of the loop if this mbuf is the last in the frame. */ if (m == NULL) break; } /* * Pad short packets. */ if ((packetSize < 64) && (i < MAXIMUM_FRAGS_PER_DESCRIPTOR)) { int padSize = 64 - packetSize; fp++; fp->frag_lsw = LSW(padBuf); fp->frag_msw = MSW(padBuf); fp->frag_size = padSize;#if (SONIC_DEBUG & SONIC_DEBUG_FRAGMENTS) printf( "PAD fp %p 0x%04x%04x %d\n", fp, fp->frag_msw, fp->frag_lsw, fp->frag_size );#endif packetSize += padSize; i++; } /* * Fill Transmit Descriptor */ tdp->pkt_size = packetSize; tdp->frag_count = i + 1; tdp->status = 0; /* * Chain onto list and start transmission. */ tdp->linkp = &(fp+1)->frag_link; *tdp->linkp = LSW(tdp->next) | TDA_LINK_EOL; if ( sc->tdaHead->frag_count ) *sc->tdaHead->linkp &= ~TDA_LINK_EOL; sc->tdaHead = tdp; /* Start transmission */ sonic_command(sc, CR_TXP ); /* * Free up transmit descriptors on the way out. */ sonic_retire_tda (sc);}/* * Driver transmit daemon */SONIC_STATIC void sonic_txDaemon (void *arg){ struct sonic_softc *sc = (struct sonic_softc *)arg; struct ifnet *ifp = &sc->arpcom.ac_if; struct mbuf *m; rtems_event_set events; for (;;) { /* * Wait for packet */ rtems_bsdnet_event_receive ( START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events ); /* * Send packets till queue is empty */ for (;;) { /* * Get the next mbuf chain to transmit. */ IF_DEQUEUE(&ifp->if_snd, m); if (!m) break; sonic_sendpacket (ifp, m); } ifp->if_flags &= ~IFF_OACTIVE; }}/* ****************************************************************** * * * Receiver Routines * * * ****************************************************************** *//* * Wait for SONIC to hand over a Receive Descriptor. */SONIC_STATIC void sonic_rda_wait( struct sonic_softc *sc, ReceiveDescriptorPointer_t rdp){ int i; void *rp = sc->sonic; rtems_event_set events; /* * Wait for Receive Descriptor. * The order of the tests is very important. * The RDA is checked after RBAE is detected. This ensures that * the driver processes all RDA entries before reusing the RRA * entry holding the giant packet. * The event wait is done after the RDA and RBAE checks. This * catches the possibility that a Receive Descriptor became ready * between the call to this function and the clearing of the * interrupt status register bit. */ for (;;) { /* * Has a giant packet arrived? * The National DP83932C data sheet is very vague on what * happens under this condition. The description of the * Interrupt Status Register (Section 4.3.6) states, * ``Reception is aborted and the SONIC fetches the next * available resource descriptors in the RRA. The buffer * space is not re-used and an RDA is not setup for the * truncated packet.'' * I take ``Reception is aborted'' to mean that the RXEN * bit in the Command Register is cleared and must be set * by the driver to begin reception again. * Unfortunately, an alternative interpretation could be * that only reception of the current packet is aborted. * This would be more difficult to recover from.... */ if ((*sc->read_register)( rp, SONIC_REG_ISR ) & ISR_RBAE) {#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS) printf( "ERROR: looks like a giant packet -- RBAE\n" );#endif /* * One more check to soak up any Receive Descriptors * that may already have been handed back to the driver. */ if (rdp->in_use == RDA_IN_USE) {#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS) printf( "ERROR: nope just an RBAE\n" );#endif break; } /* * Check my interpretation of the SONIC manual. */ if ((*sc->read_register)( rp, SONIC_REG_CR ) & CR_RXEN) rtems_panic ("SONIC RBAE/RXEN"); /* * Update statistics */ sc->rxGiant++; /* * Reuse receive buffer. * Again, the manual is subject to interpretation. The * RRP register is described as, `the lower address of * the next descriptor the SONIC will read.'' * Since, acording to the ISR/RBAE notes, the SONIC has * ``fetched the next available resource descriptor in * the RRA'', I interpret this to mean that that the * driver has to move the RRP back *two* entries to * reuse the receive buffer holding the giant packet. */ for (i = 0 ; i < 2 ; i++) { if ((*sc->read_register)( rp, SONIC_REG_RRP ) == (*sc->read_register)( rp, SONIC_REG_RSA )) (*sc->write_register)( rp, SONIC_REG_RRP, (*sc->read_register)( rp, SONIC_REG_REA ) ); (*sc->write_register)( rp, SONIC_REG_RRP, (*sc->read_register)(rp, SONIC_REG_RRP) - sizeof(ReceiveResource_t) ); } /* * Restart reception */ sonic_clear_interrupts( sc, ISR_RBAE ); sonic_command( sc, CR_RXEN ); } /* * Has Receive Descriptor become available? */ if (rdp->in_use == RDA_IN_USE) break; /* * Enable interrupts. */ sonic_enable_interrupts( sc, (IMR_PRXEN | IMR_RBAEEN) ); /* * Wait for interrupt. */ rtems_bsdnet_event_receive( INTERRUPT_EVENT, RTEMS_WAIT|RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events ); }#if (SONIC_DEBUG & SONIC_DEBUG_DESCRIPTORS) printf( "RDA %p\n", rdp );#endif#if (SONIC_DEBUG & SONIC_DEBUG_ERRORS) if (rdp->status & 0x000E) printf( "ERROR: RDA %p (0x%04x)\n", rdp, rdp->status );#endif}#ifdef CPU_U32_FIX/* * Routine to align the received packet so that the ip header * is on a 32-bit boundary. Necessary for cpu's that do not * allow unaligned loads and stores and when the 32-bit DMA * mode is used. * * Transfers are done on word basis to avoid possibly slow byte * and half-word writes. */ void ipalign(struct mbuf *m){ unsigned int *first, *last, data; unsigned int tmp = 0; if ((((int) m->m_data) & 2) && (m->m_len)) { last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3); first = (unsigned int *) (((int) m->m_data) & ~3); tmp = *first << 16; first++; do { data = *first; *first = tmp | (data >> 16); tmp = data << 16; first++; } while (first <= last); m->m_data = (caddr_t)(((int) m->m_data) + 2); }}#endif/* * SONIC reader task */SONIC_STATIC void sonic_rxDaemon (void *arg){ struct sonic_softc *sc = (struct sonic_softc *)arg; struct ifnet *ifp = &sc->arpcom.ac_if; void *rp = sc->sonic; struct mbuf *m; rtems_unsigned16 status; ReceiveDescriptorPointer_t rdp; ReceiveResourcePointer_t rwp, rea; rtems_unsigned16 newMissedTally, oldMissedTally; rwp = sc->rsa; rea = sc->rea; rdp = sc->rda; /* * Start the receiver */ oldMissedTally = (*sc->read_register)( rp, SONIC_REG_MPT ); /* * Input packet handling loop */ for (;;) { /* * Wait till SONIC supplies a Receive Descriptor. */ if (rdp->in_use == RDA_FREE) { sonic_rda_wait (sc, rdp); }#if (SONIC_DEBUG & SONIC_DEBUG_DESCRIPTORS) printf( "Incoming packet %p status=0x%04x\n", rdp, rdp->status );#endif /* * Check that packet is valid */ status = rdp->status; if (status & RDA_STATUS_PRX) { struct ether_header *eh; void *p; /* * Pass the packet up the chain. * The mbuf count is reduced to remove * the frame check sequence at the end * of the packet. * ===CACHE=== * Invalidate cache entries for this memory. */#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY_DESCRIPTORS) sonic_print_rx_descriptor( rdp ); if ((LSW(rdp->mbufp->m_data) != rdp->pkt_lsw) || (MSW(rdp->mbufp->m_data) != rdp->pkt_msw)) printf ("SONIC RDA/RRA %p, %08x\n",rdp->mbufp->m_data,(rdp->pkt_msw << 16) | (rdp->pkt_lsw & 0x0ffff));#endif rdp->byte_count &= 0x0ffff; /* ERC32 pollutes msb of byte_count */ m = rdp->mbufp; m->m_len = m->m_pkthdr.len = rdp->byte_count - sizeof(rtems_unsigned32) - sizeof(struct ether_header); eh = mtod (m, struct ether_header *); m->m_data += sizeof(struct ether_header); #ifdef CPU_U32_FIX ipalign(m); /* Align packet on 32-bit boundary */#endif#if (SONIC_DEBUG & SONIC_DEBUG_DUMP_RX_MBUFS) Dump_Buffer( (void *) eh, sizeof(struct ether_header) ); Dump_Buffer( (void *) m, 96 /* m->m_len*/ );#endif /* printf( "ether_input %p\n", m ); */ /* printf( "pkt %p, seq %04x, mbuf %p, m_data %p\n", rdp, rdp->seq_no, m, m->m_data ); printf( "%u, %u\n", ((int*)m->m_data)[6], ((int*)m->m_data)[7]); */ ether_input (ifp, eh, m); /* */ /* * Sanity check that Receive Resource Area is * still in sync with Receive Descriptor Area * The buffer reported in the Receive Descriptor * should be the same as the buffer in the Receive * Resource we are about to reuse. *//* XXX figure out whether this is valid or not */#if 0 if ((LSW(p) != rwp->buff_ptr_lsw) || (MSW(p) != rwp->buff_ptr_msw)) rtems_panic ("SONIC RDA/RRA");#endif /* * Allocate a new mbuf. */ MGETHDR (m, M_WAIT, MT_DATA); MCLGET (m, M_WAIT); m->m_pkthdr.rcvif = ifp; rdp->mbufp = m; p = mtod (m, void *); /* * Reuse Receive Resource. */ rwp->buff_ptr_lsw = LSW(p); rwp->buff_ptr_msw = MSW(p); rwp->buff_wc_lsw = RBUF_WC; rwp->buff_wc_msw = 0; rwp++; if (rwp == rea) {#if (SONIC_DEBUG & SONIC_DEBUG_MEMORY) printf( "Wrapping RWP from %p to %p\n", rwp, sc->rsa );#endif rwp = sc->rsa; } (*sc->write_register)( rp, SONIC_REG_RWP , LSW(rwp) ); /* * Tell the SONIC to reread the RRA. */ if ((*sc->read_register)( rp, SONIC_REG_ISR ) & ISR_RBE) sonic_clear_interrupts( sc, ISR_RBE ); } else { if (status & RDA_STATUS_COL) sc->rxCollision++; if (status & RDA_STATUS_FAER) sc->rxNonOctet++; else if (status & RDA_STATUS_CRCR) sc->rxBadCRC++; } /* * Count missed packets */ newMissedTally = (*sc->read_register)( rp, SONIC_REG_MPT ); if (newMissedTally != oldMissedTally) { sc->rxMissed += (newMissedTally - oldMissedTally) & 0xFFFF; newMissedTally = oldMissedTally; } /* * Move to next receive descriptor and update EOL */ rdp->link |= RDA_LINK_EOL; rdp->in_use = RDA_FREE; sc->rdp_last->link &= ~RDA_LINK_EOL; sc->rdp_last = rdp; rdp = rdp->next; }}/* ****************************************************************** * * * Initialization Routines * * * ****************************************************************** *//* * Initialize the SONIC hardware */SONIC_STATIC void sonic_initialize_hardware(struct sonic_softc *sc){ void *rp = sc->sonic; int i; unsigned char *hwaddr; rtems_isr_entry old_handler; TransmitDescriptorPointer_t tdp; ReceiveDescriptorPointer_t ordp, rdp; ReceiveResourcePointer_t rwp; struct mbuf *m; void *p; CamDescriptorPointer_t cdp; /* * The Revision B SONIC has a horrible bug known as the "Zero * Length Packet bug". The initial board used to develop this * driver had a newer revision of the SONIC so there was no reason * to check for this. If you have the Revision B SONIC chip, then * you need to add some code to the RX path to handle this weirdness. */ if ( (*sc->read_register)( rp, SONIC_REG_SR ) <= SONIC_REVISION_B ) { rtems_fatal_error_occurred( 0x0BADF00D ); /* don't eat this part :) */ } /* * Set up circular linked list in Transmit Descriptor Area. * Use the PINT bit in the transmit configuration field to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -