////////////////////////////////////////////////////////////////////////////////
//
// INTEL CONFIDENTIAL
//
// Portions Copyright 2007 Intel Corporation. All Rights Reserved.
//
// Portions of the source code contained or described herein and all documents
// related to the source code ("Material") are owned by Intel Corporation or its
// suppliers or licensors. Title to the Material remains with Intel Corporation
// or its suppliers and licensors. The Material contains trade secrets and
// proprietary and confidential information of Intel or its suppliers and
// licensors. The Material is protected by worldwide copyright and trade secret
// laws and treaty provisions. No part of the Material may be used, copied,
// reproduced, modified, published, uploaded, posted, transmitted, distributed,
// or disclosed in any way without Intel's prior express written permission.
//
// No license under any patent, copyright, trade secret or other intellectual
// property right is granted to or conferred upon you by disclosure or delivery
// of the Materials, either expressly, by implication, inducement, estoppel or
// otherwise. Any license under such intellectual property rights must be
// express and approved by Intel in writing.

#include <windows.h>
#include <x86kitl.h>
#include <pci.h>
#include "e1000.h"

#define LEN_CSR_INTMEM			0x20000		// Internal registers and memories
#define LEN_EXP_FLASH			0x80000		// Expansion ROM or Flash
#define E1000_MAX_INTR			10
#define E1000_MAX_TXD_PWR		11
#define E1000_MAX_DATA_PER_TXD		(1 << E1000_MAX_TXD_PWR)
#define TXD_USE_COUNT(S, X)		(((S) >> (X)) + 1 )
#define NEXT(a, MAX)			(++(a) >= (MAX))? ((a) = 0) : (0)

#define TO_PHYS(addr)			((ULONG)addr & ~0x80000000)

#define cpu_to_le64(x)			(uint64_t)(x)
#define cpu_to_le32(x)			(uint32_t)(x)
#define le16_to_cpu(x)			(uint16_t)(x)

static struct e1000_adapter e1000;
static struct e1000_tx_ring e1000_tx_ring;
static struct e1000_rx_ring e1000_rx_ring;
static struct e1000_buffer e1000_tx_bufinfo[E1000_DEFAULT_TXD];
static struct e1000_buffer e1000_rx_bufinfo[E1000_DEFAULT_RXD];

void usec_delay (UINT32 usec)
{
    while (usec--)
	e1000_io_read(&e1000.hw, e1000.hw.io_base + 8); // dummy
}

void msec_delay (UINT32 msec)
{
    while (msec--)
	usec_delay(1000);
}

#if DBG
static void PrintHex (UINT32 value, UINT8 bits)
{
    UINT32 mask = (0xf << (bits - 4)), shift = (bits - 4);
    for (; mask; mask >>= 4, shift -= 4) {
	UINT32 digit = (value & mask) >> shift;
	EdbgOutputDebugString("%c", (digit < 10)? ('0' + digit) : ('a' + digit - 10));
    }
}

static void MemoryDump (void* ptr, UINT32 len)
{
    int count;
    UINT8* buf = (UINT8*)ptr;
    for (count = 0; len > 0; len--) {
	if (count == 0) {
	    PrintHex((UINT32)buf, 32);
	    EdbgOutputDebugString(": ");
	}
	PrintHex((UINT32)*buf++, 8);
	EdbgOutputDebugString((count = (++count) % 16)? " " : "\n");
    }
    EdbgOutputDebugString("\n");
}
#else
#define PrintHex(value, bits)
#define MemoryDump(ptr, len)
#endif

static BOOLEAN e1000_check_64k_bound (struct e1000_adapter *adapter, void *start, unsigned long len)
{
	unsigned long begin = (unsigned long) start;
	unsigned long end = begin + len;

	switch (adapter->hw.mac_type) {
	    case e1000_82545 :	// [Errata 23] 82545 and 82546 not allow any memory
	    case e1000_82546 :	// write location to cross 64k boundary
		return ((begin ^ (end - 1)) >> 16) != 0 ? FALSE : TRUE;
	}
	return TRUE;
}

