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

📄 lan91c111.c

📁 lwip tcp/ip 协议栈 adsp BF533 DSP 移植 用 visual dsp++ 编译
💻 C
📖 第 1 页 / 共 4 页
字号:

   packet_number = _inpw(FIFO_REG);

   if ( packet_number & RXFIFO_REMPTY )
   {
      // we got called , but nothing was on the FIFO
      // so, just leave
      return;
   }

   //  start reading from the start of the packet
   _outpw(PTR_REG, PTR_READ | PTR_RCV | PTR_AUTOINC);

   // First two words are status and packet_length
   status          = _inpw(DATA_REG);
   packet_length   = _inpw(DATA_REG);

   // store for debug
   dev->LAN_state.rpsize = packet_length;

   // max 2k packets over Ethernet
   packet_length &= 0x07ff;  /* mask off top bits */

   if ( !(status & RS_ERRORS ) )
   {
      ADI_ETHER_BUFFER *tmp_q_ele;

#if LAN91C111_LOG_NET_ERRORS
      if ( status & RS_MULTICAST ) dev->Stats->cEMAC_RX_CNT_MULTI++;
#endif

      // collect the packet
      // first two words already read: status and packet size
	  if((status & 0x1000))
	      packet_length -= 5;   //## used to be 4
	  else
	  {
		  // Get the chip id and fix the hardware anomaly rev-A
		  _outpw(BSR_REG,3);
		  chip_id = _inpw(REV_REG);
		 if( ((chip_id & 0x0F00) == 9) && ((chip_id & 0xF000) == 0) ) 
			 packet_length -= 4;
		 else
			 packet_length -= 6;
		 _outpw(BSR_REG, 2);
	  }
	  
	  
      tmp_q_ele = dev->m_RxEnqueuedHead;
      if (tmp_q_ele != NULL) {
		  elnth = (unsigned short *)tmp_q_ele->Data;
		  *elnth = (packet_length + 4);	// add on 4 bytes for the CRC (even if we dont store it)
		  tmp_q_ele->ProcessedElementCount = (*elnth+2+tmp_q_ele->ElementWidth-1)/tmp_q_ele->ElementWidth;
      }
     
      if ((tmp_q_ele)&&(tmp_q_ele->ProcessedElementCount <= tmp_q_ele->ElementCount))
      {
         //store packet length
         // assign pointer
         data = (void *)( ((char *)tmp_q_ele->Data) +2);
      }
      else
      {
#if LAN91C111_LOG_NET_ERRORS
		 if (tmp_q_ele) {
         	dev->Stats->cEMAC_RX_CNT_LONG++;
		 } else {
         	dev->Stats->cEMAC_RX_CNT_LOST++;
		 }
#endif
         // drop packet
         //  good or bad, delete this packet */
         _outpw(MMU_CMD_REG, MC_RELEASE);
         return;
      }

#ifndef USE_16_BIT
      // read in 32bits
      for (i=0; i <= (packet_length >> 2); i++)
      {
         *data++ = _inpd(DATA_REG);
      }
#else
      for (i=0; i <= (packet_length >> 1); i++)
      {
         *data++ = _inpw(DATA_REG);
      }
#endif // USE_16_BIT


      /* Change the Enqueued head */
      dev->m_RxEnqueuedHead = (ADI_ETHER_BUFFER*)tmp_q_ele->pNext;
      dev->m_RxEnqueuedCount--;
      if (dev->m_RxEnqueuedCount == 0)
         dev->m_RxEnqueuedTail = NULL;

      /* Add the packet to dequeued list*/
      if (dev->m_RxDequeuedCount)
         dev->m_RxDequeuedTail->pNext = (ADI_ETHER_BUFFER *)tmp_q_ele;
      else
         dev->m_RxDequeuedHead = tmp_q_ele;

      //No matter what this is also the tail.
      dev->m_RxDequeuedTail = tmp_q_ele;
      //And tail->next should point to NULL
      tmp_q_ele->pNext = NULL;
      dev->m_RxDequeuedCount++;
      
      // finally we have to update the status word etc
      tmp_q_ele->ProcessedFlag = 1;
      tmp_q_ele->StatusWord = 0x3000 + (packet_length+4);

#if LAN91C111_LOG_NET_ERRORS
      dev->Stats->cEMAC_RX_CNT_OK++;
#endif
   }
   else
   {
#if LAN91C111_LOG_NET_ERRORS
      if ( status & RS_ALGNERR )  dev->Stats->cEMAC_RX_CNT_ALIGN++;
      if ( status & (RS_TOOSHORT|RS_TOOLONG)) dev->Stats->cEMAC_RX_CNT_LONG++;
      if ( status & RS_BADCRC)    dev->Stats->cEMAC_RX_CNT_FCS++;
#endif
   }

   while ( _inpw(MMU_CMD_REG ) & MC_BUSY );

   //  good or bad, delete this packet */
   _outpw(MMU_CMD_REG, MC_RELEASE);
   return;
}

