1 /*
2  * Cisco router simulation platform.
3  * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4  *
5  * Cisco 2600 PCI controller.
6  */
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include "utils.h"
13 #include "net.h"
14 #include "cpu.h"
15 #include "vm.h"
16 #include "dynamips.h"
17 #include "memory.h"
18 #include "device.h"
19 #include "net_io.h"
20 
21 /* Debugging flags */
22 #define DEBUG_ACCESS    0
23 #define DEBUG_UNKNOWN   1
24 #define DEBUG_PCI       1
25 
26 #define C2600_PCI_BRIDGE_VENDOR_ID   0x10ee
27 #define C2600_PCI_BRIDGE_PRODUCT_ID  0x4013
28 
29 /* C2600 PCI controller */
30 struct c2600_pci_data {
31    char *name;
32    vm_obj_t vm_obj;
33    struct vdevice dev;
34    struct pci_device *pci_dev;
35    vm_instance_t *vm;
36 
37    struct pci_bus *bus;
38    m_uint32_t bridge_bar0,bridge_bar1;
39 };
40 
41 /*
42  * dev_c2600_pci_access()
43  */
dev_c2600_pci_access(cpu_gen_t * cpu,struct vdevice * dev,m_uint32_t offset,u_int op_size,u_int op_type,m_uint64_t * data)44 void *dev_c2600_pci_access(cpu_gen_t *cpu,struct vdevice *dev,
45                            m_uint32_t offset,u_int op_size,u_int op_type,
46                            m_uint64_t *data)
47 {
48    struct c2600_pci_data *d = dev->priv_data;
49    struct pci_device *pci_dev;
50    u_int bus,device,function,reg;
51 
52    if (op_type == MTS_READ)
53       *data = 0x0;
54 
55    bus      = 0;
56    device   = (offset >> 12) & 0x0F;
57    function = (offset >> 8)  & 0x07;
58    reg      = offset & 0xFF;
59 
60    /* Find the corresponding PCI device */
61    pci_dev = pci_dev_lookup(d->bus,bus,device,function);
62 
63 #if DEBUG_PCI
64    if (op_type == MTS_READ) {
65       cpu_log(cpu,"PCI","read request at pc=0x%llx: "
66               "bus=%d,device=%d,function=%d,reg=0x%2.2x\n",
67               cpu_get_pc(cpu), bus, device, function, reg);
68    } else {
69       cpu_log(cpu,"PCI","write request (data=0x%8.8llx) at pc=0x%llx: "
70               "bus=%d,device=%d,function=%d,reg=0x%2.2x\n",
71               *data, cpu_get_pc(cpu), bus, device, function, reg);
72    }
73 #endif
74 
75    if (!pci_dev) {
76       if (op_type == MTS_READ) {
77          cpu_log(cpu,"PCI","read request for unknown device at pc=0x%llx "
78                  "(bus=%d,device=%d,function=%d,reg=0x%2.2x).\n",
79                  cpu_get_pc(cpu), bus, device, function, reg);
80       } else {
81          cpu_log(cpu,"PCI","write request (data=0x%8.8llx) for unknown device "
82                  "at pc=0x%llx (bus=%d,device=%d,function=%d,reg=0x%2.2x).\n",
83                  *data, cpu_get_pc(cpu), bus, device, function, reg);
84       }
85 
86       /* Returns an invalid device ID */
87       if ((op_type == MTS_READ) && (reg == PCI_REG_ID))
88          *data = 0xffffffff;
89    } else {
90       if (op_type == MTS_WRITE) {
91          if (pci_dev->write_register != NULL)
92             pci_dev->write_register(cpu,pci_dev,reg,*data);
93       } else {
94          if (reg == PCI_REG_ID)
95             *data = (pci_dev->product_id << 16) | pci_dev->vendor_id;
96          else {
97             if (pci_dev->read_register != NULL)
98                *data = pci_dev->read_register(cpu,pci_dev,reg);
99          }
100       }
101    }
102 
103    return NULL;
104 }
105 
106 /* Shutdown the c2600 PCI controller device */
dev_c2600_pci_shutdown(vm_instance_t * vm,struct c2600_pci_data * d)107 void dev_c2600_pci_shutdown(vm_instance_t *vm,struct c2600_pci_data *d)
108 {
109    if (d != NULL) {
110       /* Remove the device */
111       dev_remove(vm,&d->dev);
112 
113       /* Free the structure itself */
114       free(d);
115    }
116 }
117 
118 /* PCI bridge read access */
dev_c2600_pci_bridge_read(cpu_gen_t * cpu,struct pci_device * dev,int reg)119 static m_uint32_t dev_c2600_pci_bridge_read(cpu_gen_t *cpu,
120                                             struct pci_device *dev,
121                                             int reg)
122 {
123    struct c2600_pci_data *d = dev->priv_data;
124 
125    switch(reg) {
126       case 0x10:
127          return(d->bridge_bar0);
128       case 0x14:
129          return(d->bridge_bar1);
130       default:
131          return(0);
132    }
133 }
134 
135 /* PCI bridge read access */
dev_c2600_pci_bridge_write(cpu_gen_t * cpu,struct pci_device * dev,int reg,m_uint32_t value)136 static void dev_c2600_pci_bridge_write(cpu_gen_t *cpu,struct pci_device *dev,
137                                        int reg,m_uint32_t value)
138 {
139    struct c2600_pci_data *d = dev->priv_data;
140 
141    switch(reg) {
142       case 0x10:
143          /* BAR0 must be at 0x00000000 for correct RAM access */
144          if (value != 0x00000000) {
145             vm_error(d->vm,"C2600_PCI",
146                      "Trying to set bridge BAR0 at 0x%8.8x!\n",
147                      value);
148          }
149          d->bridge_bar0 = value;
150          break;
151       case 0x14:
152          /* BAR1 = byte swapped zone */
153          if (!d->bridge_bar1) {
154             d->bridge_bar1 = value;
155 
156             /* XXX */
157             dev_bswap_init(d->vm,"pci_bswap",d->bridge_bar1,0x10000000,
158                            0x00000000);
159          }
160          break;
161    }
162 }
163 
164 /* Create the c2600 PCI controller device */
dev_c2600_pci_init(vm_instance_t * vm,char * name,m_uint64_t paddr,m_uint32_t len,struct pci_bus * bus)165 int dev_c2600_pci_init(vm_instance_t *vm,char *name,
166                        m_uint64_t paddr,m_uint32_t len,
167                        struct pci_bus *bus)
168 {
169    struct c2600_pci_data *d;
170 
171    if (!(d = malloc(sizeof(*d)))) {
172       fprintf(stderr,"c2600_pci: unable to create device data.\n");
173       return(-1);
174    }
175 
176    memset(d,0,sizeof(*d));
177    d->name = name;
178    d->vm   = vm;
179    d->bus  = bus;
180 
181    vm_object_init(&d->vm_obj);
182    d->vm_obj.name = name;
183    d->vm_obj.data = d;
184    d->vm_obj.shutdown = (vm_shutdown_t)dev_c2600_pci_shutdown;
185 
186    dev_init(&d->dev);
187    d->dev.name      = name;
188    d->dev.priv_data = d;
189    d->dev.phys_addr = paddr;
190    d->dev.phys_len  = len;
191    d->dev.handler   = dev_c2600_pci_access;
192 
193    pci_dev_add(d->bus,"pci_bridge",
194                C2600_PCI_BRIDGE_VENDOR_ID,C2600_PCI_BRIDGE_PRODUCT_ID,
195                15,0,-1,d,
196                NULL,
197                dev_c2600_pci_bridge_read,
198                dev_c2600_pci_bridge_write);
199 
200    /* Map this device to the VM */
201    vm_bind_device(vm,&d->dev);
202    vm_object_add(vm,&d->vm_obj);
203    return(0);
204 }
205 
206