BOOLEAN E1000InitDMABuffer (UINT32 dwStartAddress, UINT32 dwBufSize)
{
    int i, size, dwSize = dwBufSize;
    UINT32 dwAlignedStart = (dwStartAddress + 0x03) & 0xfffffffc;
    struct e1000_tx_desc* tx_desc;
    struct e1000_rx_desc* rx_desc;
    extern PCKITL_NIC_INFO g_pKitlPCINic;

#ifndef NOMEMIO
    DWORD addr = g_pKitlPCINic->pciConfig.u.type0.BaseAddresses[0];
    e1000.hw.hw_addr = (dwStartAddress & 0x80000000)?
		       (PUCHAR)NKCreateStaticMapping(addr >> 8, LEN_CSR_INTMEM) : (PUCHAR)addr;

    switch (e1000.hw.mac_type) {
	case e1000_ich8lan :
#ifdef NAHUM2
	case e1000_ich9lan :
#endif
	addr = g_pKitlPCINic->pciConfig.u.type0.BaseAddresses[1];
	e1000.hw.flash_address = (dwStartAddress & 0x80000000)?
				 (PUCHAR)NKCreateStaticMapping(addr >> 8, LEN_EXP_FLASH) : (PUCHAR)addr;
    }
    EdbgOutputDebugString("E1000InitDMABuffer: memory 0x%x, flash 0x%x\n", e1000.hw.hw_addr, e1000.hw.flash_address);
#endif
    /*
     * WinCE 6.0 will translate the address of BAR[0] for PCI devices
     * (OALKitlInfo in Platform\Common\Src\Common\Kitl\device.c), and
     * pass it to EthDrv (*pfnInit)() as base address, however E1000
     * devices use BAR[0] as memory space.
     */
    e1000.hw.io_base = (unsigned long)g_pKitlPCINic->dwIoBase;

    dwSize -= (dwAlignedStart - dwStartAddress);
    dwStartAddress = dwAlignedStart;

    EdbgOutputDebugString("E1000InitDMABuffer: DMA buffer 0x%x-0x%x\n", dwStartAddress, dwStartAddress + dwSize - 1);

    e1000.tx_ring = &e1000_tx_ring;
    size = (e1000_tx_ring.count = E1000_DEFAULT_TXD) * sizeof(struct e1000_tx_desc);
    E1000_ROUNDUP(size, 4096);
    if (!e1000_check_64k_bound(&e1000, (void*)dwStartAddress, size)) {
	E1000_ERR("Unable to allocate aligned memory for the transmit descriptor ring\n");
	return FALSE;
    }
    tx_desc = (struct e1000_tx_desc*)dwStartAddress;
    e1000_tx_ring.desc = (void *)dwStartAddress;
    dwStartAddress += (e1000_tx_ring.size = size);
    if ((dwSize -= size) < 0) {
	E1000_ERR("Unable to allocate memory for the transmit descriptor ring\n");
	return FALSE;
    }
    e1000_tx_ring.buffer_info = e1000_tx_bufinfo;
    for (i = 0; i < E1000_DEFAULT_TXD; tx_desc++, i++) {
	e1000_tx_bufinfo[i].buffer = dwStartAddress;
	dwStartAddress += E1000_MAX_DATA_PER_TXD;
	if ((dwSize -= E1000_MAX_DATA_PER_TXD) < 0) {
	    E1000_ERR("Unable to allocate data buffer for the transmit descriptor\n");
	    return FALSE;
	}
    }

#define E1000_MAX_DATA_PER_RXD E1000_RXBUFFER_2048
    e1000.rx_ring = &e1000_rx_ring;
    size = (e1000.hw.mac_type <= e1000_82547_rev_2)? sizeof(struct e1000_rx_desc) : sizeof(union e1000_rx_desc_packet_split);
    size = (e1000_rx_ring.count = E1000_DEFAULT_RXD) * size;
    E1000_ROUNDUP(size, 4096);
    if (!e1000_check_64k_bound(&e1000, (void*)dwStartAddress, size)) {
	E1000_ERR("Unable to allocate aligned memory for the receive descriptor ring\n");
	return FALSE;
    }
    rx_desc = (struct e1000_rx_desc*)dwStartAddress;
    e1000_rx_ring.desc = (void *)dwStartAddress;
    dwStartAddress += (e1000_rx_ring.size = size);
    if ((dwSize -= size) < 0) {
	E1000_ERR("Unable to allocate memory for the receive descriptor ring\n");
	return FALSE;
    }
    e1000_rx_ring.buffer_info = e1000_rx_bufinfo;
    for (i = 0; i < E1000_DEFAULT_RXD; rx_desc++, i++) {
        if (!e1000_check_64k_bound(&e1000, (void*)dwStartAddress, E1000_MAX_DATA_PER_RXD)) {
	    E1000_ERR("Receive data buffer can't cross 64KB boundary\n");
	    return FALSE;
	}
	e1000_rx_bufinfo[i].buffer = dwStartAddress;
	dwStartAddress += E1000_MAX_DATA_PER_RXD;
	if ((dwSize -= E1000_MAX_DATA_PER_RXD) < 0) {
	    E1000_ERR("Unable to allocate data buffer for the receive descriptor\n");
	    return FALSE;
	}
    }

    EdbgOutputDebugString("TxDesc=0x%x(%d) RxDesc=0x%x(%d)\n", e1000_tx_ring.desc, e1000_tx_ring.size,
							       e1000_rx_ring.desc, e1000_rx_ring.size);

    return TRUE;
}   //  E1000InitDMABuffer()

static void e1000_power_up_phy (struct e1000_adapter *adapter)
{
	uint16_t mii_reg;
	struct e1000_hw *hw = &adapter->hw;

	if (hw->media_type == e1000_media_type_copper) {
		e1000_read_phy_reg(hw, PHY_CTRL, &mii_reg);
		mii_reg &= ~MII_CR_POWER_DOWN;
		e1000_write_phy_reg(hw, PHY_CTRL, mii_reg);
	}
}

static int e1000_sw_init (struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;

	adapter->itr = 0;
	adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
	hw->max_frame_size = MAXIMUM_ETHERNET_VLAN_SIZE + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
	hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;

	switch (hw->mac_type) {
	case e1000_82541:
	case e1000_82547:
	case e1000_82541_rev_2:
	case e1000_82547_rev_2:
		hw->phy_init_script = 1;
	}

	e1000_set_media_type(hw);

	hw->autoneg = TRUE;
	hw->wait_autoneg_complete = TRUE;
	hw->tbi_compatibility_en = TRUE;
	hw->adaptive_ifs = TRUE;

	if (hw->media_type == e1000_media_type_copper) {
		hw->mdix = AUTO_ALL_MODES;
		hw->disable_polarity_correction = FALSE;
		hw->master_slave = E1000_MASTER_SLAVE;
	}

	return 0;
}

