Просмотр исходного кода

!313 为x86添加pcnet32网卡支持
Merge pull request !313 from 胡自成/rt-smart-x86

bernard 4 лет назад
Родитель
Сommit
429da3589d

+ 24 - 18
bsp/x86/.config

@@ -416,6 +416,7 @@ CONFIG_LWP_TID_MAX_NR=64
 # CONFIG_PKG_USING_LUA is not set
 # CONFIG_PKG_USING_JERRYSCRIPT is not set
 # CONFIG_PKG_USING_MICROPYTHON is not set
+# CONFIG_PKG_USING_PIKASCRIPT is not set
 
 #
 # multimedia packages
@@ -526,6 +527,7 @@ CONFIG_LWP_TID_MAX_NR=64
 # CONFIG_PKG_USING_LPM is not set
 # CONFIG_PKG_USING_TLSF is not set
 # CONFIG_PKG_USING_EVENT_RECORDER is not set
+# CONFIG_PKG_USING_ARM_2D is not set
 
 #
 # peripheral libraries and drivers
@@ -597,6 +599,7 @@ CONFIG_LWP_TID_MAX_NR=64
 # CONFIG_PKG_USING_ROSSERIAL is not set
 # CONFIG_PKG_USING_MICRO_ROS is not set
 # CONFIG_PKG_USING_MCP23008 is not set
+# CONFIG_PKG_USING_BLUETRUM_SDK is not set
 
 #
 # AI packages
@@ -614,6 +617,27 @@ CONFIG_LWP_TID_MAX_NR=64
 #
 # miscellaneous packages
 #
+
+#
+# samples: kernel and components samples
+#
+# CONFIG_PKG_USING_KERNEL_SAMPLES is not set
+# CONFIG_PKG_USING_FILESYSTEM_SAMPLES is not set
+# CONFIG_PKG_USING_NETWORK_SAMPLES is not set
+# CONFIG_PKG_USING_PERIPHERAL_SAMPLES is not set
+
+#
+# entertainment: terminal games and other interesting software packages
+#
+# CONFIG_PKG_USING_CMATRIX is not set
+# CONFIG_PKG_USING_SL is not set
+# CONFIG_PKG_USING_CAL is not set
+# CONFIG_PKG_USING_ACLOCK is not set
+# CONFIG_PKG_USING_THREES is not set
+# CONFIG_PKG_USING_2048 is not set
+# CONFIG_PKG_USING_SNAKE is not set
+# CONFIG_PKG_USING_TETRIS is not set
+# CONFIG_PKG_USING_DONUT is not set
 # CONFIG_PKG_USING_LIBCSV is not set
 # CONFIG_PKG_USING_OPTPARSE is not set
 # CONFIG_PKG_USING_FASTLZ is not set
@@ -631,14 +655,6 @@ CONFIG_LWP_TID_MAX_NR=64
 # CONFIG_PKG_USING_DIGITALCTRL is not set
 # CONFIG_PKG_USING_UPACKER is not set
 # CONFIG_PKG_USING_UPARAM is not set
-
-#
-# samples: kernel and components samples
-#
-# CONFIG_PKG_USING_KERNEL_SAMPLES is not set
-# CONFIG_PKG_USING_FILESYSTEM_SAMPLES is not set
-# CONFIG_PKG_USING_NETWORK_SAMPLES is not set
-# CONFIG_PKG_USING_PERIPHERAL_SAMPLES is not set
 # CONFIG_PKG_USING_HELLO is not set
 # CONFIG_PKG_USING_VI is not set
 # CONFIG_PKG_USING_KI is not set
@@ -646,16 +662,6 @@ CONFIG_LWP_TID_MAX_NR=64
 # CONFIG_PKG_USING_VT100 is not set
 # CONFIG_PKG_USING_UKAL is not set
 # CONFIG_PKG_USING_CRCLIB is not set
-
-#
-# entertainment: terminal games and other interesting software packages
-#
-# CONFIG_PKG_USING_THREES is not set
-# CONFIG_PKG_USING_2048 is not set
-# CONFIG_PKG_USING_SNAKE is not set
-# CONFIG_PKG_USING_TETRIS is not set
-# CONFIG_PKG_USING_DONUT is not set
-# CONFIG_PKG_USING_ACLOCK is not set
 # CONFIG_PKG_USING_LWGPS is not set
 # CONFIG_PKG_USING_STATE_MACHINE is not set
 # CONFIG_PKG_USING_MCURSES is not set

