Browse Source

[bsp][x86] add rtl8139 eth driver

JasonHu 3 years ago
parent
commit
58fd905ea7

+ 79 - 5
bsp/x86/.config

@@ -16,7 +16,7 @@ CONFIG_RT_THREAD_PRIORITY_32=y
 # CONFIG_RT_THREAD_PRIORITY_256 is not set
 CONFIG_RT_THREAD_PRIORITY_MAX=32
 CONFIG_RT_TICK_PER_SECOND=100
-# CONFIG_RT_USING_OVERFLOW_CHECK is not set
+CONFIG_RT_USING_OVERFLOW_CHECK=y
 CONFIG_RT_USING_HOOK=y
 CONFIG_RT_USING_IDLE_HOOK=y
 CONFIG_RT_IDLE_HOOK_LIST_SIZE=4
@@ -137,13 +137,16 @@ CONFIG_RT_USING_DFS_ROMFS=y
 # CONFIG_RT_USING_DFS_RAMFS is not set
 # CONFIG_RT_USING_DFS_UFFS is not set
 # CONFIG_RT_USING_DFS_JFFS2 is not set
+# CONFIG_RT_USING_DFS_NFS is not set
 
 #
 # Device Drivers
 #
 CONFIG_RT_USING_DEVICE_IPC=y
 CONFIG_RT_PIPE_BUFSZ=512
-# CONFIG_RT_USING_SYSTEM_WORKQUEUE is not set
+CONFIG_RT_USING_SYSTEM_WORKQUEUE=y
+CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=4096
+CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23
 CONFIG_RT_USING_SERIAL=y
 # CONFIG_RT_SERIAL_USING_DMA is not set
 CONFIG_RT_SERIAL_RB_BUFSZ=64
@@ -202,22 +205,90 @@ CONFIG_RT_USING_POSIX_CLOCKTIME=y
 #
 # Socket abstraction layer
 #
-# CONFIG_RT_USING_SAL is not set
+CONFIG_RT_USING_SAL=y
+
+#
+# protocol stack implement
+#
+CONFIG_SAL_USING_LWIP=y
+CONFIG_SAL_USING_POSIX=y
 
 #
 # Network interface device
 #
-# CONFIG_RT_USING_NETDEV is not set
+CONFIG_RT_USING_NETDEV=y
+CONFIG_NETDEV_USING_IFCONFIG=y
+CONFIG_NETDEV_USING_PING=y
+CONFIG_NETDEV_USING_NETSTAT=y
+CONFIG_NETDEV_USING_AUTO_DEFAULT=y
+CONFIG_NETDEV_USING_IPV6=y
+CONFIG_NETDEV_IPV4=1
+CONFIG_NETDEV_IPV6=1
+CONFIG_NETDEV_IPV6_SCOPES=y
 
 #
 # light weight TCP/IP stack
 #
-# CONFIG_RT_USING_LWIP is not set
+CONFIG_RT_USING_LWIP=y
+# CONFIG_RT_USING_LWIP141 is not set
+# CONFIG_RT_USING_LWIP202 is not set
+CONFIG_RT_USING_LWIP212=y
+CONFIG_RT_USING_LWIP_IPV6=y
+CONFIG_RT_LWIP_MEM_ALIGNMENT=4
+CONFIG_RT_LWIP_IGMP=y
+CONFIG_RT_LWIP_ICMP=y
+# CONFIG_RT_LWIP_SNMP is not set
+CONFIG_RT_LWIP_DNS=y
+CONFIG_RT_LWIP_DHCP=y
+CONFIG_IP_SOF_BROADCAST=1
+CONFIG_IP_SOF_BROADCAST_RECV=1
+
+#
+# Static IPv4 Address
+#
+CONFIG_RT_LWIP_IPADDR="192.168.1.30"
+CONFIG_RT_LWIP_GWADDR="192.168.1.1"
+CONFIG_RT_LWIP_MSKADDR="255.255.255.0"
+CONFIG_RT_LWIP_UDP=y
+CONFIG_RT_LWIP_TCP=y
+CONFIG_RT_LWIP_RAW=y
+# CONFIG_RT_LWIP_PPP is not set
+CONFIG_RT_MEMP_NUM_NETCONN=8
+CONFIG_RT_LWIP_PBUF_NUM=16
+CONFIG_RT_LWIP_RAW_PCB_NUM=4
+CONFIG_RT_LWIP_UDP_PCB_NUM=4
+CONFIG_RT_LWIP_TCP_PCB_NUM=4
+CONFIG_RT_LWIP_TCP_SEG_NUM=40
+CONFIG_RT_LWIP_TCP_SND_BUF=8196
+CONFIG_RT_LWIP_TCP_WND=8196
+CONFIG_RT_LWIP_TCPTHREAD_PRIORITY=10
+CONFIG_RT_LWIP_TCPTHREAD_MBOX_SIZE=8
+CONFIG_RT_LWIP_TCPTHREAD_STACKSIZE=2048
+# CONFIG_LWIP_NO_RX_THREAD is not set
+# CONFIG_LWIP_NO_TX_THREAD is not set
+CONFIG_RT_LWIP_ETHTHREAD_PRIORITY=12
+CONFIG_RT_LWIP_ETHTHREAD_STACKSIZE=2048
+CONFIG_RT_LWIP_ETHTHREAD_MBOX_SIZE=8
+# CONFIG_RT_LWIP_REASSEMBLY_FRAG is not set
+CONFIG_LWIP_NETIF_STATUS_CALLBACK=1
+CONFIG_LWIP_NETIF_LINK_CALLBACK=1
+CONFIG_SO_REUSE=1
+CONFIG_LWIP_SO_RCVTIMEO=1
+CONFIG_LWIP_SO_SNDTIMEO=1
+CONFIG_LWIP_SO_RCVBUF=1
+CONFIG_LWIP_SO_LINGER=0
+# CONFIG_RT_LWIP_NETIF_LOOPBACK is not set
+CONFIG_LWIP_NETIF_LOOPBACK=0
+# CONFIG_RT_LWIP_STATS is not set
+# CONFIG_RT_LWIP_USING_HW_CHECKSUM is not set
+CONFIG_RT_LWIP_USING_PING=y
+# CONFIG_RT_LWIP_DEBUG is not set
 
 #
 # AT commands
 #
 # CONFIG_RT_USING_AT is not set
+# CONFIG_LWIP_USING_DHCPD is not set
 
 #
 # VBUS(Virtual Software BUS)
@@ -287,6 +358,7 @@ CONFIG_LWP_TID_MAX_NR=64
 # CONFIG_PKG_USING_AT_DEVICE is not set
 # CONFIG_PKG_USING_ATSRV_SOCKET is not set
 # CONFIG_PKG_USING_WIZNET is not set
+# CONFIG_PKG_USING_ZB_COORDINATOR is not set
 
 #
 # IoT Cloud
@@ -327,6 +399,7 @@ CONFIG_LWP_TID_MAX_NR=64
 # CONFIG_PKG_USING_AGILE_MODBUS is not set
 # CONFIG_PKG_USING_AGILE_FTP is not set
 # CONFIG_PKG_USING_EMBEDDEDPROTO is not set
+# CONFIG_PKG_USING_RT_LINK_HW is not set
 
 #
 # security packages
@@ -523,6 +596,7 @@ CONFIG_LWP_TID_MAX_NR=64
 # CONFIG_PKG_USING_KOBUKI is not set
 # CONFIG_PKG_USING_ROSSERIAL is not set
 # CONFIG_PKG_USING_MICRO_ROS is not set
+# CONFIG_PKG_USING_MCP23008 is not set
 
 #
 # AI packages

+ 17 - 0
bsp/x86/Makefile

@@ -19,6 +19,13 @@ RTTHREAD_ELF:= rtthread.elf
 # config graphic window ? (y/n)
 QEMU_WINDOW ?= n
 
+# config netcard ? (y/n)
+QEMU_NETCARD ?= y
+QEMU_NETCARD_NAME ?=rtl8139
+
+# netcard type: tap/user
+QEMU_NET_MODE ?=user
+
 # qemu args
 QEMU_ARGS	:= 	-m 256m \
 				-rtc base=localtime \
@@ -31,6 +38,16 @@ else
 	QEMU_ARGS += -nographic
 endif
 
+ifeq ($(QEMU_NETCARD),y)
+	QEMU_ARGS += -net nic,model=$(QEMU_NETCARD_NAME)
+ifeq ($(QEMU_NET_MODE),tap)
+	QEMU_ARGS += -net tap,ifname=tap0,script=no,downscript=no 
+else
+	QEMU_ARGS += -net user
+endif
+
+endif
+
 QEMU_ARGS +=-drive id=disk0,file=$(DISK0),format=raw,if=none \
 			-drive id=disk1,file=$(DISK1),format=raw,if=none \
 			-device ahci,id=ahci \

+ 2 - 2
bsp/x86/drivers/board.c

@@ -67,8 +67,8 @@ void rt_hw_board_init(void)
     init_page_region.start = (size_t)HW_PAGE_START;
     init_page_region.end = page_region_init();
     /* init no mapped area in kernel table, must in kernel space */