static void e1000_reset (struct e1000_adapter *adapter)
{
	uint32_t pba;
	uint16_t fc_high_water_mark = E1000_FC_HIGH_DIFF;
	struct e1000_hw *hw = &adapter->hw;

	switch (hw->mac_type) {
	case e1000_82547:
	case e1000_82547_rev_2:
		pba = E1000_PBA_30K;
		break;
	case e1000_82571:
	case e1000_82572:
	case e1000_80003es2lan:
		pba = E1000_PBA_38K;
		break;
	case e1000_82573:
		pba = E1000_PBA_12K;
		break;
	case e1000_82574:
		pba = E1000_PBA_12K;
		break;
	case e1000_ich8lan:
		pba = E1000_PBA_8K;
		break;
#ifdef NAHUM2
	case e1000_ich9lan:
		pba = E1000_PBA_10K;
		break;
#endif /* NAHUM2 */
	default:
		pba = E1000_PBA_48K;
		break;
	}

	if (hw->mac_type == e1000_82547) {
		adapter->tx_fifo_head = 0;
		adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT;
		adapter->tx_fifo_size = (E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT;
	}

	E1000_WRITE_REG(hw, PBA, pba);

	fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8;
	if (pba < E1000_PBA_16K)
		fc_high_water_mark = (pba * 1024) - 1600;

	hw->fc_high_water = fc_high_water_mark;
	hw->fc_low_water = fc_high_water_mark - 8;
	if (hw->mac_type == e1000_80003es2lan)
		hw->fc_pause_time = 0xFFFF;
	else
		hw->fc_pause_time = E1000_FC_PAUSE_TIME;
	hw->fc_send_xon = 1;
	hw->fc = hw->original_fc;

	e1000_reset_hw(hw);
	if (hw->mac_type >= e1000_82544)
		E1000_WRITE_REG(hw, WUC, 0);
	if (e1000_init_hw(hw))
		E1000_ERR("Hardware Error\n");
#if 0
	e1000_update_mng_vlan(adapter);
	E1000_WRITE_REG(hw, VET, ETHERNET_IEEE_VLAN_TYPE);
#endif

	e1000_reset_adaptive(hw);
	e1000_phy_get_info(hw, &adapter->phy_info);

	if (!adapter->smart_power_down &&
	    (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572)) {
		uint16_t phy_data;
		e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
		phy_data &= ~IGP02E1000_PM_SPD;
		e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
	}
}

static void e1000_get_hw_control (struct e1000_adapter *adapter)
{
	uint32_t ctrl_ext;
	uint32_t swsm;
	uint32_t extcnf;
	struct e1000_hw *hw = &adapter->hw;

	switch (hw->mac_type) {
	case e1000_82571:
	case e1000_82572:
	case e1000_80003es2lan:
		ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
		E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
		break;
	case e1000_82573:
		swsm = E1000_READ_REG(hw, SWSM);
		E1000_WRITE_REG(hw, SWSM, swsm | E1000_SWSM_DRV_LOAD);
		break;
	case e1000_82574:
		swsm = E1000_READ_REG(hw, SWSM);
		E1000_WRITE_REG(hw, SWSM, swsm | E1000_SWSM_DRV_LOAD);
		break;
	case e1000_ich8lan:
#ifdef NAHUM2
	case e1000_ich9lan:
#endif /* NAHUM2 */
		extcnf = E1000_READ_REG(hw, EXTCNF_CTRL);
		E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf | E1000_EXTCNF_CTRL_SWFLAG);
		break;
	}
}

static void e1000_configure_tx (struct e1000_adapter *adapter)
{
	uint64_t tdba;
	struct e1000_hw *hw = &adapter->hw;
	uint32_t tdlen, tctl, tipg, tarc;
	uint32_t ipgr1, ipgr2;

	tdba = TO_PHYS((uint32_t)adapter->tx_ring->desc);
	tdlen = adapter->tx_ring->count * sizeof(struct e1000_tx_desc);
	E1000_WRITE_REG(hw, TDLEN, tdlen);
	E1000_WRITE_REG(hw, TDBAH, (tdba >> 32));
	E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL));
	E1000_WRITE_REG(hw, TDT, 0);
	E1000_WRITE_REG(hw, TDH, 0);
	adapter->tx_ring->tdh = ((hw->mac_type >= e1000_82543) ? E1000_TDH : E1000_82542_TDH);
	adapter->tx_ring->tdt = ((hw->mac_type >= e1000_82543) ? E1000_TDT : E1000_82542_TDT);

	if (hw->media_type == e1000_media_type_fiber ||
	    hw->media_type == e1000_media_type_internal_serdes)
		tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
	else
		tipg = DEFAULT_82543_TIPG_IPGT_COPPER;

	switch (hw->mac_type) {
	case e1000_82542_rev2_0:
	case e1000_82542_rev2_1:
		tipg = DEFAULT_82542_TIPG_IPGT;
		ipgr1 = DEFAULT_82542_TIPG_IPGR1;
		ipgr2 = DEFAULT_82542_TIPG_IPGR2;
		break;
	case e1000_80003es2lan:
		ipgr1 = DEFAULT_82543_TIPG_IPGR1;
		ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2;
		break;
	default:
		ipgr1 = DEFAULT_82543_TIPG_IPGR1;
		ipgr2 = DEFAULT_82543_TIPG_IPGR2;
		break;
	}
	tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT;
	tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT;
	E1000_WRITE_REG(hw, TIPG, tipg);

	E1000_WRITE_REG(hw, TIDV, 64);
	if (hw->mac_type >= e1000_82540)
		E1000_WRITE_REG(hw, TADV, 64);

	tctl = E1000_READ_REG(hw, TCTL);
	tctl &= ~E1000_TCTL_CT;
	tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);

#ifdef DISABLE_MULR
	tctl &= ~E1000_TCTL_MULR;
#endif

	if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) {
		tarc = E1000_READ_REG(hw, TARC0);
		tarc |= ((1 << 25) | (1 << 21));
		E1000_WRITE_REG(hw, TARC0, tarc);
		tarc = E1000_READ_REG(hw, TARC1);
		tarc |= (1 << 25);
		if (tctl & E1000_TCTL_MULR)
			tarc &= ~(1 << 28);
		else
			tarc |= (1 << 28);
		E1000_WRITE_REG(hw, TARC1, tarc);
	} else if (hw->mac_type == e1000_80003es2lan) {
		tarc = E1000_READ_REG(hw, TARC0);
		tarc |= 1;
		if (hw->media_type == e1000_media_type_internal_serdes)
			tarc |= (1 << 20);
		E1000_WRITE_REG(hw, TARC0, tarc);
		tarc = E1000_READ_REG(hw, TARC1);
		tarc |= 1;
		E1000_WRITE_REG(hw, TARC1, tarc);
	}

	e1000_config_collision_dist(hw);

	adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;

	if (hw->mac_type < e1000_82543)
		adapter->txd_cmd |= E1000_TXD_CMD_RPS;
	else
		adapter->txd_cmd |= E1000_TXD_CMD_RS;

	/* Cache if we're 82544 running in PCI-X because we'll
	 * need this to apply a workaround later in the send path. */
	if (hw->mac_type == e1000_82544 && hw->bus_type == e1000_bus_type_pcix)
		adapter->pcix_82544 = 1;

	E1000_DBG("E1000_TCTL <- 0x%x\n", tctl);
	E1000_WRITE_REG(hw, TCTL, tctl);
}

