xref: /haiku/src/add-ons/kernel/drivers/network/ether/wb840/wb840.c (revision 268f99dd7dc4bd7474a8bd2742d3f1ec1de6752a)
1 /* Copyright (c) 2003-2011
2  * Stefano Ceccherini <stefano.ceccherini@gmail.com>. All rights reserved.
3  * This file is released under the MIT license
4  */
5 #include "device.h"
6 #include "driver.h"
7 #include "debug.h"
8 #include "ether_driver.h"
9 #include "interface.h"
10 #include "wb840.h"
11 
12 #include <ByteOrder.h>
13 #include <KernelExport.h>
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
20 
21 // MII chip info table
22 #define PHY_ID0_DAVICOM_DM9101	0x0181
23 #define PHY_ID1_DAVICOM_DM9101	0xb800
24 #define	MII_HOME	0x0001
25 #define MII_LAN		0x0002
26 
27 struct mii_chip_info
28 {
29 	const char* name;
30 	uint16 id0;
31 	uint16 id1;
32 	uint8  types;
33 };
34 
35 
36 const static struct mii_chip_info
37 gMIIChips[] = {
38 	{"DAVICOM_DM9101", PHY_ID0_DAVICOM_DM9101, PHY_ID1_DAVICOM_DM9101, MII_LAN},
39 	{NULL, 0, 0, 0}
40 };
41 
42 
43 static int
mii_readstatus(wb_device * device)44 mii_readstatus(wb_device* device)
45 {
46 	int i = 0;
47 	int status;
48 
49 	// status bit has to be retrieved 2 times
50 	while (i++ < 2)
51 		status = wb_miibus_readreg(device, device->phy, MII_STATUS);
52 
53 	return status;
54 }
55 
56 
57 static phys_addr_t
physicalAddress(volatile void * addr,uint32 length)58 physicalAddress(volatile void* addr, uint32 length)
59 {
60 	physical_entry table;
61 
62 	get_memory_map((void*)addr, length, &table, 1);
63 
64 	return table.address;
65 }
66 
67 
68 // Prepares a RX descriptor to be used by the chip
69 void
wb_put_rx_descriptor(volatile wb_desc * descriptor)70 wb_put_rx_descriptor(volatile wb_desc* descriptor)
71 {
72 	descriptor->wb_status = WB_RXSTAT_OWN;
73 	descriptor->wb_ctl |= WB_MAX_FRAMELEN | WB_RXCTL_RLINK;
74 }
75 
76 
77 void
wb_enable_interrupts(wb_device * device)78 wb_enable_interrupts(wb_device* device)
79 {
80 	write32(device->reg_base + WB_IMR, WB_INTRS);
81 	write32(device->reg_base + WB_ISR, 0xFFFFFFFF);
82 }
83 
84 
85 void
wb_disable_interrupts(wb_device * device)86 wb_disable_interrupts(wb_device* device)
87 {
88 	write32(device->reg_base + WB_IMR, 0L);
89 	write32(device->reg_base + WB_ISR, 0L);
90 }
91 
92 
93 static void
wb_selectPHY(wb_device * device)94 wb_selectPHY(wb_device* device)
95 {
96 	uint16 status;
97 
98 	// ToDo: need to be changed, select PHY in relation to the link mode
99 	device->currentPHY = device->firstPHY;
100 	device->phy = device->currentPHY->address;
101 	status = wb_miibus_readreg(device, device->phy, MII_CONTROL);
102 	status &= ~MII_CONTROL_ISOLATE;
103 
104 	wb_miibus_writereg(device, device->phy, MII_CONTROL, status);
105 
106 	wb_read_mode(device);
107 }
108 
109 
110 status_t
wb_initPHYs(wb_device * device)111 wb_initPHYs(wb_device* device)
112 {
113 	uint16 phy;
114 	// search for total of 32 possible MII PHY addresses
115 	for (phy = 0; phy < 32; phy++) {
116 		struct mii_phy* mii;
117 		uint16 status;
118 		int i = 0;
119 
120 		status = wb_miibus_readreg(device, phy, MII_STATUS);
121 		status = wb_miibus_readreg(device, phy, MII_STATUS);
122 
123 		if (status == 0xffff || status == 0x0000)
124 			// this MII is not accessable
125 			continue;
126 
127 		mii = (struct mii_phy*)calloc(1, sizeof(struct mii_phy));
128 		if (mii == NULL)
129 			return B_NO_MEMORY;
130 
131 		mii->address = phy;
132 		mii->id0 = wb_miibus_readreg(device, phy, MII_PHY_ID0);
133 		mii->id1 = wb_miibus_readreg(device, phy, MII_PHY_ID1);
134 		mii->types = MII_HOME;
135 		mii->next = device->firstPHY;
136 		device->firstPHY = mii;
137 
138 		while (gMIIChips[i].name != NULL) {
139 			if (gMIIChips[i].id0 == mii->id0
140 				&& gMIIChips[i].id1 == (mii->id1 & 0xfff0)) {
141 				dprintf("Found MII PHY: %s\n", gMIIChips[i].name);
142 				mii->types = gMIIChips[i].types;
143 				break;
144 			}
145 			i++;
146 		}
147 		if (gMIIChips[i].name == NULL) {
148 			dprintf("Unknown MII PHY transceiver: id = (%x, %x).\n",
149 				mii->id0, mii->id1);
150 		}
151 	}
152 
153 	if (device->firstPHY == NULL) {
154 		dprintf("No MII PHY transceiver found!\n");
155 		return B_ENTRY_NOT_FOUND;
156 	}
157 
158 	wb_selectPHY(device);
159 	device->link = mii_readstatus(device) & MII_STATUS_LINK;
160 
161 	return B_OK;
162 }
163 
164 
165 void
wb_init(wb_device * device)166 wb_init(wb_device* device)
167 {
168 	LOG((DEVICE_NAME": init()\n"));
169 
170 	wb_reset(device);
171 
172 	device->wb_txthresh = WB_TXTHRESH_INIT;
173 
174 	switch(device->wb_cachesize) {
175 		case 32:
176 			WB_SETBIT(device->reg_base + WB_BUSCTL, WB_CACHEALIGN_32LONG);
177 			break;
178 		case 16:
179 			WB_SETBIT(device->reg_base + WB_BUSCTL, WB_CACHEALIGN_16LONG);
180 			break;
181 		case 8:
182 			WB_SETBIT(device->reg_base + WB_BUSCTL, WB_CACHEALIGN_8LONG);
183 			break;
184 		case 0:
185 		default:
186 			WB_SETBIT(device->reg_base + WB_BUSCTL, WB_CACHEALIGN_NONE);
187 			break;
188 	}
189 
190 	write32(device->reg_base + WB_BUSCTL,
191 		WB_BUSCTL_MUSTBEONE | WB_BUSCTL_ARBITRATION);
192 	WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BURSTLEN_16LONG);
193 
194 	write32(device->reg_base + WB_BUSCTL_SKIPLEN, WB_SKIPLEN_4LONG);
195 
196 	// Disable early TX/RX interrupt, as we can't take advantage
197 	// from them, at least for now.
198 	WB_CLRBIT(device->reg_base + WB_NETCFG,
199 		(WB_NETCFG_TX_EARLY_ON | WB_NETCFG_RX_EARLY_ON));
200 
201 	wb_set_rx_filter(device);
202 }
203 
204 
205 void
wb_reset(wb_device * device)206 wb_reset(wb_device *device)
207 {
208 	int i = 0;
209 
210 	LOG((DEVICE_NAME": reset()\n"));
211 
212 	write32(device->reg_base + WB_NETCFG, 0L);
213 	write32(device->reg_base + WB_BUSCTL, 0L);
214 	write32(device->reg_base + WB_TXADDR, 0L);
215 	write32(device->reg_base + WB_RXADDR, 0L);
216 
217 	WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BUSCTL_RESET);
218 	WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BUSCTL_RESET);
219 
220 	for (i = 0; i < WB_TIMEOUT; i++) {
221 		if (!(read32(device->reg_base + WB_BUSCTL) & WB_BUSCTL_RESET))
222 			break;
223 	}
224 
225 	if (i == WB_TIMEOUT)
226 		LOG((DEVICE_NAME": reset hasn't completed!!!"));
227 
228 	/* Wait a bit while the chip reorders his toughts */
229 	snooze(1000);
230 }
231 
232 
233 status_t
wb_stop(wb_device * device)234 wb_stop(wb_device* device)
235 {
236 	uint32 cfgAddress = (uint32)device->reg_base + WB_NETCFG;
237 	int32 i = 0;
238 
239 	if (read32(cfgAddress) & (WB_NETCFG_TX_ON | WB_NETCFG_RX_ON)) {
240 		WB_CLRBIT(cfgAddress, (WB_NETCFG_TX_ON | WB_NETCFG_RX_ON));
241 
242 		for (i = 0; i < WB_TIMEOUT; i++) {
243 			if ((read32(device->reg_base + WB_ISR) & WB_ISR_TX_IDLE) &&
244 				(read32(device->reg_base + WB_ISR) & WB_ISR_RX_IDLE))
245 				break;
246 		}
247 	}
248 
249 	if (i < WB_TIMEOUT)
250 		return B_OK;
251 
252 	return B_ERROR;
253 }
254 
255 
256 static void
wb_updateLink(wb_device * device)257 wb_updateLink(wb_device* device)
258 {
259 	if (!device->autoNegotiationComplete) {
260 		int32 mode = wb_read_mode(device);
261 		if (mode)
262 			wb_set_mode(device, mode);
263 
264 		return;
265 	}
266 
267 	if (device->link) {
268 		uint16 status = mii_readstatus(device);
269 
270 		// Check if link lost
271 		if ((status & MII_STATUS_LINK) == 0)
272 			device->link = false;
273 	} else {
274 		uint16 status;
275 		wb_selectPHY(device);
276 
277 		// Check if we have a new link
278 		status = mii_readstatus(device);
279 		if (status & MII_STATUS_LINK)
280 			device->link = true;
281 	}
282 }
283 
284 
285 int32
wb_tick(timer * arg)286 wb_tick(timer* arg)
287 {
288 	wb_device* device = (wb_device*)arg;
289 
290 	wb_updateLink(device);
291 
292 	return B_HANDLED_INTERRUPT;
293 }
294 
295 
296 /*
297  * Program the rx filter.
298  */
299 void
wb_set_rx_filter(wb_device * device)300 wb_set_rx_filter(wb_device* device)
301 {
302 	// TODO: Basically we just config the filter to accept broadcasts
303 	// packets. We'll need also to configure it to multicast.
304 	WB_SETBIT(device->reg_base + WB_NETCFG, WB_NETCFG_RX_BROAD);
305 }
306 
307 
308 /***************** Interrupt handling ******************************/
309 static status_t
wb_rxok(wb_device * device)310 wb_rxok(wb_device* device)
311 {
312 	uint32 releaseRxSem = 0;
313 	int16 limit;
314 
315 	acquire_spinlock(&device->rxSpinlock);
316 
317 	for (limit = device->rxFree; limit > 0; limit--) {
318 		if (device->rxDescriptor[device->rxInterruptIndex].wb_status
319 			& WB_RXSTAT_OWN) {
320 			break;
321 		}
322 
323 		releaseRxSem++;
324 		device->rxInterruptIndex = (device->rxInterruptIndex + 1)
325 			& WB_RX_CNT_MASK;
326 		device->rxFree--;
327 	}
328 
329 	// Re-enable receive queue
330 	write32(device->reg_base + WB_RXSTART, 0xFFFFFFFF);
331 
332 	release_spinlock(&device->rxSpinlock);
333 
334 	if (releaseRxSem > 0) {
335 		release_sem_etc(device->rxSem, releaseRxSem, B_DO_NOT_RESCHEDULE);
336 		return B_INVOKE_SCHEDULER;
337 	}
338 
339 	return B_HANDLED_INTERRUPT;
340 }
341 
342 
343 static status_t
wb_tx_nobuf(wb_device * info)344 wb_tx_nobuf(wb_device* info)
345 {
346 	int16 releaseTxSem = 0;
347 	int16 limit;
348 	status_t status;
349 
350 	acquire_spinlock(&info->txSpinlock);
351 
352 	for (limit = info->txSent; limit > 0; limit--) {
353 		status = info->txDescriptor[info->txInterruptIndex].wb_status;
354 
355 		LOG(("wb_tx_nobuf, status: %lx\n", status));
356 		if (status & WB_TXSTAT_TXERR) {
357 			LOG(("TX_STAT_ERR\n"));
358 			break;
359 		} else if (status & WB_UNSENT) {
360 			LOG(("TX_STAT_UNSENT\n"));
361 			break;
362 		} else if (status & WB_TXSTAT_OWN) {
363 			LOG((DEVICE_NAME": Device still owns the descriptor\n"));
364 			break;
365 		} else
366 			info->txDescriptor[info->txInterruptIndex].wb_status = 0;
367 
368 		releaseTxSem++;	// this many buffers are free
369 		info->txInterruptIndex = (info->txInterruptIndex + 1) & WB_TX_CNT_MASK;
370 		info->txSent--;
371 
372 		if (info->txSent < 0 || info->txSent > WB_TX_LIST_CNT)
373 			dprintf("ERROR interrupt: txSent = %d\n", info->txSent);
374 	}
375 
376 	release_spinlock(&info->txSpinlock);
377 
378 	if (releaseTxSem) {
379 		release_sem_etc(info->txSem, releaseTxSem, B_DO_NOT_RESCHEDULE);
380 		return B_INVOKE_SCHEDULER;
381 	}
382 
383 	return B_HANDLED_INTERRUPT;
384 }
385 
386 
387 int32
wb_interrupt(void * arg)388 wb_interrupt(void* arg)
389 {
390 	wb_device* device = (wb_device*)arg;
391 	int32 retval = B_UNHANDLED_INTERRUPT;
392 	uint32 status;
393 
394 	// TODO: Handle other interrupts
395 
396 	acquire_spinlock(&device->intLock);
397 
398 	status = read32(device->reg_base + WB_ISR);
399 
400 	// Did this card request the interrupt ?
401 	if (status & WB_INTRS) {
402 		// Clean all the interrupts bits
403 		if (status)
404 			write32(device->reg_base + WB_ISR, status);
405 
406 		if (status & WB_ISR_ABNORMAL)
407 			LOG((DEVICE_NAME": *** Abnormal Interrupt received ***\n"));
408 		else
409 			LOG((DEVICE_NAME": interrupt received: \n"));
410 
411 		if (status & WB_ISR_RX_EARLY) {
412 			LOG(("WB_ISR_RX_EARLY\n"));
413 		}
414 
415 		if (status & WB_ISR_RX_NOBUF) {
416 			LOG(("WB_ISR_RX_NOBUF\n"));
417 			// Something is screwed
418 		}
419 
420 		if (status & WB_ISR_RX_ERR) {
421 			LOG(("WB_ISR_RX_ERR\n"));
422 			// TODO: Do something useful
423 		}
424 
425 		if (status & WB_ISR_RX_OK) {
426 			LOG(("WB_ISR_RX_OK\n"));
427 			retval = wb_rxok(device);
428 		}
429 
430 		if (status & WB_ISR_RX_IDLE) {
431 			LOG(("WB_ISR_RX_IDLE\n"));
432 			// ???
433 		}
434 
435 		if (status & WB_ISR_TX_EARLY) {
436 			LOG(("WB_ISR_TX_EARLY\n"));
437 
438 		}
439 
440 		if (status & WB_ISR_TX_NOBUF) {
441 			LOG(("WB_ISR_TX_NOBUF\n"));
442 			retval = wb_tx_nobuf(device);
443 		}
444 
445 		if (status & WB_ISR_TX_UNDERRUN) {
446 			LOG(("WB_ISR_TX_UNDERRUN\n"));
447 			// TODO: Jack up TX Threshold
448 		}
449 
450 		if (status & WB_ISR_TX_IDLE) {
451 			LOG(("WB_ISR_TX_IDLE\n"));
452 		}
453 
454 		if (status & WB_ISR_TX_OK) {
455 			LOG(("WB_ISR_TX_OK\n"));
456 			// So what ?
457 		}
458 
459 		if (status & WB_ISR_BUS_ERR) {
460 			LOG(("WB_ISR_BUS_ERROR: %lx\n", (status & WB_ISR_BUSERRTYPE) >> 4));
461 			//wb_reset(device);
462 		}
463 
464 		if (status & WB_ISR_TIMER_EXPIRED) {
465 			LOG(("WB_ISR_TIMER_EXPIRED\n"));
466 			// ??
467 		}
468 	}
469 
470 	release_spinlock(&device->intLock);
471 
472 	return retval;
473 }
474 
475 
476 /*
477  * Print an ethernet address
478  */
479 void
print_address(ether_address_t * addr)480 print_address(ether_address_t* addr)
481 {
482 	int i;
483 	char buf[3 * 6 + 1];
484 
485 	for (i = 0; i < 5; i++) {
486 		sprintf(&buf[3 * i], "%02x:", addr->ebyte[i]);
487 	}
488 	sprintf(&buf[3 * 5], "%02x", addr->ebyte[5]);
489 	dprintf("%s\n", buf);
490 }
491 
492 
493 status_t
wb_create_semaphores(wb_device * device)494 wb_create_semaphores(wb_device* device)
495 {
496 	device->rxSem = create_sem(0, "wb840 receive");
497 	if (device->rxSem < B_OK) {
498 		LOG(("Couldn't create sem, sem_id %ld\n", device->rxSem));
499 		return device->rxSem;
500 	}
501 
502 	device->txSem = create_sem(WB_TX_LIST_CNT, "wb840 transmit");
503 	if (device->txSem < B_OK) {
504 		LOG(("Couldn't create sem, sem_id %ld\n", device->txSem));
505 		delete_sem(device->rxSem);
506 		return device->txSem;
507 	}
508 
509 	set_sem_owner(device->rxSem, B_SYSTEM_TEAM);
510 	set_sem_owner(device->txSem, B_SYSTEM_TEAM);
511 
512 	device->rxLock = 0;
513 	device->txLock = 0;
514 
515 	return B_OK;
516 }
517 
518 
519 void
wb_delete_semaphores(wb_device * device)520 wb_delete_semaphores(wb_device* device)
521 {
522 	if (device->rxSem >= 0)
523 		delete_sem(device->rxSem);
524 	if (device->txSem >= 0)
525 		delete_sem(device->txSem);
526 }
527 
528 
529 status_t
wb_create_rings(wb_device * device)530 wb_create_rings(wb_device* device)
531 {
532 	int i;
533 
534 	device->rxArea = create_area("wb840 rx buffer",
535 		(void**)&device->rxBuffer[0], B_ANY_KERNEL_ADDRESS,
536 		ROUND_TO_PAGE_SIZE(WB_BUFBYTES * WB_RX_LIST_CNT),
537 		B_32_BIT_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
538 	if (device->rxArea < B_OK)
539 		return device->rxArea;
540 
541 	for (i = 1; i < WB_RX_LIST_CNT; i++) {
542 		device->rxBuffer[i] = (void*)(((addr_t)device->rxBuffer[0])
543 			+ (i * WB_BUFBYTES));
544 	}
545 
546 	for (i = 0; i < WB_RX_LIST_CNT; i++) {
547 		device->rxDescriptor[i].wb_status = 0;
548 		device->rxDescriptor[i].wb_ctl = WB_RXCTL_RLINK;
549 		wb_put_rx_descriptor(&device->rxDescriptor[i]);
550 		device->rxDescriptor[i].wb_data = physicalAddress(
551 			device->rxBuffer[i], WB_BUFBYTES);
552 		device->rxDescriptor[i].wb_next = physicalAddress(
553 			&device->rxDescriptor[(i + 1) & WB_RX_CNT_MASK],
554 			sizeof(struct wb_desc));
555 	}
556 
557 	device->rxFree = WB_RX_LIST_CNT;
558 
559 	device->txArea = create_area("wb840 tx buffer",
560 		(void**)&device->txBuffer[0], B_ANY_KERNEL_ADDRESS,
561 		ROUND_TO_PAGE_SIZE(WB_BUFBYTES * WB_TX_LIST_CNT),
562 		B_32_BIT_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
563 
564 	if (device->txArea < B_OK) {
565 		delete_area(device->rxArea);
566 		return device->txArea;
567 	}
568 
569 	for (i = 1; i < WB_TX_LIST_CNT; i++) {
570 		device->txBuffer[i] = (void*)(((addr_t)device->txBuffer[0])
571 			+ (i * WB_BUFBYTES));
572 	}
573 
574 	for (i = 0; i < WB_TX_LIST_CNT; i++) {
575 		device->txDescriptor[i].wb_status = 0;
576 		device->txDescriptor[i].wb_ctl = WB_TXCTL_TLINK;
577 		device->txDescriptor[i].wb_data = physicalAddress(
578 			device->txBuffer[i], WB_BUFBYTES);
579 		device->txDescriptor[i].wb_next = physicalAddress(
580 			&device->txDescriptor[(i + 1) & WB_TX_CNT_MASK],
581 			sizeof(struct wb_desc));
582 	}
583 
584 	if (wb_stop(device) == B_OK) {
585 		write32(device->reg_base + WB_RXADDR,
586 			physicalAddress(&device->rxDescriptor[0], sizeof(struct wb_desc)));
587 		write32(device->reg_base + WB_TXADDR,
588 			physicalAddress(&device->txDescriptor[0], sizeof(struct wb_desc)));
589 	}
590 
591 	return B_OK;
592 }
593 
594 
595 void
wb_delete_rings(wb_device * device)596 wb_delete_rings(wb_device* device)
597 {
598 	delete_area(device->rxArea);
599 	delete_area(device->txArea);
600 }
601 
602 
603 int32
wb_read_mode(wb_device * info)604 wb_read_mode(wb_device* info)
605 {
606 	uint16 autoAdv;
607 	uint16 autoLinkPartner;
608 	int32 speed;
609 	int32 duplex;
610 
611 	uint16 status = mii_readstatus(info);
612 	if (!(status & MII_STATUS_LINK)) {
613 		LOG((DEVICE_NAME ": no link detected (status = %x)\n", status));
614 		return 0;
615 	}
616 
617 	// auto negotiation completed
618 	autoAdv = wb_miibus_readreg(info, info->phy, MII_AUTONEG_ADV);
619 	autoLinkPartner = wb_miibus_readreg(info, info->phy,
620 		MII_AUTONEG_LINK_PARTNER);
621 	status = autoAdv & autoLinkPartner;
622 
623 	speed = status & (MII_NWAY_TX | MII_NWAY_TX_FDX)
624 		? LINK_SPEED_100_MBIT : LINK_SPEED_10_MBIT;
625 	duplex = status & (MII_NWAY_TX_FDX | MII_NWAY_T_FDX)
626 		? LINK_FULL_DUPLEX : LINK_HALF_DUPLEX;
627 
628 	info->autoNegotiationComplete = true;
629 
630 	LOG((DEVICE_NAME ": linked, 10%s MBit, %s duplex\n",
631 				speed == LINK_SPEED_100_MBIT ? "0" : "",
632 				duplex == LINK_FULL_DUPLEX ? "full" : "half"));
633 
634 	return speed | duplex;
635 }
636 
637 
638 void
wb_set_mode(wb_device * info,int mode)639 wb_set_mode(wb_device* info, int mode)
640 {
641 	uint32 cfgAddress = (uint32)info->reg_base + WB_NETCFG;
642 
643 	uint32 configFlags = 0;
644 	status_t status;
645 
646 	info->speed = mode & LINK_SPEED_MASK;
647 	info->full_duplex = mode & LINK_DUPLEX_MASK;
648 
649 	status = wb_stop(info);
650 
651 	if ((mode & LINK_DUPLEX_MASK) == LINK_FULL_DUPLEX)
652 		configFlags |= WB_NETCFG_FULLDUPLEX;
653 
654 	if (info->speed == LINK_SPEED_100_MBIT)
655 		configFlags |= WB_NETCFG_100MBPS;
656 
657 	write32(cfgAddress, configFlags);
658 
659 	if (status == B_OK)
660 		WB_SETBIT(cfgAddress, WB_NETCFG_TX_ON|WB_NETCFG_RX_ON);
661 }
662