1*1b8adde7SWilliam Kucharski /* -*- Mode:C; c-basic-offset:4; -*- */ 2*1b8adde7SWilliam Kucharski 3*1b8adde7SWilliam Kucharski /* 4*1b8adde7SWilliam Kucharski natsemi.c: An Etherboot driver for the NatSemi DP8381x series. 5*1b8adde7SWilliam Kucharski 6*1b8adde7SWilliam Kucharski Copyright (C) 2001 Entity Cyber, Inc. 7*1b8adde7SWilliam Kucharski 8*1b8adde7SWilliam Kucharski This development of this Etherboot driver was funded by 9*1b8adde7SWilliam Kucharski 10*1b8adde7SWilliam Kucharski Sicom Systems: http://www.sicompos.com/ 11*1b8adde7SWilliam Kucharski 12*1b8adde7SWilliam Kucharski Author: Marty Connor (mdc@thinguin.org) 13*1b8adde7SWilliam Kucharski Adapted from a Linux driver which was written by Donald Becker 14*1b8adde7SWilliam Kucharski 15*1b8adde7SWilliam Kucharski This software may be used and distributed according to the terms 16*1b8adde7SWilliam Kucharski of the GNU Public License (GPL), incorporated herein by reference. 17*1b8adde7SWilliam Kucharski 18*1b8adde7SWilliam Kucharski Original Copyright Notice: 19*1b8adde7SWilliam Kucharski 20*1b8adde7SWilliam Kucharski Written/copyright 1999-2001 by Donald Becker. 21*1b8adde7SWilliam Kucharski 22*1b8adde7SWilliam Kucharski This software may be used and distributed according to the terms of 23*1b8adde7SWilliam Kucharski the GNU General Public License (GPL), incorporated herein by reference. 24*1b8adde7SWilliam Kucharski Drivers based on or derived from this code fall under the GPL and must 25*1b8adde7SWilliam Kucharski retain the authorship, copyright and license notice. This file is not 26*1b8adde7SWilliam Kucharski a complete program and may only be used when the entire operating 27*1b8adde7SWilliam Kucharski system is licensed under the GPL. License for under other terms may be 28*1b8adde7SWilliam Kucharski available. Contact the original author for details. 29*1b8adde7SWilliam Kucharski 30*1b8adde7SWilliam Kucharski The original author may be reached as becker@scyld.com, or at 31*1b8adde7SWilliam Kucharski Scyld Computing Corporation 32*1b8adde7SWilliam Kucharski 410 Severn Ave., Suite 210 33*1b8adde7SWilliam Kucharski Annapolis MD 21403 34*1b8adde7SWilliam Kucharski 35*1b8adde7SWilliam Kucharski Support information and updates available at 36*1b8adde7SWilliam Kucharski http://www.scyld.com/network/netsemi.html 37*1b8adde7SWilliam Kucharski 38*1b8adde7SWilliam Kucharski References: 39*1b8adde7SWilliam Kucharski 40*1b8adde7SWilliam Kucharski http://www.scyld.com/expert/100mbps.html 41*1b8adde7SWilliam Kucharski http://www.scyld.com/expert/NWay.html 42*1b8adde7SWilliam Kucharski Datasheet is available from: 43*1b8adde7SWilliam Kucharski http://www.national.com/pf/DP/DP83815.html 44*1b8adde7SWilliam Kucharski 45*1b8adde7SWilliam Kucharski */ 46*1b8adde7SWilliam Kucharski 47*1b8adde7SWilliam Kucharski /* Revision History */ 48*1b8adde7SWilliam Kucharski 49*1b8adde7SWilliam Kucharski /* 50*1b8adde7SWilliam Kucharski 13 Dec 2003 timlegge 1.1 Enabled Multicast Support 51*1b8adde7SWilliam Kucharski 29 May 2001 mdc 1.0 52*1b8adde7SWilliam Kucharski Initial Release. Tested with Netgear FA311 and FA312 boards 53*1b8adde7SWilliam Kucharski */ 54*1b8adde7SWilliam Kucharski /* Includes */ 55*1b8adde7SWilliam Kucharski 56*1b8adde7SWilliam Kucharski #include "etherboot.h" 57*1b8adde7SWilliam Kucharski #include "nic.h" 58*1b8adde7SWilliam Kucharski #include "pci.h" 59*1b8adde7SWilliam Kucharski 60*1b8adde7SWilliam Kucharski /* defines */ 61*1b8adde7SWilliam Kucharski 62*1b8adde7SWilliam Kucharski #define OWN 0x80000000 63*1b8adde7SWilliam Kucharski #define DSIZE 0x00000FFF 64*1b8adde7SWilliam Kucharski #define CRC_SIZE 4 65*1b8adde7SWilliam Kucharski 66*1b8adde7SWilliam Kucharski /* Time in ticks before concluding the transmitter is hung. */ 67*1b8adde7SWilliam Kucharski #define TX_TIMEOUT (4*TICKS_PER_SEC) 68*1b8adde7SWilliam Kucharski 69*1b8adde7SWilliam Kucharski #define TX_BUF_SIZE 1536 70*1b8adde7SWilliam Kucharski #define RX_BUF_SIZE 1536 71*1b8adde7SWilliam Kucharski 72*1b8adde7SWilliam Kucharski #define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */ 73*1b8adde7SWilliam Kucharski 74*1b8adde7SWilliam Kucharski typedef uint8_t u8; 75*1b8adde7SWilliam Kucharski typedef int8_t s8; 76*1b8adde7SWilliam Kucharski typedef uint16_t u16; 77*1b8adde7SWilliam Kucharski typedef int16_t s16; 78*1b8adde7SWilliam Kucharski typedef uint32_t u32; 79*1b8adde7SWilliam Kucharski typedef int32_t s32; 80*1b8adde7SWilliam Kucharski 81*1b8adde7SWilliam Kucharski /* helpful macroes if on a big_endian machine for changing byte order. 82*1b8adde7SWilliam Kucharski not strictly needed on Intel */ 83*1b8adde7SWilliam Kucharski #define get_unaligned(ptr) (*(ptr)) 84*1b8adde7SWilliam Kucharski #define put_unaligned(val, ptr) ((void)( *(ptr) = (val) )) 85*1b8adde7SWilliam Kucharski #define get_u16(ptr) (*(u16 *)(ptr)) 86*1b8adde7SWilliam Kucharski #define virt_to_le32desc(addr) virt_to_bus(addr) 87*1b8adde7SWilliam Kucharski 88*1b8adde7SWilliam Kucharski enum pcistuff { 89*1b8adde7SWilliam Kucharski PCI_USES_IO = 0x01, 90*1b8adde7SWilliam Kucharski PCI_USES_MEM = 0x02, 91*1b8adde7SWilliam Kucharski PCI_USES_MASTER = 0x04, 92*1b8adde7SWilliam Kucharski PCI_ADDR0 = 0x08, 93*1b8adde7SWilliam Kucharski PCI_ADDR1 = 0x10, 94*1b8adde7SWilliam Kucharski }; 95*1b8adde7SWilliam Kucharski 96*1b8adde7SWilliam Kucharski /* MMIO operations required */ 97*1b8adde7SWilliam Kucharski #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) 98*1b8adde7SWilliam Kucharski 99*1b8adde7SWilliam Kucharski /* Offsets to the device registers. 100*1b8adde7SWilliam Kucharski Unlike software-only systems, device drivers interact with complex hardware. 101*1b8adde7SWilliam Kucharski It's not useful to define symbolic names for every register bit in the 102*1b8adde7SWilliam Kucharski device. 103*1b8adde7SWilliam Kucharski */ 104*1b8adde7SWilliam Kucharski enum register_offsets { 105*1b8adde7SWilliam Kucharski ChipCmd = 0x00, 106*1b8adde7SWilliam Kucharski ChipConfig = 0x04, 107*1b8adde7SWilliam Kucharski EECtrl = 0x08, 108*1b8adde7SWilliam Kucharski PCIBusCfg = 0x0C, 109*1b8adde7SWilliam Kucharski IntrStatus = 0x10, 110*1b8adde7SWilliam Kucharski IntrMask = 0x14, 111*1b8adde7SWilliam Kucharski IntrEnable = 0x18, 112*1b8adde7SWilliam Kucharski TxRingPtr = 0x20, 113*1b8adde7SWilliam Kucharski TxConfig = 0x24, 114*1b8adde7SWilliam Kucharski RxRingPtr = 0x30, 115*1b8adde7SWilliam Kucharski RxConfig = 0x34, 116*1b8adde7SWilliam Kucharski ClkRun = 0x3C, 117*1b8adde7SWilliam Kucharski WOLCmd = 0x40, 118*1b8adde7SWilliam Kucharski PauseCmd = 0x44, 119*1b8adde7SWilliam Kucharski RxFilterAddr = 0x48, 120*1b8adde7SWilliam Kucharski RxFilterData = 0x4C, 121*1b8adde7SWilliam Kucharski BootRomAddr = 0x50, 122*1b8adde7SWilliam Kucharski BootRomData = 0x54, 123*1b8adde7SWilliam Kucharski SiliconRev = 0x58, 124*1b8adde7SWilliam Kucharski StatsCtrl = 0x5C, 125*1b8adde7SWilliam Kucharski StatsData = 0x60, 126*1b8adde7SWilliam Kucharski RxPktErrs = 0x60, 127*1b8adde7SWilliam Kucharski RxMissed = 0x68, 128*1b8adde7SWilliam Kucharski RxCRCErrs = 0x64, 129*1b8adde7SWilliam Kucharski PCIPM = 0x44, 130*1b8adde7SWilliam Kucharski PhyStatus = 0xC0, 131*1b8adde7SWilliam Kucharski MIntrCtrl = 0xC4, 132*1b8adde7SWilliam Kucharski MIntrStatus = 0xC8, 133*1b8adde7SWilliam Kucharski 134*1b8adde7SWilliam Kucharski /* These are from the spec, around page 78... on a separate table. */ 135*1b8adde7SWilliam Kucharski PGSEL = 0xCC, 136*1b8adde7SWilliam Kucharski PMDCSR = 0xE4, 137*1b8adde7SWilliam Kucharski TSTDAT = 0xFC, 138*1b8adde7SWilliam Kucharski DSPCFG = 0xF4, 139*1b8adde7SWilliam Kucharski SDCFG = 0x8C 140*1b8adde7SWilliam Kucharski }; 141*1b8adde7SWilliam Kucharski 142*1b8adde7SWilliam Kucharski /* Bit in ChipCmd. */ 143*1b8adde7SWilliam Kucharski enum ChipCmdBits { 144*1b8adde7SWilliam Kucharski ChipReset = 0x100, 145*1b8adde7SWilliam Kucharski RxReset = 0x20, 146*1b8adde7SWilliam Kucharski TxReset = 0x10, 147*1b8adde7SWilliam Kucharski RxOff = 0x08, 148*1b8adde7SWilliam Kucharski RxOn = 0x04, 149*1b8adde7SWilliam Kucharski TxOff = 0x02, 150*1b8adde7SWilliam Kucharski TxOn = 0x01 151*1b8adde7SWilliam Kucharski }; 152*1b8adde7SWilliam Kucharski 153*1b8adde7SWilliam Kucharski /* Bits in the RxMode register. */ 154*1b8adde7SWilliam Kucharski enum rx_mode_bits { 155*1b8adde7SWilliam Kucharski AcceptErr = 0x20, 156*1b8adde7SWilliam Kucharski AcceptRunt = 0x10, 157*1b8adde7SWilliam Kucharski AcceptBroadcast = 0xC0000000, 158*1b8adde7SWilliam Kucharski AcceptMulticast = 0x00200000, 159*1b8adde7SWilliam Kucharski AcceptAllMulticast = 0x20000000, 160*1b8adde7SWilliam Kucharski AcceptAllPhys = 0x10000000, 161*1b8adde7SWilliam Kucharski AcceptMyPhys = 0x08000000, 162*1b8adde7SWilliam Kucharski RxFilterEnable = 0x80000000 163*1b8adde7SWilliam Kucharski }; 164*1b8adde7SWilliam Kucharski 165*1b8adde7SWilliam Kucharski typedef struct _BufferDesc { 166*1b8adde7SWilliam Kucharski u32 link; 167*1b8adde7SWilliam Kucharski volatile u32 cmdsts; 168*1b8adde7SWilliam Kucharski u32 bufptr; 169*1b8adde7SWilliam Kucharski u32 software_use; 170*1b8adde7SWilliam Kucharski } BufferDesc; 171*1b8adde7SWilliam Kucharski 172*1b8adde7SWilliam Kucharski /* Bits in network_desc.status */ 173*1b8adde7SWilliam Kucharski enum desc_status_bits { 174*1b8adde7SWilliam Kucharski DescOwn = 0x80000000, 175*1b8adde7SWilliam Kucharski DescMore = 0x40000000, 176*1b8adde7SWilliam Kucharski DescIntr = 0x20000000, 177*1b8adde7SWilliam Kucharski DescNoCRC = 0x10000000, 178*1b8adde7SWilliam Kucharski DescPktOK = 0x08000000, 179*1b8adde7SWilliam Kucharski RxTooLong = 0x00400000 180*1b8adde7SWilliam Kucharski }; 181*1b8adde7SWilliam Kucharski 182*1b8adde7SWilliam Kucharski /* Globals */ 183*1b8adde7SWilliam Kucharski 184*1b8adde7SWilliam Kucharski static int natsemi_debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ 185*1b8adde7SWilliam Kucharski 186*1b8adde7SWilliam Kucharski const char *nic_name; 187*1b8adde7SWilliam Kucharski 188*1b8adde7SWilliam Kucharski static u32 SavedClkRun; 189*1b8adde7SWilliam Kucharski 190*1b8adde7SWilliam Kucharski 191*1b8adde7SWilliam Kucharski static unsigned short vendor, dev_id; 192*1b8adde7SWilliam Kucharski static unsigned long ioaddr; 193*1b8adde7SWilliam Kucharski 194*1b8adde7SWilliam Kucharski static unsigned int cur_rx; 195*1b8adde7SWilliam Kucharski 196*1b8adde7SWilliam Kucharski static unsigned int advertising; 197*1b8adde7SWilliam Kucharski 198*1b8adde7SWilliam Kucharski static unsigned int rx_config; 199*1b8adde7SWilliam Kucharski static unsigned int tx_config; 200*1b8adde7SWilliam Kucharski 201*1b8adde7SWilliam Kucharski /* Note: transmit and receive buffers and descriptors must be 202*1b8adde7SWilliam Kucharski longword aligned 203*1b8adde7SWilliam Kucharski */ 204*1b8adde7SWilliam Kucharski 205*1b8adde7SWilliam Kucharski static BufferDesc txd __attribute__ ((aligned(4))); 206*1b8adde7SWilliam Kucharski static BufferDesc rxd[NUM_RX_DESC] __attribute__ ((aligned(4))); 207*1b8adde7SWilliam Kucharski 208*1b8adde7SWilliam Kucharski static unsigned char txb[TX_BUF_SIZE] __attribute__ ((aligned(4))); 209*1b8adde7SWilliam Kucharski static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE] __attribute__ ((aligned(4))); 210*1b8adde7SWilliam Kucharski 211*1b8adde7SWilliam Kucharski /* Function Prototypes */ 212*1b8adde7SWilliam Kucharski 213*1b8adde7SWilliam Kucharski static int natsemi_probe(struct dev *dev, struct pci_device *pci); 214*1b8adde7SWilliam Kucharski static int eeprom_read(long addr, int location); 215*1b8adde7SWilliam Kucharski static int mdio_read(int phy_id, int location); 216*1b8adde7SWilliam Kucharski static void natsemi_init(struct nic *nic); 217*1b8adde7SWilliam Kucharski static void natsemi_reset(struct nic *nic); 218*1b8adde7SWilliam Kucharski static void natsemi_init_rxfilter(struct nic *nic); 219*1b8adde7SWilliam Kucharski static void natsemi_init_txd(struct nic *nic); 220*1b8adde7SWilliam Kucharski static void natsemi_init_rxd(struct nic *nic); 221*1b8adde7SWilliam Kucharski static void natsemi_set_rx_mode(struct nic *nic); 222*1b8adde7SWilliam Kucharski static void natsemi_check_duplex(struct nic *nic); 223*1b8adde7SWilliam Kucharski static void natsemi_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p); 224*1b8adde7SWilliam Kucharski static int natsemi_poll(struct nic *nic, int retrieve); 225*1b8adde7SWilliam Kucharski static void natsemi_disable(struct dev *dev); 226*1b8adde7SWilliam Kucharski static void natsemi_irq(struct nic *nic, irq_action_t action); 227*1b8adde7SWilliam Kucharski 228*1b8adde7SWilliam Kucharski /* 229*1b8adde7SWilliam Kucharski * Function: natsemi_probe 230*1b8adde7SWilliam Kucharski * 231*1b8adde7SWilliam Kucharski * Description: Retrieves the MAC address of the card, and sets up some 232*1b8adde7SWilliam Kucharski * globals required by other routines, and initializes the NIC, making it 233*1b8adde7SWilliam Kucharski * ready to send and receive packets. 234*1b8adde7SWilliam Kucharski * 235*1b8adde7SWilliam Kucharski * Side effects: 236*1b8adde7SWilliam Kucharski * leaves the ioaddress of the natsemi chip in the variable ioaddr. 237*1b8adde7SWilliam Kucharski * leaves the natsemi initialized, and ready to recieve packets. 238*1b8adde7SWilliam Kucharski * 239*1b8adde7SWilliam Kucharski * Returns: struct nic *: pointer to NIC data structure 240*1b8adde7SWilliam Kucharski */ 241*1b8adde7SWilliam Kucharski 242*1b8adde7SWilliam Kucharski static int 243*1b8adde7SWilliam Kucharski natsemi_probe(struct dev *dev, struct pci_device *pci) 244*1b8adde7SWilliam Kucharski { 245*1b8adde7SWilliam Kucharski struct nic *nic = (struct nic *)dev; 246*1b8adde7SWilliam Kucharski int i; 247*1b8adde7SWilliam Kucharski int prev_eedata; 248*1b8adde7SWilliam Kucharski u32 tmp; 249*1b8adde7SWilliam Kucharski 250*1b8adde7SWilliam Kucharski if (pci->ioaddr == 0) 251*1b8adde7SWilliam Kucharski return 0; 252*1b8adde7SWilliam Kucharski 253*1b8adde7SWilliam Kucharski adjust_pci_device(pci); 254*1b8adde7SWilliam Kucharski 255*1b8adde7SWilliam Kucharski /* initialize some commonly used globals */ 256*1b8adde7SWilliam Kucharski 257*1b8adde7SWilliam Kucharski nic->irqno = 0; 258*1b8adde7SWilliam Kucharski nic->ioaddr = pci->ioaddr & ~3; 259*1b8adde7SWilliam Kucharski 260*1b8adde7SWilliam Kucharski ioaddr = pci->ioaddr & ~3; 261*1b8adde7SWilliam Kucharski vendor = pci->vendor; 262*1b8adde7SWilliam Kucharski dev_id = pci->dev_id; 263*1b8adde7SWilliam Kucharski nic_name = pci->name; 264*1b8adde7SWilliam Kucharski 265*1b8adde7SWilliam Kucharski /* natsemi has a non-standard PM control register 266*1b8adde7SWilliam Kucharski * in PCI config space. Some boards apparently need 267*1b8adde7SWilliam Kucharski * to be brought to D0 in this manner. 268*1b8adde7SWilliam Kucharski */ 269*1b8adde7SWilliam Kucharski pcibios_read_config_dword(pci->bus, pci->devfn, PCIPM, &tmp); 270*1b8adde7SWilliam Kucharski if (tmp & (0x03|0x100)) { 271*1b8adde7SWilliam Kucharski /* D0 state, disable PME assertion */ 272*1b8adde7SWilliam Kucharski u32 newtmp = tmp & ~(0x03|0x100); 273*1b8adde7SWilliam Kucharski pcibios_write_config_dword(pci->bus, pci->devfn, PCIPM, newtmp); 274*1b8adde7SWilliam Kucharski } 275*1b8adde7SWilliam Kucharski 276*1b8adde7SWilliam Kucharski /* get MAC address */ 277*1b8adde7SWilliam Kucharski 278*1b8adde7SWilliam Kucharski prev_eedata = eeprom_read(ioaddr, 6); 279*1b8adde7SWilliam Kucharski for (i = 0; i < 3; i++) { 280*1b8adde7SWilliam Kucharski int eedata = eeprom_read(ioaddr, i + 7); 281*1b8adde7SWilliam Kucharski nic->node_addr[i*2] = (eedata << 1) + (prev_eedata >> 15); 282*1b8adde7SWilliam Kucharski nic->node_addr[i*2+1] = eedata >> 7; 283*1b8adde7SWilliam Kucharski prev_eedata = eedata; 284*1b8adde7SWilliam Kucharski } 285*1b8adde7SWilliam Kucharski 286*1b8adde7SWilliam Kucharski printf("\nnatsemi_probe: MAC addr %! at ioaddr %#hX\n", 287*1b8adde7SWilliam Kucharski nic->node_addr, ioaddr); 288*1b8adde7SWilliam Kucharski printf("natsemi_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id); 289*1b8adde7SWilliam Kucharski 290*1b8adde7SWilliam Kucharski /* Reset the chip to erase any previous misconfiguration. */ 291*1b8adde7SWilliam Kucharski outl(ChipReset, ioaddr + ChipCmd); 292*1b8adde7SWilliam Kucharski 293*1b8adde7SWilliam Kucharski advertising = mdio_read(1, 4); 294*1b8adde7SWilliam Kucharski { 295*1b8adde7SWilliam Kucharski u32 chip_config = inl(ioaddr + ChipConfig); 296*1b8adde7SWilliam Kucharski printf("%s: Transceiver default autoneg. %s " 297*1b8adde7SWilliam Kucharski "10%s %s duplex.\n", 298*1b8adde7SWilliam Kucharski nic_name, 299*1b8adde7SWilliam Kucharski chip_config & 0x2000 ? "enabled, advertise" : "disabled, force", 300*1b8adde7SWilliam Kucharski chip_config & 0x4000 ? "0" : "", 301*1b8adde7SWilliam Kucharski chip_config & 0x8000 ? "full" : "half"); 302*1b8adde7SWilliam Kucharski } 303*1b8adde7SWilliam Kucharski printf("%s: Transceiver status %hX advertising %hX\n", 304*1b8adde7SWilliam Kucharski nic_name, (int)inl(ioaddr + 0x84), advertising); 305*1b8adde7SWilliam Kucharski 306*1b8adde7SWilliam Kucharski /* Disable PME: 307*1b8adde7SWilliam Kucharski * The PME bit is initialized from the EEPROM contents. 308*1b8adde7SWilliam Kucharski * PCI cards probably have PME disabled, but motherboard 309*1b8adde7SWilliam Kucharski * implementations may have PME set to enable WakeOnLan. 310*1b8adde7SWilliam Kucharski * With PME set the chip will scan incoming packets but 311*1b8adde7SWilliam Kucharski * nothing will be written to memory. */ 312*1b8adde7SWilliam Kucharski SavedClkRun = inl(ioaddr + ClkRun); 313*1b8adde7SWilliam Kucharski outl(SavedClkRun & ~0x100, ioaddr + ClkRun); 314*1b8adde7SWilliam Kucharski 315*1b8adde7SWilliam Kucharski /* initialize device */ 316*1b8adde7SWilliam Kucharski natsemi_init(nic); 317*1b8adde7SWilliam Kucharski 318*1b8adde7SWilliam Kucharski dev->disable = natsemi_disable; 319*1b8adde7SWilliam Kucharski nic->poll = natsemi_poll; 320*1b8adde7SWilliam Kucharski nic->transmit = natsemi_transmit; 321*1b8adde7SWilliam Kucharski nic->irq = natsemi_irq; 322*1b8adde7SWilliam Kucharski 323*1b8adde7SWilliam Kucharski return 1; 324*1b8adde7SWilliam Kucharski } 325*1b8adde7SWilliam Kucharski 326*1b8adde7SWilliam Kucharski /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. 327*1b8adde7SWilliam Kucharski The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. 328*1b8adde7SWilliam Kucharski */ 329*1b8adde7SWilliam Kucharski 330*1b8adde7SWilliam Kucharski /* Delay between EEPROM clock transitions. 331*1b8adde7SWilliam Kucharski No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need 332*1b8adde7SWilliam Kucharski a delay. */ 333*1b8adde7SWilliam Kucharski #define eeprom_delay(ee_addr) inl(ee_addr) 334*1b8adde7SWilliam Kucharski 335*1b8adde7SWilliam Kucharski enum EEPROM_Ctrl_Bits { 336*1b8adde7SWilliam Kucharski EE_ShiftClk = 0x04, 337*1b8adde7SWilliam Kucharski EE_DataIn = 0x01, 338*1b8adde7SWilliam Kucharski EE_ChipSelect = 0x08, 339*1b8adde7SWilliam Kucharski EE_DataOut = 0x02 340*1b8adde7SWilliam Kucharski }; 341*1b8adde7SWilliam Kucharski 342*1b8adde7SWilliam Kucharski #define EE_Write0 (EE_ChipSelect) 343*1b8adde7SWilliam Kucharski #define EE_Write1 (EE_ChipSelect | EE_DataIn) 344*1b8adde7SWilliam Kucharski 345*1b8adde7SWilliam Kucharski /* The EEPROM commands include the alway-set leading bit. */ 346*1b8adde7SWilliam Kucharski enum EEPROM_Cmds { 347*1b8adde7SWilliam Kucharski EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6), 348*1b8adde7SWilliam Kucharski }; 349*1b8adde7SWilliam Kucharski 350*1b8adde7SWilliam Kucharski static int eeprom_read(long addr, int location) 351*1b8adde7SWilliam Kucharski { 352*1b8adde7SWilliam Kucharski int i; 353*1b8adde7SWilliam Kucharski int retval = 0; 354*1b8adde7SWilliam Kucharski int ee_addr = addr + EECtrl; 355*1b8adde7SWilliam Kucharski int read_cmd = location | EE_ReadCmd; 356*1b8adde7SWilliam Kucharski outl(EE_Write0, ee_addr); 357*1b8adde7SWilliam Kucharski 358*1b8adde7SWilliam Kucharski /* Shift the read command bits out. */ 359*1b8adde7SWilliam Kucharski for (i = 10; i >= 0; i--) { 360*1b8adde7SWilliam Kucharski short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0; 361*1b8adde7SWilliam Kucharski outl(dataval, ee_addr); 362*1b8adde7SWilliam Kucharski eeprom_delay(ee_addr); 363*1b8adde7SWilliam Kucharski outl(dataval | EE_ShiftClk, ee_addr); 364*1b8adde7SWilliam Kucharski eeprom_delay(ee_addr); 365*1b8adde7SWilliam Kucharski } 366*1b8adde7SWilliam Kucharski outl(EE_ChipSelect, ee_addr); 367*1b8adde7SWilliam Kucharski eeprom_delay(ee_addr); 368*1b8adde7SWilliam Kucharski 369*1b8adde7SWilliam Kucharski for (i = 0; i < 16; i++) { 370*1b8adde7SWilliam Kucharski outl(EE_ChipSelect | EE_ShiftClk, ee_addr); 371*1b8adde7SWilliam Kucharski eeprom_delay(ee_addr); 372*1b8adde7SWilliam Kucharski retval |= (inl(ee_addr) & EE_DataOut) ? 1 << i : 0; 373*1b8adde7SWilliam Kucharski outl(EE_ChipSelect, ee_addr); 374*1b8adde7SWilliam Kucharski eeprom_delay(ee_addr); 375*1b8adde7SWilliam Kucharski } 376*1b8adde7SWilliam Kucharski 377*1b8adde7SWilliam Kucharski /* Terminate the EEPROM access. */ 378*1b8adde7SWilliam Kucharski outl(EE_Write0, ee_addr); 379*1b8adde7SWilliam Kucharski outl(0, ee_addr); 380*1b8adde7SWilliam Kucharski 381*1b8adde7SWilliam Kucharski return retval; 382*1b8adde7SWilliam Kucharski } 383*1b8adde7SWilliam Kucharski 384*1b8adde7SWilliam Kucharski /* MII transceiver control section. 385*1b8adde7SWilliam Kucharski The 83815 series has an internal transceiver, and we present the 386*1b8adde7SWilliam Kucharski management registers as if they were MII connected. */ 387*1b8adde7SWilliam Kucharski 388*1b8adde7SWilliam Kucharski static int mdio_read(int phy_id, int location) 389*1b8adde7SWilliam Kucharski { 390*1b8adde7SWilliam Kucharski if (phy_id == 1 && location < 32) 391*1b8adde7SWilliam Kucharski return inl(ioaddr + 0x80 + (location<<2)) & 0xffff; 392*1b8adde7SWilliam Kucharski else 393*1b8adde7SWilliam Kucharski return 0xffff; 394*1b8adde7SWilliam Kucharski } 395*1b8adde7SWilliam Kucharski 396*1b8adde7SWilliam Kucharski /* Function: natsemi_init 397*1b8adde7SWilliam Kucharski * 398*1b8adde7SWilliam Kucharski * Description: resets the ethernet controller chip and configures 399*1b8adde7SWilliam Kucharski * registers and data structures required for sending and receiving packets. 400*1b8adde7SWilliam Kucharski * 401*1b8adde7SWilliam Kucharski * Arguments: struct nic *nic: NIC data structure 402*1b8adde7SWilliam Kucharski * 403*1b8adde7SWilliam Kucharski * returns: void. 404*1b8adde7SWilliam Kucharski */ 405*1b8adde7SWilliam Kucharski 406*1b8adde7SWilliam Kucharski static void 407*1b8adde7SWilliam Kucharski natsemi_init(struct nic *nic) 408*1b8adde7SWilliam Kucharski { 409*1b8adde7SWilliam Kucharski natsemi_reset(nic); 410*1b8adde7SWilliam Kucharski 411*1b8adde7SWilliam Kucharski /* Disable PME: 412*1b8adde7SWilliam Kucharski * The PME bit is initialized from the EEPROM contents. 413*1b8adde7SWilliam Kucharski * PCI cards probably have PME disabled, but motherboard 414*1b8adde7SWilliam Kucharski * implementations may have PME set to enable WakeOnLan. 415*1b8adde7SWilliam Kucharski * With PME set the chip will scan incoming packets but 416*1b8adde7SWilliam Kucharski * nothing will be written to memory. */ 417*1b8adde7SWilliam Kucharski outl(SavedClkRun & ~0x100, ioaddr + ClkRun); 418*1b8adde7SWilliam Kucharski 419*1b8adde7SWilliam Kucharski natsemi_init_rxfilter(nic); 420*1b8adde7SWilliam Kucharski 421*1b8adde7SWilliam Kucharski natsemi_init_txd(nic); 422*1b8adde7SWilliam Kucharski natsemi_init_rxd(nic); 423*1b8adde7SWilliam Kucharski 424*1b8adde7SWilliam Kucharski /* Initialize other registers. */ 425*1b8adde7SWilliam Kucharski /* Configure the PCI bus bursts and FIFO thresholds. */ 426*1b8adde7SWilliam Kucharski /* Configure for standard, in-spec Ethernet. */ 427*1b8adde7SWilliam Kucharski if (inl(ioaddr + ChipConfig) & 0x20000000) { /* Full duplex */ 428*1b8adde7SWilliam Kucharski tx_config = 0xD0801002; 429*1b8adde7SWilliam Kucharski rx_config = 0x10000020; 430*1b8adde7SWilliam Kucharski } else { 431*1b8adde7SWilliam Kucharski tx_config = 0x10801002; 432*1b8adde7SWilliam Kucharski rx_config = 0x0020; 433*1b8adde7SWilliam Kucharski } 434*1b8adde7SWilliam Kucharski outl(tx_config, ioaddr + TxConfig); 435*1b8adde7SWilliam Kucharski outl(rx_config, ioaddr + RxConfig); 436*1b8adde7SWilliam Kucharski 437*1b8adde7SWilliam Kucharski natsemi_check_duplex(nic); 438*1b8adde7SWilliam Kucharski natsemi_set_rx_mode(nic); 439*1b8adde7SWilliam Kucharski 440*1b8adde7SWilliam Kucharski outl(RxOn, ioaddr + ChipCmd); 441*1b8adde7SWilliam Kucharski } 442*1b8adde7SWilliam Kucharski 443*1b8adde7SWilliam Kucharski /* 444*1b8adde7SWilliam Kucharski * Function: natsemi_reset 445*1b8adde7SWilliam Kucharski * 446*1b8adde7SWilliam Kucharski * Description: soft resets the controller chip 447*1b8adde7SWilliam Kucharski * 448*1b8adde7SWilliam Kucharski * Arguments: struct nic *nic: NIC data structure 449*1b8adde7SWilliam Kucharski * 450*1b8adde7SWilliam Kucharski * Returns: void. 451*1b8adde7SWilliam Kucharski */ 452*1b8adde7SWilliam Kucharski static void 453*1b8adde7SWilliam Kucharski natsemi_reset(struct nic *nic __unused) 454*1b8adde7SWilliam Kucharski { 455*1b8adde7SWilliam Kucharski outl(ChipReset, ioaddr + ChipCmd); 456*1b8adde7SWilliam Kucharski 457*1b8adde7SWilliam Kucharski /* On page 78 of the spec, they recommend some settings for "optimum 458*1b8adde7SWilliam Kucharski performance" to be done in sequence. These settings optimize some 459*1b8adde7SWilliam Kucharski of the 100Mbit autodetection circuitry. Also, we only want to do 460*1b8adde7SWilliam Kucharski this for rev C of the chip. 461*1b8adde7SWilliam Kucharski */ 462*1b8adde7SWilliam Kucharski if (inl(ioaddr + SiliconRev) == 0x302) { 463*1b8adde7SWilliam Kucharski outw(0x0001, ioaddr + PGSEL); 464*1b8adde7SWilliam Kucharski outw(0x189C, ioaddr + PMDCSR); 465*1b8adde7SWilliam Kucharski outw(0x0000, ioaddr + TSTDAT); 466*1b8adde7SWilliam Kucharski outw(0x5040, ioaddr + DSPCFG); 467*1b8adde7SWilliam Kucharski outw(0x008C, ioaddr + SDCFG); 468*1b8adde7SWilliam Kucharski } 469*1b8adde7SWilliam Kucharski /* Disable interrupts using the mask. */ 470*1b8adde7SWilliam Kucharski outl(0, ioaddr + IntrMask); 471*1b8adde7SWilliam Kucharski outl(0, ioaddr + IntrEnable); 472*1b8adde7SWilliam Kucharski } 473*1b8adde7SWilliam Kucharski 474*1b8adde7SWilliam Kucharski /* Function: natsemi_init_rxfilter 475*1b8adde7SWilliam Kucharski * 476*1b8adde7SWilliam Kucharski * Description: sets receive filter address to our MAC address 477*1b8adde7SWilliam Kucharski * 478*1b8adde7SWilliam Kucharski * Arguments: struct nic *nic: NIC data structure 479*1b8adde7SWilliam Kucharski * 480*1b8adde7SWilliam Kucharski * returns: void. 481*1b8adde7SWilliam Kucharski */ 482*1b8adde7SWilliam Kucharski 483*1b8adde7SWilliam Kucharski static void 484*1b8adde7SWilliam Kucharski natsemi_init_rxfilter(struct nic *nic) 485*1b8adde7SWilliam Kucharski { 486*1b8adde7SWilliam Kucharski int i; 487*1b8adde7SWilliam Kucharski 488*1b8adde7SWilliam Kucharski for (i = 0; i < ETH_ALEN; i += 2) { 489*1b8adde7SWilliam Kucharski outl(i, ioaddr + RxFilterAddr); 490*1b8adde7SWilliam Kucharski outw(nic->node_addr[i] + (nic->node_addr[i+1] << 8), ioaddr + RxFilterData); 491*1b8adde7SWilliam Kucharski } 492*1b8adde7SWilliam Kucharski } 493*1b8adde7SWilliam Kucharski 494*1b8adde7SWilliam Kucharski /* 495*1b8adde7SWilliam Kucharski * Function: natsemi_init_txd 496*1b8adde7SWilliam Kucharski * 497*1b8adde7SWilliam Kucharski * Description: initializes the Tx descriptor 498*1b8adde7SWilliam Kucharski * 499*1b8adde7SWilliam Kucharski * Arguments: struct nic *nic: NIC data structure 500*1b8adde7SWilliam Kucharski * 501*1b8adde7SWilliam Kucharski * returns: void. 502*1b8adde7SWilliam Kucharski */ 503*1b8adde7SWilliam Kucharski 504*1b8adde7SWilliam Kucharski static void 505*1b8adde7SWilliam Kucharski natsemi_init_txd(struct nic *nic __unused) 506*1b8adde7SWilliam Kucharski { 507*1b8adde7SWilliam Kucharski txd.link = (u32) 0; 508*1b8adde7SWilliam Kucharski txd.cmdsts = (u32) 0; 509*1b8adde7SWilliam Kucharski txd.bufptr = virt_to_bus(&txb[0]); 510*1b8adde7SWilliam Kucharski 511*1b8adde7SWilliam Kucharski /* load Transmit Descriptor Register */ 512*1b8adde7SWilliam Kucharski outl(virt_to_bus(&txd), ioaddr + TxRingPtr); 513*1b8adde7SWilliam Kucharski if (natsemi_debug > 1) 514*1b8adde7SWilliam Kucharski printf("natsemi_init_txd: TX descriptor register loaded with: %X\n", 515*1b8adde7SWilliam Kucharski inl(ioaddr + TxRingPtr)); 516*1b8adde7SWilliam Kucharski } 517*1b8adde7SWilliam Kucharski 518*1b8adde7SWilliam Kucharski /* Function: natsemi_init_rxd 519*1b8adde7SWilliam Kucharski * 520*1b8adde7SWilliam Kucharski * Description: initializes the Rx descriptor ring 521*1b8adde7SWilliam Kucharski * 522*1b8adde7SWilliam Kucharski * Arguments: struct nic *nic: NIC data structure 523*1b8adde7SWilliam Kucharski * 524*1b8adde7SWilliam Kucharski * Returns: void. 525*1b8adde7SWilliam Kucharski */ 526*1b8adde7SWilliam Kucharski 527*1b8adde7SWilliam Kucharski static void 528*1b8adde7SWilliam Kucharski natsemi_init_rxd(struct nic *nic __unused) 529*1b8adde7SWilliam Kucharski { 530*1b8adde7SWilliam Kucharski int i; 531*1b8adde7SWilliam Kucharski 532*1b8adde7SWilliam Kucharski cur_rx = 0; 533*1b8adde7SWilliam Kucharski 534*1b8adde7SWilliam Kucharski /* init RX descriptor */ 535*1b8adde7SWilliam Kucharski for (i = 0; i < NUM_RX_DESC; i++) { 536*1b8adde7SWilliam Kucharski rxd[i].link = virt_to_bus((i+1 < NUM_RX_DESC) ? &rxd[i+1] : &rxd[0]); 537*1b8adde7SWilliam Kucharski rxd[i].cmdsts = (u32) RX_BUF_SIZE; 538*1b8adde7SWilliam Kucharski rxd[i].bufptr = virt_to_bus(&rxb[i*RX_BUF_SIZE]); 539*1b8adde7SWilliam Kucharski if (natsemi_debug > 1) 540*1b8adde7SWilliam Kucharski printf("natsemi_init_rxd: rxd[%d]=%X link=%X cmdsts=%X bufptr=%X\n", 541*1b8adde7SWilliam Kucharski i, &rxd[i], rxd[i].link, rxd[i].cmdsts, rxd[i].bufptr); 542*1b8adde7SWilliam Kucharski } 543*1b8adde7SWilliam Kucharski 544*1b8adde7SWilliam Kucharski /* load Receive Descriptor Register */ 545*1b8adde7SWilliam Kucharski outl(virt_to_bus(&rxd[0]), ioaddr + RxRingPtr); 546*1b8adde7SWilliam Kucharski 547*1b8adde7SWilliam Kucharski if (natsemi_debug > 1) 548*1b8adde7SWilliam Kucharski printf("natsemi_init_rxd: RX descriptor register loaded with: %X\n", 549*1b8adde7SWilliam Kucharski inl(ioaddr + RxRingPtr)); 550*1b8adde7SWilliam Kucharski } 551*1b8adde7SWilliam Kucharski 552*1b8adde7SWilliam Kucharski /* Function: natsemi_set_rx_mode 553*1b8adde7SWilliam Kucharski * 554*1b8adde7SWilliam Kucharski * Description: 555*1b8adde7SWilliam Kucharski * sets the receive mode to accept all broadcast packets and packets 556*1b8adde7SWilliam Kucharski * with our MAC address, and reject all multicast packets. 557*1b8adde7SWilliam Kucharski * 558*1b8adde7SWilliam Kucharski * Arguments: struct nic *nic: NIC data structure 559*1b8adde7SWilliam Kucharski * 560*1b8adde7SWilliam Kucharski * Returns: void. 561*1b8adde7SWilliam Kucharski */ 562*1b8adde7SWilliam Kucharski 563*1b8adde7SWilliam Kucharski static void natsemi_set_rx_mode(struct nic *nic __unused) 564*1b8adde7SWilliam Kucharski { 565*1b8adde7SWilliam Kucharski u32 rx_mode = RxFilterEnable | AcceptBroadcast | 566*1b8adde7SWilliam Kucharski AcceptAllMulticast | AcceptMyPhys; 567*1b8adde7SWilliam Kucharski 568*1b8adde7SWilliam Kucharski outl(rx_mode, ioaddr + RxFilterAddr); 569*1b8adde7SWilliam Kucharski } 570*1b8adde7SWilliam Kucharski 571*1b8adde7SWilliam Kucharski static void natsemi_check_duplex(struct nic *nic __unused) 572*1b8adde7SWilliam Kucharski { 573*1b8adde7SWilliam Kucharski int duplex = inl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0; 574*1b8adde7SWilliam Kucharski 575*1b8adde7SWilliam Kucharski if (natsemi_debug) 576*1b8adde7SWilliam Kucharski printf("%s: Setting %s-duplex based on negotiated link" 577*1b8adde7SWilliam Kucharski " capability.\n", nic_name, 578*1b8adde7SWilliam Kucharski duplex ? "full" : "half"); 579*1b8adde7SWilliam Kucharski if (duplex) { 580*1b8adde7SWilliam Kucharski rx_config |= 0x10000000; 581*1b8adde7SWilliam Kucharski tx_config |= 0xC0000000; 582*1b8adde7SWilliam Kucharski } else { 583*1b8adde7SWilliam Kucharski rx_config &= ~0x10000000; 584*1b8adde7SWilliam Kucharski tx_config &= ~0xC0000000; 585*1b8adde7SWilliam Kucharski } 586*1b8adde7SWilliam Kucharski outl(tx_config, ioaddr + TxConfig); 587*1b8adde7SWilliam Kucharski outl(rx_config, ioaddr + RxConfig); 588*1b8adde7SWilliam Kucharski } 589*1b8adde7SWilliam Kucharski 590*1b8adde7SWilliam Kucharski /* Function: natsemi_transmit 591*1b8adde7SWilliam Kucharski * 592*1b8adde7SWilliam Kucharski * Description: transmits a packet and waits for completion or timeout. 593*1b8adde7SWilliam Kucharski * 594*1b8adde7SWilliam Kucharski * Arguments: char d[6]: destination ethernet address. 595*1b8adde7SWilliam Kucharski * unsigned short t: ethernet protocol type. 596*1b8adde7SWilliam Kucharski * unsigned short s: size of the data-part of the packet. 597*1b8adde7SWilliam Kucharski * char *p: the data for the packet. 598*1b8adde7SWilliam Kucharski * 599*1b8adde7SWilliam Kucharski * Returns: void. 600*1b8adde7SWilliam Kucharski */ 601*1b8adde7SWilliam Kucharski 602*1b8adde7SWilliam Kucharski static void 603*1b8adde7SWilliam Kucharski natsemi_transmit(struct nic *nic, 604*1b8adde7SWilliam Kucharski const char *d, /* Destination */ 605*1b8adde7SWilliam Kucharski unsigned int t, /* Type */ 606*1b8adde7SWilliam Kucharski unsigned int s, /* size */ 607*1b8adde7SWilliam Kucharski const char *p) /* Packet */ 608*1b8adde7SWilliam Kucharski { 609*1b8adde7SWilliam Kucharski u32 to, nstype; 610*1b8adde7SWilliam Kucharski u32 tx_status; 611*1b8adde7SWilliam Kucharski 612*1b8adde7SWilliam Kucharski /* Stop the transmitter */ 613*1b8adde7SWilliam Kucharski outl(TxOff, ioaddr + ChipCmd); 614*1b8adde7SWilliam Kucharski 615*1b8adde7SWilliam Kucharski /* load Transmit Descriptor Register */ 616*1b8adde7SWilliam Kucharski outl(virt_to_bus(&txd), ioaddr + TxRingPtr); 617*1b8adde7SWilliam Kucharski if (natsemi_debug > 1) 618*1b8adde7SWilliam Kucharski printf("natsemi_transmit: TX descriptor register loaded with: %X\n", 619*1b8adde7SWilliam Kucharski inl(ioaddr + TxRingPtr)); 620*1b8adde7SWilliam Kucharski 621*1b8adde7SWilliam Kucharski memcpy(txb, d, ETH_ALEN); 622*1b8adde7SWilliam Kucharski memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN); 623*1b8adde7SWilliam Kucharski nstype = htons(t); 624*1b8adde7SWilliam Kucharski memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2); 625*1b8adde7SWilliam Kucharski memcpy(txb + ETH_HLEN, p, s); 626*1b8adde7SWilliam Kucharski 627*1b8adde7SWilliam Kucharski s += ETH_HLEN; 628*1b8adde7SWilliam Kucharski s &= DSIZE; 629*1b8adde7SWilliam Kucharski 630*1b8adde7SWilliam Kucharski if (natsemi_debug > 1) 631*1b8adde7SWilliam Kucharski printf("natsemi_transmit: sending %d bytes ethtype %hX\n", (int) s, t); 632*1b8adde7SWilliam Kucharski 633*1b8adde7SWilliam Kucharski /* pad to minimum packet size */ 634*1b8adde7SWilliam Kucharski while (s < ETH_ZLEN) 635*1b8adde7SWilliam Kucharski txb[s++] = '\0'; 636*1b8adde7SWilliam Kucharski 637*1b8adde7SWilliam Kucharski /* set the transmit buffer descriptor and enable Transmit State Machine */ 638*1b8adde7SWilliam Kucharski txd.bufptr = virt_to_bus(&txb[0]); 639*1b8adde7SWilliam Kucharski txd.cmdsts = (u32) OWN | s; 640*1b8adde7SWilliam Kucharski 641*1b8adde7SWilliam Kucharski /* restart the transmitter */ 642*1b8adde7SWilliam Kucharski outl(TxOn, ioaddr + ChipCmd); 643*1b8adde7SWilliam Kucharski 644*1b8adde7SWilliam Kucharski if (natsemi_debug > 1) 645*1b8adde7SWilliam Kucharski printf("natsemi_transmit: Queued Tx packet size %d.\n", (int) s); 646*1b8adde7SWilliam Kucharski 647*1b8adde7SWilliam Kucharski to = currticks() + TX_TIMEOUT; 648*1b8adde7SWilliam Kucharski 649*1b8adde7SWilliam Kucharski while ((((volatile u32) tx_status=txd.cmdsts) & OWN) && (currticks() < to)) 650*1b8adde7SWilliam Kucharski /* wait */ ; 651*1b8adde7SWilliam Kucharski 652*1b8adde7SWilliam Kucharski if (currticks() >= to) { 653*1b8adde7SWilliam Kucharski printf("natsemi_transmit: TX Timeout! Tx status %X.\n", tx_status); 654*1b8adde7SWilliam Kucharski } 655*1b8adde7SWilliam Kucharski 656*1b8adde7SWilliam Kucharski if (!(tx_status & 0x08000000)) { 657*1b8adde7SWilliam Kucharski printf("natsemi_transmit: Transmit error, Tx status %X.\n", tx_status); 658*1b8adde7SWilliam Kucharski } 659*1b8adde7SWilliam Kucharski } 660*1b8adde7SWilliam Kucharski 661*1b8adde7SWilliam Kucharski /* Function: natsemi_poll 662*1b8adde7SWilliam Kucharski * 663*1b8adde7SWilliam Kucharski * Description: checks for a received packet and returns it if found. 664*1b8adde7SWilliam Kucharski * 665*1b8adde7SWilliam Kucharski * Arguments: struct nic *nic: NIC data structure 666*1b8adde7SWilliam Kucharski * 667*1b8adde7SWilliam Kucharski * Returns: 1 if packet was received. 668*1b8adde7SWilliam Kucharski * 0 if no packet was received. 669*1b8adde7SWilliam Kucharski * 670*1b8adde7SWilliam Kucharski * Side effects: 671*1b8adde7SWilliam Kucharski * Returns (copies) the packet to the array nic->packet. 672*1b8adde7SWilliam Kucharski * Returns the length of the packet in nic->packetlen. 673*1b8adde7SWilliam Kucharski */ 674*1b8adde7SWilliam Kucharski 675*1b8adde7SWilliam Kucharski static int 676*1b8adde7SWilliam Kucharski natsemi_poll(struct nic *nic, int retrieve) 677*1b8adde7SWilliam Kucharski { 678*1b8adde7SWilliam Kucharski u32 rx_status = rxd[cur_rx].cmdsts; 679*1b8adde7SWilliam Kucharski int retstat = 0; 680*1b8adde7SWilliam Kucharski 681*1b8adde7SWilliam Kucharski if (natsemi_debug > 2) 682*1b8adde7SWilliam Kucharski printf("natsemi_poll: cur_rx:%d, status:%X\n", cur_rx, rx_status); 683*1b8adde7SWilliam Kucharski 684*1b8adde7SWilliam Kucharski if (!(rx_status & OWN)) 685*1b8adde7SWilliam Kucharski return retstat; 686*1b8adde7SWilliam Kucharski 687*1b8adde7SWilliam Kucharski if ( ! retrieve ) return 1; 688*1b8adde7SWilliam Kucharski 689*1b8adde7SWilliam Kucharski if (natsemi_debug > 1) 690*1b8adde7SWilliam Kucharski printf("natsemi_poll: got a packet: cur_rx:%d, status:%X\n", 691*1b8adde7SWilliam Kucharski cur_rx, rx_status); 692*1b8adde7SWilliam Kucharski 693*1b8adde7SWilliam Kucharski nic->packetlen = (rx_status & DSIZE) - CRC_SIZE; 694*1b8adde7SWilliam Kucharski 695*1b8adde7SWilliam Kucharski if ((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { 696*1b8adde7SWilliam Kucharski /* corrupted packet received */ 697*1b8adde7SWilliam Kucharski printf("natsemi_poll: Corrupted packet received, buffer status = %X\n", 698*1b8adde7SWilliam Kucharski rx_status); 699*1b8adde7SWilliam Kucharski retstat = 0; 700*1b8adde7SWilliam Kucharski } else { 701*1b8adde7SWilliam Kucharski /* give packet to higher level routine */ 702*1b8adde7SWilliam Kucharski memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen); 703*1b8adde7SWilliam Kucharski retstat = 1; 704*1b8adde7SWilliam Kucharski } 705*1b8adde7SWilliam Kucharski 706*1b8adde7SWilliam Kucharski /* return the descriptor and buffer to receive ring */ 707*1b8adde7SWilliam Kucharski rxd[cur_rx].cmdsts = RX_BUF_SIZE; 708*1b8adde7SWilliam Kucharski rxd[cur_rx].bufptr = virt_to_bus(&rxb[cur_rx*RX_BUF_SIZE]); 709*1b8adde7SWilliam Kucharski 710*1b8adde7SWilliam Kucharski if (++cur_rx == NUM_RX_DESC) 711*1b8adde7SWilliam Kucharski cur_rx = 0; 712*1b8adde7SWilliam Kucharski 713*1b8adde7SWilliam Kucharski /* re-enable the potentially idle receive state machine */ 714*1b8adde7SWilliam Kucharski outl(RxOn, ioaddr + ChipCmd); 715*1b8adde7SWilliam Kucharski 716*1b8adde7SWilliam Kucharski return retstat; 717*1b8adde7SWilliam Kucharski } 718*1b8adde7SWilliam Kucharski 719*1b8adde7SWilliam Kucharski /* Function: natsemi_disable 720*1b8adde7SWilliam Kucharski * 721*1b8adde7SWilliam Kucharski * Description: Turns off interrupts and stops Tx and Rx engines 722*1b8adde7SWilliam Kucharski * 723*1b8adde7SWilliam Kucharski * Arguments: struct nic *nic: NIC data structure 724*1b8adde7SWilliam Kucharski * 725*1b8adde7SWilliam Kucharski * Returns: void. 726*1b8adde7SWilliam Kucharski */ 727*1b8adde7SWilliam Kucharski 728*1b8adde7SWilliam Kucharski static void 729*1b8adde7SWilliam Kucharski natsemi_disable(struct dev *dev) 730*1b8adde7SWilliam Kucharski { 731*1b8adde7SWilliam Kucharski struct nic *nic = (struct nic *)dev; 732*1b8adde7SWilliam Kucharski /* merge reset and disable */ 733*1b8adde7SWilliam Kucharski natsemi_init(nic); 734*1b8adde7SWilliam Kucharski 735*1b8adde7SWilliam Kucharski /* Disable interrupts using the mask. */ 736*1b8adde7SWilliam Kucharski outl(0, ioaddr + IntrMask); 737*1b8adde7SWilliam Kucharski outl(0, ioaddr + IntrEnable); 738*1b8adde7SWilliam Kucharski 739*1b8adde7SWilliam Kucharski /* Stop the chip's Tx and Rx processes. */ 740*1b8adde7SWilliam Kucharski outl(RxOff | TxOff, ioaddr + ChipCmd); 741*1b8adde7SWilliam Kucharski 742*1b8adde7SWilliam Kucharski /* Restore PME enable bit */ 743*1b8adde7SWilliam Kucharski outl(SavedClkRun, ioaddr + ClkRun); 744*1b8adde7SWilliam Kucharski } 745*1b8adde7SWilliam Kucharski 746*1b8adde7SWilliam Kucharski /* Function: natsemi_irq 747*1b8adde7SWilliam Kucharski * 748*1b8adde7SWilliam Kucharski * Description: Enable, Disable, or Force interrupts 749*1b8adde7SWilliam Kucharski * 750*1b8adde7SWilliam Kucharski * Arguments: struct nic *nic: NIC data structure 751*1b8adde7SWilliam Kucharski * irq_action_t action: requested action to perform 752*1b8adde7SWilliam Kucharski * 753*1b8adde7SWilliam Kucharski * Returns: void. 754*1b8adde7SWilliam Kucharski */ 755*1b8adde7SWilliam Kucharski 756*1b8adde7SWilliam Kucharski static void 757*1b8adde7SWilliam Kucharski natsemi_irq(struct nic *nic __unused, irq_action_t action __unused) 758*1b8adde7SWilliam Kucharski { 759*1b8adde7SWilliam Kucharski switch ( action ) { 760*1b8adde7SWilliam Kucharski case DISABLE : 761*1b8adde7SWilliam Kucharski break; 762*1b8adde7SWilliam Kucharski case ENABLE : 763*1b8adde7SWilliam Kucharski break; 764*1b8adde7SWilliam Kucharski case FORCE : 765*1b8adde7SWilliam Kucharski break; 766*1b8adde7SWilliam Kucharski } 767*1b8adde7SWilliam Kucharski } 768*1b8adde7SWilliam Kucharski 769*1b8adde7SWilliam Kucharski static struct pci_id natsemi_nics[] = { 770*1b8adde7SWilliam Kucharski PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815"), 771*1b8adde7SWilliam Kucharski }; 772*1b8adde7SWilliam Kucharski 773*1b8adde7SWilliam Kucharski struct pci_driver natsemi_driver = { 774*1b8adde7SWilliam Kucharski .type = NIC_DRIVER, 775*1b8adde7SWilliam Kucharski .name = "NATSEMI", 776*1b8adde7SWilliam Kucharski .probe = natsemi_probe, 777*1b8adde7SWilliam Kucharski .ids = natsemi_nics, 778*1b8adde7SWilliam Kucharski .id_count = sizeof(natsemi_nics)/sizeof(natsemi_nics[0]), 779*1b8adde7SWilliam Kucharski .class = 0, 780*1b8adde7SWilliam Kucharski }; 781