static void e1000_setup_rctl (struct e1000_adapter *adapter)
{
	uint32_t rctl;
	uint32_t psrctl = 0;
	struct e1000_hw *hw = &adapter->hw;

	rctl = E1000_READ_REG(hw, RCTL);
	rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
	rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
		E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
		(hw->mc_filter_type << E1000_RCTL_MO_SHIFT);

	if (hw->tbi_compatibility_on == 1)
		rctl |= E1000_RCTL_SBP;
	else
		rctl &= ~E1000_RCTL_SBP;

	rctl &= ~E1000_RCTL_LPE;

	rctl &= ~E1000_RCTL_SZ_4096;
	rctl |= E1000_RCTL_BSEX;
	switch (adapter->rx_buffer_len) {
		case E1000_RXBUFFER_256:
			rctl |= E1000_RCTL_SZ_256;
			rctl &= ~E1000_RCTL_BSEX;
			break;
		case E1000_RXBUFFER_512:
			rctl |= E1000_RCTL_SZ_512;
			rctl &= ~E1000_RCTL_BSEX;
			break;
		case E1000_RXBUFFER_1024:
			rctl |= E1000_RCTL_SZ_1024;
			rctl &= ~E1000_RCTL_BSEX;
			break;
		case E1000_RXBUFFER_2048:
		default:
			rctl |= E1000_RCTL_SZ_2048;
			rctl &= ~E1000_RCTL_BSEX;
			break;
		case E1000_RXBUFFER_4096:
			rctl |= E1000_RCTL_SZ_4096;
			break;
		case E1000_RXBUFFER_8192:
			rctl |= E1000_RCTL_SZ_8192;
			break;
		case E1000_RXBUFFER_16384:
			rctl |= E1000_RCTL_SZ_16384;
			break;
	}

	E1000_WRITE_REG(hw, RCTL, rctl);
}

static void e1000_configure_rx (struct e1000_adapter *adapter)
{
	uint64_t rdba;
	struct e1000_hw *hw = &adapter->hw;
	uint32_t rdlen, rctl, rxcsum, ctrl_ext;

	rdlen = adapter->rx_ring->count * sizeof(struct e1000_rx_desc);

	rctl = E1000_READ_REG(hw, RCTL);
	E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);

	E1000_WRITE_REG(hw, RDTR, 0);

	if (hw->mac_type >= e1000_82540) {
		E1000_WRITE_REG(hw, RADV, 128);
		if (adapter->itr > 1)
			E1000_WRITE_REG(hw, ITR, 1000000000 / (adapter->itr * 256));
	}

	if (hw->mac_type >= e1000_82571) {
		ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
		ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR;
		E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
		E1000_WRITE_REG(hw, IAM, ~0);
		E1000_WRITE_FLUSH(hw);
	}

	rdba = TO_PHYS((uint32_t)adapter->rx_ring->desc);
	E1000_WRITE_REG(hw, RDLEN, rdlen);
	E1000_WRITE_REG(hw, RDBAH, (rdba >> 32));
	E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL));
	E1000_WRITE_REG(hw, RDT, 0);
	E1000_WRITE_REG(hw, RDH, 0);
	adapter->rx_ring->rdh = ((hw->mac_type >= e1000_82543) ? E1000_RDH : E1000_82542_RDH);
	adapter->rx_ring->rdt = ((hw->mac_type >= e1000_82543) ? E1000_RDT : E1000_82542_RDT);

	if (hw->mac_type >= e1000_82543) {
		rxcsum = E1000_READ_REG(hw, RXCSUM);
		if (adapter->rx_csum == TRUE) {
			rxcsum |= E1000_RXCSUM_TUOFL;
		} else {
			rxcsum &= ~E1000_RXCSUM_TUOFL;
		}
		E1000_WRITE_REG(hw, RXCSUM, rxcsum);
	}

	E1000_DBG("E1000_RTCL <- 0x%x\n", rctl);
	E1000_WRITE_REG(hw, RCTL, rctl);
}

static void e1000_alloc_rx_buffers (struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, int cleaned_count)
{
	struct e1000_rx_desc *rx_desc;
	struct e1000_buffer *buffer_info;
	unsigned int i;

	i = rx_ring->next_to_use;

	while (cleaned_count--) {
		buffer_info = rx_ring->buffer_info + i;
		rx_desc = E1000_RX_DESC(*rx_ring, i);
		rx_desc->buffer_addr = cpu_to_le64(TO_PHYS(buffer_info->buffer));

		NEXT(i, rx_ring->count);
	}

	if (rx_ring->next_to_use != i) {
		rx_ring->next_to_use = i;
#ifndef NOMEMIO
		*(UINT32*)(adapter->hw.hw_addr + rx_ring->rdt) = i? (i - 1) : (rx_ring->count - 1);
#else
		e1000_write_reg_io(&adapter->hw, rx_ring->rdt, i? (i - 1) : (rx_ring->count - 1));
#endif
	}
}

