
|
[openbeos]
||
[Date Prev]
[01-2007 Date Index]
[Date Next]
||
[Thread Prev]
[01-2007 Thread Index]
[Thread Next]
[openbeos] updated driver
- From: Bernd Korz <bernd.korz@xxxxxxxxxxx>
- To: openbeos@xxxxxxxxxxxxx
- Date: Fri, 05 Jan 2007 08:55:44 +0100
Hi Axel,
i added a new device to the driver. I have attached the already modified
sis900.c from the haiku tree, so you just need to replace it.
This is the change for track:
#define PHY_ID0_VIA_6103 0x0101
#define PHY_ID1_VIA_6103 0x8f20
{"VIA 6103 PHY",
PHY_ID0_VIA_6103, PHY_ID1_VIA_6103, MII_LAN},
Take care,
Bernd
www.berndsworld.com/* SiS 900 chip specific functions
*
* Copyright © 2001-2005 pinc Software. All Rights Reserved.
* Distributed under the terms of the MIT license.
*/
#include <OS.h>
#include <KernelExport.h>
#include <Drivers.h>
#include <PCI.h>
#include <SupportDefs.h>
#include <stdlib.h>
#include <string.h>
#include "ether_driver.h"
#include "driver.h"
#include "device.h"
#include "interface.h"
#include "sis900.h"
// prototypes
uint16 sis900_resetPHY(struct sis_info *info);
void sis900_selectPHY(struct sis_info *info);
void sis900_setMode(struct sis_info *info, int32 mode);
int32 sis900_readMode(struct sis_info *info);
// MII chip info table
#define PHY_ID0_SiS900_INTERNAL 0x001d
#define PHY_ID1_SiS900_INTERNAL 0x8000
#define PHY_ID0_ICS_1893 0x0015
#define PHY_ID1_ICS_1893 0xff40
#define PHY_ID0_REALTEK_8201 0x0000
#define PHY_ID1_REALTEK_8201 0x8200
#define PHY_ID0_VIA_6103 0x0101
#define PHY_ID1_VIA_6103 0x8f20
#define MII_HOME 0x0001
#define MII_LAN 0x0002
const static struct mii_chip_info {
const char *name;
uint16 id0, id1;
uint8 types;
} gMIIChips[] = {
{"SiS 900 Internal MII PHY",
PHY_ID0_SiS900_INTERNAL, PHY_ID1_SiS900_INTERNAL, MII_LAN},
{"SiS 7014 Physical Layer Solution",
0x0016, 0xf830, MII_LAN},
{"AMD 79C901 10BASE-T PHY",
0x0000, 0x6B70, MII_LAN},
{"AMD 79C901 HomePNA PHY",
0x0000, 0x6B90, MII_HOME},
{"ICS 1893 LAN PHY",
PHY_ID0_ICS_1893, PHY_ID1_ICS_1893, MII_LAN},
{"NS 83851 PHY",
0x2000, 0x5C20, MII_LAN | MII_HOME},
{"Realtek RTL8201 PHY",
PHY_ID0_REALTEK_8201, PHY_ID1_REALTEK_8201, MII_LAN},
{"VIA 6103 PHY",
PHY_ID0_VIA_6103, PHY_ID1_VIA_6103, MII_LAN},
{NULL, 0, 0, 0}
};
/***************************** helper functions *****************************/
static uint32
physicalAddress(volatile void *address, uint32 length)
{
physical_entry table;
get_memory_map((void *)address, length, &table, 1);
return (uint32)table.address;
}
/***************************** interrupt handling *****************************/
// #pragma mark -
int32 intrCounter = 0;
int32 lastIntr[100];
static int32
sis900_rxInterrupt(struct sis_info *info)
{
int32 handled = B_UNHANDLED_INTERRUPT;
int16 releaseRxSem = 0;
int16 limit;
acquire_spinlock(&info->rxSpinlock);
HACK(spin(10000));
// check for packet ownership
for (limit = info->rxFree; limit > 0; limit--) {
if (!(info->rxDescriptor[info->rxInterruptIndex].status &
SiS900_DESCR_OWN)) {
// if (limit == info->rxFree)
// {
//dprintf("here!\n");
// limit++;
// continue;
// }
break;
}
//dprintf("received frame %d!\n",info->rxInterruptIndex);
releaseRxSem++;
info->rxInterruptIndex = (info->rxInterruptIndex + 1) &
NUM_Rx_MASK;
info->rxFree--;
}
release_spinlock(&info->rxSpinlock);
// reenable rx queue
write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Rx_ENABLE);
if (releaseRxSem) {
release_sem_etc(info->rxSem, releaseRxSem, B_DO_NOT_RESCHEDULE);
return B_INVOKE_SCHEDULER;
}
return handled;
}
static int32
sis900_txInterrupt(struct sis_info *info)
{
int16 releaseTxSem = 0;
uint32 status;
int16 limit;
acquire_spinlock(&info->txSpinlock);
HACK(spin(10000));
for (limit = info->txSent; limit > 0; limit--) {
status = info->txDescriptor[info->txInterruptIndex].status;
//dprintf("txIntr: %d: mem = %lx : hardware = %lx\n",info->txInterruptIndex,
//
physicalAddress(&info->txDescriptor[info->txInterruptIndex],sizeof(struct
buffer_desc)),
// read32(info->registers + SiS900_MAC_Tx_DESCR));
/* Does the device generate extra interrupts? */
if (status & SiS900_DESCR_OWN) {
struct buffer_desc *descriptor = (void
*)read32(info->registers + SiS900_MAC_Tx_DESCR);
int16 that;
for (that = 0;
that < NUM_Tx_DESCR && (void
*)physicalAddress(&info->txDescriptor[that],
sizeof(struct buffer_desc)) !=
descriptor; that++) {
}
if (that == NUM_Tx_DESCR)
that = 0;
//dprintf("tx busy %d: %lx (hardware status %d =
%lx)!\n",info->txInterruptIndex,status,that,info->txDescriptor[that].status);
// if (limit == info->txSent)
// {
//dprintf("oh no!\n");
// limit++;
// continue;
// }
break;
}
if (status & (SiS900_DESCR_Tx_ABORT | SiS900_DESCR_Tx_UNDERRUN
| SiS900_DESCR_Tx_OOW_COLLISION)) {
dprintf("tx error: %lx\n", status);
} else
info->txDescriptor[info->txInterruptIndex].status = 0;
releaseTxSem++; /* this many buffers are free */
info->txInterruptIndex = (info->txInterruptIndex + 1) &
NUM_Tx_MASK;
info->txSent--;
if (info->txSent < 0 || info->txSent > NUM_Tx_DESCR)
dprintf("ERROR interrupt: txSent = %d\n", info->txSent);
}
release_spinlock(&info->txSpinlock);
if (releaseTxSem) {
release_sem_etc(info->txSem, releaseTxSem, B_DO_NOT_RESCHEDULE);
return B_INVOKE_SCHEDULER;
}
return B_HANDLED_INTERRUPT;
}
int32
sis900_interrupt(void *data)
{
struct sis_info *info = data;
int32 handled = B_UNHANDLED_INTERRUPT;
int16 worklimit = 20;
uint32 intr;
cpu_status former;
former = disable_interrupts();
acquire_spinlock(&info->lock);
while (worklimit-- > 0) {
// reading the interrupt status register clears all interrupts
intr = read32(info->registers + SiS900_MAC_INTR_STATUS);
if (!intr)
break;
TRACE(("************ interrupt received: %08lx
**************\n", intr));
intrCounter = (intrCounter + 1) % 100;
lastIntr[intrCounter] = intr;
// wake-up event interrupt
if (intr & SiS900_INTR_WAKEUP_EVENT) {
TRACE(("wake-up event received: %ld\n",
read32(info->registers +
SiS900_MAC_WAKEUP_EVENT)));
// clear PM event register
write32(info->registers + SiS900_MAC_WAKEUP_EVENT,
SiS900_WAKEUP_LINK_ON |
SiS900_WAKEUP_LINK_LOSS);
handled = B_HANDLED_INTERRUPT;
}
// receive packet interrupts
if (intr & (/*SiS900_INTR_Rx_STATUS_OVERRUN |*/
SiS900_INTR_Rx_OVERRUN |
SiS900_INTR_Rx_ERROR |
SiS900_INTR_Rx_OK))
handled = sis900_rxInterrupt(info);
// transmit packet interrupts
if (intr & (SiS900_INTR_Tx_UNDERRUN | SiS900_INTR_Tx_ERROR |
SiS900_INTR_Tx_IDLE |
SiS900_INTR_Tx_OK))
handled = sis900_txInterrupt(info);
}
release_spinlock(&info->lock);
restore_interrupts(former);
return handled;
}
void
sis900_disableInterrupts(struct sis_info *info)
{
write32(info->registers + SiS900_MAC_INTR_MASK, 0);
write32(info->registers + SiS900_MAC_INTR_ENABLE, 0);
}
void
sis900_enableInterrupts(struct sis_info *info)
{
write32(info->registers + SiS900_MAC_INTR_ENABLE, 0);
// enable link detection
write32(info->registers + SiS900_MAC_WAKEUP_CONTROL,
SiS900_WAKEUP_LINK_ON | SiS900_WAKEUP_LINK_LOSS);
// set interrupt mask
write32(info->registers + SiS900_MAC_INTR_MASK,
//SiS900_INTR_WAKEUP_EVENT |
SiS900_INTR_Tx_UNDERRUN | SiS900_INTR_Tx_ERROR |
SiS900_INTR_Tx_IDLE | SiS900_INTR_Tx_OK |
SiS900_INTR_Rx_STATUS_OVERRUN | SiS900_INTR_Rx_OVERRUN |
SiS900_INTR_Rx_ERROR | SiS900_INTR_Rx_OK);
write32(info->registers + SiS900_MAC_INTR_ENABLE,1);
}
/***************************** PHY and link mode *****************************/
// #pragma mark -
int32
sis900_timer(timer *t)
{
struct sis_info *info = (struct sis_info *)t;
if (!info->autoNegotiationComplete) {
int32 mode = sis900_readMode(info);
if (mode)
sis900_setMode(info, mode);
return 0;
}
if (info->link) { // link lost
uint16 status = mdio_status(info);
if ((status & MII_STATUS_LINK) == 0) {
info->link = false;
dprintf(DEVICE_NAME ": link lost\n");
// if it's the internal SiS900 MII PHY, reset it
if (info->currentPHY->id0 == PHY_ID0_SiS900_INTERNAL
&& (info->currentPHY->id1 & 0xfff0) ==
PHY_ID1_SiS900_INTERNAL)
sis900_resetPHY(info);
}
}
if (!info->link) { // new link established
uint16 status;
sis900_selectPHY(info);
status = mdio_status(info);
if (status & MII_STATUS_LINK) {
sis900_checkMode(info);
info->link = true;
}
}
// revision = info->pciInfo->revision;
// if (!(revision == SiS900_REVISION_SiS630E || revision ==
SiS900_REVISION_SiS630EA1
// || revision == SiS900_REVISION_SiS630A || revision ==
SiS900_REVISION_SiS630ET))
// bug(DEVICE_NAME ": set_eq() not needed!\n");
// else
// bug("********* set_eq() would be needed! ********\n");
return 0;
}
uint16
sis900_resetPHY(struct sis_info *info)
{
uint16 status = mdio_status(info);
mdio_write(info, MII_CONTROL, MII_CONTROL_RESET);
return status;
}
status_t
sis900_initPHYs(struct sis_info *info)
{
uint16 phy;
// search for total of 32 possible MII PHY addresses
for (phy = 0; phy < 32; phy++) {
struct mii_phy *mii;
uint16 status;
int32 i;
status = mdio_statusFromPHY(info, phy);
if (status == 0xffff || status == 0x0000)
// this MII is not accessable
continue;
mii = (struct mii_phy *)malloc(sizeof(struct mii_phy));
if (mii == NULL)
return B_NO_MEMORY;
mii->address = phy;
mii->id0 = mdio_readFromPHY(info, phy, MII_PHY_ID0);
mii->id1 = mdio_readFromPHY(info, phy, MII_PHY_ID1);
mii->types = MII_HOME;
mii->next = info->firstPHY;
info->firstPHY = mii;
for (i = 0; gMIIChips[i].name; i++) {
if (gMIIChips[i].id0 != mii->id0
|| gMIIChips[i].id1 != (mii->id1 & 0xfff0))
continue;
dprintf("Found MII PHY: %s\n", gMIIChips[i].name);
mii->types = gMIIChips[i].types;
break;
}
if (gMIIChips[i].name == NULL)
dprintf("Unknown MII PHY transceiver: id = (%x,
%x).\n", mii->id0, mii->id1);
}
if (info->firstPHY == NULL) {
dprintf("No MII PHY transceiver found!\n");
return B_ENTRY_NOT_FOUND;
}
sis900_selectPHY(info);
// if the internal PHY is selected, reset it
if (info->currentPHY->id0 == PHY_ID0_SiS900_INTERNAL
&& (info->currentPHY->id1 & 0xfff0) == PHY_ID1_SiS900_INTERNAL)
{
if (sis900_resetPHY(info) & MII_STATUS_LINK) {
uint16 poll = MII_STATUS_LINK;
while (poll) {
poll ^= mdio_read(info, MII_STATUS) & poll;
}
}
}
// workaround for ICS1893 PHY
if (info->currentPHY->id0 == PHY_ID0_ICS_1893
&& (info->currentPHY->id1 & 0xfff0) == PHY_ID1_ICS_1893)
mdio_write(info, 0x0018, 0xD200);
// SiS 630E has some bugs on default value of PHY registers
if (info->pciInfo->revision == SiS900_REVISION_SiS630E) {
mdio_write(info, MII_AUTONEG_ADV, 0x05e1);
mdio_write(info, MII_CONFIG1, 0x22);
mdio_write(info, MII_CONFIG2, 0xff00);
mdio_write(info, MII_MASK, 0xffc0);
}
info->link = mdio_status(info) & MII_STATUS_LINK;
return B_OK;
}
void
sis900_selectPHY(struct sis_info *info)
{
uint16 status;
// ToDo: need to be changed, select PHY in relation to the link mode
info->currentPHY = info->firstPHY;
info->phy = info->currentPHY->address;
status = mdio_read(info, MII_CONTROL);
status &= ~MII_CONTROL_ISOLATE;
mdio_write(info, MII_CONTROL, status);
}
void
sis900_setMode(struct sis_info *info, int32 mode)
{
uint32 address = info->registers + SiS900_MAC_CONFIG;
uint32 txFlags = SiS900_Tx_AUTO_PADDING | SiS900_Tx_FILL_THRES;
uint32 rxFlags = 0;
int32 speed = mode & LINK_SPEED_MASK;
if (read32(address) & SiS900_MAC_CONFIG_EDB_MASTER) {
TRACE((DEVICE_NAME ": EDB master is set!\n"));
txFlags |= 5 << SiS900_DMA_SHIFT;
rxFlags = 5 << SiS900_DMA_SHIFT;
}
// link speed FIFO thresholds
if (speed == LINK_SPEED_HOME || speed == LINK_SPEED_10_MBIT) {
rxFlags |= SiS900_Rx_10_MBIT_DRAIN_THRES;
txFlags |= SiS900_Tx_10_MBIT_DRAIN_THRES;
} else {
rxFlags |= SiS900_Rx_100_MBIT_DRAIN_THRES;
txFlags |= SiS900_Tx_100_MBIT_DRAIN_THRES;
}
// duplex mode
if ((mode & LINK_DUPLEX_MASK) == LINK_FULL_DUPLEX) {
txFlags |= SiS900_Tx_CS_IGNORE | SiS900_Tx_HB_IGNORE;
rxFlags |= SiS900_Rx_ACCEPT_Tx_PACKETS;
}
write32(info->registers + SiS900_MAC_Tx_CONFIG, txFlags);
write32(info->registers + SiS900_MAC_Rx_CONFIG, rxFlags);
}
int32
sis900_readMode(struct sis_info *info)
{
struct mii_phy *phy = info->currentPHY;
uint16 autoAdv, autoLinkPartner;
int32 speed, duplex;
uint16 status = mdio_status(info);
if (!(status & MII_STATUS_LINK)) {
dprintf(DEVICE_NAME ": no link detected (status = %x)\n",
status);
return 0;
}
// auto negotiation completed
autoAdv = mdio_read(info, MII_AUTONEG_ADV);
autoLinkPartner = mdio_read(info, MII_AUTONEG_LINK_PARTNER);
status = autoAdv & autoLinkPartner;
speed = status & (MII_NWAY_TX | MII_NWAY_TX_FDX) ? LINK_SPEED_100_MBIT
: LINK_SPEED_10_MBIT;
duplex = status & (MII_NWAY_TX_FDX | MII_NWAY_T_FDX) ? LINK_FULL_DUPLEX
: LINK_HALF_DUPLEX;
info->autoNegotiationComplete = true;
// workaround for Realtek RTL8201 PHY issue
if (phy->id0 == PHY_ID0_REALTEK_8201 && (phy->id1 & 0xFFF0) ==
PHY_ID1_REALTEK_8201) {
if (mdio_read(info, MII_CONTROL) & MII_CONTROL_FULL_DUPLEX)
duplex = LINK_FULL_DUPLEX;
if (mdio_read(info, 0x0019) & 0x01)
speed = LINK_SPEED_100_MBIT;
}
dprintf(DEVICE_NAME ": linked, 10%s MBit, %s duplex\n",
speed == LINK_SPEED_100_MBIT ? "0" : "",
duplex == LINK_FULL_DUPLEX ? "full" : "half");
return speed | duplex;
}
static void
sis900_setAutoNegotiationCapabilities(struct sis_info *info)
{
uint16 status = mdio_status(info);
uint16 capabilities = MII_NWAY_CSMA_CD
| (status & MII_STATUS_CAN_TX_FDX ? MII_NWAY_TX_FDX : 0)
| (status & MII_STATUS_CAN_TX ? MII_NWAY_TX : 0)
| (status & MII_STATUS_CAN_T_FDX ? MII_NWAY_T_FDX : 0)
| (status & MII_STATUS_CAN_T ? MII_NWAY_T : 0);
TRACE((DEVICE_NAME ": write capabilities %d\n", capabilities));
mdio_write(info, MII_AUTONEG_ADV, capabilities);
}
static void
sis900_autoNegotiate(struct sis_info *info)
{
uint16 status = mdio_status(info);
if ((status & MII_STATUS_LINK) == 0)
{
TRACE((DEVICE_NAME ": media link off\n"));
info->autoNegotiationComplete = true;
return;
}
TRACE((DEVICE_NAME ": auto negotiation started...\n"));
// reset auto negotiation
mdio_write(info, MII_CONTROL, MII_CONTROL_AUTO |
MII_CONTROL_RESET_AUTONEG);
info->autoNegotiationComplete = false;
}
void
sis900_checkMode(struct sis_info *info)
{
uint32 address = info->registers + SiS900_MAC_CONFIG;
if (info->fixedMode != 0) {
TRACE((DEVICE_NAME ": link mode set via settings\n"));
// ToDo: what about the excessive deferral timer?
sis900_setMode(info, info->fixedMode);
info->autoNegotiationComplete = true;
} else if (info->currentPHY->types == MII_LAN) {
TRACE((DEVICE_NAME ": PHY type is LAN\n"));
// enable excessive deferral timer
write32(address, ~SiS900_MAC_CONFIG_EXCESSIVE_DEFERRAL &
read32(address));
sis900_setAutoNegotiationCapabilities(info);
sis900_autoNegotiate(info);
} else {
TRACE((DEVICE_NAME ": PHY type is not LAN\n"));
// disable excessive deferral timer
write32(address, SiS900_MAC_CONFIG_EXCESSIVE_DEFERRAL |
read32(address));
sis900_setMode(info, LINK_SPEED_HOME | LINK_HALF_DUPLEX);
info->autoNegotiationComplete = true;
}
}
/***************************** MACs, rings & config
*****************************/
// #pragma mark -
bool
sis900_getMACAddress(struct sis_info *info)
{
if (info->pciInfo->revision >= SiS900_REVISION_SiS96x) {
// SiS 962 & 963 are using a different method to access the
EEPROM
// than the standard SiS 630
addr_t eepromAccess = info->registers +
SiS900_MAC_EEPROM_ACCESS;
uint32 tries = 0;
write32(eepromAccess, SiS96x_EEPROM_CMD_REQ);
while (tries < 1000) {
if (read32(eepromAccess) & SiS96x_EEPROM_CMD_GRANT) {
int i;
/* get MAC address from EEPROM */
for (i = 0; i < 3; i++) {
uint16 id;
id = eeprom_read(info,
SiS900_EEPROM_MAC_ADDRESS + i);
info->address.ebyte[i*2 + 1] = id >> 8;
info->address.ebyte[i*2] = id & 0xff;
}
write32(eepromAccess, SiS96x_EEPROM_CMD_DONE);
return true;
} else {
spin(2);
tries++;
}
}
write32(eepromAccess, SiS96x_EEPROM_CMD_DONE);
return false;
} else if (info->pciInfo->revision >= SiS900_REVISION_SiS630E) {
/* SiS630E and above are using CMOS RAM to store MAC address */
pci_info isa;
int32 index;
for (index = 0; pci->get_nth_pci_info(index, &isa) == B_OK;
index++) {
if (isa.vendor_id == VENDOR_ID_SiS
&& isa.device_id == DEVICE_ID_SiS_ISA_BRIDGE) {
uint8 reg,i;
addr_t registers = isa.u.h0.base_registers[0];
reg =
pci->read_pci_config(isa.bus,isa.device,isa.function,0x48,1);
pci->write_pci_config(isa.bus,isa.device,isa.function,0x48,1,reg | 0x40);
for (i = 0; i < 6; i++) {
write8(registers + 0x70,0x09 + i);
info->address.ebyte[i] =
read8(registers + 0x71);
}
pci->write_pci_config(isa.bus,isa.device,isa.function,0x48,1,reg & ~0x40);
return true;
}
}
return false;
} else {
/* SiS630 stores the MAC in an eeprom */
uint16 signature;
int i;
/* check to see if we have sane EEPROM */
signature = eeprom_read(info,SiS900_EEPROM_SIGNATURE);
if (signature == 0xffff || signature == 0x0000) {
dprintf(DEVICE_NAME ": cannot read EEPROM signature\n");
return false;
}
/* get MAC address from EEPROM */
for (i = 0; i < 3; i++) {
uint16 id;
id = eeprom_read(info,SiS900_EEPROM_MAC_ADDRESS + i);
info->address.ebyte[i*2 + 1] = id >> 8;
info->address.ebyte[i*2] = id & 0xff;
}
return true;
}
return false;
}
status_t
sis900_reset(struct sis_info *info)
{
addr_t address = info->registers + SiS900_MAC_COMMAND;
int16 tries = 1000;
TRACE(("sis900 reset\n"));
write32(address, SiS900_MAC_CMD_RESET);
write32(info->registers + SiS900_MAC_Rx_FILTER_CONTROL,
SiS900_RxF_ENABLE |
SiS900_RxF_ACCEPT_ALL_BROADCAST |
SiS900_RxF_ACCEPT_ALL_MULTICAST);
// wait until the chip leaves reset state
while ((read32(address) & SiS900_MAC_CMD_RESET) && tries-- > 0)
snooze(2);
write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Tx_ENABLE);
return B_OK;
}
void
sis900_setPromiscuous(struct sis_info *info, bool on)
{
addr_t filterControl = info->registers + SiS900_MAC_Rx_FILTER_CONTROL;
int32 filter = read32(filterControl);
// accept all incoming packets (or not)
if (on) {
write32(filterControl, SiS900_RxF_ENABLE |
SiS900_RxF_ACCEPT_ALL_BROADCAST |
SiS900_RxF_ACCEPT_ALL_MULTICAST);
} else
write32(filterControl, filter |
~SiS900_RxF_ACCEPT_ALL_ADDRESSES);
}
void
sis900_setRxFilter(struct sis_info *info)
{
addr_t filterControl = info->registers + SiS900_MAC_Rx_FILTER_CONTROL;
addr_t filterData = info->registers + SiS900_MAC_Rx_FILTER_DATA;
int32 i;
// set MAC address as receive filter
for (i = 0; i < 3; i++) {
write32(filterControl, i << SiS900_Rx_FILTER_ADDRESS_SHIFT);
write32(filterData, info->address.ebyte[i*2] |
(info->address.ebyte[i*2 + 1] << 8));
}
write32(filterControl, SiS900_RxF_ENABLE
| SiS900_RxF_ACCEPT_ALL_BROADCAST
| SiS900_RxF_ACCEPT_ALL_MULTICAST /*|
SiS900_RxF_ACCEPT_ALL_ADDRESSES*/);
}
void
sis900_deleteRings(struct sis_info *info)
{
delete_area(info->txArea);
delete_area(info->rxArea);
}
status_t
sis900_createRings(struct sis_info *info)
{
uint16 i;
// create transmit buffer area
info->txArea = create_area("sis900 tx buffer", (void
**)&info->txBuffer[0],
B_ANY_KERNEL_ADDRESS,
ROUND_TO_PAGE_SIZE(BUFFER_SIZE * NUM_Tx_DESCR),
B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
if (info->txArea < B_OK)
return info->txArea;
// initialize transmit buffer descriptors
for (i = 1; i < NUM_Tx_DESCR; i++)
info->txBuffer[i] = (void *)(((uint32)info->txBuffer[0]) + (i *
BUFFER_SIZE));
for (i = 0; i < NUM_Tx_DESCR; i++) {
info->txDescriptor[i].status = 0;
info->txDescriptor[i].buffer =
physicalAddress(info->txBuffer[i], BUFFER_SIZE);
info->txDescriptor[i].link =
#if (NUM_Tx_DESCR == 1)
0;
#else
physicalAddress(&info->txDescriptor[(i + 1) &
NUM_Tx_MASK], sizeof(struct buffer_desc));
#endif
}
// create receive buffer area
info->rxArea = create_area("sis900 rx buffer", (void
**)&info->rxBuffer[0],
B_ANY_KERNEL_ADDRESS,
ROUND_TO_PAGE_SIZE(BUFFER_SIZE * NUM_Rx_DESCR),
B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
if (info->rxArea < B_OK) {
delete_area(info->txArea);
return info->rxArea;
}
// initialize receive buffer descriptors
for (i = 1; i < NUM_Rx_DESCR; i++)
info->rxBuffer[i] = (void *)(((uint32)info->rxBuffer[0]) + (i *
BUFFER_SIZE));
for (i = 0; i < NUM_Rx_DESCR; i++) {
info->rxDescriptor[i].status = MAX_FRAME_SIZE;
info->rxDescriptor[i].buffer =
physicalAddress(info->rxBuffer[i], BUFFER_SIZE);
info->rxDescriptor[i].link =
physicalAddress(&info->rxDescriptor[(i + 1) & NUM_Rx_MASK],
sizeof(struct buffer_desc));
}
info->rxFree = NUM_Rx_DESCR;
// set descriptor pointer registers
write32(info->registers + SiS900_MAC_Tx_DESCR,
physicalAddress(&info->txDescriptor[0], sizeof(struct
buffer_desc)));
write32(info->registers + SiS900_MAC_Rx_DESCR,
physicalAddress(&info->rxDescriptor[0], sizeof(struct
buffer_desc)));
return B_OK;
}
|

|