/[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 4 - (hide 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 dpavlin 4 /*
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