1/* SiS 900 chip specific functions
2 *
3 * Copyright © 2001-2005 pinc Software. All Rights Reserved.
4 * Distributed under the terms of the MIT license.
5 */
6
7
8#include <OS.h>
9#include <KernelExport.h>
10#include <Drivers.h>
11#include <PCI.h>
12#include <SupportDefs.h>
13
14#include <stdlib.h>
15#include <string.h>
16
17#include "ether_driver.h"
18#include "driver.h"
19#include "device.h"
20#include "interface.h"
21#include "sis900.h"
22
23
24// prototypes
25
26uint16 sis900_resetPHY(struct sis_info *info);
27void sis900_selectPHY(struct sis_info *info);
28void sis900_setMode(struct sis_info *info, int32 mode);
29int32 sis900_readMode(struct sis_info *info);
30
31
32// MII chip info table
33
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
42
43#define	MII_HOME	0x0001
44#define MII_LAN		0x0002
45
46const 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}
68};
69
70
71/***************************** helper functions *****************************/
72
73
74static phys_addr_t
75physicalAddress(volatile void *address, uint32 length)
76{
77	physical_entry table;
78
79	get_memory_map((void *)address, length, &table, 1);
80	return table.address;
81}
82
83
84/***************************** interrupt handling *****************************/
85// #pragma mark -
86int32 intrCounter = 0;
87int32 lastIntr[100];
88
89
90static int32
91sis900_rxInterrupt(struct sis_info *info)
92{
93	int32 handled = B_UNHANDLED_INTERRUPT;
94	int16 releaseRxSem = 0;
95	int16 limit;
96
97	acquire_spinlock(&info->rxSpinlock);
98
99	HACK(spin(10000));
100
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;
111		}
112		//dprintf("received frame %d!\n",info->rxInterruptIndex);
113
114		releaseRxSem++;
115		info->rxInterruptIndex = (info->rxInterruptIndex + 1) & NUM_Rx_MASK;
116		info->rxFree--;
117	}
118	release_spinlock(&info->rxSpinlock);
119
120	// reenable rx queue
121	write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Rx_ENABLE);
122
123	if (releaseRxSem) {
124		release_sem_etc(info->rxSem, releaseRxSem, B_DO_NOT_RESCHEDULE);
125		return B_INVOKE_SCHEDULER;
126	}
127
128	return handled;
129}
130
131
132static int32
133sis900_txInterrupt(struct sis_info *info)
134{
135	int16 releaseTxSem = 0;
136	uint32 status;
137	int16 limit;
138
139	acquire_spinlock(&info->txSpinlock);
140
141	HACK(spin(10000));
142
143	for (limit = info->txSent; limit > 0; limit--) {
144		status = info->txDescriptor[info->txInterruptIndex].status;
145
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));
149
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++) {
159			}
160			if (that == NUM_Tx_DESCR)
161				that = 0;
162
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;
171		}
172
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;
178
179		releaseTxSem++;	/* this many buffers are free */
180		info->txInterruptIndex = (info->txInterruptIndex + 1) & NUM_Tx_MASK;
181		info->txSent--;
182
183		if (info->txSent < 0 || info->txSent > NUM_Tx_DESCR)
184			dprintf("ERROR interrupt: txSent = %d\n", info->txSent);
185	}
186	release_spinlock(&info->txSpinlock);
187
188	if (releaseTxSem) {
189		release_sem_etc(info->txSem, releaseTxSem, B_DO_NOT_RESCHEDULE);
190		return B_INVOKE_SCHEDULER;
191	}
192
193	return B_HANDLED_INTERRUPT;
194}
195
196
197int32
198sis900_interrupt(void *data)
199{
200	struct sis_info *info = data;
201	int32 handled = B_UNHANDLED_INTERRUPT;
202	int16 worklimit = 20;
203	uint32 intr;
204	cpu_status former;
205
206	former = disable_interrupts();
207	acquire_spinlock(&info->lock);
208
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;
214
215		TRACE(("************ interrupt received: %08lx **************\n", intr));
216		intrCounter = (intrCounter + 1) % 100;
217		lastIntr[intrCounter] = intr;
218
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)));
223
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;
228		}
229
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);
234
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);
239	}
240
241	release_spinlock(&info->lock);
242	restore_interrupts(former);
243
244	return handled;
245}
246
247
248void
249sis900_disableInterrupts(struct sis_info *info)
250{
251	write32(info->registers + SiS900_MAC_INTR_MASK, 0);
252	write32(info->registers + SiS900_MAC_INTR_ENABLE, 0);
253}
254
255
256void
257sis900_enableInterrupts(struct sis_info *info)
258{
259	write32(info->registers + SiS900_MAC_INTR_ENABLE, 0);
260
261	// enable link detection
262	write32(info->registers + SiS900_MAC_WAKEUP_CONTROL,
263		SiS900_WAKEUP_LINK_ON | SiS900_WAKEUP_LINK_LOSS);
264
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);
271
272	write32(info->registers + SiS900_MAC_INTR_ENABLE,1);
273}
274
275
276/***************************** PHY and link mode *****************************/
277// #pragma mark -
278
279
280int32
281sis900_timer(timer *t)
282{
283	struct sis_info *info = (struct sis_info *)t;
284
285	if (!info->autoNegotiationComplete) {
286		int32 mode = sis900_readMode(info);
287		if (mode)
288			sis900_setMode(info, mode);
289
290		return 0;
291	}
292
293	if (info->link)	{	// link lost
294		uint16 status = mdio_status(info);
295
296		if ((status & MII_STATUS_LINK) == 0) {
297			info->link = false;
298			dprintf(DEVICE_NAME ": link lost\n");
299
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);
304		}
305	}
306	if (!info->link) {	// new link established
307		uint16 status;
308
309		sis900_selectPHY(info);
310
311		status = mdio_status(info);
312		if (status & MII_STATUS_LINK) {
313			sis900_checkMode(info);
314			info->link = true;
315		}
316	}
317
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");
324
325	return 0;
326}
327
328
329uint16
330sis900_resetPHY(struct sis_info *info)
331{
332	uint16 status = mdio_status(info);
333
334	mdio_write(info, MII_CONTROL, MII_CONTROL_RESET);
335	return status;
336}
337
338
339status_t
340sis900_initPHYs(struct sis_info *info)
341{
342	uint16 phy;
343
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;
349
350		status = mdio_statusFromPHY(info, phy);
351		if (status == 0xffff || status == 0x0000)
352			// this MII is not accessable
353			continue;
354
355		mii = (struct mii_phy *)malloc(sizeof(struct mii_phy));
356		if (mii == NULL)
357			return B_NO_MEMORY;
358
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;
365
366		for (i = 0; gMIIChips[i].name; i++) {
367			if (gMIIChips[i].id0 != mii->id0
368				|| gMIIChips[i].id1 != (mii->id1 & 0xfff0))
369				continue;
370
371			dprintf("Found MII PHY: %s\n", gMIIChips[i].name);
372
373			mii->types = gMIIChips[i].types;
374			break;
375		}
376		if (gMIIChips[i].name == NULL)
377			dprintf("Unknown MII PHY transceiver: id = (%x, %x).\n", mii->id0, mii->id1);
378	}
379
380	if (info->firstPHY == NULL) {
381		dprintf("No MII PHY transceiver found!\n");
382		return B_ENTRY_NOT_FOUND;
383	}
384
385	sis900_selectPHY(info);
386
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;
394			}
395		}
396	}
397
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);
402
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);
409	}
410
411	info->link = mdio_status(info) & MII_STATUS_LINK;
412
413	return B_OK;
414}
415
416
417void
418sis900_selectPHY(struct sis_info *info)
419{
420	uint16 status;
421
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;
425
426	status = mdio_read(info, MII_CONTROL);
427	status &= ~MII_CONTROL_ISOLATE;
428
429	mdio_write(info, MII_CONTROL, status);
430}
431
432
433void
434sis900_setMode(struct sis_info *info, int32 mode)
435{
436	uint32 address = info->registers + SiS900_MAC_CONFIG;
437	uint32 txFlags = SiS900_Tx_AUTO_PADDING | SiS900_Tx_FILL_THRES;
438	uint32 rxFlags = 0;
439
440	info->speed = mode & LINK_SPEED_MASK;
441	info->full_duplex = (mode & LINK_DUPLEX_MASK) == LINK_FULL_DUPLEX;
442
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;
447	}
448
449	// link speed FIFO thresholds
450
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;
457	}
458
459	// duplex mode
460
461	if (info->full_duplex) {
462		txFlags |= SiS900_Tx_CS_IGNORE | SiS900_Tx_HB_IGNORE;
463		rxFlags |= SiS900_Rx_ACCEPT_Tx_PACKETS;
464	}
465
466	write32(info->registers + SiS900_MAC_Tx_CONFIG, txFlags);
467	write32(info->registers + SiS900_MAC_Rx_CONFIG, rxFlags);
468}
469
470
471int32
472sis900_readMode(struct sis_info *info)
473{
474	struct mii_phy *phy = info->currentPHY;
475	uint16 autoAdv, autoLinkPartner;
476	int32 speed, duplex;
477
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;
482	}
483
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;
488
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;
491
492	info->autoNegotiationComplete = true;
493
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;
500	}
501
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");
505
506	return speed | duplex;
507}
508
509
510static void
511sis900_setAutoNegotiationCapabilities(struct sis_info *info)
512{
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);
519
520	TRACE((DEVICE_NAME ": write capabilities %d\n", capabilities));
521	mdio_write(info, MII_AUTONEG_ADV, capabilities);
522}
523
524
525static void
526sis900_autoNegotiate(struct sis_info *info)
527{
528	uint16 status = mdio_status(info);
529
530	if ((status & MII_STATUS_LINK) == 0)
531	{
532		TRACE((DEVICE_NAME ": media link off\n"));
533		info->autoNegotiationComplete = true;
534		return;
535	}
536	TRACE((DEVICE_NAME ": auto negotiation started...\n"));
537
538	// reset auto negotiation
539	mdio_write(info, MII_CONTROL, MII_CONTROL_AUTO | MII_CONTROL_RESET_AUTONEG);
540	info->autoNegotiationComplete = false;
541}
542
543
544void
545sis900_checkMode(struct sis_info *info)
546{
547	uint32 address = info->registers + SiS900_MAC_CONFIG;
548
549	if (info->fixedMode != 0) {
550		TRACE((DEVICE_NAME ": link mode set via settings\n"));
551
552		// ToDo: what about the excessive deferral timer?
553
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"));
558
559		// enable excessive deferral timer
560		write32(address, ~SiS900_MAC_CONFIG_EXCESSIVE_DEFERRAL & read32(address));
561
562		sis900_setAutoNegotiationCapabilities(info);
563		sis900_autoNegotiate(info);
564	} else {
565		TRACE((DEVICE_NAME ": PHY type is not LAN\n"));
566
567		// disable excessive deferral timer
568		write32(address, SiS900_MAC_CONFIG_EXCESSIVE_DEFERRAL | read32(address));
569
570		sis900_setMode(info, LINK_SPEED_HOME | LINK_HALF_DUPLEX);
571		info->autoNegotiationComplete = true;
572	}
573}
574
575
576/***************************** MACs, rings & config *****************************/
577// #pragma mark -
578
579
580bool
581sis900_getMACAddress(struct sis_info *info)
582{
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;
588
589		write32(eepromAccess, SiS96x_EEPROM_CMD_REQ);
590
591		while (tries < 1000) {
592			if (read32(eepromAccess) & SiS96x_EEPROM_CMD_GRANT) {
593				int i;
594
595				/* get MAC address from EEPROM */
596				for (i = 0; i < 3; i++) {
597					uint16 id;
598
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;
602				}
603
604				write32(eepromAccess, SiS96x_EEPROM_CMD_DONE);
605				return true;
606			} else {
607				spin(2);
608				tries++;
609			}
610		}
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;
617
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];
623
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);
626
627				for (i = 0; i < 6; i++) {
628					write8(registers + 0x70,0x09 + i);
629					info->address.ebyte[i] = read8(registers + 0x71);
630				}
631
632				pci->write_pci_config(isa.bus,isa.device,isa.function,0x48,1,reg & ~0x40);
633				return true;
634			}
635		}
636		return false;
637	} else {
638		/* SiS630 stores the MAC in an eeprom */
639		uint16 signature;
640		int i;
641
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;
647		}
648
649		/* get MAC address from EEPROM */
650		for (i = 0; i < 3; i++) {
651			uint16 id;
652
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;
656		}
657
658		return true;
659	}
660	return false;
661}
662
663
664status_t
665sis900_reset(struct sis_info *info)
666{
667	addr_t address = info->registers + SiS900_MAC_COMMAND;
668	int16 tries = 1000;
669
670	TRACE(("sis900 reset\n"));
671
672	write32(address, SiS900_MAC_CMD_RESET);
673
674	write32(info->registers + SiS900_MAC_Rx_FILTER_CONTROL, SiS900_RxF_ENABLE |
675			SiS900_RxF_ACCEPT_ALL_BROADCAST | SiS900_RxF_ACCEPT_ALL_MULTICAST);
676
677	// wait until the chip leaves reset state
678	while ((read32(address) & SiS900_MAC_CMD_RESET) && tries-- > 0)
679		snooze(2);
680
681	write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Tx_ENABLE);
682
683	return B_OK;
684}
685
686
687void
688sis900_setPromiscuous(struct sis_info *info, bool on)
689{
690	addr_t filterControl = info->registers + SiS900_MAC_Rx_FILTER_CONTROL;
691	int32 filter = read32(filterControl);
692
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);
699}
700
701
702void
703sis900_setRxFilter(struct sis_info *info)
704{
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;
708
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));
713	}
714	write32(filterControl, SiS900_RxF_ENABLE
715		| SiS900_RxF_ACCEPT_ALL_BROADCAST
716		| SiS900_RxF_ACCEPT_ALL_MULTICAST /*| SiS900_RxF_ACCEPT_ALL_ADDRESSES*/);
717}
718
719
720void
721sis900_deleteRings(struct sis_info *info)
722{
723	delete_area(info->txArea);
724	delete_area(info->rxArea);
725}
726
727
728status_t
729sis900_createRings(struct sis_info *info)
730{
731	uint16 i;
732
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;
740
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));
744
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)
750			0;
751#else
752			physicalAddress(&info->txDescriptor[(i + 1) & NUM_Tx_MASK], sizeof(struct buffer_desc));
753#endif
754	}
755
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;
764	}
765
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));
769
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));
775	}
776	info->rxFree = NUM_Rx_DESCR;
777
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)));
783
784	return B_OK;
785}
786
787