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