e1000g_rx.c revision ede5269ebe7fa3787cc9b58c3781b639c578f93d
/*
* 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 - 2008 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms of the CDDLv1.
*/
/*
* **********************************************************************
* *
* Module Name: *
* e1000g_rx.c *
* *
* Abstract: *
* This file contains some routines that take care of Receive *
* interrupt and also for the received packets it sends up to *
* upper layer. *
* It tries to do a zero copy if free buffers are available in *
* the pool. *
* *
* **********************************************************************
*/
#include "e1000g_sw.h"
#include "e1000g_debug.h"
#pragma inline(e1000g_get_buf)
static void e1000g_priv_devi_list_clean();
/*
* e1000g_rxfree_func - the call-back function to reclaim rx buffer
*
* This function is called when an 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
*/
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;
}
rx_ring->pending_count--;
if (rx_ring->pending_count == 0) {
}
}
/*
* If e1000g_force_detach is enabled, we need to clean up
* the idle priv_dip entries in the private dip list while
* e1000g_mblks_pending is zero.
*/
if (e1000g_force_detach && (e1000g_mblks_pending == 0))
return;
}
/*
* Here the e1000g_mblks_pending may be modified by different
* rx recycling threads simultaneously, so we need to protect
* it with RW_WRITER.
*/
/*
* If e1000g_force_detach is enabled, we need to clean up
* the idle priv_dip entries in the private dip list while
* e1000g_mblks_pending is zero.
*/
if (e1000g_force_detach && (e1000g_mblks_pending == 0))
return;
}
/*
* Allocate a mblk that binds to the data buffer
*/
} else {
}
}
rx_ring->avail_freepkt++;
}
/*
* e1000g_priv_devi_list_clean - clean up e1000g_private_devi_list
*
* We will walk the e1000g_private_devi_list to free the entry marked
* with the E1000G_PRIV_DEVI_DETACH flag.
*/
static void
{
if (e1000g_private_devi_list == NULL)
return;
sizeof (struct dev_info));
sizeof (private_devi_list_t));
}
if (e1000g_private_devi_list == NULL)
return;
sizeof (struct dev_info));
sizeof (private_devi_list_t));
} else {
}
}
}
/*
* e1000g_rx_setup - setup rx data structures
*
* 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.
*/
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->rx_buffer_setup) {
/* 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->rx_desc_num;
/* Add this rx_sw_packet to the receive list */
}
for (i = 0; i < Adapter->rx_freelist_num;
/* Add this rx_sw_packet to the free list */
}
} else {
/* Setup the initial pointer to the first rx descriptor */
for (i = 0; i < Adapter->rx_desc_num; i++) {
/* Get next rx_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 */
E1000_RCTL_LBM_NO; /* Loopback Mode = none */
} else {
else
}
rctl |= E1000_RCTL_SBP;
/*
* Enable early receives on supported devices, only takes effect when
* packet size is equal or larger than the specified value (in 8 byte
* units), e.g. using jumbo frames when setting to E1000_ERT_2048
*/
/*
* Special modification when ERT and
* jumbo frames are enabled
*/
}
}
reg_val =
E1000_RXCSUM_TUOFL | /* TCP/UDP checksum offload Enable */
E1000_RXCSUM_IPOFL; /* IP checksum offload Enable */
/*
* Workaround: Set bit 16 (IPv6_ExDIS) to disable the
* processing of received IPV6 extension headers
*/
}
/* Write to enable the receive unit */
}
/*
* e1000g_get_buf - get an rx sw packet from the free_list
*/
static p_rx_sw_packet_t
{
rx_ring->avail_freepkt--;
return (packet);
}
/*
* e1000g_receive - main receive routine
*
* This routine will process packets received in an interrupt
*/
mblk_t *
{
struct e1000_rx_desc *current_desc;
struct e1000_rx_desc *last_desc;
pkt_count = 0;
desc_count = 0;
cksumflags = 0;
/* Sync the Rx descriptor DMA buffers */
0, 0, DDI_DMA_SYNC_FORKERNEL);
}
/*
* 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
else
#else
#endif
}
((current_desc->errors &
(E1000_RXD_ERR_TCPE | E1000_RXD_ERR_IPE)) != 0);
unsigned char last_byte;
if (TBI_ACCEPT(hw,
length--;
} else if (e1000_tbi_sbp_enabled_82543(hw) &&
}
}
/*
* 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
*/
if (!accept_frame) {
/*
* 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;
}
/*
* If the Ethernet CRC is not stripped by the hardware,
* we need to strip it before sending it up to the stack.
*/
} else {
/*
* If the fragment is smaller than the CRC,
* drop this fragment, do the processing of
* the end of the packet.
*/
rx_ring->rx_mblk_len -=
goto rx_end_of_packet;
}
}
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.
*/
} else {
}
}
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
*/
/*
* 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
*/
/*
* IP checksum offload
*/
/*
*/
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;
}
/*
* Count packets that span multi-descriptors
*/
/*
* Append to list to send upstream
*/
} else {
}
rx_ring->rx_mblk_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 */
/* Sync the Rx descriptor DMA buffers */
0, 0, DDI_DMA_SYNC_FORDEV);
/*
* 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 */
0, 0, DDI_DMA_SYNC_FORDEV);
else
/*
* Reclaim all old buffers already allocated during
* Jumbo receives.....for incomplete reception
*/
rx_ring->rx_mblk_len = 0;
}
/*
* Advance the E1000's Receive Queue #0 "Tail Pointer".
*/
}
return (ret_mp);
}