/[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 4 - (show annotations)
Sat Oct 6 16:06:49 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC3/dev_plx.c
File MIME type: text/plain
File size: 10305 byte(s)
dynamips-0.2.6-RC3

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

  ViewVC Help
Powered by ViewVC 1.1.26