/******************************************************************************
 * TX IRQ Error Handler Function for SMSC91C111
 *
 * Purpose:  Handle the transmit error message.
 *  This is only called when an TX error occured because of
 *  the AUTO_RELEASE mode.
 *
 * Actions:
 *  - Save pointer and packet no
 *  - Get the packet no from the top of the queue
 *  - check if it's valid ( if not, is this an error??? )
 *  - read the status word
 *  - record the error
 *  - ( resend?  Not really, since we don't want old packets around )
 *  - Restore saved values
 *
 *****************************************************************************/
static void LAN91C111_tx(ADI_ETHER_LAN91C111_DATA * dev)
{
   volatile unsigned char saved_packet;
   volatile unsigned char packet_no;
   volatile unsigned short tx_status;

   // bank 2 already opened by main IRQ entry
   saved_packet = _inp(PN_REG);
   packet_no = _inpw(FIFO_REG);
   packet_no &= 0x7F;

   // If the TX FIFO is empty then nothing to do
   if ( packet_no & TXFIFO_TEMPTY )
      return;

   // select this as the packet to read from
   _outp(PN_REG, packet_no);

   // read the first word (status word) from this packet
   _outpw(PTR_REG, PTR_AUTOINC|PTR_READ);

   // read tx status
   tx_status = _inpw(DATA_REG );

#if LAN91C111_LOG_NET_ERRORS
   dev->Stats->cEMAC_TX_CNT_ABORT++;
   if ( tx_status & TS_LOSTCAR ) dev->Stats->cEMAC_TX_CNT_CRS++;
   if ( tx_status & TS_LATCOL  ) dev->Stats->cEMAC_TX_CNT_LATE++;
#endif

   // re-enable transmit
   _outpw(BSR_REG, 0);
   _outpw(TCR_REG, _inpw(TCR_REG) | TCR_TXENA);

   // kill the packet
   _outpw(BSR_REG, 2);
   _outpw(MMU_CMD_REG, MC_FREEPKT);

   // one less packet waiting for me
   dev->LAN_state.packets_waiting--;

   // Don't change Packet Number Reg until busy bit is cleared
   while ( _inpw(MMU_CMD_REG) & MC_BUSY );

   _outp(PN_REG, saved_packet);

   return;
}

/******************************************************************************
 * IRQ Sub Function: smc_phy_interrupt for the LAN91C111
 *
 * Purpose:
 *  Handle interrupts relating to PHY register 18.
 *
 * Actions:
 *  Log last Phy18 Interrupt Source
 *
 *****************************************************************************/
static void LAN91C111_phy_interrupt(ADI_ETHER_LAN91C111_DATA * cptr)
{
   volatile unsigned short phy18;

   while (1)
   {
      // Read PHY Register 18, Status Output
      phy18 = LAN91C111_read_phy_register(PHY_INT_REG);

      // Exit if no more changes
      if (phy18 == cptr->LAN_state.lastPhy18)
         break;

      // Update the last phy 18 variable
      cptr->LAN_state.lastPhy18 = phy18;
   } // end while
}
/******************************************************************************
 * LANC91C111: LAN91C111_hardware_send_packet
 *
 * Purpose:
 *  This sends the actual packet to the SMC9xxx chip.
 *
 *  - First, see if a pending packet is available.
 *      this should NOT be called if there is none
 *  - Find the packet number that the chip allocated
 *  - Point the data pointers at it in memory
 *  - Set the length word in the chip's memory
 *  - Dump the packet to chip memory
 *  - Check if a last byte is needed ( odd length packet )
 *      if so, set the control flag right
 *  - Tell the LAn 91C111 to send it
 *  - Enable the transmit interrupt, so I know if it failed
 *  - Free the packet data if I actually sent it.
 *
 *****************************************************************************/