+ 3 - 1
bsp/x86/Makefile

@@ -21,7 +21,9 @@ QEMU_WINDOW ?= n
 
 # config netcard ? (y/n)
 QEMU_NETCARD ?= y
-QEMU_NETCARD_NAME ?=rtl8139
+
+# netcard name: rtl8139/pcnet
+QEMU_NETCARD_NAME ?=pcnet
 
 # netcard type: tap/user
 QEMU_NET_MODE ?=user

+ 670 - 0
bsp/x86/drivers/drv_pcnet32.c

@@ -0,0 +1,670 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-08-19     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 "PCNET32"
+#include <rtdbg.h>
+
+#include "drv_pcnet32.h"
+
+#define DEV_NAME "e0"
+
+#define GET_PCNET32(eth)    (struct eth_device_pcnet32 *)(eth)
+
+/**
+ * rx ring desc struct
+ */
+struct pcnet32_rx_desc
+{
+    rt_uint32_t base;   /* buffer base addr */
+    rt_uint16_t buf_length; /* two`s complement of length */
+    rt_uint16_t status; /* desc status */
+    rt_uint16_t msg_length; /*  Message Byte Count is the length in bytes of the received message. */
+    rt_uint16_t rpc_rcc;
+    rt_uint32_t reserved;
+} __attribute__ ((packed));
+
+/**
+ * tx ring desc struct
+ */
+struct pcnet32_tx_desc
+{
+    rt_uint32_t base;   /* buffer base addr */
+    rt_uint16_t buf_length; /* two`s complement of length */
+    rt_uint16_t status; /* desc status */
+    rt_uint32_t misc;
+    rt_uint32_t reserved;
+} __attribute__ ((packed));
+
+/**
+ * The PCNET32 32-Bit initialization block, described in databook.
+ * The Mode Register (CSR15) allows alteration of the chip's operating
+ * parameters. The Mode field of the Initialization Block is copied directly
+ * into CSR15. Normal operation is the result of configuring the Mode field
+ * with all bits zero.
+ */
+struct pcnet32_init_block
+{
+    rt_uint16_t mode;
+    rt_uint16_t tlen_rlen;
+    rt_uint8_t  phys_addr[6];
+    rt_uint16_t reserved;
+    rt_uint32_t filter[2];
+    /* Receive and transmit ring base, along with extra bits. */
+    rt_uint32_t rx_ring;
+    rt_uint32_t tx_ring;
+} __attribute__ ((packed));
+
+struct eth_device_pcnet32
+{
+    /* 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 */
+
+    rt_mq_t rx_mqueue;  /* msg queue for rx */
+
+    struct pcnet32_init_block *init_block;
+
+    rt_uint16_t rx_len_bits;
+    rt_uint16_t tx_len_bits;
+
+    rt_ubase_t rx_ring_dma_addr;
+    rt_ubase_t tx_ring_dma_addr;
+
+    rt_ubase_t init_block_dma_addr;
+
+    rt_ubase_t rx_buffer_ptr;
+    rt_ubase_t tx_buffer_ptr;  /* pointers to transmit/receive buffers */
+
+    rt_size_t rx_buffer_count;   /* total number of receive buffers */
+    rt_size_t tx_buffer_count;   /* total number of transmit buffers */
+
+    rt_size_t buffer_size;  /* length of each packet buffer */
+
+    rt_size_t de_size;    /* length of descriptor entry */
+
+    struct pcnet32_rx_desc *rdes;   /* pointer to ring buffer of receive des */
+    struct pcnet32_tx_desc *tdes;   /* pointer to ring buffer of transmit des */
+
+    rt_uint32_t rx_buffers; /* physical address of actual receive buffers (< 4 GiB) */
+    rt_uint32_t tx_buffers; /* physical address of actual transmit buffers (< 4 GiB) */
+};
+static struct eth_device_pcnet32 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 */
+
+/**
+ * does the driver own the particular buffer?
+ */
+rt_inline rt_bool_t pcnet32_is_driver_own(struct eth_device_pcnet32 *dev, rt_bool_t is_tx, rt_uint32_t idx)
+{
+    return (rt_bool_t)(is_tx ? ((dev->tdes[idx].status & PCNET32_DESC_STATUS_OWN) == 0) :
+                   ((dev->rdes[idx].status & PCNET32_DESC_STATUS_OWN) == 0));
+}
+
+/*
+ * get the next desc buffer index
+ */
+rt_inline rt_uint32_t pcnet32_get_next_desc(struct eth_device_pcnet32 *dev, rt_uint32_t cur_idx, rt_uint32_t buf_count)
+{
+    return (cur_idx + 1) % buf_count;
+}
+
+static void pcnet32_init_rx_desc_entry(struct eth_device_pcnet32 *dev, rt_uint32_t idx)
+{
+    struct pcnet32_rx_desc *des = dev->rdes + idx;
+    rt_memset(des, 0, dev->de_size);
+
+    des->base = dev->rx_buffers + idx * dev->buffer_size;
+
+    /* next 2 bytes are 0xf000 OR'd with the first 12 bits of the 2s complement of the length */
+    rt_uint16_t bcnt = (rt_uint16_t)(-dev->buffer_size);
+    bcnt &= 0x0fff;
+    bcnt |= 0xf000; /* high 4 bits fixed 1 */
+    des->buf_length = bcnt;
+
+    /* finally, set ownership bit - transmit buffers are owned by us, receive buffers by the card */
+    des->status = PCNET32_DESC_STATUS_OWN;
+}
+
+static void pcnet32_init_tx_desc_entry(struct eth_device_pcnet32 *dev, rt_uint32_t idx)
+{
+    struct pcnet32_tx_desc *des = dev->tdes + idx;
+    rt_memset(des, 0, dev->de_size);
+
+    des->base = dev->tx_buffers + idx * dev->buffer_size;
+
+    /* next 2 bytes are 0xf000 OR'd with the first 12 bits of the 2s complement of the length */
+    rt_uint16_t bcnt = (rt_uint16_t)(-dev->buffer_size);
+    bcnt &= 0x0fff;
+    bcnt |= 0xf000; /* high 4 bits fixed 1 */
+    des->buf_length = bcnt;
+}
+
+static rt_uint16_t pcnet32_wio_read_mac(rt_uint32_t addr, int index)
+{
+    return inw(addr + index);
+}
+
+/*
+ * write index to RAP, read data from RDP
+ */
+static rt_uint16_t pcnet32_wio_read_csr(rt_uint32_t addr, int index)
+{
+    outw(addr + PCNET32_WIO_RAP, index);
+    return inw(addr + PCNET32_WIO_RDP);
+}
+
+/**
+ * write index to RAP, write data to RDP
+ */
+static void pcnet32_wio_write_csr(rt_uint32_t addr, int index, rt_uint16_t val)
+{
+    outw(addr + PCNET32_WIO_RAP, index);
+    outw(addr + PCNET32_WIO_RDP, val);
+}
+
+static void pcnet32_wio_write_bcr(rt_uint32_t addr, int index, rt_uint16_t val)
+{
+    outw(addr + PCNET32_WIO_RAP, index);
+    outw(addr + PCNET32_WIO_BDP, val);
+}
+
+/*
+ * Reset causes the device to cease operation and clear its internal logic.
+ */
+static void pcnet32_wio_reset(rt_uint32_t addr)
+{
+    inw(addr + PCNET32_WIO_RESET);
+}
+
+static int pcnet32_get_pci(struct eth_device_pcnet32 *dev)
+{
+    /* get pci device */
+    rt_pci_device_t *pci_dev = rt_pci_device_get(PCNET32_VENDOR_ID, PCNET32_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 pcnet32_transmit(struct eth_device_pcnet32 *dev, rt_uint8_t *buf, rt_size_t len)
+{
+    if(len > ETH_FRAME_LEN)
+    {
+        len = ETH_FRAME_LEN;
+    }
+
+    rt_uint32_t tx_retry = PCNET32_TX_RETRY;
+
+    while (tx_retry > 0)
+    {
+        /* the next available descriptor entry index is in tx_buffer_ptr */
+        if(!pcnet32_is_driver_own(dev, RT_TRUE, dev->tx_buffer_ptr))
+        {
+            /* try encourage the card to send all buffers. */
+            pcnet32_wio_write_csr(dev->iobase, CSR0, pcnet32_wio_read_csr(dev->iobase, CSR0) | CSR0_TXPOLL);
+        }
+        else
+        {
+            break;
+        }
+        --tx_retry;
+    }
+
+    if (!tx_retry)  /* retry end, no entry available */
+    {
+        dbg_log(DBG_ERROR, "transmit no available descriptor entry\n")
+        return -1;
+    }
+
+    rt_memcpy((void *)(dev->tx_buffers + dev->tx_buffer_ptr * dev->buffer_size), buf, len);
+
+    struct pcnet32_tx_desc *tdes = dev->tdes + dev->tx_buffer_ptr;
+    /**
+     * set the STP bit in the descriptor entry (signals this is the first
+     * frame in a split packet - we only support single frames)
+     */
+    tdes->status |= PCNET32_DESC_STATUS_STP;
+
+    /* similarly, set the ENP bit to state this is also the end of a packet */
+    tdes->status |= PCNET32_DESC_STATUS_ENP;
+
+    rt_uint16_t bcnt = (rt_uint16_t)(-len);
+    bcnt &= 0xfff;
+    bcnt |= 0xf000; /* high 4 bits fixed 1 */
+    tdes->buf_length = bcnt;
+
+    /* finally, flip the ownership bit back to the card */
+    tdes->status |= PCNET32_DESC_STATUS_OWN;
+
+    dev->tx_buffer_ptr = pcnet32_get_next_desc(dev, dev->tx_buffer_ptr, dev->tx_buffer_count);
+    return 0;
+}
+
+static rt_err_t pcnet32_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 (pcnet32_transmit(GET_PCNET32(device), tx_cache_pbuf, p->tot_len) < 0)
+    {
+        err = RT_ERROR;
+    }
+    return err;
+}
+
+static struct pbuf *pcnet32_rx(rt_device_t device)
+{
+    struct eth_device_pcnet32 *dev = GET_PCNET32(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)
+    {
+        return pbuf;
+    }
+    /* 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);
+    }
+    return pbuf;
+}
+
+static rt_err_t pcnet32_control(rt_device_t device, int cmd, void *args)
+{
+    struct eth_device_pcnet32 *dev = GET_PCNET32(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 void pcnet32_rx_packet(struct eth_device_pcnet32 *dev)
+{
+    while (pcnet32_is_driver_own(dev, RT_FALSE, dev->rx_buffer_ptr))
+    {
+        struct pcnet32_rx_desc *rdes = dev->rdes + dev->rx_buffer_ptr;
+        rt_uint32_t plen = rdes->msg_length; /* msg len no need to negate it unlike BCNT above */
+
+        void *pbuf = (void *)(dev->rx_buffers + dev->rx_buffer_ptr * dev->buffer_size);
+        dbg_log(DBG_LOG, "recv packet on ring %d: buf=%p, len=%d\n", dev->rx_buffer_ptr, pbuf, plen);
+        /* merge size and data into receive pkg */
+        rt_memcpy(rx_cache_send_buf, &plen, 4);
+        rt_memcpy(&rx_cache_send_buf[4], pbuf, plen);
+
+        rt_mq_send_interrupt(dev->rx_mqueue, rx_cache_send_buf, plen + 4);
+        eth_device_ready(&dev->parent); /* notify eth thread to read packet */
+
+        /* hand the buffer back to the card */
+        rdes->status = PCNET32_DESC_STATUS_OWN;
+
+        dev->rx_buffer_ptr = pcnet32_get_next_desc(dev, dev->rx_buffer_ptr, dev->rx_buffer_count);
+    }
+}
+
+static void rt_hw_pcnet32_isr(int vector, void *param)
+{
+    struct eth_device_pcnet32 *dev = GET_PCNET32(param);
+    rt_uint32_t iobase = dev->iobase;
+    rt_uint32_t csr0 = pcnet32_wio_read_csr(iobase, 0);
+
+    if (csr0 & CSR0_RINT) /* recv packet */
+    {
+        dbg_log(DBG_LOG, "RX intr occur!\n");
+        pcnet32_rx_packet(dev);
+    }
+    else if ((csr0 & CSR0_TINT))    /* packet transmitted */
+    {
+        dbg_log(DBG_LOG, "TX intr occur!\n");
+    }
+    else if ((csr0 & CSR0_IDON))
+    {
+        dbg_log(DBG_INFO, "init done\n");
+    }
+    else if ((csr0 & CSR0_MERR))
+    {
+        dbg_log(DBG_WARNING, "memory error!\n");
+    }
+    else if ((csr0 & CSR0_MISS))
+    {
+        dbg_log(DBG_WARNING, "missed frame!\n");
+    }
+    else if ((csr0 & CSR0_CERR))
+    {
+        dbg_log(DBG_WARNING, "collision error!\n");
+    }
+    else if ((csr0 & CSR0_BABL))
+    {
+        dbg_log(DBG_WARNING, "transmitter time-out error!\n");
+    }
+    else
+    {
+        dbg_log(DBG_WARNING, "unknown intr\n");
+    }
+    /* ack pcnet32 interrupt as handled */
+    pcnet32_wio_write_csr(iobase, 0, csr0);
+}
+
+static rt_err_t pcnet32_alloc_ring_buffer(struct eth_device_pcnet32 *dev)
+{
+    dev->rdes = rt_malloc_align(dev->rx_buffer_count * dev->de_size, 16);
+    if (dev->rdes == RT_NULL)
+    {
+        dbg_log(DBG_ERROR, "alloc memory for rx ring failed!");
+        return RT_ERROR;
+    }
+    dev->tdes = rt_malloc_align(dev->tx_buffer_count * dev->de_size, 16);
+    if (dev->tdes == RT_NULL)
+    {
+        dbg_log(DBG_ERROR, "alloc memory for tx ring failed!");
+        rt_free_align(dev->rdes);
+        return RT_ERROR;
+    }
+
+    dev->rx_buffers = (uint32_t)rt_malloc_align(dev->rx_buffer_count * dev->buffer_size, 16);
+    if (dev->rx_buffers == 0)
+    {
+        dbg_log(DBG_ERROR, "alloc memory for rx ring buffer failed!");
+        rt_free_align(dev->rdes);
+        rt_free_align(dev->tdes);
+        return RT_ERROR;
+    }
+
+    dev->tx_buffers = (uint32_t)rt_malloc_align(dev->tx_buffer_count * dev->buffer_size, 16);
+    if (dev->tx_buffers == 0)
+    {
+        dbg_log(DBG_ERROR, "alloc memory for tx ring buffer failed!");
+        rt_free_align(dev->rdes);
+        rt_free_align(dev->tdes);
+        rt_free_align((void *)dev->rx_buffers);
+        return RT_ERROR;
+    }
+    dbg_log(DBG_LOG, "rdes:%p tdes:%p rbuf:%p tbuf:%p\n", dev->rdes, dev->tdes, dev->rx_buffers, dev->tx_buffers);
+
+    int i = 0;
+    for (i = 0; i < dev->rx_buffer_count; i++)
+    {
+        pcnet32_init_rx_desc_entry(dev, i);
+    }
+    for (i = 0; i < dev->tx_buffer_count; i++)
+    {
+        pcnet32_init_tx_desc_entry(dev, i);
+    }
+    return RT_EOK;
+}
+
+static void pcnet32_free_ring_buffer(struct eth_device_pcnet32 *dev)
+{
+    rt_free_align(dev->rdes);
+    rt_free_align(dev->tdes);
+    rt_free_align((void *)dev->rx_buffers);
+    rt_free_align((void *)dev->tx_buffers);
+}
+
+static void pcnet32_print_init_block(struct eth_device_pcnet32 *dev)
+{
+    rt_uint32_t iobase = dev->iobase;
+
+    struct pcnet32_init_block *init_block = dev->init_block;
+    dbg_log(DBG_LOG, "============\nprint init block\n");
+    dbg_log(DBG_LOG, "mode: %x, tlen_rlen:%x\n", init_block->mode, init_block->tlen_rlen);
+    dbg_log(DBG_LOG, "mac: %x:%x:%x:%x:%x:%x\n",
+            init_block->phys_addr[0],
+            init_block->phys_addr[1],
+            init_block->phys_addr[2],
+            init_block->phys_addr[3],
+            init_block->phys_addr[4],
+            init_block->phys_addr[5]);
+    dbg_log(DBG_LOG, "filter0: %x, filter1: %x\n", init_block->filter[0], init_block->filter[1]);
+    dbg_log(DBG_LOG, "rx ring dma: %x, tx ring dma: %x\n", init_block->rx_ring, init_block->tx_ring);
+    dbg_log(DBG_LOG, "init block dma: %x\n", dev->init_block_dma_addr);
+
+    int i = 0;
+    for (; i <= 46; i++)
+    {
+        dbg_log(DBG_LOG, "csr%d=%x\n", i, pcnet32_wio_read_csr(iobase, i));
+    }
+}
+
+static rt_err_t pcnet32_init(rt_device_t device)
+{
+    struct eth_device_pcnet32 *dev = GET_PCNET32(device);
+    rt_uint32_t iobase = dev->iobase;
+
+    /* init buffer info */
+    dev->rx_buffer_ptr = 0;
+    dev->tx_buffer_ptr = 0;
+
+    dev->rx_buffer_count = PCNET32_RX_BUFFERS;
+    dev->tx_buffer_count = PCNET32_TX_BUFFERS;
+
+    dev->buffer_size = ETH_FRAME_LEN;
+    dev->de_size = PCNET32_RING_DE_SIZE;
+
+    if (pcnet32_alloc_ring_buffer(dev) != RT_EOK)
+    {
+        return RT_ERROR;
+    }
+
+    dev->rx_ring_dma_addr = (rt_ubase_t)rt_hw_vir2phy(dev->rdes);
+    dev->tx_ring_dma_addr = (rt_ubase_t)rt_hw_vir2phy(dev->tdes);
+
+    /* 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");
+        pcnet32_free_ring_buffer(dev);
+        return RT_ERROR;
+    }
+
+    /* alloc init block, must 16 bit align */
+    dev->init_block = rt_malloc_align(sizeof(struct pcnet32_init_block), 16);
+    if (dev->init_block == RT_NULL)
+    {
+        dbg_log(DBG_ERROR, "alloc memory for init block failed!");
+        rt_mq_delete(dev->rx_mqueue);
+        pcnet32_free_ring_buffer(dev);
+        return RT_ERROR;
+    }
+    dev->init_block_dma_addr = (rt_ubase_t)rt_hw_vir2phy(dev->init_block);
+
+    dbg_log(DBG_LOG, "init block addr:%p size:%d\n", dev->init_block, sizeof(struct pcnet32_init_block));
+
+    /* fill init block */
+    dev->init_block->mode = 0;
+    dev->tx_len_bits = (PCNET32_LOG_TX_BUFFERS << 4);
+    dev->rx_len_bits = (PCNET32_LOG_RX_BUFFERS << 4);
+    dev->init_block->tlen_rlen = (dev->tx_len_bits << 8) | dev->rx_len_bits;
+    int i = 0;
+    for (i = 0; i < ETH_ALEN; i++)
+    {
+        dev->init_block->phys_addr[i] = dev->dev_addr[i];
+    }
+    dev->init_block->filter[0] = 0x00000000;
+    dev->init_block->filter[1] = 0x00000000;
+    dev->init_block->rx_ring = dev->rx_ring_dma_addr;
+    dev->init_block->tx_ring = dev->tx_ring_dma_addr;
+
+    /* register init block, CSR1 save low 16 bit, CSR1 save high 16 bit */
+    pcnet32_wio_write_csr(iobase, CSR1, (dev->init_block_dma_addr & 0xffff));
+    pcnet32_wio_write_csr(iobase, CSR2, (dev->init_block_dma_addr >> 16) & 0xffff);
+
+    /* register intr */
+    if (rt_hw_interrupt_install(dev->irqno, rt_hw_pcnet32_isr, (void *) dev, "pcnet32") < 0)
+    {
+        LOG_E("install IRQ failed!\n");
+        rt_free_align(dev->init_block);
+        rt_mq_delete(dev->rx_mqueue);
+        pcnet32_free_ring_buffer(dev);
+        return RT_ERROR;
+    }
+    rt_hw_interrupt_umask(dev->irqno);
+
+    /* Start init */
+    pcnet32_wio_write_csr(iobase, CSR0, CSR0_INIT | CSR0_INTEN);
+    dbg_log(DBG_LOG, "card init done.\n");
+
+    /* add auto pad amd strip recv */
+    rt_uint16_t csr4 = pcnet32_wio_read_csr(iobase, CSR4);
+    pcnet32_wio_write_csr(iobase, CSR4, csr4 | CSR4_ASTRP_RCV | CSR4_APAD_XMT);
+
+    /* start work */
+    pcnet32_wio_write_csr(iobase, CSR0, CSR0_START | CSR0_INTEN);
+
+    pcnet32_print_init_block(dev);
+
+    eth_device_linkchange(&dev->parent, RT_TRUE);
+    return RT_EOK;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops pcnet32_ops =
+{
+    pcnet32_init,
+    RT_NULL,
+    RT_NULL,
+    RT_NULL,
+    RT_NULL,
+    pcnet32_control
+};
+#endif
+
+static rt_err_t pcnet32_init_hw(struct eth_device_pcnet32 *dev)
+{
+    rt_uint32_t iobase = dev->iobase;
+
+    /* reset card to 16 bit io mode */
+    pcnet32_wio_reset(iobase);
+
+    /* use dealy to wait reset done, at least 1 microsecond */
+    rt_thread_delay(1);
+
+    /* switch to 32 bit soft-style mode, use 32 bit struct */
+    pcnet32_wio_write_bcr(iobase, 20, 0x102);
+
+    /* stop card work */
+    pcnet32_wio_write_csr(iobase, 0, 0x4);
+
+    /* read mac addr */
+    rt_uint16_t mac0 = pcnet32_wio_read_mac(iobase, 0);
+    rt_uint16_t mac1 = pcnet32_wio_read_mac(iobase, 2);
+    rt_uint16_t mac2 = pcnet32_wio_read_mac(iobase, 4);
+
+    dev->dev_addr[0] = mac0 & 0xff;
+    dev->dev_addr[1] = (mac0 >> 8) & 0xff;
+    dev->dev_addr[2] = mac1 & 0xff;
+    dev->dev_addr[3] = (mac1 >> 8) & 0xff;
+    dev->dev_addr[4] = mac2 & 0xff;
+    dev->dev_addr[5] = (mac2 >> 8) & 0xff;
+
+    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]);
+    return RT_EOK;
+}
+
+static int rt_hw_pcnet32_init(void)
+{
+    rt_memset(&eth_dev, 0x0, sizeof(eth_dev));
+
+    if (pcnet32_get_pci(&eth_dev) < 0)
+    {
+        return -1;
+    }
+
+    if (pcnet32_init_hw(&eth_dev) != RT_EOK)
+    {
+        return -1;
+    }
+
+    /* set device opts */
+#ifdef RT_USING_DEVICE_OPS
+    eth_dev.parent.parent.ops        = &pcnet32_ops;
+#else
+    eth_dev.parent.parent.init       = pcnet32_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    = pcnet32_control;
+#endif
+    eth_dev.parent.parent.user_data  = RT_NULL;
+    eth_dev.parent.eth_rx     = pcnet32_rx;
+    eth_dev.parent.eth_tx     = pcnet32_tx;
+
+    /* register ETH device */
+    if (eth_device_init(&(eth_dev.parent), DEV_NAME) != RT_EOK)
+    {
+        return -1;
+    }
+    return 0;
+}
+INIT_DEVICE_EXPORT(rt_hw_pcnet32_init);

