qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 5/8] partially working network driver, needs more co


From: Bryce Lanham
Subject: [Qemu-devel] [PATCH 5/8] partially working network driver, needs more comparison with real hardware before it can be made fully working
Date: Wed, 17 Aug 2011 17:09:09 -0500

Signed-off-by: Bryce Lanham <address@hidden>
---
 hw/next-net.c |  513 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/next-net.h |    2 +
 2 files changed, 515 insertions(+), 0 deletions(-)
 create mode 100644 hw/next-net.c
 create mode 100644 hw/next-net.h

diff --git a/hw/next-net.c b/hw/next-net.c
new file mode 100644
index 0000000..94739a1
--- /dev/null
+++ b/hw/next-net.c
@@ -0,0 +1,513 @@
+/*
+ * QEMU NeXT Network (MB8795) emulation
+ *
+ * Copyright (c) 2011 Bryce Lanham
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "sysemu.h"//only needed for vm_stop
+#include "hw.h"
+#include "net.h"
+#include "next-net.h"
+#include "sysbus.h"
+/* debug NeXT ethernet */
+#define DEBUG_NET
+
+#ifdef DEBUG_NET
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("NET: " fmt , ## __VA_ARGS__); } while (0);
+#else
+#define DPRINTF(fmt, ...)
+#endif
+    
+/* IRQs should be moved to header later */
+#define TX_I_DMA 0
+#define RX_I_DMA 1
+#define TX_I    2
+#define RX_I     3
+/* names could be better */
+typedef struct NextDMA {
+       uint32_t csr;
+       uint32_t savedbase;
+       uint32_t savedlimit;
+       
+    uint32_t baser;
+    uint32_t base;
+    uint32_t limit;
+    uint32_t chainbase;
+    uint32_t chainlimit;
+       uint32_t basew;
+
+       
+} NextDMA;
+
+typedef struct NextNetState {
+    uint8_t mac[6];
+    
+    qemu_irq *irq;
+    
+    NICState *nic;
+    NICConf c;
+       
+    NextDMA tx_dma;
+       uint8_t tx_stat;
+       uint8_t tx_mask;
+    uint8_t tx_mode;
+       
+    NextDMA rx_dma;
+    uint8_t rx_stat;
+    uint8_t rx_mask;
+    uint8_t rx_mode;
+
+    uint8_t rst_mode;
+
+} NextNetState;
+
+NextNetState nextnet_state;
+
+void *env_g;
+
+void nextnet_irq(void *opaque, int n, int level);
+static int nextnet_can_rx(VLANClientState *nc);
+static ssize_t nextnet_rx(VLANClientState *nc, const uint8_t *buf, size_t 
size);
+static void nextnet_cleanup(VLANClientState *nc);
+
+static NetClientInfo nextnet_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = nextnet_can_rx,
+    .receive = nextnet_rx,
+    .cleanup = nextnet_cleanup,
+};
+/* these need to be somewhere else */
+extern uint32_t int_status;//should be set in a global irq handler
+extern uint32_t int_mask;
+extern uint32_t event_test;
+
+void nextnet_reset(NextNetState *s);
+void nextnet_reset(NextNetState *s)
+{
+
+
+}
+
+static uint32_t net_readb(void*opaque, target_phys_addr_t addr);
+static uint32_t net_readw(void*opaque, target_phys_addr_t addr);
+static uint32_t net_readl(void*opaque, target_phys_addr_t addr);
+static CPUReadMemoryFunc *net_read[3] = {
+       net_readb,
+       net_readw,
+       net_readl
+};
+
+static void net_writeb(void*opaque, target_phys_addr_t addr, uint32_t value);
+static void net_writew(void*opaque, target_phys_addr_t addr, uint32_t value);
+static void net_writel(void*opaque, target_phys_addr_t addr, uint32_t value);
+static CPUWriteMemoryFunc * const net_write[3] = {
+       net_writeb,
+       net_writew,
+       net_writel
+};
+
+
+void nextnet_init(void *opaque)
+{
+    NextNetState *s = &nextnet_state;
+       CPUState *env = (CPUState *)opaque; 
+    env_g = opaque;//used this as a global during testing, should be removed
+    
+       /*register device register space */
+    cpu_register_physical_memory((uint32_t)0x2106000,0x1000,
+        cpu_register_io_memory(net_read,net_write, (void 
*)&nextnet_state,DEVICE_NATIVE_ENDIAN));
+  cpu_register_physical_memory((uint32_t)0x2006000,0x1000,
+        cpu_register_io_memory(net_read,net_write, (void 
*)&nextnet_state,DEVICE_NATIVE_ENDIAN));
+
+
+    /* and ethernet control/status registers *///including DMA for now, will 
seperate out later
+    cpu_register_physical_memory((uint32_t)0x2000110,0x4400,
+        cpu_register_io_memory(net_read,net_write, (void 
*)&nextnet_state,DEVICE_NATIVE_ENDIAN));
+
+    /* connect to virtual lan */
+    s->c.vlan = qemu_find_vlan(0,1); 
+    
+    /* register nic */
+    s->nic = qemu_new_nic(&nextnet_info,&s->c, "NeXT MB8795\0", NULL, s);
+
+    /* this needs to be read, will have to load rom file i guess */
+    uint8_t mac[6] = {0,0,0xf,0,0xf3,0x2};
+    memcpy(&s->mac,mac,6);     
+    
+       /* allocate TX/RX and DMA irqs - will be global later */
+    s->irq = qemu_allocate_irqs(nextnet_irq, env, 4);
+    
+    /* this sets the nic's info */
+    qemu_format_nic_info_str(&s->nic->nc, mac);
+
+
+}
+/* It is likely that all register reads are bytes, while all CSR r/w are longs 
*/
+static uint32_t net_readb(void*opaque, target_phys_addr_t addr)
+{
+    NextNetState *s = (NextNetState *)opaque;
+    
+//     CPUState *env = (CPUState *)env_g; 
+    switch(addr)
+    {
+        case 0x6000://TXSTAT
+            // DPRINTF("TXSTAT \tRead\n");
+            return s->tx_stat;
+        
+        case 0x6001:
+            DPRINTF("TXMASK \tRead\n");
+            return s->tx_mask;
+
+        case 0x6002:
+          //  DPRINTF("RXSTAT \tRead  %x @ %x\n",s->rx_stat,env->pc);
+            return s->rx_stat;
+
+        case 0x6003:
+          //  DPRINTF("RXMASK \tRead\n");
+            return s->rx_mask;
+
+        case 0x6004:
+            DPRINTF("TXMODE \tRead\n");
+            return s->tx_mode;
+        
+        case 0x6005:
+          //  DPRINTF("RXMODE \tRead\n");
+            return s->rx_mode;
+        
+        case 0x6006:
+            DPRINTF("RSTMODE \tRead\n");
+            return s->rst_mode;
+        
+        default:
+            fprintf(stderr,"NET Read B @ %x\n",addr);
+            return 0;
+    }
+}
+static uint32_t net_readw(void*opaque, target_phys_addr_t addr)
+{
+       fprintf(stderr,"S Read W @ %x\n",addr);
+       return 0;
+}
+static uint32_t net_readl(void*opaque, target_phys_addr_t addr)
+{
+    NextNetState *s = (NextNetState *)opaque;
+       CPUState *env = (CPUState *)env_g; 
+       switch(addr)
+    {
+        case 0x110:
+
+            //DPRINTF("TXCSR Read\n");
+            return s->tx_dma.csr;
+        case 0x4100: 
+            fprintf(stderr,"SAVEDBASE Read\n");
+            return s->tx_dma.savedbase;
+               case 0x4104: 
+            fprintf(stderr,"SAVELIMIT Read\n");
+                       return s->tx_dma.savedlimit;
+               case 0x4114: 
+            fprintf(stderr,"TXLIMIT Read\n");
+                       return s->tx_dma.limit;
+               case 0x4310:
+            fprintf(stderr,"TXBASE Read\n");
+                       /* FUTURE :return nextdma_read(device, addr); */        
+                       return s->tx_dma.basew;
+
+               case 0x150:
+           // fprintf(stderr,"RXCSR Read %x\n",s->rx_dma.csr);
+            return s->rx_dma.csr;
+        
+               case 0x4140:
+                       return s->rx_dma.savedbase;
+        case 0x4144:
+            DPRINTF("SAVELIMIT %x @ %x\n",s->rx_dma.savedlimit,env->pc);
+            return s->rx_dma.savedlimit;
+               
+        default:
+        fprintf(stderr,"NET Read l @ %x\n",addr);
+        return 0;
+    }
+}
+#define NET_TXSTAT_CLEAR 0xFF
+#define NET_RXSTAT_CLEAR 0xFF
+static void net_writeb(void*opaque, target_phys_addr_t addr, uint32_t value)
+{
+//     CPUState *env = (CPUState *)env_g; 
+    NextNetState *s = (NextNetState *)opaque;
+    switch(addr)
+    {
+       case 0x6000:
+            DPRINTF("TXSTAT \tWrite: %x\n",value);
+            if(value == NET_TXSTAT_CLEAR)
+               s->tx_stat = 0x80;
+            else
+                s->tx_stat = value;
+            break;
+        case 0x6001:
+            DPRINTF("TXMASK \tWrite: %x\n",value);
+            s->tx_mask = value;
+            break;
+        case 0x6002:
+         //   DPRINTF("RXSTAT \tWrite: %x @ %x\n",value,env->pc);
+            if(value == NET_RXSTAT_CLEAR)
+                s->rx_stat = 0;
+            else
+                s->rx_stat = value;
+            break;
+        case 0x6003:
+        //    DPRINTF("RXMASK \tWrite: %x\n",value);
+            s->rx_mask = value;
+            break;
+        case 0x6004:
+            DPRINTF("TXMODE \tWrite: %x\n",value);
+            s->tx_mode = value;
+            break;
+        case 0x6005:
+          //  DPRINTF("RXMODE \tWrite: %x\n",value);
+            s->rx_mode = value;
+            break;
+        case 0x6006:
+            DPRINTF("RSTMODE \tWrite: %x\n",value);
+            s->rst_mode = value;
+            break;
+        case 0x600d:
+        s->mac[(addr&0xF)-8] = value;         
+        DPRINTF("Set MAC ADDR %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+            s->mac[0],s->mac[1],s->mac[2],s->mac[3],s->mac[4],s->mac[5]);
+        qemu_macaddr_default_if_unset((MACAddr *)&s->mac);
+        break;
+        case 0x6008:case 0x6009:case 0x600a: case 0x600b: case 0x600c:
+        s->mac[(addr&0xF)-8] = value;         
+        break; 
+        case 0x6010:case 0x6011: case 0x6012: case 0x6013: case 0x6014:
+     //   break;
+        default:
+        fprintf(stderr,"NET Write B @ %x with %x\n",addr,value);
+    }
+}
+static void net_writew(void*opaque, target_phys_addr_t addr, uint32_t value)
+{
+       fprintf(stderr,"NET W w @ %x with %x\n",addr,value);
+}
+#define DMA_ENABLE             0x01000000
+#define DMA_SUPDATE            0x02000000
+#define DMA_COMPLETE   0x08000000
+
+#define DMA_M2DEV       0x0
+#define DMA_SETENABLE   0x00010000
+#define DMA_SETSUPDATE  0x00020000
+#define DMA_DEV2M              0x00040000
+#define DMA_CLRCOMPLETE 0x00080000
+#define DMA_RESET              0x00100000
+static void net_writel(void*opaque, target_phys_addr_t addr, uint32_t value)
+{
+       static int tx_count = 0;
+    NextNetState *s = (NextNetState *)opaque;
+       switch(addr)
+    {
+        case 0x110:
+        {
+                               
+                                                               
+                               if(value & DMA_SETENABLE)
+                               {
+                tx_count++;
+                       //      if(tx_count % 4) return;
+                               size_t len = (0xFFFFFFF & s->tx_dma.limit) - 
s->tx_dma.base;
+              DPRINTF("TXDMA ENABLE: %x len: %zu\n",s->tx_dma.base, len);
+                               DPRINTF("TX Enable\n");
+                uint8_t buf[1600];//needs to be in dma struct?
+                cpu_physical_memory_read(s->tx_dma.base, buf, len); 
+                
+                               qemu_send_packet(&s->nic->nc, buf,len);   
+                       s->tx_dma.csr |= DMA_COMPLETE | DMA_SUPDATE;
+                           s->tx_stat =  0x80;
+                       //      if(tx_count > 1510) vm_stop(VMSTOP_DEBUG);
+                               
+                       qemu_set_irq(s->irq[TX_I_DMA],3);
+
+                               }
+                               if(value & DMA_SETSUPDATE)
+                                       s->tx_dma.csr |= DMA_SUPDATE;   
+               
+                               if(value & DMA_CLRCOMPLETE)
+                                       s->tx_dma.csr &= ~DMA_COMPLETE;
+
+                               if(value & DMA_RESET)
+                                       s->tx_dma.csr &= ~(DMA_COMPLETE | 
DMA_SUPDATE | DMA_ENABLE);            
+               }
+        break;
+        
+        case 0x4100: 
+        DPRINTF("Write l @ %x with %x\n",addr,value);
+                       s->tx_dma.savedbase = value;
+                   break;
+               
+               case 0x4104: 
+        DPRINTF("Write l @ %x with %x\n",addr,value);
+                       s->tx_dma.savedlimit = value;
+                   break;
+               case 0x4110:
+        DPRINTF("Write l @ %x with %x\n",addr,value);
+                       s->tx_dma.base = value;
+                       break;  
+        case 0x4114: 
+        DPRINTF("Write l @ %x with %x\n",addr,value);
+                       s->tx_dma.limit = value;
+                   break;
+               
+        case 0x4310:
+        DPRINTF("Write l @ %x with %x\n",addr,value);
+                       s->tx_dma.base = value;
+                       /* FUTURE :nextdma_write(device, addr, value); */       
+            break;
+
+        case 0x150:
+               if(value & DMA_DEV2M)
+                {
+                    DPRINTF("RX Dev to Memory\n");
+                               }       
+                               
+                if(value & DMA_SETENABLE)
+                    s->rx_dma.csr |= DMA_ENABLE;
+                
+                               if(value & DMA_SETSUPDATE)
+                                       s->rx_dma.csr |= DMA_SUPDATE;   
+               
+                               if(value & DMA_CLRCOMPLETE)
+                                       s->rx_dma.csr &= ~DMA_COMPLETE;
+
+                               if(value & DMA_RESET)
+                                       s->rx_dma.csr &= ~(DMA_COMPLETE | 
DMA_SUPDATE | DMA_ENABLE);                            
+                               //
+       
+                               DPRINTF("RXCSR \tWrite: %x\n",value);
+                       break;
+        
+        case 0x4150:
+            
+       // DPRINTF("Write l @ %x with %x\n",addr,value);
+            s->rx_dma.base = value;
+               //      s->rx_dma.savedbase = value;
+            break;
+
+        case 0x4154:
+            s->rx_dma.limit = value;
+       // DPRINTF("Write l @ %x with %x\n",addr,value);
+            break;
+
+        case 0x4158:
+            s->rx_dma.chainbase = value;
+       // DPRINTF("Write l @ %x with %x\n",addr,value);
+            break;
+    
+        case 0x415c:
+            s->rx_dma.chainlimit = value;
+       // DPRINTF("Write l @ %x with %x\n",addr,value);
+            //DPRINTF("Pointer write %x w %x\n",addr,value);
+            break;
+        default:
+        DPRINTF("Write l @ %x with %x\n",addr,value);
+    }
+
+}
+
+static int nextnet_can_rx(VLANClientState *nc)
+{
+    NextNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    if(s->rx_mode & 0x3)
+               return 1;
+       else
+               return -1;
+}
+
+static ssize_t nextnet_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+       NextNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+    
+       DPRINTF("received packet %zu\n",size);
+
+       /* Ethernet DMA is supposedly 32 byte aligned */        
+       if((size % 32) != 0)
+       {
+               size -= size % 32;
+               size += 32;
+       }
+       
+       /* write the packet into memory */
+       cpu_physical_memory_write(s->rx_dma.base,buf,size);
+       
+       /* saved limit is checked to calculate packet size
+               by both the rom and netbsd */ 
+       s->rx_dma.savedlimit = (s->rx_dma.base + size);
+       s->rx_dma.savedbase = (s->rx_dma.base);
+       
+       /*32 bytes under savedbase seems to be some kind of register
+       of which the purpose is unknown as of yet*/
+       //stl_phys(s->rx_dma.base-32,0xFFFFFFFF);
+       
+       if((s->rx_dma.csr & DMA_SUPDATE)){      
+               s->rx_dma.base = s->rx_dma.chainbase;
+               s->rx_dma.limit = s->rx_dma.chainlimit;
+       }
+       //we received a packet
+    s->rx_stat = 0x80;
+       
+       //Set dma registers and raise an irq
+       s->rx_dma.csr |= DMA_COMPLETE; //DON'T CHANGE THIS!!!!
+       qemu_set_irq(s->irq[RX_I_DMA],6);
+    
+       return size;
+}
+
+static void nextnet_cleanup(VLANClientState *nc)
+{
+}
+
+/* level and vector values taken from Plan 9 source */
+void nextnet_irq(void *opaque, int n, int level)
+{
+    CPUM68KState *s = (CPUM68KState *)opaque;
+    switch(n)
+       {
+               case TX_I:
+                       int_status = 1<<10;
+                       m68k_set_irq_level(s,3,27);
+                       break;
+               
+               case RX_I:
+                       int_status = 1<<9;
+                       m68k_set_irq_level(s,3,27);
+                       break;
+               
+               case TX_I_DMA:
+                       int_status = 1<<28;
+                       m68k_set_irq_level(s,6,30);
+            break;
+               
+               case RX_I_DMA:
+                       int_status = 1<<27;
+                       m68k_set_irq_level(s,6,30);
+                       break;
+       }
+
+       
+}              
diff --git a/hw/next-net.h b/hw/next-net.h
new file mode 100644
index 0000000..28b7358
--- /dev/null
+++ b/hw/next-net.h
@@ -0,0 +1,2 @@
+
+void nextnet_init(void *opaque);
-- 
1.7.2.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]