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