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:
@@ -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
|
||||
Reference in New Issue
Block a user