• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ***************************************************************************/
tiara_reset(struct nic * nic)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 ***************************************************************************/
tiara_poll(struct nic * nic)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 ***************************************************************************/
tiara_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)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 ***************************************************************************/
tiara_disable(struct nic * nic)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 
tiara_probe1(struct nic * nic)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 ***************************************************************************/
tiara_probe(struct nic * nic,unsigned short * probe_addrs)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