17c478bd9Sstevel@tonic-gate 
27c478bd9Sstevel@tonic-gate /* epic100.c: A SMC 83c170 EPIC/100 fast ethernet driver for Etherboot */
37c478bd9Sstevel@tonic-gate 
47c478bd9Sstevel@tonic-gate /* 05/06/2003	timlegge	Fixed relocation and implemented Multicast */
57c478bd9Sstevel@tonic-gate #define LINUX_OUT_MACROS
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate #include "etherboot.h"
87c478bd9Sstevel@tonic-gate #include "pci.h"
97c478bd9Sstevel@tonic-gate #include "nic.h"
107c478bd9Sstevel@tonic-gate #include "timer.h"
117c478bd9Sstevel@tonic-gate #include "epic100.h"
127c478bd9Sstevel@tonic-gate 
137c478bd9Sstevel@tonic-gate /* Condensed operations for readability */
147c478bd9Sstevel@tonic-gate #define virt_to_le32desc(addr)	cpu_to_le32(virt_to_bus(addr))
157c478bd9Sstevel@tonic-gate #define le32desc_to_virt(addr)	bus_to_virt(le32_to_cpu(addr))
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #define TX_RING_SIZE	2	/* use at least 2 buffers for TX */
187c478bd9Sstevel@tonic-gate #define RX_RING_SIZE	2
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate #define PKT_BUF_SZ	1536	/* Size of each temporary Tx/Rx buffer.*/
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate #define DEBUG_RX
247c478bd9Sstevel@tonic-gate #define DEBUG_TX
257c478bd9Sstevel@tonic-gate #define DEBUG_EEPROM
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #define EPIC_DEBUG 0	/* debug level */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /* The EPIC100 Rx and Tx buffer descriptors. */
317c478bd9Sstevel@tonic-gate struct epic_rx_desc {
327c478bd9Sstevel@tonic-gate     unsigned long status;
337c478bd9Sstevel@tonic-gate     unsigned long bufaddr;
347c478bd9Sstevel@tonic-gate     unsigned long buflength;
357c478bd9Sstevel@tonic-gate     unsigned long next;
367c478bd9Sstevel@tonic-gate };
377c478bd9Sstevel@tonic-gate /* description of the tx descriptors control bits commonly used */
387c478bd9Sstevel@tonic-gate #define TD_STDFLAGS	TD_LASTDESC
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate struct epic_tx_desc {
417c478bd9Sstevel@tonic-gate     unsigned long status;
427c478bd9Sstevel@tonic-gate     unsigned long bufaddr;
437c478bd9Sstevel@tonic-gate     unsigned long buflength;
447c478bd9Sstevel@tonic-gate     unsigned long  next;
457c478bd9Sstevel@tonic-gate };
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #define delay(nanosec)   do { int _i = 3; while (--_i > 0) \
487c478bd9Sstevel@tonic-gate                                      { __SLOW_DOWN_IO; }} while (0)
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static void	epic100_open(void);
517c478bd9Sstevel@tonic-gate static void	epic100_init_ring(void);
527c478bd9Sstevel@tonic-gate static void	epic100_disable(struct dev *dev);
537c478bd9Sstevel@tonic-gate static int	epic100_poll(struct nic *nic, int retrieve);
547c478bd9Sstevel@tonic-gate static void	epic100_transmit(struct nic *nic, const char *destaddr,
557c478bd9Sstevel@tonic-gate 				 unsigned int type, unsigned int len, const char *data);
567c478bd9Sstevel@tonic-gate #ifdef	DEBUG_EEPROM
577c478bd9Sstevel@tonic-gate static int	read_eeprom(int location);
587c478bd9Sstevel@tonic-gate #endif
597c478bd9Sstevel@tonic-gate static int	mii_read(int phy_id, int location);
607c478bd9Sstevel@tonic-gate static void     epic100_irq(struct nic *nic, irq_action_t action);
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate static int	ioaddr;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static int	command;
657c478bd9Sstevel@tonic-gate static int	intstat;
667c478bd9Sstevel@tonic-gate static int	intmask;
677c478bd9Sstevel@tonic-gate static int	genctl ;
687c478bd9Sstevel@tonic-gate static int	eectl  ;
697c478bd9Sstevel@tonic-gate static int	test   ;
707c478bd9Sstevel@tonic-gate static int	mmctl  ;
717c478bd9Sstevel@tonic-gate static int	mmdata ;
727c478bd9Sstevel@tonic-gate static int	lan0   ;
737c478bd9Sstevel@tonic-gate static int	mc0    ;
747c478bd9Sstevel@tonic-gate static int	rxcon  ;
757c478bd9Sstevel@tonic-gate static int	txcon  ;
767c478bd9Sstevel@tonic-gate static int	prcdar ;
777c478bd9Sstevel@tonic-gate static int	ptcdar ;
787c478bd9Sstevel@tonic-gate static int	eththr ;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate static unsigned int	cur_rx, cur_tx;		/* The next free ring entry */
817c478bd9Sstevel@tonic-gate #ifdef	DEBUG_EEPROM
827c478bd9Sstevel@tonic-gate static unsigned short	eeprom[64];
837c478bd9Sstevel@tonic-gate #endif
847c478bd9Sstevel@tonic-gate static signed char	phys[4];		/* MII device addresses. */
857c478bd9Sstevel@tonic-gate static struct epic_rx_desc	rx_ring[RX_RING_SIZE]
867c478bd9Sstevel@tonic-gate 	__attribute__ ((aligned(4)));
877c478bd9Sstevel@tonic-gate static struct epic_tx_desc	tx_ring[TX_RING_SIZE]
887c478bd9Sstevel@tonic-gate 	__attribute__ ((aligned(4)));
897c478bd9Sstevel@tonic-gate static unsigned char	 	rx_packet[PKT_BUF_SZ * RX_RING_SIZE];
907c478bd9Sstevel@tonic-gate static unsigned char		tx_packet[PKT_BUF_SZ * TX_RING_SIZE];
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /***********************************************************************/
937c478bd9Sstevel@tonic-gate /*                    Externally visible functions                     */
947c478bd9Sstevel@tonic-gate /***********************************************************************/
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate     static int
epic100_probe(struct dev * dev,struct pci_device * pci)987c478bd9Sstevel@tonic-gate epic100_probe(struct dev *dev, struct pci_device *pci)
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate     struct nic *nic = (struct nic *)dev;
1017c478bd9Sstevel@tonic-gate     int i;
1027c478bd9Sstevel@tonic-gate     unsigned short* ap;
1037c478bd9Sstevel@tonic-gate     unsigned int phy, phy_idx;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate     if (pci->ioaddr == 0)
1067c478bd9Sstevel@tonic-gate 	return 0;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate     /* Ideally we would detect all network cards in slot order.  That would
1097c478bd9Sstevel@tonic-gate        be best done a central PCI probe dispatch, which wouldn't work
1107c478bd9Sstevel@tonic-gate        well with the current structure.  So instead we detect just the
1117c478bd9Sstevel@tonic-gate        Epic cards in slot order. */
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate     ioaddr = pci->ioaddr;
1147c478bd9Sstevel@tonic-gate     nic->irqno  = 0;
1157c478bd9Sstevel@tonic-gate     nic->ioaddr = pci->ioaddr & ~3;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate     /* compute all used static epic100 registers address */
1187c478bd9Sstevel@tonic-gate     command = ioaddr + COMMAND;		/* Control Register */
1197c478bd9Sstevel@tonic-gate     intstat = ioaddr + INTSTAT;		/* Interrupt Status */
1207c478bd9Sstevel@tonic-gate     intmask = ioaddr + INTMASK;		/* Interrupt Mask */
1217c478bd9Sstevel@tonic-gate     genctl  = ioaddr + GENCTL;		/* General Control */
1227c478bd9Sstevel@tonic-gate     eectl   = ioaddr + EECTL;		/* EEPROM Control  */
1237c478bd9Sstevel@tonic-gate     test    = ioaddr + TEST;		/* Test register (clocks) */
1247c478bd9Sstevel@tonic-gate     mmctl   = ioaddr + MMCTL;		/* MII Management Interface Control */
1257c478bd9Sstevel@tonic-gate     mmdata  = ioaddr + MMDATA;		/* MII Management Interface Data */
1267c478bd9Sstevel@tonic-gate     lan0    = ioaddr + LAN0;		/* MAC address. (0x40-0x48) */
1277c478bd9Sstevel@tonic-gate     mc0     = ioaddr + MC0; 		/* Multicast Control */
1287c478bd9Sstevel@tonic-gate     rxcon   = ioaddr + RXCON;		/* Receive Control */
1297c478bd9Sstevel@tonic-gate     txcon   = ioaddr + TXCON;		/* Transmit Control */
1307c478bd9Sstevel@tonic-gate     prcdar  = ioaddr + PRCDAR;		/* PCI Receive Current Descr Address */
1317c478bd9Sstevel@tonic-gate     ptcdar  = ioaddr + PTCDAR;		/* PCI Transmit Current Descr Address */
1327c478bd9Sstevel@tonic-gate     eththr  = ioaddr + ETHTHR;		/* Early Transmit Threshold */
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate     /* Reset the chip & bring it out of low-power mode. */
1357c478bd9Sstevel@tonic-gate     outl(GC_SOFT_RESET, genctl);
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate     /* Disable ALL interrupts by setting the interrupt mask. */
1387c478bd9Sstevel@tonic-gate     outl(INTR_DISABLE, intmask);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate     /*
1417c478bd9Sstevel@tonic-gate      * set the internal clocks:
1427c478bd9Sstevel@tonic-gate      * Application Note 7.15 says:
1437c478bd9Sstevel@tonic-gate      *    In order to set the CLOCK TEST bit in the TEST register,
1447c478bd9Sstevel@tonic-gate      *	  perform the following:
1457c478bd9Sstevel@tonic-gate      *
1467c478bd9Sstevel@tonic-gate      *        Write 0x0008 to the test register at least sixteen
1477c478bd9Sstevel@tonic-gate      *        consecutive times.
1487c478bd9Sstevel@tonic-gate      *
1497c478bd9Sstevel@tonic-gate      * The CLOCK TEST bit is Write-Only. Writing it several times
1507c478bd9Sstevel@tonic-gate      * consecutively insures a successful write to the bit...
1517c478bd9Sstevel@tonic-gate      */
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate     for (i = 0; i < 16; i++) {
1547c478bd9Sstevel@tonic-gate 	outl(0x00000008, test);
1557c478bd9Sstevel@tonic-gate     }
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate #ifdef	DEBUG_EEPROM
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate     unsigned short sum = 0;
1607c478bd9Sstevel@tonic-gate     unsigned short value;
1617c478bd9Sstevel@tonic-gate     for (i = 0; i < 64; i++) {
1627c478bd9Sstevel@tonic-gate 	value = read_eeprom(i);
1637c478bd9Sstevel@tonic-gate 	eeprom[i] = value;
1647c478bd9Sstevel@tonic-gate 	sum += value;
1657c478bd9Sstevel@tonic-gate     }
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate #if	(EPIC_DEBUG > 1)
1697c478bd9Sstevel@tonic-gate     printf("EEPROM contents\n");
1707c478bd9Sstevel@tonic-gate     for (i = 0; i < 64; i++) {
1717c478bd9Sstevel@tonic-gate 	printf(" %hhX%s", eeprom[i], i % 16 == 15 ? "\n" : "");
1727c478bd9Sstevel@tonic-gate     }
1737c478bd9Sstevel@tonic-gate #endif
1747c478bd9Sstevel@tonic-gate #endif
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate     /* This could also be read from the EEPROM. */
1777c478bd9Sstevel@tonic-gate     ap = (unsigned short*)nic->node_addr;
1787c478bd9Sstevel@tonic-gate     for (i = 0; i < 3; i++)
1797c478bd9Sstevel@tonic-gate 	*ap++ = inw(lan0 + i*4);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate     printf(" I/O %#hX %! ", ioaddr, nic->node_addr);
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate     /* Find the connected MII xcvrs. */
1847c478bd9Sstevel@tonic-gate     for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(phys); phy++) {
1857c478bd9Sstevel@tonic-gate 	int mii_status = mii_read(phy, 0);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	if (mii_status != 0xffff  && mii_status != 0x0000) {
1887c478bd9Sstevel@tonic-gate 	    phys[phy_idx++] = phy;
1897c478bd9Sstevel@tonic-gate #if	(EPIC_DEBUG > 1)
1907c478bd9Sstevel@tonic-gate 	    printf("MII transceiver found at address %d.\n", phy);
1917c478bd9Sstevel@tonic-gate #endif
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate     }
1947c478bd9Sstevel@tonic-gate     if (phy_idx == 0) {
1957c478bd9Sstevel@tonic-gate #if	(EPIC_DEBUG > 1)
1967c478bd9Sstevel@tonic-gate 	printf("***WARNING***: No MII transceiver found!\n");
1977c478bd9Sstevel@tonic-gate #endif
1987c478bd9Sstevel@tonic-gate 	/* Use the known PHY address of the EPII. */
1997c478bd9Sstevel@tonic-gate 	phys[0] = 3;
2007c478bd9Sstevel@tonic-gate     }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate     epic100_open();
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate     dev->disable  = epic100_disable;
2057c478bd9Sstevel@tonic-gate     nic->poll     = epic100_poll;
2067c478bd9Sstevel@tonic-gate     nic->transmit = epic100_transmit;
2077c478bd9Sstevel@tonic-gate     nic->irq      = epic100_irq;
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate     return 1;
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
set_rx_mode(void)2127c478bd9Sstevel@tonic-gate static void set_rx_mode(void)
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate 	unsigned char mc_filter[8];
2157c478bd9Sstevel@tonic-gate 	int i;
2167c478bd9Sstevel@tonic-gate 	memset(mc_filter, 0xff, sizeof(mc_filter));
2177c478bd9Sstevel@tonic-gate 	outl(0x0C, rxcon);
2187c478bd9Sstevel@tonic-gate 	for(i = 0; i < 4; i++)
2197c478bd9Sstevel@tonic-gate 		outw(((unsigned short *)mc_filter)[i], mc0 + i*4);
2207c478bd9Sstevel@tonic-gate 	return;
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate    static void
epic100_open(void)2247c478bd9Sstevel@tonic-gate epic100_open(void)
2257c478bd9Sstevel@tonic-gate {
2267c478bd9Sstevel@tonic-gate     int mii_reg5;
2277c478bd9Sstevel@tonic-gate     int full_duplex = 0;
2287c478bd9Sstevel@tonic-gate     unsigned long tmp;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate     epic100_init_ring();
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate     /* Pull the chip out of low-power mode, and set for PCI read multiple. */
2337c478bd9Sstevel@tonic-gate     outl(GC_RX_FIFO_THR_64 | GC_MRC_READ_MULT | GC_ONE_COPY, genctl);
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate     outl(TX_FIFO_THRESH, eththr);
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate     tmp = TC_EARLY_TX_ENABLE | TX_SLOT_TIME;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate     mii_reg5 = mii_read(phys[0], 5);
2407c478bd9Sstevel@tonic-gate     if (mii_reg5 != 0xffff && (mii_reg5 & 0x0100)) {
2417c478bd9Sstevel@tonic-gate 	full_duplex = 1;
2427c478bd9Sstevel@tonic-gate 	printf(" full-duplex mode");
2437c478bd9Sstevel@tonic-gate 	tmp |= TC_LM_FULL_DPX;
2447c478bd9Sstevel@tonic-gate     } else
2457c478bd9Sstevel@tonic-gate 	tmp |= TC_LM_NORMAL;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate     outl(tmp, txcon);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate     /* Give adress of RX and TX ring to the chip */
2507c478bd9Sstevel@tonic-gate     outl(virt_to_le32desc(&rx_ring), prcdar);
2517c478bd9Sstevel@tonic-gate     outl(virt_to_le32desc(&tx_ring), ptcdar);
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate     /* Start the chip's Rx process: receive unicast and broadcast */
2547c478bd9Sstevel@tonic-gate     set_rx_mode();
2557c478bd9Sstevel@tonic-gate     outl(CR_START_RX | CR_QUEUE_RX, command);
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate     putchar('\n');
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate /* Initialize the Rx and Tx rings. */
2617c478bd9Sstevel@tonic-gate     static void
epic100_init_ring(void)2627c478bd9Sstevel@tonic-gate epic100_init_ring(void)
2637c478bd9Sstevel@tonic-gate {
2647c478bd9Sstevel@tonic-gate     int i;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate     cur_rx = cur_tx = 0;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate     for (i = 0; i < RX_RING_SIZE; i++) {
2697c478bd9Sstevel@tonic-gate 	rx_ring[i].status    = cpu_to_le32(RRING_OWN);	/* Owned by Epic chip */
2707c478bd9Sstevel@tonic-gate 	rx_ring[i].buflength = cpu_to_le32(PKT_BUF_SZ);
2717c478bd9Sstevel@tonic-gate 	rx_ring[i].bufaddr   = virt_to_bus(&rx_packet[i * PKT_BUF_SZ]);
2727c478bd9Sstevel@tonic-gate 	rx_ring[i].next      = virt_to_le32desc(&rx_ring[i + 1]) ;
2737c478bd9Sstevel@tonic-gate     }
2747c478bd9Sstevel@tonic-gate     /* Mark the last entry as wrapping the ring. */
2757c478bd9Sstevel@tonic-gate     rx_ring[i-1].next = virt_to_le32desc(&rx_ring[0]);
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate     /*
2787c478bd9Sstevel@tonic-gate      *The Tx buffer descriptor is filled in as needed,
2797c478bd9Sstevel@tonic-gate      * but we do need to clear the ownership bit.
2807c478bd9Sstevel@tonic-gate      */
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate     for (i = 0; i < TX_RING_SIZE; i++) {
2837c478bd9Sstevel@tonic-gate 	tx_ring[i].status  = 0x0000;			/* Owned by CPU */
2847c478bd9Sstevel@tonic-gate     	tx_ring[i].buflength = 0x0000 | cpu_to_le32(TD_STDFLAGS << 16);
2857c478bd9Sstevel@tonic-gate 	tx_ring[i].bufaddr = virt_to_bus(&tx_packet[i * PKT_BUF_SZ]);
2867c478bd9Sstevel@tonic-gate 	tx_ring[i].next    = virt_to_le32desc(&tx_ring[i + 1]);
2877c478bd9Sstevel@tonic-gate     }
2887c478bd9Sstevel@tonic-gate 	tx_ring[i-1].next    = virt_to_le32desc(&tx_ring[0]);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate /* function: epic100_transmit
2927c478bd9Sstevel@tonic-gate  * This transmits a packet.
2937c478bd9Sstevel@tonic-gate  *
2947c478bd9Sstevel@tonic-gate  * Arguments: char d[6]:          destination ethernet address.
2957c478bd9Sstevel@tonic-gate  *            unsigned short t:   ethernet protocol type.
2967c478bd9Sstevel@tonic-gate  *            unsigned short s:   size of the data-part of the packet.
2977c478bd9Sstevel@tonic-gate  *            char *p:            the data for the packet.
2987c478bd9Sstevel@tonic-gate  * returns:   void.
2997c478bd9Sstevel@tonic-gate  */
3007c478bd9Sstevel@tonic-gate     static void
epic100_transmit(struct nic * nic,const char * destaddr,unsigned int type,unsigned int len,const char * data)3017c478bd9Sstevel@tonic-gate epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type,
3027c478bd9Sstevel@tonic-gate 		 unsigned int len, const char *data)
3037c478bd9Sstevel@tonic-gate {
3047c478bd9Sstevel@tonic-gate     unsigned short nstype;
3057c478bd9Sstevel@tonic-gate     unsigned char *txp;
3067c478bd9Sstevel@tonic-gate     int entry;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate     /* Calculate the next Tx descriptor entry. */
3097c478bd9Sstevel@tonic-gate     entry = cur_tx % TX_RING_SIZE;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate     if ((tx_ring[entry].status & TRING_OWN) == TRING_OWN) {
3127c478bd9Sstevel@tonic-gate 	printf("eth_transmit: Unable to transmit. status=%hX. Resetting...\n",
3137c478bd9Sstevel@tonic-gate 	       tx_ring[entry].status);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	epic100_open();
3167c478bd9Sstevel@tonic-gate 	return;
3177c478bd9Sstevel@tonic-gate     }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate     txp = tx_packet + (entry * PKT_BUF_SZ);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate     memcpy(txp, destaddr, ETH_ALEN);
3227c478bd9Sstevel@tonic-gate     memcpy(txp + ETH_ALEN, nic->node_addr, ETH_ALEN);
3237c478bd9Sstevel@tonic-gate     nstype = htons(type);
3247c478bd9Sstevel@tonic-gate     memcpy(txp + 12, (char*)&nstype, 2);
3257c478bd9Sstevel@tonic-gate     memcpy(txp + ETH_HLEN, data, len);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate     len += ETH_HLEN;
3287c478bd9Sstevel@tonic-gate 	len &= 0x0FFF;
3297c478bd9Sstevel@tonic-gate 	while(len < ETH_ZLEN)
3307c478bd9Sstevel@tonic-gate 		txp[len++] = '\0';
3317c478bd9Sstevel@tonic-gate     /*
3327c478bd9Sstevel@tonic-gate      * Caution: the write order is important here,
3337c478bd9Sstevel@tonic-gate      * set the base address with the "ownership"
3347c478bd9Sstevel@tonic-gate      * bits last.
3357c478bd9Sstevel@tonic-gate      */
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate     tx_ring[entry].buflength |= cpu_to_le32(len);
3387c478bd9Sstevel@tonic-gate     tx_ring[entry].status = cpu_to_le32(len << 16) |
3397c478bd9Sstevel@tonic-gate 	    cpu_to_le32(TRING_OWN);	/* Pass ownership to the chip. */
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate     cur_tx++;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate     /* Trigger an immediate transmit demand. */
3447c478bd9Sstevel@tonic-gate     outl(CR_QUEUE_TX, command);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate     load_timer2(10*TICKS_PER_MS);         /* timeout 10 ms for transmit */
3477c478bd9Sstevel@tonic-gate     while ((le32_to_cpu(tx_ring[entry].status) & (TRING_OWN)) && timer2_running())
3487c478bd9Sstevel@tonic-gate 	/* Wait */;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate     if ((le32_to_cpu(tx_ring[entry].status) & TRING_OWN) != 0)
3517c478bd9Sstevel@tonic-gate 	printf("Oops, transmitter timeout, status=%hX\n",
3527c478bd9Sstevel@tonic-gate 	    tx_ring[entry].status);
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate /* function: epic100_poll / eth_poll
3567c478bd9Sstevel@tonic-gate  * This receives a packet from the network.
3577c478bd9Sstevel@tonic-gate  *
3587c478bd9Sstevel@tonic-gate  * Arguments: none
3597c478bd9Sstevel@tonic-gate  *
3607c478bd9Sstevel@tonic-gate  * returns:   1 if a packet was received.
3617c478bd9Sstevel@tonic-gate  *            0 if no pacet was received.
3627c478bd9Sstevel@tonic-gate  * side effects:
3637c478bd9Sstevel@tonic-gate  *            returns the packet in the array nic->packet.
3647c478bd9Sstevel@tonic-gate  *            returns the length of the packet in nic->packetlen.
3657c478bd9Sstevel@tonic-gate  */
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate     static int
epic100_poll(struct nic * nic,int retrieve)3687c478bd9Sstevel@tonic-gate epic100_poll(struct nic *nic, int retrieve)
3697c478bd9Sstevel@tonic-gate {
3707c478bd9Sstevel@tonic-gate     int entry;
3717c478bd9Sstevel@tonic-gate     int retcode;
3727c478bd9Sstevel@tonic-gate     int status;
3737c478bd9Sstevel@tonic-gate     entry = cur_rx % RX_RING_SIZE;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate     if ((rx_ring[entry].status & cpu_to_le32(RRING_OWN)) == RRING_OWN)
3767c478bd9Sstevel@tonic-gate 	return (0);
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate     if ( ! retrieve ) return 1;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate     status = le32_to_cpu(rx_ring[entry].status);
3817c478bd9Sstevel@tonic-gate     /* We own the next entry, it's a new packet. Send it up. */
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate #if	(EPIC_DEBUG > 4)
3847c478bd9Sstevel@tonic-gate     printf("epic_poll: entry %d status %hX\n", entry, status);
3857c478bd9Sstevel@tonic-gate #endif
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate     cur_rx++;
3887c478bd9Sstevel@tonic-gate     if (status & 0x2000) {
3897c478bd9Sstevel@tonic-gate 	printf("epic_poll: Giant packet\n");
3907c478bd9Sstevel@tonic-gate 	retcode = 0;
3917c478bd9Sstevel@tonic-gate     } else if (status & 0x0006) {
3927c478bd9Sstevel@tonic-gate 	/* Rx Frame errors are counted in hardware. */
3937c478bd9Sstevel@tonic-gate 	printf("epic_poll: Frame received with errors\n");
3947c478bd9Sstevel@tonic-gate 	retcode = 0;
3957c478bd9Sstevel@tonic-gate     } else {
3967c478bd9Sstevel@tonic-gate 	/* Omit the four octet CRC from the length. */
3977c478bd9Sstevel@tonic-gate 	nic->packetlen = le32_to_cpu((rx_ring[entry].buflength))- 4;
3987c478bd9Sstevel@tonic-gate 	memcpy(nic->packet, &rx_packet[entry * PKT_BUF_SZ], nic->packetlen);
3997c478bd9Sstevel@tonic-gate 	retcode = 1;
4007c478bd9Sstevel@tonic-gate     }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate     /* Clear all error sources. */
4037c478bd9Sstevel@tonic-gate     outl(status & INTR_CLEARERRS, intstat);
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate     /* Give the descriptor back to the chip */
4067c478bd9Sstevel@tonic-gate     rx_ring[entry].status = RRING_OWN;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate     /* Restart Receiver */
4097c478bd9Sstevel@tonic-gate     outl(CR_START_RX | CR_QUEUE_RX, command);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate     return retcode;
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate     static void
epic100_disable(struct dev * dev __unused)4167c478bd9Sstevel@tonic-gate epic100_disable(struct dev *dev __unused)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	/* Soft reset the chip. */
4197c478bd9Sstevel@tonic-gate 	outl(GC_SOFT_RESET, genctl);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
epic100_irq(struct nic * nic __unused,irq_action_t action __unused)4227c478bd9Sstevel@tonic-gate static void epic100_irq(struct nic *nic __unused, irq_action_t action __unused)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate   switch ( action ) {
4257c478bd9Sstevel@tonic-gate   case DISABLE :
4267c478bd9Sstevel@tonic-gate     break;
4277c478bd9Sstevel@tonic-gate   case ENABLE :
4287c478bd9Sstevel@tonic-gate     break;
4297c478bd9Sstevel@tonic-gate   case FORCE :
4307c478bd9Sstevel@tonic-gate     break;
4317c478bd9Sstevel@tonic-gate   }
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate #ifdef	DEBUG_EEPROM
4357c478bd9Sstevel@tonic-gate /* Serial EEPROM section. */
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate /*  EEPROM_Ctrl bits. */
4387c478bd9Sstevel@tonic-gate #define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
4397c478bd9Sstevel@tonic-gate #define EE_CS		0x02	/* EEPROM chip select. */
4407c478bd9Sstevel@tonic-gate #define EE_DATA_WRITE	0x08	/* EEPROM chip data in. */
4417c478bd9Sstevel@tonic-gate #define EE_WRITE_0	0x01
4427c478bd9Sstevel@tonic-gate #define EE_WRITE_1	0x09
4437c478bd9Sstevel@tonic-gate #define EE_DATA_READ	0x10	/* EEPROM chip data out. */
4447c478bd9Sstevel@tonic-gate #define EE_ENB		(0x0001 | EE_CS)
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate /* The EEPROM commands include the alway-set leading bit. */
4477c478bd9Sstevel@tonic-gate #define EE_WRITE_CMD	(5 << 6)
4487c478bd9Sstevel@tonic-gate #define EE_READ_CMD	(6 << 6)
4497c478bd9Sstevel@tonic-gate #define EE_ERASE_CMD	(7 << 6)
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate #define eeprom_delay(n)	delay(n)
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate     static int
read_eeprom(int location)4547c478bd9Sstevel@tonic-gate read_eeprom(int location)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate     int i;
4577c478bd9Sstevel@tonic-gate     int retval = 0;
4587c478bd9Sstevel@tonic-gate     int read_cmd = location | EE_READ_CMD;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate     outl(EE_ENB & ~EE_CS, eectl);
4617c478bd9Sstevel@tonic-gate     outl(EE_ENB, eectl);
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate     /* Shift the read command bits out. */
4647c478bd9Sstevel@tonic-gate     for (i = 10; i >= 0; i--) {
4657c478bd9Sstevel@tonic-gate 	short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
4667c478bd9Sstevel@tonic-gate 	outl(EE_ENB | dataval, eectl);
4677c478bd9Sstevel@tonic-gate 	eeprom_delay(100);
4687c478bd9Sstevel@tonic-gate 	outl(EE_ENB | dataval | EE_SHIFT_CLK, eectl);
4697c478bd9Sstevel@tonic-gate 	eeprom_delay(150);
4707c478bd9Sstevel@tonic-gate 	outl(EE_ENB | dataval, eectl);	/* Finish EEPROM a clock tick. */
4717c478bd9Sstevel@tonic-gate 	eeprom_delay(250);
4727c478bd9Sstevel@tonic-gate     }
4737c478bd9Sstevel@tonic-gate     outl(EE_ENB, eectl);
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate     for (i = 16; i > 0; i--) {
4767c478bd9Sstevel@tonic-gate 	outl(EE_ENB | EE_SHIFT_CLK, eectl);
4777c478bd9Sstevel@tonic-gate 	eeprom_delay(100);
4787c478bd9Sstevel@tonic-gate 	retval = (retval << 1) | ((inl(eectl) & EE_DATA_READ) ? 1 : 0);
4797c478bd9Sstevel@tonic-gate 	outl(EE_ENB, eectl);
4807c478bd9Sstevel@tonic-gate 	eeprom_delay(100);
4817c478bd9Sstevel@tonic-gate     }
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate     /* Terminate the EEPROM access. */
4847c478bd9Sstevel@tonic-gate     outl(EE_ENB & ~EE_CS, eectl);
4857c478bd9Sstevel@tonic-gate     return retval;
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate #endif
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate #define MII_READOP	1
4917c478bd9Sstevel@tonic-gate #define MII_WRITEOP	2
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate     static int
mii_read(int phy_id,int location)4947c478bd9Sstevel@tonic-gate mii_read(int phy_id, int location)
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate     int i;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate     outl((phy_id << 9) | (location << 4) | MII_READOP, mmctl);
4997c478bd9Sstevel@tonic-gate     /* Typical operation takes < 50 ticks. */
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate     for (i = 4000; i > 0; i--)
5027c478bd9Sstevel@tonic-gate 	if ((inl(mmctl) & MII_READOP) == 0)
5037c478bd9Sstevel@tonic-gate 	    break;
5047c478bd9Sstevel@tonic-gate     return inw(mmdata);
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate static struct pci_id epic100_nics[] = {
5097c478bd9Sstevel@tonic-gate PCI_ROM(0x10b8, 0x0005, "epic100",    "SMC EtherPowerII"),		/* SMC 83c170 EPIC/100 */
5107c478bd9Sstevel@tonic-gate PCI_ROM(0x10b8, 0x0006, "smc-83c175", "SMC EPIC/C 83c175"),
5117c478bd9Sstevel@tonic-gate };
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate struct pci_driver epic100_driver = {
5147c478bd9Sstevel@tonic-gate 	.type     = NIC_DRIVER,
5157c478bd9Sstevel@tonic-gate 	.name     = "EPIC100",
5167c478bd9Sstevel@tonic-gate 	.probe    = epic100_probe,
5177c478bd9Sstevel@tonic-gate 	.ids      = epic100_nics,
5187c478bd9Sstevel@tonic-gate 	.id_count = sizeof(epic100_nics)/sizeof(epic100_nics[0]),
5197c478bd9Sstevel@tonic-gate 	.class    = 0,
5207c478bd9Sstevel@tonic-gate };
521