drivers/rtl8169: Remove.

Has not been included in the image for a long time; all the devices
it supported are handled by the "rtl81xx" FreeBSD driver.
This commit is contained in:
Augustin Cavalier
2018-12-21 13:16:13 -05:00
parent 1ac98e3ab4
commit a380bb0236
14 changed files with 0 additions and 2009 deletions
@@ -8,7 +8,6 @@ SubInclude HAIKU_TOP src add-ons kernel drivers network wwan ;
SubInclude HAIKU_TOP src add-ons kernel drivers network etherpci ;
SubInclude HAIKU_TOP src add-ons kernel drivers network pegasus ;
SubInclude HAIKU_TOP src add-ons kernel drivers network virtio ;
SubInclude HAIKU_TOP src add-ons kernel drivers network rtl8169 ;
SubInclude HAIKU_TOP src add-ons kernel drivers network sis19x ;
SubInclude HAIKU_TOP src add-ons kernel drivers network sis900 ;
SubInclude HAIKU_TOP src add-ons kernel drivers network usb_asix ;
@@ -1,26 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel drivers network rtl8169 ;
SetSubDirSupportedPlatformsBeOSCompatible ;
# For ether_driver.h
UsePrivateHeaders net ;
KernelAddon rtl8169 :
driver.c
device.c
timer.c
util.c
;
# Installation
HaikuInstall install-networking : /boot/home/config/add-ons/kernel/drivers/bin :
rtl8169
;
HaikuInstallRelSymLink install-networking : /boot/home/config/add-ons/kernel/drivers/dev/net :
<installed>rtl8169 :
installed-symlink
;
@@ -1,43 +0,0 @@
/* Realtek RTL8169 Family Driver
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies, and that both the
* copyright notice and this permission notice appear in supporting documentation.
*
* Marcus Overhagen makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
*
* MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
* OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __DEBUG_H
#define __DEBUG_H
#include <KernelExport.h>
// #define PROFILING
#ifdef DEBUG
#define TRACE(a...) dprintf("rtl8169: " a)
#define ASSERT(a) if (a) ; else panic("rtl8169: ASSERT failed, " #a)
#else
#define TRACE(a...)
#define ASSERT(a...)
#endif
#ifdef PROFILING
#define PROFILING_ONLY(a) a
#else
#define PROFILING_ONLY(a)
#endif
#define ERROR(a...) dprintf("rtl8169: ERROR " a)
#define PRINT(a...) dprintf("rtl8169: " a)
#endif
@@ -1,999 +0,0 @@
/* Realtek RTL8169 Family Driver
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies, and that both the
* copyright notice and this permission notice appear in supporting documentation.
*
* Marcus Overhagen makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
*
* MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
* OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <KernelExport.h>
#include <Errors.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <driver_settings.h>
#include <net/if_media.h>
#include "debug.h"
#include "device.h"
#include "driver.h"
#include "hardware.h"
#include "util.h"
static int32 gOpenMask = 0;
static void
read_settings(rtl8169_device *device)
{
void *handle;
const char *param;
int mtu, count;
handle = load_driver_settings("rtl8169");
if (!handle)
return;
param = get_driver_parameter(handle, "mtu", "-1", "-1");
mtu = atoi(param);
if (mtu >= 50 && mtu <= 1500)
device->maxframesize = mtu + 14;
else if (mtu != -1)
dprintf("rtl8169: unsupported mtu setting '%s' ignored\n", param);
param = get_driver_parameter(handle, "rx_buffer_count", "-1", "-1");
count = atoi(param);
if (count >= 2 && count <= 1024)
device->rxBufferCount = count;
else if (count != -1)
dprintf("rtl8169: unsupported rx_buffer_count setting '%s' ignored\n", param);
param = get_driver_parameter(handle, "tx_buffer_count", "-1", "-1");
count = atoi(param);
if (count >= 2 && count <= 1024)
device->txBufferCount = count;
else if (count != -1)
dprintf("rtl8169: unsupported tx_buffer_count setting '%s' ignored\n", param);
unload_driver_settings(handle);
}
static void
write_phy_reg(rtl8169_device *device, int reg, uint16 value)
{
int i;
write32(REG_PHYAR, 0x80000000 | (reg & 0x1f) << 16 | value);
snooze(1000);
for (i = 0; i < 2000; i++) {
if ((read32(REG_PHYAR) & 0x80000000) == 0)
break;
snooze(100);
}
}
static uint16
read_phy_reg(rtl8169_device *device, int reg)
{
uint32 v;
int i;
write32(REG_PHYAR, (reg & 0x1f) << 16);
snooze(1000);
for (i = 0; i < 2000; i++) {
v = read32(REG_PHYAR);
if (v & 0x80000000)
return v & 0xffff;
snooze(100);
}
return 0xffff;
}
static inline void
write_phy_reg_bit(rtl8169_device *device, int reg, int bitnum, int bitval)
{
uint16 val = read_phy_reg(device, reg);
if (bitval == 1)
val |= (1 << bitnum);
else
val &= ~(1 << bitnum);
write_phy_reg(device, reg, val);
}
static void
phy_config(rtl8169_device *device)
{
TRACE("phy_config()\n");
if (device->phy_version == 0 || device->phy_version == 1) {
uint16 val;
TRACE("performing phy init\n");
// XXX this should probably not be done if the phy wasn't
// identified, but BSD does it too for mac_version == 0 (=> phy_version also 0)
// doing the same as the BSD and Linux driver here
// see IEE 802.3-2002 (is also uses decimal numbers when refering
// to the registers, as do we). Added a little documentation
write_phy_reg(device, 31, 0x0001); // vendor specific (enter programming mode?)
write_phy_reg(device, 21, 0x1000); // vendor specific
write_phy_reg(device, 24, 0x65c7); // vendor specific
write_phy_reg_bit(device, 4, 11, 0); // reset T (T=toggle) bit in reg 4 (ability)
val = read_phy_reg(device, 4) & 0x0fff; // get only the message code fields
write_phy_reg(device, 4, val); // and write them back. this clears the page and makes it unformatted (see 37.2.4.3.1)
write_phy_reg(device, 3, 0x00a1); // assign 32 bit phy identifier high word
write_phy_reg(device, 2, 0x0008); // assign 32 bit phy identifier low word
write_phy_reg(device, 1, 0x1020); // set status: 10 MBit full duplex and auto negotiation completed
write_phy_reg(device, 0, 0x1000); // reset the phy!
write_phy_reg_bit(device, 4, 11, 1); // set toggle bit high
write_phy_reg_bit(device, 4, 11, 0); // set toggle bit low => this is a toggle
val = (read_phy_reg(device, 4) & 0x0fff) | 0x7000; // set ack1, ack2, indicate formatted page
write_phy_reg(device, 4, val); // write the value from above
write_phy_reg(device, 3, 0xff41); // assign another
write_phy_reg(device, 2, 0xde60); // 32 bit phy identifier
write_phy_reg(device, 1, 0x0140); // phy will accept management frames with preamble suppressed, extended capability in reg 15
write_phy_reg(device, 0, 0x0077); //
write_phy_reg_bit(device, 4, 11, 1); // set toggle bit high
write_phy_reg_bit(device, 4, 11, 0); // set toggle bit low => this is a toggle
val = ( read_phy_reg(device, 4) & 0x0fff) | 0xa000;
write_phy_reg(device, 4, val); //
write_phy_reg(device, 3, 0xdf01); // assign another
write_phy_reg(device, 2, 0xdf20); // 32 bit phy identifier
write_phy_reg(device, 1, 0xff95); // phy will do 100Mbit and 10Mbit in full and half duplex, something reserved and
// remote fault detected, link is up and extended capability in reg 15
write_phy_reg(device, 0, 0xfa00); // select 10 MBit, disable auto neg., half duplex normal operation
write_phy_reg_bit(device, 4, 11, 1); // set toggle bit high
write_phy_reg_bit(device, 4, 11, 0); // set toggle bit low => this is a toggle
val = ( read_phy_reg(device, 4) & 0x0fff) | 0xb000;
write_phy_reg(device, 4, val); // write capabilites
write_phy_reg(device, 3, 0xff41); // assign another
write_phy_reg(device, 2, 0xde20); // 32 bit phy identifier
write_phy_reg(device, 1, 0x0140); // phy will accept management frames with preamble suppressed, extended capability in reg 15
write_phy_reg(device, 0, 0x00bb); // write status
write_phy_reg_bit(device, 4, 11, 1); // set toggle bit high
write_phy_reg_bit(device, 4, 11, 0); // set toggle bit low => this is a toggle
val = ( read_phy_reg(device, 4) & 0x0fff) | 0xf000;
write_phy_reg(device, 4, val); //w 4 15 12 f
write_phy_reg(device, 3, 0xdf01); // assign another
write_phy_reg(device, 2, 0xdf20); // 32 bit phy identifier
write_phy_reg(device, 1, 0xff95); // write capabilites
write_phy_reg(device, 0, 0xbf00); // write status
write_phy_reg_bit(device, 4, 11, 1); // set toggle bit high
write_phy_reg_bit(device, 4, 11, 0); // set toggle bit low => this is a toggle
write_phy_reg(device, 31, 0x0000); // vendor specific (leave programming mode?)
}
write_phy_reg(device, 4, 0x01e1); // 10/100 capability
write_phy_reg(device, 9, 0x0200); // 1000 capability
write_phy_reg(device, 0, 0x1200); // enable auto negotiation and restart it
}
static void
dump_phy_stat(rtl8169_device *device)
{
uint32 v = read8(REG_PHY_STAT);
if (v & PHY_STAT_EnTBI) {
uint32 tbi = read32(REG_TBICSR);
TRACE("TBI mode active\n");
if (tbi & TBICSR_ResetTBI)
TRACE("TBICSR_ResetTBI\n");
if (tbi & TBICSR_TBILoopBack)
TRACE("TBICSR_TBILoopBack\n");
if (tbi & TBICSR_TBINWEn)
TRACE("TBICSR_TBINWEn\n");
if (tbi & TBICSR_TBIReNW)
TRACE("TBICSR_TBIReNW\n");
if (tbi & TBICSR_TBILinkOk)
TRACE("TBICSR_TBILinkOk\n");
if (tbi & TBICSR_NWComplete)
TRACE("TBICSR_NWComplete\n");
} else {
TRACE("TBI mode NOT active\n");
if (v & PHY_STAT_1000MF)
TRACE("PHY_STAT_1000MF\n");
if (v & PHY_STAT_100M)
TRACE("PHY_STAT_100M\n");
if (v & PHY_STAT_10M)
TRACE("PHY_STAT_10M\n");
}
if (v & PHY_STAT_TxFlow)
TRACE("PHY_STAT_TxFlow\n");
if (v & PHY_STAT_RxFlow)
TRACE("PHY_STAT_RxFlow\n");
if (v & PHY_STAT_LinkSts)
TRACE("PHY_STAT_LinkSts\n");
if (v & PHY_STAT_FullDup)
TRACE("PHY_STAT_FullDup\n");
}
static void
print_link_status(rtl8169_device *device)
{
uint32 phy = read8(REG_PHY_STAT);
if (phy & PHY_STAT_EnTBI) {
if (read32(REG_TBICSR) & TBICSR_TBILinkOk)
PRINT("Link active, 1000 Mbit Full Duplex (TBI mode)\n");
else
PRINT("Link not active (TBI mode)\n");
} else {
if (phy & PHY_STAT_LinkSts) {
if (phy & PHY_STAT_1000MF)
PRINT("Link active, 1000 Mbit Full Duplex (GMII mode)\n");
else
PRINT("Link active, %s Mbit %s Duplex (MII mode)\n",
(phy & PHY_STAT_100M) ? "100" : (phy & PHY_STAT_10M) ? "10" : "unknown",
(phy & PHY_STAT_FullDup) ? "Full" : "Half");
} else {
PRINT("Link not active (MII mode)\n");
}
}
}
#ifdef PROFILING
static void
print_debug_info(void *cookie)
{
rtl8169_device *device = (rtl8169_device *)cookie;
// only print if interrupt count changed
if (device->intTotalCount == device->intTotalCountOld)
return;
PRINT("Int %10d, %6d/s Rx: %10d, %6d/s Tx: %10d, %6d/s Tmr %10d, %6d/s\n",
device->intTotalCount,
device->intCurrentCount,
device->intRxTotalCount,
device->intRxCurrentCount,
device->intTxTotalCount,
device->intTxCurrentCount,
device->intTimerTotalCount,
device->intTimerCurrentCount);
device->intTotalCountOld = device->intTotalCount;
device->intCurrentCount = 0;
device->intRxCurrentCount = 0;
device->intTxCurrentCount = 0;
device->intTimerCurrentCount = 0;
}
#endif // PROFILING
static status_t
init_buf_desc(rtl8169_device *device)
{
void *rx_buf_desc_virt, *rx_buf_desc_phy;
void *tx_buf_desc_virt, *tx_buf_desc_phy;
void *tx_buf_virt, *tx_buf_phy;
void *rx_buf_virt, *rx_buf_phy;
int i;
device->txBufArea = alloc_contiguous(&tx_buf_virt, &tx_buf_phy,
device->txBufferCount * FRAME_SIZE, 0, "rtl8169 tx buf");
device->rxBufArea = alloc_contiguous(&rx_buf_virt, &rx_buf_phy,
device->rxBufferCount * FRAME_SIZE, 0, "rtl8169 rx buf");
device->txDescArea = alloc_contiguous(&tx_buf_desc_virt, &tx_buf_desc_phy,
device->txBufferCount * sizeof(buf_desc), 0, "rtl8169 tx desc");
device->rxDescArea = alloc_contiguous(&rx_buf_desc_virt, &rx_buf_desc_phy,
device->rxBufferCount * sizeof(buf_desc), 0, "rtl8169 rx desc");
if (device->txBufArea < B_OK || device->rxBufArea < B_OK
|| device->txDescArea < B_OK || device->rxDescArea < B_OK)
return B_NO_MEMORY;
device->txDesc = (buf_desc *)tx_buf_desc_virt;
device->rxDesc = (buf_desc *)rx_buf_desc_virt;
// setup transmit descriptors
for (i = 0; i < device->txBufferCount; i++) {
device->txBuf[i] = (char *)tx_buf_virt + (i * FRAME_SIZE);
device->txDesc[i].stat_len = TX_DESC_FS | TX_DESC_LS;
device->txDesc[i].buf_low
= (uint32)((char *)tx_buf_phy + (i * FRAME_SIZE));
device->txDesc[i].buf_high = 0;
}
device->txDesc[i - 1].stat_len |= TX_DESC_EOR;
// setup receive descriptors
for (i = 0; i < device->rxBufferCount; i++) {
device->rxBuf[i] = (char *)rx_buf_virt + (i * FRAME_SIZE);
device->rxDesc[i].stat_len = RX_DESC_OWN | FRAME_SIZE;
device->rxDesc[i].buf_low
= (uint32)((char *)rx_buf_phy + (i * FRAME_SIZE));
device->rxDesc[i].buf_high = 0;
}
device->rxDesc[i - 1].stat_len |= RX_DESC_EOR;
write32(REG_RDSAR_LOW, (uint32)rx_buf_desc_phy);
write32(REG_RDSAR_HIGH, 0);
write32(REG_TNPDS_LOW, (uint32)tx_buf_desc_phy);
write32(REG_TNPDS_HIGH, 0);
write32(REG_THPDS_LOW, 0); // high priority tx is unused
write32(REG_THPDS_HIGH, 0);
return B_OK;
}
static inline void
rtl8169_tx_int(rtl8169_device *device)
{
int32 limit;
int32 count;
acquire_spinlock(&device->txSpinlock);
for (count = 0, limit = device->txUsed; limit > 0; limit--) {
if (device->txDesc[device->txIntIndex].stat_len & TX_DESC_OWN)
break;
device->txIntIndex = (device->txIntIndex + 1) % device->txBufferCount;
count++;
}
// dprintf("tx int, txUsed %d, count %d\n", device->txUsed, count);
device->txUsed -= count;
release_spinlock(&device->txSpinlock);
if (count)
release_sem_etc(device->txFreeSem, count, B_DO_NOT_RESCHEDULE);
}
static inline void
rtl8169_rx_int(rtl8169_device *device)
{
int32 limit;
int32 count;
acquire_spinlock(&device->rxSpinlock);
for (count = 0, limit = device->rxFree; limit > 0; limit--) {
if (device->rxDesc[device->rxIntIndex].stat_len & RX_DESC_OWN)
break;
device->rxIntIndex = (device->rxIntIndex + 1) % device->rxBufferCount;
count++;
}
// dprintf("rx int, rxFree %d, count %d\n", device->rxFree, count);
device->rxFree -= count;
release_spinlock(&device->rxSpinlock);
if (count)
release_sem_etc(device->rxReadySem, count, B_DO_NOT_RESCHEDULE);
}
static status_t
rtl8169_get_link_state(rtl8169_device *device)
{
bool link_ok = false;
bool full_duplex = false;
uint32 speed = 0;
bool linkStateChange = false;
uint32 phy;
dump_phy_stat(device);
print_link_status(device);
phy = read8(REG_PHY_STAT);
if (phy & PHY_STAT_EnTBI) {
link_ok = (read32(REG_TBICSR) & TBICSR_TBILinkOk);
if (link_ok) {
speed = 1000000;
full_duplex = true;
}
} else {
if (phy & PHY_STAT_LinkSts) {
link_ok = true;
if (phy & PHY_STAT_1000MF) {
speed = 1000000;
full_duplex = true;
} else {
speed = (phy & PHY_STAT_100M) ? 100000 : 10000;
full_duplex = (phy & PHY_STAT_FullDup);
}
}
}
linkStateChange = (link_ok != device->link_ok
|| full_duplex != device->full_duplex
|| speed != device->speed);
device->link_ok = link_ok;
device->full_duplex = full_duplex;
device->speed = speed;
if (linkStateChange && device->linkChangeSem >= B_OK)
release_sem_etc(device->linkChangeSem, 1, B_DO_NOT_RESCHEDULE);
return B_OK;
}
static int32
rtl8169_int(void *data)
{
rtl8169_device *device = (rtl8169_device *)data;
uint16 stat;
int32 ret;
stat = read16(REG_INT_STAT);
if (stat == 0 || stat == 0xffff)
return B_UNHANDLED_INTERRUPT;
write16(REG_INT_STAT, stat);
ret = B_HANDLED_INTERRUPT;
PROFILING_ONLY(device->intTotalCount++);
PROFILING_ONLY(device->intCurrentCount++);
if (stat & INT_TimeOut) {
PROFILING_ONLY(device->intTimerTotalCount++);
PROFILING_ONLY(device->intTimerCurrentCount++);
}
if (stat & INT_PUN) {
rtl8169_get_link_state(device);
}
if (stat & (INT_TOK | INT_TER)) {
rtl8169_tx_int(device);
PROFILING_ONLY(device->intTxTotalCount++);
PROFILING_ONLY(device->intTxCurrentCount++);
ret = B_INVOKE_SCHEDULER;
}
if (stat & (INT_ROK | INT_RER | INT_FOVW)) {
rtl8169_rx_int(device);
PROFILING_ONLY(device->intRxTotalCount++);
PROFILING_ONLY(device->intRxCurrentCount++);
ret = B_INVOKE_SCHEDULER;
}
return ret;
}
status_t
rtl8169_open(const char *name, uint32 flags, void** cookie)
{
rtl8169_device *device;
char *deviceName;
int mmioIndex;
uint32 val;
int dev_id;
int mask;
int i;
TRACE("rtl8169_open()\n");
for (dev_id = 0; (deviceName = gDevNameList[dev_id]) != NULL; dev_id++) {
if (!strcmp(name, deviceName))
break;
}
if (deviceName == NULL) {
ERROR("invalid device name\n");
return B_ERROR;
}
// allow only one concurrent access
mask = 1 << dev_id;
if (atomic_or(&gOpenMask, mask) & mask)
return B_BUSY;
*cookie = device = (rtl8169_device *)malloc(sizeof(rtl8169_device));
if (!device) {
atomic_and(&gOpenMask, ~(1 << dev_id));
return B_NO_MEMORY;
}
memset(device, 0, sizeof(*device));
device->devId = dev_id;
device->pciInfo = gDevList[dev_id];
device->nonblocking = (flags & O_NONBLOCK) ? true : false;
device->closed = false;
// setup defaults
device->maxframesize = 1514; // not FRAME_SIZE
device->txBufferCount = DEFAULT_TX_BUF_COUNT;
device->rxBufferCount = DEFAULT_RX_BUF_COUNT;
// get modifications from settings file
read_settings(device);
device->rxBuf = (void **)malloc(sizeof(void *) * device->rxBufferCount);
B_INITIALIZE_SPINLOCK(&device->rxSpinlock);
device->rxNextIndex = 0;
device->rxIntIndex = 0;
device->rxFree = device->rxBufferCount;
device->rxReadySem = create_sem(0, "rtl8169 rx ready");
device->txBuf = (void **)malloc(sizeof(void *) * device->txBufferCount);
B_INITIALIZE_SPINLOCK(&device->txSpinlock);
device->txNextIndex = 0;
device->txIntIndex = 0;
device->txUsed = 0;
device->txFreeSem = create_sem(device->txBufferCount, "rtl8169 tx free");
// enable busmaster and memory mapped access, disable io port access
val = gPci->read_pci_config(device->pciInfo->bus, device->pciInfo->device,
device->pciInfo->function, PCI_command, 2);
val = PCI_PCICMD_BME | PCI_PCICMD_MSE | (val & ~PCI_PCICMD_IOS);
gPci->write_pci_config(device->pciInfo->bus, device->pciInfo->device,
device->pciInfo->function, PCI_command, 2, val);
// adjust PCI latency timer
TRACE("changing PCI latency to 0x40\n");
gPci->write_pci_config(device->pciInfo->bus, device->pciInfo->device,
device->pciInfo->function, PCI_latency, 1, 0x40);
// get IRQ
device->irq = device->pciInfo->u.h0.interrupt_line;
if (device->irq == 0 || device->irq == 0xff) {
ERROR("no IRQ assigned\n");
goto err;
}
TRACE("IRQ %d\n", device->irq);
// map registers into memory
if (device->pciInfo->device_id == 0x8168)
mmioIndex = 2;
else
mmioIndex = 1;
TRACE("hardware register address [%i] %p\n", mmioIndex,
(void *)device->pciInfo->u.h0.base_registers[mmioIndex]);
device->regArea = map_mem(&device->regAddr,
(void *)device->pciInfo->u.h0.base_registers[mmioIndex], 256, 0,
"rtl8169 register");
if (device->regArea < B_OK) {
ERROR("can't map hardware registers\n");
goto err;
}
TRACE("mapped registers to %p\n", device->regAddr);
// disable receiver & transmitter XXX might be removed
write8(REG_CR, read8(REG_CR) & ~(CR_RE | CR_TE));
// do a soft reset
write8(REG_CR, read8(REG_CR) | CR_RST);
for (i = 0; (read8(REG_CR) & CR_RST) && i < 1000; i++)
snooze(10);
if (i == 1000) {
ERROR("hardware reset failed\n");
goto err;
}
TRACE("reset done\n");
// get MAC hardware version
device->mac_version = ((read32(REG_TX_CONFIG) & 0x7c000000) >> 25)
| ((read32(REG_TX_CONFIG) & 0x00800000) >> 23);
TRACE("8169 Mac Version %d\n", device->mac_version);
if (device->mac_version > 0) { // this is a RTL8169s single chip
// get PHY hardware version
device->phy_version = read_phy_reg(device, 0x03) & 0x000f;
TRACE("8169 Phy Version %d\n", device->phy_version);
} else {
// we should probably detect what kind of phy is used
device->phy_version = 0;
TRACE("8169 Phy Version unknown\n");
}
if (device->mac_version == 1) {
// as it's done by the BSD driver...
TRACE("Setting MAC Reg C+CR 0x82h = 0x01h\n");
write8(0x82, 0x01); // don't know what this does
TRACE("Setting PHY Reg 0x0bh = 0x00h\n");
write_phy_reg(device, 0x0b, 0x0000);
// 0xb is a reserved (vendor specific register), don't know what
// this does
}
// configure PHY
phy_config(device);
device->linkChangeSem = -1;
rtl8169_get_link_state(device);
// initialize MAC address
for (i = 0; i < 6; i++)
device->macaddr[i] = read8(i);
TRACE("MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
device->macaddr[0], device->macaddr[1], device->macaddr[2],
device->macaddr[3], device->macaddr[4], device->macaddr[5]);
// setup interrupt handler
if (install_io_interrupt_handler(device->irq, rtl8169_int, device, 0)
< B_OK) {
ERROR("can't install interrupt handler\n");
goto err;
}
#ifdef PROFILING
device->intTotalCount = 0;
device->intTotalCountOld = 0;
device->intRxTotalCount = 0;
device->intTxTotalCount = 0;
device->intTimerTotalCount = 0;
device->intCurrentCount = 0;
device->intRxCurrentCount = 0;
device->intTxCurrentCount = 0;
device->intTimerCurrentCount = 0;
device->timer = create_timer(print_debug_info, device, 1000000,
B_PERIODIC_TIMER);
#endif // PROFILING
write16(0xe0, read16(0xe0)); // write CR+ command
write16(0xe0, read16(0xe0) | 0x0003);
// don't know what this does, BSD says "enable C+ Tx/Rx"
if (device->mac_version == 1) {
TRACE("Setting Reg C+CR bit 3 and bit 14 to 1\n");
// bit 3 is PCI multiple read/write enable (max Tx/Rx DMA burst size
// setting is no longer valid then)
// bit 14 ??? (need more docs)
write16(0xe0, read16(0xe0) | 0x4008);
}
// setup buffer descriptors and buffers
if (init_buf_desc(device) != B_OK) {
ERROR("setting up buffer descriptors failed\n");
goto err;
}
// enable receiver & transmitter
write8(REG_CR, read8(REG_CR) | CR_RE | CR_TE);
write8(REG_9346CR, 0xc0); // enable config access
write8(REG_CONFIG1, read8(REG_CONFIG1) & ~1); // disable power management
write8(REG_9346CR, 0x00); // disable config access
write8(0xec, 0x3f); // disable early transmit treshold
write16(0xda, FRAME_SIZE); // receive packet maximum size
write16(0x5c, read16(0x5c) & 0xf000); // disable early receive interrupts
write32(0x4c, 0); // RxMissed ???
// setup receive config, can only be done when receiver is enabled!
// 1024 byte FIFO treshold, 1024 DMA burst
write32(REG_RX_CONFIG, (read32(REG_RX_CONFIG) & RX_CONFIG_MASK)
| (0x6 << RC_CONFIG_RXFTH_Shift) | (0x6 << RC_CONFIG_MAXDMA_Shift)
| RX_CONFIG_AcceptBroad | RX_CONFIG_AcceptMulti
| RX_CONFIG_AcceptMyPhys);
write32(0x8, 0); // multicast filter
write32(0xc, 0); // multicast filter
// setup transmit config, can only be done when transmitter is enabled!
// append CRC, 1024 DMA burst
write32(REG_TX_CONFIG, (read32(REG_TX_CONFIG) & ~(0x10000 | (1 << 8)))
| (0x6 << 8));
// clear pending interrupt status
write16(REG_INT_STAT, 0xffff);
// enable used interrupts
write16(REG_INT_MASK, INT_FOVW | INT_PUN | INT_TER | INT_TOK | INT_RER
| INT_ROK);
return B_OK;
err:
delete_sem(device->rxReadySem);
delete_sem(device->txFreeSem);
delete_area(device->regArea);
delete_area(device->txBufArea);
delete_area(device->rxBufArea);
delete_area(device->txDescArea);
delete_area(device->rxDescArea);
free(device->txBuf);
free(device->rxBuf);
free(device);
atomic_and(&gOpenMask, ~(1 << dev_id));
return B_ERROR;
}
status_t
rtl8169_close(void* cookie)
{
rtl8169_device *device = (rtl8169_device *)cookie;
TRACE("rtl8169_close()\n");
device->closed = true;
release_sem(device->rxReadySem);
release_sem(device->txFreeSem);
return B_OK;
}
status_t
rtl8169_free(void* cookie)
{
rtl8169_device *device = (rtl8169_device *)cookie;
TRACE("rtl8169_free()\n");
// disable receiver & transmitter
write8(REG_CR, read8(REG_CR) & ~(CR_RE | CR_TE));
// disable interrupts
write16(REG_INT_MASK, 0);
PROFILING_ONLY(delete_timer(device->timer));
// well...
remove_io_interrupt_handler (device->irq, rtl8169_int, device);
delete_sem(device->rxReadySem);
delete_sem(device->txFreeSem);
delete_area(device->regArea);
delete_area(device->txBufArea);
delete_area(device->rxBufArea);
delete_area(device->txDescArea);
delete_area(device->rxDescArea);
free(device->txBuf);
free(device->rxBuf);
free(device);
atomic_and(&gOpenMask, ~(1 << device->devId));
return B_OK;
}
status_t
rtl8169_read(void* cookie, off_t position, void *buf, size_t* numBytes)
{
rtl8169_device *device = (rtl8169_device *)cookie;
cpu_status cpu;
status_t stat;
int len;
TRACE("rtl8169_read() enter\n");
if (device->closed) {
TRACE("rtl8169_read() interrupted 1\n");
return B_INTERRUPTED;
}
retry:
stat = acquire_sem_etc(device->rxReadySem, 1,
B_CAN_INTERRUPT | (device->nonblocking ? B_TIMEOUT : 0), 0);
if (device->closed) {
// TRACE("rtl8169_read() interrupted 2\n");
// net_server will crash if we print this
// (race condition in net_server?)
return B_INTERRUPTED;
}
if (stat == B_WOULD_BLOCK) {
TRACE("rtl8169_read() would block (OK 0 bytes)\n");
*numBytes = 0;
return B_OK;
}
if (stat != B_OK) {
TRACE("rtl8169_read() error\n");
return B_ERROR;
}
if (device->rxDesc[device->rxNextIndex].stat_len & RX_DESC_OWN) {
ERROR("rtl8169_read() buffer still in use\n");
goto retry;
}
len = (device->rxDesc[device->rxNextIndex].stat_len & RX_DESC_LEN_MASK);
len -= 4; // remove CRC that Realtek always appends
if (len < 0)
len = 0;
if (len > (int)*numBytes)
len = *numBytes;
memcpy(buf, device->rxBuf[device->rxNextIndex], len);
*numBytes = len;
cpu = disable_interrupts();
acquire_spinlock(&device->rxSpinlock);
device->rxDesc[device->rxNextIndex].stat_len = RX_DESC_OWN | FRAME_SIZE
| (device->rxDesc[device->rxNextIndex].stat_len & RX_DESC_EOR);
device->rxFree++;
release_spinlock(&device->rxSpinlock);
restore_interrupts(cpu);
device->rxNextIndex = (device->rxNextIndex + 1) % device->rxBufferCount;
TRACE("rtl8169_read() leave\n");
return B_OK;
}
status_t
rtl8169_write(void* cookie, off_t position, const void* buffer,
size_t* numBytes)
{
rtl8169_device *device = (rtl8169_device *)cookie;
cpu_status cpu;
status_t stat;
int len;
TRACE("rtl8169_write() enter\n");
len = *numBytes;
if (len > FRAME_SIZE) {
TRACE("rtl8169_write() buffer too large\n");
return B_ERROR;
}
if (device->closed) {
TRACE("rtl8169_write() interrupted 1\n");
return B_INTERRUPTED;
}
retry:
stat = acquire_sem_etc(device->txFreeSem, 1, B_CAN_INTERRUPT | B_TIMEOUT,
device->nonblocking ? 0 : TX_TIMEOUT);
if (device->closed) {
TRACE("rtl8169_write() interrupted 2\n");
return B_INTERRUPTED;
}
if (stat == B_WOULD_BLOCK) {
TRACE("rtl8169_write() would block (OK 0 bytes)\n");
*numBytes = 0;
return B_OK;
}
if (stat == B_TIMED_OUT) {
TRACE("rtl8169_write() timeout\n");
return B_BUSY;
}
if (stat != B_OK) {
TRACE("rtl8169_write() error\n");
return B_ERROR;
}
if (device->txDesc[device->txNextIndex].stat_len & TX_DESC_OWN) {
ERROR("rtl8169_write() buffer still in use\n");
goto retry;
}
memcpy(device->txBuf[device->txNextIndex], buffer, len);
cpu = disable_interrupts();
acquire_spinlock(&device->txSpinlock);
device->txUsed++;
device->txDesc[device->txNextIndex].stat_len
= (device->txDesc[device->txNextIndex].stat_len & RX_DESC_EOR)
| TX_DESC_OWN | TX_DESC_FS | TX_DESC_LS | len;
release_spinlock(&device->txSpinlock);
restore_interrupts(cpu);
device->txNextIndex = (device->txNextIndex + 1) % device->txBufferCount;
write8(REG_TPPOLL, read8(REG_TPPOLL) | TPPOLL_NPQ); // set queue polling bit
TRACE("rtl8169_write() leave\n");
return B_OK;
}
status_t
rtl8169_control(void *cookie, uint32 op, void *arg, size_t len)
{
rtl8169_device *device = (rtl8169_device *)cookie;
switch (op) {
case ETHER_INIT:
TRACE("rtl8169_control() ETHER_INIT\n");
return B_OK;
case ETHER_GETADDR:
TRACE("rtl8169_control() ETHER_GETADDR\n");
memcpy(arg, &device->macaddr, sizeof(device->macaddr));
return B_OK;
case ETHER_NONBLOCK:
if (*(int32 *)arg) {
TRACE("non blocking mode on\n");
device->nonblocking = true;
/* could be used to unblock pending read and write calls,
* but this doesn't seem to be required
release_sem_etc(device->txFreeSem, 1, B_DO_NOT_RESCHEDULE);
release_sem_etc(device->rxReadySem, 1, B_DO_NOT_RESCHEDULE);
*/
} else {
TRACE("non blocking mode off\n");
device->nonblocking = false;
}
return B_OK;
case ETHER_ADDMULTI:
TRACE("rtl8169_control() ETHER_ADDMULTI\n");
break;
case ETHER_REMMULTI:
TRACE("rtl8169_control() ETHER_REMMULTI\n");
return B_OK;
case ETHER_SETPROMISC:
if (*(int32 *)arg) {
TRACE("promiscuous mode on\n");
write32(REG_RX_CONFIG, read32(REG_RX_CONFIG)
| RX_CONFIG_AcceptAllPhys);
write32(0x8, 0xffffffff); // multicast filter
write32(0xc, 0xffffffff); // multicast filter
} else {
TRACE("promiscuous mode off\n");
write32(REG_RX_CONFIG, read32(REG_RX_CONFIG)
& ~RX_CONFIG_AcceptAllPhys);
write32(0x8, 0); // multicast filter
write32(0xc, 0); // multicast filter
}
return B_OK;
case ETHER_GETFRAMESIZE:
TRACE("rtl8169_control() ETHER_GETFRAMESIZE, framesize = %d (MTU = %d)\n", device->maxframesize, device->maxframesize - 14);
*(uint32*)arg = device->maxframesize;
return B_OK;
case ETHER_GET_LINK_STATE:
{
ether_link_state_t state;
state.media = IFM_ETHER;
state.media |= (device->link_ok ? IFM_ACTIVE : 0);
state.media |= (device->full_duplex ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX);
if (device->speed == 1000000000)
state.media |= IFM_1000_T;
else if (device->speed == 100000000)
state.media |= IFM_100_TX;
else if (device->speed == 10000000)
state.media |= IFM_10_T;
state.speed = device->speed;
state.quality = 1000;
return user_memcpy(arg, &state, sizeof(ether_link_state_t));
}
case ETHER_SET_LINK_STATE_SEM:
{
if (user_memcpy(&device->linkChangeSem, arg, sizeof(sem_id)) < B_OK) {
device->linkChangeSem = -1;
return B_BAD_ADDRESS;
}
return B_OK;
}
default:
TRACE("rtl8169_control() Invalid command\n");
break;
}
return B_ERROR;
}
@@ -1,111 +0,0 @@
/* Realtek RTL8169 Family Driver
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies, and that both the
* copyright notice and this permission notice appear in supporting documentation.
*
* Marcus Overhagen makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
*
* MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
* OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __DEVICE_H
#define __DEVICE_H
#include <PCI.h>
#include "debug.h"
#include "hardware.h"
#include "timer.h"
#define TX_TIMEOUT 6000000 // 6 seconds
#define FRAME_SIZE 1536 // must be multiple of 8
#define DEFAULT_TX_BUF_COUNT 256 // must be <= 1024
#define DEFAULT_RX_BUF_COUNT 256 // must be <= 1024
extern pci_module_info *gPci;
status_t rtl8169_open(const char *name, uint32 flags, void** cookie);
status_t rtl8169_read(void* cookie, off_t position, void *buf, size_t* num_bytes);
status_t rtl8169_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes);
status_t rtl8169_control(void *cookie, uint32 op, void *arg, size_t len);
status_t rtl8169_close(void* cookie);
status_t rtl8169_free(void* cookie);
typedef struct {
int devId;
pci_info * pciInfo;
volatile bool nonblocking;
volatile bool closed;
#ifdef PROFILING
volatile int intTotalCount;
volatile int intTotalCountOld;
volatile int intRxTotalCount;
volatile int intTxTotalCount;
volatile int intTimerTotalCount;
volatile int intCurrentCount;
volatile int intRxCurrentCount;
volatile int intTxCurrentCount;
volatile int intTimerCurrentCount;
timer_id timer;
#endif // PROFILING
spinlock txSpinlock;
sem_id txFreeSem;
volatile int32 txNextIndex; // next descriptor that will be used for writing
volatile int32 txIntIndex; // current descriptor that needs be checked
volatile int32 txUsed;
int txBufferCount;
spinlock rxSpinlock;
sem_id rxReadySem;
volatile int32 rxNextIndex; // next descriptor that will be used for reading
volatile int32 rxIntIndex; // current descriptor that needs be checked
volatile int32 rxFree;
int rxBufferCount;
volatile buf_desc * txDesc;
volatile buf_desc * rxDesc;
area_id txDescArea;
area_id rxDescArea;
void ** txBuf;
void ** rxBuf;
area_id txBufArea;
area_id rxBufArea;
void * regAddr;
area_id regArea;
uint8 irq;
uint8 macaddr[6];
int maxframesize;
int mac_version;
int phy_version;
bool link_ok;
uint32 speed;
bool full_duplex;
sem_id linkChangeSem;
} rtl8169_device;
#define read8(offset) (*(volatile uint8 *) ((char *)(device->regAddr) + (offset)))
#define read16(offset) (*(volatile uint16 *)((char *)(device->regAddr) + (offset)))
#define read32(offset) (*(volatile uint32 *)((char *)(device->regAddr) + (offset)))
#define write8(offset, value) (*(volatile uint8 *) ((char *)(device->regAddr) + (offset)) = value)
#define write16(offset, value) (*(volatile uint16 *)((char *)(device->regAddr) + (offset)) = value)
#define write32(offset, value) (*(volatile uint32 *)((char *)(device->regAddr) + (offset)) = value)
#endif
@@ -1,203 +0,0 @@
/* Realtek RTL8169 Family Driver
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies, and that both the
* copyright notice and this permission notice appear in supporting documentation.
*
* Marcus Overhagen makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
*
* MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
* OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <KernelExport.h>
#include <Errors.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//#define DEBUG
#include "debug.h"
#include "device.h"
#include "driver.h"
#include "setup.h"
#include "timer.h"
#define VENDOR_ID_REALTEK 0x10ec
static const uint32 kSupportedDevices[] = {
0x8167,
0x8168,
0x8169,
};
int32 api_version = B_CUR_DRIVER_API_VERSION;
char* gDevNameList[MAX_CARDS + 1];
pci_info *gDevList[MAX_CARDS];
pci_module_info *gPci;
static device_hooks sDeviceHooks = {
rtl8169_open,
rtl8169_close,
rtl8169_free,
rtl8169_control,
rtl8169_read,
rtl8169_write,
};
static status_t
get_next_supported_pci_info(int32 *_cookie, pci_info *info)
{
int32 index = *_cookie;
uint32 i;
// find devices
for (; gPci->get_nth_pci_info(index, info) == B_OK; index++) {
// check vendor
if (info->vendor_id != VENDOR_ID_REALTEK)
continue;
// check device
for (i = 0; i < sizeof(kSupportedDevices)
/ sizeof(kSupportedDevices[0]); i++) {
if (info->device_id == kSupportedDevices[i]) {
*_cookie = index + 1;
return B_OK;
}
}
}
return B_ENTRY_NOT_FOUND;
}
// #pragma mark -
status_t
init_hardware(void)
{
uint32 cookie = 0;
status_t result;
pci_info info;
TRACE("init_hardware()\n");
if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK)
return B_ERROR;
result = get_next_supported_pci_info(&cookie, &info);
put_module(B_PCI_MODULE_NAME);
return result;
}
status_t
init_driver(void)
{
struct pci_info *item;
uint32 index = 0;
int cards = 0;
#ifdef DEBUG
set_dprintf_enabled(true);
load_driver_symbols("rtl8169");
#endif
dprintf(INFO1"\n");
dprintf(INFO2"\n");
item = (pci_info *)malloc(sizeof(pci_info));
if (!item)
return B_NO_MEMORY;
if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK) {
free(item);
return B_ERROR;
}
while (get_next_supported_pci_info(&index, item) == B_OK) {
char name[64];
sprintf(name, "net/rtl8169/%d", cards);
gDevList[cards] = item;
gDevNameList[cards] = strdup(name);
gDevNameList[cards + 1] = NULL;
cards++;
item = (pci_info *)malloc(sizeof(pci_info));
if (!item)
goto err_outofmem;
if (cards == MAX_CARDS)
break;
}
TRACE("found %d cards\n", cards);
free(item);
if (!cards)
goto err_cards;
if (initialize_timer() != B_OK) {
ERROR("timer init failed\n");
goto err_timer;
}
return B_OK;
err_timer:
err_cards:
err_outofmem:
for (index = 0; index < cards; index++) {
free(gDevList[index]);
free(gDevNameList[index]);
}
put_module(B_PCI_MODULE_NAME);
return B_ERROR;
}
void
uninit_driver(void)
{
int32 i;
TRACE("uninit_driver()\n");
terminate_timer();
for (i = 0; gDevNameList[i] != NULL; i++) {
free(gDevList[i]);
free(gDevNameList[i]);
}
put_module(B_PCI_MODULE_NAME);
}
const char**
publish_devices()
{
return (const char**)gDevNameList;
}
device_hooks*
find_device(const char* name)
{
return &sDeviceHooks;
}
@@ -1,33 +0,0 @@
/* Realtek RTL8169 Family Driver
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies, and that both the
* copyright notice and this permission notice appear in supporting documentation.
*
* Marcus Overhagen makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
*
* MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
* OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __DRIVER_H
#define __DRIVER_H
#include <Drivers.h>
#include <PCI.h>
#include "ether_driver.h"
#define MAX_CARDS 8
extern pci_module_info *gPci;
extern char* gDevNameList[];
extern pci_info *gDevList[];
#endif
@@ -1,156 +0,0 @@
/* Realtek RTL8169 Family Driver
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies, and that both the
* copyright notice and this permission notice appear in supporting documentation.
*
* Marcus Overhagen makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
*
* MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
* OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __HARDWARE_H
#define __HARDWARE_H
#define PCI_PCICMD_IOS 0x01
#define PCI_PCICMD_MSE 0x02
#define PCI_PCICMD_BME 0x04
typedef struct {
uint32 stat_len;
uint32 vlan;
uint32 buf_low; // must be 8 byte aligned
uint32 buf_high;
} _PACKED buf_desc;
enum {
TX_DESC_OWN = 0x80000000,
TX_DESC_EOR = 0x40000000,
TX_DESC_FS = 0x20000000,
TX_DESC_LS = 0x10000000,
TX_DESC_LEN_MASK = 0x00003fff,
};
enum {
RX_DESC_OWN = 0x80000000,
RX_DESC_EOR = 0x40000000,
RX_DESC_FS = 0x20000000,
RX_DESC_LS = 0x10000000,
RX_DESC_MAR = 0x08000000,
RX_DESC_PAM = 0x04000000,
RX_DESC_BAR = 0x02000000,
RX_DESC_BOVF = 0x01000000,
RX_DESC_FOVF = 0x00800000,
RX_DESC_RWT = 0x00400000,
RX_DESC_RES = 0x00200000,
RX_DESC_RUNT = 0x00100000,
RX_DESC_CRC = 0x00080000,
RX_DESC_LEN_MASK = 0x00003fff,
};
enum {
REG_TNPDS_LOW = 0x20,
REG_TNPDS_HIGH = 0x24,
REG_THPDS_LOW = 0x28,
REG_THPDS_HIGH = 0x2c,
REG_RDSAR_LOW = 0xe4,
REG_RDSAR_HIGH = 0xe8,
REG_CR = 0x37, // 8 bit
REG_TPPOLL = 0x38, // 8 bit
REG_INT_MASK = 0x3c, // 16 bit
REG_INT_STAT = 0x3e, // 16 bit
REG_TX_CONFIG = 0x40,
REG_RX_CONFIG = 0x44,
REG_9346CR = 0x50, // 8 bit
REG_CONFIG0 = 0x51, // 8 bit
REG_CONFIG1 = 0x52, // 8 bit
REG_CONFIG2 = 0x53, // 8 bit
REG_CONFIG3 = 0x54, // 8 bit
REG_CONFIG4 = 0x55, // 8 bit
REG_CONFIG5 = 0x56, // 8 bit
REG_PHYAR = 0x60,
REG_TBICSR = 0x64,
REG_PHY_STAT = 0x6c, // 8bit
};
// for REG_CR
enum {
CR_RST = 0x10,
CR_RE = 0x08,
CR_TE = 0x04,
};
// for REG_TPPOLL
enum {
TPPOLL_HPQ = 0x80,
TPPOLL_NPQ = 0x40,
TPPOLL_FSWINT = 0x01,
};
// for REG_INT_MASK and REG_INT_STAT
enum {
INT_SERR = 0x8000,
INT_TimeOut = 0x4000,
INT_SwInt = 0x0100,
INT_TDU = 0x0080,
INT_FOVW = 0x0040,
INT_PUN = 0x0020,
INT_RDU = 0x0010,
INT_TER = 0x0008,
INT_TOK = 0x0004,
INT_RER = 0x0002,
INT_ROK = 0x0001,
};
// for REG_PHY_STAT
enum {
PHY_STAT_EnTBI = 0x80,
PHY_STAT_TxFlow = 0x40,
PHY_STAT_RxFlow = 0x20,
PHY_STAT_1000MF = 0x10,
PHY_STAT_100M = 0x08,
PHY_STAT_10M = 0x04,
PHY_STAT_LinkSts = 0x02,
PHY_STAT_FullDup = 0x01,
};
// for REG_TBICSR
enum {
TBICSR_ResetTBI = 0x80000000,
TBICSR_TBILoopBack = 0x40000000,
TBICSR_TBINWEn = 0x20000000,
TBICSR_TBIReNW = 0x10000000,
TBICSR_TBILinkOk = 0x02000000,
TBICSR_NWComplete = 0x01000000,
};
// for REG_RX_CONFIG
enum {
RX_CONFIG_MulERINT = 0x01000000,
RX_CONFIG_RER8 = 0x00010000,
RX_CONFIG_AcceptErr = 0x00000020,
RX_CONFIG_AcceptRunt = 0x00000010,
RX_CONFIG_AcceptBroad = 0x00000008,
RX_CONFIG_AcceptMulti = 0x00000004,
RX_CONFIG_AcceptMyPhys = 0x00000002,
RX_CONFIG_AcceptAllPhys = 0x00000001,
RX_CONFIG_MASK = 0xfe7e1880, // XXX should be 0xfefe1880 but Realtek driver clears the undocumented bit 23
RC_CONFIG_RXFTH_Shift = 13,
RC_CONFIG_MAXDMA_Shift = 8,
};
#endif
@@ -1,22 +0,0 @@
# Sample settings file for the rtl8169 driver
#
# This file should be moved to the directory ~/config/settings/kernel/drivers/
# and RENAMED into "rtl8169"
# Currently supported settings are:
#
# rx_buffer_count <value>
# tx_buffer_count <value>
#
# where value can be in the range 2 to 1024
# the default value is 256
#
# mtu <value>
#
# where value can be in the range 50 to 1500
#
# to fix upload problems with DSL, use
#
# mtu 1492
@@ -1,27 +0,0 @@
/* Realtek RTL8169 Family Driver
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies, and that both the
* copyright notice and this permission notice appear in supporting documentation.
*
* Marcus Overhagen makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
*
* MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
* OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __SETUP_H
#define __SETUP_H
#define VERSION "1.2"
#define INFO1 "rtl8169: Realtek RTL8169 and RTL8110 Family Driver. Version " VERSION
#define INFO2 "rtl8169: Written by Marcus Overhagen. Build " __DATE__ " "__TIME__
#endif
@@ -1,215 +0,0 @@
/* Realtek RTL8169 Family Driver
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies, and that both the
* copyright notice and this permission notice appear in supporting documentation.
*
* Marcus Overhagen makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
*
* MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
* OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <Errors.h>
#include <OS.h>
#include <string.h>
#include "debug.h"
#include "timer.h"
#define MAX_TIMERS 8
struct timer_info
{
timer_id id;
timer_function func;
void * cookie;
bigtime_t next_event;
bigtime_t interval;
bool periodic;
};
static struct timer_info sTimerData[MAX_TIMERS];
static int sTimerCount;
static timer_id sTimerNextId;
static thread_id sTimerThread;
static sem_id sTimerSem;
static spinlock sTimerSpinlock;
static int32
timer_thread(void *cookie)
{
status_t status = 0;
do {
bigtime_t timeout;
bigtime_t now;
cpu_status cpu;
timer_function func;
void * cookie;
int i;
int index;
cpu = disable_interrupts();
acquire_spinlock(&sTimerSpinlock);
now = system_time();
cookie = 0;
func = 0;
// find timer with smallest event time
index = -1;
timeout = B_INFINITE_TIMEOUT;
for (i = 0; i < sTimerCount; i++) {
if (sTimerData[i].next_event < timeout) {
timeout = sTimerData[i].next_event;
index = i;
}
}
if (timeout < now) {
// timer is ready for execution, load func and cookie
ASSERT(index >= 0 && index < sTimerCount);
func = sTimerData[index].func;
cookie = sTimerData[index].cookie;
if (sTimerData[index].periodic) {
// periodic timer is ready, update the entry
sTimerData[index].next_event += sTimerData[index].interval;
} else {
// single shot timer is ready, delete the entry
if (index != (sTimerCount - 1) && sTimerCount != 1) {
memcpy(&sTimerData[index], &sTimerData[sTimerCount - 1], sizeof(struct timer_info));
}
sTimerCount--;
}
}
release_spinlock(&sTimerSpinlock);
restore_interrupts(cpu);
// execute timer hook
if (timeout < now) {
ASSERT(func);
func(cookie);
continue;
}
status = acquire_sem_etc(sTimerSem, 1, B_ABSOLUTE_TIMEOUT, timeout);
} while (status != B_BAD_SEM_ID);
return 0;
}
timer_id
create_timer(timer_function func, void *cookie, bigtime_t interval, uint32 flags)
{
cpu_status cpu;
timer_id id;
if (func == 0)
return -1;
// Attention: flags are not real flags, as B_PERIODIC_TIMER is 3
cpu = disable_interrupts();
acquire_spinlock(&sTimerSpinlock);
if (sTimerCount < MAX_TIMERS) {
id = sTimerNextId;
sTimerData[sTimerCount].id = id;
sTimerData[sTimerCount].func = func;
sTimerData[sTimerCount].cookie = cookie;
sTimerData[sTimerCount].next_event = (flags == B_ONE_SHOT_ABSOLUTE_TIMER) ? interval : system_time() + interval;
sTimerData[sTimerCount].interval = interval;
sTimerData[sTimerCount].periodic = flags == B_PERIODIC_TIMER;
sTimerNextId++;
sTimerCount++;
} else {
id = -1;
}
release_spinlock(&sTimerSpinlock);
restore_interrupts(cpu);
if (id != -1)
release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE);
return id;
}
status_t
delete_timer(timer_id id)
{
cpu_status cpu;
bool deleted;
int i;
deleted = false;
cpu = disable_interrupts();
acquire_spinlock(&sTimerSpinlock);
for (i = 0; i < sTimerCount; i++) {
if (sTimerData[i].id == id) {
if (i != (sTimerCount - 1) && sTimerCount != 1) {
memcpy(&sTimerData[i], &sTimerData[sTimerCount - 1], sizeof(struct timer_info));
}
sTimerCount--;
deleted = true;
break;
}
}
release_spinlock(&sTimerSpinlock);
restore_interrupts(cpu);
if (!deleted)
return B_ERROR;
release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE);
return B_OK;
}
status_t
initialize_timer(void)
{
sTimerCount = 0;
sTimerNextId = 1;
B_INITIALIZE_SPINLOCK(&sTimerSpinlock);
sTimerThread = spawn_kernel_thread(timer_thread, "rtl8169 timer", 80, 0);
sTimerSem = create_sem(0, "rtl8169 timer");
set_sem_owner(sTimerSem, B_SYSTEM_TEAM);
if (sTimerSem < 0 || sTimerThread < 0) {
delete_sem(sTimerSem);
kill_thread(sTimerThread);
return B_ERROR;
}
resume_thread(sTimerThread);
return B_OK;
}
status_t
terminate_timer(void)
{
status_t thread_return_value;
delete_sem(sTimerSem);
return wait_for_thread(sTimerThread, &thread_return_value);
}
@@ -1,44 +0,0 @@
/* Realtek RTL8169 Family Driver
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies, and that both the
* copyright notice and this permission notice appear in supporting documentation.
*
* Marcus Overhagen makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
*
* MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
* OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __TIMER_H
#define __TIMER_H
#include <KernelExport.h>
// Since the BeOS kernel timers are executed in interrupt context,
// a new timer has been created. The timers are executed in thread
// context, and are passed a cookie.
typedef int32 timer_id;
typedef void (*timer_function)(void *cookie);
// create_timer() can be called from interrupt context.
// Only up to 8 concurrent timers are supported.
// Flags can be one of B_ONE_SHOT_ABSOLUTE_TIMER,
// B_ONE_SHOT_RELATIVE_TIMER or B_PERIODIC_TIMER.
timer_id create_timer(timer_function func, void *cookie, bigtime_t interval, uint32 flags);
status_t delete_timer(timer_id id);
status_t initialize_timer(void);
status_t terminate_timer(void);
#endif
@@ -1,101 +0,0 @@
/* Realtek RTL8169 Family Driver
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies, and that both the
* copyright notice and this permission notice appear in supporting documentation.
*
* Marcus Overhagen makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
*
* MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
* OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <Errors.h>
#include <OS.h>
#include <string.h>
//#define DEBUG
#include "debug.h"
#include "util.h"
static inline uint32
round_to_pagesize(uint32 size)
{
return (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
}
area_id
alloc_contiguous(void **virt, void **phy, size_t size, uint32 protection,
const char *name)
{
// TODO: phy should be phys_addr_t*!
physical_entry pe;
void * virtadr;
area_id areaid;
status_t rv;
TRACE("allocating %ld bytes for %s\n", size, name);
size = round_to_pagesize(size);
areaid = create_area(name, &virtadr, B_ANY_KERNEL_ADDRESS, size,
B_32_BIT_CONTIGUOUS, protection);
// TODO: The rest of the code doesn't deal correctly with physical
// addresses > 4 GB, so we have to force 32 bit addresses here.
if (areaid < B_OK) {
ERROR("couldn't allocate area %s\n", name);
return B_ERROR;
}
rv = get_memory_map(virtadr, size, &pe, 1);
if (rv < B_OK) {
delete_area(areaid);
ERROR("couldn't get mapping for %s\n", name);
return B_ERROR;
}
memset(virtadr, 0, size);
if (virt)
*virt = virtadr;
if (phy)
*phy = (void*)(addr_t)pe.address;
TRACE("area = %ld, size = %ld, virt = %p, phy = %p\n", areaid, size, virtadr, pe.address);
return areaid;
}
area_id
map_mem(void **virt, void *phy, size_t size, uint32 protection,
const char *name)
{
uint32 offset;
void *phyadr;
void *mapadr;
area_id area;
TRACE("mapping physical address %p with %ld bytes for %s\n", phy, size, name);
offset = (uint32)phy & (B_PAGE_SIZE - 1);
phyadr = (char *)phy - offset;
size = round_to_pagesize(size + offset);
area = map_physical_memory(name, (addr_t)phyadr, size, B_ANY_KERNEL_ADDRESS,
protection, &mapadr);
if (area < B_OK) {
ERROR("mapping '%s' failed, error 0x%lx (%s)\n", name, area, strerror(area));
return area;
}
*virt = (char *)mapadr + offset;
TRACE("physical = %p, virtual = %p, offset = %ld, phyadr = %p, mapadr = "
"%p, size = %ld, area = 0x%08lx\n", phy, *virt, offset, phyadr, mapadr,
size, area);
return area;
}
@@ -1,28 +0,0 @@
/* Realtek RTL8169 Family Driver
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies, and that both the
* copyright notice and this permission notice appear in supporting documentation.
*
* Marcus Overhagen makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
*
* MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
* OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __UTIL_H
#define __UTIL_H
#include <OS.h>
area_id alloc_contiguous(void **virt, void **phy, size_t size,
uint32 protection, const char *name);
area_id map_mem(void **virt, void *phy, size_t size, uint32 protection, const char *name);
#endif