/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (hide 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 dpavlin 4 /*
2 dpavlin 7 * Cisco router simulation platform.
3 dpavlin 4 * 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 dpavlin 7 #include "cpu.h"
16     #include "vm.h"
17 dpavlin 4 #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 dpavlin 7 void *dev_plx_access(cpu_gen_t *cpu,struct vdevice *dev,
91 dpavlin 4 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 dpavlin 7 offset,cpu_get_pc(cpu),op_size);
135 dpavlin 4 } else {
136     cpu_log(cpu,d->name,
137     "write to handled addr 0x%x, value=0x%llx, "
138 dpavlin 7 "pc=0x%llx (size=%u)\n",
139     offset,*data,cpu_get_pc(cpu),op_size);
140 dpavlin 4 }
141     }
142    
143     return NULL;
144     }
145    
146     /* PLX9054 access routine */
147 dpavlin 7 void *dev_plx9054_access(cpu_gen_t *cpu,struct vdevice *dev,
148 dpavlin 4 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 dpavlin 7 static m_uint32_t pci_plx_read(cpu_gen_t *cpu,struct pci_device *dev,int reg)
178 dpavlin 4 {
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 dpavlin 7 static void pci_plx_write(cpu_gen_t *cpu,struct pci_device *dev,
202 dpavlin 4 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 dpavlin 7 static m_uint32_t pci_plx9054_read(cpu_gen_t *cpu,struct pci_device *dev,
229 dpavlin 4 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 dpavlin 7 static void pci_plx9054_write(cpu_gen_t *cpu,struct pci_device *dev,
250 dpavlin 4 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