e1000g_rx.c revision 080575042aba2197b425ebfd52061dea061a9aa1
/*
* This file is provided under a CDDLv1 license. When using or
* redistributing this file, you may do so under this license.
* In redistributing this file this license must be included
* and no other modification of this header file is permitted.
*
* CDDL LICENSE SUMMARY
*
* Copyright(c) 1999 - 2007 Intel Corporation. All rights reserved.
*
* The contents of this file are subject to the terms of Version
* 1.0 of the Common Development and Distribution License (the "License").
*
* You should have received a copy of the License with this software.
* You can obtain a copy of the License at
* See the License for the specific language governing permissions
* and limitations under the License.
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms of the CDDLv1.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* **********************************************************************
* *
* Module Name: *
* e1000g_rx.c *
* *
* Abstract: *
* This file contains some routines that takes care of Receive *
* interrupt and also for the received packet *
* it sends up to upper layer. *
* It tries to do a zero copy if free buffers are available in *
* the pool. Also it implements shortcut to Ipq *
* *
* *
* This driver runs on the following hardware: *
* - Wisemane based PCI gigabit ethernet adapters *
* *
* Environment: *
* Kernel Mode - *
* *
* **********************************************************************
*/
#include "e1000g_sw.h"
#include "e1000g_debug.h"
/*
* local prototypes
*/
#pragma inline(e1000g_get_buf)
/*
* **********************************************************************
* Name: e1000g_rxfree_func *
* *
* Description: *
* *
* This functionis called when a mp is freed by the user thru *
* freeb call (Only for mp constructed through desballoc call) *
* It returns back the freed buffer to the freelist *
* *
* *
* Parameter Passed: *
* *
* Return Value: *
* *
* Functions called: *
* *
* **********************************************************************
*/
void
{
/*
* Here the rx recycling processes different rx packets in different
* threads, so we protect it with RW_READER to ensure it won't block
* other rx recycling threads.
*/
return;
}
/*
* Here the e1000g_mblks_pending may be modified by different
* rx recycling threads simultaneously, so we need to protect
* it with RW_WRITER.
*/
return;
}
/*
* Allocate a mblk that binds to the data buffer
*/
} else {
}
}
}
/*
* **********************************************************************
* Name: SetupReceiveStructures *
* *
* Description: This routine initializes all of the receive related *
* structures. This includes the receive descriptors, the *
* actual receive buffers, and the RX_SW_PACKET software *
* structures. *
* *
* NOTE -- The device must have been reset before this *
* routine is called. *
* *
* Author: Hari Seshadri *
* Functions Called : get_32bit_value; *
* *
* *
* *
* Arguments: *
* Adapter - A pointer to our context sensitive "Adapter" *
* structure. *
* *
* Returns: *
* (none) *
* *
* Modification log: *
* Date Who Description *
* -------- --- ----------------------------------------------------- *
* *
* **********************************************************************
*/
void
{
struct e1000_rx_desc *descriptor;
int i;
int size;
/*
* zero out all of the receive buffer descriptor memory
* assures any previous data or status is erased
*/
if (Adapter->init_count == 0) {
/* Init the list of "Receive Buffer" */
/* Init the list of "Free Receive Buffer" */
/*
* Setup Receive list and the Free list. Note that
* the both were allocated in one packet area.
*/
for (i = 0; i < Adapter->NumRxDescriptors;
#ifdef __sparc
#else
#endif
/* Add this RX_SW_PACKET to the receive list */
}
for (i = 0; i < Adapter->NumRxFreeList;
/* Add this RX_SW_PACKET to the free list */
}
} else {
/* Setup the initial pointer to the first rx descriptor */
packet = (PRX_SW_PACKET)
for (i = 0; i < Adapter->NumRxDescriptors; i++) {
#ifdef __sparc
#else
#endif
/* Get next RX_SW_PACKET */
packet = (PRX_SW_PACKET)
descriptor++;
}
}
/*
* Setup our descriptor pointers
*/
/* To get lower order bits */
/* To get the higher order bits */
/*
* Setup our HW Rx Head & Tail descriptor pointers
*/
/*
* Setup the Receive Control Register (RCTL), and ENABLE the
* receiver. The initial configuration is to: Enable the receiver,
* accept broadcasts, discard bad packets (and long packets),
* disable VLAN filter checking, set the receive descriptor
* minimum threshold size to 1/2, and the receive buffer size to
* 2k.
*/
E1000_RCTL_BAM | /* Accept Broadcast Packets */
E1000_RCTL_LPE | /* Large Packet Enable bit */
#ifdef __sparc
E1000_RCTL_SECRC | /* Strip Ethernet CRC */
#endif
E1000_RCTL_LBM_NO; /* Loopback Mode = none */
case ETHERMAX:
break;
case FRAME_SIZE_UPTO_4K:
break;
case FRAME_SIZE_UPTO_8K:
break;
case FRAME_SIZE_UPTO_10K:
case FRAME_SIZE_UPTO_16K:
break;
default:
break;
}
reg_val =
E1000_RXCSUM_TUOFL | /* TCP/UDP checksum offload Enable */
E1000_RXCSUM_IPOFL; /* IP checksum offload Enable */
}
/*
* **********************************************************************
* Name: SetupMulticastTable *
* *
* Description: This routine initializes all of the multicast related *
* structures. *
* NOTE -- The device must have been reset before this routine *
* is called. *
* *
* Author: Hari Seshadri *
* *
* Arguments: *
* Adapter - A pointer to our context sensitive "Adapter" *
* structure. *
* *
* Returns: *
* (none) *
* *
* Modification log: *
* Date Who Description *
* -------- --- ----------------------------------------------------- *
* *
* **********************************************************************
*/
void
{
int i;
/*
* The e1000g has the ability to do perfect filtering of 16
* addresses. The driver uses one of the e1000g's 16 receive
* address registers for its node/network/mac/individual address.
* So, we have room for up to 15 multicast addresses in the CAM,
* additional MC addresses are handled by the MTA (Multicast Table
* Array)
*/
"Adapter requested more than %d MC Addresses.\n",
} else {
/*
* Set the number of MC addresses that we are being
* requested to use
*/
}
/*
* The Wiseman 2.0 silicon has an errata by which the receiver will
* hang while writing to the receive address registers if the receiver
* is not in reset before writing to the registers. Updating the RAR
* is done during the setting up of the multicast table, hence the
* receiver has to be put in reset before updating the multicast table
* and then taken out of reset at the end
*/
/*
* if WMI was enabled then dis able it before issueing the global
* reset to the hardware.
*/
/*
* Only required for WISEMAN_2_0
*/
/*
* The e1000g must be in reset before changing any RA
* registers. Reset receive unit. The chip will remain in
* the reset state until software explicitly restarts it.
*/
/* Allow receiver time to go in to reset */
}
/*
* Only for Wiseman_2_0
* If MWI was enabled then re-enable it after issueing (as we
* disabled it up there) the receive reset command.
* Wainwright does not have a receive reset command and only thing
* close to it is global reset which will require tx setup also
*/
/*
* if WMI was enabled then reenable it after issueing the
* global or receive reset to the hardware.
*/
/*
* Take receiver out of reset
* clear E1000_RCTL_RST bit (and all others)
*/
}
/*
* Restore original value
*/
}
/*
* **********************************************************************
* Name: e1000g_get_buf *
* *
* Description: This routine gets newpkt. *
* *
* Author: Hari Seshadri *
* *
* Arguments: *
* *
* Returns: *
* RX_SW_PACKET* *
* *
* Modification log: *
* Date Who Description *
* -------- --- ----------------------------------------------------- *
* *
* **********************************************************************
*/
static RX_SW_PACKET *
{
packet = (PRX_SW_PACKET)
return (packet);
}
/*
* **********************************************************************
* Name: e1000g_receive *
* *
* Description: This routine will process packets spanning multiple *
* buffers *
* - Called from the e1000g_intr Handles interrupt for RX side *
* - Checks the interrupt cause and process it. At the time of *
* calling the interrupt cause register has been already *
* cleared. *
* *
* Author: Vinay K Awasthi *
* *
* Date : Feb 9, 2000 *
* *
* Arguments: *
* Adapter - A pointer to our context sensitive "Adapter" *
* structure. *
* *
* Returns: *
* Pointer to list of mblks to pass up to GLD *
* Functions Called: *
* (none) *
* *
* Modification log: *
* Date Who Description *
* -------- --- ----------------------------------------------------- *
* *
* **********************************************************************
*/
mblk_t *
{
/*
* Need :
* This function addresses the need to process jumbo frames using
* standard 2048 byte buffers. In solaris, getting large aligned
* buffers in low memory systems is hard and often it comprises
* of multiple cookies rather than just one cookie which our HW
* wants. In low memory systems, it is hard to get lots of large
* chunks of memory i.e. you can get 256 2k buffers but it is hard
* to get 64 8k buffers. Pagesize is playing an important role here.
* If system administrator is willing to tune stream and system dma
* resources then we may not need this function. At the same time
* we may not have this option.
* This function will also make our driver do Jumbo frames on Wiseman
* hardware.
*/
struct e1000_rx_desc *current_desc;
struct e1000_rx_desc *last_desc;
unsigned char LastByte;
pkt_count = 0;
desc_count = 0;
cksumflags = 0;
/* Sync the Rx descriptor DMA buffers */
0, 0, DDI_DMA_SYNC_FORCPU);
/*
* don't send anything up. just clear the RFD
*/
return (ret_mp);
}
/*
* Loop through the receive descriptors starting at the last known
* descriptor owned by the hardware that begins a packet.
*/
desc_count++;
/*
* Now this can happen in Jumbo frame situation.
*/
/* packet has EOP set */
} else {
/*
* If this received buffer does not have the
* End-Of-Packet bit set, the received packet
* will consume multiple buffers. We won't send this
* packet upstack till we get all the related buffers.
*/
}
/*
* Get a pointer to the actual receive buffer
* The mp->b_rptr is mapped to The CurrentDescriptor
* Buffer Address.
*/
packet =
#ifdef __sparc
case USE_DVMA:
break;
#endif
case USE_DMA:
break;
default:
break;
}
LastByte =
length--;
} else {
}
/*
* Indicate the packet to the NOS if it was good.
* Normally, hardware will discard bad packets for us.
* Check for the packet to be a valid Ethernet packet
*/
/*
* There can be few packets which are less than 2k but
* more than 1514 bytes length. They are really jumbo
* packets, but for our driver's buffer they can still
* fit in one buffer as minimum buffer size if 2K. In our
* above condition, we are taking all EOP packets as
* JumboPacket=False... JumboPacket=FALSE just tells us
* that now we can process this packet...as we have
* received complete packet.
*/
if (!((current_desc->errors == 0) ||
(current_desc->errors &
(E1000_RXD_ERR_TCPE | E1000_RXD_ERR_IPE)) ||
AcceptFrame)) {
/*
* error in incoming packet, either the packet is not a
* ethernet size packet, or the packet has an error. In
* either case, the packet will simply be discarded.
*/
"Process Receive Interrupts: Error in Packet\n");
/*
* Returning here as we are done here. There is
* no point in waiting for while loop to elapse
* and the things which were done. More efficient
* and less error prone...
*/
goto rx_drop;
}
goto rx_copy;
/*
* Get the pre-constructed mblk that was associated
* to the receive data buffer.
*/
} else {
}
}
/*
* We have two sets of buffer pool. One associated with
* the Rxdescriptors and other a freelist buffer pool.
* Each time we get a good packet, Try to get a buffer
* from the freelist pool using e1000g_get_buf. If we
* get free buffer, then replace the descriptor buffer
* address with the free buffer we just got, and pass
* the pre-constructed mblk upstack. (note no copying)
*
* If we failed to get a free buffer, then try to
* allocate a new buffer(mp) and copy the recv buffer
* content to our newly allocated buffer(mp). Don't
* disturb the desriptor buffer address. (note copying)
*/
/*
* Get the mblk associated to the data,
* and strip it off the sw packet.
*/
/*
* Now replace old buffer with the new
* one we got from free list
* Both the RxSwPacket as well as the
* Receive Buffer Descriptor will now
* point to this new packet.
*/
#ifdef __sparc
#else
#endif
} else {
Adapter->rx_no_freepkt++;
}
}
if (need_copy) {
/*
* No buffers available on free list,
* bcopy the data from the buffer and
* keep the original buffer. Dont want to
* do this.. Yack but no other way
*/
if ((nmp =
/*
* The system has no buffers available
* to send up the incoming packet, hence
* the packet will have to be processed
* when there're more buffers available.
*/
goto rx_drop;
}
/*
* The free list did not have any buffers
* available, so, the received packet will
* have to be copied into a mp and the original
* buffer will have to be retained for future
* packet reception.
*/
}
/*
* The RX_SW_PACKET MUST be popped off the
* RxSwPacketList before either a putnext or freemsg
* is done on the mp that has now been created by the
* desballoc. If not, it is possible that the free
* routine will get called from the interrupt context
* and try to put this packet on the free list
*/
ETHERTYPE_IP)) {
/*
* IP checksum offload
*/
if (!(current_desc->status &
/*
*/
if ((current_desc->status &
!(current_desc->errors &
cksumflags |= HCK_FULLCKSUM |
/*
* Check IP Checksum
*/
if ((current_desc->status &
!(current_desc->errors &
}
}
/*
* We need to maintain our packet chain in the global
* Adapter structure, for the Rx processing can end
* with a fragment that has no EOP set.
*/
/* Get the head of the message chain */
} else { /* Not the first packet */
/* Continue adding buffers */
}
/*
* Now this MP is ready to travel upwards but some more
* fragments are coming.
* We will send packet upwards as soon as we get EOP
* set on the packet.
*/
if (!end_of_packet) {
/*
* continue to get the next descriptor,
* Tail would be advanced at the end
*/
goto rx_next_desc;
}
/*
* Found packet with EOP
* Process the last fragment.
*/
if (cksumflags != 0) {
cksumflags = 0;
}
/*
* Jumbo Frame Counters
*/
if (Adapter->ProfileJumboTraffic) {
Adapter->JumboRx_4K++;
Adapter->JumboRx_8K++;
Adapter->JumboRx_16K++;
}
/*
* Count packets that span multi-descriptors
*/
Adapter->rx_multi_desc++;
/*
* Append to list to send upstream
*/
} else {
}
Adapter->rx_packet_len = 0;
pkt_count++;
/*
* Zero out the receive descriptors status
*/
current_desc->status = 0;
else
/*
* Put the buffer that we just indicated back
* at the end of our list
*/
} /* while loop */
Adapter->rx_exceed_pkt++;
/* Sync the Rx descriptor DMA buffers */
/* Check the wrap-around case */
sync_offset * sizeof (struct e1000_rx_desc),
sync_len * sizeof (struct e1000_rx_desc),
} else {
sync_offset * sizeof (struct e1000_rx_desc),
0,
0,
sync_len * sizeof (struct e1000_rx_desc),
}
/*
* Advance the E1000's Receive Queue #0 "Tail Pointer".
*/
return (ret_mp);
/*
* Zero out the receive descriptors status
*/
current_desc->status = 0;
/* Sync the Rx descriptor DMA buffers */
/* Check the wrap-around case */
sync_offset * sizeof (struct e1000_rx_desc),
sync_len * sizeof (struct e1000_rx_desc),
} else {
sync_offset * sizeof (struct e1000_rx_desc),
0,
0,
sync_len * sizeof (struct e1000_rx_desc),
}
else
/*
* Reclaim all old buffers already allocated during
* Jumbo receives.....for incomplete reception
*/
Adapter->rx_packet_len = 0;
}
/*
* Advance the E1000's Receive Queue #0 "Tail Pointer".
*/
return (ret_mp);
}