-    RT_ASSERT(!rt_hw_mmu_map_init(&mmu_info, (void *)HW_KERNEL_DELAY_MAP_START, 
-              HW_KERNEL_DELAY_MAP_SIZE, (rt_size_t *)g_mmu_table, 0))
+    RT_ASSERT(!rt_hw_mmu_map_init(&mmu_info, (void *)HW_KERNEL_DELAY_MAP_START,
+              HW_KERNEL_DELAY_MAP_SIZE, (rt_size_t *)g_mmu_table, 0));
 
     rt_page_init(init_page_region);
     /* map kernel space, then can read/write this area directly. */

+ 889 - 0
bsp/x86/drivers/drv_rtl8139.c

@@ -0,0 +1,889 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-08-16     JasonHu      first version
+ */
+
+#include <board.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
+#include <netif/ethernetif.h>
+#include <pci.h>
+#include <mmu.h>
+
+#define DBG_LVL DBG_INFO
+#define DBG_TAG "RTL8139"
+#include <rtdbg.h>
+
+#include "drv_rtl8139.h"
+
+#define DEV_NAME "e0"
+
+#define GET_RTL8139(eth)    (struct eth_device_rtl8139 *)(eth)
+
+struct eth_device_rtl8139
+{
+    /* inherit from Ethernet device */
+    struct eth_device parent;
+    /* interface address info. */
+    rt_uint8_t dev_addr[ETH_ALEN];         /* MAC address  */
+
+    rt_pci_device_t *pci_dev;   /* pci device info */
+
+    rt_uint32_t iobase; /* io port base */
+    rt_uint32_t irqno;  /* irq number */
+
+    card_chip_t chipset;
+
+    rt_spinlock_t lock; /* lock for rx packet */
+
+    rt_uint8_t *rx_buffer;
+    rt_uint8_t *rx_ring;
+    rt_uint8_t  current_rx; /* CAPR, Current Address of Packet Read */
+    rt_uint32_t rx_flags;
+    rt_ubase_t rx_ring_dma; /* dma phy addr */
+    rt_uint32_t rx_config;  /* receive config */
+    struct rtl8139_status   rx_status;
+
+    rt_uint8_t *tx_buffers;
+    rt_uint8_t *tx_buffer[NUM_TX_DESC]; /* tx buffer pointer array */
+    rt_uint32_t current_tx;
+    rt_uint32_t dirty_tx;
+    rt_size_t   tx_free_counts;
+    rt_uint32_t tx_flags;
+    rt_ubase_t tx_buffer_dma;  /* dma phy addr */
+    struct rtl8139_status   tx_status;
+
+    struct net_device_status stats; /* device stats */
+    struct rtl_extra_status xstats; /* extra status */
+
+    rt_uint32_t dev_flags;  /* flags of net device */
+    rt_mq_t rx_mqueue;  /* msg queue for rx */
+    rt_uint8_t linked;  /* eth device linked */
+};
+
+static struct eth_device_rtl8139 eth_dev;
+static rt_uint8_t rx_cache_send_buf[RX_MSG_SIZE] = {0};     /* buf for rx packet, put size and data into mq */
+static rt_uint8_t rx_cache_recv_buf[RX_MSG_SIZE] = {0};     /* buf for rx packet, get size and data from mq */
+static rt_uint8_t tx_cache_pbuf[TX_CACHE_BUF_SIZE] = {0};   /* buf for tx packet, get data from pbuf payload */
+
+static int rtl8139_next_desc(int current_desc)
+{
+    return (current_desc == NUM_TX_DESC - 1) ? 0 : (current_desc + 1);
+}
+
+int rtl8139_transmit(struct eth_device_rtl8139 *dev, rt_uint8_t *buf, rt_size_t len)
+{
+    rt_uint32_t entry;
+    rt_uint32_t length = len;
+
+    entry = dev->current_tx;
+
+    rt_base_t level = rt_hw_interrupt_disable();
+
+    if (dev->tx_free_counts > 0)
+    {
+        if (length < TX_BUF_SIZE)
+        {
+            if (length < ETH_ZLEN)
+            {
+                rt_memset(dev->tx_buffer[entry], 0, ETH_ZLEN);  /* pad zero */
+            }
+            rt_memcpy(dev->tx_buffer[entry], buf, length);
+        }
+        else
+        {
+            /* drop packet */
+            dev->stats.tx_dropped++;
+            dbg_log(DBG_WARNING, "dropped a packed!\n");
+
+            rt_hw_interrupt_enable(level);
+            return 0;
+        }
+        /*
+        * Writing to tx_status triggers a DMA transfer of the data
+        * copied to dev->tx_buffer[entry] above. Use a memory barrier
+        * to make sure that the device sees the updated data.
+        */
+        rt_hw_dsb();
+
+        outl(dev->iobase + TX_STATUS0 + (entry * 4), dev->tx_flags | ETH_MAX(length, (rt_uint32_t )ETH_ZLEN));
+        inl(dev->iobase + TX_STATUS0 + (entry * 4)); // flush
+
+        dev->current_tx = rtl8139_next_desc(dev->current_tx);
+
+        --dev->tx_free_counts;
+    } else {
+        LOG_E("Stop Tx packet!\n");
+        rt_hw_interrupt_enable(level);
+        return -1;
+    }
+    rt_hw_interrupt_enable(level);
+    return 0;
+}
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void rtl8139_init_ring(struct eth_device_rtl8139 *dev)
+{
+    int i;
+
+    dev->current_rx = 0;
+    dev->current_tx = 0;
+    dev->dirty_tx = 0;
+
+    /* set free counts */
+    dev->tx_free_counts = NUM_TX_DESC;
+
+    for (i = 0; i < NUM_TX_DESC; i++)
+    {
+        dev->tx_buffer[i] = (unsigned char *)&dev->tx_buffers[i * TX_BUF_SIZE];
+    }
+}
+
+static void rtl8139_chip_reset(struct eth_device_rtl8139 *dev)
+{
+    /* software reset, to clear the RX and TX buffers and set everything back to defaults. */
+    outb(dev->iobase + CHIP_CMD, CMD_RESET);
+
+    /* wait reset done */
+    for (;;)
+    {
+        rt_hw_dmb();
+        if ((inb(dev->iobase + CHIP_CMD) & CMD_RESET) == 0)
+        {
+            break;
+        }
+        rt_hw_cpu_pause();
+    }
+}
+
+static void rtl8139_set_rx_mode(struct eth_device_rtl8139 *dev)
+{
+    rt_base_t level = rt_hw_interrupt_disable();
+
+    int rx_mode = ACCEPT_BROADCAST | ACCEPT_MY_PHYS | ACCEPT_MULTICAST;
+
+    rx_mode |= (ACCEPT_ERR | ACCEPT_RUNT);
+
+    rt_uint32_t tmp;
+    tmp = rtl8139_rx_config | rx_mode;
+    if (dev->rx_config != tmp)
+    {
+        outl(dev->iobase + RX_CONFIG, tmp);
+        /* flush */
+        inl(dev->iobase + RX_CONFIG);
+        dev->rx_config = tmp;
+    }
+
+    /* filter packet */
+    rt_uint32_t mac_filter[2];
+
+    mac_filter[0] = mac_filter[1] = 0;
+
+    outl(dev->iobase + MAR0 + 0, mac_filter[0]);
+    inl(dev->iobase + MAR0 + 0);
+
+    outl(dev->iobase + MAR0 + 4, mac_filter[1]);
+    inl(dev->iobase + MAR0 + 4);
+
+    rt_hw_interrupt_enable(level);
+}
+
+static void rtl8139_hardware_start(struct eth_device_rtl8139 *dev)
+{
+    /* Bring old chips out of low-power mode. */
+    if (rtl_chip_info[dev->chipset].flags & HAS_HLT_CLK)
+    {
+        outb(dev->iobase + HLT_CTL, 'R');
+    }
+
+    rtl8139_chip_reset(dev);
+
+    /* unlock Config[01234] and BMCR register writes */
+    outb(dev->iobase + CFG9346, CFG9346_UNLOCK);
+    inb(dev->iobase + CFG9346);   // flush
+
+    /* Restore our rtl8139a of the MAC address. */
+    outl(dev->iobase + MAC0, *(rt_uint32_t *)(dev->dev_addr + 0));
+    inl(dev->iobase + MAC0);
+
+    outw(dev->iobase + MAC0 + 4, *(uint16_t *)(dev->dev_addr + 4));
+    inw(dev->iobase + MAC0 + 4);
+
+    dev->current_rx = 0;
+
+    /* init Rx ring buffer DMA address */
+    outl(dev->iobase + RX_BUF, dev->rx_ring_dma);
+    inl(dev->iobase + RX_BUF);
+
+    /* Must enable Tx/Rx before setting transfer thresholds! */
+    outb(dev->iobase + CHIP_CMD, CMD_RX_ENABLE | CMD_TX_ENABLE);
+
+    /* set receive config */
+    dev->rx_config = rtl8139_rx_config | ACCEPT_BROADCAST | ACCEPT_MY_PHYS;
+
+    outl(dev->iobase + RX_CONFIG, dev->rx_config);
+    outl(dev->iobase + TX_CONFIG, rtl8139_tx_config);
+
+    if (dev->chipset >= CH_8139B)
+    {
+        /* Disable magic packet scanning, which is enabled
+         * when PM is enabled in Config1.  It can be reenabled
+         * via ETHTOOL_SWOL if desired.
+         * clear MAGIC bit
+         */
+        outb(dev->iobase + CONFIG3, inb(dev->iobase + CONFIG3) & ~CFG3_MAGIC);
+    }
+
+    /* Lock Config[01234] and BMCR register writes */
+    outb(dev->iobase + CFG9346, CFG9346_LOCK);
+
+    /* init Tx buffer DMA addresses */
+    int i;
+    for (i = 0; i < NUM_TX_DESC; i++)
+    {
+        outl(dev->iobase + TX_ADDR0 + (i * 4), dev->tx_buffer_dma + (dev->tx_buffer[i] - dev->tx_buffers));
+        /* flush */
+        inl(dev->iobase + TX_ADDR0 + (i * 4));
+    }
+
+    outl(dev->iobase + RX_MISSED, 0);
+
+    rtl8139_set_rx_mode(dev);
+
+    /* no early-rx intr */
+    outw(dev->iobase + MULTI_INTR, inw(dev->iobase + MULTI_INTR) & MULTI_INTR_CLEAR);
+
+    /* make sure tx & rx enabled */
+    uint8_t tmp = inb(dev->iobase + CHIP_CMD);
+    if (!(tmp & CMD_RX_ENABLE) || !(tmp & CMD_TX_ENABLE))
+    {
+        outb(dev->iobase + CHIP_CMD, CMD_RX_ENABLE | CMD_TX_ENABLE);
+    }
+
+    /* enable 8139 intr mask */
+    outw(dev->iobase + INTR_MASK, rtl8139_intr_mask);
+}
+
+static int rtl8139_tx_interrupt(struct eth_device_rtl8139 *dev)
+{
+    while (dev->tx_free_counts < NUM_TX_DESC)
+    {
+        int entry = dev->dirty_tx;
+        int tx_status;
+
+        /* read tx status */
+        tx_status = inl(dev->iobase + TX_STATUS0 + (entry * 4));
+
+        /* no tx intr, exit */
+        if (!(tx_status & (TX_STAT_OK | TX_UNDERRUN | TX_ABORTED)))
+        {
+            dbg_log(DBG_ERROR, "tx status not we want!\n");
+            break;
+        }
+
+        /* NOTE: TxCarrierLost is always asserted at 100mbps. */
+        if (tx_status & (TX_OUT_OF_WINDOW | TX_ABORTED))
+        {
+            dbg_log(DBG_ERROR, "Transmit error, Tx status %x\n", tx_status);
+            dev->stats.tx_errors++;
+            if (tx_status & TX_ABORTED)
+            {
+                dev->stats.tx_aborted_errors++;
+                /* clear abort bit */
+                outl(dev->iobase + TX_CONFIG, TX_CLEAR_ABT);
+
+                /* set intr tx error */
+                outw(dev->iobase + INTR_STATUS, TX_ERR);
+
+                rt_hw_dsb();
+            }
+            if (tx_status & TX_CARRIER_LOST)
+            {
+                dev->stats.tx_carrier_errors++;
+            }
+
+            if (tx_status & TX_OUT_OF_WINDOW)
+            {
+                dev->stats.tx_window_errors++;
+            }
+        }
+        else
+        {
+            if (tx_status & TX_UNDERRUN)
+            {
+                /* Add 64 to the Tx FIFO threshold. */
+                if (dev->tx_flags < 0x00300000) {
+                    dev->tx_flags += 0x00020000;
+                }
+                dev->stats.tx_fifo_errors++;
+            }
+            dev->stats.collisions += (tx_status >> 24) & 15;
+
+            dev->tx_status.packets++;
+            dev->tx_status.bytes += tx_status & 0x7ff;
+        }
+
+        dev->dirty_tx = rtl8139_next_desc(dev->dirty_tx);
+
+        if (dev->tx_free_counts == 0)
+        {
+            rt_hw_dmb();
+        }
+
+        dev->tx_free_counts++;
+    }
+    return 0;
+}
+
+static void rtl8139_other_interrupt(struct eth_device_rtl8139 *dev, int status, int link_changed)
+{
+    /* Update the error count. */
+    dev->stats.rx_missed_errors += inl(dev->iobase + RX_MISSED);
+    outl(dev->iobase + RX_MISSED, 0);
+
+    if ((status & RX_UNDERRUN) && link_changed && (dev->dev_flags & HAS_LNK_CHNG))
+    {
+        dev->linked = RT_FALSE; /* dev not linked */
+        status &= ~RX_UNDERRUN;
+    }
+
+    if (status & (RX_UNDERRUN | RX_ERR))
+    {
+        dev->stats.rx_errors++;
+    }
+
+    if (status & PCS_TIMEOUT)
+    {
+        dev->stats.rx_length_errors++;
+    }
+
+    if (status & RX_UNDERRUN)
+    {
+        dev->stats.rx_fifo_errors++;
+    }
+
+    if (status & PCI_ERR)   /* error on pci */
+    {
+        rt_uint32_t pci_cmd_status;
+        pci_cmd_status = rt_pci_device_read(dev->pci_dev, PCI_STATUS_COMMAND);
+        rt_pci_device_write(dev->pci_dev, PCI_STATUS_COMMAND, pci_cmd_status);
+        dbg_log(DBG_ERROR, "PCI Bus error %x\n", pci_cmd_status >> 16);
+    }
+}
+
+static void rtl8139_rx_error(rt_uint32_t rx_status, struct eth_device_rtl8139 *dev)
+{
+    rt_uint8_t tmp;
+
+    dev->stats.rx_errors++;
+
+    /* rx error */
+    if (!(rx_status & RX_STATUS_OK))
+    {
+        /* frame error */
+        if (rx_status & (RX_BAD_SYMBOL | RX_BAD_Align))
+        {
+            dev->stats.rx_frame_errors++;
+        }
+
+        /* long */
+        if (rx_status & (RX_RUNT | RX_TOO_LONG))
+        {
+            dev->stats.rx_length_errors++;
+        }
+
+        /* CRC check */
+        if (rx_status & RX_CRC_ERR)
+        {
+            dev->stats.rx_crc_errors++;
+        }
+    }
+    else
+    {
+        /* receive ok, but lost */
+        dev->xstats.rx_lost_in_ring++;
+    }
+
+    /* reset receive */
+    tmp = inb(dev->iobase + CHIP_CMD);
+    outb(dev->iobase + CHIP_CMD, tmp & ~CMD_RX_ENABLE);
+    outb(dev->iobase + CHIP_CMD, tmp);
+    outl(dev->iobase + RX_CONFIG, dev->rx_config);
+    dev->current_rx = 0;
+}
+
+static void rtl8139_isr_ack(struct eth_device_rtl8139 *dev)
+{
+    rt_uint16_t status;
+
+    status = inw(dev->iobase + INTR_STATUS) & RX_ACK_BITS;
+
+    /* Clear out errors and receive interrupts */
+    if (status != 0)
+    {
+        if (status & (RX_FIFO_OVER | RX_OVERFLOW))
+        {
+            dev->stats.rx_errors++;
+            if (status & RX_FIFO_OVER)
+            {
+                dev->stats.rx_fifo_errors++;
+            }
+        }
+        /* write rx ack */
+        outw(dev->iobase + INTR_STATUS, RX_ACK_BITS);
+        inw(dev->iobase + INTR_STATUS); // for flush
+    }
+}
+
+static int rtl8139_rx_interrupt(struct eth_device_rtl8139 *dev)
+{
+    int received = 0;
+    rt_uint8_t *rx_ring = dev->rx_ring;
+    rt_uint32_t current_rx = dev->current_rx;
+    rt_uint32_t rx_size = 0;
+
+    while (!(inb(dev->iobase + CHIP_CMD) & RX_BUFFER_EMPTY))
+    {
+        rt_uint32_t ring_offset = current_rx % RX_BUF_LEN;
+        rt_uint32_t rx_status;
+
+        rt_size_t pkt_size;
+
+        rt_hw_dmb();
+
+        /* read size+status of next frame from DMA ring buffer */
+        rx_status = *(rt_uint32_t *)(rx_ring + ring_offset);
+
+        /* size on high 16 bit */
+        rx_size = rx_status >> 16;
+
+        if (!(dev->dev_flags & DEV_FLAGS_RXFCS)) {
+            pkt_size = rx_size - 4;
+        } else {
+            pkt_size = rx_size;
+        }
+
+        /* Packet copy from FIFO still in progress.
+         * Theoretically, this should never happen
+         * since early_rx is disabled.
+         */
+        if (rx_size == 0xfff0)
+        {
+            dbg_log(DBG_WARNING, "rx fifo copy in progress\n");
+            dev->xstats.early_rx++;
+            break;
+        }
+
+        /* If Rx err or invalid rx_size/rx_status received
+         * (which happens if we get lost in the ring),
+         * Rx process gets reset, so we abort any further
+         * Rx processing.
+         */
+        if ((rx_size > (MAX_ETH_FRAME_SIZE + 4) || (rx_size < 8) || (!(rx_status & RX_STATUS_OK))))
+        {
+            if ((dev->dev_flags & DEV_FLAGS_RXALL) && (rx_size <= (MAX_ETH_FRAME_SIZE + 4)) &&
+                (rx_size >= 8) && (!(rx_status & RX_STATUS_OK)))
+            {
+                dev->stats.rx_errors++;
+                if (rx_status & RX_CRC_ERR)
+                {
+                    dev->stats.rx_crc_errors++;
+                    goto keep_pkt;
+                }
+
+                if (rx_status & RX_RUNT)
+                {
+                    dev->stats.rx_length_errors++;
+                    goto keep_pkt;
+                }
+            }
+            /* rx error handle */
+            rtl8139_rx_error(rx_status, dev);
+            received = -1;
+            goto out;
+        }
+
+keep_pkt:
+        /* merge size and data into receive pkg */
+        rt_memcpy(rx_cache_send_buf, &pkt_size, 4);
+        rt_memcpy(&rx_cache_send_buf[4], &rx_ring[ring_offset + 4], pkt_size);
+
+        rt_mq_send_interrupt(dev->rx_mqueue, rx_cache_send_buf, pkt_size + 4);
+        eth_device_ready(&dev->parent); /* notify eth thread to read packet */
+
+        dev->rx_status.packets++;
+        dev->rx_status.bytes += pkt_size;
+
+        received++;
+
+        /* 4:for header length(length include 4 bytes CRC)
+         * 3:for dword alignment
+         */
+        current_rx = (current_rx + rx_size + 4 + 3) & ~3;
+        outw(dev->iobase + RX_BUF_PTR, (rt_uint16_t)(current_rx - 16));
+
+        rtl8139_isr_ack(dev);
+    }
+
+    if (!received || rx_size == 0xfff0)
+    {
+        rtl8139_isr_ack(dev);
+    }
+
+    dev->current_rx = current_rx;
+out:
+    return received;
+}
+
+static void rt_hw_rtl8139_isr(int vector, void *param)
+{
+    struct eth_device_rtl8139 *dev = GET_RTL8139(param);
+
+    rt_uint16_t status, ackstat;
+
+    int link_changed = 0; /* avoid bogus "uninit" warning */
+
+    rt_spin_lock(&dev->lock);
+
+    status = inw(dev->iobase + INTR_STATUS);
+    outw(dev->iobase + INTR_STATUS, status);
+
+    if ((status & rtl8139_intr_mask) == 0)
+    {
+        dbg_log(DBG_LOG, "no interrupt occured on me!\n");
+        rt_spin_unlock(&dev->lock);
+        return;
+    }
+
+    /* check netif state whether running. */
+    if (!dev->linked)
+    {
+        /* clear intr mask, don't receive intr forever */
+        outw(dev->iobase + INTR_MASK, 0);
+        goto out;
+    }
+
+    /* Acknowledge all of the current interrupt sources ASAP, but
+       an first get an additional status bit from CSCR. */
+    if (status & RX_UNDERRUN)
+    {
+        link_changed = inw(dev->iobase + CSCR) & CSCR_LINK_CHANGE;
+    }
+
+    ackstat = status & ~(RX_ACK_BITS | TX_ERR);
+    if (ackstat)
+    {
+        outw(dev->iobase + INTR_STATUS, ackstat);
+    }
+
+    if (status & RX_ACK_BITS)
+    {
+        rtl8139_rx_interrupt(dev);
+    }
+
+    /* Check uncommon events with one test. */
+    if (status & (PCI_ERR | PCS_TIMEOUT | RX_UNDERRUN | RX_ERR))
+    {
+        rtl8139_other_interrupt(dev, status, link_changed);
+    }
+
+    /* handle receive */
+    if (status & (TX_OK | TX_ERR))
+    {
+        rtl8139_tx_interrupt(dev);
+
+        if (status & TX_ERR)
+            outw(dev->iobase + INTR_STATUS, TX_ERR);
+    }
+out:
+    rt_spin_unlock(&dev->lock);
+}
+
+static rt_err_t rtl8139_init(rt_device_t device)
+{
+    struct eth_device_rtl8139 *dev = GET_RTL8139(device);
+
+    /* alloc transmit buffer */
+    dev->tx_buffers = (rt_uint8_t *) rt_malloc(TX_BUF_TOTAL_LEN);
+    if (dev->tx_buffers == RT_NULL)
+    {
+        LOG_E("alloc memory for rtl8139 tx buffer failed!\n");
+        return -1;
+    }
+
+    /* alloc receive buffer */
+    dev->rx_ring = (rt_uint8_t *) rt_malloc(RX_BUF_TOTAL_LEN);
+    if (dev->rx_ring == RT_NULL) {
+        LOG_E("alloc memory for rtl8139 rx buffer failed!\n");
+        rt_free(dev->tx_buffers);
+        return -1;
+    }
+
+    /* create msg queue for eth rx */
+    dev->rx_mqueue = rt_mq_create("rx_mqueue", RX_MSG_SIZE, RX_MSG_CNT, 0);
+    if (dev->rx_mqueue == RT_NULL)
+    {
+        LOG_E("crete msg queue for rx buffer failed!\n");
+        rt_free(dev->tx_buffers);
+        rt_free(dev->rx_ring);
+        return -1;
+    }
+
+    dev->tx_buffer_dma = (rt_ubase_t)rt_hw_vir2phy(dev->tx_buffers);
+    dev->rx_ring_dma = (rt_ubase_t)rt_hw_vir2phy(dev->rx_ring);
+
+    dev->tx_flags = (TX_FIFO_THRESH << 11) & 0x003f0000;
+
+    /* init tx and rx ring */
+    rtl8139_init_ring(dev);
+    rtl8139_hardware_start(dev);
+
+    dev->dev_flags = DEV_FLAGS_RXALL;
+    dev->linked = RT_TRUE;
+
+    eth_device_linkchange(&dev->parent, RT_TRUE);
+
+    if (rt_hw_interrupt_install(dev->irqno, rt_hw_rtl8139_isr, (void *) dev, "rtl8139") < 0)
+    {
+        LOG_E("install IRQ failed!\n");
+        rt_free(dev->tx_buffers);
+        rt_free(dev->rx_ring);
+        rt_mq_delete(dev->rx_mqueue);
+        return RT_ERROR;
+    }
+    rt_hw_interrupt_umask(dev->irqno);
+
+    dbg_log(DBG_INFO, "ethernet card init done.\n");
+
+    return RT_EOK;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops rtl8139_ops =
+{
+    rtl8139_init,
+    RT_NULL,
+    RT_NULL,
+    RT_NULL,
+    RT_NULL,
+    rtl8139_control
+};
+#endif
+
+static int rtl8139_get_pci(struct eth_device_rtl8139 *dev)
+{
+    /* get pci device */
+    rt_pci_device_t *pci_dev = rt_pci_device_get(RTL8139_VENDOR_ID, RTL8139_DEVICE_ID);
+    if (pci_dev == RT_NULL)
+    {
+        LOG_E("device not find on pci device.\n");
+        return -1;
+    }
+    dev->pci_dev = pci_dev;
+    dbg_log(DBG_LOG, "find device, vendor id: 0x%x, device id: 0x%x\n",
+          pci_dev->vendor_id, pci_dev->device_id);
+
+    /* enable bus mastering */
+    rt_pci_enable_bus_mastering(pci_dev);
+
+    /* get io port address */
+    dev->iobase = rt_pci_device_get_io_addr(pci_dev);
+    if (dev->iobase == 0)
+    {
+        LOG_E("invalid pci device io address.\n");
+        return -1;
+    }
+    dbg_log(DBG_LOG, "io base address: 0x%x\n", dev->iobase);
+    /* get irq */
+    dev->irqno = rt_pci_device_get_irq_line(pci_dev);
+    if (dev->irqno == 0xff)
+    {
+        LOG_E("invalid irqno.\n");
+        return -1;
+    }
+    dbg_log(DBG_LOG, "irqno %d\n", dev->irqno);
+    return 0;
+}
+
+static int rtl8139_init_board(struct eth_device_rtl8139 *dev)
+{
+    /* check for missing/broken hardware */
+    if (inl(dev->iobase + TX_CONFIG) == 0xFFFFFFFF)
+    {
+        dbg_log(DBG_ERROR, "chip not responding, ignoring board.\n");
+        return -1;
+    }
+
+    rt_uint32_t version = inl(dev->iobase + TX_CONFIG) & HW_REVID_MASK;
+    int i;
+    for (i = 0; i < CHIP_INFO_NR; i++)
+    {
+        if (version == rtl_chip_info[i].version) {
+            dev->chipset = i;
+            goto chip_match;
+        }
+    }
+
+    /* if unknown chip, assume array element #0, original RTL-8139 in this case */
+    i = 0;
+
+    dbg_log(DBG_LOG, "unknown chip version, assuming RTL-8139\n");
+    dbg_log(DBG_LOG, "TxConfig = 0x%x\n", inl(dev->iobase + TX_CONFIG));
+    dev->chipset = 0;
+
+chip_match:
+    dbg_log(DBG_LOG, "chipset id (%x) == index %d, '%s'\n",
+            version, i, rtl_chip_info[i].name);
+    /* start netcard */
+    if (dev->chipset >= CH_8139B)
+    {
+        dbg_log(DBG_WARNING, "PCI PM wakeup, not support now!\n");
+    }
+    else
+    {
+        rt_uint8_t tmp = inb(dev->iobase + CONFIG1);
+        tmp &= ~(CFG1_SLEEP | CFG1_PWRDN);
+        outb(dev->iobase + CONFIG1, tmp);
+    }
+
+    /* reset chip */
+    rtl8139_chip_reset(dev);
+    return 0;
+}
+
+static int rtl8139_init_hw(struct eth_device_rtl8139 *dev)
+{
+    rt_pci_device_t *pci_dev = dev->pci_dev;
+
+    /* check version */
+    if (pci_dev->vendor_id  == RTL8139_VENDOR_ID && pci_dev->device_id == RTL8139_DEVICE_ID &&
+        pci_dev->revision_id >= 0x20)
+    {
+        dbg_log(DBG_LOG, "This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip, use 8139cp\n",
+                pci_dev->vendor_id, pci_dev->device_id, pci_dev->revision_id);
+    }
+
+    if (rtl8139_init_board(dev) < 0)
+    {
+        return -1;
+    }
+
+    /* get MAC from pci config */
+    int i;
+    for (i = 0; i < ETH_ALEN; i++) {
+        dev->dev_addr[i] = inb(dev->iobase + MAC0 + i);
+    }
+    dbg_log(DBG_INFO, "MAC addr: %x:%x:%x:%x:%x:%x\n", dev->dev_addr[0], dev->dev_addr[1],
+            dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+    rt_spin_lock_init(&dev->lock);
+
+    /* Put the chip into low-power mode. */
+    if (rtl_chip_info[dev->chipset].flags & HAS_HLT_CLK)
+    {
+        outb(dev->iobase + HLT_CTL, 'H');   /* 'R' would leave the clock running. */
+    }
+    return 0;
+}
+
+static rt_err_t rtl8139_tx(rt_device_t device, struct pbuf *p)
+{
+    rt_err_t err = RT_EOK;
+    /* copy data from pbuf to tx cache */
+    pbuf_copy_partial(p, (void *)&tx_cache_pbuf[0], p->tot_len, 0);
+    if (rtl8139_transmit(GET_RTL8139(device), tx_cache_pbuf, p->tot_len) < 0)
+    {
+        err = RT_ERROR;
+    }
+    return err;
+}
+
+static struct pbuf *rtl8139_rx(rt_device_t device)
+{
+    struct eth_device_rtl8139 *dev = GET_RTL8139(device);
+    int recv_len = 0;
+    struct pbuf *pbuf = RT_NULL;
+    rt_err_t err;
+
+    /* get data from rx queue. */
+    err = rt_mq_recv_interruptible(dev->rx_mqueue, rx_cache_recv_buf, RX_MSG_SIZE, 0);
+    if (err != RT_EOK)
+    {
+        goto end;
+    }
+    /* get recv len from rx cache, 0~3: recv len, 3-n: frame data */
+    recv_len = *(int *)rx_cache_recv_buf;
+    if (recv_len > 0)
+    {
+        pbuf = pbuf_alloc(PBUF_LINK, recv_len, PBUF_RAM);
+        rt_memcpy(pbuf->payload, (char *)rx_cache_recv_buf + 4, recv_len);
+    }
+end:
+    return pbuf;
+}
+
+static rt_err_t rtl8139_control(rt_device_t device, int cmd, void *args)
+{
+    struct eth_device_rtl8139 *dev = GET_RTL8139(device);
+    switch(cmd)
+    {
+    case NIOCTL_GADDR:
+        /* get MAC address */
+        if(args)
+        {
+            rt_memcpy(args, dev->dev_addr, ETH_ALEN);
+        }
+        else
+        {
+            return -RT_ERROR;
+        }
+        break;
+    default :
+        break;
+    }
+    return RT_EOK;
+}
+
+static int rt_hw_rtl8139_init(void)
+{
+    rt_memset(&eth_dev, 0x0, sizeof(eth_dev));
+
+    if (rtl8139_get_pci(&eth_dev) < 0)
+    {
+        return -1;
+    }
+
+    if (rtl8139_init_hw(&eth_dev) < 0)
+    {
+        return -1;
+    }
+
+    /* set device opts */
+#ifdef RT_USING_DEVICE_OPS
+    eth_dev.parent.parent.ops        = &rtl8139_ops;
+#else
+    eth_dev.parent.parent.init       = rtl8139_init;
+    eth_dev.parent.parent.open       = RT_NULL;
+    eth_dev.parent.parent.close      = RT_NULL;
+    eth_dev.parent.parent.read       = RT_NULL;
+    eth_dev.parent.parent.write      = RT_NULL;
+    eth_dev.parent.parent.control    = rtl8139_control;
+#endif
+    eth_dev.parent.parent.user_data  = RT_NULL;
+    eth_dev.parent.eth_rx     = rtl8139_rx;
+    eth_dev.parent.eth_tx     = rtl8139_tx;
+
+    /* register ETH device */
+    if (eth_device_init(&(eth_dev.parent), DEV_NAME) != RT_EOK)
+    {
+        return -1;
+    }
+    return 0;
+}
+INIT_DEVICE_EXPORT(rt_hw_rtl8139_init);

+ 408 - 0
bsp/x86/drivers/drv_rtl8139.h

@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-08-16     JasonHu      first version
+ */
+
+#ifndef __DRV_RTL8139_H__
+#define __DRV_RTL8139_H__
+
+#include <rtdef.h>
+
+#define ETH_ALEN 6  /* MAC addr */
+#define ETH_ZLEN 60 /* Minimum length of data without CRC check */
+#define ETH_DATA_LEN 1500 /* Maximum length of data in a frame */
+#define ETH_FRAME_LEN 1514 /* Maximum Ethernet data length without CRC checksum */
+
+#define ETH_MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define RX_MSG_CNT 8  /* 4 msg queue */
+#define RX_MSG_SIZE (ETH_FRAME_LEN + 4)  /* 4 save real msg size */
+
+#define TX_CACHE_BUF_SIZE          (2048)
+
+#define DEV_FLAGS_RXALL     (1 << 0) /* receive all pkgs */
+#define DEV_FLAGS_RXFCS     (1 << 1) /* receive no crc check */
+
+/* pci device info */
+#define RTL8139_VENDOR_ID   0x10ec
+#define RTL8139_DEVICE_ID   0x8139
+
+#define RX_BUF_IDX  2   /* 32K ring */
+
+#define RX_BUF_LEN  (8192 << RX_BUF_IDX)
+#define RX_BUF_PAD  16      /* pad 16 bytes */
+#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
+
+/* The total length of the receive buffer */
+#define RX_BUF_TOTAL_LEN    (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
+
+/* Number of Tx descriptor registers. */
+#define NUM_TX_DESC 4
+
+/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE  1536
+
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE
+#define TX_BUF_TOTAL_LEN    (TX_BUF_SIZE * NUM_TX_DESC)
+
+/* PCI Tuning Parameters
+   Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH  256 /* In bytes, rounded down to 32 byte units. */
+
+/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
+#define RX_FIFO_THRESH  7   /* Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST    7   /* Maximum PCI burst, '7' is unlimited */
+#define TX_DMA_BURST    6   /* Maximum PCI burst, '6' is 1024 */
+#define TX_RETRY    8   /* 0-15.  retries = 16 + (TX_RETRY * 16) */
+
+enum
+{
+    HAS_MII_XCVR = 0x010000,
+    HAS_CHIP_XCVR = 0x020000,
+    HAS_LNK_CHNG = 0x040000,
+};
+
+#define RTL_NUM_STATS 4     /* number of ETHTOOL_GSTATS u64's */
+#define RTL_REGS_VER 1      /* version of reg. data in ETHTOOL_GREGS */
+#define RTL_MIN_IO_SIZE 0x80
+#define RTL8139B_IO_SIZE 256
+#define RTL8129_CAPS    HAS_MII_XCVR
+#define RTL8139_CAPS    (HAS_CHIP_XCVR | HAS_LNK_CHNG)
+
+/* Symbolic offsets to registers. */
+enum rtl8139_registers
+{
+    MAC0        = 0,     /* Ethernet hardware address. */
+    MAR0        = 8,     /* Multicast filter. */
+    TX_STATUS0  = 0x10,  /* Transmit status (Four 32bit registers). */
+    TX_ADDR0    = 0x20,  /* Tx descriptors (also four 32bit). */
+    RX_BUF      = 0x30,
+    CHIP_CMD    = 0x37,
+    RX_BUF_PTR  = 0x38,
+    RX_BUF_ADDR = 0x3A,
+    INTR_MASK   = 0x3C,
+    INTR_STATUS = 0x3E,
+    TX_CONFIG   = 0x40,
+    RX_CONFIG   = 0x44,
+    TIMER       = 0x48,  /* A general-purpose counter. */
+    RX_MISSED   = 0x4C,  /* 24 bits valid, write clears. */
+    CFG9346     = 0x50,
+    CONFIG0     = 0x51,
+    CONFIG1     = 0x52,
+    TIMER_INT   = 0x54,
+    MEDIA_STATUS= 0x58,
+    CONFIG3     = 0x59,
+    CONFIG4     = 0x5A,  /* absent on RTL-8139A */
+    HLT_CTL     = 0x5B,
+    MULTI_INTR  = 0x5C,
+    TX_SUMMARY  = 0x60,
+    BASIC_MODE_CTRL     = 0x62,
+    BASIC_MODE_STATUS   = 0x64,
+    NWAY_ADVERT = 0x66,
+    NWAY_LPAR   = 0x68,
+    NWAY_EXPANSION  = 0x6A,
+    /* Undocumented registers, but required for proper operation. */
+    FIFOTMS     = 0x70,  /* FIFO Control and test. */
+    CSCR        = 0x74,  /* Chip Status and Configuration Register. */
+    PARA78      = 0x78,
+    FLASH_REG   = 0xD4, /* Communication with Flash ROM, four bytes. */
+    PARA7c      = 0x7c,  /* Magic transceiver parameter register. */
+    CONFIG5     = 0xD8,  /* absent on RTL-8139A */
+};
+
+enum clear_bit_masks
+{
+    MULTI_INTR_CLEAR    = 0xF000,
+    CHIP_CMD_CLEAR  = 0xE2,
+    CONFIG1_CLEAR   = (1 <<7 ) | (1 << 6) | (1 << 3) | (1 << 2) | (1 << 1),
+};
+
+enum chip_cmd_bits
+{
+    CMD_RESET       = 0x10,
+    CMD_RX_ENABLE   = 0x08,
+    CMD_TX_ENABLE   = 0x04,
+    RX_BUFFER_EMPTY = 0x01,
+};
+
+/* Interrupt register bits, using my own meaningful names. */
+enum intr_status_bits
+{
+    PCI_ERR     = 0x8000,
+    PCS_TIMEOUT = 0x4000,
+    RX_FIFO_OVER = 0x40,
+    RX_UNDERRUN = 0x20,
+    RX_OVERFLOW = 0x10,
+    TX_ERR      = 0x08,
+    TX_OK       = 0x04,
+    RX_ERR      = 0x02,
+    RX_OK       = 0x01,
+    RX_ACK_BITS = RX_FIFO_OVER | RX_OVERFLOW | RX_OK,
+};
+
+enum tx_status_bits
+{
+    TX_HOST_OWNS    = 0x2000,
+    TX_UNDERRUN     = 0x4000,
+    TX_STAT_OK      = 0x8000,
+    TX_OUT_OF_WINDOW = 0x20000000,
+    TX_ABORTED      = 0x40000000,
+    TX_CARRIER_LOST = 0x80000000,
+};
+
+enum rx_status_bits
+{
+    RX_MULTICAST    = 0x8000,
+    RX_PHYSICAL     = 0x4000,
+    RX_BROADCAST    = 0x2000,
+    RX_BAD_SYMBOL   = 0x0020,
+    RX_RUNT         = 0x0010,
+    RX_TOO_LONG     = 0x0008,
+    RX_CRC_ERR      = 0x0004,
+    RX_BAD_Align    = 0x0002,
+    RX_STATUS_OK    = 0x0001,
+};
+
+/* Bits in rx_config. */
+enum rx_mode_bits
+{
+    ACCEPT_ERR  = 0x20,
+    ACCEPT_RUNT = 0x10,
+    ACCEPT_BROADCAST    = 0x08,
+    ACCEPT_MULTICAST    = 0x04,
+    ACCEPT_MY_PHYS  = 0x02,
+    ACCEPT_ALL_PHYS = 0x01,
+};
+
+/* Bits in TxConfig. */
+enum tx_config_bits
+{
+    /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
+    TX_IFG_SHIFT    = 24,
+    TX_IFG84        = (0 << TX_IFG_SHIFT), /* 8.4us / 840ns (10 / 100Mbps) */
+    TX_IFG88        = (1 << TX_IFG_SHIFT), /* 8.8us / 880ns (10 / 100Mbps) */
+    TX_IFG92        = (2 << TX_IFG_SHIFT), /* 9.2us / 920ns (10 / 100Mbps) */
+    TX_IFG96        = (3 << TX_IFG_SHIFT), /* 9.6us / 960ns (10 / 100Mbps) */
+
+    TX_LOOP_BACK    = (1 << 18) | (1 << 17), /* enable loopback test mode */
+    TX_CRC          = (1 << 16),    /* DISABLE Tx pkt CRC append */
+    TX_CLEAR_ABT    = (1 << 0), /* Clear abort (WO) */
+    TX_DMA_SHIFT    = 8, /* DMA burst value (0-7) is shifted X many bits */
+    TX_RETRY_SHIFT  = 4, /* TXRR value (0-15) is shifted X many bits */
+
+    TX_VERSION_MASK = 0x7C800000, /* mask out version bits 30-26, 23 */
+};
+
+/* Bits in Config1 */
+enum config1_bits
+{
+    CFG1_PM_ENABLE  = 0x01,
+    CFG1_VPD_ENABLE = 0x02,
+    CFG1_PIO    = 0x04,
+    CFG1_MMIO   = 0x08,
+    CFG1_LWAKE      = 0x10,     /* not on 8139, 8139A */
+    CFG1_DRIVER_LOAD = 0x20,
+    CFG1_LED0   = 0x40,
+    CFG1_LED1   = 0x80,
+    CFG1_SLEEP      = (1 << 1), /* only on 8139, 8139A */
+    CFG1_PWRDN      = (1 << 0), /* only on 8139, 8139A */
+};
+
+/* Bits in Config3 */
+enum config3_bits
+{
+    CFG3_FAST_ENABLE        = (1 << 0), /* 1    = Fast Back to Back */
+    CFG3_FUNCTION_ENABLE    = (1 << 1), /* 1    = enable CardBus Function registers */
+    CFG3_CLKRUN_ENABLE      = (1 << 2), /* 1    = enable CLKRUN */
+    CFG3_CARD_BUS_ENABLE    = (1 << 3), /* 1    = enable CardBus registers */
+    CFG3_LINK_UP            = (1 << 4), /* 1    = wake up on link up */
+    CFG3_MAGIC              = (1 << 5), /* 1    = wake up on Magic Packet (tm) */
+    CFG3_PARM_ENABLE        = (1 << 6), /* 0    = software can set twister parameters */
+    CFG3_GNT                = (1 << 7), /* 1    = delay 1 clock from PCI GNT signal */
+};
+
+/* Bits in Config4 */
+enum config4_bits
+{
+    CFG4_LWPTN  = (1 << 2), /* not on 8139, 8139A */
+};
+
+/* Bits in Config5 */
+enum config5_bits
+{
+    Cfg5_PME_STS    = (1 << 0), /* 1    = PCI reset resets PME_Status */
+    Cfg5_LANWake    = (1 << 1), /* 1    = enable LANWake signal */
+    Cfg5_LDPS       = (1 << 2), /* 0    = save power when link is down */
+    Cfg5_FIFOAddrPtr= (1 << 3), /* Realtek internal SRAM testing */
+    Cfg5_UWF        = (1 << 4), /* 1 = accept unicast wakeup frame */
+    Cfg5_MWF        = (1 << 5), /* 1 = accept multicast wakeup frame */
+    Cfg5_BWF        = (1 << 6), /* 1 = accept broadcast wakeup frame */
+};
+
+enum rx_config_bits
+{
+    /* rx fifo threshold */
+    RX_CFG_FIFO_SHIFT   = 13,
+    RX_CFG_FIFO_NONE    = (7 << RX_CFG_FIFO_SHIFT),
+
+    /* Max DMA burst */
+    RX_CFG_DMA_SHIFT    = 8,
+    RX_CFG_DMA_UNLIMITED = (7 << RX_CFG_DMA_SHIFT),
+
+    /* rx ring buffer length */
+    RX_CFG_RCV_8K   = 0,
+    RX_CFG_RCV_16K  = (1 << 11),
+    RX_CFG_RCV_32K  = (1 << 12),
+    RX_CFG_RCV_64K  = (1 << 11) | (1 << 12),
+
+    /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
+    RX_NO_WRAP  = (1 << 7),
+};
+
+/* Twister tuning parameters from RealTek.
+   Completely undocumented, but required to tune bad links on some boards. */
+enum cscr_bits
+{
+    CSCR_LINK_OK        = 0x0400,
+    CSCR_LINK_CHANGE    = 0x0800,
+    CSCR_LINK_STATUS    = 0x0f000,
+    CSCR_LINK_DOWN_OFF_CMD  = 0x003c0,
+    CSCR_LINK_DOWN_CMD  = 0x0f3c0,
+};
+
+enum config9346_bits
+{
+    CFG9346_LOCK    = 0x00,
+    CFG9346_UNLOCK  = 0xC0,
+};
+
+typedef enum {
+    CH_8139 = 0,
+    CH_8139_K,
+    CH_8139A,
+    CH_8139A_G,
+    CH_8139B,
+    CH_8130,
+    CH_8139C,
+    CH_8100,
+    CH_8100B_8139D,
+    CH_8101,
+} card_chip_t;
+
+enum chip_flags {
+    HAS_HLT_CLK = (1 << 0),
+    HAS_LWAKE   = (1 << 1),
+};
+
+#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
+        ((b30) << 30 | (b29) << 29 | (b28) << 28 | (b27) << 27 | (b26) << 26 | (b23) << 23 | (b22) << 22)
+#define HW_REVID_MASK   HW_REVID(1, 1, 1, 1, 1, 1, 1)
+
+#define CHIP_INFO_NR    10
+
+/* directly indexed by chip_t, above */
+static const struct
+{
+    const char *name;
+    rt_uint32_t version; /* from RTL8139C/RTL8139D docs */
+    rt_uint32_t flags;
+} rtl_chip_info[CHIP_INFO_NR] = {
+    { "RTL-8139",
+      HW_REVID(1, 0, 0, 0, 0, 0, 0),
+      HAS_HLT_CLK,
+    },
+    { "RTL-8139 rev K",
+      HW_REVID(1, 1, 0, 0, 0, 0, 0),
+      HAS_HLT_CLK,
+    },
+    { "RTL-8139A",
+      HW_REVID(1, 1, 1, 0, 0, 0, 0),
+      HAS_HLT_CLK, /* XXX undocumented? */
+    },
+    { "RTL-8139A rev G",
+      HW_REVID(1, 1, 1, 0, 0, 1, 0),
+      HAS_HLT_CLK, /* XXX undocumented? */
+    },
+    { "RTL-8139B",
+      HW_REVID(1, 1, 1, 1, 0, 0, 0),
+      HAS_LWAKE,
+    },
+    { "RTL-8130",
+      HW_REVID(1, 1, 1, 1, 1, 0, 0),
+      HAS_LWAKE,
+    },
+    { "RTL-8139C",
+      HW_REVID(1, 1, 1, 0, 1, 0, 0),
+      HAS_LWAKE,
+    },
+    { "RTL-8100",
+      HW_REVID(1, 1, 1, 1, 0, 1, 0),
+      HAS_LWAKE,
+    },
+    { "RTL-8100B/8139D",
+      HW_REVID(1, 1, 1, 0, 1, 0, 1),
+      HAS_HLT_CLK /* XXX undocumented? */ | HAS_LWAKE,
+    },
+    { "RTL-8101",
+      HW_REVID(1, 1, 1, 0, 1, 1, 1),
+      HAS_LWAKE,
+    }
+};
+
+struct rtl8139_status
+{
+    rt_ubase_t packets;
+    rt_ubase_t bytes;
+};
+
+/* rx config */
+static const rt_uint32_t rtl8139_rx_config = RX_CFG_RCV_32K | RX_NO_WRAP |
+    (RX_FIFO_THRESH << RX_CFG_FIFO_SHIFT) |
+    (RX_DMA_BURST << RX_CFG_DMA_SHIFT);
+
+/* tx config */
+static const rt_uint32_t rtl8139_tx_config = TX_IFG96 | (TX_DMA_BURST << TX_DMA_SHIFT) |
+    (TX_RETRY << TX_RETRY_SHIFT);
+
+/* intr mask, 1: receive, 0: ignore */
+static const rt_uint16_t rtl8139_intr_mask = PCI_ERR | PCS_TIMEOUT | RX_UNDERRUN | RX_OVERFLOW | RX_FIFO_OVER |
+    TX_ERR | TX_OK | RX_ERR | RX_OK;
+
+struct net_device_status
+{
+    rt_ubase_t tx_errors;
+    rt_ubase_t tx_aborted_errors;
+    rt_ubase_t tx_carrier_errors;
+    rt_ubase_t tx_window_errors;
+    rt_ubase_t tx_fifo_errors;
+    rt_ubase_t tx_dropped;
+
+    rt_ubase_t rx_errors;
+    rt_ubase_t rx_length_errors;
+    rt_ubase_t rx_missed_errors;
+    rt_ubase_t rx_fifo_errors;
+    rt_ubase_t rx_crc_errors;
+    rt_ubase_t rx_frame_errors;
+    rt_ubase_t rx_dropped;
+
+    rt_ubase_t tx_packets;
+    rt_ubase_t tx_bytes;
+
+    rt_ubase_t collisions;
+};
+
+struct rtl_extra_status
+{
+    rt_ubase_t early_rx;
+    rt_ubase_t tx_buf_mapped;
+    rt_ubase_t tx_timeouts;
+    rt_ubase_t rx_lost_in_ring;
+};
+
+#endif  /* __DRV_RTL8139_H__ */

+ 2 - 2
bsp/x86/drivers/drv_uart.c

@@ -27,7 +27,7 @@ struct hw_uart_device
     rt_uint16_t divisor_high_reg;
     rt_uint16_t intr_indenty_reg;
     rt_uint16_t fifo_reg;
-    rt_uint16_t line_ctrl_reg; 
+    rt_uint16_t line_ctrl_reg;
     rt_uint16_t modem_ctrl_reg;
     rt_uint16_t line_status_reg;
     rt_uint16_t modem_status_reg;
@@ -266,7 +266,7 @@ static void do_uart_init(char *name, struct hw_uart_device *uart, struct rt_seri
 
     /*
      * Set FIFO, open FIFO, clear receive FIFO, clear transmit FIFO Open 64Byte FIFO,
-     * interrupt trigger level is 14Byte 
+     * interrupt trigger level is 14Byte
      */
     outb(uart->fifo_reg, FIFO_ENABLE | FIFO_CLEAR_TRANSMIT |
         FIFO_CLEAR_RECEIVE | FIFO_ENABLE_64 |

+ 1 - 1
bsp/x86/drivers/pci.h

@@ -72,7 +72,7 @@ typedef struct rt_pci_device_id rt_pci_device_id_t;
 struct rt_pci_device_bar
 {
     rt_uint32_t type;          /* Type of address bar (IO address/MEM address) */
-    rt_uint32_t base_addr;     
+    rt_uint32_t base_addr;
     rt_uint32_t length;        /* Length of address */
 };
 typedef struct rt_pci_device_bar rt_pci_device_bar_t;

+ 61 - 0
bsp/x86/rtconfig.h

@@ -12,6 +12,7 @@
 #define RT_THREAD_PRIORITY_32
 #define RT_THREAD_PRIORITY_MAX 32
 #define RT_TICK_PER_SECOND 100
+#define RT_USING_OVERFLOW_CHECK
 #define RT_USING_HOOK
 #define RT_USING_IDLE_HOOK
 #define RT_IDLE_HOOK_LIST_SIZE 4
@@ -98,6 +99,9 @@
 
 #define RT_USING_DEVICE_IPC
 #define RT_PIPE_BUFSZ 512
+#define RT_USING_SYSTEM_WORKQUEUE
+#define RT_SYSTEM_WORKQUEUE_STACKSIZE 4096
+#define RT_SYSTEM_WORKQUEUE_PRIORITY 23
 #define RT_USING_SERIAL
 #define RT_SERIAL_RB_BUFSZ 64
 
@@ -115,12 +119,69 @@
 
 /* Socket abstraction layer */
 
+#define RT_USING_SAL
+
+/* protocol stack implement */
+
+#define SAL_USING_LWIP
+#define SAL_USING_POSIX
 
 /* Network interface device */
 
+#define RT_USING_NETDEV
+#define NETDEV_USING_IFCONFIG
+#define NETDEV_USING_PING
+#define NETDEV_USING_NETSTAT
+#define NETDEV_USING_AUTO_DEFAULT
+#define NETDEV_USING_IPV6
+#define NETDEV_IPV4 1
+#define NETDEV_IPV6 1
+#define NETDEV_IPV6_SCOPES
 
 /* light weight TCP/IP stack */
 
+#define RT_USING_LWIP
+#define RT_USING_LWIP212
+#define RT_USING_LWIP_IPV6
+#define RT_LWIP_MEM_ALIGNMENT 4
+#define RT_LWIP_IGMP
+#define RT_LWIP_ICMP
+#define RT_LWIP_DNS
+#define RT_LWIP_DHCP
+#define IP_SOF_BROADCAST 1
+#define IP_SOF_BROADCAST_RECV 1
+
+/* Static IPv4 Address */
+
+#define RT_LWIP_IPADDR "192.168.1.30"
+#define RT_LWIP_GWADDR "192.168.1.1"
+#define RT_LWIP_MSKADDR "255.255.255.0"
+#define RT_LWIP_UDP
+#define RT_LWIP_TCP
+#define RT_LWIP_RAW
+#define RT_MEMP_NUM_NETCONN 8
+#define RT_LWIP_PBUF_NUM 16
+#define RT_LWIP_RAW_PCB_NUM 4
+#define RT_LWIP_UDP_PCB_NUM 4
+#define RT_LWIP_TCP_PCB_NUM 4
+#define RT_LWIP_TCP_SEG_NUM 40
+#define RT_LWIP_TCP_SND_BUF 8196
+#define RT_LWIP_TCP_WND 8196
+#define RT_LWIP_TCPTHREAD_PRIORITY 10
+#define RT_LWIP_TCPTHREAD_MBOX_SIZE 8
+#define RT_LWIP_TCPTHREAD_STACKSIZE 2048
+#define RT_LWIP_ETHTHREAD_PRIORITY 12
+#define RT_LWIP_ETHTHREAD_STACKSIZE 2048
+#define RT_LWIP_ETHTHREAD_MBOX_SIZE 8
+#define LWIP_NETIF_STATUS_CALLBACK 1
+#define LWIP_NETIF_LINK_CALLBACK 1
+#define SO_REUSE 1
+#define LWIP_SO_RCVTIMEO 1
+#define LWIP_SO_SNDTIMEO 1
+#define LWIP_SO_RCVBUF 1
+#define LWIP_SO_LINGER 0
+#define LWIP_NETIF_LOOPBACK 0
+#define RT_LWIP_USING_PING
 
 /* AT commands */
 

+ 2 - 2
bsp/x86/rtconfig.py

@@ -53,8 +53,8 @@ if PLATFORM == 'gcc':
     else:
         EXT_CFLAGS = ''
 
-    CFLAGS = DEVICE + ' -Wall'  + EXT_CFLAGS
-    AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp'
+    CFLAGS = DEVICE + ' -Wall' + EXT_CFLAGS
+    AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -I.'
 
     if LIBC_MODE == 'debug':
         EXT_LFLAGS = ' -nostdlib'

+ 3 - 2
libcpu/x86/i386/cpuport.c

@@ -54,7 +54,8 @@ static void rt_hw_thread_entry(hw_thread_func_t function, void *arg, void (*texi
         texit();
     dbg_log(DBG_ERROR, "rt thread execute done, should never be here!");
     for (;;)
-        ;
+    {
+    }
 }
 
 rt_uint8_t *rt_hw_stack_init(void       *tentry,
@@ -132,7 +133,7 @@ void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to, rt_thread_t
 
     rt_interrupt_to_thread = to;
     rt_thread_switch_interrupt_flag = 1;
-    return ;
+    return;
 }
 
 void rt_hw_cpu_shutdown()

+ 19 - 10
libcpu/x86/i386/interrupt.c

@@ -31,21 +31,29 @@ enum HW_EXCEPTION_TYPE
     HW_EXCEPT_BREAKPOINT,                          /* Debug breakpoint: instruction INT3 */
     HW_EXCEPT_OVERFLOW,                            /* Overflow: instruction INTO */
     HW_EXCEPT_BOUND_RANGE,                         /* Out of bounds: command BOUND */
-    HW_EXCEPT_INVALID_OPCODE,                      /* Invalid (undefined) opcode: instruction UD2 or invalid instruction */
-    HW_EXCEPT_DEVICE_NOT_AVAILABLE,                /* Device unavailable (no math processor): floating point or WAIT/FWAIT instructions */
-    HW_EXCEPT_DOUBLE_FAULT,                        /* Double error: all instructions that can generate an exception or NMI or INTR */
-    HW_EXCEPT_COPROCESSOR_SEGMENT_OVERRUN,         /* Assist the processor segment to cross the boundary: floating-point instructions 
-                                                      (IA32 processors after 386 no longer generate such exceptions) */
+    HW_EXCEPT_INVALID_OPCODE,                      /* Invalid (undefined) opcode: 
+                                                      instruction UD2 or invalid instruction */
+    HW_EXCEPT_DEVICE_NOT_AVAILABLE,                /* Device unavailable (no math processor): 
+                                                      floating point or WAIT/FWAIT instructions */
+    HW_EXCEPT_DOUBLE_FAULT,                        /* Double error: all instructions that can generate an exception 
+                                                      or NMI or INTR */
+    HW_EXCEPT_COPROCESSOR_SEGMENT_OVERRUN,         /* Assist the processor segment to cross the boundary: 
+                                                      floating-point instructions (IA32 processors after 386 
+                                                      no longer generate such exceptions) */
     HW_EXCEPT_INVALID_TSS,                         /* Invalid TSS: When switching tasks or accessing TSS */
-    HW_EXCEPT_SEGMENT_NOT_PRESENT,                 /* Segment does not exist: when loading segment registers or accessing system segments */
+    HW_EXCEPT_SEGMENT_NOT_PRESENT,                 /* Segment does not exist: when loading segment registers 
+                                                      or accessing system segments */
     HW_EXCEPT_STACK_FAULT,                         /* Stack segmentation error: stack operation or loading SS */
     HW_EXCEPT_GENERAL_PROTECTION,                  /* General protection error: memory or other protection check */
     HW_EXCEPT_PAGE_FAULT,                          /* Page fault: memory access */
     HW_EXCEPT_RESERVED,                            /* INTEL reserved, not used */
-    HW_EXCEPT_X87_FLOAT_POINT,                     /* X87FPU floating point error (math error): X87FPU floating point instruction or WAIT/FWAIIT instruction */
+    HW_EXCEPT_X87_FLOAT_POINT,                     /* X87FPU floating point error (math error): 
+                                                      X87FPU floating point instruction or WAIT/FWAIIT instruction */
     HW_EXCEPT_ALIGNMENT_CHECK,                     /* Alignment check: data access in memory (supported from 486) */
-    HW_EXCEPT_MACHINE_CHECK,                       /* Machine Check: The error code (if any) and source depend on the specific mode (Pentium CPU starts to support) */
-    HW_EXCEPT_SIMD_FLOAT_POINT,                    /* SIMD floating-point exceptions: SSE and SSE2 floating-point instructions (supported by Pentium III) */
+    HW_EXCEPT_MACHINE_CHECK,                       /* Machine Check: The error code (if any) and source 
+                                                      depend on the specific mode (Pentium CPU starts to support) */
+    HW_EXCEPT_SIMD_FLOAT_POINT,                    /* SIMD floating-point exceptions: SSE and SSE2 floating-point 
+                                                      instructions (supported by Pentium III) */
 };
 
 typedef void (*rt_hw_intr_handler_t)(rt_hw_stack_frame_t *);
@@ -188,7 +196,8 @@ static void hw_exception_handler(rt_hw_stack_frame_t *frame)
     /* unhandled exception */
     rt_hw_interrupt_disable();
     for (;;)
-        ;
+    {
+    }
 }
 
 rt_base_t rt_hw_interrupt_disable(void)

+ 13 - 5
libcpu/x86/i386/syscall_c.c

@@ -43,7 +43,9 @@ void rt_hw_syscall_dispath(struct rt_hw_stack_frame *frame)
 #ifdef RT_USING_SIGNALS
         lwp_thread_kill(rt_thread_self(), SIGSYS);
 #else
-        while(1);
+        for(;;)
+        {
+        }
 #endif
     }
 
@@ -53,7 +55,9 @@ void rt_hw_syscall_dispath(struct rt_hw_stack_frame *frame)
 #ifdef RT_USING_SIGNALS
         lwp_thread_kill(rt_thread_self(), SIGSYS);
 #else
-        while(1);
+        for(;;)
+        {
+        }
 #endif
     }
 
@@ -69,15 +73,19 @@ void rt_hw_syscall_dispath(struct rt_hw_stack_frame *frame)
 
     if(syscallfunc == RT_NULL)
     {
-        dbg_log(DBG_ERROR, "[syscall] thread %s called unsupported syscall %d!\n", rt_thread_self()->name, frame->eax);
+        dbg_log(DBG_ERROR, "[syscall] thread %s called unsupported syscall %d!\n",
+            rt_thread_self()->name, frame->eax);
 #ifdef RT_USING_SIGNALS
         lwp_thread_kill(rt_thread_self(), SIGSYS);
 #else
-        while(1);
+        for(;;)
+        {
+        }
 #endif
     }
     /* TODO: support arg6 */
-    LOG_I("\033[36msyscall id = %d,arg0 = 0x%p,arg1 = 0x%p,arg2 = 0x%p,arg3 = 0x%p,arg4 = 0x%p,arg5 = 0x%p,arg6 = 0x%p(unsupport)\n\033[37m",
+    LOG_I("\033[36msyscall id = %d,arg0 = 0x%p,arg1 = 0x%p,arg2 = 0x%p,arg3 = 0x%p,arg4 = 0x%p,"
+          "arg5 = 0x%p,arg6 = 0x%p(unsupport)\n\033[37m",
         frame->eax, frame->ebx, frame->ecx, frame->edx, frame->esi, frame->edi, frame->ebp, 0);
     frame->eax = syscallfunc(frame->ebx, frame->ecx, frame->edx, frame->esi, frame->edi, frame->ebp, 0);
     LOG_I("\033[36msyscall deal ok,ret = 0x%p\n\033[37m",frame->eax);