e1000g_tx.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_tx.c *
* *
* Abstract: *
* This file contains some routines that takes care of Transmit *
* interrupt and also makes the hardware to send the data pointed *
* by the packet out on to the physical medium. *
* *
* *
* Environment: *
* Kernel Mode - *
* *
* Source History: *
* The code in this file is based somewhat on the "send" code *
* developed for the Intel Pro/100 family(Speedo1 and Speedo3) by *
* Steve Lindsay, and partly on some sample DDK code *
* of solaris. *
* *
* March 12, 1997 Steve Lindsay *
* 1st created - Ported from E100B send.c file *
* *
* **********************************************************************
*/
#include "e1000g_sw.h"
#include "e1000g_debug.h"
static void e1000g_fill_context_descriptor(e1000g_tx_ring_t *,
struct e1000_context_desc *);
static int e1000g_fill_tx_desc(struct e1000g *,
static int e1000g_tx_workaround_PCIX_82544(struct e1000g *,
static int e1000g_tx_workaround_jumbo_82544(struct e1000g *,
static void e1000g_82547_timeout(void *);
static void e1000g_82547_tx_move_tail(e1000g_tx_ring_t *);
static void e1000g_82547_tx_move_tail_work(e1000g_tx_ring_t *);
#ifndef e1000g_DEBUG
#pragma inline(e1000g_tx_copy)
#pragma inline(e1000g_tx_bind)
#pragma inline(e1000g_fill_tx_ring)
#pragma inline(e1000g_fill_context_descriptor)
#pragma inline(e1000g_fill_tx_desc)
#pragma inline(e1000g_fill_82544_desc)
#pragma inline(e1000g_tx_workaround_PCIX_82544)
#pragma inline(e1000g_tx_workaround_jumbo_82544)
#pragma inline(FreeTxSwPacket)
#pragma inline(e1000g_tx_free_desc_num)
#endif
/*
* **********************************************************************
* Name: FreeTxSwPacket *
* *
* Description: *
* Frees up the previusly allocated Dma handle for given *
* transmit sw packet. *
* *
* Parameter Passed: *
* *
* Return Value: *
* *
* Functions called: *
* *
* **********************************************************************
*/
void
{
switch (packet->data_transfer_type) {
case USE_BCOPY:
break;
#ifdef __sparc
case USE_DVMA:
break;
#endif
case USE_DMA:
break;
default:
break;
}
/*
* The mblk has been stripped off the sw packet
* and will be freed in a triggered soft intr.
*/
packet->num_mblk_frag = 0;
}
{
return (DDI_INTR_UNCLAIMED);
return (DDI_INTR_CLAIMED);
return (DDI_INTR_CLAIMED);
}
static uint32_t
{
int num;
if (num <= 0)
return (num);
}
mblk_t *
{
}
break;
}
}
return (mp);
}
/*
* **********************************************************************
* Name: e1000g_send *
* *
* Description: *
* Called from e1000g_m_tx with an mp ready to send. this *
* routine sets up the transmit descriptors and sends to *
* the wire. It also pushes the just transmitted packet to *
* the used tx sw packet list *
* *
* Arguments: *
* Pointer to the mblk to be sent, pointer to this adapter *
* *
* Returns: *
* B_TRUE, B_FALSE *
* *
* Modification log: *
* Date Who Description *
* -------- --- ----------------------------------------------------- *
* **********************************************************************
*/
static boolean_t
{
int desc_count;
/* Get the total size and frags number of the message */
force_bcopy = 0;
frag_count = 0;
msg_size = 0;
frag_count++;
}
/* Empty packet */
if (msg_size == 0) {
return (B_TRUE);
}
/* Make sure packet is less than the max frame size */
/*
* For the over size packet, we'll just drop it.
* So we return B_TRUE here.
*/
"Tx packet out of bound. length = %d \n", msg_size);
Adapter->tx_over_size++;
return (B_TRUE);
}
/*
* Check and reclaim tx descriptors.
* This low water mark check should be done all the time as
* Transmit interrupt delay can produce Transmit interrupts little
* late and that may cause few problems related to reaping Tx
* Descriptors... As you may run short of them before getting any
* transmit interrupt...
*/
}
Adapter->tx_recycle++;
(void) e1000g_recycle(tx_ring);
}
Adapter->tx_lack_desc++;
goto tx_no_resource;
}
/*
* If there are many frags of the message, then bcopy them
* into one tx descriptor buffer will get better performance.
*/
}
/*
* If the message size is less than the minimum ethernet packet size,
* we'll use bcopy to send it, and padd it to 60 bytes later.
*/
if (msg_size < MINIMUM_ETHERNET_PACKET_SIZE) {
Adapter->tx_under_size++;
}
/* Initialize variables */
desc_total = 0;
/* Retrieve checksum info */
if (cksum_flags) {
ether_header_size = sizeof (struct ether_vlan_header);
else
ether_header_size = sizeof (struct ether_header);
cksum_load = B_TRUE;
}
}
/* Process each mblk fragment and fill tx descriptors */
while (nmp) {
/* Check zero length mblks */
if (len == 0) {
/*
* If there're no packet buffers have been used,
* or we just completed processing a buffer, then
* skip the empty mblk fragment.
* Otherwise, there's still a pending buffer that
* needs to be processed (tx_copy).
*/
if (desc_count > 0) {
continue;
}
}
/*
* Get a new TxSwPacket to process mblk buffers.
*/
if (desc_count > 0) {
packet = (PTX_SW_PACKET)
"No Tx SwPacket available\n");
Adapter->tx_no_swpkt++;
goto tx_send_failed;
}
}
/*
* If the size of the fragment is less than the tx_bcopy_thresh
* we'll use bcopy; Otherwise, we'll use DMA binding.
*/
} else {
}
if (desc_count < 0)
goto tx_send_failed;
if (desc_count > 0)
desc_total += desc_count;
}
/* Assign the message to the last sw packet */
/* Try to recycle the tx descriptors again */
(void) e1000g_recycle(tx_ring);
}
/*
* If the number of available tx descriptors is not enough for transmit
* (one redundant descriptor and one hw checksum context descriptor are
* included), then return failure.
*/
"No Enough Tx descriptors\n");
Adapter->tx_no_desc++;
goto tx_send_failed;
}
ASSERT(desc_count > 0);
/* Update statistic counters */
if (Adapter->ProfileJumboTraffic) {
(msg_size <= FRAME_SIZE_UPTO_4K))
Adapter->JumboTx_4K++;
if ((msg_size > FRAME_SIZE_UPTO_4K) &&
(msg_size <= FRAME_SIZE_UPTO_8K))
Adapter->JumboTx_8K++;
if ((msg_size > FRAME_SIZE_UPTO_8K) &&
(msg_size <= FRAME_SIZE_UPTO_16K))
Adapter->JumboTx_16K++;
}
/* Send successful */
return (B_TRUE);
/* Free pending TxSwPackets */
while (packet) {
packet = (PTX_SW_PACKET)
}
/* Return pending TxSwPackets to the "Free" list */
Adapter->tx_send_fail++;
/* Send failed, message dropped */
return (B_TRUE);
/*
* Enable Transmit interrupts, so that the interrupt routine can
* call mac_tx_update() when transmit descriptors become available.
*/
if (!Adapter->tx_intr_enable)
/* Message will be scheduled for re-transmit */
return (B_FALSE);
}
static int
{
struct e1000_context_desc *cksum_desc;
struct e1000_tx_desc *first_data_desc;
struct e1000_tx_desc *next_desc;
struct e1000_tx_desc *descriptor;
int sync_len;
int desc_count;
int i;
desc_count = 0;
cksum_desc = NULL;
descriptor = NULL;
if (cksum_load) {
/* Check the wrap-around case */
else
next_desc++;
desc_count++;
}
if (cksum_desc == NULL)
first_packet = NULL;
while (packet) {
#ifdef __sparc
#else
#endif
/* Zero out status */
/* must set RS on every outgoing descriptor */
/* Check the wrap-around case */
else
next_desc++;
desc_count++;
}
if (first_packet != NULL) {
/*
* Count the checksum context descriptor for
* the first SwPacket.
*/
first_packet->num_desc++;
first_packet = NULL;
}
packet = (PTX_SW_PACKET)
}
if (cksum_flags) {
if (cksum_flags & HCK_IPV4_HDRCKSUM)
((struct e1000_data_desc *)first_data_desc)->
if (cksum_flags & HCK_PARTIALCKSUM)
((struct e1000_data_desc *)first_data_desc)->
}
/*
* Last Descriptor of Packet needs End Of Packet (EOP), Report
* Status (RS) and append Ethernet CRC (IFCS) bits set.
*/
if (Adapter->TxInterruptDelay) {
} else {
}
/*
* Sync the Tx descriptors DMA buffer
*/
/* Check the wrap-around case */
if (sync_len > 0) {
sync_offset * sizeof (struct e1000_tx_desc),
sync_len * sizeof (struct e1000_tx_desc),
} else {
sync_offset * sizeof (struct e1000_tx_desc),
0,
0,
sync_len * sizeof (struct e1000_tx_desc),
}
/*
* Advance the Transmit Descriptor Tail (Tdt), this tells the
* FX1000 that this frame is available to transmit.
*/
else
/* Put the pending SwPackets to the "Used" list */
return (desc_count);
}
/*
* **********************************************************************
* Name: SetupTransmitStructures *
* *
* Description: This routine initializes all of the transmit related *
* structures. This includes the Transmit descriptors, the *
* coalesce buffers, and the TX_SW_PACKETs 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
{
UINT i;
int size;
/* init the lists */
/*
* Here we don't need to protect the lists using the
* tx_usedlist_lock and tx_freelist_lock, for they have
* been protected by the chip_lock.
*/
/* Go through and set up each SW_Packet */
/* Initialize this TX_SW_PACKET area */
/* Add this TX_SW_PACKET to the free list */
}
/* Setup TX descriptor pointers */
/*
* Setup Hardware TX Registers
*/
/* Setup the Transmit Control Register (TCTL). */
/* Enable the MULR bit */
if (speed == SPEED_1000)
if (reg_tctl & E1000_TCTL_MULR)
else
reg_tarc |= 1;
reg_tarc |= 1;
}
/* Setup HW Base and Length of Tx descriptor area */
/* Setup our HW Tx Head & Tail descriptor pointers */
/* Set the default values for the Tx Inter Packet Gap timer */
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
reg_tipg |=
reg_tipg |=
break;
default:
else
reg_tipg |=
reg_tipg |=
break;
}
/* Setup Transmit Interrupt Delay Value */
if (Adapter->TxInterruptDelay) {
}
tx_ring->cksum_stuff = 0;
tx_ring->cksum_start = 0;
tx_ring->cksum_flags = 0;
/* Initialize tx parameters */
}
/*
* **********************************************************************
* Name: e1000g_recycle *
* *
* Description: This routine cleans transmit packets. *
* *
* *
* *
* Arguments: *
* Adapter - A pointer to our context sensitive "Adapter" *
* structure. *
* *
* Returns: *
* (none) *
* Functions Called: *
* None *
* *
* Modification log: *
* Date Who Description *
* -------- --- ----------------------------------------------------- *
* *
* **********************************************************************
*/
int
{
struct e1000_tx_desc *descriptor;
int desc_count;
/*
* This function will examine each TxSwPacket in the 'used' queue
* if the e1000g is done with it then the associated resources (Tx
* Descriptors) will be "freed" and the TxSwPacket will be
* returned to the 'free' queue.
*/
desc_count = 0;
Adapter->tx_recycle_fail = 0;
Adapter->StallWatchdog = 0;
return (0);
}
/*
* While there are still TxSwPackets in the used queue check them
*/
while (packet =
/*
* Get hold of the next descriptor that the e1000g will
* report status back to (this will be the last descriptor
* of a given TxSwPacket). We only want to free the
* TxSwPacket (and it resources) if the e1000g is done
* with ALL of the descriptors. If the e1000g is done
* with the last one then it is done with all of them.
*/
/* Check for wrap case */
/* Sync the Tx descriptor DMA buffer */
sizeof (struct e1000_tx_desc),
sizeof (struct e1000_tx_desc),
/*
* If the descriptor done bit is set free TxSwPacket and
* associated resources
*/
else
descriptor + 1;
break;
} else {
/*
* Found a TxSwPacket that the e1000g is not done
* with then there is no reason to check the rest
* of the queue.
*/
break;
}
}
if (desc_count == 0) {
return (0);
}
Adapter->tx_recycle_fail = 0;
Adapter->StallWatchdog = 0;
/* Assemble the message chain */
} else {
}
/* Disconnect the message from the sw packet */
}
/* Free the TxSwPackets */
packet = (PTX_SW_PACKET)
}
/* Save the message chain */
} else {
}
/*
* If the tx interrupt is enabled, the messages will be freed
* in the tx interrupt; Otherwise, they are freed here by
* triggering a soft interrupt.
*/
if (!Adapter->tx_intr_enable)
NULL);
}
/* Return the TxSwPackets back to the FreeList */
return (desc_count);
}
/*
* 82544 Coexistence issue workaround:
* There are 2 issues.
* 1. If a 32 bit split completion happens from P64H2 and another
* 82544 has a problem where in to clock all the data in, it
* looks at REQ64# signal and since it has changed so fast (i.e. 1
* idle clock turn around), it will fail to clock all the data in.
* Data coming from certain ending addresses has exposure to this issue.
*
* To detect this issue, following equation can be used...
* SIZE[3:0] + ADDR[2:0] = SUM[3:0].
* If SUM[3:0] is in between 1 to 4, we will have this issue.
*
* ROOT CAUSE:
* The erratum involves the 82544 PCIX elasticity FIFO implementations as
* 64-bit FIFO's and flushing of the final partial-bytes corresponding
* to the end of a requested read burst. Under a specific burst condition
* of ending-data alignment and 32-byte split-completions, the final
* byte(s) of split-completion data require an extra clock cycle to flush
* into 64-bit FIFO orientation. An incorrect logic dependency on the
* REQ64# signal occurring during during this clock cycle may cause the
* residual byte(s) to be lost, thereby rendering the internal DMA client
* forever awaiting the final byte(s) for an outbound data-fetch. The
* erratum is confirmed to *only* occur if certain subsequent external
* 64-bit PCIX bus transactions occur immediately (minimum possible bus
* turn- around) following the odd-aligned 32-bit split-completion
* containing the final byte(s). Intel has confirmed that this has been
* 32-bit split-completion data, and in the presence of newer PCIX bus
* agents which fully-optimize the inter-transaction turn-around (zero
* additional initiator latency when pre-granted bus ownership).
*
* This issue does not exist in PCI bus mode, when any agent is operating
* in 32 bit only mode or on chipsets that do not do 32 bit split
* completions for 64 bit read requests (Serverworks chipsets). P64H2 does
* 32 bit split completions for any read request that has bit 2 set to 1
* for the requested address and read request size is more than 8 bytes.
*
* 2. Another issue is related to 82544 driving DACs under the similar
* scenario (32 bit split completion followed by 64 bit transaction with
* only 1 cycle turnaround). This issue is still being root caused. We
* think that both of these issues can be avoided if following workaround
* is implemented. It seems DAC issues is related to ending addresses being
* 0x9, 0xA, 0xB, 0xC and hence ending up at odd boundaries in elasticity
* FIFO which does not get flushed due to REQ64# dependency. We will only
* know the full story after it has been simulated successfully by HW team.
*
* WORKAROUND:
* Make sure we do not have ending address as 1,2,3,4(Hang) or 9,a,b,c(DAC)
*/
static uint32_t
{
/*
* Since issue is sensitive to length and address.
* Let us first check the address...
*/
if (Length <= 4) {
return (desc_array->Elements);
}
/*
* if it does not fall between 0x1 to 0x4 and 0x9 to 0xC then
* return
*/
if (safe_terminator == 0 ||
(safe_terminator > 4 &&
safe_terminator < 9) ||
return (desc_array->Elements);
}
return (desc_array->Elements);
}
static int
{
int desc_count;
desc_count = 0;
if (len > 0) {
len);
packet->num_mblk_frag++;
}
} else {
else if (force_bcopy)
else
}
if (finished) {
Adapter->tx_multi_copy++;
/*
* If the packet is smaller than 64 bytes, which is the
* minimum ethernet packet size, pad the packet to make
* it at least 60 bytes. The hardware will add 4 bytes
* for CRC.
*/
if (force_bcopy & FORCE_BCOPY_UNDER_SIZE) {
}
#ifdef __sparc
case USE_DVMA:
break;
#endif
case USE_DMA:
break;
default:
break;
}
if (desc_count <= 0)
return (-1);
}
return (desc_count);
}
static int
{
int j;
int mystat;
int desc_count;
desc_total = 0;
/*
* ddi_dma_addr_bind_handle() allocates DMA resources for a
* memory object such that a device can perform DMA to or from
* the object. DMA resources are allocated considering the
* device's DMA attributes as expressed by ddi_dma_attr(9S)
* (see ddi_dma_alloc_handle(9F)).
*
* ddi_dma_addr_bind_handle() fills in the first DMA cookie
* pointed to by cookiep with the appropriate address, length,
* and bus type. *ccountp is set to the number of DMA cookies
* representing this DMA object. Subsequent DMA cookies must be
* retrieved by calling ddi_dma_nextcookie(9F) the number of
* times specified by *countp - 1.
*/
#ifdef __sparc
case USE_DVMA:
ncookies = 1;
break;
#endif
case USE_DMA:
if ((mystat = ddi_dma_addr_bind_handle(
DDI_DMA_DONTWAIT, 0, &dma_cookie,
&ncookies)) != DDI_DMA_MAPPED) {
"Couldn't bind mblk buffer to Tx DMA handle: "
"return: %X, Pkt: %X\n",
return (-1);
}
/*
* An implicit ddi_dma_sync() is done when the
* ddi_dma_addr_bind_handle() is called. So we
* don't need to explicitly call ddi_dma_sync()
* here any more.
*/
if (ncookies > 1)
/*
* The data_transfer_type value must be set after the handle
* has been bound, for it will be used in FreeTxSwPacket()
* to decide whether we need to unbind the handle.
*/
break;
default:
break;
}
packet->num_mblk_frag++;
/*
* Each address could span thru multpile cookie..
* Each cookie will have one descriptor
*/
for (j = ncookies; j != 0; j--) {
if (desc_count <= 0)
return (-1);
desc_total += desc_count;
/*
* ddi_dma_nextcookie() retrieves subsequent DMA
* cookies for a DMA object.
* ddi_dma_nextcookie() fills in the
* ddi_dma_cookie(9S) structure pointed to by
* cookiep. The ddi_dma_cookie(9S) structure
* must be allocated prior to calling
* ddi_dma_nextcookie(). The DMA cookie count
* returned by ddi_dma_buf_bind_handle(9F),
* ddi_dma_addr_bind_handle(9F), or
* ddi_dma_getwin(9F) indicates the number of DMA
* cookies a DMA object consists of. If the
* resulting cookie count, N, is larger than 1,
* ddi_dma_nextcookie() must be called N-1 times
* to retrieve all DMA cookies.
*/
if (j > 1) {
&dma_cookie);
}
}
return (desc_total);
}
static void
struct e1000_context_desc *cksum_desc)
{
sizeof (struct ip) - 1;
} else
/*
* The packet with same protocol has the following
* stuff and start offset:
* | Protocol | Stuff | Start | Checksum
* | | Offset | Offset | Enable
* | IPv4 + TCP | 0x24 | 0x14 | Yes
* | IPv4 + UDP | 0x1A | 0x14 | Yes
* | IPv6 + TCP | 0x20 | 0x10 | No
* | IPv6 + UDP | 0x14 | 0x10 | No
*/
} else
/*
* Zero out the options for TCP Segmentation Offload,
* since we don't support it in this version
*/
}
static int
{
int desc_count;
desc_count = 0;
(size > JUMBO_FRAG_LENGTH)) {
} else {
desc_count++;
}
return (desc_count);
}
static int
{
int desc_count;
long size_left;
/*
* Coexist Workaround for cordova: RP: 07/04/03
*
* RP: ERRATA: Workaround ISSUE:
* 8kb_buffer_Lockup CONTROLLER: Cordova Breakup
* Eachbuffer in to 8kb pieces until the
* remainder is < 8kb
*/
desc_count = 0;
while (size_left > 0) {
if (size_left > MAX_TX_BUF_SIZE)
else
len, &desc_array);
"No enough preparing tx descriptors");
return (-1);
}
/*
* Put in the buffer address
*/
desc_count++;
} /* for */
/*
* Update the buffer address and length
*/
} /* while */
return (desc_count);
}
static int
{
int desc_count;
long size_left;
/*
* Workaround for Jumbo Frames on Cordova
* PSD 06/01/2001
*/
desc_count = 0;
offset = 0;
while (size_left > 0) {
"No enough preparing tx descriptors");
return (-1);
}
if (size_left > JUMBO_FRAG_LENGTH)
else
desc_count++;
}
return (desc_count);
}
static void
{
struct e1000_tx_desc *tx_desc;
hw_tdt = 0;
if (eop) {
length) != E1000_SUCCESS) {
if (tx_ring->timer_enable_82547) {
(void *)Adapter,
drv_usectohz(10000));
}
return;
} else {
hw_tdt);
length);
length = 0;
}
}
}
}
static void
e1000g_82547_timeout(void *arg)
{
tx_ring->timer_id_82547 = 0;
}
static void
{
tx_ring->timer_id_82547 = 0;
if (tid != 0) {
}
}