Home | History | Annotate | Download | only in netboot
      1 /**************************************************************************
      2 Etherboot -  BOOTP/TFTP Bootstrap Program
      3 
      4 TIARA (Fujitsu Etherstar) NIC driver for Etherboot
      5 Copyright (c) Ken Yap 1998
      6 
      7 Information gleaned from:
      8 
      9 TIARA.ASM Packet driver by Brian Fisher, Queens U, Kingston, Ontario
     10 Fujitsu MB86960 spec sheet (different chip but same family)
     11 ***************************************************************************/
     12 
     13 /*
     14  * This program is free software; you can redistribute it and/or
     15  * modify it under the terms of the GNU General Public License as
     16  * published by the Free Software Foundation; either version 2, or (at
     17  * your option) any later version.
     18  */
     19 
     20 /* to get some global routines like printf */
     21 #include "etherboot.h"
     22 /* to get the interface to the body of the program */
     23 #include "nic.h"
     24 #include "cards.h"
     25 
     26 /*
     27 	EtherStar I/O Register offsets
     28 */
     29 
     30 /* Offsets of registers */
     31 #define	DLCR_XMIT_STAT	0x00
     32 #define	DLCR_XMIT_MASK	0x01
     33 #define	DLCR_RECV_STAT	0x02
     34 #define	DLCR_RECV_MASK	0x03
     35 #define	DLCR_XMIT_MODE	0x04
     36 #define	DLCR_RECV_MODE	0x05
     37 #define	DLCR_ENABLE	0x06
     38 #define	DLCR_TDR_LOW	0x07
     39 #define	DLCR_NODE_ID	0x08
     40 #define	DLCR_TDR_HIGH	0x0F
     41 #define	BMPR_MEM_PORT	0x10
     42 #define	BMPR_PKT_LEN	0x12
     43 #define	BMPR_DMA_ENABLE	0x14
     44 #define	PROM_ID		0x18
     45 
     46 #define	TMST		0x80
     47 #define	TMT_OK		0x80
     48 #define	TMT_16COLL	0x02
     49 #define	BUF_EMPTY	0x40
     50 
     51 #define	CARD_DISABLE	0x80	/* written to DLCR_ENABLE to disable card */
     52 #define	CARD_ENABLE	0	/* written to DLCR_ENABLE to enable card */
     53 
     54 #define	CLEAR_STATUS	0x0F	/* used to clear status info */
     55 /*
     56 	00001111B
     57 	!!!!!!!!--------
     58 	!!!!!!!+--------CLEAR BUS WRITE ERROR
     59 	!!!!!!+---------CLEAR 16 COLLISION
     60 	!!!!!+----------CLEAR COLLISION
     61 	!!!!+-----------CLEAR UNDERFLOW
     62 	!!!+------------NC
     63 	!!+-------------NC
     64 	!+--------------NC
     65 	+---------------NC
     66 */
     67 
     68 #define	NO_TX_IRQS	0	/* written to clear transmit IRQs */
     69 
     70 #define	CLR_RCV_STATUS	0xCF	/* clears receive status */
     71 
     72 #define	EN_RCV_IRQS	0x80	/* enable receive interrupts */
     73 /*
     74 	10000000B
     75 	!!!!!!!!--------
     76 	!!!!!!!+--------ENABLE OVERFLOW
     77 	!!!!!!+---------ENABLE CRC
     78 	!!!!!+----------ENABLE ALIGN
     79 	!!!!+-----------ENABLE SHORT PKT
     80 	!!!+------------DISABLE REMOTE RESET
     81 	!!+-------------RESERVED
     82 	!+--------------RESERVED
     83 	+---------------ENABLE PKT READY
     84 */
     85 
     86 #define	XMIT_MODE	0x02
     87 /*
     88 	00000010B
     89 	!!!!!!!!---------ENABLE CARRIER DETECT
     90 	!!!!!!!+---------DISABLE LOOPBACK
     91 */
     92 
     93 #define	RECV_MODE	0x02
     94 /*
     95 	00000010B
     96 	!!!!!!!!---------ACCEPT ALL PACKETS
     97 	!!!!!!!+---------ACCEPT PHYSICAL, MULTICAST, AND
     98 	!!!!!!+----------BROADCAST PACKETS
     99 	!!!!!+-----------DISABLE REMOTE RESET
    100 	!!!!+------------DISABLE SHORT PACKETS
    101 	!!!+-------------USE 6 BYTE ADDRESS
    102 	!!+--------------NC
    103 	!+---------------NC
    104 	+----------------DISABLE CRC TEST MODE
    105 */
    106 
    107 /* NIC specific static variables go here */
    108 
    109 static unsigned short	ioaddr;
    110 
    111 /**************************************************************************
    112 RESET - Reset adapter
    113 ***************************************************************************/
    114 static void tiara_reset(struct nic *nic)
    115 {
    116 	int		i;
    117 
    118 	outb(CARD_DISABLE, ioaddr + DLCR_ENABLE);
    119 	outb(CLEAR_STATUS, ioaddr + DLCR_XMIT_STAT);
    120 	outb(NO_TX_IRQS, ioaddr + DLCR_XMIT_MASK);
    121 	outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
    122 	outb(XMIT_MODE, ioaddr + DLCR_XMIT_MODE);
    123 	outb(RECV_MODE, ioaddr + DLCR_RECV_MODE);
    124 	/* Vacuum recv buffer */
    125 	while ((inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY) == 0)
    126 		inb(ioaddr + BMPR_MEM_PORT);
    127 	/* Set node address */
    128 	for (i = 0; i < ETH_ALEN; ++i)
    129 		outb(nic->node_addr[i], ioaddr + DLCR_NODE_ID + i);
    130 	outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
    131 	outb(CARD_ENABLE, ioaddr + DLCR_ENABLE);
    132 }
    133 
    134 /**************************************************************************
    135 POLL - Wait for a frame
    136 ***************************************************************************/
    137 static int tiara_poll(struct nic *nic)
    138 {
    139 	unsigned int		len;
    140 
    141 	if (inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY)
    142 		return (0);
    143 	/* Ack packet */
    144 	outw(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
    145 	len = inw(ioaddr + BMPR_MEM_PORT);		/* throw away status */
    146 	len = inw(ioaddr + BMPR_MEM_PORT);
    147 	/* Drop overlength packets */
    148 	if (len > ETH_FRAME_LEN)
    149 		return (0);		/* should we drain the buffer? */
    150 	insw(ioaddr + BMPR_MEM_PORT, nic->packet, len / 2);
    151 	/* If it's our own, drop it */
    152 	if (memcmp(nic->packet + ETH_ALEN, nic->node_addr, ETH_ALEN) == 0)
    153 		return (0);
    154 	nic->packetlen = len;
    155 	return (1);
    156 }
    157 
    158 /**************************************************************************
    159 TRANSMIT - Transmit a frame
    160 ***************************************************************************/
    161 static void tiara_transmit(
    162 struct nic *nic,
    163 const char *d,			/* Destination */
    164 unsigned int t,			/* Type */
    165 unsigned int s,			/* size */
    166 const char *p)			/* Packet */
    167 {
    168 	unsigned int	len;
    169 	unsigned long	time;
    170 
    171 	len = s + ETH_HLEN;
    172 	if (len < ETH_ZLEN)
    173 		len = ETH_ZLEN;
    174 	t = htons(t);
    175 	outsw(ioaddr + BMPR_MEM_PORT, d, ETH_ALEN / 2);
    176 	outsw(ioaddr + BMPR_MEM_PORT, nic->node_addr, ETH_ALEN / 2);
    177 	outw(t, ioaddr + BMPR_MEM_PORT);
    178 	outsw(ioaddr + BMPR_MEM_PORT, p, s / 2);
    179 	if (s & 1)					/* last byte */
    180 		outb(p[s-1], ioaddr + BMPR_MEM_PORT);
    181 	while (s++ < ETH_ZLEN - ETH_HLEN)	/* pad */
    182 		outb(0, ioaddr + BMPR_MEM_PORT);
    183 	outw(len | (TMST << 8), ioaddr + BMPR_PKT_LEN);
    184 	/* wait for transmit complete */
    185 	time = currticks() + TICKS_PER_SEC;		/* wait one second */
    186 	while (currticks() < time && (inb(ioaddr) & (TMT_OK|TMT_16COLL)) == 0)
    187 		;
    188 	if ((inb(ioaddr) & (TMT_OK|TMT_16COLL)) == 0)
    189 		printf("Tiara timed out on transmit\n");
    190 	/* Do we need to ack the transmit? */
    191 }
    192 
    193 /**************************************************************************
    194 DISABLE - Turn off ethernet interface
    195 ***************************************************************************/
    196 static void tiara_disable(struct nic *nic)
    197 {
    198 	/* Apparently only a power down can do this properly */
    199 	outb(CARD_DISABLE, ioaddr + DLCR_ENABLE);
    200 }
    201 
    202 static int tiara_probe1(struct nic *nic)
    203 {
    204 	/* Hope all the Tiara cards have this vendor prefix */
    205 	static char	vendor_prefix[] = { 0x08, 0x00, 0x1A };
    206 	static char	all_ones[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
    207 	int		i;
    208 
    209 	for (i = 0; i < ETH_ALEN; ++i)
    210 		nic->node_addr[i] = inb(ioaddr + PROM_ID + i);
    211 	if (memcmp(nic->node_addr, vendor_prefix, sizeof(vendor_prefix)) != 0)
    212 		return (0);
    213 	if (memcmp(nic->node_addr, all_ones, sizeof(all_ones)) == 0)
    214 		return (0);
    215 	printf("\nTiara ioaddr %#hX, addr %!\n", ioaddr, nic->node_addr);
    216 	return (1);
    217 }
    218 
    219 /**************************************************************************
    220 PROBE - Look for an adapter, this routine's visible to the outside
    221 ***************************************************************************/
    222 struct nic *tiara_probe(struct nic *nic, unsigned short *probe_addrs)
    223 {
    224 	/* missing entries are addresses usually already used */
    225 	static unsigned short	io_addrs[] = {
    226 		0x100, 0x120, 0x140, 0x160,
    227 		0x180, 0x1A0, 0x1C0, 0x1E0,
    228 		0x200, 0x220, 0x240, /*Par*/
    229 		0x280, 0x2A0, 0x2C0, /*Ser*/
    230 		0x300, 0x320, 0x340, /*Par*/
    231 		0x380, /*Vid,Par*/ 0x3C0, /*Ser*/
    232 		0x0
    233 	};
    234 	unsigned short		*p;
    235 
    236 	/* if probe_addrs is 0, then routine can use a hardwired default */
    237 	if (probe_addrs == 0)
    238 		probe_addrs = io_addrs;
    239 	for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
    240 		if (tiara_probe1(nic))
    241 			break;
    242 	/* if board found */
    243 	if (ioaddr != 0)
    244 	{
    245 		tiara_reset(nic);
    246 		/* point to NIC specific routines */
    247 		nic->reset = tiara_reset;
    248 		nic->poll = tiara_poll;
    249 		nic->transmit = tiara_transmit;
    250 		nic->disable = tiara_disable;
    251 		return nic;
    252 	}
    253 	else
    254 		return (0);
    255 }
    256