]> Zhao Yanbai Git Server - minix.git/commitdiff
Add the driver for VIA Technology 6105/6106S Ethernet card 67/3367/1
authorJia-Ju Bai <baijiaju1990@163.com>
Wed, 19 Oct 2016 10:11:26 +0000 (10:11 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Wed, 19 Oct 2016 19:54:58 +0000 (21:54 +0200)
Change-Id: I690c34f0a37bcbb20a5b7748e3dd315707460caf

distrib/sets/lists/minix-base/md.i386
distrib/sets/lists/minix-debug/md.i386
minix/drivers/net/Makefile
minix/drivers/net/vt6105/Makefile [new file with mode: 0755]
minix/drivers/net/vt6105/vt6105.c [new file with mode: 0644]
minix/drivers/net/vt6105/vt6105.conf [new file with mode: 0755]
minix/drivers/net/vt6105/vt6105.h [new file with mode: 0644]
minix/fs/procfs/service.c

index 3280f85f53fd2b8c5efcf98c87e4d75adcbc9549..52aa190aabb8925b396335ba57c4b31fc09ba446 100644 (file)
@@ -23,6 +23,7 @@
 ./etc/system.conf.d/vbfs                                minix-base
 ./etc/system.conf.d/vbox                                minix-base
 ./etc/system.conf.d/virtio_net                          minix-base
+./etc/system.conf.d/vt6105                              minix-base
 ./service/3c90x                                         minix-base
 ./service/acpi                                          minix-base
 ./service/ahci                                          minix-base
@@ -53,6 +54,7 @@
 ./service/vbox                                          minix-base
 ./service/virtio_blk                                    minix-base
 ./service/virtio_net                                    minix-base
+./service/vt6105                                        minix-base
 ./usr/lib/libhgfs.a                                     minix-base
 ./usr/lib/libhgfs_pic.a                                 minix-base
 ./usr/lib/libm387.a                                     minix-base
index 377a58e2c54f194af867bc3ffc5de39994189479..ee66c819ec3669f5fabb83cd9618cfe8a9eaf8f8 100644 (file)
@@ -39,6 +39,7 @@
 ./usr/libdata/debug/service/vbox.debug                  minix-debug     debug
 ./usr/libdata/debug/service/virtio_blk.debug            minix-debug     debug
 ./usr/libdata/debug/service/virtio_net.debug            minix-debug     debug
+./usr/libdata/debug/service/vt6105.debug                minix-debug     debug
 ./usr/libdata/debug/usr/lib/libm387.so.0.1.debug        minix-debug     debug
 ./usr/libdata/debug/usr/tests/minix-posix/test47.debug  minix-debug     debug
 ./usr/libdata/debug/usr/tests/minix-posix/test51.debug  minix-debug     debug
index 51cf094f040c3990fd1e052fc1a532836a774201..b8c4e479bdc39df5da79c1d821bf56611ee20d48 100644 (file)
@@ -12,6 +12,7 @@ SUBDIR+=      lance
 SUBDIR+=       rtl8139
 SUBDIR+=       rtl8169
 SUBDIR+=       virtio_net
+SUBDIR+=       vt6105
 .endif # ${MACHINE_ARCH} == "i386"
 
 .if ${MACHINE_ARCH} == "earm"
diff --git a/minix/drivers/net/vt6105/Makefile b/minix/drivers/net/vt6105/Makefile
new file mode 100755 (executable)
index 0000000..8ac4245
--- /dev/null
@@ -0,0 +1,14 @@
+# Makefile for the VIA Technology 6105/6106S Ethernet driver (vt6105)
+PROG=  vt6105
+SRCS=  vt6105.c
+
+FILES=${PROG}.conf
+FILESNAME=${PROG}
+FILESDIR= /etc/system.conf.d
+
+DPADD+=        ${LIBNETDRIVER} ${LIBSYS}
+LDADD+=        -lnetdriver -lsys
+
+CPPFLAGS+=     -I${NETBSDSRCDIR}/minix
+
+.include <minix.service.mk>
diff --git a/minix/drivers/net/vt6105/vt6105.c b/minix/drivers/net/vt6105/vt6105.c
new file mode 100644 (file)
index 0000000..92b6289
--- /dev/null
@@ -0,0 +1,807 @@
+#include "vt6105.h"
+
+/* global value */
+static vt_driver g_driver;
+static int g_instance;
+
+/* I/O function */
+static u8_t my_inb(u16_t port) {
+       u32_t value;
+       int r;
+       if ((r = sys_inb(port, &value)) != OK)
+               printf("VT6105: sys_inb failed: %d\n", r);
+       return (u8_t)value;
+}
+#define vt_inb(port, offset)   (my_inb((port) + (offset)))
+
+static u16_t my_inw(u16_t port) {
+       u32_t value;
+       int r;
+       if ((r = sys_inw(port, &value)) != OK)
+               printf("VT6105: sys_inw failed: %d\n", r);
+       return (u16_t)value;
+}
+#define vt_inw(port, offset)   (my_inw((port) + (offset)))
+
+static u32_t my_inl(u16_t port) {
+       u32_t value;
+       int r;
+       if ((r = sys_inl(port, &value)) != OK)
+               printf("VT6105: sys_inl failed: %d\n", r);
+       return value;
+}
+#define vt_inl(port, offset)   (my_inl((port) + (offset)))
+
+static void my_outb(u16_t port, u8_t value) {
+       int r;
+       if ((r = sys_outb(port, value)) != OK)
+               printf("VT6105: sys_outb failed: %d\n", r);
+}
+#define vt_outb(port, offset, value)   (my_outb((port) + (offset), (value)))
+
+static void my_outw(u16_t port, u16_t value) {
+       int r;
+       if ((r = sys_outw(port, value)) != OK)
+               printf("VT6105: sys_outw failed: %d\n", r);
+}
+#define vt_outw(port, offset, value)   (my_outw((port) + (offset), (value)))
+
+static void my_outl(u16_t port, u32_t value) {
+       int r;
+       if ((r = sys_outl(port, value)) != OK)
+               printf("VT6105: sys_outl failed: %d\n", r);
+}
+#define vt_outl(port, offset, value)   (my_outl((port) + (offset), (value)))
+
+/* driver interface */
+static int vt_init(unsigned int instance, ether_addr_t *addr);
+static void vt_stop(void);
+static void vt_mode(unsigned int mode);
+static ssize_t vt_recv(struct netdriver_data *data, size_t max);
+static int vt_send(struct netdriver_data *data, size_t size);
+static void vt_intr(unsigned int mask);
+static void vt_stat(eth_stat_t *stat);
+static void vt_alarm(clock_t stamp);
+
+static int vt_probe(vt_driver *pdev, int instance);
+static int vt_init_buf(vt_driver *pdev);
+static int vt_init_hw(vt_driver *pdev, ether_addr_t *addr);
+static void vt_reset_hw(vt_driver *pdev);
+static void vt_power_init(vt_driver *pdev);
+static void vt_conf_addr(vt_driver *pdev, ether_addr_t *addr);
+static void vt_check_link(vt_driver *pdev);
+static void vt_handler(vt_driver *pdev);
+static void vt_check_ints(vt_driver *pdev);
+
+static const struct netdriver vt_table = {
+       .ndr_init = vt_init,
+       .ndr_stop = vt_stop,
+       .ndr_mode = vt_mode,
+       .ndr_recv = vt_recv,
+       .ndr_send = vt_send,
+       .ndr_stat = vt_stat,
+       .ndr_intr = vt_intr,
+       .ndr_alarm = vt_alarm
+};
+
+int main(int argc, char *argv[]) {
+       env_setargs(argc, argv);
+       netdriver_task(&vt_table);
+}
+
+/* Initialize the driver */
+static int vt_init(unsigned int instance, ether_addr_t *addr) {
+       int ret = 0;
+
+       /* Intialize driver data structure */
+       memset(&g_driver, 0, sizeof(g_driver));
+       g_driver.vt_link = VT_LINK_UNKNOWN;
+       strcpy(g_driver.vt_name, "vt6105#0");
+       g_driver.vt_name[7] += instance;
+       g_instance = instance;
+
+       /* Probe the device */
+       if (vt_probe(&g_driver, instance)) {
+               printf("VT6105: Device is not found!\n");
+               ret = -ENODEV;
+               goto err_probe;
+       }
+
+       /* Allocate and initialize buffer */
+       if (vt_init_buf(&g_driver)) {
+               printf("VT6105: Device is not found!\n");
+               ret = -ENODEV;
+               goto err_init_buf;
+       }
+
+       /* Intialize hardware */
+       if (vt_init_hw(&g_driver, addr)) {
+               printf("VT6105: Find to initialize hardware!\n");
+               ret = -EIO;
+               goto err_init_hw;
+       }
+
+       /* Use a synchronous alarm instead of a watchdog timer */
+       sys_setalarm(sys_hz(), 0);
+
+       /* Clear send and recv flag */
+       g_driver.vt_send_flag = FALSE;
+       g_driver.vt_recv_flag = FALSE;
+
+       return 0;
+
+err_init_hw:
+       free_contig(g_driver.vt_buf, g_driver.vt_buf_size);
+err_init_buf:
+err_probe:
+       return ret;
+}
+
+/* Match the device and get base address */
+static int vt_probe(vt_driver *pdev, int instance) {
+       int devind;
+       u16_t cr, vid, did;
+       u32_t bar;
+       u8_t irq, rev;
+
+       /* Find pci device */
+       pci_init();
+       if (!pci_first_dev(&devind, &vid, &did))
+               return -EIO;
+       while (instance--) {
+               if (!pci_next_dev(&devind, &vid, &did))
+                       return -EIO;
+       }
+       pci_reserve(devind);
+
+       /* Enable bus mastering */
+       cr = pci_attr_r16(devind, PCI_CR);
+       if (!(cr & PCI_CR_MAST_EN))
+               pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN);
+
+       /* Get base address */
+       bar = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
+       if (bar < 0x400) {
+               printf("VT6105: base address is not properly configured!\n");
+               return -EIO;
+       }
+       pdev->vt_base_addr = bar;
+
+       /* Get irq number */
+       irq = pci_attr_r8(devind, PCI_ILR);
+       pdev->vt_irq = irq;
+
+       /* Get revision ID */
+       rev = pci_attr_r8(devind, PCI_REV);
+       pdev->vt_revision = rev;
+
+#ifdef VT6105_DEBUG
+       printf("VT6105: Base address is 0x%08x\n", pdev->vt_base_addr);
+       printf("VT6105: IRQ number is 0x%08x\n", pdev->vt_irq);
+       printf("VT6105: Revision ID is 0x%08x\n", pdev->vt_revision);
+#endif
+
+       return 0;
+}
+
+/* Allocate and initialize buffer */
+static int vt_init_buf(vt_driver *pdev) {
+       size_t rx_desc_size, tx_desc_size, rx_buf_size, tx_buf_size, tot_buf_size;
+       vt_desc *desc;
+       phys_bytes buf_dma, next;
+       char *buf;
+       int i;
+
+       /* Build Rx and Tx descriptor buffer */
+       rx_desc_size = VT_RX_DESC_NUM * sizeof(vt_desc);
+       tx_desc_size = VT_TX_DESC_NUM * sizeof(vt_desc);
+
+       /* Allocate Rx and Tx buffer */
+       tx_buf_size = VT_TX_BUF_SIZE;
+       if (tx_buf_size % 4)
+               tx_buf_size += 4 - (tx_buf_size % 4);
+       rx_buf_size = VT_RX_BUF_SIZE;
+       tot_buf_size = rx_desc_size + tx_desc_size;
+       tot_buf_size += VT_TX_DESC_NUM * tx_buf_size + VT_RX_DESC_NUM * rx_buf_size;
+       if (tot_buf_size % 4096)
+               tot_buf_size += 4096 - (tot_buf_size % 4096);
+
+       if (!(buf = alloc_contig(tot_buf_size, 0, &buf_dma))) {
+               printf("VT6105: Fail to allocate memory!\n");
+               return -ENOMEM;
+       }
+       pdev->vt_buf_size = tot_buf_size;
+       pdev->vt_buf = buf;
+
+       /* Rx descriptor */
+       pdev->vt_rx_desc = (vt_desc *)buf;
+       pdev->vt_rx_desc_dma = buf_dma;
+       memset(buf, 0, rx_desc_size);
+       buf += rx_desc_size;
+       buf_dma += rx_desc_size;
+
+       /* Tx descriptor */
+       pdev->vt_tx_desc = (vt_desc *)buf;
+       pdev->vt_tx_desc_dma = buf_dma;
+       memset(buf, 0, tx_desc_size);
+       buf += tx_desc_size;
+       buf_dma += tx_desc_size;
+
+       /* Rx buffer assignment */
+       desc = pdev->vt_rx_desc;
+       next = pdev->vt_rx_desc_dma;
+       for (i = 0; i < VT_RX_DESC_NUM; i++) {
+               /* Set Rx buffer */
+               pdev->vt_rx[i].buf_dma = buf_dma;
+               pdev->vt_rx[i].buf = buf;
+               buf_dma += rx_buf_size;
+               buf += rx_buf_size;
+
+               /* Set Rx descriptor */
+               desc->status = VT_DESC_OWN |
+                               ((VT_RX_BUF_SIZE << 16) & VT_DESC_RX_LENMASK);
+               desc->addr = pdev->vt_rx[i].buf_dma;
+               desc->length = VT_RX_BUF_SIZE;
+               if (i == (VT_RX_DESC_NUM - 1))
+                       desc->next_desc = pdev->vt_rx_desc_dma;
+               else {
+                       next += sizeof(vt_desc);
+                       desc->next_desc = next;
+                       desc++;
+               }
+       }
+
+       /* Tx buffer assignment */
+       desc = pdev->vt_tx_desc;
+       next = pdev->vt_tx_desc_dma;
+       for (i = 0; i < VT_TX_DESC_NUM; i++) {
+               /* Set Tx buffer */
+               pdev->vt_tx[i].busy = 0;
+               pdev->vt_tx[i].buf_dma = buf_dma;
+               pdev->vt_tx[i].buf = buf;
+               buf_dma += tx_buf_size;
+               buf += tx_buf_size;
+
+               /* Set Rx descriptor */
+               desc->addr = pdev->vt_tx[i].buf_dma;
+               desc->length = VT_TX_BUF_SIZE;
+               if (i == (VT_TX_DESC_NUM - 1))
+                       desc->next_desc = pdev->vt_tx_desc_dma;
+               else {
+                       next += sizeof(vt_desc);
+                       desc->next_desc = next;
+                       desc++;
+               }
+       }
+       pdev->vt_tx_busy_num = 0;
+       pdev->vt_tx_head = 0;
+       pdev->vt_tx_tail = 0;
+       pdev->vt_rx_head = 0;
+       pdev->vt_tx_alive = FALSE;
+
+       return 0;
+}
+
+/* Intialize hardware */
+static int vt_init_hw(vt_driver *pdev, ether_addr_t *addr) {
+       int r, ret;
+
+       /* Set the interrupt handler */
+       pdev->vt_hook = pdev->vt_irq;
+       if ((r = sys_irqsetpolicy(pdev->vt_irq, 0, &pdev->vt_hook)) != OK) {
+               printf("VT6105: Fail to set IRQ policy: %d!\n", r);
+               ret = -EFAULT;
+               goto err_irq_policy;
+       }
+
+       /* Reset hardware */
+       vt_reset_hw(pdev);
+
+       /* Enable IRQ */
+       if ((r = sys_irqenable(&pdev->vt_hook)) != OK) {
+               printf("VT6105: Fail to enable IRQ: %d!\n", r);
+               ret = -EFAULT;
+               goto err_irq_enable;
+       }
+
+       /* Configure MAC address */
+       vt_conf_addr(pdev, addr);
+
+       /* Detect link status */
+       vt_check_link(pdev);
+#ifdef VT6105_DEBUG
+       if (pdev->vt_link)
+               printf("VT6105: Link up!\n");
+       else
+               printf("VT6105: Link down!\n");
+#endif
+
+       return 0;
+
+err_irq_enable:
+err_irq_policy:
+       return ret;
+}
+
+/* Reset hardware */
+static void vt_reset_hw(vt_driver *pdev) {
+       u16_t base = pdev->vt_base_addr;
+       u8_t db;
+       u16_t dw;
+       u32_t dl;
+
+       /* Let power registers into sane state */
+       vt_power_init(pdev);
+
+       /* Reset the chip */
+       vt_outw(base, VT_REG_CR, VT_CMD_RESET);
+       vt_inb(base, VT_REG_ADDR);
+
+#ifdef VT6105_DEBUG
+       if (vt_inw(base, VT_REG_CR) & VT_CMD_RESET) {
+               vt_outb(base, VT_REG_MCR1, 0x40);
+               usleep(100000);
+               if (vt_inw(base, VT_REG_CR) & VT_CMD_RESET)
+                       printf("VT6105: Fail to completely reset!\n");
+       }
+       else
+               printf("VT6105: Reset successfully!\n");
+#endif
+
+       /* Initialize regsiters */
+       vt_outw(base, VT_REG_BCR0, 0x0006);
+       vt_outb(base, VT_REG_TCR, 0x20);        /* Tx threshold is 256 bytes */
+       vt_outb(base, VT_REG_RCR, 0x78);        /* Rx threshold is 256 bytes */
+       vt_outl(base, VT_REG_RD_BASE, pdev->vt_rx_desc_dma);    /* Set Rx descriptor base address */
+       vt_outl(base, VT_REG_TD_BASE, pdev->vt_tx_desc_dma);    /* Set Tx descriptor base address */
+
+#ifdef VT6105_DEBUG
+       dl = vt_inl(base, VT_REG_RD_BASE);
+       printf("VT6105: Rx descriptor DMA address is: 0x%08x\n", dl);
+       dl = vt_inl(base, VT_REG_TD_BASE);
+       printf("VT6105: Tx descriptor DMA address is: 0x%08x\n", dl);
+#endif
+
+       /* Enable interrupts */
+       vt_outw(base, VT_REG_IMR, 0xfeff);
+
+       /* Start the device, Rx and Tx */
+       dw = VT_CMD_START | VT_CMD_RX_ON | VT_CMD_TX_ON | VT_CMD_NO_POLL | VT_CMD_FDUPLEX;
+       vt_outw(base, VT_REG_CR, dw);
+       dw = vt_inw(base, VT_REG_CR);
+
+#ifdef VT6105_DEBUG
+       dw = vt_inw(base, VT_REG_CR);
+       printf("VT6105: Control status is 0x%04x\n", dw);
+#endif
+}
+
+/* Initialize power registers */
+static void vt_power_init(vt_driver *pdev) {
+       u8_t db, wolstat;
+       u16_t dw, base = pdev->vt_base_addr;
+       u32_t dl;
+
+       /* Make sure chip is in power state D0 */
+       db = vt_inb(base, VT_REG_STICK);
+       vt_outb(base, VT_REG_STICK, db & 0xfc);
+
+       /* Disable "force PME-enable" */
+       vt_outb(base, VT_REG_WOLC_SET, 0x80);
+
+       /* Clear power-event config bits (WOL) */
+       vt_outb(base, VT_REG_WOL_SET, 0xff);
+
+       /* Save power-event status bits */
+       wolstat = vt_inb(base, VT_REG_WOLS_SET);
+
+       /* Clear power-event status bits */
+       vt_outb(base, VT_REG_WOLS_CLR, 0xff);
+
+#ifdef VT6105_DEBUG
+       if (wolstat) {
+               char reason[50];
+               switch (wolstat) {
+                       case VT_WOL_MAGIC:
+                               strcpy(reason, "Magic packet");
+                               break;
+                       case VT_WOL_LINK_UP:
+                               strcpy(reason, "Link up");
+                               break;
+                       case VT_WOL_LINK_DOWN:
+                               strcpy(reason, "Link down");
+                               break;
+                       case VT_WOL_UCAST:
+                               strcpy(reason, "Unicast packet");
+                               break;
+                       case VT_WOL_MCAST:
+                               strcpy(reason, "Multicast/Broadcast packet");
+                               break;
+                       default:
+                               strcpy(reason, "Unknown");
+               }
+               printf("VT6105: Wake system up: %s\n", reason);
+       }
+#endif
+}
+
+static void vt_conf_addr(vt_driver *pdev, ether_addr_t *addr) {
+       u16_t dw, base = pdev->vt_base_addr;
+       int i;
+
+       for (i=0; i<6; i++)
+               addr->ea_addr[i] = vt_inb(base, VT_REG_ADDR + i);
+
+#ifdef VT6105_DEBUG
+       printf("VT6105: Ethernet address is %02x:%02x:%02x:%02x:%02x:%02x\n",
+               addr->ea_addr[0], addr->ea_addr[1], addr->ea_addr[2],
+               addr->ea_addr[3], addr->ea_addr[4], addr->ea_addr[5]);
+#endif
+}
+
+/* Detect link status (MII interface) */
+static void vt_check_link(vt_driver *pdev) {
+       u16_t base = pdev->vt_base_addr;
+       u32_t res;
+
+       vt_outb(base, VT_REG_MII_CFG, 0x01);
+       vt_outb(base, VT_REG_MII_ADDR, 0x01);
+       vt_outb(base, VT_REG_MII_CR, 0x40);
+       usleep(10000);
+       res = vt_inw(base, VT_REG_MII_DATA);
+       if (res & 0x0004)
+               pdev->vt_link = TRUE;
+       else
+               pdev->vt_link = FALSE;
+}
+
+/* Stop the driver */
+static void vt_stop(void) {
+       u16_t base = g_driver.vt_base_addr;
+
+       /* Free Rx and Tx buffer*/
+       free_contig(g_driver.vt_buf, g_driver.vt_buf_size);
+
+       /* Stop IRQ and device */
+       vt_outw(base, VT_REG_IMR, 0x0000);
+       vt_outw(base, VT_REG_CR, VT_CMD_STOP);
+}
+
+/* Set driver mode */
+static void vt_mode(unsigned int mode) {
+       vt_driver *pdev = &g_driver;
+       u16_t base = pdev->vt_base_addr;
+       u8_t rcr;
+
+       pdev->vt_mode = mode;
+       vt_outl(base, VT_REG_MAR0, 0xffffffff);
+       vt_outl(base, VT_REG_MAR1, 0xffffffff);
+
+       rcr = vt_inb(base, VT_REG_RCR);
+       rcr &= ~(VT_RCR_AB | VT_RCR_AM | VT_RCR_AP | VT_RCR_AE | VT_RCR_AR);
+       if (pdev->vt_mode & NDEV_PROMISC)
+               rcr |= VT_RCR_AB | VT_RCR_AM | VT_RCR_AE | VT_RCR_AR;
+       if (pdev->vt_mode & NDEV_BROAD)
+               rcr |= VT_RCR_AB;
+       if (pdev->vt_mode & NDEV_MULTI)
+               rcr |= VT_RCR_AM;
+       rcr |= VT_RCR_AP;
+       vt_outb(base, VT_REG_RCR, 0x60 | rcr);
+}
+
+/* Receive data */
+static ssize_t vt_recv(struct netdriver_data *data, size_t max) {
+       vt_driver *pdev = &g_driver;
+       u32_t rxstat, totlen, packlen;
+       vt_desc *desc;
+       int index, i;
+
+       index = pdev->vt_rx_head;
+       desc = pdev->vt_rx_desc;
+       desc += index;
+
+       /* Manage Rx buffer */
+       for (;;) {
+               rxstat = desc->status;
+
+               if (rxstat & VT_DESC_OWN)
+                       return SUSPEND;
+
+               if (rxstat & VT_DESC_RX_ALL_ERR) {
+#ifdef VT6105_DEBUG
+                       printf("VT6105: Rx error: 0x%08x\n", rxstat);
+#endif
+                       if (rxstat & VT_DESC_RX_FOV) {
+#ifdef VT6105_DEBUG
+                               printf("VT6105: Rx buffer overflow\n");
+#endif
+                               pdev->vt_stat.ets_fifoOver++;
+                       }
+                       if (rxstat & VT_DESC_RX_FAE) {
+#ifdef VT6105_DEBUG
+                               printf("VT6105: Rx frames not align\n");
+#endif
+                               pdev->vt_stat.ets_frameAll++;
+                       }
+                       if (rxstat & VT_DESC_RX_CRCE) {
+#ifdef VT6105_DEBUG
+                               printf("VT6105: Rx CRC error\n");
+#endif
+                               pdev->vt_stat.ets_CRCerr++;
+                       }
+               }
+
+               /* Normal packet */
+               if ((rxstat & VT_DESC_RX_PACK) == VT_DESC_RX_PACK)
+                       break;
+
+               /* Other packet */
+               if (index == VT_RX_DESC_NUM - 1) {
+                       desc->status = VT_DESC_OWN |
+                                               ((VT_RX_BUF_SIZE << 16) & VT_DESC_RX_LENMASK);
+                       index = 0;
+                       desc = pdev->vt_rx_desc;
+               }
+               else {
+                       desc->status = VT_DESC_OWN |
+                                               ((VT_RX_BUF_SIZE << 16) & VT_DESC_RX_LENMASK);
+                       index++;
+                       desc++;
+               }
+       }
+
+       /* Get data length */
+       totlen = (rxstat & VT_DESC_RX_LENMASK) >> 16;
+       if (totlen < 8 || totlen > 2 * ETH_MAX_PACK_SIZE) {
+               printf("VT6105: Bad data length: %d\n", totlen);
+               panic(NULL);
+       }
+
+       /* Substract CRC to get packet */
+       packlen = totlen - ETH_CRC_SIZE;
+       if (packlen > max)
+               packlen = max;
+
+       /* Copy data to user */
+       netdriver_copyout(data, 0, pdev->vt_rx[index].buf, packlen);
+       pdev->vt_stat.ets_packetR++;
+
+       /* Set Rx descriptor status */
+       if (index == VT_RX_DESC_NUM - 1) {
+               desc->status = VT_DESC_OWN |
+                                               ((VT_RX_BUF_SIZE << 16) & VT_DESC_RX_LENMASK);
+               index = 0;
+       }
+       else {
+               desc->status = VT_DESC_OWN |
+                                               ((VT_RX_BUF_SIZE << 16) & VT_DESC_RX_LENMASK);
+               index++;
+       }
+       pdev->vt_rx_head = index;
+
+#ifdef VT6105_DEBUG
+       printf("VT6105: Successfully receive a packet, length = %d\n", packlen);
+#endif
+
+       return packlen;
+}
+
+/* Transmit data */
+static int vt_send(struct netdriver_data *data, size_t size) {
+       vt_driver *pdev = &g_driver;
+       vt_desc *desc;
+       int tx_head, i;
+       u8_t db;
+       u16_t base = pdev->vt_base_addr;
+
+       tx_head = pdev->vt_tx_head;
+       desc = pdev->vt_tx_desc;
+       desc += tx_head;
+
+       if (pdev->vt_tx[tx_head].busy)
+               return SUSPEND;
+
+       /* Copy data from user */
+       netdriver_copyin(data, 0, pdev->vt_tx[tx_head].buf, size);
+
+       /* Set busy */
+       pdev->vt_tx[tx_head].busy = TRUE;
+       pdev->vt_tx_busy_num++;
+
+       /* Set Tx descriptor status */
+       desc->status = VT_DESC_OWN | VT_DESC_FIRST | VT_DESC_LAST;
+       desc->length = 0x00e08000 | (size >= 60 ? size : 60);
+       if (tx_head == VT_TX_DESC_NUM - 1)
+               tx_head = 0;
+       else
+               tx_head++;
+       pdev->vt_tx_head = tx_head;
+
+       /* Wake up transmit channel */
+       db = vt_inb(base, VT_REG_CR);
+       db |= VT_CMD_TX_DEMAND;
+       vt_outb(base, VT_REG_CR, db);
+
+       return 0;
+}
+
+/* Handle Interrupt */
+static void vt_intr(unsigned int mask) {
+       int s;
+
+       /* Run interrupt handler at driver level */
+       vt_handler(&g_driver);
+
+       /* Reenable interrupts for this hook */
+       if ((s = sys_irqenable(&g_driver.vt_hook)) != OK)
+               printf("VT6105: Cannot enable interrupts: %d\n", s);
+
+       /* Perform tasks based on the flagged conditions */
+       vt_check_ints(&g_driver);
+}
+
+/* Real handler interrupt */
+static void vt_handler(vt_driver *pdev) {
+       u16_t base = pdev->vt_base_addr;
+       int intr_status;
+       u8_t db;
+       u16_t dw;
+       u32_t dl, txstat;
+       int flag = 0, tx_head, tx_tail;
+       vt_desc *desc;
+
+       /* Get interrupt status */
+       intr_status = vt_inw(base, VT_REG_ISR);
+
+       /* Clear interrupt */
+       dw = intr_status & ~(VT_INTR_PCI_ERR | VT_INTR_PORT_CHANGE);
+       vt_outw(base, VT_REG_ISR, dw);
+
+       /* Check link status */
+       if (intr_status & VT_INTR_PORT_CHANGE)
+               printf("VT6105: Port state change!\n");
+
+       /* Check interrupt status */
+       if (intr_status & VT_INTR_RX_DONE) {
+               pdev->vt_recv_flag = TRUE;
+               flag++;
+
+               if (intr_status & VT_INTR_RX_ERR) {
+                       pdev->vt_stat.ets_recvErr++;
+                       printf("VT6105: Rx error in interrupt: 0x%04x\n", intr_status);
+               }
+               if (intr_status & VT_INTR_RX_NOBUF)
+                       printf("VT6105: Rx no buffer in interrupt: 0x%04x\n", intr_status);
+               if (intr_status & VT_INTR_RX_EMPTY)
+                       printf("VT6105: Rx buffer empty in interrupt: 0x%04x\n", intr_status);
+               if (intr_status & VT_INTR_RX_OVERFLOW)
+                       printf("VT6105: Rx buffer overflow in interrupt: 0x%04x\n", intr_status);
+               if (intr_status & VT_INTR_RX_DROPPED)
+                       printf("VT6105: Rx buffer dropped in interrupt: 0x%04x\n", intr_status);
+       }
+       if (intr_status & VT_INTR_TX_DONE) {
+               pdev->vt_send_flag = TRUE;
+               flag++;
+
+               if (intr_status & VT_INTR_TX_ERR) {
+                       pdev->vt_stat.ets_sendErr++;
+                       printf("VT6105: Tx error in interrupt: 0x%04x\n", intr_status);
+               }
+               if (intr_status & VT_INTR_TX_UNDER_RUN)
+                       printf("VT6105: Tx buffer underflow in interrupt: 0x%04x\n", intr_status);
+               if (intr_status & VT_INTR_TX_ABORT)
+                       printf("VT6105: Tx abort in interrupt: 0x%04x\n", intr_status);
+
+               /* Manage Tx Buffer */
+               tx_head = pdev->vt_tx_head;
+               tx_tail = pdev->vt_tx_tail;
+               while (tx_tail != tx_head) {
+                       desc = pdev->vt_tx_desc;
+                       desc += tx_tail;
+                       if (!pdev->vt_tx[tx_tail].busy)
+                               printf("VT6105: Strange, buffer not busy?\n");
+                       txstat = desc->status;
+
+                       /* Check whether the buffer is ready */
+                       if (txstat & VT_DESC_OWN) {
+                               break;
+                       }
+
+                       if (txstat & VT_DESC_TX_ERR) {
+#ifdef VT6105_DEBUG
+                               printf("VT6105: Tx error: 0x%08x\n", txstat);
+#endif
+                               if (txstat & VT_DESC_TX_UDF) {
+#ifdef VT6105_DEBUG
+                                       printf("VT6105: Tx buffer underflow\n");
+#endif
+                                       pdev->vt_stat.ets_fifoUnder++;
+                               }
+                               if (txstat & VT_DESC_TX_CRS) {
+#ifdef VT6105_DEBUG
+                                       printf("VT6105: Tx carrier sense lost\n");
+#endif
+                                       pdev->vt_stat.ets_carrSense++;
+                               }
+                               if (txstat & VT_DESC_TX_CDH) {
+#ifdef VT6105_DEBUG
+                                       printf("VT6105: Tx collision detect\n");
+#endif
+                                       pdev->vt_stat.ets_collision++;
+                               }
+                               if (txstat & VT_DESC_TX_OWC) {
+#ifdef VT6105_DEBUG
+                                       printf("VT6105: Tx buffer out of winidow\n");
+#endif
+                                       pdev->vt_stat.ets_OWC++;
+                               }
+                       }
+
+                       pdev->vt_stat.ets_packetT++;
+                       pdev->vt_tx[tx_tail].busy = FALSE;
+                       pdev->vt_tx_busy_num--;
+
+                       if (++tx_tail >= VT_TX_DESC_NUM)
+                               tx_tail = 0;
+
+                       pdev->vt_send_flag = TRUE;
+                       pdev->vt_recv_flag = TRUE;
+                       pdev->vt_tx_alive = TRUE;
+
+#ifdef VT6105_DEBUG
+                       printf("VT6105: Successfully send a packet\n");
+#endif
+               }
+               pdev->vt_tx_tail = tx_tail;
+       }
+       if (!flag) {
+               printf("VT6105: Unknown error in interrupt: 0x%04x\n", intr_status);
+               return;
+       }
+
+       /* Perform tasks based on the flagged condition */
+       vt_check_ints(pdev);
+}
+
+/* Check interrupt and perform */
+static void vt_check_ints(vt_driver *pdev) {
+       if (!pdev->vt_recv_flag)
+               return;
+       pdev->vt_recv_flag = FALSE;
+
+       /* Handle data receive */
+       netdriver_recv();
+
+       /* Handle data transmit */
+       if (pdev->vt_send_flag) {
+               pdev->vt_send_flag = FALSE;
+               netdriver_send();
+       }
+}
+
+static void vt_stat(eth_stat_t *stat) {
+       memcpy(stat, &g_driver.vt_stat, sizeof(*stat));
+}
+
+static void vt_alarm(clock_t stamp) {
+       vt_driver *pdev = &g_driver;
+
+       /* Use a synchronous alarm instead of a watchdog timer */
+       sys_setalarm(sys_hz(), 0);
+
+       /* Assume the an idle system is alive  */
+       if (!pdev->vt_tx_busy_num) {
+               pdev->vt_tx_alive = TRUE;
+               return;
+       }
+       if (pdev->vt_tx_alive) {
+               pdev->vt_tx_alive = FALSE;
+               return;
+       }
+
+       printf("VT6105: Resetting the driver\n");
+       vt_reset_hw(pdev);
+       pdev->vt_recv_flag = TRUE;
+
+       vt_check_ints(pdev);
+}
diff --git a/minix/drivers/net/vt6105/vt6105.conf b/minix/drivers/net/vt6105/vt6105.conf
new file mode 100755 (executable)
index 0000000..887aa42
--- /dev/null
@@ -0,0 +1,15 @@
+service vt6105
+{
+       type net;
+       descr "VIA Technology 6105/6106S Ethernet Card";
+       system
+               UMAP            # 14
+               IRQCTL          # 19
+               DEVIO           # 21
+       ;
+       pci device      1106:3106;
+       ipc
+               SYSTEM pm rs log tty ds vm
+               pci inet lwip amddev
+               ;
+};
diff --git a/minix/drivers/net/vt6105/vt6105.h b/minix/drivers/net/vt6105/vt6105.h
new file mode 100644 (file)
index 0000000..51c8427
--- /dev/null
@@ -0,0 +1,194 @@
+#include <minix/drivers.h>
+#include <minix/netdriver.h>
+#include <machine/pci.h>
+#include <minix/ds.h>
+#include <assert.h>
+
+/* PCI Register */
+#define VT_PCI_VID             0x00    /* Vendor ID */
+#define VT_PCI_DID             0x02    /* Device ID */
+#define VT_PCI_CMD             0x04    /* Command */
+#define VT_PCI_STS             0x06    /* Status */
+#define VT_PCI_RID             0x08    /* Revision ID */
+#define VT_PCI_CC              0x09    /* Class Code */
+#define VT_PCI_CLS             0x0c    /* Cache Line Size */
+#define VT_PCI_LT              0x0d    /* Latency Timer */
+#define VT_PCI_HT              0x0e    /* Header Type */
+
+/* Internal Register */
+#define VT_REG_ADDR            0x00    /* Ethernet Address */
+#define VT_REG_RCR             0x06    /* Receive Configure Request */
+#define VT_REG_TCR             0x07    /* Transmit Configure Request */
+#define VT_REG_CR              0x08    /* Control 0 */
+#define VT_REG_ISR             0x0c    /* Interrupt Status */
+#define VT_REG_IMR             0x0e    /* Interrupt Mask */
+#define VT_REG_MAR0            0x10    /* Multicast Address 0 */
+#define VT_REG_MAR1            0x14    /* Multicast Address 1 */
+#define VT_REG_RD_BASE         0x18    /* Receive Descriptor Base Address */
+#define VT_REG_TD_BASE         0x1c    /* Transmit Descriptor Base Address */
+#define VT_REG_MII_CFG         0x6c    /* MII Configuration */
+#define VT_REG_MII_STS         0x6d    /* MII Status */
+#define VT_REG_BCR0            0x6e    /* Bus Control 0 */
+#define VT_REG_BCR1            0x6f    /* Bus Control 1 */
+#define VT_REG_MII_CR          0x70    /* MII Control */
+#define VT_REG_MII_ADDR                0x71    /* MII Interface Address*/
+#define VT_REG_MII_DATA                0x72    /* MII Data Port */
+#define VT_REG_EECSR   0x74    /* EEPROM Control/Status */
+#define VT_REG_CFG_A   0x78    /* Chip Configuration A */
+#define VT_REG_CFG_B   0x79    /* Chip Configuration B */
+#define VT_REG_CFG_C   0x7a    /* Chip Configuration C */
+#define VT_REG_CFG_D   0x7b    /* Chip Configuration D */
+#define VT_REG_MCR0            0x80    /* Miscellaneous Control 0 */
+#define VT_REG_MCR1            0x81    /* Miscellaneous Control 1 */
+#define VT_REG_STICK   0x83    /* Sticky Hardware Control */
+#define VT_REG_MISR            0x84    /* MII Interrupt Status */
+#define VT_REG_MIMR            0x86    /* MII Interrupt Mask */
+#define VT_REG_FCR0            0x98    /* Flow Control 0 */
+#define VT_REG_FCR1            0x99    /* Flow Control 1 */
+#define VT_REG_WOL_SET         0xA4    /* Wake On LAN Set */
+#define VT_REG_WOL_CLR         0xA0    /* Wake On LAN Clear */
+#define VT_REG_PCS_CLR         0xA5    /* Power Configuration Set */
+#define VT_REG_PCS_SET         0xA1    /* Power Configuration Clear */
+#define VT_REG_WOLC_SET                0xA7    /* WOL Configuration Set */
+#define VT_REG_WOLC_CLR                0xA3    /* WOL Configuration Clear */
+#define VT_REG_WOLS_SET                0xA8    /* WOL Status Clear */
+#define VT_REG_WOLS_CLR                0xAC    /* WOL Status Set */
+
+/* Interrupt Status/Mask Register */
+#define VT_INTR_RX_DONE                        0x0001
+#define VT_INTR_TX_DONE                        0x0002
+#define VT_INTR_RX_ERR                 0x0004
+#define VT_INTR_TX_ERR                 0x0008
+#define VT_INTR_RX_EMPTY               0x0020
+#define VT_INTR_PCI_ERR                        0x0040
+#define VT_INTR_STS_MAX                        0x0080
+#define VT_INTR_RX_EARLY               0x0100
+#define VT_INTR_TX_UNDER_RUN   0x0210
+#define VT_INTR_RX_OVERFLOW            0x0400
+#define VT_INTR_RX_DROPPED             0x0800
+#define VT_INTR_RX_NOBUF               0x1000
+#define VT_INTR_TX_ABORT               0x2000
+#define VT_INTR_PORT_CHANGE            0x4000
+#define VT_INTR_RX_WAKE_UP             0x8000
+
+/* Control Register Command */
+#define VT_CMD_START           0x0002
+#define VT_CMD_STOP                    0x0004
+#define VT_CMD_RX_ON           0x0008
+#define VT_CMD_TX_ON           0x0010
+#define VT_CMD_TX_DEMAND       0x0020
+#define VT_CMD_RX_DEMAND       0x0040
+#define VT_CMD_EARLY_RX                0x0100
+#define VT_CMD_EARLY_TX                0x0200
+#define VT_CMD_FDUPLEX         0x0400
+#define VT_CMD_NO_POLL         0x0800
+#define VT_CMD_RESET           0x8000
+
+/* Receive Configure Mode */
+#define VT_RCR_AP              0x10
+#define VT_RCR_AB              0x08
+#define VT_RCR_AM              0x04
+#define VT_RCR_AR              0x02
+#define VT_RCR_AE              0x01
+
+/* General Descriptor Flag */
+#define VT_DESC_OWN            0x80000000      /* Ownership */
+#define VT_DESC_FIRST  0x00000200      /* First Descriptor */
+#define VT_DESC_LAST   0x00000100      /* Last Descriptor */
+
+/* Rx Descriptor Flag */
+#define VT_DESC_RX_LENMASK     0x7fff0000      /* Receive Frame Length Mask */
+#define VT_DESC_RX_OK          0x00008000      /* Receive OK */
+#define VT_DESC_RX_MAR         0x00002000      /* Multicast Address Received */
+#define VT_DESC_RX_BAR         0x00001000      /* Broadcast Address Received */
+#define VT_DESC_RX_PHY         0x00000800      /* Physical Address Received */
+#define VT_DESC_RX_LINK_ERR    0x00000080      /* Descriptor Link Structure Error */
+#define VT_DESC_RX_RUNT                0x00000020      /* Runt Packet */
+#define VT_DESC_RX_LONG                0x00000010      /* Long Packet */
+#define VT_DESC_RX_FOV         0x00000008      /* FIFO Overflow */
+#define VT_DESC_RX_FAE         0x00000004      /* Frame Align Error */
+#define VT_DESC_RX_CRCE                0x00000002      /* CRC Error */
+#define VT_DESC_RX_ERR         0x00000001      /* Receive Error */
+#define VT_DESC_RX_ALL_ERR     (VT_DESC_RX_LINK_ERR | VT_DESC_RX_RUNT | \
+                                                       VT_DESC_RX_LONG | VT_DESC_RX_FOV | \
+                                                       VT_DESC_RX_FAE | VT_DESC_RX_CRCE | VT_DESC_RX_ERR)
+#define VT_DESC_RX_PACK                (VT_DESC_FIRST | VT_DESC_LAST)
+
+/* Tx Descriptor Flag */
+#define VT_DESC_TX_ERR         0x00008000      /* Transmit Error */
+#define VT_DESC_TX_UDF         0x00000800      /* FIFO Underflow */
+#define VT_DESC_TX_CRS         0x00000400      /* Carrier Sense Lost Detect */
+#define VT_DESC_TX_OWC         0x00000200      /* Out of Window Collision */
+#define VT_DESC_TX_ABT         0x00000100      /* Excessive Collision Abort */
+#define VT_DESC_TX_CDH         0x00000010      /* Collision Detect */
+
+/* WOL status */
+#define VT_WOL_UCAST           0x10
+#define VT_WOL_MAGIC           0x20
+#define VT_WOL_MCAST           0x30
+#define VT_WOL_LINK_UP         0x40
+#define VT_WOL_LINK_DOWN       0x80
+
+/* Link status */
+#define VT_LINK_UP                     1
+#define VT_LINK_DOWN           0
+#define VT_LINK_UNKNOWN                -1
+
+#define VT_RX_BUF_SIZE         1536
+#define VT_TX_BUF_SIZE         1536
+#define VT_RX_DESC_NUM         64
+#define VT_TX_DESC_NUM         64
+
+/* #define VT6105_DEBUG */
+
+/* Data Descriptor */
+typedef struct vt_desc {
+       u32_t status;           /* command/status */
+       u32_t length;           /* Buffer/Frame length */
+       u32_t addr;                     /* DMA buffer address */
+       u32_t next_desc;        /* Next descriptor */
+} vt_desc;
+
+/* Driver Data Structure */
+typedef struct vt_driver {
+       u16_t vt_base_addr;             /* Base address */
+       int vt_revision;                /* Revision ID */
+       int vt_irq;                             /* IRQ number */
+       int vt_mode;
+       int vt_link;                    /* Whether link-up */
+       int vt_recv_flag;               /* Receive flag */
+       int vt_send_flag;               /* Send flag */
+       int vt_report_link;
+       int vt_tx_alive;
+       int vt_tx_busy;
+
+       /* Buffer */
+       size_t vt_buf_size;
+       char *vt_buf;
+
+       /* Rx data */
+       int vt_rx_head;
+       struct {
+               phys_bytes buf_dma;
+               char *buf;
+       } vt_rx[VT_RX_DESC_NUM];
+       vt_desc *vt_rx_desc;                    /* Rx descriptor buffer */
+       phys_bytes vt_rx_desc_dma;              /* Rx descriptor DMA buffer */
+
+       /* Tx data */
+       int vt_tx_head;
+       int vt_tx_tail;
+       struct {
+               int busy;
+               phys_bytes buf_dma;
+               char *buf;
+       } vt_tx[VT_TX_DESC_NUM];
+       vt_desc *vt_tx_desc;                    /* Tx descriptor buffer */
+       phys_bytes vt_tx_desc_dma;              /* Tx descriptor DMA buffer */
+       int vt_tx_busy_num;                             /* Number of busy Tx descriptors */
+
+       int vt_hook;            /* IRQ hook id at kernel */
+       eth_stat_t vt_stat;
+
+       char vt_name[20];
+} vt_driver;
index bb2606e654b4909475ac9b182802494ac7c54fa5..e8b06eef51a7f4b0d4c28b12741be44df9fbbd6e 100644 (file)
@@ -73,6 +73,7 @@ service_get_policies(struct policies * pol, index_t slot)
                { .label = "rtl8169", .policy_str = "reset" },
                { .label = "uds", .policy_str = "reset" },
                { .label = "virtio_net", .policy_str = "reset" },
+               { .label = "vt6105", .policy_str = "reset" },
                /* power */
                { .label = "acpi", .policy_str = "" },
                { .label = "tps65217", .policy_str = "" },