+ 115 - 0
bsp/x86/drivers/drv_pcnet32.h

@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-08-19     JasonHu      first version
+ */
+
+#ifndef __DRV_PCNET32_H__
+#define __DRV_PCNET32_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 1518 /* Maximum Ethernet data length */
+
+#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 JUMP_TO(label)  goto label
+
+#define PCNET32_VENDOR_ID   0x1022
+#define PCNET32_DEVICE_ID   0x2000
+
+/* Offsets from base I/O address. */
+#define PCNET32_WIO_RDP     0x10
+#define PCNET32_WIO_RAP     0x12
+#define PCNET32_WIO_RESET   0x14
+#define PCNET32_WIO_BDP     0x16
+
+#define CSR0        0
+#define CSR0_INIT   0x1
+#define CSR0_START  0x2
+#define CSR0_STOP   0x4
+#define CSR0_TXPOLL 0x8
+#define CSR0_INTEN  0x40
+#define CSR0_IDON   0x0100
+#define CSR0_NORMAL (CSR0_START | CSR0_INTEN)
+#define CSR0_TINT   0x0200  /* Transmit Interrupt */
+#define CSR0_RINT   0x0400  /* Receive Interrupt */
+#define CSR0_MERR   0x0800  /* Memory Error */
+#define CSR0_MISS   0x1000  /* Missed Frame */
+#define CSR0_CERR   0x2000  /* Collision Error */
+#define CSR0_BABL   0x4000  /* Babble is a transmitter time-out error. */
+
+/* Error is set by the ORing of BABL, CERR, MISS, and MERR.
+ * ERR remains set as long as any of the error flags are true.
+ */
+#define CSR0_ERR   0x8000
+
+#define CSR1        1
+#define CSR2        2
+#define CSR3        3   /*  Interrupt Masks and Deferral Control */
+#define CSR3_IDONM  (1 << 8)   /* Initialization Done Mask. */
+#define CSR4        4   /* Test and Features Control */
+#define CSR4_ASTRP_RCV  (1 << 10)   /* Auto Strip Receive */
+#define CSR4_APAD_XMT   (1 << 11)   /* Auto Pad Transmit */
+
+#define CSR5        5
+#define CSR5_SUSPEND    0x0001
+#define CSR6        6   /* RX/TX Descriptor Table Length */
+
+#define CSR15       15  /* Mode */
+#define CSR18       18  /* Current Receive Buffer Address Lower */
+#define CSR19       19  /* Current Receive Buffer Address Upper */
+#define CSR24       24  /* Base Address of Receive Descriptor Ring Lower */
+#define CSR25       25  /* Base Address of Receive Descriptor Ring Upper */
+#define CSR30       30  /* Base Address of Transmit Descriptor Ring Lower */
+#define CSR31       31  /* Base Address of Transmit Descriptor Ring Upper */
+
+#define CSR58       58  /* Software Style */
+#define CSR58_PCNET_PCI_II   0x02
+
+#define PCNET32_INIT_LOW    1
+#define PCNET32_INIT_HIGH   2
+#define PCNET32_MC_FILTER 8   /* broadcast filter */
+
+#define CSR72       72  /* Receive Descriptor Ring Counter */
+#define CSR74       74  /* Transmit Descriptor Ring Counter */
+
+#define BCR2        2
+#define BCR2_ASEL   (1 << 1)
+
+#define PCNET32_TX_BUFFERS 8
+#define PCNET32_RX_BUFFERS 32
+#define PCNET32_LOG_TX_BUFFERS 3    /* 2^3 = 8 buffers */
+#define PCNET32_LOG_RX_BUFFERS 5    /* 2^5 = 32 buffers */
+
+#define PCNET32_RING_DE_SIZE     16
+
+#define PCNET32_TX_RETRY     10 /* tx retry counter when no available descriptor entry */
+
+#define PCNET32_DESC_STATUS_OWN 0x8000  /* card own the desc */
+
+/**
+ * End of Packet indicates that this is the last buffer used by
+ * the PCnet-PCI II controller for this frame.
+ */
+#define PCNET32_DESC_STATUS_ENP 0x0100
+
+/**
+ * Start of Packet indicates that this
+ * is the first buffer used by the
+ * PCnet-PCI II controller for this
+ * frame.
+ */
+#define PCNET32_DESC_STATUS_STP 0x0200
+
+#endif  /* __DRV_PCNET32_H__ */

