1 /* Copyright (c) 2003-2011
2 * Stefano Ceccherini <stefano.ceccherini@gmail.com>. All rights reserved.
3 * This file is released under the MIT license
8 #include "ether_driver.h"
12 #include <ByteOrder.h>
13 #include <KernelExport.h>
19 #define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
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
36 const static struct mii_chip_info
38 {"DAVICOM_DM9101", PHY_ID0_DAVICOM_DM9101
, PHY_ID1_DAVICOM_DM9101
, MII_LAN
},
44 mii_readstatus(wb_device
* device
)
49 // status bit has to be retrieved 2 times
51 status
= wb_miibus_readreg(device
, device
->phy
, MII_STATUS
);
58 physicalAddress(volatile void* addr
, uint32 length
)
62 get_memory_map((void*)addr
, length
, &table
, 1);
68 // Prepares a RX descriptor to be used by the chip
70 wb_put_rx_descriptor(volatile wb_desc
* descriptor
)
72 descriptor
->wb_status
= WB_RXSTAT_OWN
;
73 descriptor
->wb_ctl
|= WB_MAX_FRAMELEN
| WB_RXCTL_RLINK
;
78 wb_enable_interrupts(wb_device
* device
)
80 write32(device
->reg_base
+ WB_IMR
, WB_INTRS
);
81 write32(device
->reg_base
+ WB_ISR
, 0xFFFFFFFF);
86 wb_disable_interrupts(wb_device
* device
)
88 write32(device
->reg_base
+ WB_IMR
, 0L);
89 write32(device
->reg_base
+ WB_ISR
, 0L);
94 wb_selectPHY(wb_device
* device
)
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
;
104 wb_miibus_writereg(device
, device
->phy
, MII_CONTROL
, status
);
106 wb_read_mode(device
);
111 wb_initPHYs(wb_device
* device
)
114 // search for total of 32 possible MII PHY addresses
115 for (phy
= 0; phy
< 32; phy
++) {
120 status
= wb_miibus_readreg(device
, phy
, MII_STATUS
);
121 status
= wb_miibus_readreg(device
, phy
, MII_STATUS
);
123 if (status
== 0xffff || status
== 0x0000)
124 // this MII is not accessable
127 mii
= (struct mii_phy
*)calloc(1, sizeof(struct mii_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
;
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
;
147 if (gMIIChips
[i
].name
== NULL
) {
148 dprintf("Unknown MII PHY transceiver: id = (%x, %x).\n",
153 if (device
->firstPHY
== NULL
) {
154 dprintf("No MII PHY transceiver found!\n");
155 return B_ENTRY_NOT_FOUND
;
158 wb_selectPHY(device
);
159 device
->link
= mii_readstatus(device
) & MII_STATUS_LINK
;
166 wb_init(wb_device
* device
)
168 LOG((DEVICE_NAME
": init()\n"));
172 device
->wb_txthresh
= WB_TXTHRESH_INIT
;
174 switch(device
->wb_cachesize
) {
176 WB_SETBIT(device
->reg_base
+ WB_BUSCTL
, WB_CACHEALIGN_32LONG
);
179 WB_SETBIT(device
->reg_base
+ WB_BUSCTL
, WB_CACHEALIGN_16LONG
);
182 WB_SETBIT(device
->reg_base
+ WB_BUSCTL
, WB_CACHEALIGN_8LONG
);
186 WB_SETBIT(device
->reg_base
+ WB_BUSCTL
, WB_CACHEALIGN_NONE
);
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
);
194 write32(device
->reg_base
+ WB_BUSCTL_SKIPLEN
, WB_SKIPLEN_4LONG
);
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
));
201 wb_set_rx_filter(device
);
206 wb_reset(wb_device
*device
)
210 LOG((DEVICE_NAME
": reset()\n"));
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);
217 WB_SETBIT(device
->reg_base
+ WB_BUSCTL
, WB_BUSCTL_RESET
);
218 WB_SETBIT(device
->reg_base
+ WB_BUSCTL
, WB_BUSCTL_RESET
);
220 for (i
= 0; i
< WB_TIMEOUT
; i
++) {
221 if (!(read32(device
->reg_base
+ WB_BUSCTL
) & WB_BUSCTL_RESET
))
226 LOG((DEVICE_NAME
": reset hasn't completed!!!"));
228 /* Wait a bit while the chip reorders his toughts */
234 wb_stop(wb_device
* device
)
236 uint32 cfgAddress
= (uint32
)device
->reg_base
+ WB_NETCFG
;
239 if (read32(cfgAddress
) & (WB_NETCFG_TX_ON
| WB_NETCFG_RX_ON
)) {
240 WB_CLRBIT(cfgAddress
, (WB_NETCFG_TX_ON
| WB_NETCFG_RX_ON
));
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
))
257 wb_updateLink(wb_device
* device
)
259 if (!device
->autoNegotiationComplete
) {
260 int32 mode
= wb_read_mode(device
);
262 wb_set_mode(device
, mode
);
268 uint16 status
= mii_readstatus(device
);
270 // Check if link lost
271 if ((status
& MII_STATUS_LINK
) == 0)
272 device
->link
= false;
275 wb_selectPHY(device
);
277 // Check if we have a new link
278 status
= mii_readstatus(device
);
279 if (status
& MII_STATUS_LINK
)
288 wb_device
* device
= (wb_device
*)arg
;
290 wb_updateLink(device
);
297 * Program the rx filter.
300 wb_set_rx_filter(wb_device
* device
)
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
);
308 /***************** Interrupt handling ******************************/
310 wb_rxok(wb_device
* device
)
312 uint32 releaseRxSem
= 0;
315 acquire_spinlock(&device
->rxSpinlock
);
317 for (limit
= device
->rxFree
; limit
> 0; limit
--) {
318 if (device
->rxDescriptor
[device
->rxInterruptIndex
].wb_status
324 device
->rxInterruptIndex
= (device
->rxInterruptIndex
+ 1)
329 // Re-enable receive queue
330 write32(device
->reg_base
+ WB_RXSTART
, 0xFFFFFFFF);
332 release_spinlock(&device
->rxSpinlock
);
334 if (releaseRxSem
> 0) {
335 release_sem_etc(device
->rxSem
, releaseRxSem
, B_DO_NOT_RESCHEDULE
);
336 return B_INVOKE_SCHEDULER
;
339 return B_HANDLED_INTERRUPT
;
344 wb_tx_nobuf(wb_device
* info
)
346 int16 releaseTxSem
= 0;
350 acquire_spinlock(&info
->txSpinlock
);
352 for (limit
= info
->txSent
; limit
> 0; limit
--) {
353 status
= info
->txDescriptor
[info
->txInterruptIndex
].wb_status
;
355 LOG(("wb_tx_nobuf, status: %lx\n", status
));
356 if (status
& WB_TXSTAT_TXERR
) {
357 LOG(("TX_STAT_ERR\n"));
359 } else if (status
& WB_UNSENT
) {
360 LOG(("TX_STAT_UNSENT\n"));
362 } else if (status
& WB_TXSTAT_OWN
) {
363 LOG((DEVICE_NAME
": Device still owns the descriptor\n"));
366 info
->txDescriptor
[info
->txInterruptIndex
].wb_status
= 0;
368 releaseTxSem
++; // this many buffers are free
369 info
->txInterruptIndex
= (info
->txInterruptIndex
+ 1) & WB_TX_CNT_MASK
;
372 if (info
->txSent
< 0 || info
->txSent
> WB_TX_LIST_CNT
)
373 dprintf("ERROR interrupt: txSent = %d\n", info
->txSent
);
376 release_spinlock(&info
->txSpinlock
);
379 release_sem_etc(info
->txSem
, releaseTxSem
, B_DO_NOT_RESCHEDULE
);
380 return B_INVOKE_SCHEDULER
;
383 return B_HANDLED_INTERRUPT
;
388 wb_interrupt(void* arg
)
390 wb_device
* device
= (wb_device
*)arg
;
391 int32 retval
= B_UNHANDLED_INTERRUPT
;
394 // TODO: Handle other interrupts
396 acquire_spinlock(&device
->intLock
);
398 status
= read32(device
->reg_base
+ WB_ISR
);
400 // Did this card request the interrupt ?
401 if (status
& WB_INTRS
) {
402 // Clean all the interrupts bits
404 write32(device
->reg_base
+ WB_ISR
, status
);
406 if (status
& WB_ISR_ABNORMAL
)
407 LOG((DEVICE_NAME
": *** Abnormal Interrupt received ***\n"));
409 LOG((DEVICE_NAME
": interrupt received: \n"));
411 if (status
& WB_ISR_RX_EARLY
) {
412 LOG(("WB_ISR_RX_EARLY\n"));
415 if (status
& WB_ISR_RX_NOBUF
) {
416 LOG(("WB_ISR_RX_NOBUF\n"));
417 // Something is screwed
420 if (status
& WB_ISR_RX_ERR
) {
421 LOG(("WB_ISR_RX_ERR\n"));
422 // TODO: Do something useful
425 if (status
& WB_ISR_RX_OK
) {
426 LOG(("WB_ISR_RX_OK\n"));
427 retval
= wb_rxok(device
);
430 if (status
& WB_ISR_RX_IDLE
) {
431 LOG(("WB_ISR_RX_IDLE\n"));
435 if (status
& WB_ISR_TX_EARLY
) {
436 LOG(("WB_ISR_TX_EARLY\n"));
440 if (status
& WB_ISR_TX_NOBUF
) {
441 LOG(("WB_ISR_TX_NOBUF\n"));
442 retval
= wb_tx_nobuf(device
);
445 if (status
& WB_ISR_TX_UNDERRUN
) {
446 LOG(("WB_ISR_TX_UNDERRUN\n"));
447 // TODO: Jack up TX Threshold
450 if (status
& WB_ISR_TX_IDLE
) {
451 LOG(("WB_ISR_TX_IDLE\n"));
454 if (status
& WB_ISR_TX_OK
) {
455 LOG(("WB_ISR_TX_OK\n"));
459 if (status
& WB_ISR_BUS_ERR
) {
460 LOG(("WB_ISR_BUS_ERROR: %lx\n", (status
& WB_ISR_BUSERRTYPE
) >> 4));
464 if (status
& WB_ISR_TIMER_EXPIRED
) {
465 LOG(("WB_ISR_TIMER_EXPIRED\n"));
470 release_spinlock(&device
->intLock
);
477 * Print an ethernet address
480 print_address(ether_address_t
* addr
)
485 for (i
= 0; i
< 5; i
++) {
486 sprintf(&buf
[3 * i
], "%02x:", addr
->ebyte
[i
]);
488 sprintf(&buf
[3 * 5], "%02x", addr
->ebyte
[5]);
489 dprintf("%s\n", buf
);
494 wb_create_semaphores(wb_device
* device
)
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
;
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
;
509 set_sem_owner(device
->rxSem
, B_SYSTEM_TEAM
);
510 set_sem_owner(device
->txSem
, B_SYSTEM_TEAM
);
520 wb_delete_semaphores(wb_device
* device
)
522 if (device
->rxSem
>= 0)
523 delete_sem(device
->rxSem
);
524 if (device
->txSem
>= 0)
525 delete_sem(device
->txSem
);
530 wb_create_rings(wb_device
* device
)
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
;
541 for (i
= 1; i
< WB_RX_LIST_CNT
; i
++) {
542 device
->rxBuffer
[i
] = (void*)(((addr_t
)device
->rxBuffer
[0])
543 + (i
* WB_BUFBYTES
));
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
));
557 device
->rxFree
= WB_RX_LIST_CNT
;
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
);
564 if (device
->txArea
< B_OK
) {
565 delete_area(device
->rxArea
);
566 return device
->txArea
;
569 for (i
= 1; i
< WB_TX_LIST_CNT
; i
++) {
570 device
->txBuffer
[i
] = (void*)(((addr_t
)device
->txBuffer
[0])
571 + (i
* WB_BUFBYTES
));
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
));
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
)));
596 wb_delete_rings(wb_device
* device
)
598 delete_area(device
->rxArea
);
599 delete_area(device
->txArea
);
604 wb_read_mode(wb_device
* info
)
607 uint16 autoLinkPartner
;
611 uint16 status
= mii_readstatus(info
);
612 if (!(status
& MII_STATUS_LINK
)) {
613 LOG((DEVICE_NAME
": no link detected (status = %x)\n", status
));
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
;
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
;
628 info
->autoNegotiationComplete
= true;
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"));
634 return speed
| duplex
;
639 wb_set_mode(wb_device
* info
, int mode
)
641 uint32 cfgAddress
= (uint32
)info
->reg_base
+ WB_NETCFG
;
643 uint32 configFlags
= 0;
646 info
->speed
= mode
& LINK_SPEED_MASK
;
647 info
->full_duplex
= mode
& LINK_DUPLEX_MASK
;
649 status
= wb_stop(info
);
651 if ((mode
& LINK_DUPLEX_MASK
) == LINK_FULL_DUPLEX
)
652 configFlags
|= WB_NETCFG_FULLDUPLEX
;
654 if (info
->speed
== LINK_SPEED_100_MBIT
)
655 configFlags
|= WB_NETCFG_100MBPS
;
657 write32(cfgAddress
, configFlags
);
660 WB_SETBIT(cfgAddress
, WB_NETCFG_TX_ON
|WB_NETCFG_RX_ON
);