[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH v2 09/24] rtl8168b: Add driver
+ I cannot remember how well this driver works, but it is certainly
better than having none at all.
Signed-off-by: Max Reitz <max@xxxxxxxxxx>
Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
src/modules/cdi/rtl8168b/include/rtl8168b.h | 143 ++++++++++
src/modules/cdi/rtl8168b/main.c | 70 +++++
src/modules/cdi/rtl8168b/rtl8168b.c | 409 ++++++++++++++++++++++++++++
3 files changed, 622 insertions(+)
create mode 100644 src/modules/cdi/rtl8168b/include/rtl8168b.h
create mode 100644 src/modules/cdi/rtl8168b/main.c
create mode 100644 src/modules/cdi/rtl8168b/rtl8168b.c
diff --git a/src/modules/cdi/rtl8168b/include/rtl8168b.h b/src/modules/cdi/rtl8168b/include/rtl8168b.h
new file mode 100644
index 0000000..a038f7a
--- /dev/null
+++ b/src/modules/cdi/rtl8168b/include/rtl8168b.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2007 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Patrick Pokatilo.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTL8168B_H_
+#define _RTL8168B_H_
+
+#include <stdint.h>
+
+#include "cdi.h"
+#include "cdi/mem.h"
+#include "cdi/net.h"
+#include "cdi/pci.h"
+
+#define REG_ID0 0x00
+#define REG_TRANSMIT_DESCRIPTORS 0x20
+#define REG_COMMAND 0x37
+#define REG_TRANSMIT_POLL 0x38
+#define REG_INTERRUPT_MASK 0x3C
+#define REG_INTERRUPT_STATUS 0x3E
+#define REG_TRANSMIT_CONFIGURATION 0x40
+#define REG_RECEIVE_CONFIGURATION 0x44
+#define REG_PHY_ACCESS 0x60
+#define REG_PHY_DATA 0x60
+#define REG_PHY_ADDRESS 0x62
+#define REG_PHY_RW 0x63
+#define REG_PHY_STATUS 0x6C
+#define REG_RECV_MAX_SIZE 0xDA
+#define REG_CP_COMMAND 0xE0
+#define REG_RECEIVE_DESCRIPTORS 0xE4
+#define REG_MAX_TRANS_SIZE 0xEC
+
+#define CR_RESET (1 << 4)
+#define CR_RECEIVER_ENABLE (1 << 3)
+#define CR_TRANSMITTER_ENABLE (1 << 2)
+
+#define CPCR_VLAN_DETAG (1 << 6)
+#define CPCR_CHECKSUM_OFFLOAD (1 << 5)
+
+#define TPR_PACKET_WAITING (1 << 6)
+
+#define TCR_IFG_STANDARD (3 << 24)
+#define TCR_MXDMA_512 (5 << 8)
+#define TCR_MXDMA_1024 (6 << 8)
+#define TCR_MXDMA_UNLIMITED (7 << 8)
+
+#define RCR_NO_FIFO_THRESHOLD (7 << 13)
+#define RCR_MXDMA_512 (5 << 8)
+#define RCR_MXDMA_1024 (6 << 8)
+#define RCR_MXDMA_UNLIMITED (7 << 8)
+#define RCR_ACCEPT_BROADCAST (1 << 3)
+#define RCR_ACCEPT_MULTICAST (1 << 2)
+#define RCR_ACCEPT_PHYS_MATCH (1 << 1)
+
+#define ISR_LINK_CHANGE (1 << 5)
+#define ISR_RECEIVE_BUFFER_OVERFLOW (1 << 4)
+#define ISR_TRANSMIT_OK (1 << 2)
+#define ISR_RECEIVE_OK (1 << 0)
+
+#define PA_RW (1 << 31)
+
+#define PHY_REG_BMCR 0x00
+
+#define PHY_BMCR_RESET (1 << 15)
+#define PHY_BMCR_AUTO_NEGOTIATION (1 << 12)
+
+#define DC_OWN (1 << 31)
+#define DC_EOR (1 << 30)
+#define DC_FS (1 << 29)
+#define DC_LS (1 << 28)
+#define DC_LENGTH 0x3FFF
+
+#define PS_1000 (1 << 4)
+#define PS_100 (1 << 3)
+#define PS_10 (1 << 2)
+#define PS_LINK (1 << 1)
+#define PS_FULLDUP (1 << 0)
+
+#define PHYS(netcard, field) \
+ (netcard->phys + offsetof(struct rtl8168b_device, field))
+
+#define TX_BUFFER_SIZE (0x1000 & DC_LENGTH)
+#define RX_BUFFER_SIZE (0x2000 & DC_LENGTH)
+
+#define TX_BUFFER_COUNT 16
+#define RX_BUFFER_COUNT 16
+
+struct rtl8168b_descriptor
+{
+ volatile uint32_t command;
+ uint32_t vlan;
+ uint64_t address;
+};
+
+struct rtl8168b_device {
+ struct cdi_net_device net;
+ void* mmio;
+
+ int tx_index;
+ int rx_index;
+
+ struct cdi_mem_area* tx_buffer_area;
+ struct cdi_mem_area* rx_buffer_area;
+
+ struct rtl8168b_descriptor* tx_buffer;
+ uintptr_t tx_buffer_phys;
+ struct cdi_mem_area* tx_area[TX_BUFFER_COUNT];
+
+ struct rtl8168b_descriptor* rx_buffer;
+ uintptr_t rx_buffer_phys;
+ struct cdi_mem_area* rx_area[RX_BUFFER_COUNT];
+};
+
+struct cdi_device* rtl8168b_init_device(struct cdi_bus_data* bus_data);
+void rtl8168b_remove_device(struct cdi_device* device);
+void rtl8168b_send_packet(struct cdi_net_device* device,
+ void* data, size_t size);
+
+#endif
diff --git a/src/modules/cdi/rtl8168b/main.c b/src/modules/cdi/rtl8168b/main.c
new file mode 100644
index 0000000..1bbf8ff
--- /dev/null
+++ b/src/modules/cdi/rtl8168b/main.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Patrick Pokatilo.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "cdi/net.h"
+#include "cdi/pci.h"
+#include "cdi/misc.h"
+
+#include "rtl8168b.h"
+
+#define DRIVER_NAME "rtl8168b"
+
+static struct cdi_net_driver rtl8168b_driver;
+
+static int rtl8168b_driver_init(void)
+{
+ cdi_net_driver_init(&rtl8168b_driver);
+
+ return 0;
+}
+
+static int rtl8168b_driver_destroy(void)
+{
+ cdi_net_driver_destroy(&rtl8168b_driver);
+
+ return 0;
+}
+
+static struct cdi_net_driver rtl8168b_driver = {
+ .drv = {
+ .name = DRIVER_NAME,
+ .type = CDI_NETWORK,
+ .bus = CDI_PCI,
+ .init = rtl8168b_driver_init,
+ .destroy = rtl8168b_driver_destroy,
+ .init_device = rtl8168b_init_device,
+ .remove_device = rtl8168b_remove_device,
+ },
+
+ .send_packet = rtl8168b_send_packet,
+};
+
+CDI_DRIVER(DRIVER_NAME, rtl8168b_driver)
diff --git a/src/modules/cdi/rtl8168b/rtl8168b.c b/src/modules/cdi/rtl8168b/rtl8168b.c
new file mode 100644
index 0000000..ac88eb4
--- /dev/null
+++ b/src/modules/cdi/rtl8168b/rtl8168b.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2007 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Patrick Pokatilo and Max Reitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <cdi.h>
+#include <cdi/mem.h>
+#include <cdi/misc.h>
+#include <cdi/net.h>
+#include <cdi/pci.h>
+
+#include "rtl8168b.h"
+
+#define DEBUG_MSG(s) \
+ printf("[RTL8111B/8168B] debug: %s() '%s'\n", __FUNCTION__, s)
+#define DEVICE_MSG printf
+
+static void rtl8168b_handle_interrupt(struct cdi_device* device);
+
+static inline void write_register_8(struct rtl8168b_device* netcard,
+ uint8_t reg, uint8_t value)
+{
+ *(volatile uint8_t *)((uintptr_t)netcard->mmio + reg) = value;
+}
+
+static inline void write_register_16(struct rtl8168b_device* netcard,
+ uint8_t reg, uint16_t value)
+{
+ *(volatile uint16_t *)((uintptr_t)netcard->mmio + reg) = value;
+}
+
+static inline void write_register_32(struct rtl8168b_device* netcard,
+ uint8_t reg, uint32_t value)
+{
+ *(volatile uint32_t *)((uintptr_t)netcard->mmio + reg) = value;
+}
+
+static inline void write_register_64(struct rtl8168b_device* netcard,
+ uint8_t reg, uint64_t value)
+{
+ *(volatile uint64_t *)((uintptr_t)netcard->mmio + reg) = value;
+}
+
+static inline uint8_t read_register_8(struct rtl8168b_device* netcard,
+ uint8_t reg)
+{
+ return *(volatile uint8_t *)((uintptr_t)netcard->mmio + reg);
+}
+
+static inline uint16_t read_register_16(struct rtl8168b_device* netcard,
+ uint8_t reg)
+{
+ return *(volatile uint16_t *)((uintptr_t)netcard->mmio + reg);
+}
+
+static inline uint32_t read_register_32(struct rtl8168b_device* netcard,
+ uint8_t reg)
+{
+ return *(volatile uint32_t *)((uintptr_t)netcard->mmio + reg);
+}
+
+static inline uint64_t read_register_64(struct rtl8168b_device* netcard,
+ uint8_t reg)
+{
+ return *(volatile uint64_t *)((uintptr_t)netcard->mmio + reg);
+}
+
+
+struct cdi_device* rtl8168b_init_device(struct cdi_bus_data* bus_data)
+{
+ struct cdi_pci_device* pci = (struct cdi_pci_device*) bus_data;
+ struct rtl8168b_device* netcard;
+ struct cdi_mem_area* buf;
+
+ if ((pci->vendor_id != 0x10ec) || (pci->device_id != 0x8168)) {
+ return NULL;
+ }
+
+
+ buf = cdi_mem_alloc(sizeof(*netcard), CDI_MEM_VIRT_ONLY | CDI_MEM_NOINIT);
+
+ if (!buf) {
+ return NULL;
+ }
+
+
+ netcard = buf->vaddr;
+
+ memset(netcard, 0, sizeof(*netcard));
+
+
+ netcard->net.dev.bus_data = (struct cdi_bus_data*) pci;
+
+ DEBUG_MSG("Interrupthandler registrieren");
+ cdi_register_irq(pci->irq, rtl8168b_handle_interrupt, &netcard->net.dev);
+ cdi_pci_alloc_memory(pci);
+
+
+ struct cdi_pci_resource* res;
+ for (int i = 0; (res = cdi_list_get(pci->resources, i)); i++) {
+ if ((res->type == CDI_PCI_MEMORY) && (res->index == 2)) {
+ netcard->mmio = res->address;
+ break;
+ }
+ }
+
+
+ DEBUG_MSG("Reset der Karte");
+ write_register_16(netcard, REG_CP_COMMAND, CPCR_VLAN_DETAG);
+
+ write_register_8(netcard, REG_COMMAND, CR_RESET);
+
+ while ((read_register_8(netcard, REG_COMMAND) & CR_RESET) == CR_RESET);
+
+ write_register_16(netcard, REG_RECV_MAX_SIZE, 1518);
+ write_register_16(netcard, REG_MAX_TRANS_SIZE, 0x0c);
+
+ DEBUG_MSG("Aktiviere Rx/Tx");
+ write_register_8(netcard, REG_COMMAND,
+ CR_RECEIVER_ENABLE | CR_TRANSMITTER_ENABLE);
+
+ DEBUG_MSG("MAC-Adresse auslesen");
+ netcard->net.mac =
+ read_register_64(netcard, REG_ID0) & 0xffffffffffffLL;
+
+ DEBUG_MSG("Setze Interruptmaske");
+ write_register_16(netcard, REG_INTERRUPT_STATUS, 0x4fff);
+ write_register_16(netcard, REG_INTERRUPT_MASK, 0x0025);
+
+ DEBUG_MSG("Initialisiere PHY");
+ write_register_32(netcard, REG_PHY_ACCESS,
+ PA_RW | (PHY_REG_BMCR << 16) | PHY_BMCR_RESET);
+
+ while (read_register_32(netcard, REG_PHY_ACCESS) & PA_RW);
+
+ do {
+ write_register_16(netcard, REG_PHY_ADDRESS, PHY_REG_BMCR);
+
+ while (!(read_register_8(netcard, REG_PHY_RW) >> 7));
+ } while (read_register_16(netcard, REG_PHY_DATA) & PHY_BMCR_RESET);
+
+ write_register_32(netcard, REG_PHY_ACCESS,
+ PA_RW | (PHY_REG_BMCR << 16) | PHY_BMCR_AUTO_NEGOTIATION);
+
+ while (read_register_32(netcard, REG_PHY_ACCESS) & PA_RW);
+
+
+ DEVICE_MSG("Lege Deskriptoren an");
+ netcard->tx_buffer_area =
+ cdi_mem_alloc(TX_BUFFER_COUNT * sizeof(struct rtl8168b_descriptor),
+ CDI_MEM_PHYS_CONTIGUOUS | 8);
+ netcard->tx_buffer = netcard->tx_buffer_area->vaddr;
+ netcard->tx_buffer_phys = netcard->tx_buffer_area->paddr.items[0].start;
+
+ netcard->rx_buffer_area =
+ cdi_mem_alloc(RX_BUFFER_COUNT * sizeof(struct rtl8168b_descriptor),
+ CDI_MEM_PHYS_CONTIGUOUS | 8);
+ netcard->rx_buffer = netcard->rx_buffer_area->vaddr;
+ netcard->rx_buffer_phys = netcard->rx_buffer_area->paddr.items[0].start;
+
+ int i;
+ for (i = 0; i < RX_BUFFER_COUNT; i++) {
+ memset(&netcard->rx_buffer[i], 0, sizeof(struct rtl8168b_descriptor));
+
+ netcard->rx_area[i] =
+ cdi_mem_alloc(RX_BUFFER_SIZE, CDI_MEM_PHYS_CONTIGUOUS | 3);
+ netcard->rx_buffer[i].address =
+ netcard->rx_area[i]->paddr.items[0].start;
+ netcard->rx_buffer[i].command = DC_OWN | RX_BUFFER_SIZE;
+
+ if (i == RX_BUFFER_COUNT - 1) {
+ netcard->rx_buffer[i].command |= DC_EOR;
+ }
+ }
+
+ if (i == 0) {
+ DEVICE_MSG("[RTL8111B/8168B] Keine Buffer zum Empfangen von Daten!\n");
+ write_register_8(netcard, REG_COMMAND,
+ read_register_8(netcard, REG_COMMAND) & ~CR_RECEIVER_ENABLE);
+ }
+
+ for (i = 0; i < TX_BUFFER_COUNT; i++) {
+ memset(&netcard->tx_buffer[i], 0, sizeof(struct rtl8168b_descriptor));
+
+ netcard->tx_area[i] =
+ cdi_mem_alloc(TX_BUFFER_SIZE, CDI_MEM_PHYS_CONTIGUOUS | 3);
+ netcard->tx_buffer[i].address =
+ netcard->tx_area[i]->paddr.items[0].start;
+ netcard->tx_buffer[i].command = 0;
+
+ if (i == TX_BUFFER_COUNT - 1) {
+ netcard->tx_buffer[i].command |= DC_EOR;
+ }
+ }
+
+ if (i == 0) {
+ DEVICE_MSG("[RTL8111B/8168B] Keine Buffer zum Senden von Daten!\n");
+ write_register_8(netcard, REG_COMMAND,
+ read_register_8(netcard, REG_COMMAND) & ~CR_TRANSMITTER_ENABLE);
+ }
+
+ DEBUG_MSG("Initialisiere Buffer");
+ write_register_64(netcard, REG_RECEIVE_DESCRIPTORS,
+ netcard->rx_buffer_phys);
+ write_register_64(netcard, REG_TRANSMIT_DESCRIPTORS,
+ netcard->tx_buffer_phys);
+
+ DEBUG_MSG("Initialisiere RCR/TCR");
+ write_register_32(netcard, REG_RECEIVE_CONFIGURATION,
+ RCR_MXDMA_UNLIMITED | RCR_NO_FIFO_THRESHOLD | RCR_ACCEPT_BROADCAST |
+ RCR_ACCEPT_PHYS_MATCH);
+ write_register_32(netcard, REG_TRANSMIT_CONFIGURATION,
+ TCR_MXDMA_UNLIMITED | TCR_IFG_STANDARD);
+
+ cdi_net_device_init(&netcard->net);
+
+ DEBUG_MSG("Fertig initialisiert");
+ return &netcard->net.dev;
+}
+
+void rtl8168b_remove_device(struct cdi_device* device)
+{
+ struct rtl8168b_device* netcard = (struct rtl8168b_device*) device;
+ int i;
+
+ cdi_pci_free_memory((struct cdi_pci_device*) netcard->net.dev.bus_data);
+
+ cdi_mem_free(netcard->tx_buffer_area);
+ cdi_mem_free(netcard->rx_buffer_area);
+
+ for (i = 0; i < RX_BUFFER_COUNT; i++) {
+ netcard->rx_buffer[i].command &= 0x40000000;
+ netcard->rx_buffer[i].address = (uintptr_t) NULL;
+
+ cdi_mem_free(netcard->rx_area[i]);
+ }
+
+ for (i = 0; i < TX_BUFFER_COUNT; i++) {
+ netcard->tx_buffer[i].command &= 0x40000000;
+ netcard->tx_buffer[i].address = (uintptr_t) NULL;
+
+ cdi_mem_free(netcard->tx_area[i]);
+ }
+}
+
+void rtl8168b_send_packet(struct cdi_net_device* device,
+ void *data, size_t size)
+{
+ struct rtl8168b_device* netcard = (struct rtl8168b_device*) device;
+
+ if (size > TX_BUFFER_SIZE) {
+ DEVICE_MSG("[RTL8111B/8168B] Paket zu groß!\n");
+
+ return;
+ }
+
+ int i;
+
+ do {
+ i = netcard->tx_index;
+ } while (!__sync_bool_compare_and_swap(&netcard->tx_index, i,
+ (i + 1) % TX_BUFFER_COUNT));
+
+ if (netcard->tx_buffer[i].command & DC_OWN) {
+ DEBUG_MSG("Tx-Buffer ist schon besetzt");
+ return;
+ }
+
+
+ memcpy(netcard->tx_area[i]->vaddr, data, size);
+ netcard->tx_buffer[i].vlan = 0;
+
+ DEVICE_MSG("[RTL8111B/8168B] Sende via Deskriptor %i\n", i);
+
+ if (i == TX_BUFFER_COUNT - 1) {
+ netcard->tx_buffer[i].command = size | DC_FS | DC_LS | DC_OWN | DC_EOR;
+ } else {
+ netcard->tx_buffer[i].command = size | DC_FS | DC_LS | DC_OWN;
+ }
+
+ write_register_8(netcard, REG_TRANSMIT_POLL, TPR_PACKET_WAITING);
+}
+
+
+static void rtl8168b_unown_rx_desc(struct rtl8168b_device* netcard, int i)
+{
+ if (i == RX_BUFFER_COUNT - 1) {
+ netcard->rx_buffer[i].command = RX_BUFFER_SIZE | DC_OWN | DC_EOR;
+ } else {
+ netcard->rx_buffer[i].command = RX_BUFFER_SIZE | DC_OWN;
+ }
+}
+
+static void rtl8168b_handle_receive_ok(struct rtl8168b_device* netcard)
+{
+ int i;
+
+ do {
+ i = netcard->rx_index;
+ } while (!__sync_bool_compare_and_swap(&netcard->rx_index, i,
+ (i + 1) % RX_BUFFER_COUNT));
+
+ if (netcard->rx_buffer[i].command & DC_OWN) {
+ netcard->rx_index = i;
+
+ if (!(netcard->rx_buffer[0].command & DC_OWN)) {
+ // FIXME: Make atomic
+ i = 0;
+ netcard->rx_index = 1;
+ } else {
+ DEVICE_MSG("[RTL8111B/8168B] Empfangsdeskriptor sollte %i sein, "
+ "dort ist aber nichts.\n", i);
+ return;
+ }
+ }
+
+
+ size_t sz = netcard->rx_buffer[i].command & DC_LENGTH;
+
+ DEVICE_MSG("[RTL8111B/8168B] Empfange %i B von Deskriptor %i\n",
+ (int)sz - 4, i);
+
+ if (sz < 5)
+ {
+ rtl8168b_unown_rx_desc(netcard, i);
+ return;
+ }
+
+ cdi_net_receive((struct cdi_net_device*) netcard,
+ netcard->rx_area[i]->vaddr, sz - 4);
+
+ rtl8168b_unown_rx_desc(netcard, i);
+}
+
+static void rtl8168b_handle_transmit_ok(struct rtl8168b_device* netcard)
+{
+ (void) netcard;
+}
+
+static void rtl8168b_handle_link_change(struct rtl8168b_device* netcard)
+{
+ uint8_t status = read_register_8(netcard, REG_PHY_STATUS);
+
+ if ((status & PS_LINK) != PS_LINK) {
+ DEVICE_MSG("[RTL8111B/8168B] Link down\n");
+ } else {
+ uint16_t speed = (status & PS_FULLDUP) << 15;
+
+ if (status & PS_1000) {
+ speed |= 1000;
+ } else if (status & PS_100) {
+ speed |= 100;
+ } else if (status & PS_10) {
+ speed |= 10;
+ }
+
+ DEVICE_MSG("[RTL8111B/8168B] Link up (%uMb/s %s-duplex)\n",
+ speed & 0x7FFF, (speed & 0x8000) ? "Full" : "Half");
+ }
+}
+
+static void rtl8168b_handle_interrupt(struct cdi_device* device)
+{
+ struct rtl8168b_device* netcard = (struct rtl8168b_device*) device;
+ uint16_t isr = read_register_16(netcard, REG_INTERRUPT_STATUS);
+
+ write_register_16(netcard, REG_INTERRUPT_STATUS, isr);
+
+ DEVICE_MSG("[RTL8111B/8168B] Interrupt: %x\n", isr);
+
+ if (isr & ISR_RECEIVE_OK) {
+ rtl8168b_handle_receive_ok(netcard);
+ }
+
+ if (isr & ISR_TRANSMIT_OK) {
+ rtl8168b_handle_transmit_ok(netcard);
+ }
+
+ if (isr & ISR_LINK_CHANGE) {
+ rtl8168b_handle_link_change(netcard);
+ }
+}
--
2.6.3