diff --git a/bsp/x86/.config b/bsp/x86/.config index 0a30bcd4f1406c99ed18d6bfb4b53e858ff5c22d..07c6bd9844f528236cdadc0a0e8128ef14472b16 100644 --- a/bsp/x86/.config +++ b/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 diff --git a/bsp/x86/Makefile b/bsp/x86/Makefile index dd5d75459944e0125ffd9158a3af30be55d95567..93522c44630278aba971c45234537465d53293e1 100644 --- a/bsp/x86/Makefile +++ b/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 \ diff --git a/bsp/x86/drivers/board.c b/bsp/x86/drivers/board.c index 6f898d83e9c794f513d70a807691d991d020c034..acb8048c98d44edefd7cb4419ceae6b784f4828d 100644 --- a/bsp/x86/drivers/board.c +++ b/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. */ diff --git a/bsp/x86/drivers/drv_rtl8139.c b/bsp/x86/drivers/drv_rtl8139.c new file mode 100644 index 0000000000000000000000000000000000000000..f8dc5eccff17599e29fddb16ab80c80ddd921f05 --- /dev/null +++ b/bsp/x86/drivers/drv_rtl8139.c @@ -0,0 +1,903 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#define DBG_LVL DBG_INFO +#define DBG_TAG "RTL8139" +#include + +#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 */ + + +/* 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; + +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) +{ + dev->current_rx = 0; + dev->current_tx = 0; + dev->dirty_tx = 0; + + /* set free counts */ + dev->tx_free_counts = NUM_TX_DESC; + + int i = 0; + for (; 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 = 0; + for (; 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; + + /* read tx status */ + int 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++; + JUMP_TO(keep_pkt); + } + + if (rx_status & RX_RUNT) + { + dev->stats.rx_length_errors++; + JUMP_TO(keep_pkt); + } + } + /* rx error handle */ + rtl8139_rx_error(rx_status, dev); + received = -1; + JUMP_TO(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); + JUMP_TO(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 = 0; + for (; i < CHIP_INFO_NR; i++) + { + if (version == rtl_chip_info[i].version) { + dev->chipset = i; + JUMP_TO(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 = 0; + for (; 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) + { + JUMP_TO(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(ð_dev, 0x0, sizeof(eth_dev)); + + if (rtl8139_get_pci(ð_dev) < 0) + { + return -1; + } + + if (rtl8139_init_hw(ð_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); diff --git a/bsp/x86/drivers/drv_rtl8139.h b/bsp/x86/drivers/drv_rtl8139.h new file mode 100644 index 0000000000000000000000000000000000000000..8e1ea5d3a566a92eeb81eedf3cca0e83dcbfe89e --- /dev/null +++ b/bsp/x86/drivers/drv_rtl8139.h @@ -0,0 +1,397 @@ +/* + * 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 + +#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) */ + +#define JUMP_TO(label) goto label + +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_LAN_WAKE = (1 << 1), /* 1 = enable LANWake signal */ + CFG5_LDPS = (1 << 2), /* 0 = save power when link is down */ + CFG5_FIFO_ADDR_PTR = (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; +}; + +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__ */ diff --git a/bsp/x86/drivers/drv_uart.c b/bsp/x86/drivers/drv_uart.c index 39f542fbfcb7c7239e4937587060dc9cdf0910f5..370f153b80570c90a65cf71b5e363c7002589faf 100644 --- a/bsp/x86/drivers/drv_uart.c +++ b/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 | diff --git a/bsp/x86/drivers/pci.h b/bsp/x86/drivers/pci.h index 6c492a61f2fef42f5edca46efd62d495eebd5093..a1ec6d28db0d909fe6a94afa1b64b17a10ddd291 100644 --- a/bsp/x86/drivers/pci.h +++ b/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; diff --git a/bsp/x86/rtconfig.h b/bsp/x86/rtconfig.h index 82fcb980e560f595147d41f837b9cf913fd5eb8d..c28059e3e6848a349040850392ba78ea66f93d31 100644 --- a/bsp/x86/rtconfig.h +++ b/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 */ diff --git a/bsp/x86/rtconfig.py b/bsp/x86/rtconfig.py index 3cd87e822bff8a462360d99bb7271834bfa1c07f..a4b6dc98851de369dac1797451d94712383d58db 100644 --- a/bsp/x86/rtconfig.py +++ b/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' diff --git a/libcpu/x86/i386/cpuport.c b/libcpu/x86/i386/cpuport.c index 3f6e296cf8666f74da5c9182099c9624fce7d058..98e55fa6f394ee86e215520264f245a47d6c8dd1 100644 --- a/libcpu/x86/i386/cpuport.c +++ b/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() diff --git a/libcpu/x86/i386/interrupt.c b/libcpu/x86/i386/interrupt.c index f499d217da1057dc51af739fe2cd7757bd126629..6f66c0daee0bc8fc81832a99c24eca649e71218f 100644 --- a/libcpu/x86/i386/interrupt.c +++ b/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) diff --git a/libcpu/x86/i386/syscall_c.c b/libcpu/x86/i386/syscall_c.c index 65c33bae3b669ab867e28d41deb6490d0671dc9b..332fb6fa967a64843c18cb5ef917dc79af7fbde3 100644 --- a/libcpu/x86/i386/syscall_c.c +++ b/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);