vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / drivers / network / sis900 / sis900.c
blobbefb4d2874f6c3fd325c6f71ea569bb9ae331dbe
1 /* SiS 900 chip specific functions
3 * Copyright © 2001-2005 pinc Software. All Rights Reserved.
4 * Distributed under the terms of the MIT license.
5 */
8 #include <OS.h>
9 #include <KernelExport.h>
10 #include <Drivers.h>
11 #include <PCI.h>
12 #include <SupportDefs.h>
14 #include <stdlib.h>
15 #include <string.h>
17 #include "ether_driver.h"
18 #include "driver.h"
19 #include "device.h"
20 #include "interface.h"
21 #include "sis900.h"
24 // prototypes
26 uint16 sis900_resetPHY(struct sis_info *info);
27 void sis900_selectPHY(struct sis_info *info);
28 void sis900_setMode(struct sis_info *info, int32 mode);
29 int32 sis900_readMode(struct sis_info *info);
32 // MII chip info table
34 #define PHY_ID0_SiS900_INTERNAL 0x001d
35 #define PHY_ID1_SiS900_INTERNAL 0x8000
36 #define PHY_ID0_ICS_1893 0x0015
37 #define PHY_ID1_ICS_1893 0xff40
38 #define PHY_ID0_REALTEK_8201 0x0000
39 #define PHY_ID1_REALTEK_8201 0x8200
40 #define PHY_ID0_VIA_6103 0x0101
41 #define PHY_ID1_VIA_6103 0x8f20
43 #define MII_HOME 0x0001
44 #define MII_LAN 0x0002
46 const static struct mii_chip_info {
47 const char *name;
48 uint16 id0, id1;
49 uint8 types;
50 } gMIIChips[] = {
51 {"SiS 900 Internal MII PHY",
52 PHY_ID0_SiS900_INTERNAL, PHY_ID1_SiS900_INTERNAL, MII_LAN},
53 {"SiS 7014 Physical Layer Solution",
54 0x0016, 0xf830, MII_LAN},
55 {"AMD 79C901 10BASE-T PHY",
56 0x0000, 0x6B70, MII_LAN},
57 {"AMD 79C901 HomePNA PHY",
58 0x0000, 0x6B90, MII_HOME},
59 {"ICS 1893 LAN PHY",
60 PHY_ID0_ICS_1893, PHY_ID1_ICS_1893, MII_LAN},
61 {"NS 83851 PHY",
62 0x2000, 0x5C20, MII_LAN | MII_HOME},
63 {"Realtek RTL8201 PHY",
64 PHY_ID0_REALTEK_8201, PHY_ID1_REALTEK_8201, MII_LAN},
65 {"VIA 6103 PHY",
66 PHY_ID0_VIA_6103, PHY_ID1_VIA_6103, MII_LAN},
67 {NULL, 0, 0, 0}
71 /***************************** helper functions *****************************/
74 static phys_addr_t
75 physicalAddress(volatile void *address, uint32 length)
77 physical_entry table;
79 get_memory_map((void *)address, length, &table, 1);
80 return table.address;
84 /***************************** interrupt handling *****************************/
85 // #pragma mark -
86 int32 intrCounter = 0;
87 int32 lastIntr[100];
90 static int32
91 sis900_rxInterrupt(struct sis_info *info)
93 int32 handled = B_UNHANDLED_INTERRUPT;
94 int16 releaseRxSem = 0;
95 int16 limit;
97 acquire_spinlock(&info->rxSpinlock);
99 HACK(spin(10000));
101 // check for packet ownership
102 for (limit = info->rxFree; limit > 0; limit--) {
103 if (!(info->rxDescriptor[info->rxInterruptIndex].status & SiS900_DESCR_OWN)) {
104 // if (limit == info->rxFree)
105 // {
106 //dprintf("here!\n");
107 // limit++;
108 // continue;
109 // }
110 break;
112 //dprintf("received frame %d!\n",info->rxInterruptIndex);
114 releaseRxSem++;
115 info->rxInterruptIndex = (info->rxInterruptIndex + 1) & NUM_Rx_MASK;
116 info->rxFree--;
118 release_spinlock(&info->rxSpinlock);
120 // reenable rx queue
121 write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Rx_ENABLE);
123 if (releaseRxSem) {
124 release_sem_etc(info->rxSem, releaseRxSem, B_DO_NOT_RESCHEDULE);
125 return B_INVOKE_SCHEDULER;
128 return handled;
132 static int32
133 sis900_txInterrupt(struct sis_info *info)
135 int16 releaseTxSem = 0;
136 uint32 status;
137 int16 limit;
139 acquire_spinlock(&info->txSpinlock);
141 HACK(spin(10000));
143 for (limit = info->txSent; limit > 0; limit--) {
144 status = info->txDescriptor[info->txInterruptIndex].status;
146 //dprintf("txIntr: %d: mem = %lx : hardware = %lx\n",info->txInterruptIndex,
147 // physicalAddress(&info->txDescriptor[info->txInterruptIndex],sizeof(struct buffer_desc)),
148 // read32(info->registers + SiS900_MAC_Tx_DESCR));
150 /* Does the device generate extra interrupts? */
151 if (status & SiS900_DESCR_OWN) {
152 uint32 descriptor = read32(info->registers + SiS900_MAC_Tx_DESCR);
153 int16 that;
154 for (that = 0;
155 that < NUM_Tx_DESCR
156 && physicalAddress(&info->txDescriptor[that],
157 sizeof(struct buffer_desc)) != descriptor;
158 that++) {
160 if (that == NUM_Tx_DESCR)
161 that = 0;
163 //dprintf("tx busy %d: %lx (hardware status %d = %lx)!\n",info->txInterruptIndex,status,that,info->txDescriptor[that].status);
164 // if (limit == info->txSent)
165 // {
166 //dprintf("oh no!\n");
167 // limit++;
168 // continue;
169 // }
170 break;
173 if (status & (SiS900_DESCR_Tx_ABORT | SiS900_DESCR_Tx_UNDERRUN
174 | SiS900_DESCR_Tx_OOW_COLLISION)) {
175 dprintf("tx error: %" B_PRIx32 "\n", status);
176 } else
177 info->txDescriptor[info->txInterruptIndex].status = 0;
179 releaseTxSem++; /* this many buffers are free */
180 info->txInterruptIndex = (info->txInterruptIndex + 1) & NUM_Tx_MASK;
181 info->txSent--;
183 if (info->txSent < 0 || info->txSent > NUM_Tx_DESCR)
184 dprintf("ERROR interrupt: txSent = %d\n", info->txSent);
186 release_spinlock(&info->txSpinlock);
188 if (releaseTxSem) {
189 release_sem_etc(info->txSem, releaseTxSem, B_DO_NOT_RESCHEDULE);
190 return B_INVOKE_SCHEDULER;
193 return B_HANDLED_INTERRUPT;
197 int32
198 sis900_interrupt(void *data)
200 struct sis_info *info = data;
201 int32 handled = B_UNHANDLED_INTERRUPT;
202 int16 worklimit = 20;
203 uint32 intr;
204 cpu_status former;
206 former = disable_interrupts();
207 acquire_spinlock(&info->lock);
209 while (worklimit-- > 0) {
210 // reading the interrupt status register clears all interrupts
211 intr = read32(info->registers + SiS900_MAC_INTR_STATUS);
212 if (!intr)
213 break;
215 TRACE(("************ interrupt received: %08lx **************\n", intr));
216 intrCounter = (intrCounter + 1) % 100;
217 lastIntr[intrCounter] = intr;
219 // wake-up event interrupt
220 if (intr & SiS900_INTR_WAKEUP_EVENT) {
221 TRACE(("wake-up event received: %ld\n",
222 read32(info->registers + SiS900_MAC_WAKEUP_EVENT)));
224 // clear PM event register
225 write32(info->registers + SiS900_MAC_WAKEUP_EVENT,
226 SiS900_WAKEUP_LINK_ON | SiS900_WAKEUP_LINK_LOSS);
227 handled = B_HANDLED_INTERRUPT;
230 // receive packet interrupts
231 if (intr & (/*SiS900_INTR_Rx_STATUS_OVERRUN |*/ SiS900_INTR_Rx_OVERRUN |
232 SiS900_INTR_Rx_ERROR | SiS900_INTR_Rx_OK))
233 handled = sis900_rxInterrupt(info);
235 // transmit packet interrupts
236 if (intr & (SiS900_INTR_Tx_UNDERRUN | SiS900_INTR_Tx_ERROR |
237 SiS900_INTR_Tx_IDLE | SiS900_INTR_Tx_OK))
238 handled = sis900_txInterrupt(info);
241 release_spinlock(&info->lock);
242 restore_interrupts(former);
244 return handled;
248 void
249 sis900_disableInterrupts(struct sis_info *info)
251 write32(info->registers + SiS900_MAC_INTR_MASK, 0);
252 write32(info->registers + SiS900_MAC_INTR_ENABLE, 0);
256 void
257 sis900_enableInterrupts(struct sis_info *info)
259 write32(info->registers + SiS900_MAC_INTR_ENABLE, 0);
261 // enable link detection
262 write32(info->registers + SiS900_MAC_WAKEUP_CONTROL,
263 SiS900_WAKEUP_LINK_ON | SiS900_WAKEUP_LINK_LOSS);
265 // set interrupt mask
266 write32(info->registers + SiS900_MAC_INTR_MASK,
267 //SiS900_INTR_WAKEUP_EVENT |
268 SiS900_INTR_Tx_UNDERRUN | SiS900_INTR_Tx_ERROR | SiS900_INTR_Tx_IDLE | SiS900_INTR_Tx_OK |
269 SiS900_INTR_Rx_STATUS_OVERRUN | SiS900_INTR_Rx_OVERRUN |
270 SiS900_INTR_Rx_ERROR | SiS900_INTR_Rx_OK);
272 write32(info->registers + SiS900_MAC_INTR_ENABLE,1);
276 /***************************** PHY and link mode *****************************/
277 // #pragma mark -
280 int32
281 sis900_timer(timer *t)
283 struct sis_info *info = (struct sis_info *)t;
285 if (!info->autoNegotiationComplete) {
286 int32 mode = sis900_readMode(info);
287 if (mode)
288 sis900_setMode(info, mode);
290 return 0;
293 if (info->link) { // link lost
294 uint16 status = mdio_status(info);
296 if ((status & MII_STATUS_LINK) == 0) {
297 info->link = false;
298 dprintf(DEVICE_NAME ": link lost\n");
300 // if it's the internal SiS900 MII PHY, reset it
301 if (info->currentPHY->id0 == PHY_ID0_SiS900_INTERNAL
302 && (info->currentPHY->id1 & 0xfff0) == PHY_ID1_SiS900_INTERNAL)
303 sis900_resetPHY(info);
306 if (!info->link) { // new link established
307 uint16 status;
309 sis900_selectPHY(info);
311 status = mdio_status(info);
312 if (status & MII_STATUS_LINK) {
313 sis900_checkMode(info);
314 info->link = true;
318 // revision = info->pciInfo->revision;
319 // if (!(revision == SiS900_REVISION_SiS630E || revision == SiS900_REVISION_SiS630EA1
320 // || revision == SiS900_REVISION_SiS630A || revision == SiS900_REVISION_SiS630ET))
321 // bug(DEVICE_NAME ": set_eq() not needed!\n");
322 // else
323 // bug("********* set_eq() would be needed! ********\n");
325 return 0;
329 uint16
330 sis900_resetPHY(struct sis_info *info)
332 uint16 status = mdio_status(info);
334 mdio_write(info, MII_CONTROL, MII_CONTROL_RESET);
335 return status;
339 status_t
340 sis900_initPHYs(struct sis_info *info)
342 uint16 phy;
344 // search for total of 32 possible MII PHY addresses
345 for (phy = 0; phy < 32; phy++) {
346 struct mii_phy *mii;
347 uint16 status;
348 int32 i;
350 status = mdio_statusFromPHY(info, phy);
351 if (status == 0xffff || status == 0x0000)
352 // this MII is not accessable
353 continue;
355 mii = (struct mii_phy *)malloc(sizeof(struct mii_phy));
356 if (mii == NULL)
357 return B_NO_MEMORY;
359 mii->address = phy;
360 mii->id0 = mdio_readFromPHY(info, phy, MII_PHY_ID0);
361 mii->id1 = mdio_readFromPHY(info, phy, MII_PHY_ID1);
362 mii->types = MII_HOME;
363 mii->next = info->firstPHY;
364 info->firstPHY = mii;
366 for (i = 0; gMIIChips[i].name; i++) {
367 if (gMIIChips[i].id0 != mii->id0
368 || gMIIChips[i].id1 != (mii->id1 & 0xfff0))
369 continue;
371 dprintf("Found MII PHY: %s\n", gMIIChips[i].name);
373 mii->types = gMIIChips[i].types;
374 break;
376 if (gMIIChips[i].name == NULL)
377 dprintf("Unknown MII PHY transceiver: id = (%x, %x).\n", mii->id0, mii->id1);
380 if (info->firstPHY == NULL) {
381 dprintf("No MII PHY transceiver found!\n");
382 return B_ENTRY_NOT_FOUND;
385 sis900_selectPHY(info);
387 // if the internal PHY is selected, reset it
388 if (info->currentPHY->id0 == PHY_ID0_SiS900_INTERNAL
389 && (info->currentPHY->id1 & 0xfff0) == PHY_ID1_SiS900_INTERNAL) {
390 if (sis900_resetPHY(info) & MII_STATUS_LINK) {
391 uint16 poll = MII_STATUS_LINK;
392 while (poll) {
393 poll ^= mdio_read(info, MII_STATUS) & poll;
398 // workaround for ICS1893 PHY
399 if (info->currentPHY->id0 == PHY_ID0_ICS_1893
400 && (info->currentPHY->id1 & 0xfff0) == PHY_ID1_ICS_1893)
401 mdio_write(info, 0x0018, 0xD200);
403 // SiS 630E has some bugs on default value of PHY registers
404 if (info->pciInfo->revision == SiS900_REVISION_SiS630E) {
405 mdio_write(info, MII_AUTONEG_ADV, 0x05e1);
406 mdio_write(info, MII_CONFIG1, 0x22);
407 mdio_write(info, MII_CONFIG2, 0xff00);
408 mdio_write(info, MII_MASK, 0xffc0);
411 info->link = mdio_status(info) & MII_STATUS_LINK;
413 return B_OK;
417 void
418 sis900_selectPHY(struct sis_info *info)
420 uint16 status;
422 // ToDo: need to be changed, select PHY in relation to the link mode
423 info->currentPHY = info->firstPHY;
424 info->phy = info->currentPHY->address;
426 status = mdio_read(info, MII_CONTROL);
427 status &= ~MII_CONTROL_ISOLATE;
429 mdio_write(info, MII_CONTROL, status);
433 void
434 sis900_setMode(struct sis_info *info, int32 mode)
436 uint32 address = info->registers + SiS900_MAC_CONFIG;
437 uint32 txFlags = SiS900_Tx_AUTO_PADDING | SiS900_Tx_FILL_THRES;
438 uint32 rxFlags = 0;
440 info->speed = mode & LINK_SPEED_MASK;
441 info->full_duplex = (mode & LINK_DUPLEX_MASK) == LINK_FULL_DUPLEX;
443 if (read32(address) & SiS900_MAC_CONFIG_EDB_MASTER) {
444 TRACE((DEVICE_NAME ": EDB master is set!\n"));
445 txFlags |= 5 << SiS900_DMA_SHIFT;
446 rxFlags = 5 << SiS900_DMA_SHIFT;
449 // link speed FIFO thresholds
451 if (info->speed == LINK_SPEED_HOME || info->speed == LINK_SPEED_10_MBIT) {
452 rxFlags |= SiS900_Rx_10_MBIT_DRAIN_THRES;
453 txFlags |= SiS900_Tx_10_MBIT_DRAIN_THRES;
454 } else {
455 rxFlags |= SiS900_Rx_100_MBIT_DRAIN_THRES;
456 txFlags |= SiS900_Tx_100_MBIT_DRAIN_THRES;
459 // duplex mode
461 if (info->full_duplex) {
462 txFlags |= SiS900_Tx_CS_IGNORE | SiS900_Tx_HB_IGNORE;
463 rxFlags |= SiS900_Rx_ACCEPT_Tx_PACKETS;
466 write32(info->registers + SiS900_MAC_Tx_CONFIG, txFlags);
467 write32(info->registers + SiS900_MAC_Rx_CONFIG, rxFlags);
471 int32
472 sis900_readMode(struct sis_info *info)
474 struct mii_phy *phy = info->currentPHY;
475 uint16 autoAdv, autoLinkPartner;
476 int32 speed, duplex;
478 uint16 status = mdio_status(info);
479 if (!(status & MII_STATUS_LINK)) {
480 dprintf(DEVICE_NAME ": no link detected (status = %x)\n", status);
481 return 0;
484 // auto negotiation completed
485 autoAdv = mdio_read(info, MII_AUTONEG_ADV);
486 autoLinkPartner = mdio_read(info, MII_AUTONEG_LINK_PARTNER);
487 status = autoAdv & autoLinkPartner;
489 speed = status & (MII_NWAY_TX | MII_NWAY_TX_FDX) ? LINK_SPEED_100_MBIT : LINK_SPEED_10_MBIT;
490 duplex = status & (MII_NWAY_TX_FDX | MII_NWAY_T_FDX) ? LINK_FULL_DUPLEX : LINK_HALF_DUPLEX;
492 info->autoNegotiationComplete = true;
494 // workaround for Realtek RTL8201 PHY issue
495 if (phy->id0 == PHY_ID0_REALTEK_8201 && (phy->id1 & 0xFFF0) == PHY_ID1_REALTEK_8201) {
496 if (mdio_read(info, MII_CONTROL) & MII_CONTROL_FULL_DUPLEX)
497 duplex = LINK_FULL_DUPLEX;
498 if (mdio_read(info, 0x0019) & 0x01)
499 speed = LINK_SPEED_100_MBIT;
502 dprintf(DEVICE_NAME ": linked, 10%s MBit, %s duplex\n",
503 speed == LINK_SPEED_100_MBIT ? "0" : "",
504 duplex == LINK_FULL_DUPLEX ? "full" : "half");
506 return speed | duplex;
510 static void
511 sis900_setAutoNegotiationCapabilities(struct sis_info *info)
513 uint16 status = mdio_status(info);
514 uint16 capabilities = MII_NWAY_CSMA_CD
515 | (status & MII_STATUS_CAN_TX_FDX ? MII_NWAY_TX_FDX : 0)
516 | (status & MII_STATUS_CAN_TX ? MII_NWAY_TX : 0)
517 | (status & MII_STATUS_CAN_T_FDX ? MII_NWAY_T_FDX : 0)
518 | (status & MII_STATUS_CAN_T ? MII_NWAY_T : 0);
520 TRACE((DEVICE_NAME ": write capabilities %d\n", capabilities));
521 mdio_write(info, MII_AUTONEG_ADV, capabilities);
525 static void
526 sis900_autoNegotiate(struct sis_info *info)
528 uint16 status = mdio_status(info);
530 if ((status & MII_STATUS_LINK) == 0)
532 TRACE((DEVICE_NAME ": media link off\n"));
533 info->autoNegotiationComplete = true;
534 return;
536 TRACE((DEVICE_NAME ": auto negotiation started...\n"));
538 // reset auto negotiation
539 mdio_write(info, MII_CONTROL, MII_CONTROL_AUTO | MII_CONTROL_RESET_AUTONEG);
540 info->autoNegotiationComplete = false;
544 void
545 sis900_checkMode(struct sis_info *info)
547 uint32 address = info->registers + SiS900_MAC_CONFIG;
549 if (info->fixedMode != 0) {
550 TRACE((DEVICE_NAME ": link mode set via settings\n"));
552 // ToDo: what about the excessive deferral timer?
554 sis900_setMode(info, info->fixedMode);
555 info->autoNegotiationComplete = true;
556 } else if (info->currentPHY->types == MII_LAN) {
557 TRACE((DEVICE_NAME ": PHY type is LAN\n"));
559 // enable excessive deferral timer
560 write32(address, ~SiS900_MAC_CONFIG_EXCESSIVE_DEFERRAL & read32(address));
562 sis900_setAutoNegotiationCapabilities(info);
563 sis900_autoNegotiate(info);
564 } else {
565 TRACE((DEVICE_NAME ": PHY type is not LAN\n"));
567 // disable excessive deferral timer
568 write32(address, SiS900_MAC_CONFIG_EXCESSIVE_DEFERRAL | read32(address));
570 sis900_setMode(info, LINK_SPEED_HOME | LINK_HALF_DUPLEX);
571 info->autoNegotiationComplete = true;
576 /***************************** MACs, rings & config *****************************/
577 // #pragma mark -
580 bool
581 sis900_getMACAddress(struct sis_info *info)
583 if (info->pciInfo->revision >= SiS900_REVISION_SiS96x) {
584 // SiS 962 & 963 are using a different method to access the EEPROM
585 // than the standard SiS 630
586 addr_t eepromAccess = info->registers + SiS900_MAC_EEPROM_ACCESS;
587 uint32 tries = 0;
589 write32(eepromAccess, SiS96x_EEPROM_CMD_REQ);
591 while (tries < 1000) {
592 if (read32(eepromAccess) & SiS96x_EEPROM_CMD_GRANT) {
593 int i;
595 /* get MAC address from EEPROM */
596 for (i = 0; i < 3; i++) {
597 uint16 id;
599 id = eeprom_read(info, SiS900_EEPROM_MAC_ADDRESS + i);
600 info->address.ebyte[i*2 + 1] = id >> 8;
601 info->address.ebyte[i*2] = id & 0xff;
604 write32(eepromAccess, SiS96x_EEPROM_CMD_DONE);
605 return true;
606 } else {
607 spin(2);
608 tries++;
611 write32(eepromAccess, SiS96x_EEPROM_CMD_DONE);
612 return false;
613 } else if (info->pciInfo->revision >= SiS900_REVISION_SiS630E) {
614 /* SiS630E and above are using CMOS RAM to store MAC address */
615 pci_info isa;
616 int32 index;
618 for (index = 0; pci->get_nth_pci_info(index, &isa) == B_OK; index++) {
619 if (isa.vendor_id == VENDOR_ID_SiS
620 && isa.device_id == DEVICE_ID_SiS_ISA_BRIDGE) {
621 uint8 reg,i;
622 addr_t registers = isa.u.h0.base_registers[0];
624 reg = pci->read_pci_config(isa.bus,isa.device,isa.function,0x48,1);
625 pci->write_pci_config(isa.bus,isa.device,isa.function,0x48,1,reg | 0x40);
627 for (i = 0; i < 6; i++) {
628 write8(registers + 0x70,0x09 + i);
629 info->address.ebyte[i] = read8(registers + 0x71);
632 pci->write_pci_config(isa.bus,isa.device,isa.function,0x48,1,reg & ~0x40);
633 return true;
636 return false;
637 } else {
638 /* SiS630 stores the MAC in an eeprom */
639 uint16 signature;
640 int i;
642 /* check to see if we have sane EEPROM */
643 signature = eeprom_read(info,SiS900_EEPROM_SIGNATURE);
644 if (signature == 0xffff || signature == 0x0000) {
645 dprintf(DEVICE_NAME ": cannot read EEPROM signature\n");
646 return false;
649 /* get MAC address from EEPROM */
650 for (i = 0; i < 3; i++) {
651 uint16 id;
653 id = eeprom_read(info,SiS900_EEPROM_MAC_ADDRESS + i);
654 info->address.ebyte[i*2 + 1] = id >> 8;
655 info->address.ebyte[i*2] = id & 0xff;
658 return true;
660 return false;
664 status_t
665 sis900_reset(struct sis_info *info)
667 addr_t address = info->registers + SiS900_MAC_COMMAND;
668 int16 tries = 1000;
670 TRACE(("sis900 reset\n"));
672 write32(address, SiS900_MAC_CMD_RESET);
674 write32(info->registers + SiS900_MAC_Rx_FILTER_CONTROL, SiS900_RxF_ENABLE |
675 SiS900_RxF_ACCEPT_ALL_BROADCAST | SiS900_RxF_ACCEPT_ALL_MULTICAST);
677 // wait until the chip leaves reset state
678 while ((read32(address) & SiS900_MAC_CMD_RESET) && tries-- > 0)
679 snooze(2);
681 write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Tx_ENABLE);
683 return B_OK;
687 void
688 sis900_setPromiscuous(struct sis_info *info, bool on)
690 addr_t filterControl = info->registers + SiS900_MAC_Rx_FILTER_CONTROL;
691 int32 filter = read32(filterControl);
693 // accept all incoming packets (or not)
694 if (on) {
695 write32(filterControl, SiS900_RxF_ENABLE |
696 SiS900_RxF_ACCEPT_ALL_BROADCAST | SiS900_RxF_ACCEPT_ALL_MULTICAST);
697 } else
698 write32(filterControl, filter | ~SiS900_RxF_ACCEPT_ALL_ADDRESSES);
702 void
703 sis900_setRxFilter(struct sis_info *info)
705 addr_t filterControl = info->registers + SiS900_MAC_Rx_FILTER_CONTROL;
706 addr_t filterData = info->registers + SiS900_MAC_Rx_FILTER_DATA;
707 int32 i;
709 // set MAC address as receive filter
710 for (i = 0; i < 3; i++) {
711 write32(filterControl, i << SiS900_Rx_FILTER_ADDRESS_SHIFT);
712 write32(filterData, info->address.ebyte[i*2] | (info->address.ebyte[i*2 + 1] << 8));
714 write32(filterControl, SiS900_RxF_ENABLE
715 | SiS900_RxF_ACCEPT_ALL_BROADCAST
716 | SiS900_RxF_ACCEPT_ALL_MULTICAST /*| SiS900_RxF_ACCEPT_ALL_ADDRESSES*/);
720 void
721 sis900_deleteRings(struct sis_info *info)
723 delete_area(info->txArea);
724 delete_area(info->rxArea);
728 status_t
729 sis900_createRings(struct sis_info *info)
731 uint16 i;
733 // create transmit buffer area
734 info->txArea = create_area("sis900 tx buffer", (void **)&info->txBuffer[0],
735 B_ANY_KERNEL_ADDRESS,
736 ROUND_TO_PAGE_SIZE(BUFFER_SIZE * NUM_Tx_DESCR),
737 B_32_BIT_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
738 if (info->txArea < B_OK)
739 return info->txArea;
741 // initialize transmit buffer descriptors
742 for (i = 1; i < NUM_Tx_DESCR; i++)
743 info->txBuffer[i] = (void *)(((addr_t)info->txBuffer[0]) + (i * BUFFER_SIZE));
745 for (i = 0; i < NUM_Tx_DESCR; i++) {
746 info->txDescriptor[i].status = 0;
747 info->txDescriptor[i].buffer = physicalAddress(info->txBuffer[i], BUFFER_SIZE);
748 info->txDescriptor[i].link =
749 #if (NUM_Tx_DESCR == 1)
751 #else
752 physicalAddress(&info->txDescriptor[(i + 1) & NUM_Tx_MASK], sizeof(struct buffer_desc));
753 #endif
756 // create receive buffer area
757 info->rxArea = create_area("sis900 rx buffer", (void **)&info->rxBuffer[0],
758 B_ANY_KERNEL_ADDRESS,
759 ROUND_TO_PAGE_SIZE(BUFFER_SIZE * NUM_Rx_DESCR),
760 B_32_BIT_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
761 if (info->rxArea < B_OK) {
762 delete_area(info->txArea);
763 return info->rxArea;
766 // initialize receive buffer descriptors
767 for (i = 1; i < NUM_Rx_DESCR; i++)
768 info->rxBuffer[i] = (void *)(((addr_t)info->rxBuffer[0]) + (i * BUFFER_SIZE));
770 for (i = 0; i < NUM_Rx_DESCR; i++) {
771 info->rxDescriptor[i].status = MAX_FRAME_SIZE;
772 info->rxDescriptor[i].buffer = physicalAddress(info->rxBuffer[i], BUFFER_SIZE);
773 info->rxDescriptor[i].link = physicalAddress(&info->rxDescriptor[(i + 1) & NUM_Rx_MASK],
774 sizeof(struct buffer_desc));
776 info->rxFree = NUM_Rx_DESCR;
778 // set descriptor pointer registers
779 write32(info->registers + SiS900_MAC_Tx_DESCR,
780 physicalAddress(&info->txDescriptor[0], sizeof(struct buffer_desc)));
781 write32(info->registers + SiS900_MAC_Rx_DESCR,
782 physicalAddress(&info->rxDescriptor[0], sizeof(struct buffer_desc)));
784 return B_OK;