text: /*
   * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
   * Use is subject to license terms.
   */
  
  /*
   * Copyright (c) 2001-2006 Advanced Micro Devices, Inc.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   * + Redistributions of source code must retain the above copyright notice,
   * + this list of conditions and the following disclaimer.
   *
   * + Redistributions in binary form must reproduce the above copyright
   * + notice, this list of conditions and the following disclaimer in the
   * + documentation and/or other materials provided with the distribution.
   *
   * + Neither the name of Advanced Micro Devices, Inc. nor the names of its
   * + contributors may be used to endorse or promote products derived from
   * + this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. OR
   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * Import/Export/Re-Export/Use/Release/Transfer Restrictions and
   * Compliance with Applicable Laws.  Notice is hereby given that
   * the software may be subject to restrictions on use, release,
   * transfer, importation, exportation and/or re-exportation under
   * the laws and regulations of the United States or other
   * countries ("Applicable Laws"), which include but are not
   * limited to U.S. export control laws such as the Export
   * Administration Regulations and national security controls as
   * defined thereunder, as well as State Department controls under
   * the U.S. Munitions List.  Permission to use and/or
   * redistribute the software is conditioned upon compliance with
   * all Applicable Laws, including U.S. export control laws
   * regarding specifically designated persons, countries and
   * nationals of countries subject to national security controls.
   */
  
  
  #include <sys/types.h>
  #include <sys/cmn_err.h>
  #include <sys/debug.h>
  #include <sys/ddi.h>
  #include <sys/sunddi.h>
  #include "amd8111s_hw.h"
  #include "amd8111s_main.h"
  
  
  #pragma inline(mdlTransmit)
  #pragma inline(mdlReceive)
  
  #pragma inline(mdlReadInterrupt)
  #pragma inline(mdlEnableInterrupt)
  #pragma inline(mdlDisableInterrupt)
  
  
  static void mdlEnableMagicPacketWakeUp(struct LayerPointers *);
  
  /* PMR (Pattern Match RAM) */
  static void mdlAddWakeUpPattern(struct LayerPointers *, unsigned char *,
      unsigned char *, unsigned long, unsigned long, int *);
  static void mdlRemoveWakeUpPattern(struct LayerPointers *, unsigned char *,
      unsigned long, int *);
  
  static int mdlMulticastBitMapping(struct LayerPointers *, unsigned char *, int);
  
  static unsigned int mdlCalculateCRC(unsigned int, unsigned char *);
  
  static void mdlChangeFilter(struct LayerPointers *, unsigned long *);
  static void mdlReceiveBroadCast(struct LayerPointers *);
  static void mdlDisableReceiveBroadCast(struct LayerPointers *);
  
  static void mdlRequestResources(ULONG *);
  static void mdlSetResources(struct LayerPointers *, ULONG *);
  static void mdlFreeResources(struct LayerPointers *, ULONG *);
  
  /*
   *	Initialises the data used in Mdl.
   */
  static void
  mdlInitGlbds(struct LayerPointers *pLayerPointers)
  {
  	struct mdl *pMdl = pLayerPointers->pMdl;
  
  	/* Disable Rx and Tx. */
  	pMdl->init_blk->MODE = 0x0000;
  
  	/* Set Interrupt Delay Parameters */
  	pMdl->IntrCoalescFlag = 1;
  	pMdl->rx_intrcoalesc_time = 0xC8;	/* 200 */
  	pMdl->rx_intrcoalesc_events = 5;
  }
  
  void
  mdlPHYAutoNegotiation(struct LayerPointers *pLayerPointers, unsigned int type)
  {
  	int iData = 0;
  	struct mdl *pMdl = pLayerPointers->pMdl;
  
  	/* PHY auto negotiation or force speed/duplex */
  	switch (type) {
  	case PHY_AUTO_NEGOTIATION: /* Auto Negotiation */
  		/* EN_PMGR: Disable the Port Manager */
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD3, EN_PMGR);
  		drv_usecwait(100000);
  
  		/*
  		 * Enable Autonegotiation the Phy now
  		 *	XPHYANE(eXternal PHY Auto Negotiation Enable)
  		 */
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CTRL2,
  		    XPHYANE | XPHYRST);
  
  		/* EN_PMGR: Enable the Port Manager */
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD3,
  		    VAL1 | EN_PMGR);
  
  		drv_usecwait(500000);
  
  		pMdl->Speed = 100;
  		pMdl->FullDuplex = B_TRUE;
  
  		break;
  
  	case PHY_FORCE_HD_100:	/* 100Mbps HD */
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD3, EN_PMGR);
  
  		/* Force 100 Mbps, half duplex */
  		iData |= XPHYSP;
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CTRL2, iData);
  
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD3,
  		    VAL1 | EN_PMGR);
  
  		drv_usecwait(500000);
  
  		pMdl->Speed = 100;
  		pMdl->FullDuplex = B_FALSE;
  
  		break;
  
  	case PHY_FORCE_FD_100:	/* 100Mbps FD */
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD3, EN_PMGR);
  
  		/* Force 100 Mbps, full duplex */
  		iData |= (XPHYSP | XPHYFD);
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CTRL2, iData);
  
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD3,
  		    VAL1 | EN_PMGR);
  
  		drv_usecwait(500000);
  
  		pMdl->Speed = 100;
  		pMdl->FullDuplex = B_TRUE;
  
  		break;
  
  	case PHY_FORCE_HD_10: /* 10 Mbps HD  */
  		/* Disable the Port Manager */
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD3, EN_PMGR);
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CTRL2, iData);
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD3,
  		    VAL1 | EN_PMGR);
  
  		drv_usecwait(500000);
  
  		pMdl->Speed = 10;
  		pMdl->FullDuplex = B_FALSE;
  
  		break;
  
  	case PHY_FORCE_FD_10: /* 10Mbps FD  */
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD3, EN_PMGR);
  
  		iData |= XPHYFD;
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CTRL2, iData);
  
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD3,
  		    VAL1 | EN_PMGR);
  
  		drv_usecwait(500000);
  
  		pMdl->Speed = 10;
  		pMdl->FullDuplex = B_TRUE;
  
  		break;
  	}
  }
  
  /*
   *	Clear HW configuration.
   */
  static void
  mdlClearHWConfig(struct LayerPointers *pLayerPointers)
  {
  	/*
  	 * Before the network controller is ready for operation,
  	 * several registers must be initialized.
  	 */
  	unsigned int data32;
  	int JumboFlag = JUMBO_DISABLED;
  	ULONG MemBaseAddress;
  
  	MemBaseAddress = pLayerPointers->pMdl->Mem_Address;
  
  	/* AUTOPOLL0 Register */
  	WRITE_REG16(pLayerPointers, MemBaseAddress + AUTOPOLL0, 0x8101);
  
  	/* Clear RCV_RING_BASE_ADDR */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + RCV_RING_BASE_ADDR0, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + RCV_RING_BASE_ADDR1, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + RCV_RING_BASE_ADDR0, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + RCV_RING_BASE_ADDR2, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + RCV_RING_BASE_ADDR3, 0);
  
  	/* Clear XMT_RING_BASE_ADDR */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + XMT_RING_BASE_ADDR0, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + XMT_RING_BASE_ADDR1, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + XMT_RING_BASE_ADDR2, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + XMT_RING_BASE_ADDR3, 0);
  
  	/* Clear CMD0 / CMD2 */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + CMD0, 0x000F0F7F);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + CMD2, 0x3F7F3F7F);
  
  	/* Enable Port Management */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + CMD3, VAL1 | EN_PMGR);
  
  	/* Clear CMD7 */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + CMD7, 0x1B);
  
  	/* Clear CTRL0/1 */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + CTRL1, XMTSP_MASK);
  
  	/* Clear DLY_INT_A/B */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + DLY_INT_A, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + DLY_INT_B, 0);
  
  	/* Clear FLOW_CONTROL */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + FLOW_CONTROL, 0);
  
  	/* Clear INT0 */
  	data32 = READ_REG32(pLayerPointers, MemBaseAddress + INT0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + INT0, data32);
  
  	/* Clear STVAL */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + STVAL, 0);
  
  	/* Clear INTEN0 */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + INTEN0, 0x1F7F7F1F);
  
  	/* Clear LADRF */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + LADRF1, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + LADRF1 + 4, 0);
  
  	/* Clear LED0 */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + LED0, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + LED1, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + LED2, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + LED3, 0);
  
  	/* Set RCV_RING_CFG */
  	WRITE_REG16(pLayerPointers, MemBaseAddress + RCV_RING_CFG, 1);
  
  	/* SRAM_SIZE & SRAM_BOUNDARY register combined */
  	if (JumboFlag == JUMBO_ENABLED) {
  		WRITE_REG32(pLayerPointers, MemBaseAddress + SRAM_SIZE,
  		    0xc0010);
  	} else {
  		WRITE_REG32(pLayerPointers, MemBaseAddress + SRAM_SIZE,
  		    0x80010);
  	}
  
  	/* Clear XMT_RING0/1/2/3_LEN */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + XMT_RING_LEN0, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + XMT_RING_LEN1, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + XMT_RING_LEN2, 0);
  	WRITE_REG32(pLayerPointers, MemBaseAddress + XMT_RING_LEN3, 0);
  
  	/* Clear XMT_RING_LIMIT */
  	WRITE_REG32(pLayerPointers, MemBaseAddress + XMT_RING_LIMIT, 0);
  
  	WRITE_REG16(pLayerPointers, MemBaseAddress + MIB_ADDR, MIB_CLEAR);
  }
  
  unsigned int
  mdlReadMib(struct LayerPointers *pLayerPointers, char MIB_COUNTER)
  {
  	unsigned int status;
  	unsigned int data;
  	unsigned long mmio = pLayerPointers->pMdl->Mem_Address;
  
  	WRITE_REG16(pLayerPointers, mmio + MIB_ADDR, MIB_RD_CMD | MIB_COUNTER);
  	do {
  		status = READ_REG16(pLayerPointers, mmio + MIB_ADDR);
  	} while ((status & MIB_CMD_ACTIVE));
  
  	data = READ_REG32(pLayerPointers, mmio + MIB_DATA);
  	return (data);
  }
  
  /* Return 1 on success, return 0 on fail */
  unsigned int
  mdlReadPHY(struct LayerPointers *pLayerPointers, unsigned char phyid,
      unsigned char regaddr, unsigned int *value)
  {
  	unsigned int status, data, count;
  	unsigned long mmio = pLayerPointers->pMdl->Mem_Address;
  
  	count = 0;
  	do {
  		status = READ_REG16(pLayerPointers, mmio + PHY_ACCESS);
  		count ++;
  		drv_usecwait(10);
  	} while ((status & PHY_CMD_ACTIVE) & (count < PHY_MAX_RETRY));
  
  	if (count == PHY_MAX_RETRY) {
  		return (0);
  	}
  
  	data = ((regaddr & 0x1f) << 16) | ((phyid & 0x1f) << 21) | PHY_RD_CMD;
  	WRITE_REG32(pLayerPointers, mmio + PHY_ACCESS, data);
  	do {
  		status = READ_REG16(pLayerPointers, mmio + PHY_ACCESS);
  		drv_usecwait(10);
  		count ++;
  	} while ((status & PHY_CMD_ACTIVE) & (count < PHY_MAX_RETRY));
  
  	if ((count == PHY_MAX_RETRY) || (status & PHY_RD_ERR)) {
  		return (0);
  	}
  
  	*value = status & 0xffff;
  	return (1);
  }
  
  void
  mdlGetPHYID(struct LayerPointers *pLayerPointers)
  {
  	unsigned int id1, id2, i;
  	for (i = 1; i < 32; i++) {
  		if (mdlReadPHY(pLayerPointers, i, MII_PHYSID1, &id1) == 0)
  			continue;
  		if (mdlReadPHY(pLayerPointers, i, MII_PHYSID2, &id2) == 0)
  			continue;
  		if ((id1 != 0xffff) & (id2 != 0xffff)) {
  			pLayerPointers->pMdl->phy_id = i;
  			return;
  		}
  	}
  }
  
  /* Return 1 on success, return 0 on fail */
  unsigned int
  mdlWritePHY(struct LayerPointers *pLayerPointers, unsigned char phyid,
      unsigned char regaddr, unsigned int value)
  {
  	unsigned int status, data, count;
  	unsigned long mmio = pLayerPointers->pMdl->Mem_Address;
  
  	count = 0;
  	do {
  		status = READ_REG16(pLayerPointers, mmio + PHY_ACCESS);
  		count ++;
  		drv_usecwait(10);
  	} while ((status & PHY_CMD_ACTIVE) & (count < PHY_MAX_RETRY));
  
  	if (count == PHY_MAX_RETRY) {
  		return (0);
  	}
  
  	data = ((regaddr & 0x1f) << 16) | ((phyid & 0x1f) << 21) |
  	    (value & 0xffff) | PHY_WR_CMD;
  	WRITE_REG32(pLayerPointers, mmio + PHY_ACCESS, data);
  
  	do {
  		status = READ_REG16(pLayerPointers, mmio + PHY_ACCESS);
  		drv_usecwait(10);
  		count ++;
  	} while ((status & PHY_CMD_ACTIVE) & (count < PHY_MAX_RETRY));
  
  	if ((count == PHY_MAX_RETRY) && (status & PHY_RD_ERR)) {
  		return (0);
  	}
  
  	return (1);
  }
  
  /*
   *	To Send the packet.
   */
  void
  mdlTransmit(struct LayerPointers *pLayerPointers)
  {
  	WRITE_REG32(pLayerPointers, pLayerPointers->pMdl->Mem_Address + CMD0,
  	    VAL1 | TDMD0);
  }
  
  /*
   *	To Receive a packet.
   */
  void
  mdlReceive(struct LayerPointers *pLayerPointers)
  {
  	/*
  	 * Receive Demand for ring 0, which when set causes the Descriptor
  	 * Management Unit to access the Receive Descriptor Ring if it does
  	 * not already own the next descriptor.
  	 */
  	WRITE_REG32(pLayerPointers, pLayerPointers->pMdl->Mem_Address + CMD0,
  	    VAL2 | RDMD0);
  }
  
  /*
   * Read the NIC interrupt.
   *
   * Returns:
   *	the value of interrupt causes register
   */
  unsigned int
  mdlReadInterrupt(struct LayerPointers *pLayerPointers)
  {
  	unsigned int nINT0;
  	struct mdl *pMdl = 0;
  
  	pMdl = (struct mdl *)(pLayerPointers->pMdl);
  
  	/*
  	 * INT0 identifies the source or sources of an interrupt. With the
  	 * exception of INTR and INTPN, all bits in this register are "write
  	 * 1 to clear" so that the CPU can clear the interrupt condition by
  	 * reading the register and then writing back the same data that it
  	 * read. Writing a 0 to a bit in this register has no effect.
  	 */
  
  	/* Read interrupt status */
  	nINT0 = READ_REG32(pLayerPointers, pMdl->Mem_Address + INT0);
  
  	/* Process all the INT event until INTR bit is clear. */
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + INT0, nINT0);
  	return (nINT0);
  }
  
  void
  mdlHWReset(struct LayerPointers *pLayerPointers)
  {
  	struct mdl *pMdl = pLayerPointers->pMdl;
  	unsigned int ulData, i = 0;
  	int  JumboFlag = JUMBO_DISABLED;
  	ULONG Mem_Address = pMdl->Mem_Address;
  
  	/*
  	 * Stop the Card:
  	 *	First we make sure that the device is stopped and no
  	 *	more interrupts come out. Also some registers must be
  	 *	programmed with CSR0 STOP bit set.
  	 */
  	mdlStopChip(pLayerPointers);
  
  	/*
  	 * MAC Address Setup:
  	 *	MAC Physical Address register. All bits in this register are
  	 *	restored to default values when the RST pin is asserted.
  	 */
  	for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++) {
  		WRITE_REG8(pLayerPointers, pMdl->Mem_Address + PADR + i,
  		    pMdl->Mac[i]);
  	}
  
  	/* Set RCV_RING_CFG */
  
  	if (JumboFlag == JUMBO_ENABLED) {
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD2,
  		    VAL0 | APAD_XMT | REX_RTRY | VAL1 | DXMTFCS | RPA | VAL2);
  
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD3,
  		    VAL2 | JUMBO);
  	} else {
  		/*
  		 * APAD_XMT: Auto Pad Transmit. When set, APAD_XMT enables
  		 * the automatic padding feature. Transmit frames are padded
  		 * to extend them to 64 bytes including FCS.
  		 *
  		 * DXMTFCS: Disable Transmit CRC. When DXMTFCS is set to 1, no
  		 * Transmit CRC is generated. DXMTFCS is overridden when
  		 * ADD_FCS and ENP bits are set in the transmit descriptor.
  		 *
  		 * ASTRIP_RCV: Auto Strip Receive. When ASTRP_RCV is set to 1,
  		 * the receiver automatically strips pad bytes from the
  		 * received message by observing the value in the length field
  		 * and by stripping excess bytes if this value is below the
  		 * minimum data size (46 bytes).
  		 */
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD2,
  		    VAL0 | APAD_XMT | REX_RTRY | REX_UFLO | VAL1 | DXMTFCS
  		    | ASTRIP_RCV | RPA | VAL2);
  	}
  
  	/* Transmit Start Point setting (csr80) */
  	ulData = READ_REG32(pLayerPointers, Mem_Address + CTRL1);
  	ulData &= ~XMTSP_MASK;
  
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CTRL1,
  	    ulData | XMTSP_128);
  	/* Disable Prom  */
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD2, PROM);
  
  	mdlPHYAutoNegotiation(pLayerPointers, pMdl->External_Phy);
  
  	pMdl->IpgValue = MIN_IPG_DEFAULT;
  	/* Set the IPG value */
  	WRITE_REG16(pLayerPointers, pMdl->Mem_Address + IFS,
  	    pMdl->IpgValue);
  
  	/* Disable Following Interrupts. */
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + INTEN0,
  	    APINT5EN | APINT4EN | APINT3EN |
  	    APINT2EN | APINT1EN | APINT0EN | MIIPDTINTEN |
  	    MCCIINTEN | MCCINTEN | MREINTEN |
  	    TINTEN0 |
  	    SPNDINTEN | MPINTEN | SINTEN | LCINTEN);
  
  	/* Enable Following Interrupt */
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + INTEN0,
  	    VAL0 | RINTEN0);
  
  	/* Base Address of Transmit Descriptor Ring 0. */
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + XMT_RING_BASE_ADDR0,
  	    pMdl->init_blk->TDRA);
  
  	/* Base Address of Receive Descriptor Ring. */
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + RCV_RING_BASE_ADDR0,
  	    pMdl->init_blk->RDRA);
  
  	/* The number of descriptors in Transmit Descriptor Ring 0 */
  	WRITE_REG16(pLayerPointers, pMdl->Mem_Address + XMT_RING_LEN0,
  	    (unsigned short)pLayerPointers->pMdl->TxRingSize);
  
  	/*
  	 * Receive Descriptor Ring Length. All bits in this register are
  	 * restored to default values when the RST pin is asserted.
  	 */
  	WRITE_REG16(pLayerPointers, pMdl->Mem_Address + RCV_RING_LEN0,
  	    (unsigned short)pLayerPointers->pMdl->RxRingSize);
  
  	if (pLayerPointers->pMdl->IntrCoalescFlag) {
  		SetIntrCoalesc(pLayerPointers, B_TRUE);
  	}
  
  	/* Start the chip */
  	mdlStartChip(pLayerPointers);
  }
  
  /*
   * Perform the open oerations on the adapter.
   */
  void
  mdlOpen(struct LayerPointers *pLayerPointers)
  {
  	int i, sum;
  	struct mdl *pMdl = pLayerPointers->pMdl;
  
  	/* Get Mac address */
  	sum = 0;
  	for (i = 0; i < 6; i++) {
  		pMdl->Mac[i] = READ_REG8(pLayerPointers,
  		    pMdl->Mem_Address + PADR + i);
  		sum += pMdl->Mac[i];
  	}
  	if (sum == 0) {
  		for (i = 0; i < 6; i++) {
  			pMdl->Mac[i] = 0;
  		}
  	}
  
  	/* Initialize the hardware */
  	mdlClearHWConfig(pLayerPointers);
  	mdlGetPHYID(pLayerPointers);
  
  }
  
  void
  mdlGetMacAddress(struct LayerPointers *pLayerPointers,
      unsigned char *macAddress)
  {
  	struct mdl *pMdl = pLayerPointers->pMdl;
  	int i;
  
  	for (i = 0; i < 6; i++) {
  		macAddress[i] =	pMdl->Mac[i] = READ_REG8(pLayerPointers,
  		    pMdl->Mem_Address + PADR + i);
  	}
  
  }
  
  
  void
  mdlSetMacAddress(struct LayerPointers *pLayerPointers,
      unsigned char *macAddress)
  {
  	int i;
  	struct mdl *pMdl = 0;
  
  	pMdl = (struct mdl *)(pLayerPointers->pMdl);
  
  	pMdl->Mac[0] = macAddress[0];
  	pMdl->Mac[1] = macAddress[1];
  	pMdl->Mac[2] = macAddress[2];
  	pMdl->Mac[3] = macAddress[3];
  	pMdl->Mac[4] = macAddress[4];
  	pMdl->Mac[5] = macAddress[5];
  
  	/*
  	 * MAC Address Setup:
  	 *	MAC Physical Address register. All bits in this register are
  	 *	restored to default values when the RST pin is asserted.
  	 */
  	for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++) {
  		WRITE_REG8(pLayerPointers, pMdl->Mem_Address + PADR + i,
  		    pMdl->Mac[i]);
  	}
  }
  
  /*
   * This array is filled with the size of the memory required for
   * allocating purposes.
   */
  static void
  mdlRequestResources(ULONG *mem_req_array)
  {
  	/* 1) For mdl structure */
  	*mem_req_array = VIRTUAL;		/* Type */
  	*(++mem_req_array) = sizeof (struct mdl); /* Size */
  
  	/* 2) For PMR PtrList array (PMR_ptrList) */
  	*(++mem_req_array) = VIRTUAL;		/* Type */
  	/* Size */
  	*(++mem_req_array) = sizeof (unsigned int) * (MAX_ALLOWED_PATTERNS + 2);
  
  	/* 3) For PMR Pattern List array (PatternList) */
  	*(++mem_req_array) = VIRTUAL;			/* Type */
  	/* Size */
  	*(++mem_req_array) = sizeof (unsigned char) * (MAX_PATTERNS + 2);
  
  	/* 4) For pmr PatternLength array (PatternLength) */
  	*(++mem_req_array) = VIRTUAL;			/* Type */
  	/* Size */
  	*(++mem_req_array) = sizeof (unsigned int) * (MAX_ALLOWED_PATTERNS + 2);
  
  	/*
  	 * 5) For the init_block (init_blk)
  	 */
  	*(++mem_req_array) = VIRTUAL;
  	*(++mem_req_array) = sizeof (struct init_block);
  
  	*(++mem_req_array) = 0;
  	mem_req_array++;
  }
  
  
  /*
   *	Purpose  :
   *		This array contains the details of the allocated memory. The
   *		pointers are taken from the respective locations in the array &
   *		assigned appropriately to the respective structures.
   *
   *	Arguments :
   *		pLayerPointers
   *			Pointer to the adapter structure.
   *		pmem_set_array
   *			Pointer to the array that holds the data after required
   *			allocating memory.
   */
  static void
  mdlSetResources(struct LayerPointers *pLayerPointers, ULONG *pmem_set_array)
  {
  	struct mdl *pMdl = 0;
  
  	/* 1) For mdl structure */
  	pmem_set_array++;	/* Type */
  	pmem_set_array++;	/* Size */
  	pLayerPointers->pMdl = (struct mdl *)(*pmem_set_array);
  
  	pMdl = (struct mdl *)(pLayerPointers->pMdl);
  
  	pMdl->RxRingLenBits = RX_RING_LEN_BITS;
  	pMdl->TxRingLenBits = TX_RING_LEN_BITS;
  	pMdl->TxRingSize = TX_RING_SIZE;
  	pMdl->RxRingSize = RX_RING_SIZE;
  
  	/*
  	 * Default values that would be used if it does not enable
  	 * enable dynamic ipg.
  	 */
  
  	/*  2) Set the pointers to the PMR Pointer List */
  	pmem_set_array++;	/* Type */
  	pmem_set_array++;	/* Size */
  	pmem_set_array++;	/* Virtual Addr of PtrList */
  	pMdl->PMR_PtrList = (unsigned int *)(*pmem_set_array);
  
  	/* 3) Set the pointers to the PMR Pattern List */
  	pmem_set_array++;	/* Type */
  	pmem_set_array++;	/* Size */
  	pmem_set_array++;	/* Virtual Addr of PatternList */
  	pMdl->PatternList = (unsigned char *)(*pmem_set_array);
  
  	/* 4) Set the pointers to the PMR Pattern Length */
  	pmem_set_array++;	/* Type */
  	pmem_set_array++;	/* Size */
  	pmem_set_array++;	/* Virtual Addr of PatternLength */
  	pMdl->PatternLength = (unsigned int *)(*pmem_set_array);
  
  	/* 5) Set the pointers to the init block */
  	pmem_set_array++;	/* Type  */
  	pmem_set_array++;	/* Size */
  	pmem_set_array++;	/* Virtual Addr of init_block */
  	pMdl->init_blk = (struct init_block *)(*pmem_set_array);
  
  	pMdl->init_blk->TLEN = pMdl->TxRingLenBits;
  	pMdl->init_blk->RLEN = pMdl->RxRingLenBits;
  
  	pmem_set_array++;
  
  	*pmem_set_array = 0;
  }
  
  /*
   *	Purpose:
   *		This array is filled with the size of the structure & its
   *		pointer for freeing purposes.
   *
   *	Arguments:
   *		pLayerPointers
   *			Pointer to the adapter structure.
   *		mem_free_array
   *			Pointer to the array that holds the data required for
   *			freeing.
   */
  static void
  mdlFreeResources(struct LayerPointers *pLayerPointers, ULONG *pmem_free_array)
  {
  	struct mdl *pMdl = 0;
  
  	pMdl = (struct mdl *)(pLayerPointers->pMdl);
  
  	/* 1) For mdl structure */
  	*(pmem_free_array) = VIRTUAL;		/* Type */
  	*(++pmem_free_array) = sizeof (struct mdl); /* Size */
  	*(++pmem_free_array) = (ULONG)pMdl;  /* VA */
  
  	/* 2) For ptr list */
  	*(++pmem_free_array) = VIRTUAL;		/* Type */
  	*(++pmem_free_array) =  sizeof (unsigned int)
  	    * (MAX_ALLOWED_PATTERNS + 2);  /* Size */
  	*(++pmem_free_array) = (ULONG)pMdl->PMR_PtrList;  /* VA */
  
  	/* 3) For pattern list */
  	*(++pmem_free_array) = VIRTUAL;		/* Type	 */
  	/* Size */
  	*(++pmem_free_array) =  sizeof (unsigned char) * (MAX_PATTERNS + 2);
  	*(++pmem_free_array) = (ULONG)pMdl->PatternList;  /* VA */
  
  	/* 4) For pattern length */
  	*(++pmem_free_array) = VIRTUAL;				/* Type */
  	*(++pmem_free_array) =  sizeof (unsigned int)
  	    * (MAX_ALLOWED_PATTERNS + 2);			/* Size */
  	*(++pmem_free_array) = (ULONG)pMdl->PatternLength;	/* VA */
  
  	/* 5) For init_blk structure */
  	*(++pmem_free_array) = VIRTUAL;				/* Type */
  	/* Size */
  	*(++pmem_free_array) = sizeof (struct init_block);
  	*(++pmem_free_array) = (ULONG)pMdl->init_blk;		/* VA */
  
  	*(++pmem_free_array) = 0;
  }
  
  void
  mdlStartChip(struct LayerPointers *pLayerPointers)
  {
  	/* Enable Receiver */
  	WRITE_REG32(pLayerPointers, pLayerPointers->pMdl->Mem_Address + CMD0,
  	    VAL2 | RDMD0);
  
  	/* Enable Interrupt and Start processing descriptor, Rx and Tx */
  	WRITE_REG32(pLayerPointers, pLayerPointers->pMdl->Mem_Address + CMD0,
  	    VAL0 | INTREN | RUN);
  }
  
  /*
   *	Stops the chip.
   */
  void
  mdlStopChip(struct LayerPointers *pLayerPointers)
  {
  	int nINT0;
  	struct mdl *pMdl = 0;
  
  	pMdl = (struct mdl *)(pLayerPointers->pMdl);
  
  	/* Disable interrupt */
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD0, INTREN);
  
  	/* Clear interrupt status */
  	nINT0 = READ_REG32(pLayerPointers, pMdl->Mem_Address + INT0);
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + INT0, nINT0);
  
  	/*
  	 * Setting the RUN bit enables the controller to start processing
  	 * descriptors and transmitting and  receiving packets. Clearing
  	 * the RUN bit to 0 abruptly disables the transmitter, receiver, and
  	 * descriptor processing logic, possibly while a frame is being
  	 * transmitted or received.
  	 * The act of changing the RUN bit from 1 to 0 causes the following
  	 * bits to be reset to 0: TX_SPND, RX_SPND, TX_FAST_SPND, RX_FAST_SPND,
  	 * RDMD, all TDMD bits, RINT, all TINT bits, MPINT, and SPNDINT.
  	 */
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD0, RUN);
  }
  
  /*
   *	Enables the interrupt.
   */
  void
  mdlEnableInterrupt(struct LayerPointers *pLayerPointers)
  {
  	/*
  	 * Interrupt Enable Bit:
  	 * This bit allows INTA to be asserted if any bit in the interrupt
  	 * register is set. If INTREN is cleared to 0, INTA will not be
  	 * asserted, regardless of the state of the interrupt register.
  	 */
  	WRITE_REG32(pLayerPointers, pLayerPointers->pMdl->Mem_Address + CMD0,
  	    VAL0 | INTREN);
  }
  
  #ifdef AMD8111S_DEBUG
  static void
  mdlClearInterrupt(struct LayerPointers *pLayerPointers)
  {
  	unsigned int nINT0;
  	struct mdl *pMdl = 0;
  
  	pMdl = (struct mdl *)(pLayerPointers->pMdl);
  
  	/* Clear interrupt status */
  	nINT0 = READ_REG32(pLayerPointers, pMdl->Mem_Address + INT0);
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + INT0, nINT0);
  
  }
  #endif
  
  /*
   *	Disables the interrupt.
   */
  void
  mdlDisableInterrupt(struct LayerPointers *pLayerPointers)
  {
  	/* Disable interrupt */
  	WRITE_REG32(pLayerPointers,
  	    pLayerPointers->pMdl->Mem_Address + CMD0, INTREN);
  }
  
  /*
   *	Reads the link status
   */
  int
  mdlReadLink(struct LayerPointers *pLayerPointers)
  {
  	unsigned int link_status = 0;
  
  	link_status = READ_REG32(pLayerPointers,
  	    pLayerPointers->pMdl->Mem_Address + STAT0);
  
  	if ((link_status & LINK_STAT)) {
  		return (LINK_UP);
  	} else {
  		return (LINK_DOWN);
  	}
  }
  
  /*
   *	Purpose  :
   *		Adds the wakeup pattern given by the upper layer.
   *
   *	Arguments :
   *		pLayerPointers
   *			Pointer to the Adapter structure.
   *		PatternMask
   *			The mask for the pattern to be added.
   *		Pattern
   *			The Pattern to be added.
   *		InfoBuffer_MaskSize
   *			The mask size as specified in the Information Buffer.
   *		PatternSize
   *			The PatternSize as specified in the Information Buffer.
   */
  static void
  mdlAddWakeUpPattern(struct LayerPointers *pLayerPointers,
      unsigned char *PatternMask, unsigned char *Pattern,
      unsigned long InfoBuffer_MaskSize, unsigned long PatternSize, int *retval)
  {
  	unsigned long MaskSize;
  	unsigned long ReqSize;
  	unsigned char byteData = 0, tmpData;
  	unsigned char Skip = 0;
  	unsigned int i = 0, flag = 1, count = 1;
  	unsigned int j;
  	int PatternOffset, SearchForStartOfPattern = 1;
  	struct mdl *pMdl = 0;
  
  	pMdl = pLayerPointers->pMdl;
  
  	if (pMdl->TotalPatterns >= MAX_ALLOWED_PATTERNS) {
  		*retval = -1;
  		return;
  	}
  
  	MaskSize = PatternSize/4 + (PatternSize%4 ? 1 : 0);
  
  	ReqSize = PatternSize + MaskSize;
  	if (((PatternSize+MaskSize)%5) != 0)
  		ReqSize +=  5 - ((PatternSize+MaskSize)%5);
  
  	if (ReqSize >
  	    (unsigned long)(MAX_PATTERNS - pMdl->PatternList_FreeIndex)) {
  		*retval = -1;
  		return;
  	}
  
  	if (InfoBuffer_MaskSize != PatternSize/8 + (PatternSize%8 ? 1 : 0)) {
  		*retval = -1;
  		return;
  	}
  
  	i = pMdl->PatternList_FreeIndex;
  
  	pMdl->PMR_PtrList[pMdl->TotalPatterns] = i;
  
  	pMdl->PatternLength[pMdl->TotalPatterns] = (unsigned int)PatternSize;
  
  	while (i < (pMdl->PatternList_FreeIndex + PatternSize + MaskSize)) {
  		if (flag) {
  			byteData = *PatternMask;
  			pMdl->PatternList[i++] =
  			    (unsigned int)((byteData & 0x0F) | (Skip<< 4));
  			flag = 0;
  		} else {
  			pMdl->PatternList[i++] = (unsigned int)
  			    (((unsigned)(byteData & 0xF0) >> 4) | (Skip << 4));
  			PatternMask++;
  			flag = 1;
  		}
  		count = 1;
  		while ((count < 5) && (i <
  		    pMdl->PatternList_FreeIndex + PatternSize + MaskSize)) {
  			tmpData = *Pattern;
  			Pattern++;
  			pMdl->PatternList[i++] = tmpData;
  			count++;
  		}
  	}
  
  	/* Filling up the extra byte blocks in the row to 0. */
  	for (i = (pMdl->PatternList_FreeIndex + PatternSize + MaskSize);
  	    i < (pMdl->PatternList_FreeIndex + ReqSize); i++)
  		pMdl->PatternList[i] = 0;
  
  	/* Set the EOP bit for the last mask!!! */
  	pMdl->PatternList[pMdl->PatternList_FreeIndex + ReqSize - 5] |= 0x80;
  
  	for (j = 0; j < 8; j++) {
  		pMdl->tmpPtrArray[j] = 0;
  	}
  
  	/* Zeroing the skip value of all the pattern masks */
  	j = 0;
  	while (j < (pMdl->PatternList_FreeIndex + ReqSize)) {
  		pMdl->PatternList[j] &= 0x8f;
  		j += 5;
  	}
  
  	/*
  	 * Scan the whole array & update the start offset of the pattern in the
  	 * PMR and update the skip value.
  	 */
  	j = 0;
  	i = 0;
  
  	PatternOffset = 1;
  	Skip = 0;
  
  	while (j < (pMdl->PatternList_FreeIndex + ReqSize)) {
  
  		if (pMdl->PatternList[j] & 0x0f) {
  			PatternOffset ++;
  			if (SearchForStartOfPattern == 1) {
  				SearchForStartOfPattern = 0;
  				pMdl->tmpPtrArray[i++] = PatternOffset;
  			} else if (pMdl->PatternList[j] & 0x80) {
  				SearchForStartOfPattern = 1;
  			}
  			pMdl->PatternList[j] |= (Skip << 4);
  			Skip = 0;
  		} else {
  			Skip++;
  		}
  		j += 5;
  	}
  
  	/* valid pattern.. so update the house keeping info. */
  	pMdl->PatternList_FreeIndex += (unsigned short)ReqSize;
  	pMdl->TotalPatterns++;
  
  	*retval = 0;
  }
  
  /*
   *	Purpose:
   *		Removes the specified wakeup pattern.
   *
   *	Arguments :
   *		pLayerPointers
   *			Pointer to the Adapter structure.
   *		Pattern
   *			The Pattern to be added.
   *		PatternSize
   *			The PatternSize as specified in the Information Buffer.
   */
  static void
  mdlRemoveWakeUpPattern(struct LayerPointers *pLayerPointers,
      unsigned char *Pattern, unsigned long PatternSize, int *retval)
  {
  	unsigned long ReqSize, MaskSize;
  	unsigned char tmpData;
  	unsigned long Data;
  	unsigned short Data1, Data2, Data3, Data4, Data5, Data6, Data7, Data8;
  	int PatternMismatch = 0;
  	int count, StartIndex, index = 0;
  	unsigned int i, j;
  	unsigned char Skip = 0;
  	struct mdl *pMdl = 0;
  	int PatternOffset, SearchForStartOfPattern = 1;
  	unsigned long tmpPtrArray[8];
  	int offset;
  
  	Data1 = Data2 = Data3 = Data4 = Data5 = Data6 = Data7 = Data8 = 0;
  
  	pMdl = (struct mdl *)(pLayerPointers->pMdl);
  
  	/* Find the pattern to be removed. */
  	if (pMdl->TotalPatterns == 0) {
  		*retval = -1;
  		return;
  	}
  
  	MaskSize = PatternSize/4 + (PatternSize%4 ? 1 : 0);
  
  	ReqSize = PatternSize + MaskSize;
  	if (((PatternSize+MaskSize)%5) != 0)
  		ReqSize +=  5 - ((PatternSize+MaskSize)%5);
  
  	count = pMdl->TotalPatterns;
  
  	while (count--) {
  		PatternMismatch = 0;
  		StartIndex = pMdl->PMR_PtrList[index];
  
  		if (pMdl->PatternLength[index] != PatternSize) {
  			index++;
  			PatternMismatch = 1;
  			continue;
  		}
  
  		for (i = StartIndex; i < (StartIndex+ReqSize); i++) {
  			if (!(i%5))
  				i++;
  
  			tmpData = *Pattern;
  			if (pMdl->PatternList[i] != tmpData) {
  				PatternMismatch = 1;
  				break;
  			}
  			Pattern++;
  		}
  
  		if (PatternMismatch == 0) {
  			i = StartIndex + ReqSize;
  
  			/* Pattern found remove it from the arrays */
  			while (i < pMdl->PatternList_FreeIndex) {
  				pMdl->PatternList[StartIndex] =
  				    pMdl->PatternList[i];
  				i++;
  				StartIndex++;
  			}
  
  			pMdl->PatternList_FreeIndex =
  			    (unsigned short)(StartIndex);
  
  			while (StartIndex < MAX_PATTERNS)
  				pMdl->PatternList[StartIndex++] = 0;
  
  			while (index < (int)pMdl->TotalPatterns) {
  				pMdl->PMR_PtrList[index] =
  				    pMdl->PMR_PtrList[index+1] - ReqSize;
  
  				pMdl->PatternLength[index] =
  				    pMdl->PatternLength[index+1];
  
  				index ++;
  			}
  
  			index--;
  			while (index < MAX_ALLOWED_PATTERNS) {
  				pMdl->PMR_PtrList[index+1] = 0;
  				pMdl->PatternLength[index+1] = 0;
  				index++;
  			}
  
  			break;
  		}
  		index++;
  	}
  
  	if (PatternMismatch) {
  		*retval = -1;
  		return;
  	}
  
  
  	for (j = 0; j < 8; j++) {
  		tmpPtrArray[j] = 0;
  	}
  
  	/* Zeroing the skip value of all the pattern masks */
  	j = 0;
  	while (j < (pMdl->PatternList_FreeIndex)) {
  		pMdl->PatternList[j] &= 0x8f;
  		j += 5;
  	}
  
  	/*
  	 * Scan the whole array & update the start offset of the pattern in the
  	 * PMR and update the skip value.
  	 */
  	j = 0;
  	i = 0;
  	Skip = 0;
  	PatternOffset = 1;
  
  	while (j < (pMdl->PatternList_FreeIndex)) {
  		if (pMdl->PatternList[j] & 0x0f) {
  
  			PatternOffset++;
  			if (SearchForStartOfPattern == 1) {
  				SearchForStartOfPattern = 0;
  				tmpPtrArray[i++] = PatternOffset;
  			} else if (pMdl->PatternList[j] & 0x80) {
  				SearchForStartOfPattern = 1;
  			}
  			pMdl->PatternList[j] |= (Skip << 4);
  			Skip = 0;
  		} else {
  			Skip++;
  		}
  		j += 5;
  	}
  
  
  	/* Write back the arrays to the PMR & lock the pmr */
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address+CMD7, PMAT_MODE);
  
  	/* Write the data & ctrl patterns from the array to the PMR */
  	i = 0;
  
  	offset = 2;
  
  	while (i < MAX_PATTERNS) {
  		if (pMdl->PatternList[i] != 0) {
  			Data = pMdl->PatternList[i+3] << 24 |
  			    pMdl->PatternList[i+2] << 16 |
  			    pMdl->PatternList[i+1] << 8  |
  			    pMdl->PatternList[i];
  
  			WRITE_REG32(pLayerPointers,
  			    pMdl->Mem_Address+PMAT1, Data);
  
  			Data = (unsigned long) ((1<<30) | (offset << 16) |
  			    pMdl->PatternList[i+4]);
  
  			WRITE_REG32(pLayerPointers,
  			    pMdl->Mem_Address+PMAT0, Data);
  
  			offset++;
  
  			if (offset >= 64) {
  				/* PMR is full !!!! */
  				*retval = -1;
  				return;
  
  			}
  		}
  		i += 5;
  	}
  
  	/* Valid pattern.. so update the house keeping info. */
  	pMdl->TotalPatterns--;
  
  	/* Update the pointer in the PMR */
  	pMdl->PatternEnableBit = 0;
  	for (i = 0; i < pMdl->TotalPatterns; i++) {
  		pMdl->PatternEnableBit |= (0x0001 << i);
  	}
  
  	Data1 = Data2 = Data3 = Data4 = Data5 = Data6 = Data7 = Data8 = 0;
  
  	switch (pMdl->TotalPatterns) {
  	case 8 :
  		Data8 = (unsigned short)tmpPtrArray[7];
  		/* FALLTHROUGH */
  	case 7 :
  		Data7 = (unsigned short)tmpPtrArray[6];
  		/* FALLTHROUGH */
  	case 6 :
  		Data6 = (unsigned short)tmpPtrArray[5];
  		/* FALLTHROUGH */
  	case 5 :
  		Data5 = (unsigned short)tmpPtrArray[4];
  		/* FALLTHROUGH */
  	case 4 :
  		Data4 = (unsigned short)tmpPtrArray[3];
  		/* FALLTHROUGH */
  	case 3 :
  		Data3 = (unsigned short)tmpPtrArray[2];
  		/* FALLTHROUGH */
  	case 2 :
  		Data2 = (unsigned short)tmpPtrArray[1];
  		/* FALLTHROUGH */
  	case 1 :
  		Data1 = (unsigned short)tmpPtrArray[0];
  		break;
  	}
  
  	Data = pMdl->PatternEnableBit & 0x0f;
  
  	/* Updating the pointers 1,2,3 & 4 */
  	Data = (Data3 << 24 |   Data2 << 16 |   Data1 << 8  |   Data);
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + PMAT1, Data);
  
  	Data = (unsigned long) ((1<<30) | Data4);
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + PMAT0, Data);
  
  	/* Updating the pointers 4,5,6 & 7 */
  	Data = (unsigned short)((unsigned)(pMdl->PatternEnableBit & 0xf0) >> 4);
  
  	Data = (Data7 << 24 |   Data6 << 16 |   Data5 << 8  |   Data);
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + PMAT1, Data);
  
  	Data = (unsigned long) ((1<<30) | (1<<16) | Data8);
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + PMAT0, Data);
  
  	/* Unlock the PMR */
  	WRITE_REG32(pLayerPointers, pMdl->Mem_Address + CMD7, VAL0 | PMAT_MODE);
  
  	*retval = 0;
  }
  
  
  /*
   *	Checks the control register for the speed and the type of the
   *	network connection.
   */
  void
  mdlGetActiveMediaInfo(struct LayerPointers *pLayerPointers)
  {
  
  	unsigned long  ulData;
  	struct mdl *pMdl = 0;
  
  	pMdl = (struct mdl *)(pLayerPointers->pMdl);
  
  	ulData = READ_REG32(pLayerPointers, pMdl->Mem_Address + STAT0);
  
  	switch (ulData & SPEED_MASK) {
  	case SPEED_100Mbps:
  		pMdl->Speed = 100;
  		break;
  	case SPEED_10Mbps:
  		pMdl->Speed = 10;
  		break;
  	default:
  		pMdl->Speed = 100;
  		break;
  	}
  
  	if (ulData & FULL_DPLX) {
  		pMdl->FullDuplex = B_TRUE;
  	} else {
  		pMdl->FullDuplex = B_FALSE;
  	}
  }
  
  void
  mdlChangeFilter(struct LayerPointers *pLayerPointers, unsigned long  *ArrayPtr)
  {
  	unsigned long *Ptr;
  	unsigned char *MulticastArray;
  	unsigned char *Pattern, *PatternMask;
  	unsigned int InfoBuffer_MaskSize, PatternSize;
  	int *retval;
  	int NumberOfAddress, i;
  	unsigned int j, CRCValue = 0;
  	unsigned char HashCode = 0, FilterByte = 0;
  	int BitMapIndex = 0;
  
  	Ptr = ArrayPtr;
  
  	while (*Ptr) {
  		switch (*Ptr) {
  		case DISABLE_BROADCAST:
  			mdlDisableReceiveBroadCast(pLayerPointers);
  			break;
  
  		case ENABLE_BROADCAST:
  			mdlReceiveBroadCast(pLayerPointers);
  			break;
  
  		case ENABLE_ALL_MULTICAST:
  			for (i = 0; i < 8; i++) {
  				pLayerPointers->pMdl->init_blk->LADRF[i] = 0xff;
  			}
  			WRITE_REG64(pLayerPointers,
  			    (unsigned long)pLayerPointers->pMdl
  			    ->Mem_Address + LADRF1,
  			    (char *)pLayerPointers->pMdl->init_blk->LADRF);
  			break;
  
  		case DISABLE_ALL_MULTICAST:
  			if (pLayerPointers->pMdl->EnableMulticast == 1) {
  				for (i = 0; i < 8; i++) {
  					pLayerPointers->pMdl->init_blk
  					    ->LADRF[i] =
  					    pLayerPointers->pMdl->TempLADRF[i];
  				}
  			}
  
  			WRITE_REG64(pLayerPointers,
  			    (unsigned long)pLayerPointers->pMdl->Mem_Address
  			    + LADRF1,
  			    (char *)pLayerPointers->pMdl->init_blk->LADRF);
  			break;
  
  
  		case ADD_MULTICAST:
  			NumberOfAddress = *(++Ptr);
  			MulticastArray = (unsigned char *)(*(++Ptr));
  			mdlAddMulticastAddresses(pLayerPointers,
  			    NumberOfAddress, MulticastArray);
  			break;
  
  
  		case ENABLE_MULTICAST:
  			for (i = 0; i < 8; i++) {
  				pLayerPointers->pMdl->init_blk->LADRF[i]  =
  				    pLayerPointers->pMdl->TempLADRF[i];
  			}
  			pLayerPointers->pMdl->EnableMulticast = 1;
  
  			WRITE_REG64(pLayerPointers,
  			    (unsigned long)pLayerPointers->pMdl->Mem_Address
  			    + LADRF1,
  			    (char *)pLayerPointers->pMdl->init_blk->LADRF);
  			break;
  
  		case DISABLE_MULTICAST:
  			for (i = 0; i < 8; i++) {
  				pLayerPointers->pMdl->init_blk->LADRF[i] = 0;
  			}
  
  			pLayerPointers->pMdl->EnableMulticast = 0;
  
  			for (BitMapIndex = 0; BitMapIndex <
  			    MULTICAST_BITMAP_ARRAY_SIZE; BitMapIndex++)
  				pLayerPointers->pMdl->MulticastBitMapArray
  				    [BitMapIndex] = 0;
  			WRITE_REG64(pLayerPointers,
  			    (unsigned long)pLayerPointers->pMdl->Mem_Address
  			    + LADRF1,
  			    (char *)pLayerPointers->pMdl->init_blk->LADRF);
  			break;
  
  
  		case ADD_WAKE_UP_PATTERN:
  			PatternMask = (unsigned char *)(*(++Ptr));
  			Pattern = (unsigned char *)(*(++Ptr));
  			InfoBuffer_MaskSize = (*(++Ptr));
  			PatternSize = (*(++Ptr));
  			retval = (int *)(*(++Ptr));
  
  			mdlAddWakeUpPattern(pLayerPointers,
  			    PatternMask,
  			    Pattern,
  			    InfoBuffer_MaskSize,
  			    PatternSize,
  			    retval);
  			break;
  
  		case REMOVE_WAKE_UP_PATTERN:
  			Pattern = (unsigned char *)(*(++Ptr));
  			PatternSize = *(++Ptr);
  			retval = (int *)(*(++Ptr));
  			mdlRemoveWakeUpPattern(pLayerPointers,
  			    Pattern,
  			    PatternSize,
  			    retval);
  			break;
  
  		case ENABLE_MAGIC_PACKET_WAKE_UP:
  			mdlEnableMagicPacketWakeUp(pLayerPointers);
  			break;
  
  		case SET_SINGLE_MULTICAST:
  			NumberOfAddress = *(++Ptr);
  			MulticastArray = (unsigned char *)(*(++Ptr));
  
  			for (i = 0; i < 8; i++) {
  				pLayerPointers->pMdl->TempLADRF[i] =
  				    pLayerPointers->pMdl->init_blk->LADRF[i];
  			}
  			CRCValue = mdlCalculateCRC(ETH_LENGTH_OF_ADDRESS,
  			    MulticastArray);
  			for (j = 0; j < 6; j++) {
  				HashCode = (HashCode << 1) +
  				    (((unsigned char)CRCValue >> j) & 0x01);
  			}
  			/*
  			 * Bits 3-5 of HashCode point to byte in address
  			 * filter.
  			 * Bits 0-2 point to bit within that byte.
  			 */
  			FilterByte = HashCode >> 3;
  			pLayerPointers->pMdl->TempLADRF[FilterByte] |=
  			    (1 << (HashCode & 0x07));
  			break;
  
  		case UNSET_SINGLE_MULTICAST:
  			NumberOfAddress = *(++Ptr);
  			MulticastArray = (unsigned char *)(*(++Ptr));
  			for (i = 0; i < 8; i++) {
  				pLayerPointers->pMdl->TempLADRF[i] =
  				    pLayerPointers->pMdl->init_blk->LADRF[i];
  			}
  			CRCValue = mdlCalculateCRC(ETH_LENGTH_OF_ADDRESS,
  			    MulticastArray);
  			for (j = 0; j < 6; j++) {
  				HashCode = ((HashCode << 1) +
  				    (((unsigned char)CRCValue >> j) & 0x01));
  			}
  
  			/*
  			 * Bits 3-5 of HashCode point to byte in address
  			 * filter.
  			 * Bits 0-2 point to bit within that byte.
  			 */
  			FilterByte = HashCode >> 3;
  			pLayerPointers->pMdl->TempLADRF[FilterByte] &=
  			    ~(1 << (HashCode & 0x07));
  			break;
  
  		default:
  			break;
  		}
  		Ptr++;
  	}
  }
  
  
  void
  mdlAddMulticastAddresses(struct LayerPointers *pLayerPointers,
      int NumberOfAddress, unsigned char *MulticastAddresses)
  {
  	unsigned int j, CRCValue;
  	unsigned char HashCode, FilterByte;
  	int i;
  
  	for (i = 0; i < 8; i++) {
  		pLayerPointers->pMdl->TempLADRF[i]  = 0x00;
  	}
  
  
  	for (i = 0; i < NumberOfAddress; i++) {
  		HashCode = 0;
  
  		/* Calculate CRC value */
  		CRCValue = mdlCalculateCRC(ETH_LENGTH_OF_ADDRESS,
  		    MulticastAddresses);
  
  		for (j = 0; j < 6; j++) {
  			HashCode = (HashCode << 1) +
  			    (((unsigned char)CRCValue >> j) & 0x01);
  		}
  
  		/* Bits 3-5 of HashCode point to byte in address filter. */
  		/* Bits 0-2 point to bit within that byte. */
  		FilterByte = HashCode >> 3;
  		pLayerPointers->pMdl->TempLADRF[FilterByte] |=
  		    (1 << (HashCode & 0x07));
  		MulticastAddresses += ETH_LENGTH_OF_ADDRESS;
  	}
  }
  
  /* Receive all packets  */
  void
  mdlSetPromiscuous(struct LayerPointers *pLayerPointers)
  {
  	/*
  	 * Writable N == Can Be Written only when device is not running
  	 * (RUN == 0)
  	 */
  	WRITE_REG32(pLayerPointers, pLayerPointers->pMdl->Mem_Address + CMD2,
  	    VAL2 | PROM);
  	pLayerPointers->pMdl->FLAGS |= PROM;	/* B16_MASK */
  }
  
  /* Stop Receiving all packets  */
  void
  mdlDisablePromiscuous(struct LayerPointers *pLayerPointers)
  {
  	/*
  	 * Writable N == Can Be Written only when device is not running
  	 * (RUN == 0)
  	 */
  	WRITE_REG32(pLayerPointers, pLayerPointers->pMdl->Mem_Address + CMD2,
  	    PROM);
  	pLayerPointers->pMdl->FLAGS &= (~ PROM); /* B16_MASK */
  }
  
  /*
   * Disable Receive Broadcast. When set, disables the controller from receiving
   * broadcast messages. Used for protocols that do not support broadcast
   * addressing, except as a function of multicast.
   * DRCVBC is cleared by activation of H_RESET (broadcast messages will be
   * received) and is unaffected by the clearing of the RUN bit.
   */
  static void
  mdlReceiveBroadCast(struct LayerPointers *pLayerPointers)
  {
  	ULONG MappedMemBaseAddress;
  
  	MappedMemBaseAddress = pLayerPointers->pMdl->Mem_Address;
  	WRITE_REG32(pLayerPointers, MappedMemBaseAddress + CMD2, DRCVBC);
  	pLayerPointers->pMdl->FLAGS |= DRCVBC;
  }
  
  static void
  mdlDisableReceiveBroadCast(struct LayerPointers *pLayerPointers)
  {
  	ULONG MappedMemBaseAddress;
  
  	MappedMemBaseAddress = pLayerPointers->pMdl->Mem_Address;
  	WRITE_REG32(pLayerPointers, MappedMemBaseAddress + CMD2, VAL2 | DRCVBC);
  	pLayerPointers->pMdl->FLAGS &= (~DRCVBC);
  }
  
  static void
  mdlEnableMagicPacketWakeUp(struct LayerPointers *pLayerPointers)
  {
  	WRITE_REG32(pLayerPointers, pLayerPointers->pMdl->Mem_Address + CMD3,
  	    VAL1 | MPPLBA);
  	WRITE_REG32(pLayerPointers, pLayerPointers->pMdl->Mem_Address + CMD7,
  	    VAL0 | MPEN_SW);
  }
  
  /*
   * BitMap for add/del the Multicast address Since more than one M/C address
   * can map to same bit in the filter matrix, we should maintain the count for
   * # of M/C addresses associated with each bit. Only when the bit<->count
   * becomes zero, we should go ahead with changing/reseting the bit, else just
   * reduce the count associated with each bit and return.
   */
  static int
  mdlMulticastBitMapping(struct LayerPointers *pLayerPointers,
      unsigned char *MulticastAddress, int FLAG)
  {
  	unsigned char HashCode, FilterByte;
  	int j = 0, BitMapIndex = 0;
  	unsigned int CRCValue = 0;
  
  	HashCode = 0;
  	/* Calculate the Bit Map location for the given Address */
  	CRCValue = mdlCalculateCRC(ETH_LENGTH_OF_ADDRESS, MulticastAddress);
  	for (j = 0; j < 6; j++) {
  		HashCode = (HashCode << 1) +
  		    (((unsigned char)CRCValue >> j) & 0x01);
  	}
  
  	/*
  	 * Bits 3-5 of HashCode point to byte in address filter.
  	 * Bits 0-2 point to bit within that byte.
  	 */
  	FilterByte = HashCode & 0x38;
  	FilterByte = FilterByte >> 3;
  	BitMapIndex =  (int)FilterByte * 8 + (HashCode & 0x7);
  
  	if (FLAG == DELETE_MULTICAST) {
  		if ((pLayerPointers->pMdl->MulticastBitMapArray[BitMapIndex]
  		    == 0) || (--pLayerPointers->pMdl->MulticastBitMapArray
  		    [BitMapIndex] == 0)) {
  			return (0);
  		} else {
  			return (-1);
  		}
  	}
  
  	if (FLAG == ADD_MULTICAST) {
  		if (pLayerPointers->pMdl
  		    ->MulticastBitMapArray[BitMapIndex] > 0) {
  			pLayerPointers->pMdl
  			    ->MulticastBitMapArray[BitMapIndex]++;
  			return (-1);
  		} else if (pLayerPointers->pMdl
  		    ->MulticastBitMapArray[BitMapIndex] == 0) {
  			pLayerPointers->pMdl
  			    ->MulticastBitMapArray[BitMapIndex]++;
  			return (0);
  		}
  	}
  	return (0);
  }
  
  /*
   * Set Interrupt Coalescing registers:
   *	To reduce the host CPU interrupt service overhead the network
   *	controller can be programmed to postpone the interrupt to the host
   *	CPU until either a programmable number of receive or transmit
   *	interrupt events have occurred or a programmable amount of time has
   *	elapsed since the first interrupt event occurred.
   */
  void
  SetIntrCoalesc(struct LayerPointers *pLayerPointers, boolean_t on)
  {
  	long MemBaseAddress = pLayerPointers->pMdl->Mem_Address;
  	struct mdl *pMdl = 0;
  	unsigned int timeout, event_count;
  
  	pMdl = (struct mdl *)(pLayerPointers->pMdl);
  
  	if (on) {
  		/* Set Rx Interrupt Coalescing */
  		timeout = pLayerPointers->pMdl->rx_intrcoalesc_time;
  		event_count = 0;
  		event_count |= pLayerPointers->pMdl->rx_intrcoalesc_events;
  		if (timeout > 0x7ff) {
  			timeout = 0x7ff;
  		}
  		if (event_count > 0x1f) {
  			event_count = 0x1f;
  		}
  
  		event_count =  event_count << 16;
  		WRITE_REG32(pLayerPointers, MemBaseAddress + DLY_INT_A,
  		    DLY_INT_A_R0 | event_count | timeout);
  
  	} else {
  		/* Disable Software Timer Interrupt */
  		WRITE_REG32(pLayerPointers, MemBaseAddress + STVAL, 0);
  		WRITE_REG32(pLayerPointers, pMdl->Mem_Address + INTEN0,
  		    STINTEN);
  
  		WRITE_REG32(pLayerPointers, MemBaseAddress + DLY_INT_A, 0);
  		WRITE_REG32(pLayerPointers, MemBaseAddress + DLY_INT_B, 0);
  	}
  }
  
  void
  mdlSendPause(struct LayerPointers *pLayerPointers)
  {
  	WRITE_REG32(pLayerPointers, pLayerPointers->pMdl->Mem_Address
  	    + FLOW_CONTROL, VAL2 | FIXP | FCCMD | 0x200);
  }
  
  /* Reset all Tx descriptors and Tx buffers */
  void
  milResetTxQ(struct LayerPointers *pLayerPointers)
  {
  	struct nonphysical *pNonphysical = pLayerPointers->pMil->pNonphysical;
  	int i;
  
  	pNonphysical->TxDescQRead = pNonphysical->TxDescQStart;
  	pNonphysical->TxDescQWrite = pNonphysical->TxDescQStart;
  
  	/* Clean all Tx descriptors */
  	for (i = 0; i < TX_RING_SIZE; i++) {
  		pNonphysical->TxDescQWrite->Tx_OWN = 0;
  		pNonphysical->TxDescQWrite->Tx_SOP = 0;
  		pNonphysical->TxDescQWrite->Tx_EOP = 0;
  		pNonphysical->TxDescQWrite++;
  	}
  	pNonphysical->TxDescQWrite = pNonphysical->TxDescQStart;
  
  	/* Re-init Tx Buffers */
  	pLayerPointers->pOdl->tx_buf.free =
  	    pLayerPointers->pOdl->tx_buf.msg_buf;
  	pLayerPointers->pOdl->tx_buf.next =
  	    pLayerPointers->pOdl->tx_buf.msg_buf;
  	pLayerPointers->pOdl->tx_buf.curr =
  	    pLayerPointers->pOdl->tx_buf.msg_buf;
  }
  
  /*
   *	Initialises the data used in Mil.
   */
  void
  milInitGlbds(struct LayerPointers *pLayerPointers)
  {
  	pLayerPointers->pMil->name = DEVICE_CHIPNAME;
  
  	mdlInitGlbds(pLayerPointers);
  }
  
  /*
   *	Purpose  :
   *		Initialises the RxBufDescQ with the packet pointer and physical
   *		address filled in the FreeQ.
   *
   *	Arguments :
   *		pLayerPointers
   *			Pointer to the Adapter structure.
   */
  void
  milInitRxQ(struct LayerPointers *pLayerPointers)
  {
  	struct mil *pMil = pLayerPointers->pMil;
  	struct nonphysical *pNonphysical = pMil->pNonphysical;
  	int i;
  
  	pNonphysical->RxBufDescQRead->descriptor = pMil->Rx_desc;
  	pNonphysical->RxBufDescQStart->descriptor = pMil->Rx_desc;
  	pNonphysical->RxBufDescQEnd->descriptor =
  	    &(pMil->Rx_desc[pMil->RxRingSize - 1]);
  
  	pNonphysical->RxBufDescQRead->USpaceMap = pMil->USpaceMapArray;
  	pNonphysical->RxBufDescQStart->USpaceMap = pMil->USpaceMapArray;
  	pNonphysical->RxBufDescQEnd->USpaceMap =
  	    &(pMil->USpaceMapArray[pMil->RxRingSize - 1]);
  
  	/* Initialize the adapter rx descriptor Q and rx buffer Q */
  	for (i = 0; i < pMil->RxRingSize; i++) {
  		pNonphysical->RxBufDescQRead->descriptor->Rx_BCNT
  		    = (unsigned)pMil->RxBufSize;
  
  		*(pNonphysical->RxBufDescQRead->USpaceMap) =
  		    (long)(pLayerPointers->pOdl->rx_buf.next->vir_addr);
  
  		pNonphysical->RxBufDescQRead->descriptor->Rx_Base_Addr
  		    = pLayerPointers->pOdl->rx_buf.next->phy_addr;
  
  		pNonphysical->RxBufDescQRead->descriptor->Rx_OWN = 1;
  		pNonphysical->RxBufDescQRead->descriptor++;
  		pNonphysical->RxBufDescQRead->USpaceMap++;
  		pLayerPointers->pOdl->rx_buf.next =
  		    NEXT(pLayerPointers->pOdl->rx_buf, next);
  	}
  
  	pNonphysical->RxBufDescQRead->descriptor =
  	    pNonphysical->RxBufDescQStart->descriptor;
  	pNonphysical->RxBufDescQRead->USpaceMap =
  	    pNonphysical->RxBufDescQStart->USpaceMap;
  	pLayerPointers->pOdl->rx_buf.next =
  	    pLayerPointers->pOdl->rx_buf.msg_buf;
  }
  
  /*
   *	Purpose		:
   *		This array is filled with the size of the structure & its
   *		pointer for freeing purposes.
   *
   *	Arguments	:
   *		pLayerPointers
   *			Pointer to the adapter structure.
   *		mem_free_array
   *			Pointer to the array that holds the data required
   *			for freeing.
   */
  void
  milFreeResources(struct LayerPointers *pLayerPointers, ULONG *mem_free_array)
  {
  	/* 1) For mil structure (pLayerPointers->pMil) */
  	/* Type */
  	*(mem_free_array) = VIRTUAL;
  	/* Size */
  	*(++mem_free_array) = sizeof (struct mil);
  	/* VA */
  	*(++mem_free_array) = (ULONG)pLayerPointers->pMil;
  
  
  	/* 2) For USpaceMapArray queue */
  	/* Type */
  	*(++mem_free_array) = VIRTUAL;
  	/* Size */
  	*(++mem_free_array) = pLayerPointers->pMil->RxRingSize *
  	    sizeof (unsigned long);
  	/* VA */
  	*(++mem_free_array) = (ULONG)pLayerPointers->pMil->USpaceMapArray;
  
  
  	/* 3) For non_physical structure */
  	/* Type */
  	*(++mem_free_array) = VIRTUAL;
  	/* Size */
  	*(++mem_free_array) =  sizeof (struct nonphysical);
  	/* VA */
  	*(++mem_free_array) = (ULONG)pLayerPointers->pMil->pNonphysical;
  
  	/*
  	 * 4~6) For four allocation are for abstracting the Rx_Descritor ring
  	 */
  
  	/* 4) Type */
  	*(++mem_free_array) = VIRTUAL;
  	/* Size */
  	*(++mem_free_array) =  sizeof (struct Rx_Buf_Desc);
  	/* VA */
  	*(++mem_free_array) =
  	    (ULONG)pLayerPointers->pMil->pNonphysical->RxBufDescQRead;
  
  	/* 5) Type */
  	*(++mem_free_array) = VIRTUAL;
  	/* Size */
  	*(++mem_free_array) =  sizeof (struct Rx_Buf_Desc);
  	/* VA */
  	*(++mem_free_array) =
  	    (ULONG)pLayerPointers->pMil->pNonphysical->RxBufDescQStart;
  
  	/* 6) Type */
  	*(++mem_free_array) = VIRTUAL;
  	/* Size */
  	*(++mem_free_array) =  sizeof (struct Rx_Buf_Desc);
  	/* VA */
  	*(++mem_free_array) =
  	    (ULONG)pLayerPointers->pMil->pNonphysical->RxBufDescQEnd;
  
  	*(++mem_free_array) = 0;
  
  	mdlFreeResources(pLayerPointers, mem_free_array);
  }
  
  
  
  /*
   *	Purpose  :
   *		This array is filled with the size of the memory required for
   *		allocating purposes.
   *
   *	Arguments :
   *		pLayerPointers
   *			Pointer to the adapter structure.
   *		mem_req_array
   *			Pointer to the array that holds the data required for
   *			allocating memory.
   */
  void
  milRequestResources(ULONG *mem_req_array)
  {
  	int RxRingSize;
  
  	RxRingSize = RX_RING_SIZE;	/* 128 */
  
  	/* 1) For mil structure (pLayerPointers->pMil) */
  	/* Type */
  	*mem_req_array   = VIRTUAL;
  	/* Size */
  	*(++mem_req_array) = sizeof (struct mil);
  
  	/* 2) For USpaceMapArray queue (pLayerPointers->pMil->USpaceMapArray) */
  	/* Type */
  	*(++mem_req_array) = VIRTUAL;
  	/* Size */
  	*(++mem_req_array) = RxRingSize * sizeof (unsigned long);
  
  
  	/* 3) For pNonphysical structure */
  	/* Type */
  	*(++mem_req_array) = VIRTUAL;
  	/* Size */
  	*(++mem_req_array) = sizeof (struct nonphysical);
  
  	/*
  	 * 4~6) For four allocation are for abstracting the Rx_Descritor ring
  	 */
  	/* 4) Type */
  	*(++mem_req_array) = VIRTUAL;
  	/* Size */
  	*(++mem_req_array) = sizeof (struct Rx_Buf_Desc);
  
  	/* 5) Type */
  	*(++mem_req_array) = VIRTUAL;
  	/* Size */
  	*(++mem_req_array) = sizeof (struct Rx_Buf_Desc);
  
  	/* 6) Type */
  	*(++mem_req_array) = VIRTUAL;
  	/* Size */
  	*(++mem_req_array) = sizeof (struct Rx_Buf_Desc);
  
  	*(++mem_req_array) = 0;
  
  	mdlRequestResources(mem_req_array);
  }
  
  
  
  /*
   *	Purpose  :
   *		This array contains the details of the allocated memory. The
   *		pointers are taken from the respective locations in the array
   *		& assigne appropriately to the respective structures.
   *
   *	Arguments :
   *		pLayerPointers
   *			Pointer to the adapter structure.
   *		pmem_set_array
   *			Pointer to the array that holds the data after required
   *			allocating memory.
   */
  void
  milSetResources(struct LayerPointers *pLayerPointers, ULONG *pmem_set_array)
  {
  	int RxRingSize, TxRingSize;
  	int RxBufSize;
  	struct mil *pMil;
  
  	RxRingSize = RX_RING_SIZE;
  	TxRingSize = TX_RING_SIZE;
  	RxBufSize = RX_BUF_SIZE;
  
  	/* 1) Set the pointers to the mil pointers */
  	/* Type */
  	pmem_set_array++;
  	/* Size */
  	pmem_set_array++;
  	pMil = (struct mil *)(*pmem_set_array);
  	pLayerPointers->pMil = pMil;
  
  	pMil->RxRingSize = RxRingSize;
  	pMil->TxRingSize = TxRingSize;
  	pMil->RxBufSize = RxBufSize;
  
  	/* 2) Type */
  	pmem_set_array++;
  	/* Size */
  	pmem_set_array++;
  	pmem_set_array++;
  	pMil->USpaceMapArray = (long *)(*pmem_set_array);
  
  	/* 3) Set the pointers to the NonPhysical part */
  	/* Type */
  	pmem_set_array++;
  	/* Size */
  	pmem_set_array++;
  	/* Virtual Addr of NonPhysical */
  	pmem_set_array++;
  	pMil->pNonphysical =
  	    (struct nonphysical *)(*pmem_set_array);
  
  	/*
  	 * 4~6) Following four allocation are for abstracting the Rx_Descritor
  	 * Ring.
  	 */
  	/* 4) Type */
  	pmem_set_array++;
  	/* Size */
  	pmem_set_array++;
  	/* Virtual Addr of Abstracted RxDesc */
  	pmem_set_array++;
  	pMil->pNonphysical->RxBufDescQRead =
  	    (struct Rx_Buf_Desc *)(*pmem_set_array);
  
  	/* 5) Type */
  	pmem_set_array++;
  	/* Size */
  	pmem_set_array++;
  	/* Virtual Addr of Abstracted RxDesc */
  	pmem_set_array++;
  	pMil->pNonphysical->RxBufDescQStart =
  	    (struct Rx_Buf_Desc *)(*pmem_set_array);
  
  	/* 6) Type */
  	pmem_set_array++;
  	/* Size */
  	pmem_set_array++;
  	/* Virtual Addr of Abstracted RxDesc */
  	pmem_set_array++;
  	pMil->pNonphysical->RxBufDescQEnd =
  	    (struct Rx_Buf_Desc *)(*pmem_set_array);
  
  	pmem_set_array++;
  
  	mdlSetResources(pLayerPointers, pmem_set_array);
  }
  
  /*
   *	Purpose  :
   *		This routine adds the Multicast addresses to the filter
   *
   *	Arguments :
   *		pLayerPointers
   *			Pointer to Layer pointers structure.
   *		pucMulticastAddress
   *			Pointer to the array of multicast addresses
   */
  void
  mdlAddMulticastAddress(struct LayerPointers *pLayerPointers,
      UCHAR *pucMulticastAddress)
  {
  	unsigned long MODE[10];
  	unsigned long tmp1;
  	unsigned long tmp2;
  
  	if (mdlMulticastBitMapping(pLayerPointers, pucMulticastAddress,
  	    ADD_MULTICAST) != 0)
  		return;
  
  	tmp2 = SET_SINGLE_MULTICAST;
  	MODE[0] = (unsigned long)tmp2;
  	MODE[1] = 1;
  	tmp1 = (unsigned long)pucMulticastAddress;
  	MODE[2] = tmp1;
  	MODE[3] = ENABLE_MULTICAST;
  	MODE[4] = 0;
  	mdlChangeFilter(pLayerPointers, (unsigned long *)MODE);
  }
  
  
  /*
   *	Purpose  :
   *		This routine deletes the Multicast addresses requested by OS.
   *
   *	Arguments :
   *		pLayerPointers
   *			Pointer to Layer pointers structure.
   *		pucMulticastAddress
   *			Pointer to the array of multicast addresses
   */
  void
  mdlDeleteMulticastAddress(struct LayerPointers *pLayerPointers,
      UCHAR *pucMulticastAddress)
  {
  	unsigned long MODE[10];
  	unsigned long tmp;
  
  	if (mdlMulticastBitMapping(pLayerPointers, pucMulticastAddress,
  	    DELETE_MULTICAST) != 0)
  		return;
  
  	MODE[0] = UNSET_SINGLE_MULTICAST;
  	MODE[1] = 1;
  	tmp = (unsigned long)pucMulticastAddress;
  	MODE[2] = tmp;
  	MODE[3] = ENABLE_MULTICAST;
  	MODE[4] = 0;
  	mdlChangeFilter(pLayerPointers, (unsigned long *)MODE);
  }
  
  /*
   *	Purpose  :
   *		Calculates the CRC value over the input number of bytes.
   *
   *	Arguments :
   *		NumberOfBytes
   *			The number of bytes in the input.
   *		Input
   *			An input "string" to calculate a CRC over.
   */
  static unsigned int
  mdlCalculateCRC(unsigned int NumberOfBytes, unsigned char *Input)
  {
  	const unsigned int POLY = 0x04c11db7;
  	unsigned int CRCValue = 0xffffffff;
  	unsigned int CurrentBit, CurrentCRCHigh;
  	unsigned char CurrentByte;
  
  	for (; NumberOfBytes; NumberOfBytes--) {
  		CurrentByte = *Input;
  		Input++;
  
  		for (CurrentBit = 8; CurrentBit; CurrentBit--) {
  			CurrentCRCHigh = CRCValue >> 31;
  			CRCValue <<= 1;
  
  			if (CurrentCRCHigh ^ (CurrentByte & 0x01)) {
  				CRCValue ^= POLY;
  				CRCValue |= 0x00000001;
  			}
  			CurrentByte >>= 1;
  		}
  	}
  	return (CRCValue);
  }
  
  void
  mdlRxFastSuspend(struct LayerPointers *pLayerPointers)
  {
  	WRITE_REG32(pLayerPointers, pLayerPointers->pMdl->Mem_Address + CMD0,
  	    VAL0 | RX_FAST_SPND);
  }
  
  void
  mdlRxFastSuspendClear(struct LayerPointers *pLayerPointers)
  {
  	WRITE_REG32(pLayerPointers, pLayerPointers->pMdl->Mem_Address + CMD0,
  	    RX_FAST_SPND);
  }
  