BOOL E1000Init (UINT8 *pbBaseAddress, UINT32 dwMemOffset, UINT16 MacAddr[3])
{
    static int e1000_ksp3_port_a = 0;
    int err;
    struct e1000_adapter *adapter = &e1000;
    struct e1000_hw *hw = &adapter->hw;

    adapter->dwMemOffset = dwMemOffset;
    hw->back    = adapter;

    if ((err = e1000_sw_init(adapter)))
	goto err_sw_init;

    if ((err = e1000_check_phy_reset_block(hw)))
	E1000_ERR("PHY reset is blocked due to SOL/IDER session.\n");

    if (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 && e1000_ksp3_port_a == 0)
	adapter->ksp3_port_a = 1;
    e1000_ksp3_port_a++;
    if (e1000_ksp3_port_a == 4)
	e1000_ksp3_port_a = 0;

    adapter->en_mng_pt = e1000_enable_mng_pass_thru(hw);

    if (e1000_init_eeprom_params(hw)) {
	E1000_ERR("EEPROM initialization failed\n");
	err = -EIO;
	goto err_eeprom;
    }

    e1000_reset_hw(hw);

    if (e1000_validate_eeprom_checksum(hw) < 0) {
	E1000_ERR("The EEPROM Checksum Is Not Valid\n");
	err = -EIO;
	goto err_eeprom;
    }

    if (e1000_read_mac_addr(hw))
	E1000_ERR("EEPROM Read Error\n");
    else {
	MacAddr[0] = (hw->mac_addr[1] << 8) | (hw->mac_addr[0]);
	MacAddr[1] = (hw->mac_addr[3] << 8) | (hw->mac_addr[2]);
	MacAddr[2] = (hw->mac_addr[5] << 8) | (hw->mac_addr[4]);
    }

    e1000_read_part_num(hw, &(adapter->part_num));
    e1000_get_bus_info(hw);

    E1000_DBG("(PCI%s:%s:%s) ",
	((hw->bus_type == e1000_bus_type_pcix) ? "-X" :
	 (hw->bus_type == e1000_bus_type_pci_express ? " Express":"")),
	((hw->bus_speed == e1000_bus_speed_2500) ? "2.5Gb/s" :
	 (hw->bus_speed == e1000_bus_speed_133) ? "133MHz" :
	 (hw->bus_speed == e1000_bus_speed_120) ? "120MHz" :
	 (hw->bus_speed == e1000_bus_speed_100) ? "100MHz" :
	 (hw->bus_speed == e1000_bus_speed_66) ? "66MHz" : "33MHz"),
	((hw->bus_width == e1000_bus_width_64) ? "64-bit" :
	 (hw->bus_width == e1000_bus_width_pciex_4) ? "Width x4" :
	 (hw->bus_width == e1000_bus_width_pciex_1) ? "Width x1" : "32-bit"));

    e1000_reset(adapter);

    if ((hw->mac_type != e1000_82573 && hw->mac_type != e1000_82574) || !e1000_check_mng_mode(hw))
	e1000_get_hw_control(adapter);

    EdbgOutputDebugString("Intel(R) PRO/1000 Network Connection\n");

    e1000_power_up_phy(adapter);

    e1000_configure_tx(adapter);
    e1000_setup_rctl(adapter);
    e1000_configure_rx(adapter);
    e1000_alloc_rx_buffers(adapter, adapter->rx_ring, E1000_DESC_UNUSED(adapter->rx_ring));

    adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
    err = 0;

err_sw_init:
err_eeprom:
    return !err;
}   //  E1000Init()

void E1000EnableInts ()
{
    struct e1000_adapter *adapter = &e1000;
    EdbgOutputDebugString("+E1000EnableInts\n");
    E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK);
    E1000_WRITE_FLUSH(&adapter->hw);
}   // E1000EnableInts()

void E1000DisableInts ()
{    
    struct e1000_adapter *adapter = &e1000;
    EdbgOutputDebugString("+E1000DisableInts\n");
    E1000_WRITE_REG(&adapter->hw, IMC, ~0);
    E1000_WRITE_FLUSH(&adapter->hw);
}   //  E1000DisableInts()

static void e1000_smartspeed (struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;
	uint16_t phy_status;
	uint16_t phy_ctrl;

	if ((hw->phy_type != e1000_phy_igp) || !hw->autoneg || !(hw->autoneg_advertised & ADVERTISE_1000_FULL))
		return;

	if (adapter->smartspeed == 0) {
		e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status);
		if (!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return;
		e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_status);
		if (!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return;
		e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_ctrl);
		if (phy_ctrl & CR_1000T_MS_ENABLE) {
			phy_ctrl &= ~CR_1000T_MS_ENABLE;
			e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_ctrl);
			adapter->smartspeed++;
			if (!e1000_phy_setup_autoneg(hw) &&
			   !e1000_read_phy_reg(hw, PHY_CTRL, &phy_ctrl)) {
				phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
				e1000_write_phy_reg(hw, PHY_CTRL, phy_ctrl);
			}
		}
		return;
	} else if (adapter->smartspeed == E1000_SMARTSPEED_DOWNSHIFT) {
		e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_ctrl);
		phy_ctrl |= CR_1000T_MS_ENABLE;
		e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_ctrl);
		if (!e1000_phy_setup_autoneg(hw) &&
		   !e1000_read_phy_reg(hw, PHY_CTRL, &phy_ctrl)) {
			phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
			e1000_write_phy_reg(hw, PHY_CTRL, phy_ctrl);
		}
	}
	if (adapter->smartspeed++ == E1000_SMARTSPEED_MAX)
		adapter->smartspeed = 0;
}