static unsigned char LAN91C111_hardware_send_packet(ADI_ETHER_LAN91C111_DATA * cptr)
{
   int     i;
   unsigned char    packet_no;
   unsigned short   length;
#ifndef USE_16_BIT
    unsigned int    *buf;
#else
    unsigned short  *buf;
#endif
   unsigned short	 *elnth;
   unsigned short	 lnth_first;
   ADI_ETHER_BUFFER  *bf = cptr->m_TxEnqueuedHead;

   // get pointer
#ifndef USE_16_BIT
   buf = (unsigned int *)(((char *)bf->Data)+2);
#else
   buf = (unsigned short *)(((char *)bf->Data)+2);
#endif


   // the length is held in the first two bytes of the 'frame', the ElementCount says the number of elements in the first buffer
   
   // get length
   elnth = (unsigned short *)bf->Data;
   length = *elnth;
   lnth_first = bf->ElementCount*bf->ElementWidth - 2; 

   length = ETH_ZLEN < length ? length : ETH_ZLEN;
   lnth_first = ETH_ZLEN < lnth_first ? lnth_first : ETH_ZLEN;

   // If I get here, I _know_ there is a packet slot waiting for me
   packet_no = _inp(AR_REG);

   // or isn't there?  BAD CHIP
   if ( packet_no & AR_FAILED ) return LAN91C111_TX_ERROR;

   // we have a packet address, so tell the card to use it
   _outp(PN_REG, packet_no);

   // point to the beginning of the packet
   _outpw(PTR_REG, PTR_AUTOINC);

   // send the packet length ( +6 for status, length and ctl byte )
   //   and the status word ( set to zeros ) */

#ifndef USE_16_BIT
   _outpd(DATA_REG, (length+6) << 16);
#else
   _outpw(DATA_REG, 0);
   _outpw(DATA_REG, (length+6));
#endif

   // send the actual data
#ifndef USE_16_BIT
   for (i=0; i < (length>>2); i++)
      _outpd(DATA_REG, *buf++);
   // last 16 bit word
   if ( length & 0x2  ) _outpw(DATA_REG, *buf);
#else
	// do the first buffer
   for (i=0; i < (lnth_first>>1); i++)
      _outpw(DATA_REG, *buf++);
     // check to see if more to go
     if (lnth_first<length) {
     	buf = bf->PayLoad;
     	length = length-lnth_first;
		// do the second buffer
	    for (i=0; i < (length>>1); i++)
	      _outpw(DATA_REG, *buf++);
     }
#endif // USE_32_BIT

   /* Send the last byte, if there is one.   */
   if ((length & 1) == 0)
   {
      // write 0 as CONTROL unsigned char
      _outpw(DATA_REG, 0x0000);
   }
   else
   {
#ifndef USE_16_BIT
      // last byte to be sent
      if (length & 2) *buf = (*buf>>16);
#endif
      // last byte to be sent
      _outpw(DATA_REG, 0x2000 | (*buf) & 0xff);
   }
   // now set the status in the buffer bf
   bf->ProcessedFlag = 1;
   bf->ProcessedElementCount = (*elnth+2 + bf->ElementWidth-1)/bf->ElementWidth;
   bf->StatusWord = 0x3;   // completed and OK
   
   #if 0
   ///////////////////////////////////////////////////////////////////
   // This code is added to handle the case where the source and
   // destination MAC address is the same.It just copies the broadcast
   // and frames that are destianted to the same MAC.
   // The below code could be commented if the client and server runs on
   // different boards.
   //   
	if( (!memcmp(cptr->phyAddr,(unsigned char *)cptr->m_TxEnqueuedHead->data_start,6) )
		|| (!memcmp((unsigned char *)cptr->m_TxEnqueuedHead->data_start,"\xff\xff\xff\xff\xff\xff",6)))
	{
		struct buffer_t *tmp_q_ele;
	
		tmp_q_ele = cptr->m_RxEnqueuedHead;
		 if(tmp_q_ele != NULL)
		 memcpy(tmp_q_ele->data_start,(unsigned short *)cptr->m_TxEnqueuedHead->data_start,cptr->m_TxEnqueuedHead->num_elements);
		 
		   /* Change the Enqueued head */
      	cptr->m_RxEnqueuedHead = (struct buffer_t*)tmp_q_ele->next;
      	cptr->m_RxEnqueuedCount--;
      	if (cptr->m_RxEnqueuedCount == 0)
        	 cptr->m_RxEnqueuedTail = (struct buffer_t*)NULL;

      	/* Add the packet to dequeued list*/
      	if (cptr->m_RxDequeuedCount)
        	 cptr->m_RxDequeuedTail->next = tmp_q_ele;
      	else
        	 cptr->m_RxDequeuedHead = tmp_q_ele;

      //No matter what this is also the tail.
      cptr->m_RxDequeuedTail = tmp_q_ele;
      //And tail->next should point to NULL
      tmp_q_ele->next = NULL;
      cptr->m_RxDequeuedCount++;
	}
	////////////////////////////////////////////////////////////
   #endif
   // enable the interrupts
   LAN91C111_enable_int( (IM_TX_INT | IM_TX_EMPTY_INT) );

   // and let the chipset deal with it
   _outpw(MMU_CMD_REG, MC_ENQUEUE);
   

   return LAN91C111_TX_SUCCESS;
}
/******************************************************************************
 * LANC91C111: LAN91C111_wait_to_send_packet()
 *
 * Purpose:
 *    Attempt to allocate memory for a packet, if chip-memory is not
 *    available, then tell the card to generate an interrupt when it
 *    is available.
 *****************************************************************************/
