/[dynamips]/upstream/dynamips-0.2.7-RC1/dev_plx.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/dynamips-0.2.7-RC1/dev_plx.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Sat Oct 6 16:23:47 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 10339 byte(s)
dynamips-0.2.7-RC1

1 /*
2 * Cisco router simulation platform.
3 * Copyright (C) 2005,2006 Christophe Fillot. All rights reserved.
4 *
5 * PLX PCI9060/PCI9054 - PCI bus master interface chip.
6 *
7 * This is very basic, it has been designed to allow the C7200 PA-POS-OC3
8 * to work, and for the upcoming PA-MC-8TE1.
9 */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "cpu.h"
16 #include "vm.h"
17 #include "dynamips.h"
18 #include "memory.h"
19 #include "device.h"
20 #include "pci_dev.h"
21 #include "dev_plx.h"
22
23 #define DEBUG_ACCESS 1
24
25 /* PLX vendor/product codes */
26 #define PLX_PCI_VENDOR_ID 0x10b5
27 #define PLX9060_PCI_PRODUCT_ID 0x9060
28 #define PLX9054_PCI_PRODUCT_ID 0x9054
29
30 /* Number of Local Spaces (1 on 9060, 2 on 9054) */
31 #define PLX_LOCSPC_MAX 2
32
33 /* Local Space ranges */
34 #define PLX_LOCSPC_RANGE_DEFAULT 0xFFF00000
35 #define PLX_LOCSPC_RANGE_DECODE_MASK 0xFFFFFFF0
36
37 /* Local space definition */
38 struct plx_locspace {
39 m_uint32_t lbaddr;
40 m_uint32_t range;
41 struct vdevice *dev;
42 };
43
44 /* PLX data */
45 struct plx_data {
46 /* Device name */
47 char *name;
48
49 /* Variant (9060, 9054) */
50 u_int variant;
51
52 /* Virtual machine and object info */
53 vm_instance_t *vm;
54 vm_obj_t vm_obj;
55
56 /* Virtual PLX device */
57 struct vdevice plx_dev;
58 struct pci_device *pci_plx_dev;
59
60 /* Local spaces */
61 struct plx_locspace lspc[PLX_LOCSPC_MAX];
62
63 /* Doorbell registers */
64 m_uint32_t pci2loc_doorbell_reg,loc2pci_doorbell_reg;
65 dev_plx_doorbell_cbk pci2loc_doorbell_cbk;
66 void *pci2loc_doorbell_cbk_arg;
67 };
68
69 /* Log a PLX message */
70 #define PLX_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)
71
72 /* Map a local space device */
73 static void plx_map_space(struct plx_data *d,u_int id)
74 {
75 struct plx_locspace *lspc;
76
77 lspc = &d->lspc[id];
78
79 if (!lspc->dev)
80 return;
81
82 lspc->dev->phys_len = 1+(~(lspc->range & PLX_LOCSPC_RANGE_DECODE_MASK));
83 vm_map_device(d->vm,lspc->dev,lspc->lbaddr);
84
85 PLX_LOG(d,"device %u mapped at 0x%llx, size=0x%x\n",
86 id,lspc->dev->phys_addr,lspc->dev->phys_len);
87 }
88
89 /* PLX device common access routine */
90 void *dev_plx_access(cpu_gen_t *cpu,struct vdevice *dev,
91 m_uint32_t offset,u_int op_size,u_int op_type,
92 m_uint64_t *data)
93 {
94 struct plx_data *d = dev->priv_data;
95
96 if (op_type == MTS_READ)
97 *data = 0;
98
99 switch(offset) {
100 /* Local Address Space 0 Range Register */
101 case 0x00:
102 if (op_type == MTS_WRITE) {
103 d->lspc[0].range = *data;
104 plx_map_space(d,0);
105 } else {
106 *data = d->lspc[0].range;
107 }
108 break;
109
110 /* PCI-to-Local Doorbell Register */
111 case 0x60:
112 if (op_type == MTS_WRITE) {
113 d->pci2loc_doorbell_reg = *data;
114
115 if (d->pci2loc_doorbell_cbk != NULL) {
116 d->pci2loc_doorbell_cbk(d,d->pci2loc_doorbell_cbk_arg,
117 d->pci2loc_doorbell_reg);
118 }
119 }
120 break;
121
122 /* Local-to-PCI Doorbell Register */
123 case 0x64:
124 if (op_type == MTS_READ)
125 *data = d->loc2pci_doorbell_reg;
126 else
127 d->loc2pci_doorbell_reg &= ~(*data);
128 break;
129
130 default:
131 if (op_type == MTS_READ) {
132 cpu_log(cpu,d->name,
133 "read from unhandled addr 0x%x, pc=0x%llx (size=%u)\n",
134 offset,cpu_get_pc(cpu),op_size);
135 } else {
136 cpu_log(cpu,d->name,
137 "write to handled addr 0x%x, value=0x%llx, "
138 "pc=0x%llx (size=%u)\n",
139 offset,*data,cpu_get_pc(cpu),op_size);
140 }
141 }
142
143 return NULL;
144 }
145
146 /* PLX9054 access routine */
147 void *dev_plx9054_access(cpu_gen_t *cpu,struct vdevice *dev,
148 m_uint32_t offset,u_int op_size,u_int op_type,
149 m_uint64_t *data)
150 {
151 struct plx_data *d = dev->priv_data;
152
153 if (op_type == MTS_READ)
154 *data = 0;
155
156 switch(offset) {
157 /* Local Address Space 1 Range Register */
158 case 0xF0:
159 if (op_type == MTS_WRITE) {
160 d->lspc[1].range = *data;
161 plx_map_space(d,1);
162 } else {
163 *data = d->lspc[1].range;
164 }
165 break;
166
167 default:
168 return(dev_plx_access(cpu,dev,offset,op_size,op_type,data));
169 }
170
171 return NULL;
172 }
173
174 /*
175 * pci_plx_read() - Common PCI read.
176 */
177 static m_uint32_t pci_plx_read(cpu_gen_t *cpu,struct pci_device *dev,int reg)
178 {
179 struct plx_data *d = dev->priv_data;
180
181 #if DEBUG_ACCESS
182 PLX_LOG(d,"read PLX PCI register 0x%x\n",reg);
183 #endif
184 switch(reg) {
185 /* PLX registers */
186 case PCI_REG_BAR0:
187 return(d->plx_dev.phys_addr);
188
189 /* Local space 0 */
190 case PCI_REG_BAR2:
191 return(d->lspc[0].lbaddr);
192
193 default:
194 return(0);
195 }
196 }
197
198 /*
199 * pci_plx_write() - Common PCI write.
200 */
201 static void pci_plx_write(cpu_gen_t *cpu,struct pci_device *dev,
202 int reg,m_uint32_t value)
203 {
204 struct plx_data *d = dev->priv_data;
205
206 #if DEBUG_ACCESS
207 PLX_LOG(d,"write 0x%x to PLX PCI register 0x%x\n",value,reg);
208 #endif
209
210 switch(reg) {
211 /* PLX registers */
212 case PCI_REG_BAR0:
213 vm_map_device(cpu->vm,&d->plx_dev,(m_uint64_t)value);
214 PLX_LOG(d,"PLX registers are mapped at 0x%x\n",value);
215 break;
216
217 /* Local space 0 */
218 case PCI_REG_BAR2:
219 d->lspc[0].lbaddr = value;
220 plx_map_space(d,0);
221 break;
222 }
223 }
224
225 /*
226 * pci_plx9054_read()
227 */
228 static m_uint32_t pci_plx9054_read(cpu_gen_t *cpu,struct pci_device *dev,
229 int reg)
230 {
231 struct plx_data *d = dev->priv_data;
232
233 #if DEBUG_ACCESS
234 PLX_LOG(d,"read PLX PCI register 0x%x\n",reg);
235 #endif
236 switch(reg) {
237 /* Local space 1 */
238 case PCI_REG_BAR3:
239 return(d->lspc[1].lbaddr);
240
241 default:
242 return(pci_plx_read(cpu,dev,reg));
243 }
244 }
245
246 /*
247 * pci_plx9054_write()
248 */
249 static void pci_plx9054_write(cpu_gen_t *cpu,struct pci_device *dev,
250 int reg,m_uint32_t value)
251 {
252 struct plx_data *d = dev->priv_data;
253
254 #if DEBUG_ACCESS
255 PLX_LOG(d,"write 0x%x to PLX PCI register 0x%x\n",value,reg);
256 #endif
257
258 switch(reg) {
259 /* Local space 1 */
260 case PCI_REG_BAR3:
261 d->lspc[1].lbaddr = value;
262 plx_map_space(d,1);
263 break;
264
265 default:
266 pci_plx_write(cpu,dev,reg,value);
267 }
268 }
269
270 /* Shutdown a PLX device */
271 void dev_plx_shutdown(vm_instance_t *vm,struct plx_data *d)
272 {
273 int i;
274
275 if (d != NULL) {
276 /* Unbind the managed devices */
277 for(i=0;i<PLX_LOCSPC_MAX;i++) {
278 if (d->lspc[i].dev)
279 vm_unbind_device(vm,d->lspc[i].dev);
280 }
281
282 /* Remove the PLX device */
283 dev_remove(vm,&d->plx_dev);
284
285 /* Remove the PCI PLX device */
286 pci_dev_remove(d->pci_plx_dev);
287
288 /* Free the structure itself */
289 free(d);
290 }
291 }
292
293 /* Create a generic PLX device */
294 struct plx_data *dev_plx_init(vm_instance_t *vm,char *name)
295 {
296 struct plx_data *d;
297 int i;
298
299 /* Allocate the private data structure */
300 if (!(d = malloc(sizeof(*d)))) {
301 fprintf(stderr,"PLX: unable to create device.\n");
302 return NULL;
303 }
304
305 memset(d,0,sizeof(*d));
306 vm_object_init(&d->vm_obj);
307 d->vm_obj.name = name;
308 d->vm_obj.data = d;
309 d->vm_obj.shutdown = (vm_shutdown_t)dev_plx_shutdown;
310
311 d->vm = vm;
312 d->name = name;
313
314 for(i=0;i<PLX_LOCSPC_MAX;i++)
315 d->lspc[i].range = PLX_LOCSPC_RANGE_DEFAULT;
316
317 dev_init(&d->plx_dev);
318 d->plx_dev.name = name;
319 d->plx_dev.priv_data = d;
320 d->plx_dev.phys_addr = 0;
321 d->plx_dev.phys_len = 0x1000;
322 d->plx_dev.handler = dev_plx_access;
323 return(d);
324 }
325
326 /* Create a PLX9060 device */
327 vm_obj_t *dev_plx9060_init(vm_instance_t *vm,char *name,
328 struct pci_bus *pci_bus,int pci_device,
329 struct vdevice *dev0)
330 {
331 struct plx_data *d;
332
333 /* Create the PLX data */
334 if (!(d = dev_plx_init(vm,name))) {
335 fprintf(stderr,"PLX: unable to create device.\n");
336 return NULL;
337 }
338
339 /* Set the PLX variant */
340 d->variant = 9060;
341
342 /* Set device for Local Space 0 */
343 d->lspc[0].dev = dev0;
344
345 /* Add PLX as a PCI device */
346 d->pci_plx_dev = pci_dev_add(pci_bus,name,
347 PLX_PCI_VENDOR_ID,PLX9060_PCI_PRODUCT_ID,
348 pci_device,0,-1,d,
349 NULL,pci_plx_read,pci_plx_write);
350
351 if (!d->pci_plx_dev) {
352 fprintf(stderr,"%s (PLX9060): unable to create PCI device.\n",name);
353 goto err_pci_dev;
354 }
355
356 vm_object_add(vm,&d->vm_obj);
357 return(&d->vm_obj);
358
359 err_pci_dev:
360 free(d);
361 return NULL;
362 }
363
364 /* Create a PLX9054 device */
365 vm_obj_t *dev_plx9054_init(vm_instance_t *vm,char *name,
366 struct pci_bus *pci_bus,int pci_device,
367 struct vdevice *dev0,struct vdevice *dev1)
368 {
369 struct plx_data *d;
370
371 /* Create the PLX data */
372 if (!(d = dev_plx_init(vm,name))) {
373 fprintf(stderr,"PLX: unable to create device.\n");
374 return NULL;
375 }
376
377 /* Set the PLX variant */
378 d->variant = 9054;
379 d->plx_dev.handler = dev_plx9054_access;
380
381 /* Set device for Local Space 0 and 1 */
382 d->lspc[0].dev = dev0;
383 d->lspc[1].dev = dev1;
384
385 /* Add PLX as a PCI device */
386 d->pci_plx_dev = pci_dev_add(pci_bus,name,
387 PLX_PCI_VENDOR_ID,PLX9054_PCI_PRODUCT_ID,
388 pci_device,0,-1,d,
389 NULL,pci_plx9054_read,pci_plx9054_write);
390
391 if (!d->pci_plx_dev) {
392 fprintf(stderr,"%s (PLX9054): unable to create PCI device.\n",name);
393 goto err_pci_dev;
394 }
395
396 vm_object_add(vm,&d->vm_obj);
397 return(&d->vm_obj);
398
399 err_pci_dev:
400 free(d);
401 return NULL;
402 }
403
404 /* Set callback function for PCI-to-Local doorbell register */
405 void dev_plx_set_pci2loc_doorbell_cbk(struct plx_data *d,
406 dev_plx_doorbell_cbk cbk,
407 void *arg)
408 {
409 if (d != NULL) {
410 d->pci2loc_doorbell_cbk = cbk;
411 d->pci2loc_doorbell_cbk_arg = arg;
412 }
413 }
414
415 /* Set the Local-to-PCI doorbell register (for Local device use) */
416 void dev_plx_set_loc2pci_doorbell_reg(struct plx_data *d,m_uint32_t value)
417 {
418 if (d != NULL)
419 d->loc2pci_doorbell_reg = value;
420 }

  ViewVC Help
Powered by ViewVC 1.1.26