#ifndef NOSTATISTICS
void e1000_update_stats (struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;
	struct e1000_hw_stats *stats = &adapter->stats;
	uint16_t phy_tmp;

#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF

	if (adapter->link_speed == 0)
		return;

	stats->crcerrs += E1000_READ_REG(hw, CRCERRS);
	stats->gprc    += E1000_READ_REG(hw, GPRC);
	stats->gorcl   += E1000_READ_REG(hw, GORCL);
	stats->gorch   += E1000_READ_REG(hw, GORCH);
	stats->bprc    += E1000_READ_REG(hw, BPRC);
	stats->mprc    += E1000_READ_REG(hw, MPRC);
	stats->roc     += E1000_READ_REG(hw, ROC);

	if (hw->mac_type != e1000_ich8lan
#ifdef NAHUM2
	    && hw->mac_type != e1000_ich9lan
#endif /* NAHUM2 */
	    ) {
		stats->prc64   += E1000_READ_REG(hw, PRC64);
		stats->prc127  += E1000_READ_REG(hw, PRC127);
		stats->prc255  += E1000_READ_REG(hw, PRC255);
		stats->prc511  += E1000_READ_REG(hw, PRC511);
		stats->prc1023 += E1000_READ_REG(hw, PRC1023);
		stats->prc1522 += E1000_READ_REG(hw, PRC1522);
	}

	stats->symerrs += E1000_READ_REG(hw, SYMERRS);
	stats->mpc     += E1000_READ_REG(hw, MPC);
	stats->scc     += E1000_READ_REG(hw, SCC);
	stats->ecol    += E1000_READ_REG(hw, ECOL);
	stats->mcc     += E1000_READ_REG(hw, MCC);
	stats->latecol += E1000_READ_REG(hw, LATECOL);
	stats->dc      += E1000_READ_REG(hw, DC);
	stats->sec     += E1000_READ_REG(hw, SEC);
	stats->rlec    += E1000_READ_REG(hw, RLEC);
	stats->xonrxc  += E1000_READ_REG(hw, XONRXC);
	stats->xontxc  += E1000_READ_REG(hw, XONTXC);
	stats->xoffrxc += E1000_READ_REG(hw, XOFFRXC);
	stats->xofftxc += E1000_READ_REG(hw, XOFFTXC);
	stats->fcruc   += E1000_READ_REG(hw, FCRUC);
	stats->gptc    += E1000_READ_REG(hw, GPTC);
	stats->gotcl   += E1000_READ_REG(hw, GOTCL);
	stats->gotch   += E1000_READ_REG(hw, GOTCH);
	stats->rnbc    += E1000_READ_REG(hw, RNBC);
	stats->ruc     += E1000_READ_REG(hw, RUC);
	stats->rfc     += E1000_READ_REG(hw, RFC);
	stats->rjc     += E1000_READ_REG(hw, RJC);
	stats->torl    += E1000_READ_REG(hw, TORL);
	stats->torh    += E1000_READ_REG(hw, TORH);
	stats->totl    += E1000_READ_REG(hw, TOTL);
	stats->toth    += E1000_READ_REG(hw, TOTH);
	stats->tpr     += E1000_READ_REG(hw, TPR);

	if (hw->mac_type != e1000_ich8lan
#ifdef NAHUM2
	    && hw->mac_type != e1000_ich9lan
#endif /* NAHUM2 */
	    ) {
		stats->ptc64   += E1000_READ_REG(hw, PTC64);
		stats->ptc127  += E1000_READ_REG(hw, PTC127);
		stats->ptc255  += E1000_READ_REG(hw, PTC255);
		stats->ptc511  += E1000_READ_REG(hw, PTC511);
		stats->ptc1023 += E1000_READ_REG(hw, PTC1023);
		stats->ptc1522 += E1000_READ_REG(hw, PTC1522);
	}

	stats->mptc += E1000_READ_REG(hw, MPTC);
	stats->bptc += E1000_READ_REG(hw, BPTC);

	hw->tx_packet_delta = E1000_READ_REG(hw, TPT);
	stats->tpt         += hw->tx_packet_delta;
	hw->collision_delta = E1000_READ_REG(hw, COLC);
	stats->colc        += hw->collision_delta;

	if (hw->mac_type >= e1000_82543) {
		stats->algnerrc += E1000_READ_REG(hw, ALGNERRC);
		stats->rxerrc   += E1000_READ_REG(hw, RXERRC);
		stats->tncrs    += E1000_READ_REG(hw, TNCRS);
		stats->cexterr  += E1000_READ_REG(hw, CEXTERR);
		stats->tsctc    += E1000_READ_REG(hw, TSCTC);
		stats->tsctfc   += E1000_READ_REG(hw, TSCTFC);
	}
	if (hw->mac_type > e1000_82547_rev_2) {
		stats->iac    += E1000_READ_REG(hw, IAC);
		stats->icrxoc += E1000_READ_REG(hw, ICRXOC);

		if (hw->mac_type != e1000_ich8lan
#ifdef NAHUM2
		    && hw->mac_type != e1000_ich9lan
#endif /* NAHUM2 */
		    ) {
			stats->icrxptc  += E1000_READ_REG(hw, ICRXPTC);
			stats->icrxatc  += E1000_READ_REG(hw, ICRXATC);
			stats->ictxptc  += E1000_READ_REG(hw, ICTXPTC);
			stats->ictxatc  += E1000_READ_REG(hw, ICTXATC);
			stats->ictxqec  += E1000_READ_REG(hw, ICTXQEC);
			stats->ictxqmtc += E1000_READ_REG(hw, ICTXQMTC);
			stats->icrxdmtc += E1000_READ_REG(hw, ICRXDMTC);
		}
	}

	if (hw->media_type == e1000_media_type_copper) {
		if ((adapter->link_speed == SPEED_1000) &&
		   (!e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) {
			phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
			adapter->phy_stats.idle_errors += phy_tmp;
		}

		if ((hw->mac_type <= e1000_82546) &&
		   (hw->phy_type == e1000_phy_m88) &&
		   !e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp))
			adapter->phy_stats.receive_errors += phy_tmp;
	}
}
#endif // NOSTATISTICS

static boolean_t e1000_clean_tx_irq (struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring)
{
	struct e1000_tx_desc *tx_desc, *eop_desc;
	unsigned int i, eop;
	boolean_t cleaned = FALSE;

	i = tx_ring->next_to_clean;
	eop = tx_ring->buffer_info[i].next_to_watch;
	eop_desc = E1000_TX_DESC(*tx_ring, eop);

	while (i != tx_ring->next_to_use && eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
		for (cleaned = FALSE; !cleaned; ) {
			tx_desc = E1000_TX_DESC(*tx_ring, i);
			cleaned = (i == eop);
			tx_desc->upper.data = 0;
			NEXT(i, tx_ring->count);
		}
		eop = tx_ring->buffer_info[i].next_to_watch;
		eop_desc = E1000_TX_DESC(*tx_ring, eop);
	}

	tx_ring->next_to_clean = i;

	return cleaned;
}