static unsigned char LAN91C111_wait_to_send_packet(ADI_ETHER_LAN91C111_DATA * cptr)
{
   unsigned short    length;
   unsigned short    numPages;
   unsigned short    time_out;
   unsigned short    status;
   unsigned short	 *elnth;
   

   // the length is held in the first two bytes of the 'frame', the ElementCount says the number of elements in the first buffer
   
   // get length
   elnth = (unsigned short *)cptr->m_TxEnqueuedHead->Data;
   length = *elnth;

   // set length
   length = ETH_ZLEN < length ? length : ETH_ZLEN;

   // clear allocation flag
   cptr->LAN_state.alloc_success = 0;

   /*
    * The MMU wants the number of pages to be the number of 256 bytes
    * 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
    *
    * Pkt size for allocating is data length +6 (for additional status
    * words, length and ctl!)
    *
    * If odd size then last byte is included in this header.
    */
   numPages = ((length & 0xfffe) + 6);
   numPages >>= 8; // Divide by 256

   if (numPages > 7 )
   {
      // way too big packet, this is an error
      // free packet
      return LAN91C111_TX_ERROR;
   }
   // either way, a packet is waiting now
   cptr->LAN_state.packets_waiting++;

   // now, try to allocate the memory */
   _outpw(BSR_REG, 2);
   _outpw(MMU_CMD_REG, MC_ALLOC | numPages);

   /*
    * Performance Hack
    *
    * wait a short amount of time.. if I can allocate a packet now, I set
    * the flag now.  Otherwise, I enable an interrupt and wait for one to be
    * available.
    *
    */
TX_RETRY:
   time_out = 200; // number of iterations
   do
   {
      status = _inp(INT_REG);
      if ( status & IM_ALLOC_INT )
      {
         /* acknowledge the interrupt */
         _outp(INT_REG, IM_ALLOC_INT);
         break;
      }
   } while ( --time_out );

   // too bad, no immediate allocation...
   if ( !time_out )
   {
      /* Check the status bit one more time just in case */
      /* it snuk in between the time we last checked it */
      /* and when we set the interrupt bit */
      status = _inp(INT_REG );
      if ( !(status & IM_ALLOC_INT) )
	  {
		/* The allocation used to fail when ever the RXOVRN was set and
		 * the packets were not transmitted. This takes cares of the 
		 * above, I have not observed any packet loss, but I am not 
		 * that sure also, MC_RELEASE release the recieve packet, 
		 * At the max we may loose one packet.
		 */

		// Relase and reset the FIFO, Now the SMSC memory is free
		while ( _inpw(MMU_CMD_REG ) & 1 ) // 1 is MC_BUSY 
		{
			//when the last release is completed
			ssync();
		}
		
		_outpw(MMU_CMD_REG, MC_RELEASE);
		_outpw(MMU_CMD_REG, MC_RSTTXFIFO);

		goto TX_RETRY;
	  }
   }

⌨️ 快捷键说明

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