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