static void e1000_tx_queue (struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
			    int tx_flags, UINT8 *data, UINT32 len, unsigned int max_per_txd)
{
	struct e1000_hw *hw = &adapter->hw;
	struct e1000_tx_desc *tx_desc = NULL;
	uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS;
	unsigned int size, first, count = 0, i;

#if 0
	if (tx_flags & E1000_TX_FLAGS_TSO) {
		txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | E1000_TXD_CMD_TSE;
		txd_upper |= E1000_TXD_POPTS_TXSM << 8;
		if (tx_flags & E1000_TX_FLAGS_IPV4)
			txd_upper |= E1000_TXD_POPTS_IXSM << 8;
	}
	if (tx_flags & E1000_TX_FLAGS_CSUM) {
		txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
		txd_upper |= E1000_TXD_POPTS_TXSM << 8;
	}
	if (tx_flags & E1000_TX_FLAGS_VLAN) {
		txd_lower |= E1000_TXD_CMD_VLE;
		txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK);
	}
#endif

	for (first = i = tx_ring->next_to_use; len > 0; count++) {
		struct e1000_buffer *buffer_info = tx_ring->buffer_info + i;
		size = min(len, max_per_txd);
		if (hw->bus_type == e1000_bus_type_pcix && (size > 2015) && count == 0)
		        size = 2015;

		if (adapter->pcix_82544 && !((unsigned long)(data + size - 1) & 4) && size > 4)
			size -= 4;

		memcpy((void*)buffer_info->buffer, data, size);
		tx_desc = E1000_TX_DESC(*tx_ring, i);
		tx_desc->buffer_addr = cpu_to_le64(TO_PHYS(buffer_info->buffer));
		tx_desc->lower.data  = cpu_to_le32(txd_lower | size);
		tx_desc->upper.data  = cpu_to_le32(txd_upper);

		data += size, len -= size;
		NEXT(i, tx_ring->count);
	}
	tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);

	tx_ring->next_to_use = i;
	tx_ring->buffer_info[first].next_to_watch = ((i == 0)? tx_ring->count - 1 : i - 1);

#ifndef NOMEMIO
	*(UINT32*)(hw->hw_addr + tx_ring->tdt) = i;
#else
	e1000_write_reg_io(hw, tx_ring->tdt, i);
#endif
}

static uint32_t e1000_clean_rx_irq (struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring, UINT8* buf)
{
	struct e1000_rx_desc *rx_desc;
	uint32_t length = 0;
	unsigned int i;
	static uint32_t cleaned_count = 0;
	uint8_t status;

	i = rx_ring->next_to_clean;
	rx_desc = E1000_RX_DESC(*rx_ring, i);

	if ((status = rx_desc->status) & E1000_RXD_STAT_DD) {
		boolean_t error = FALSE;
		cleaned_count++;
		if (!(status & E1000_RXD_STAT_EOP)) {
			E1000_ERR("Receive packet consumed multiple buffers\n");
			error = TRUE;
		}
		if (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
			E1000_ERR("Receive error packet\n");
			error = TRUE;
		}

		if (error) {
#ifdef DBG
#define DUMP_PKTSIZE 64
			struct e1000_buffer *buffer_info = rx_ring->buffer_info + i;
			MemoryDump(rx_desc, sizeof(*rx_desc));
			MemoryDump((void*)buffer_info->buffer, DUMP_PKTSIZE);
#endif
		} else if ((length = le16_to_cpu(rx_desc->length)) > 0) {
			memcpy(buf, (void*)rx_ring->buffer_info[i].buffer, length);
			/* adjust length to remove Ethernet CRC */
			length -= 4;
		}
		rx_desc->status = 0;

		NEXT(i, rx_ring->count);

		/* return some buffers to hardware, one at a time is too slow */
		if (cleaned_count >= (rx_ring->count >> 1)) {
			e1000_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
			cleaned_count = 0;
		}
	}
	rx_ring->next_to_clean = i;

	return length;
}

