xref: /minix/minix/drivers/net/rtl8139/rtl8139.c (revision e3b78ef1)
1 /*
2  * rtl8139.c
3  *
4  * This file contains a ethernet device driver for Realtek rtl8139 based
5  * ethernet cards.
6  *
7  * Created:	Aug 2003 by Philip Homburg <philip@cs.vu.nl>
8  * Changes:
9  *   Aug 15, 2004   sync alarms replace watchdogs timers  (Jorrit N. Herder)
10  *   May 02, 2004   flag alarms replace micro_elapsed()  (Jorrit N. Herder)
11  *
12  */
13 
14 #define VERBOSE 0 /* Verbose debugging output */
15 #define RTL8139_FKEY 0 /* Use function key to dump RTL8139 status */
16 
17 #include "rtl8139.h"
18 
19 static re_t re_state;
20 
21 static int re_instance;
22 
23 static unsigned my_inb(u16_t port) {
24 	u32_t value;
25 	int s;
26 	if ((s=sys_inb(port, &value)) !=OK)
27 		printf("RTL8139: warning, sys_inb failed: %d\n", s);
28 	return value;
29 }
30 static unsigned my_inw(u16_t port) {
31 	u32_t value;
32 	int s;
33 	if ((s=sys_inw(port, &value)) !=OK)
34 		printf("RTL8139: warning, sys_inw failed: %d\n", s);
35 	return value;
36 }
37 static unsigned my_inl(u16_t port) {
38 	u32_t value;
39 	int s;
40 	if ((s=sys_inl(port, &value)) !=OK)
41 		printf("RTL8139: warning, sys_inl failed: %d\n", s);
42 	return value;
43 }
44 #define rl_inb(port, offset)	(my_inb((port) + (offset)))
45 #define rl_inw(port, offset)	(my_inw((port) + (offset)))
46 #define rl_inl(port, offset)	(my_inl((port) + (offset)))
47 
48 static void my_outb(u16_t port, u8_t value) {
49 	int s;
50 	if ((s=sys_outb(port, value)) !=OK)
51 		printf("RTL8139: warning, sys_outb failed: %d\n", s);
52 }
53 static void my_outw(u16_t port, u16_t value) {
54 	int s;
55 	if ((s=sys_outw(port, value)) !=OK)
56 		printf("RTL8139: warning, sys_outw failed: %d\n", s);
57 }
58 static void my_outl(u16_t port, u32_t value) {
59 	int s;
60 	if ((s=sys_outl(port, value)) !=OK)
61 		printf("RTL8139: warning, sys_outl failed: %d\n", s);
62 }
63 #define rl_outb(port, offset, value)	(my_outb((port) + (offset), (value)))
64 #define rl_outw(port, offset, value)	(my_outw((port) + (offset), (value)))
65 #define rl_outl(port, offset, value)	(my_outl((port) + (offset), (value)))
66 
67 static int rl_init(unsigned int instance, ether_addr_t *addr);
68 static int rl_probe(re_t *rep, unsigned int skip);
69 static void rl_init_buf(re_t *rep);
70 static void rl_init_hw(re_t *rep, ether_addr_t *addr);
71 static void rl_reset_hw(re_t *rep);
72 static void rl_confaddr(re_t *rep, ether_addr_t *addr);
73 static void rl_stop(void);
74 static void rl_rec_mode(re_t *rep);
75 static void rl_mode(unsigned int mode);
76 static ssize_t rl_recv(struct netdriver_data *data, size_t max);
77 static int rl_send(struct netdriver_data *data, size_t size);
78 static void rl_intr(unsigned int mask);
79 static void rl_check_ints(re_t *rep);
80 static void rl_report_link(re_t *rep);
81 #if VERBOSE
82 static void mii_print_techab(u16_t techab);
83 static void mii_print_stat_speed(u16_t stat, u16_t extstat);
84 #endif
85 static void rl_clear_rx(re_t *rep);
86 static void rl_do_reset(re_t *rep);
87 static void rl_stat(eth_stat_t *stat);
88 static void rl_other(const message *m_ptr, int ipc_status);
89 static void rl_dump(void);
90 #if 0
91 static void dump_phy(re_t *rep);
92 #endif
93 static int rl_handler(re_t *rep);
94 static void rl_alarm(clock_t stamp);
95 static void tell_iommu(vir_bytes start, size_t size, int pci_bus, int
96 	pci_dev, int pci_func);
97 
98 static const struct netdriver rl_table = {
99 	.ndr_init	= rl_init,
100 	.ndr_stop	= rl_stop,
101 	.ndr_mode	= rl_mode,
102 	.ndr_recv	= rl_recv,
103 	.ndr_send	= rl_send,
104 	.ndr_stat	= rl_stat,
105 	.ndr_intr	= rl_intr,
106 	.ndr_alarm	= rl_alarm,
107 	.ndr_other	= rl_other,
108 };
109 
110 /*===========================================================================*
111  *				main					     *
112  *===========================================================================*/
113 int main(int argc, char *argv[])
114 {
115 
116 	env_setargs(argc, argv);
117 
118 	netdriver_task(&rl_table);
119 
120 	return 0;
121 }
122 
123 /*===========================================================================*
124  *				rl_intr					     *
125  *===========================================================================*/
126 static void rl_intr(unsigned int __unused mask)
127 {
128 	re_t *rep;
129 	int s;
130 
131 	rep = &re_state;
132 
133 	/* Run interrupt handler at driver level. */
134 	rl_handler(rep);
135 
136 	/* Reenable interrupts for this hook. */
137 	if ((s = sys_irqenable(&rep->re_hook_id)) != OK)
138 		printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
139 
140 	/* Perform tasks based on the flagged conditions. */
141 	rl_check_ints(rep);
142 }
143 
144 /*===========================================================================*
145  *				rl_other				     *
146  *===========================================================================*/
147 static void rl_other(const message *m_ptr, int ipc_status)
148 {
149 	if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR)
150 		rl_dump();
151 }
152 
153 /*===========================================================================*
154  *				rl_stop					     *
155  *===========================================================================*/
156 static void rl_stop(void)
157 {
158 	re_t *rep;
159 
160 	rep = &re_state;
161 
162 	rl_outb(rep->re_base_port, RL_CR, 0);
163 }
164 
165 /*===========================================================================*
166  *				rl_dump					     *
167  *===========================================================================*/
168 static void rl_dump(void)
169 {
170 	re_t *rep;
171 
172 	rep= &re_state;
173 
174 	printf("\n");
175 	printf("Realtek RTL 8139 statistics of instance %d:\n", re_instance);
176 
177 	printf("recvErr    :%8ld\t", rep->re_stat.ets_recvErr);
178 	printf("sendErr    :%8ld\t", rep->re_stat.ets_sendErr);
179 	printf("OVW        :%8ld\n", rep->re_stat.ets_OVW);
180 
181 	printf("CRCerr     :%8ld\t", rep->re_stat.ets_CRCerr);
182 	printf("frameAll   :%8ld\t", rep->re_stat.ets_frameAll);
183 	printf("missedP    :%8ld\n", rep->re_stat.ets_missedP);
184 
185 	printf("packetR    :%8ld\t", rep->re_stat.ets_packetR);
186 	printf("packetT    :%8ld\t", rep->re_stat.ets_packetT);
187 	printf("transDef   :%8ld\n", rep->re_stat.ets_transDef);
188 
189 	printf("collision  :%8ld\t", rep->re_stat.ets_collision);
190 	printf("transAb    :%8ld\t", rep->re_stat.ets_transAb);
191 	printf("carrSense  :%8ld\n", rep->re_stat.ets_carrSense);
192 
193 	printf("fifoUnder  :%8ld\t", rep->re_stat.ets_fifoUnder);
194 	printf("fifoOver   :%8ld\t", rep->re_stat.ets_fifoOver);
195 	printf("CDheartbeat:%8ld\n", rep->re_stat.ets_CDheartbeat);
196 
197 	printf("OWC        :%8ld\t", rep->re_stat.ets_OWC);
198 
199 	printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
200 		rl_inw(rep->re_base_port, RL_TSAD),
201 		rl_inl(rep->re_base_port, RL_TSD0+0*4),
202 		rl_inl(rep->re_base_port, RL_TSD0+1*4),
203 		rl_inl(rep->re_base_port, RL_TSD0+2*4),
204 		rl_inl(rep->re_base_port, RL_TSD0+3*4));
205 	printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
206 		rep->re_tx_head, rep->re_tx_tail,
207 		rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
208 		rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
209 }
210 
211 /*===========================================================================*
212  *				rl_mode					     *
213  *===========================================================================*/
214 static void rl_mode(unsigned int mode)
215 {
216 	re_t *rep;
217 
218 	rep= &re_state;
219 
220 	rep->re_mode = mode;
221 
222 	rl_rec_mode(rep);
223 }
224 
225 /*===========================================================================*
226  *				rl_init					     *
227  *===========================================================================*/
228 static int rl_init(unsigned int instance, ether_addr_t *addr)
229 {
230 /* Initialize the rtl8139 driver. */
231 	re_t *rep;
232 #if RTL8139_FKEY
233 	int r, fkeys, sfkeys;
234 #endif
235 
236 	/* Initialize driver state. */
237 	rep= &re_state;
238 	memset(rep, 0, sizeof(*rep));
239 
240 	rep->re_link_up= -1;	/* Unknown */
241 	rep->re_ertxth= RL_TSD_ERTXTH_8;
242 	strlcpy(rep->re_name, "rtl8139#0", sizeof(rep->re_name));
243 	rep->re_name[8] += instance;
244 
245 	re_instance = instance;
246 
247 	/* Try to find a matching device. */
248 	if (!rl_probe(rep, instance))
249 		return ENXIO;
250 
251 	/* Claim buffer memory. */
252 	rl_init_buf(rep);
253 
254 	/* Initialize the device we found. */
255 	rl_init_hw(rep, addr);
256 
257 #if VERBOSE
258 	/* Report initial link status. */
259 	rl_report_link(rep);
260 #endif
261 
262 	/* Use a synchronous alarm instead of a watchdog timer. */
263 	sys_setalarm(sys_hz(), 0);
264 
265 #if RTL8139_FKEY
266 	/* Observe some function key for debug dumps. */
267 	fkeys = sfkeys = 0; bit_set(sfkeys, 9);
268 	if ((r = fkey_map(&fkeys, &sfkeys)) != OK)
269 	    printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r);
270 #endif
271 
272 	return OK;
273 }
274 
275 /*===========================================================================*
276  *				rl_probe				     *
277  *===========================================================================*/
278 static int rl_probe(re_t *rep, unsigned int skip)
279 {
280 	int r, devind;
281 	u16_t cr, vid, did;
282 	u32_t bar;
283 	u8_t ilr;
284 #if VERBOSE
285 	char *dname;
286 #endif
287 
288 	pci_init();
289 
290 	r= pci_first_dev(&devind, &vid, &did);
291 	if (r == 0)
292 		return 0;
293 
294 	while (skip--)
295 	{
296 		r= pci_next_dev(&devind, &vid, &did);
297 		if (!r)
298 			return 0;
299 	}
300 
301 #if VERBOSE	/* stay silent at startup, can always get status later */
302 	dname= pci_dev_name(vid, did);
303 	if (!dname)
304 		dname= "unknown device";
305 	printf("%s: ", rep->re_name);
306 	printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind));
307 #endif
308 	pci_reserve(devind);
309 
310 	/* Enable bus mastering if necessary. */
311 	cr = pci_attr_r16(devind, PCI_CR);
312 	/* printf("cr = 0x%x\n", cr); */
313 	if (!(cr & PCI_CR_MAST_EN))
314 		pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN);
315 
316 	bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
317 	if (bar < 0x400) {
318 		panic("base address is not properly configured");
319 	}
320 	rep->re_base_port= bar;
321 
322 	ilr= pci_attr_r8(devind, PCI_ILR);
323 	rep->re_irq= ilr;
324 #if VERBOSE
325 	printf("%s: using I/O address 0x%lx, IRQ %d\n",
326 		rep->re_name, (unsigned long)bar, ilr);
327 #endif
328 
329 	return TRUE;
330 }
331 
332 /*===========================================================================*
333  *				rl_init_buf				     *
334  *===========================================================================*/
335 static void rl_init_buf(re_t *rep)
336 {
337 	size_t rx_bufsize, tx_bufsize, tot_bufsize;
338 	phys_bytes buf;
339 	char *mallocbuf;
340 	int i, off;
341 
342 	/* Allocate receive and transmit buffers */
343 	tx_bufsize= ETH_MAX_PACK_SIZE_TAGGED;
344 	if (tx_bufsize % 4)
345 		tx_bufsize += 4-(tx_bufsize % 4);	/* Align */
346 	rx_bufsize= RX_BUFSIZE;
347 	tot_bufsize= N_TX_BUF*tx_bufsize + rx_bufsize;
348 
349 	if (tot_bufsize % 4096)
350 		tot_bufsize += 4096-(tot_bufsize % 4096);
351 
352 #define BUF_ALIGNMENT (64*1024)
353 
354 	if (!(mallocbuf = alloc_contig(BUF_ALIGNMENT + tot_bufsize, 0, &buf)))
355 		panic("Couldn't allocate kernel buffer");
356 
357 	/* click-align mallocced buffer. this is what we used to get
358 	 * from kmalloc() too.
359 	 */
360 	if((off = buf % BUF_ALIGNMENT)) {
361 		mallocbuf += BUF_ALIGNMENT - off;
362 		buf += BUF_ALIGNMENT - off;
363 	}
364 
365 	tell_iommu((vir_bytes)mallocbuf, tot_bufsize, 0, 0, 0);
366 
367 	for (i= 0; i<N_TX_BUF; i++)
368 	{
369 		rep->re_tx[i].ret_buf= buf;
370 		rep->re_tx[i].v_ret_buf= mallocbuf;
371 		buf += tx_bufsize;
372 		mallocbuf += tx_bufsize;
373 	}
374 	rep->re_rx_buf= buf;
375 	rep->v_re_rx_buf= mallocbuf;
376 }
377 
378 /*===========================================================================*
379  *				rl_init_hw				     *
380  *===========================================================================*/
381 static void rl_init_hw(re_t *rep, ether_addr_t *addr)
382 {
383 #if VERBOSE
384 	int i;
385 #endif
386 	int s;
387 
388 	/* Set the interrupt handler. The policy is to only send HARD_INT
389 	 * notifications. Don't reenable interrupts automatically. The id
390 	 * that is passed back is the interrupt line number.
391 	 */
392 	rep->re_hook_id = rep->re_irq;
393 	if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK)
394 		printf("RTL8139: error, couldn't set IRQ policy: %d\n", s);
395 
396 	rl_reset_hw(rep);
397 
398 	if ((s=sys_irqenable(&rep->re_hook_id)) != OK)
399 		printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
400 
401 #if VERBOSE	/* stay silent during startup, can always get status later */
402 	if (rep->re_model) {
403 		printf("%s: model %s\n", rep->re_name, rep->re_model);
404 	} else
405 	{
406 		printf("%s: unknown model 0x%08x\n",
407 			rep->re_name,
408 			rl_inl(rep->re_base_port, RL_TCR) &
409 			(RL_TCR_HWVER_AM | RL_TCR_HWVER_BM));
410 	}
411 #endif
412 
413 	rl_confaddr(rep, addr);
414 
415 #if VERBOSE
416 	printf("%s: Ethernet address ", rep->re_name);
417 	for (i= 0; i < 6; i++)
418 		printf("%x%c", addr->ea_addr[i], i < 5 ? ':' : '\n');
419 #endif
420 }
421 
422 /*===========================================================================*
423  *				rl_reset_hw				     *
424  *===========================================================================*/
425 static void rl_reset_hw(re_t *rep)
426 {
427 	port_t port;
428 	u32_t t;
429 	phys_bytes bus_buf;
430 	int i;
431 
432 	port= rep->re_base_port;
433 
434 #if 0
435 	/* Reset the PHY */
436 	rl_outb(port, RL_BMCR, MII_CTRL_RST);
437 	SPIN_UNTIL(!(rl_inb(port, RL_BMCR) & MII_CTRL_RST), 1000000);
438 	if (rl_inb(port, RL_BMCR) & MII_CTRL_RST)
439 		panic("reset PHY failed to complete");
440 #endif
441 
442 	/* Reset the device */
443 #if VERBOSE
444 	printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
445 		port, rl_inb(port, RL_CR));
446 #endif
447 	rl_outb(port, RL_CR, RL_CR_RST);
448 	SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RST), 1000000);
449 #if VERBOSE
450 	printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
451 		port, rl_inb(port, RL_CR));
452 #endif
453 	if (rl_inb(port, RL_CR) & RL_CR_RST)
454 		printf("rtl8139: reset failed to complete");
455 
456 	t= rl_inl(port, RL_TCR);
457 	switch(t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM))
458 	{
459 	case RL_TCR_HWVER_RTL8139: rep->re_model= "RTL8139"; break;
460 	case RL_TCR_HWVER_RTL8139A: rep->re_model= "RTL8139A"; break;
461 	case RL_TCR_HWVER_RTL8139AG:
462 		rep->re_model= "RTL8139A-G / RTL8139C";
463 		break;
464 	case RL_TCR_HWVER_RTL8139B:
465 		rep->re_model= "RTL8139B / RTL8130";
466 		break;
467 	case RL_TCR_HWVER_RTL8100: rep->re_model= "RTL8100"; break;
468 	case RL_TCR_HWVER_RTL8100B:
469 		rep->re_model= "RTL8100B/RTL8139D";
470 		break;
471 	case RL_TCR_HWVER_RTL8139CP: rep->re_model= "RTL8139C+"; break;
472 	case RL_TCR_HWVER_RTL8101: rep->re_model= "RTL8101"; break;
473 	default:
474 		rep->re_model= NULL;
475 		break;
476 	}
477 
478 #if 0
479 	printf("REVID: 0x%02x\n", rl_inb(port, RL_REVID));
480 #endif
481 
482 	/* Intialize Rx */
483 
484 	/* Should init multicast mask */
485 #if 0
486 08-0f	R/W	MAR[0-7]	multicast
487 #endif
488 	bus_buf= vm_1phys2bus(rep->re_rx_buf);
489 	rl_outl(port, RL_RBSTART, bus_buf);
490 
491 	/* Initialize Tx */
492 	for (i= 0; i<N_TX_BUF; i++)
493 	{
494 		rep->re_tx[i].ret_busy= FALSE;
495 		bus_buf= vm_1phys2bus(rep->re_tx[i].ret_buf);
496 		rl_outl(port, RL_TSAD0+i*4, bus_buf);
497 		t= rl_inl(port, RL_TSD0+i*4);
498 		assert(t & RL_TSD_OWN);
499 	}
500 
501 	rep->re_tx_busy = 0;
502 
503 #if 0
504 	dump_phy(rep);
505 #endif
506 
507 	t= rl_inw(port, RL_IMR);
508 	rl_outw(port, RL_IMR, t | (RL_IMR_SERR | RL_IMR_TIMEOUT |
509 		RL_IMR_LENCHG));
510 
511 	t= rl_inw(port, RL_IMR);
512 	rl_outw(port, RL_IMR, t | (RL_IMR_FOVW | RL_IMR_PUN |
513 		RL_IMR_RXOVW | RL_IMR_RER | RL_IMR_ROK));
514 
515 	t= rl_inw(port, RL_IMR);
516 	rl_outw(port, RL_IMR, t | (RL_IMR_TER | RL_IMR_TOK));
517 
518 	t= rl_inb(port, RL_CR);
519 	rl_outb(port, RL_CR, t | RL_CR_RE);
520 
521 	t= rl_inb(port, RL_CR);
522 	rl_outb(port, RL_CR, t | RL_CR_TE);
523 
524 	rl_outl(port, RL_RCR, RX_BUFBITS);
525 
526 	t= rl_inl(port, RL_TCR);
527 	rl_outl(port, RL_TCR, t | RL_TCR_IFG_STD);
528 }
529 
530 /*===========================================================================*
531  *				rl_confaddr				     *
532  *===========================================================================*/
533 static void rl_confaddr(re_t *rep, ether_addr_t *addr)
534 {
535 	static char eakey[]= RL_ENVVAR "#_EA";
536 	static char eafmt[]= "x:x:x:x:x:x";
537 
538 	int i;
539 	port_t port;
540 	u32_t w;
541 	long v;
542 
543 	/* User defined ethernet address? */
544 	eakey[sizeof(RL_ENVVAR)-1]= '0' + re_instance;
545 
546 	port= rep->re_base_port;
547 
548 	for (i= 0; i < 6; i++)
549 	{
550 		if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
551 			break;
552 		addr->ea_addr[i]= v;
553 	}
554 
555 	if (i != 0 && i != 6) env_panic(eakey);	/* It's all or nothing */
556 
557 	/* Should update ethernet address in hardware */
558 	if (i == 6)
559 	{
560 		port= rep->re_base_port;
561 		rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG);
562 		w= 0;
563 		for (i= 0; i<4; i++)
564 			w |= (addr->ea_addr[i] << (i*8));
565 		rl_outl(port, RL_IDR, w);
566 		w= 0;
567 		for (i= 4; i<6; i++)
568 			w |= (addr->ea_addr[i] << ((i-4)*8));
569 		rl_outl(port, RL_IDR+4, w);
570 		rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL);
571 	}
572 
573 	/* Get ethernet address */
574 	for (i= 0; i<6; i++)
575 		addr->ea_addr[i]= rl_inb(port, RL_IDR+i);
576 }
577 
578 /*===========================================================================*
579  *				rl_rec_mode				     *
580  *===========================================================================*/
581 static void rl_rec_mode(re_t *rep)
582 {
583 	port_t port;
584 	u32_t rcr;
585 
586 	port= rep->re_base_port;
587 	rcr= rl_inl(port, RL_RCR);
588 	rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP);
589 	if (rep->re_mode & NDEV_PROMISC)
590 		rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP;
591 	if (rep->re_mode & NDEV_BROAD)
592 		rcr |= RL_RCR_AB;
593 	if (rep->re_mode & NDEV_MULTI)
594 		rcr |= RL_RCR_AM;
595 	rcr |= RL_RCR_APM;
596 
597 	rl_outl(port, RL_RCR, rcr);
598 }
599 
600 /*===========================================================================*
601  *				rl_recv					     *
602  *===========================================================================*/
603 static ssize_t rl_recv(struct netdriver_data *data, size_t max)
604 {
605 	int o, s;
606 	port_t port;
607 	unsigned amount, totlen, packlen;
608 	u16_t d_start, d_end;
609 	u32_t l, rxstat;
610 	re_t *rep;
611 
612 	rep= &re_state;
613 
614 	if (rep->re_clear_rx)
615 		return SUSPEND;	/* Buffer overflow */
616 
617 	port= rep->re_base_port;
618 
619 	if (rl_inb(port, RL_CR) & RL_CR_BUFE)
620 	{
621 		/* Receive buffer is empty, suspend */
622 		return SUSPEND;
623 	}
624 
625 	d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
626 	d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
627 
628 #if RX_BUFSIZE <= USHRT_MAX
629 	if (d_start >= RX_BUFSIZE)
630 	{
631 		printf("rl_recv: strange value in RL_CAPR: 0x%x\n",
632 			rl_inw(port, RL_CAPR));
633 		d_start %= RX_BUFSIZE;
634 	}
635 #endif
636 
637 	if (d_end > d_start)
638 		amount= d_end-d_start;
639 	else
640 		amount= d_end+RX_BUFSIZE - d_start;
641 
642 	rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
643 
644 	/* Should convert from little endian to host byte order */
645 
646 	if (!(rxstat & RL_RXS_ROK))
647 	{
648 		printf("rxstat = 0x%08x\n", rxstat);
649 		printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%x\n",
650 			d_start, d_end, rxstat);
651 		panic("received packet not OK");
652 	}
653 	totlen= (rxstat >> RL_RXS_LEN_S);
654 	if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE)
655 	{
656 		/* Someting went wrong */
657 		printf(
658 		"rl_recv: bad length (%u) in status 0x%08x at offset 0x%x\n",
659 			totlen, rxstat, d_start);
660 		printf(
661 		"d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
662 			d_start, d_end, totlen, rxstat);
663 		panic(NULL);
664 	}
665 
666 #if 0
667 	printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
668 		d_start, d_end, totlen, rxstat);
669 #endif
670 
671 	if (totlen+4 > amount)
672 	{
673 		printf("rl_recv: packet not yet ready\n");
674 		return SUSPEND;
675 	}
676 
677 	/* Should subtract the CRC */
678 	packlen = MIN(totlen - ETH_CRC_SIZE, max);
679 
680 	/* Copy out the data.  The packet may wrap in the receive buffer. */
681 	o = (d_start+4) % RX_BUFSIZE;
682 	s = MIN(RX_BUFSIZE - o, packlen);
683 
684 	netdriver_copyout(data, 0, rep->v_re_rx_buf + o, s);
685 	if (s < packlen)
686 		netdriver_copyout(data, s, rep->v_re_rx_buf, packlen - s);
687 
688 	rep->re_stat.ets_packetR++;
689 
690 	/* Avoid overflow in 16-bit computations */
691 	l= d_start;
692 	l += totlen+4;
693 	l= (l+3) & ~3;	/* align */
694 	if (l >= RX_BUFSIZE)
695 	{
696 		l -= RX_BUFSIZE;
697 		assert(l < RX_BUFSIZE);
698 	}
699 	rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
700 
701 	return packlen;
702 }
703 
704 /*===========================================================================*
705  *				rl_send					     *
706  *===========================================================================*/
707 static int rl_send(struct netdriver_data *data, size_t size)
708 {
709 	int tx_head;
710 	re_t *rep;
711 
712 	rep= &re_state;
713 
714 	tx_head= rep->re_tx_head;
715 	if (rep->re_tx[tx_head].ret_busy)
716 		return SUSPEND;
717 
718 	netdriver_copyin(data, 0, rep->re_tx[tx_head].v_ret_buf, size);
719 
720 	rl_outl(rep->re_base_port, RL_TSD0+tx_head*4, rep->re_ertxth | size);
721 	rep->re_tx[tx_head].ret_busy= TRUE;
722 	rep->re_tx_busy++;
723 
724 	if (++tx_head == N_TX_BUF)
725 		tx_head= 0;
726 	assert(tx_head < RL_N_TX);
727 	rep->re_tx_head= tx_head;
728 
729 	return OK;
730 }
731 
732 /*===========================================================================*
733  *				rl_check_ints				     *
734  *===========================================================================*/
735 static void rl_check_ints(re_t *rep)
736 {
737 #if 0
738 10-1f	R/W	TSD[0-3]	Transmit Status of Descriptor [0-3]
739 	31	R	CRS	Carrier Sense Lost
740 	30	R	TABT	Transmit Abort
741 	29	R	OWC	Out of Window Collision
742 	27-24	R	NCC[3-0] Number of Collision Count
743 	23-22			reserved
744 	21-16	R/W	ERTXH[5-0] Early Tx Threshold
745 	15	R	TOK	Transmit OK
746 	14	R	TUN	Transmit FIFO Underrun
747 	13	R/W	OWN	OWN
748 	12-0	R/W	SIZE	Descriptor Size
749 3e-3f	R/W	ISR		Interrupt Status Register
750 	6	R/W	FOVW	Fx FIFO Overflow Interrupt
751 	5	R/W	PUN/LinkChg Packet Underrun / Link Change Interrupt
752 	3	R/W	TER	Transmit Error Interrupt
753 	2	R/W	TOK	Transmit OK Interrupt
754 3e-3f	R/W	ISR		Interrupt Status Register
755 	15	R/W	SERR	System Error Interrupt
756 	14	R/W	TimeOut	Time Out Interrupt
757 	13	R/W	LenChg	Cable Length Change Interrupt
758 3e-3f	R/W	ISR		Interrupt Status Register
759 	4	R/W	RXOVW	Rx Buffer Overflow Interrupt
760 	1	R/W	RER	Receive Error Interrupt
761 	0	R/W	ROK	Receive OK Interrupt
762 4c-4f	R/W	MPC		Missed Packet Counter
763 60-61	R	TSAD		Transmit Status of All Descriptors
764 	15-12	R	TOK[3-0] TOK bit of Descriptor [3-0]
765 	11-8	R	TUN[3-0] TUN bit of Descriptor [3-0]
766 	7-4	R	TABT[3-0] TABT bit of Descriptor [3-0]
767 	3-0     R       OWN[3-0] OWN bit of Descriptor [3-0]
768 6c-6d	R	DIS		Disconnect Counter
769 	15-0	R	DCNT	Disconnect Counter
770 6e-6f	R	FCSC		False Carrier Sense Counter
771 	15-0	R	FCSCNT	False Carrier event counter
772 72-73	R	REC		RX_ER Counter
773 	15-0	R	RXERCNT	Received packet counter
774 #endif
775 
776 	if (!rep->re_got_int)
777 		return;
778 	rep->re_got_int = FALSE;
779 
780 	netdriver_recv();
781 
782 	if (rep->re_clear_rx)
783 		rl_clear_rx(rep);
784 
785 	if (rep->re_need_reset)
786 		rl_do_reset(rep);
787 
788 	if (rep->re_send_int) {
789 		rep->re_send_int = FALSE;
790 
791 		netdriver_send();
792 	}
793 
794 	if (rep->re_report_link) {
795 		rep->re_report_link = FALSE;
796 
797 		rl_report_link(rep);
798 	}
799 }
800 
801 /*===========================================================================*
802  *				rl_report_link				     *
803  *===========================================================================*/
804 static void rl_report_link(re_t *rep)
805 {
806 	port_t port;
807 	u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat;
808 	u8_t msr;
809 	int f, link_up;
810 
811 	port= rep->re_base_port;
812 	msr= rl_inb(port, RL_MSR);
813 	link_up= !(msr & RL_MSR_LINKB);
814 	rep->re_link_up= link_up;
815 	if (!link_up)
816 	{
817 		printf("%s: link down\n", rep->re_name);
818 		return;
819 	}
820 
821 	mii_ctrl= rl_inw(port, RL_BMCR);
822 	mii_status= rl_inw(port, RL_BMSR);
823 	mii_ana= rl_inw(port, RL_ANAR);
824 	mii_anlpa= rl_inw(port, RL_ANLPAR);
825 	mii_ane= rl_inw(port, RL_ANER);
826 	mii_extstat= 0;
827 
828 	if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
829 	{
830 		printf("%s: PHY: ", rep->re_name);
831 		f= 1;
832 		if (mii_ctrl & MII_CTRL_LB)
833 		{
834 			printf("loopback mode");
835 			f= 0;
836 		}
837 		if (mii_ctrl & MII_CTRL_PD)
838 		{
839 			if (!f) printf(", ");
840 			f= 0;
841 			printf("powered down");
842 		}
843 		if (mii_ctrl & MII_CTRL_ISO)
844 		{
845 			if (!f) printf(", ");
846 			f= 0;
847 			printf("isolated");
848 		}
849 		printf("\n");
850 		return;
851 	}
852 	if (!(mii_ctrl & MII_CTRL_ANE))
853 	{
854 		printf("%s: manual config: ", rep->re_name);
855 		switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
856 		{
857 		case MII_CTRL_SP_10:	printf("10 Mbps"); break;
858 		case MII_CTRL_SP_100:	printf("100 Mbps"); break;
859 		case MII_CTRL_SP_1000:	printf("1000 Mbps"); break;
860 		case MII_CTRL_SP_RES:	printf("reserved speed"); break;
861 		}
862 		if (mii_ctrl & MII_CTRL_DM)
863 			printf(", full duplex");
864 		else
865 			printf(", half duplex");
866 		printf("\n");
867 		return;
868 	}
869 
870 #if VERBOSE
871 	printf("%s: ", rep->re_name);
872 	mii_print_stat_speed(mii_status, mii_extstat);
873 	printf("\n");
874 
875 	if (!(mii_status & MII_STATUS_ANC))
876 		printf("%s: auto-negotiation not complete\n", rep->re_name);
877 	if (mii_status & MII_STATUS_RF)
878 		printf("%s: remote fault detected\n", rep->re_name);
879 	if (!(mii_status & MII_STATUS_ANA))
880 	{
881 		printf("%s: local PHY has no auto-negotiation ability\n",
882 			rep->re_name);
883 	}
884 	if (!(mii_status & MII_STATUS_LS))
885 		printf("%s: link down\n", rep->re_name);
886 	if (mii_status & MII_STATUS_JD)
887 		printf("%s: jabber condition detected\n", rep->re_name);
888 	if (!(mii_status & MII_STATUS_EC))
889 	{
890 		printf("%s: no extended register set\n", rep->re_name);
891 		goto resspeed;
892 	}
893 	if (!(mii_status & MII_STATUS_ANC))
894 		goto resspeed;
895 
896 	printf("%s: local cap.: ", rep->re_name);
897 	mii_print_techab(mii_ana);
898 	printf("\n");
899 
900 	if (mii_ane & MII_ANE_PDF)
901 		printf("%s: parallel detection fault\n", rep->re_name);
902 	if (!(mii_ane & MII_ANE_LPANA))
903 	{
904 		printf("%s: link-partner does not support auto-negotiation\n",
905 			rep->re_name);
906 		goto resspeed;
907 	}
908 
909 	printf("%s: remote cap.: ", rep->re_name);
910 	mii_print_techab(mii_anlpa);
911 	printf("\n");
912 resspeed:
913 #endif
914 
915 	printf("%s: ", rep->re_name);
916 	printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100);
917 	printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half"));
918 
919 }
920 
921 #if VERBOSE
922 static void mii_print_techab(u16_t techab)
923 {
924 	int fs, ft;
925 	if ((techab & MII_ANA_SEL_M) != MII_ANA_SEL_802_3)
926 	{
927 		printf("strange selector 0x%x, value 0x%x",
928 			techab & MII_ANA_SEL_M,
929 			(techab & MII_ANA_TAF_M) >> MII_ANA_TAF_S);
930 		return;
931 	}
932 	fs= 1;
933 	if (techab & (MII_ANA_100T4 | MII_ANA_100TXFD | MII_ANA_100TXHD))
934 	{
935 		printf("100 Mbps: ");
936 		fs= 0;
937 		ft= 1;
938 		if (techab & MII_ANA_100T4)
939 		{
940 			printf("T4");
941 			ft= 0;
942 		}
943 		if (techab & (MII_ANA_100TXFD | MII_ANA_100TXHD))
944 		{
945 			if (!ft)
946 				printf(", ");
947 			ft= 0;
948 			printf("TX-");
949 			switch(techab & (MII_ANA_100TXFD|MII_ANA_100TXHD))
950 			{
951 			case MII_ANA_100TXFD:	printf("FD"); break;
952 			case MII_ANA_100TXHD:	printf("HD"); break;
953 			default:		printf("FD/HD"); break;
954 			}
955 		}
956 	}
957 	if (techab & (MII_ANA_10TFD | MII_ANA_10THD))
958 	{
959 		if (!fs)
960 			printf(", ");
961 		printf("10 Mbps: ");
962 		fs= 0;
963 		printf("T-");
964 		switch(techab & (MII_ANA_10TFD|MII_ANA_10THD))
965 		{
966 		case MII_ANA_10TFD:	printf("FD"); break;
967 		case MII_ANA_10THD:	printf("HD"); break;
968 		default:		printf("FD/HD"); break;
969 		}
970 	}
971 	if (techab & MII_ANA_PAUSE_SYM)
972 	{
973 		if (!fs)
974 			printf(", ");
975 		fs= 0;
976 		printf("pause(SYM)");
977 	}
978 	if (techab & MII_ANA_PAUSE_ASYM)
979 	{
980 		if (!fs)
981 			printf(", ");
982 		fs= 0;
983 		printf("pause(ASYM)");
984 	}
985 	if (techab & MII_ANA_TAF_RES)
986 	{
987 		if (!fs)
988 			printf(", ");
989 		fs= 0;
990 		printf("0x%x", (techab & MII_ANA_TAF_RES) >> MII_ANA_TAF_S);
991 	}
992 }
993 
994 static void mii_print_stat_speed(u16_t stat, u16_t extstat)
995 {
996 	int fs, ft;
997 	fs= 1;
998 	if (stat & MII_STATUS_EXT_STAT)
999 	{
1000 		if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD |
1001 			MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1002 		{
1003 			printf("1000 Mbps: ");
1004 			fs= 0;
1005 			ft= 1;
1006 			if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD))
1007 			{
1008 				ft= 0;
1009 				printf("X-");
1010 				switch(extstat &
1011 					(MII_ESTAT_1000XFD|MII_ESTAT_1000XHD))
1012 				{
1013 				case MII_ESTAT_1000XFD:	printf("FD"); break;
1014 				case MII_ESTAT_1000XHD:	printf("HD"); break;
1015 				default:		printf("FD/HD"); break;
1016 				}
1017 			}
1018 			if (extstat & (MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1019 			{
1020 				if (!ft)
1021 					printf(", ");
1022 				ft= 0;
1023 				printf("T-");
1024 				switch(extstat &
1025 					(MII_ESTAT_1000TFD|MII_ESTAT_1000THD))
1026 				{
1027 				case MII_ESTAT_1000TFD:	printf("FD"); break;
1028 				case MII_ESTAT_1000THD:	printf("HD"); break;
1029 				default:		printf("FD/HD"); break;
1030 				}
1031 			}
1032 		}
1033 	}
1034 	if (stat & (MII_STATUS_100T4 |
1035 		MII_STATUS_100XFD | MII_STATUS_100XHD |
1036 		MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1037 	{
1038 		if (!fs)
1039 			printf(", ");
1040 		fs= 0;
1041 		printf("100 Mbps: ");
1042 		ft= 1;
1043 		if (stat & MII_STATUS_100T4)
1044 		{
1045 			printf("T4");
1046 			ft= 0;
1047 		}
1048 		if (stat & (MII_STATUS_100XFD | MII_STATUS_100XHD))
1049 		{
1050 			if (!ft)
1051 				printf(", ");
1052 			ft= 0;
1053 			printf("TX-");
1054 			switch(stat & (MII_STATUS_100XFD|MII_STATUS_100XHD))
1055 			{
1056 			case MII_STATUS_100XFD:	printf("FD"); break;
1057 			case MII_STATUS_100XHD:	printf("HD"); break;
1058 			default:		printf("FD/HD"); break;
1059 			}
1060 		}
1061 		if (stat & (MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1062 		{
1063 			if (!ft)
1064 				printf(", ");
1065 			ft= 0;
1066 			printf("T2-");
1067 			switch(stat & (MII_STATUS_100T2FD|MII_STATUS_100T2HD))
1068 			{
1069 			case MII_STATUS_100T2FD:	printf("FD"); break;
1070 			case MII_STATUS_100T2HD:	printf("HD"); break;
1071 			default:		printf("FD/HD"); break;
1072 			}
1073 		}
1074 	}
1075 	if (stat & (MII_STATUS_10FD | MII_STATUS_10HD))
1076 	{
1077 		if (!fs)
1078 			printf(", ");
1079 		printf("10 Mbps: ");
1080 		fs= 0;
1081 		printf("T-");
1082 		switch(stat & (MII_STATUS_10FD|MII_STATUS_10HD))
1083 		{
1084 		case MII_STATUS_10FD:	printf("FD"); break;
1085 		case MII_STATUS_10HD:	printf("HD"); break;
1086 		default:		printf("FD/HD"); break;
1087 		}
1088 	}
1089 }
1090 #endif /* VERBOSE */
1091 
1092 /*===========================================================================*
1093  *				rl_clear_rx				     *
1094  *===========================================================================*/
1095 static void rl_clear_rx(re_t *rep)
1096 {
1097 	port_t port;
1098 	u8_t cr;
1099 
1100 	rep->re_clear_rx= FALSE;
1101 	port= rep->re_base_port;
1102 
1103 	/* Reset the receiver */
1104 	cr= rl_inb(port, RL_CR);
1105 	cr &= ~RL_CR_RE;
1106 	rl_outb(port, RL_CR, cr);
1107 	SPIN_UNTIL(!(rl_inb(port, RL_CR) & RL_CR_RE), 1000000);
1108 	if (rl_inb(port, RL_CR) & RL_CR_RE)
1109 		panic("cannot disable receiver");
1110 
1111 #if 0
1112 	printf("RBSTART = 0x%08x\n", rl_inl(port, RL_RBSTART));
1113 	printf("CAPR = 0x%04x\n", rl_inw(port, RL_CAPR));
1114 	printf("CBR = 0x%04x\n", rl_inw(port, RL_CBR));
1115 	printf("RCR = 0x%08x\n", rl_inl(port, RL_RCR));
1116 #endif
1117 
1118 	rl_outb(port, RL_CR, cr | RL_CR_RE);
1119 
1120 	rl_outl(port, RL_RCR, RX_BUFBITS);
1121 
1122 	rl_rec_mode(rep);
1123 
1124 	rep->re_stat.ets_missedP++;
1125 }
1126 
1127 /*===========================================================================*
1128  *				rl_do_reset				     *
1129  *===========================================================================*/
1130 static void rl_do_reset(re_t *rep)
1131 {
1132 	rep->re_need_reset= FALSE;
1133 	rl_reset_hw(rep);
1134 	rl_rec_mode(rep);
1135 
1136 	rep->re_tx_head= 0;
1137 	if (rep->re_tx[rep->re_tx_head].ret_busy)
1138 		rep->re_tx_busy--;
1139 	rep->re_tx[rep->re_tx_head].ret_busy= FALSE;
1140 	rep->re_send_int= TRUE;
1141 }
1142 
1143 /*===========================================================================*
1144  *				rl_stat					     *
1145  *===========================================================================*/
1146 static void rl_stat(eth_stat_t *stat)
1147 {
1148 	memcpy(stat, &re_state.re_stat, sizeof(*stat));
1149 }
1150 
1151 #if 0
1152 /*===========================================================================*
1153  *				dump_phy				     *
1154  *===========================================================================*/
1155 static void dump_phy(re_t *rep)
1156 {
1157 	port_t port;
1158 	u32_t t;
1159 
1160 	port= rep->re_base_port;
1161 
1162 	t= rl_inb(port, RL_MSR);
1163 	printf("MSR: 0x%02lx\n", t);
1164 	if (t & RL_MSR_SPEED_10)
1165 		printf("\t10 Mbps\n");
1166 	if (t & RL_MSR_LINKB)
1167 		printf("\tLink failed\n");
1168 
1169 	t= rl_inb(port, RL_CONFIG1);
1170 	printf("CONFIG1: 0x%02lx\n", t);
1171 
1172 	t= rl_inb(port, RL_CONFIG3);
1173 	printf("CONFIG3: 0x%02lx\n", t);
1174 
1175 	t= rl_inb(port, RL_CONFIG4);
1176 	printf("CONFIG4: 0x%02lx\n", t);
1177 
1178 	t= rl_inw(port, RL_BMCR);
1179 	printf("BMCR (MII_CTRL): 0x%04lx\n", t);
1180 
1181 	t= rl_inw(port, RL_BMSR);
1182 	printf("BMSR:");
1183 	if (t & MII_STATUS_100T4)
1184 		printf(" 100Base-T4");
1185 	if (t & MII_STATUS_100XFD)
1186 		printf(" 100Base-X-FD");
1187 	if (t & MII_STATUS_100XHD)
1188 		printf(" 100Base-X-HD");
1189 	if (t & MII_STATUS_10FD)
1190 		printf(" 10Mbps-FD");
1191 	if (t & MII_STATUS_10HD)
1192 		printf(" 10Mbps-HD");
1193 	if (t & MII_STATUS_100T2FD)
1194 		printf(" 100Base-T2-FD");
1195 	if (t & MII_STATUS_100T2HD)
1196 		printf(" 100Base-T2-HD");
1197 	if (t & MII_STATUS_EXT_STAT)
1198 		printf(" Ext-stat");
1199 	if (t & MII_STATUS_RES)
1200 		printf(" res-0x%lx", t & MII_STATUS_RES);
1201 	if (t & MII_STATUS_MFPS)
1202 		printf(" MFPS");
1203 	if (t & MII_STATUS_ANC)
1204 		printf(" ANC");
1205 	if (t & MII_STATUS_RF)
1206 		printf(" remote-fault");
1207 	if (t & MII_STATUS_ANA)
1208 		printf(" ANA");
1209 	if (t & MII_STATUS_LS)
1210 		printf(" Link");
1211 	if (t & MII_STATUS_JD)
1212 		printf(" Jabber");
1213 	if (t & MII_STATUS_EC)
1214 		printf(" Extended-capability");
1215 	printf("\n");
1216 
1217 	t= rl_inw(port, RL_ANAR);
1218 	printf("ANAR (MII_ANA): 0x%04lx\n", t);
1219 
1220 	t= rl_inw(port, RL_ANLPAR);
1221 	printf("ANLPAR: 0x%04lx\n", t);
1222 
1223 	t= rl_inw(port, RL_ANER);
1224 	printf("ANER (MII_ANE): ");
1225 	if (t & MII_ANE_RES)
1226 		printf(" res-0x%lx", t & MII_ANE_RES);
1227 	if (t & MII_ANE_PDF)
1228 		printf(" Par-Detect-Fault");
1229 	if (t & MII_ANE_LPNPA)
1230 		printf(" LP-Next-Page-Able");
1231 	if (t & MII_ANE_NPA)
1232 		printf(" Loc-Next-Page-Able");
1233 	if (t & MII_ANE_PR)
1234 		printf(" Page-Received");
1235 	if (t & MII_ANE_LPANA)
1236 		printf(" LP-Auto-Neg-Able");
1237 	printf("\n");
1238 
1239 	t= rl_inw(port, RL_NWAYTR);
1240 	printf("NWAYTR: 0x%04lx\n", t);
1241 	t= rl_inw(port, RL_CSCR);
1242 	printf("CSCR: 0x%04lx\n", t);
1243 
1244 	t= rl_inb(port, RL_CONFIG5);
1245 	printf("CONFIG5: 0x%02lx\n", t);
1246 }
1247 #endif
1248 
1249 /*===========================================================================*
1250  *				rl_handler				     *
1251  *===========================================================================*/
1252 static int rl_handler(re_t *rep)
1253 {
1254 	int i, port, tx_head, tx_tail, link_up;
1255 	u16_t isr, tsad;
1256 	u32_t tsd, tcr, ertxth;
1257 
1258 	port= rep->re_base_port;
1259 
1260 	/* Ack interrupt */
1261 	isr= rl_inw(port, RL_ISR);
1262 	rl_outw(port, RL_ISR, isr);
1263 
1264 	if (isr & RL_IMR_FOVW)
1265 	{
1266 		isr &= ~RL_IMR_FOVW;
1267 		/* Should do anything? */
1268 
1269 		rep->re_stat.ets_fifoOver++;
1270 	}
1271 	if (isr & RL_IMR_PUN)
1272 	{
1273 		isr &= ~RL_IMR_PUN;
1274 
1275 		/* Either the link status changed or there was a TX fifo
1276 		 * underrun.
1277 		 */
1278 		link_up= !(rl_inb(port, RL_MSR) & RL_MSR_LINKB);
1279 		if (link_up != rep->re_link_up)
1280 		{
1281 			rep->re_report_link= TRUE;
1282 			rep->re_got_int= TRUE;
1283 		}
1284 	}
1285 	if (isr & RL_IMR_RXOVW)
1286 	{
1287 		isr &= ~RL_IMR_RXOVW;
1288 
1289 		/* Clear the receive buffer */
1290 		rep->re_clear_rx= TRUE;
1291 		rep->re_got_int= TRUE;
1292 	}
1293 
1294 	if (isr & (RL_ISR_RER | RL_ISR_ROK))
1295 	{
1296 		isr &= ~(RL_ISR_RER | RL_ISR_ROK);
1297 
1298 		rep->re_got_int= TRUE;
1299 	}
1300 	if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1)
1301 	{
1302 		isr &= ~(RL_ISR_TER | RL_ISR_TOK);
1303 
1304 		tsad= rl_inw(port, RL_TSAD);
1305 		if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1|
1306 			RL_TSAD_TABT2|RL_TSAD_TABT3))
1307 		{
1308 			printf("rl_handler, TABT, tasd = 0x%04x\n",
1309 				tsad);
1310 
1311 			/* Find the aborted transmit request */
1312 			for (i= 0; i< N_TX_BUF; i++)
1313 			{
1314 				tsd= rl_inl(port, RL_TSD0+i*4);
1315 				if (tsd & RL_TSD_TABT)
1316 					break;
1317 			}
1318 			if (i >= N_TX_BUF)
1319 			{
1320 				printf(
1321 				"rl_handler: can't find aborted TX req.\n");
1322 			}
1323 			else
1324 			{
1325 				printf("TSD%d = 0x%04x\n", i, tsd);
1326 
1327 				/* Set head and tail to this buffer */
1328 				rep->re_tx_head= rep->re_tx_tail= i;
1329 			}
1330 
1331 			/* Aborted transmission, just kick the device
1332 			 * and be done with it.
1333 			 */
1334 			rep->re_stat.ets_transAb++;
1335 			tcr= rl_inl(port, RL_TCR);
1336 			rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
1337 		}
1338 
1339 		/* Transmit completed */
1340 		tx_head= rep->re_tx_head;
1341 		tx_tail= rep->re_tx_tail;
1342 		for (i= 0; i< 2*N_TX_BUF; i++)
1343 		{
1344 			if (!rep->re_tx[tx_tail].ret_busy)
1345 			{
1346 				/* Strange, this buffer is not in-use.
1347 				 * Increment tx_tail until tx_head is
1348 				 * reached (or until we find a buffer that
1349 				 * is in-use.
1350 				 */
1351 				if (tx_tail == tx_head)
1352 					break;
1353 				if (++tx_tail >= N_TX_BUF)
1354 					tx_tail= 0;
1355 				assert(tx_tail < RL_N_TX);
1356 				rep->re_tx_tail= tx_tail;
1357 				continue;
1358 			}
1359 			tsd= rl_inl(port, RL_TSD0+tx_tail*4);
1360 			if (!(tsd & RL_TSD_OWN))
1361 			{
1362 				/* Buffer is not yet ready */
1363 				break;
1364 			}
1365 
1366 			/* Should collect statistics */
1367 			if (tsd & RL_TSD_CRS)
1368 				rep->re_stat.ets_carrSense++;
1369 			if (tsd & RL_TSD_TABT)
1370 			{
1371 				printf("rl_handler, TABT, TSD%d = 0x%04x\n",
1372 					tx_tail, tsd);
1373 				assert(0);	/* CLRABT is not all that
1374 						 * effective, why not?
1375 						 */
1376 				rep->re_stat.ets_transAb++;
1377 				tcr= rl_inl(port, RL_TCR);
1378 				rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
1379 			}
1380 			if (tsd & RL_TSD_OWC)
1381 				rep->re_stat.ets_OWC++;
1382 			if (tsd & RL_TSD_CDH)
1383 				rep->re_stat.ets_CDheartbeat++;
1384 
1385 			/* What about collisions? */
1386 			if (tsd & RL_TSD_TOK)
1387 				rep->re_stat.ets_packetT++;
1388 			else
1389 				rep->re_stat.ets_sendErr++;
1390 			if (tsd & RL_TSD_TUN)
1391 			{
1392 				rep->re_stat.ets_fifoUnder++;
1393 
1394 				/* Increase ERTXTH */
1395 				ertxth= tsd + (1 << RL_TSD_ERTXTH_S);
1396 				ertxth &= RL_TSD_ERTXTH_M;
1397 #if VERBOSE
1398 				if (ertxth > rep->re_ertxth)
1399 				{
1400 					printf("%s: new ertxth: %d bytes\n",
1401 						rep->re_name,
1402 						(ertxth >> RL_TSD_ERTXTH_S) *
1403 						32);
1404 					rep->re_ertxth= ertxth;
1405 				}
1406 #endif
1407 			}
1408 			rep->re_tx[tx_tail].ret_busy= FALSE;
1409 			rep->re_tx_busy--;
1410 
1411 #if 0
1412 			printf("TSD%d: %08lx\n", tx_tail, tsd);
1413 			printf(
1414 			"rl_handler: head %d, tail %d, busy: %d %d %d %d\n",
1415 				tx_head, tx_tail,
1416 				rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1417 				rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1418 #endif
1419 
1420 			if (++tx_tail >= N_TX_BUF)
1421 				tx_tail= 0;
1422 			assert(tx_tail < RL_N_TX);
1423 			rep->re_tx_tail= tx_tail;
1424 
1425 			rep->re_send_int= TRUE;
1426 			rep->re_got_int= TRUE;
1427 			rep->re_tx_alive= TRUE;
1428 		}
1429 		assert(i < 2*N_TX_BUF);
1430 	}
1431 	if (isr)
1432 	{
1433 		printf("rl_handler: unhandled interrupt: isr = 0x%04x\n",
1434 			isr);
1435 	}
1436 
1437 	return 1;
1438 }
1439 
1440 /*===========================================================================*
1441  *				rl_alarm				     *
1442  *===========================================================================*/
1443 static void rl_alarm(clock_t __unused stamp)
1444 {
1445 	re_t *rep;
1446 
1447 	/* Use a synchronous alarm instead of a watchdog timer. */
1448 	sys_setalarm(sys_hz(), 0);
1449 
1450 	rep= &re_state;
1451 
1452 	assert(rep->re_tx_busy >= 0 && rep->re_tx_busy <= N_TX_BUF);
1453 	if (rep->re_tx_busy == 0)
1454 	{
1455 		/* Assume that an idle system is alive */
1456 		rep->re_tx_alive= TRUE;
1457 		return;
1458 	}
1459 	if (rep->re_tx_alive)
1460 	{
1461 		rep->re_tx_alive= FALSE;
1462 		return;
1463 	}
1464 	printf("rl_alarm: resetting instance %d\n", re_instance);
1465 	printf("TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
1466 		rl_inw(rep->re_base_port, RL_TSAD),
1467 		rl_inl(rep->re_base_port, RL_TSD0+0*4),
1468 		rl_inl(rep->re_base_port, RL_TSD0+1*4),
1469 		rl_inl(rep->re_base_port, RL_TSD0+2*4),
1470 		rl_inl(rep->re_base_port, RL_TSD0+3*4));
1471 	printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
1472 		rep->re_tx_head, rep->re_tx_tail,
1473 		rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1474 		rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1475 	rep->re_need_reset= TRUE;
1476 	rep->re_got_int= TRUE;
1477 
1478 	rl_check_ints(rep);
1479 }
1480 
1481 /* TODO: obviously this needs a lot of work. */
1482 static void tell_iommu(vir_bytes buf, size_t size, int pci_bus, int pci_dev,
1483 	int pci_func)
1484 {
1485 	int r;
1486 	endpoint_t dev_e;
1487 	message m;
1488 
1489 	r= ds_retrieve_label_endpt("amddev", &dev_e);
1490 	if (r != OK)
1491 	{
1492 #if 0
1493 		printf("rtl8139`tell_dev: ds_retrieve_label_endpt failed "
1494 		    "for 'amddev': %d\n", r);
1495 #endif
1496 		return;
1497 	}
1498 
1499 	m.m_type= IOMMU_MAP;
1500 	m.m2_i1= pci_bus;
1501 	m.m2_i2= pci_dev;
1502 	m.m2_i3= pci_func;
1503 	m.m2_l1= buf;
1504 	m.m2_l2= size;
1505 
1506 	r= ipc_sendrec(dev_e, &m);
1507 	if (r != OK)
1508 	{
1509 		printf("rtl8139`tell_dev: ipc_sendrec to %d failed: %d\n",
1510 			dev_e, r);
1511 		return;
1512 	}
1513 	if (m.m_type != OK)
1514 	{
1515 		printf("rtl8139`tell_dev: dma map request failed: %d\n",
1516 			m.m_type);
1517 		return;
1518 	}
1519 }
1520 
1521 /*
1522  * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $
1523  */
1524