123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- /**************************************************************************
- Etherboot - BOOTP/TFTP Bootstrap Program
- TIARA (Fujitsu Etherstar) NIC driver for Etherboot
- Copyright (c) Ken Yap 1998
- Information gleaned from:
- TIARA.ASM Packet driver by Brian Fisher, Queens U, Kingston, Ontario
- Fujitsu MB86960 spec sheet (different chip but same family)
- ***************************************************************************/
- /*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or (at
- * your option) any later version.
- */
- /* to get some global routines like printf */
- #include "etherboot.h"
- /* to get the interface to the body of the program */
- #include "nic.h"
- #include "cards.h"
- /*
- EtherStar I/O Register offsets
- */
- /* Offsets of registers */
- #define DLCR_XMIT_STAT 0x00
- #define DLCR_XMIT_MASK 0x01
- #define DLCR_RECV_STAT 0x02
- #define DLCR_RECV_MASK 0x03
- #define DLCR_XMIT_MODE 0x04
- #define DLCR_RECV_MODE 0x05
- #define DLCR_ENABLE 0x06
- #define DLCR_TDR_LOW 0x07
- #define DLCR_NODE_ID 0x08
- #define DLCR_TDR_HIGH 0x0F
- #define BMPR_MEM_PORT 0x10
- #define BMPR_PKT_LEN 0x12
- #define BMPR_DMA_ENABLE 0x14
- #define PROM_ID 0x18
- #define TMST 0x80
- #define TMT_OK 0x80
- #define TMT_16COLL 0x02
- #define BUF_EMPTY 0x40
- #define CARD_DISABLE 0x80 /* written to DLCR_ENABLE to disable card */
- #define CARD_ENABLE 0 /* written to DLCR_ENABLE to enable card */
- #define CLEAR_STATUS 0x0F /* used to clear status info */
- /*
- 00001111B
- !!!!!!!!--------
- !!!!!!!+--------CLEAR BUS WRITE ERROR
- !!!!!!+---------CLEAR 16 COLLISION
- !!!!!+----------CLEAR COLLISION
- !!!!+-----------CLEAR UNDERFLOW
- !!!+------------NC
- !!+-------------NC
- !+--------------NC
- +---------------NC
- */
- #define NO_TX_IRQS 0 /* written to clear transmit IRQs */
- #define CLR_RCV_STATUS 0xCF /* clears receive status */
- #define EN_RCV_IRQS 0x80 /* enable receive interrupts */
- /*
- 10000000B
- !!!!!!!!--------
- !!!!!!!+--------ENABLE OVERFLOW
- !!!!!!+---------ENABLE CRC
- !!!!!+----------ENABLE ALIGN
- !!!!+-----------ENABLE SHORT PKT
- !!!+------------DISABLE REMOTE RESET
- !!+-------------RESERVED
- !+--------------RESERVED
- +---------------ENABLE PKT READY
- */
- #define XMIT_MODE 0x02
- /*
- 00000010B
- !!!!!!!!---------ENABLE CARRIER DETECT
- !!!!!!!+---------DISABLE LOOPBACK
- */
- #define RECV_MODE 0x02
- /*
- 00000010B
- !!!!!!!!---------ACCEPT ALL PACKETS
- !!!!!!!+---------ACCEPT PHYSICAL, MULTICAST, AND
- !!!!!!+----------BROADCAST PACKETS
- !!!!!+-----------DISABLE REMOTE RESET
- !!!!+------------DISABLE SHORT PACKETS
- !!!+-------------USE 6 BYTE ADDRESS
- !!+--------------NC
- !+---------------NC
- +----------------DISABLE CRC TEST MODE
- */
- /* NIC specific static variables go here */
- static unsigned short ioaddr;
- /**************************************************************************
- RESET - Reset adapter
- ***************************************************************************/
- static void tiara_reset(struct nic *nic)
- {
- int i;
- outb(CARD_DISABLE, ioaddr + DLCR_ENABLE);
- outb(CLEAR_STATUS, ioaddr + DLCR_XMIT_STAT);
- outb(NO_TX_IRQS, ioaddr + DLCR_XMIT_MASK);
- outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
- outb(XMIT_MODE, ioaddr + DLCR_XMIT_MODE);
- outb(RECV_MODE, ioaddr + DLCR_RECV_MODE);
- /* Vacuum recv buffer */
- while ((inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY) == 0)
- inb(ioaddr + BMPR_MEM_PORT);
- /* Set node address */
- for (i = 0; i < ETH_ALEN; ++i)
- outb(nic->node_addr[i], ioaddr + DLCR_NODE_ID + i);
- outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
- outb(CARD_ENABLE, ioaddr + DLCR_ENABLE);
- }
- /**************************************************************************
- POLL - Wait for a frame
- ***************************************************************************/
- static int tiara_poll(struct nic *nic)
- {
- unsigned int len;
- if (inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY)
- return (0);
- /* Ack packet */
- outw(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
- len = inw(ioaddr + BMPR_MEM_PORT); /* throw away status */
- len = inw(ioaddr + BMPR_MEM_PORT);
- /* Drop overlength packets */
- if (len > ETH_FRAME_LEN)
- return (0); /* should we drain the buffer? */
- insw(ioaddr + BMPR_MEM_PORT, nic->packet, len / 2);
- /* If it's our own, drop it */
- if (memcmp(nic->packet + ETH_ALEN, nic->node_addr, ETH_ALEN) == 0)
- return (0);
- nic->packetlen = len;
- return (1);
- }
- /**************************************************************************
- TRANSMIT - Transmit a frame
- ***************************************************************************/
- static void tiara_transmit(
- struct nic *nic,
- const char *d, /* Destination */
- unsigned int t, /* Type */
- unsigned int s, /* size */
- const char *p) /* Packet */
- {
- unsigned int len;
- unsigned long time;
- len = s + ETH_HLEN;
- if (len < ETH_ZLEN)
- len = ETH_ZLEN;
- t = htons(t);
- outsw(ioaddr + BMPR_MEM_PORT, d, ETH_ALEN / 2);
- outsw(ioaddr + BMPR_MEM_PORT, nic->node_addr, ETH_ALEN / 2);
- outw(t, ioaddr + BMPR_MEM_PORT);
- outsw(ioaddr + BMPR_MEM_PORT, p, s / 2);
- if (s & 1) /* last byte */
- outb(p[s-1], ioaddr + BMPR_MEM_PORT);
- while (s++ < ETH_ZLEN - ETH_HLEN) /* pad */
- outb(0, ioaddr + BMPR_MEM_PORT);
- outw(len | (TMST << 8), ioaddr + BMPR_PKT_LEN);
- /* wait for transmit complete */
- time = currticks() + TICKS_PER_SEC; /* wait one second */
- while (currticks() < time && (inb(ioaddr) & (TMT_OK|TMT_16COLL)) == 0)
- ;
- if ((inb(ioaddr) & (TMT_OK|TMT_16COLL)) == 0)
- printf("Tiara timed out on transmit\n");
- /* Do we need to ack the transmit? */
- }
- /**************************************************************************
- DISABLE - Turn off ethernet interface
- ***************************************************************************/
- static void tiara_disable(struct nic *nic)
- {
- /* Apparently only a power down can do this properly */
- outb(CARD_DISABLE, ioaddr + DLCR_ENABLE);
- }
- static int tiara_probe1(struct nic *nic)
- {
- /* Hope all the Tiara cards have this vendor prefix */
- static char vendor_prefix[] = { 0x08, 0x00, 0x1A };
- static char all_ones[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
- int i;
- for (i = 0; i < ETH_ALEN; ++i)
- nic->node_addr[i] = inb(ioaddr + PROM_ID + i);
- if (memcmp(nic->node_addr, vendor_prefix, sizeof(vendor_prefix)) != 0)
- return (0);
- if (memcmp(nic->node_addr, all_ones, sizeof(all_ones)) == 0)
- return (0);
- printf("\nTiara ioaddr %#hX, addr %!\n", ioaddr, nic->node_addr);
- return (1);
- }
- /**************************************************************************
- PROBE - Look for an adapter, this routine's visible to the outside
- ***************************************************************************/
- struct nic *tiara_probe(struct nic *nic, unsigned short *probe_addrs)
- {
- /* missing entries are addresses usually already used */
- static unsigned short io_addrs[] = {
- 0x100, 0x120, 0x140, 0x160,
- 0x180, 0x1A0, 0x1C0, 0x1E0,
- 0x200, 0x220, 0x240, /*Par*/
- 0x280, 0x2A0, 0x2C0, /*Ser*/
- 0x300, 0x320, 0x340, /*Par*/
- 0x380, /*Vid,Par*/ 0x3C0, /*Ser*/
- 0x0
- };
- unsigned short *p;
- /* if probe_addrs is 0, then routine can use a hardwired default */
- if (probe_addrs == 0)
- probe_addrs = io_addrs;
- for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
- if (tiara_probe1(nic))
- break;
- /* if board found */
- if (ioaddr != 0)
- {
- tiara_reset(nic);
- /* point to NIC specific routines */
- nic->reset = tiara_reset;
- nic->poll = tiara_poll;
- nic->transmit = tiara_transmit;
- nic->disable = tiara_disable;
- return nic;
- }
- else
- return (0);
- }
|