static void e1000_watchdog (struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;
	struct e1000_tx_ring *txdr = adapter->tx_ring;
	uint32_t link, tctl;
	int32_t ret_val;
	static boolean_t last_link, first = TRUE;

	ret_val = e1000_check_for_link(hw);
	if ((ret_val == E1000_ERR_PHY) &&
	    (hw->phy_type == e1000_phy_igp_3) &&
	    (E1000_READ_REG(hw, CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) {
		E1000_DBG("Gigabit has been disabled, downgrading speed\n");
	}
	if ((hw->mac_type == e1000_82573) ||(hw->mac_type == e1000_82574)) {
		e1000_enable_tx_pkt_filtering(hw);
#if 0
		if (adapter->mng_vlan_id != hw->mng_cookie.vlan_id)
			e1000_update_mng_vlan(adapter);
#endif
	}

	if ((hw->media_type == e1000_media_type_internal_serdes) && !(E1000_READ_REG(hw, TXCW) & E1000_TXCW_ANE))
		link = !hw->serdes_link_down;
	else
		link = E1000_READ_REG(hw, STATUS) & E1000_STATUS_LU;

	if (first || link != last_link) {
		first = FALSE;
		if (link) {
			boolean_t txb2b = 1;
			e1000_get_speed_and_duplex(hw, &adapter->link_speed, &adapter->link_duplex);
			EdbgOutputDebugString("NIC Link is Up %d Mbps %s\n",
			       adapter->link_speed,
			       adapter->link_duplex == FULL_DUPLEX ?
			       "Full Duplex" : "Half Duplex");

			adapter->tx_timeout_factor = 1;
			switch (adapter->link_speed) {
			case SPEED_10:
				txb2b = 0;
				adapter->tx_timeout_factor = 8;
				break;
			case SPEED_100:
				txb2b = 0;
				break;
			}

			if ((hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) && txb2b == 0) {
#define SPEED_MODE_BIT (1 << 21)
				uint32_t tarc0;
				tarc0 = E1000_READ_REG(hw, TARC0);
				tarc0 &= ~SPEED_MODE_BIT;
				E1000_WRITE_REG(hw, TARC0, tarc0);
			}

			tctl = E1000_READ_REG(hw, TCTL);
			tctl |= E1000_TCTL_EN;
			E1000_WRITE_REG(hw, TCTL, tctl);

			adapter->smartspeed = 0;
		} else {
			adapter->link_speed = adapter->link_duplex = 0;
			EdbgOutputDebugString("NIC Link is Down\n");
		}
		e1000_smartspeed(adapter);
		last_link = link;
	}

#ifndef NOSTATISTICS
	e1000_update_stats(adapter);
#endif

	hw->tx_packet_delta = (uint32_t)(adapter->stats.tpt - adapter->tpt_old);
	adapter->tpt_old = adapter->stats.tpt;
	hw->collision_delta = (uint32_t)(adapter->stats.colc - adapter->colc_old);
	adapter->colc_old = adapter->stats.colc;

	adapter->gorcl = (uint32_t)(adapter->stats.gorcl - adapter->gorcl_old);
	adapter->gorcl_old = adapter->stats.gorcl;
	adapter->gotcl = (uint32_t)(adapter->stats.gotcl - adapter->gotcl_old);
	adapter->gotcl_old = adapter->stats.gotcl;

	e1000_update_adaptive(hw);

	if (hw->mac_type >= e1000_82540 && adapter->itr == 1) {
		uint32_t goc = (adapter->gotcl + adapter->gorcl) / 10000;
		uint32_t dif = (adapter->gotcl > adapter->gorcl ?
			adapter->gotcl - adapter->gorcl :
			adapter->gorcl - adapter->gotcl) / 10000;
		uint32_t itr = goc > 0 ? (dif * 6000 / goc + 2000) : 8000;
		E1000_WRITE_REG(hw, ITR, 1000000000 / (itr * 256));
	}

	if (hw->mac_type == e1000_82571 && hw->laa_is_present)
		e1000_rar_set(hw, hw->mac_addr, 0);
}

static void e1000_service_intr (struct e1000_adapter *adapter, UINT8 *pbData, UINT16 *pwLength)
{
	struct e1000_hw *hw = &adapter->hw;
	uint32_t rctl, icr = E1000_READ_REG(hw, ICR);
	int i;

	if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
		hw->get_link_status = 1;
		if (hw->mac_type == e1000_80003es2lan) {
			rctl = E1000_READ_REG(hw, RCTL);
			E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
		}
		e1000_watchdog(adapter);
	}

	if (hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) {
		E1000_WRITE_REG(hw, IMC, ~0);
	}

	for (i = 0; i < E1000_MAX_INTR; i++)
		if (!e1000_clean_tx_irq(adapter, adapter->tx_ring))
			break;

	*pwLength = (UINT16)e1000_clean_rx_irq(adapter, adapter->rx_ring, pbData);

	if (hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2)
		E1000EnableInts();
}

UINT16 E1000GetFrame (UINT8 *pbData, UINT16 *pwLength)
{
    *pwLength = 0;

    e1000_service_intr(&e1000, pbData, pwLength);

    return *pwLength;
}    // E1000GetFrame()

UINT16 E1000SendFrame (UINT8 *pbData, UINT32 dwLength)
{       
    struct e1000_adapter *adapter = &e1000;
    struct e1000_tx_ring *tx_ring = adapter->tx_ring;
    unsigned int max_per_txd = E1000_MAX_DATA_PER_TXD, max_txd_pwr = E1000_MAX_TXD_PWR;
    unsigned int count, tx_flags = 0;

    for (count = 0; count < E1000_MAX_INTR; count++)
	if (!e1000_clean_tx_irq(adapter, tx_ring))
	    break;

    count = TXD_USE_COUNT(dwLength, max_txd_pwr);
    if (adapter->pcix_82544)
	count++;

    if (adapter->hw.bus_type == e1000_bus_type_pcix && dwLength > 2015)
	count++;

    if (E1000_DESC_UNUSED(tx_ring) < count + 2) {
	E1000_ERR("Transmission busy.\n");
	msec_delay(100);
	return -EBUSY;
    }

    e1000_tx_queue(adapter, tx_ring, tx_flags, pbData, dwLength, max_per_txd);

    return 0;
}    // E1000SendFrame()

void E1000CurrentPacketFilter (UINT32 dwFilter)
{	
    __FUNC_NOT_IMPLEMENTED__
}	//	E1000CurrentPacketFilter()

BOOL E1000MulticastList (UINT8 *pucMulticastAddresses, UINT32 dwNoOfAddresses)
{
    __FUNC_NOT_IMPLEMENTED__
    return FALSE;
}	//	E1000MulticastList()

PCSUPPORTED_NIC E1000_Probe (PCI_COMMON_CONFIG *pPciCfg)
{
    PCSUPPORTED_NIC pNicFound = NULL;

    EdbgOutputDebugString("Intel(R) PRO/1000 KITL driver [Build: %s  %s]\n", __DATE__, __TIME__);

    e1000.hw.vendor_id           = pPciCfg->VendorID;
    e1000.hw.device_id           = pPciCfg->DeviceID;
    e1000.hw.revision_id         = pPciCfg->RevisionID;
    e1000.hw.pci_cmd_word        = pPciCfg->Command;
    e1000.hw.subsystem_vendor_id = pPciCfg->u.type0.SubVendorID;
    e1000.hw.subsystem_id        = pPciCfg->u.type0.SubSystemID;
    if (pPciCfg->VendorID == PCI_VENDOR_ID_INTEL && e1000_set_mac_type(&e1000.hw) == E1000_SUCCESS) {
	extern PCSUPPORTED_NIC FindNICByVendor (PCI_COMMON_CONFIG *);
	UINT16 device_id = pPciCfg->DeviceID;

	EdbgOutputDebugString("Found E1000 NIC DevID:0x%x MacType:%d\n", device_id, e1000.hw.mac_type);
	pPciCfg->DeviceID = 0x1000;	// set device ID temporary for searching the generic e1000 slot
	pNicFound = FindNICByVendor(pPciCfg);
	pPciCfg->DeviceID = device_id;
    }

    return pNicFound;
}