+ 2 - 4
bsp/x86/drivers/drv_rtl8139.c

@@ -72,7 +72,6 @@ static rt_uint8_t rx_cache_send_buf[RX_MSG_SIZE] = {0};     /* buf for rx packet
 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 */
 
-
 /* rx config */
 static const rt_uint32_t rtl8139_rx_config = RX_CFG_RCV_32K | RX_NO_WRAP |
     (RX_FIFO_THRESH << RX_CFG_FIFO_SHIFT) |
@@ -91,7 +90,7 @@ 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)
+static 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;
@@ -829,7 +828,7 @@ static struct pbuf *rtl8139_rx(rt_device_t device)
     err = rt_mq_recv_interruptible(dev->rx_mqueue, rx_cache_recv_buf, RX_MSG_SIZE, 0);
     if (err != RT_EOK)
     {
-        JUMP_TO(end);
+        return pbuf;
     }
     /* get recv len from rx cache, 0~3: recv len, 3-n: frame data */
     recv_len = *(int *)rx_cache_recv_buf;
@@ -838,7 +837,6 @@ static struct pbuf *rtl8139_rx(rt_device_t device)
         pbuf = pbuf_alloc(PBUF_LINK, recv_len, PBUF_RAM);
         rt_memcpy(pbuf->payload, (char *)rx_cache_recv_buf + 4, recv_len);
     }
-end:
     return pbuf;
 }
 

+ 0 - 1
bsp/x86/rtconfig.h

@@ -243,7 +243,6 @@
 
 /* miscellaneous packages */
 
-
 /* samples: kernel and components samples */
 
 

+ 2 - 2
libcpu/x86/i386/mmu.h

@@ -143,7 +143,7 @@ void rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size);
 void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info,void *v_addr);
 
 /* used in kernel mmaped area */
-#define rt_hw_phy2vir(p) ((p) + KERNEL_VADDR_START)
-#define rt_hw_vir2phy(v) ((v) - KERNEL_VADDR_START)
+#define rt_hw_phy2vir(p) ((rt_ubase_t)(p) + KERNEL_VADDR_START)
+#define rt_hw_vir2phy(v) ((rt_ubase_t)(v) - KERNEL_VADDR_START)
 
 #endif