From d5c64db1c558b0391f6a8b1c7bea7d9efbd8a4f4 Mon Sep 17 00:00:00 2001 From: beveloper Date: Mon, 3 May 2004 20:12:18 +0000 Subject: [PATCH] First version of the: Realtek RTL8169 Family Gigabit Ethernet Driver Very basic, does only detection of the card and sets up some buffer descriptors. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7380 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/drivers/network/rtl8169/debug.h | 14 + .../kernel/drivers/network/rtl8169/device.c | 324 ++++++++++++++++++ .../kernel/drivers/network/rtl8169/device.h | 58 ++++ .../kernel/drivers/network/rtl8169/driver.c | 116 +++++++ .../kernel/drivers/network/rtl8169/driver.h | 15 + .../drivers/network/rtl8169/ether_driver.h | 39 +++ .../kernel/drivers/network/rtl8169/hardware.h | 65 ++++ .../kernel/drivers/network/rtl8169/util.c | 76 ++++ .../kernel/drivers/network/rtl8169/util.h | 9 + 9 files changed, 716 insertions(+) create mode 100644 src/add-ons/kernel/drivers/network/rtl8169/debug.h create mode 100644 src/add-ons/kernel/drivers/network/rtl8169/device.c create mode 100644 src/add-ons/kernel/drivers/network/rtl8169/device.h create mode 100644 src/add-ons/kernel/drivers/network/rtl8169/driver.c create mode 100644 src/add-ons/kernel/drivers/network/rtl8169/driver.h create mode 100644 src/add-ons/kernel/drivers/network/rtl8169/ether_driver.h create mode 100644 src/add-ons/kernel/drivers/network/rtl8169/hardware.h create mode 100644 src/add-ons/kernel/drivers/network/rtl8169/util.c create mode 100644 src/add-ons/kernel/drivers/network/rtl8169/util.h diff --git a/src/add-ons/kernel/drivers/network/rtl8169/debug.h b/src/add-ons/kernel/drivers/network/rtl8169/debug.h new file mode 100644 index 0000000000..03b6a2d292 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/rtl8169/debug.h @@ -0,0 +1,14 @@ +#ifndef __DEBUG_H +#define __DEBUG_H + +#include + +#define DEBUG + +#ifdef DEBUG + #define LOG dprintf +#else + #define LOG(a...) +#endif + +#endif diff --git a/src/add-ons/kernel/drivers/network/rtl8169/device.c b/src/add-ons/kernel/drivers/network/rtl8169/device.c new file mode 100644 index 0000000000..be199854a9 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/rtl8169/device.c @@ -0,0 +1,324 @@ +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "device.h" +#include "driver.h" +#include "hardware.h" +#include "util.h" + +static int32 gOpenMask = 0; + +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_prio_buf_desc_virt, *tx_prio_buf_desc_phy; + void *tx_buf_virt, *tx_buf_phy; + void *rx_buf_virt, *rx_buf_phy; + int i; + + device->txBufArea = alloc_mem(&tx_buf_virt, &tx_buf_phy, TX_DESC_COUNT * FRAME_SIZE, 0, "rtl8169 tx buf"); + device->rxBufArea = alloc_mem(&rx_buf_virt, &rx_buf_phy, RX_DESC_COUNT * FRAME_SIZE, 0, "rtl8169 rx buf"); + device->txDescArea = alloc_mem(&tx_buf_desc_virt, &tx_buf_desc_phy, TX_DESC_COUNT * sizeof(tx_desc), 0, "rtl8169 tx desc"); + device->txPrioDescArea = alloc_mem(&tx_prio_buf_desc_virt, &tx_prio_buf_desc_phy, sizeof(tx_desc), 0, "rtl8169 prio tx desc"); + device->rxDescArea = alloc_mem(&rx_buf_desc_virt, &rx_buf_desc_phy, RX_DESC_COUNT * sizeof(rx_desc), 0, "rtl8169 rx desc"); + if (device->txBufArea < B_OK || device->rxBufArea < B_OK || device->txDescArea < B_OK || device->txPrioDescArea < B_OK || device->rxDescArea < B_OK) + return B_NO_MEMORY; + + device->txDesc = (tx_desc *) tx_buf_desc_virt; + device->txPrioDesc = (tx_desc *) tx_prio_buf_desc_virt; + device->rxDesc = (rx_desc *) rx_buf_desc_virt; + + // setup unused priority transmit descriptor + device->txPrioDesc->stat_len = TX_DESC_FS | TX_DESC_LS | TX_DESC_EOR; + device->txPrioDesc->vlan = 0; + device->txPrioDesc->buf_low = 0; + device->txPrioDesc->buf_high = 0; + + // setup transmit descriptors + for (i = 0; i < TX_DESC_COUNT; 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 < RX_DESC_COUNT; i++) { + device->rxBuf[i] = (char *)rx_buf_virt + (i * FRAME_SIZE); + device->rxDesc[i].stat_len = RX_DESC_FS | RX_DESC_LS | RX_DESC_OWN; + 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; + + LOG("tx_buf_desc_phy = %p\n", tx_buf_desc_phy); + *REG32(REG_TNPDS_LOW) = (uint32)tx_buf_desc_phy; + LOG("REG_TNPDS_LOW = %p\n", (void *) *REG32(REG_TNPDS_LOW)); + + *REG32(REG_TNPDS_HIGH) = 0; + *REG32(REG_THPDS_LOW) = (uint32)tx_prio_buf_desc_phy; + *REG32(REG_THPDS_HIGH) = 0; + *REG32(REG_RDSAR_LOW) = (uint32)rx_buf_desc_phy; + *REG32(REG_RDSAR_HIGH) = 0; + + return B_OK; +} + +status_t +rtl8169_open(const char *name, uint32 flags, void** cookie) +{ + rtl8169_device *device; + char *deviceName; + uint32 val; + int dev_id; + int mask; + int i; + + LOG("rtl8169_open()\n"); + + for (dev_id = 0; (deviceName = gDevNameList[dev_id]) != NULL; dev_id++) { + if (!strcmp(name, deviceName)) + break; + } + if (deviceName == NULL) { + LOG("invalid device name"); + 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->blockFlag = (flags & O_NONBLOCK) ? B_TIMEOUT : 0; + device->closed = false; + device->rxReadySem = create_sem(0, "rtl8169 rx ready"); + device->txFreeSem = create_sem(TX_DESC_COUNT, "rtl8169 tx free"); + device->txIndex = 0; + device->rxIndex = 0; + + // 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); + + // map registers into memory + val = gPci->read_pci_config(device->pciInfo->bus, device->pciInfo->device, device->pciInfo->function, 0x14, 4); + val &= PCI_address_memory_32_mask; + LOG("hardware register address %p\n", (void *) val); + device->refArea = map_mem(&device->regAddr, (void *)val, 256, 0, "rtl8169 register"); + if (device->refArea < B_OK) + goto err; + + LOG("mapped %p to %p\n", (void *)val, device->regAddr); + + // get IRQ + device->irq = gPci->read_pci_config(device->pciInfo->bus, device->pciInfo->device, device->pciInfo->function, PCI_interrupt_line, 1); + if (device->irq == 0 || device->irq == 0xff) + goto err; + + LOG("IRQ %d\n", device->irq); + + // disable receiver & transmitter + *REG8(REG_CR) &= ~REG_CR_RE | REG_CR_TE; + + // setup buffer descriptors and buffers + if (init_buf_desc(device) != B_OK) + goto err; + + // soft reset + *REG8(REG_CR) |= REG_CR_RST; + for (i = 0; ((*REG8(REG_CR)) & REG_CR_RST) && i < 100; i++) + snooze(10000); + if (i == 100) { + LOG("reset failed\n"); + goto err; + } + LOG("reset done, i %d\n", i); + + for (i = 0; i < 6; i++) + device->macaddr[i] = *REG8(i); + + dprintf("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]); + + LOG("tx base = %p\n", (void *) *REG32(REG_TNPDS_LOW)); + + // enable receiver & transmitter +// *REG8(REG_CR) |= REG_CR_RE | REG_CR_TE; + + return B_OK; +err: + LOG("error!\n"); + delete_sem(device->rxReadySem); + delete_sem(device->txFreeSem); + delete_area(device->refArea); + delete_area(device->txBufArea); + delete_area(device->rxBufArea); + delete_area(device->txDescArea); + delete_area(device->txPrioDescArea); + delete_area(device->rxDescArea); + free(device); + atomic_and(&gOpenMask, ~(1 << dev_id)); + return B_ERROR; +} + + +status_t +rtl8169_close(void* cookie) +{ + rtl8169_device *device = (rtl8169_device *)cookie; + LOG("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; + LOG("rtl8169_free()\n"); + + // disable receiver & transmitter + *REG8(REG_CR) &= ~REG_CR_RE | REG_CR_TE; + + delete_sem(device->rxReadySem); + delete_sem(device->txFreeSem); + delete_area(device->refArea); + delete_area(device->txBufArea); + delete_area(device->rxBufArea); + delete_area(device->txDescArea); + delete_area(device->txPrioDescArea); + delete_area(device->rxDescArea); + free(device); + atomic_and(&gOpenMask, ~(1 << device->devId)); + return B_OK; +} + + +status_t +rtl8169_read(void* cookie, off_t position, void *buf, size_t* num_bytes) +{ + rtl8169_device *device = (rtl8169_device *)cookie; + status_t stat; + LOG("rtl8169_read()\n"); + + if (device->closed) + return B_INTERRUPTED; +retry: + stat = acquire_sem_etc(device->rxReadySem, 1, B_CAN_INTERRUPT | device->blockFlag, 0); + if (device->closed) + return B_INTERRUPTED; + if (stat == B_WOULD_BLOCK) { + *num_bytes = 0; + return B_OK; + } + if (stat != B_OK) + return B_ERROR; + + + + return B_OK; +} + + +status_t +rtl8169_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes) +{ + rtl8169_device *device = (rtl8169_device *)cookie; + status_t stat; + + LOG("rtl8169_write()\n"); + + if (device->closed) + return B_INTERRUPTED; + + stat = acquire_sem_etc(device->txFreeSem, 1, B_CAN_INTERRUPT | B_TIMEOUT, TX_TIMEOUT); + if (device->closed) + return B_INTERRUPTED; + if (device->blockFlag && stat == B_WOULD_BLOCK) { + *num_bytes = 0; + return B_OK; + } + if (stat != B_OK) + return B_ERROR; + + + + return B_OK; +} + + + +status_t +rtl8169_control(void *cookie, uint32 op, void *arg, size_t len) +{ + rtl8169_device *device = (rtl8169_device *)cookie; + + LOG("rtl8169_control()\n"); + + + switch (op) { + case ETHER_INIT: + LOG("ETHER_INIT\n"); + return B_OK; + + case ETHER_GETADDR: + LOG("ETHER_GETADDR\n"); + memcpy(arg, &device->macaddr, sizeof(device->macaddr)); + return B_OK; + + case ETHER_NONBLOCK: + LOG("ETHER_NON_BLOCK\n"); + device->blockFlag = *(int32 *)arg ? B_TIMEOUT : 0; + return B_OK; + + case ETHER_ADDMULTI: + LOG("ETHER_ADDMULTI\n"); + break; + + case ETHER_REMMULTI: + LOG("ETHER_REMMULTI\n"); + return B_OK; + + case ETHER_SETPROMISC: + LOG("ETHER_SETPROMISC\n"); + return B_OK; + + case ETHER_GETFRAMESIZE: + LOG("ETHER_GETFRAMESIZE\n"); + *(uint32*)arg = FRAME_SIZE; + return B_OK; + + default: + LOG("Invalid command\n"); + break; + } + + return B_ERROR; +} + diff --git a/src/add-ons/kernel/drivers/network/rtl8169/device.h b/src/add-ons/kernel/drivers/network/rtl8169/device.h new file mode 100644 index 0000000000..9e4aba874f --- /dev/null +++ b/src/add-ons/kernel/drivers/network/rtl8169/device.h @@ -0,0 +1,58 @@ +#ifndef __DEVICE_H +#define __DEVICE_H + +#include +#include "hardware.h" + +#define TX_TIMEOUT 250000 +#define FRAME_SIZE 1536 // must be multiple of 8 +#define TX_DESC_COUNT 42 // must be <= 1024 +#define RX_DESC_COUNT 42 // 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 uint32 blockFlag; + volatile bool closed; + + sem_id rxReadySem; + sem_id txFreeSem; + + volatile int32 txIndex; + volatile int32 rxIndex; + + volatile tx_desc * txDesc; + volatile tx_desc * txPrioDesc; + volatile rx_desc * rxDesc; + + area_id txDescArea; + area_id txPrioDescArea; + area_id rxDescArea; + area_id txBufArea; + area_id rxBufArea; + + void * txBuf[TX_DESC_COUNT]; + void * rxBuf[RX_DESC_COUNT]; + + void * regAddr; + area_id refArea; + uint8 irq; + + uint8 macaddr[6]; +} rtl8169_device; + +#define REG8(offset) ((volatile uint8 *)((char *)(device->regAddr) + (offset))) +#define REG16(offset) ((volatile uint16 *)((char *)(device->regAddr) + (offset))) +#define REG32(offset) ((volatile uint32 *)((char *)(device->regAddr) + (offset))) + +#endif diff --git a/src/add-ons/kernel/drivers/network/rtl8169/driver.c b/src/add-ons/kernel/drivers/network/rtl8169/driver.c new file mode 100644 index 0000000000..92e1ee883f --- /dev/null +++ b/src/add-ons/kernel/drivers/network/rtl8169/driver.c @@ -0,0 +1,116 @@ +/* Realtek RTL8169 Family Driver + * Copyright (C) 2004 Marcus Overhagen . All rights reserved. + */ +#include +#include +#include +#include +#include + +#include "debug.h" +#include "device.h" +#include "driver.h" + +int32 api_version = B_CUR_DRIVER_API_VERSION; + +pci_module_info *gPci; + +char* gDevNameList[MAX_CARDS + 1]; +pci_info *gDevList[MAX_CARDS]; + + +status_t +init_hardware(void) +{ + LOG("rtl8169: init_hardware()\n"); + return B_OK; +} + + +status_t +init_driver(void) +{ + struct pci_info *item; + int index; + int cards; + + LOG("rtl8169: init_driver()\n"); + +#ifdef DEBUG + set_dprintf_enabled(true); + load_driver_symbols("rtl8169"); +#endif + + 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) + return B_ERROR; + + for (cards = 0, index = 0; gPci->get_nth_pci_info(index++, item) == B_OK; ) { + if (item->vendor_id == 0x10ec && item->device_id == 0x8169) { + 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) + return B_OK; // already found 1 card, but out of memory + } + } + + LOG("rtl8169: found %d cards\n", cards); + + free(item); + + if (!cards) { + put_module(B_PCI_MODULE_NAME); + return B_ERROR; + } + + return B_OK; +} + + +void +uninit_driver(void) +{ + int32 i; + + LOG("rtl8169: uninit_driver()\n"); + + for (i = 0; gDevNameList[i] != NULL; i++) { + free(gDevList[i]); + free(gDevNameList[i]); + } + + put_module(B_PCI_MODULE_NAME); +} + + +device_hooks +gDeviceHooks = { + rtl8169_open, + rtl8169_close, + rtl8169_free, + rtl8169_control, + rtl8169_read, + rtl8169_write, +}; + + +const char** +publish_devices() +{ + return (const char**)gDevNameList; +} + + +device_hooks* +find_device(const char* name) +{ + return &gDeviceHooks; +} diff --git a/src/add-ons/kernel/drivers/network/rtl8169/driver.h b/src/add-ons/kernel/drivers/network/rtl8169/driver.h new file mode 100644 index 0000000000..fb8e6b59b5 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/rtl8169/driver.h @@ -0,0 +1,15 @@ +#ifndef __DRIVER_H +#define __DRIVER_H + +#include +#include +#include "ether_driver.h" + +#define MAX_CARDS 8 + +extern pci_module_info *gPci; + +extern char* gDevNameList[]; +extern pci_info *gDevList[]; + +#endif diff --git a/src/add-ons/kernel/drivers/network/rtl8169/ether_driver.h b/src/add-ons/kernel/drivers/network/rtl8169/ether_driver.h new file mode 100644 index 0000000000..e25f369b4a --- /dev/null +++ b/src/add-ons/kernel/drivers/network/rtl8169/ether_driver.h @@ -0,0 +1,39 @@ +#ifndef _ETHER_DRIVER_H +#define _ETHER_DRIVER_H + +#include + +/* + * ioctls: belongs in a public header file + * somewhere, so that the net_server and other ethernet drivers can use. + */ +enum { + ETHER_GETADDR = B_DEVICE_OP_CODES_END, /* get ethernet address */ + ETHER_INIT, /* set irq and port */ + ETHER_NONBLOCK, /* set/unset nonblocking mode */ + ETHER_ADDMULTI, /* add multicast addr */ + ETHER_REMMULTI, /* rem multicast addr */ + ETHER_SETPROMISC, /* set promiscuous */ + ETHER_GETFRAMESIZE /* get frame size */ +}; + + +/* + * 48-bit ethernet address, passed back from ETHER_GETADDR + */ +typedef struct { + unsigned char ebyte[6]; +} ether_address_t; + + +/* + * info passed to ETHER_INIT + */ + +typedef struct ether_init_params { + short port; + short irq; + unsigned long mem; +} ether_init_params_t; + +#endif /* _ETHER_DRIVER_H */ diff --git a/src/add-ons/kernel/drivers/network/rtl8169/hardware.h b/src/add-ons/kernel/drivers/network/rtl8169/hardware.h new file mode 100644 index 0000000000..625bf58e39 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/rtl8169/hardware.h @@ -0,0 +1,65 @@ +#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; + uint32 buf_high; +} _PACKED tx_desc; + +enum { + TX_DESC_OWN = 0x80000000, + TX_DESC_EOR = 0x40000000, + TX_DESC_FS = 0x20000000, + TX_DESC_LS = 0x10000000, + TX_DESC_LEN_MASK = 0x00007fff, +}; + +typedef struct { + uint32 stat_len; + uint32 vlan; + uint32 buf_low; // must be 8 byte aligned + uint32 buf_high; +} _PACKED rx_desc; + +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 = 0x00007fff, +}; + +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, +}; + +enum { + REG_CR_RST = 0x10, + REG_CR_RE = 0x08, + REG_CR_TE = 0x04, +}; + +#endif diff --git a/src/add-ons/kernel/drivers/network/rtl8169/util.c b/src/add-ons/kernel/drivers/network/rtl8169/util.c new file mode 100644 index 0000000000..f0149c21a3 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/rtl8169/util.c @@ -0,0 +1,76 @@ +#include +#include +#include + +#include "debug.h" +#include "util.h" + +uint32 round_to_pagesize(uint32 size); + +uint32 round_to_pagesize(uint32 size) +{ + return (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); +} + +area_id +alloc_mem(void **virt, void **phy, size_t size, uint32 protection, const char *name) +{ + physical_entry pe; + void * virtadr; + area_id areaid; + status_t rv; + + LOG("allocating %ld bytes for %s\n", size, name); + + size = round_to_pagesize(size); + areaid = create_area(name, &virtadr, B_ANY_KERNEL_ADDRESS, size, B_FULL_LOCK | B_CONTIGUOUS, protection); + if (areaid < B_OK) { + LOG("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); + LOG("couldn't map %s\n", name); + return B_ERROR; + } + memset(virtadr, 0, size); + if (virt) + *virt = virtadr; + if (phy) + *phy = pe.address; + LOG("area = %ld, size = %ld, virt = %p, phy = %p\n", areaid, size, virtadr, pe.address); + return areaid; +} + +/* This is not the most advanced method to map physical memory for io access. + * Perhaps using B_ANY_KERNEL_ADDRESS instead of B_ANY_KERNEL_BLOCK_ADDRESS + * makes the whole offset calculation and relocation obsolete. But the code + * below does work, and I can't test if using B_ANY_KERNEL_ADDRESS also works. + */ +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; + + LOG("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, phyadr, size, B_ANY_KERNEL_BLOCK_ADDRESS, protection, &mapadr); + if (area < B_OK) { + LOG("mapping failed, error 0x%x (%s)\n", area, strerror(area)); + return area; + } + + *virt = (char *)mapadr + offset; + + LOG("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; +} diff --git a/src/add-ons/kernel/drivers/network/rtl8169/util.h b/src/add-ons/kernel/drivers/network/rtl8169/util.h new file mode 100644 index 0000000000..e261c5f12b --- /dev/null +++ b/src/add-ons/kernel/drivers/network/rtl8169/util.h @@ -0,0 +1,9 @@ +#ifndef __UTIL_H +#define __UTIL_H + +#include + +area_id alloc_mem(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