/[dynamips]/upstream/dynamips-0.2.5/pci_dev.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.5/pci_dev.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Sat Oct 6 16:01:44 2007 UTC (12 years, 3 months ago) by dpavlin
File MIME type: text/plain
File size: 14929 byte(s)
import 0.2.5 from upstream

1 dpavlin 1 /*
2     * Cisco 7200 (Predator) simulation platform.
3     * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4     *
5     * PCI devices.
6     *
7     * Very interesting docs:
8     * http://www.science.unitn.it/~fiorella/guidelinux/tlk/node72.html
9     * http://www.science.unitn.it/~fiorella/guidelinux/tlk/node76.html
10     */
11    
12     #include <stdio.h>
13     #include <stdlib.h>
14     #include <string.h>
15     #include <unistd.h>
16     #include <sys/types.h>
17    
18     #include "mips64.h"
19     #include "dynamips.h"
20     #include "memory.h"
21     #include "device.h"
22     #include "vm.h"
23    
24     #define DEBUG_PCI 1
25    
26     #define GET_PCI_ADDR(offset,mask) ((pci_bus->pci_addr >> offset) & mask)
27    
28     /* Trigger a PCI device IRQ */
29     void pci_dev_trigger_irq(vm_instance_t *vm,struct pci_device *dev)
30     {
31     if (dev->irq != -1)
32     vm_set_irq(vm,dev->irq);
33     }
34    
35     /* Clear a PCI device IRQ */
36     void pci_dev_clear_irq(vm_instance_t *vm,struct pci_device *dev)
37     {
38     if (dev->irq != -1)
39     vm_clear_irq(vm,dev->irq);
40     }
41    
42     /* Swapping function */
43     static inline m_uint32_t pci_swap(m_uint32_t val,int swap)
44     {
45     return((swap) ? swap32(val) : val);
46     }
47    
48     /* PCI bus lookup */
49     struct pci_bus *pci_bus_lookup(struct pci_bus *pci_bus_root,int bus)
50     {
51     struct pci_bus *next_bus,*cur_bus = pci_bus_root;
52     struct pci_bridge *bridge;
53    
54     while(cur_bus != NULL) {
55     if (cur_bus->bus == bus)
56     return cur_bus;
57    
58     /* Try busses behind PCI bridges */
59     next_bus = NULL;
60    
61     for(bridge=cur_bus->bridge_list;bridge;bridge=bridge->next) {
62     /*
63     * Specific case: final bridge with no checking of secondary
64     * bus number. Dynamically programming.
65     */
66     if (bridge->skip_bus_check) {
67     pci_bridge_set_bus_info(bridge,cur_bus->bus,bus,bus);
68     bridge->skip_bus_check = FALSE;
69     return bridge->pci_bus;
70     }
71    
72     if ((bus >= bridge->sec_bus) && (bus <= bridge->sub_bus)) {
73     next_bus = bridge->pci_bus;
74     break;
75     }
76     }
77    
78     cur_bus = next_bus;
79     }
80    
81     return NULL;
82     }
83    
84     /* PCI device local lookup */
85     struct pci_device *pci_dev_lookup_local(struct pci_bus *pci_bus,
86     int device,int function)
87     {
88     struct pci_device *dev;
89    
90     for(dev=pci_bus->dev_list;dev;dev=dev->next)
91     if ((dev->device == device) && (dev->function == function))
92     return dev;
93    
94     return NULL;
95     }
96    
97     /* PCI Device lookup */
98     struct pci_device *pci_dev_lookup(struct pci_bus *pci_bus_root,
99     int bus,int device,int function)
100     {
101     struct pci_bus *req_bus;
102    
103     /* Find, try to find the request bus */
104     if (!(req_bus = pci_bus_lookup(pci_bus_root,bus)))
105     return NULL;
106    
107     /* Walk through devices present on this bus */
108     return pci_dev_lookup_local(req_bus,device,function);
109     }
110    
111     /* Handle the address register access */
112     void pci_dev_addr_handler(cpu_mips_t *cpu,struct pci_bus *pci_bus,
113     u_int op_type,int swap,m_uint64_t *data)
114     {
115     if (op_type == MTS_WRITE)
116     pci_bus->pci_addr = pci_swap(*data,swap);
117     else
118     *data = pci_swap(pci_bus->pci_addr,swap);
119     }
120    
121     /*
122     * Handle the data register access.
123     *
124     * The address of requested register is first written at address 0xcf8
125     * (with pci_dev_addr_handler).
126     *
127     * The data is read/written at address 0xcfc.
128     */
129     void pci_dev_data_handler(cpu_mips_t *cpu,struct pci_bus *pci_bus,
130     u_int op_type,int swap,m_uint64_t *data)
131     {
132     struct pci_device *dev;
133     int bus,device,function,reg;
134    
135     if (op_type == MTS_READ)
136     *data = 0;
137    
138     /*
139     * http://www.mega-tokyo.com/osfaq2/index.php/PciSectionOfPentiumVme
140     *
141     * 31 : Enable Bit
142     * 30 - 24 : Reserved
143     * 23 - 16 : Bus Number
144     * 15 - 11 : Device Number
145     * 10 - 8 : Function Number
146     * 7 - 2 : Register Number
147     * 1 - 0 : always 00
148     */
149     bus = GET_PCI_ADDR(16,0xff);
150     device = GET_PCI_ADDR(11,0x1f);
151     function = GET_PCI_ADDR(8,0x7);
152     reg = GET_PCI_ADDR(0,0xff);
153    
154     /* Find the corresponding PCI device */
155     dev = pci_dev_lookup(pci_bus,bus,device,function);
156    
157     #if DEBUG_PCI
158     if (op_type == MTS_READ) {
159     cpu_log(cpu,"PCI","read request at pc=0x%llx: "
160     "bus=%d,device=%d,function=%d,reg=0x%2.2x\n",
161     cpu->pc, bus, device, function, reg);
162     } else {
163     cpu_log(cpu,"PCI","write request (data=0x%8.8x) at pc=0x%llx: "
164     "bus=%d,device=%d,function=%d,reg=0x%2.2x\n",
165     pci_swap(*data,swap), cpu->pc, bus, device, function, reg);
166     }
167     #endif
168    
169     if (!dev) {
170     if (op_type == MTS_READ) {
171     cpu_log(cpu,"PCI","read request for unknown device at pc=0x%llx "
172     "(bus=%d,device=%d,function=%d,reg=0x%2.2x).\n",
173     cpu->pc, bus, device, function, reg);
174     } else {
175     cpu_log(cpu,"PCI","write request (data=0x%8.8x) for unknown device "
176     "at pc=0x%llx (bus=%d,device=%d,function=%d,reg=0x%2.2x).\n",
177     pci_swap(*data,swap), cpu->pc, bus, device, function, reg);
178     }
179    
180     /* Returns an invalid device ID */
181     if ((op_type == MTS_READ) && (reg == PCI_REG_ID))
182     *data = 0xffffffff;
183     } else {
184     if (op_type == MTS_WRITE) {
185     if (dev->write_register != NULL)
186     dev->write_register(cpu,dev,reg,pci_swap(*data,swap));
187     } else {
188     if (reg == PCI_REG_ID)
189     *data = pci_swap((dev->product_id << 16) | dev->vendor_id,swap);
190     else {
191     if (dev->read_register != NULL)
192     *data = pci_swap(dev->read_register(cpu,dev,reg),swap);
193     }
194     }
195     }
196     }
197    
198     /* Add a PCI bridge */
199     struct pci_bridge *pci_bridge_add(struct pci_bus *pci_bus)
200     {
201     struct pci_bridge *bridge;
202    
203     if (!pci_bus)
204     return NULL;
205    
206     if (!(bridge = malloc(sizeof(*bridge)))) {
207     fprintf(stderr,"pci_bridge_add: unable to create new PCI bridge.\n");
208     return NULL;
209     }
210    
211     memset(bridge,0,sizeof(*bridge));
212     bridge->pri_bus = pci_bus->bus;
213     bridge->sec_bus = -1;
214     bridge->sub_bus = -1;
215     bridge->pci_bus = NULL;
216    
217     /* Insert the bridge in the double-linked list */
218     bridge->next = pci_bus->bridge_list;
219     bridge->pprev = &pci_bus->bridge_list;
220    
221     if (pci_bus->bridge_list != NULL)
222     pci_bus->bridge_list->pprev = &bridge->next;
223    
224     pci_bus->bridge_list = bridge;
225     return bridge;
226     }
227    
228     /* Remove a PCI bridge from the double-linked list */
229     static inline void pci_bridge_remove_from_list(struct pci_bridge *bridge)
230     {
231     if (bridge->next)
232     bridge->next->pprev = bridge->pprev;
233    
234     if (bridge->pprev)
235     *(bridge->pprev) = bridge->next;
236     }
237    
238     /* Remove a PCI bridge */
239     void pci_bridge_remove(struct pci_bridge *bridge)
240     {
241     if (bridge != NULL) {
242     pci_bridge_remove_from_list(bridge);
243     free(bridge);
244     }
245     }
246    
247     /* Map secondary bus to a PCI bridge */
248     void pci_bridge_map_bus(struct pci_bridge *bridge,struct pci_bus *pci_bus)
249     {
250     if (bridge != NULL) {
251     bridge->pci_bus = pci_bus;
252    
253     if (bridge->pci_bus != NULL)
254     bridge->pci_bus->bus = bridge->sec_bus;
255     }
256     }
257    
258     /* Set PCI bridge bus info */
259     void pci_bridge_set_bus_info(struct pci_bridge *bridge,
260     int pri_bus,int sec_bus,int sub_bus)
261     {
262     if (bridge != NULL) {
263     bridge->pri_bus = pri_bus;
264     bridge->sec_bus = sec_bus;
265     bridge->sub_bus = sub_bus;
266    
267     if (bridge->pci_bus != NULL)
268     bridge->pci_bus->bus = bridge->sec_bus;
269     }
270     }
271    
272     /* Add a PCI device */
273     struct pci_device *
274     pci_dev_add(struct pci_bus *pci_bus,char *name,
275     u_int vendor_id,u_int product_id,
276     int device,int function,int irq,
277     void *priv_data,pci_init_t init,
278     pci_reg_read_t read_register,
279     pci_reg_write_t write_register)
280     {
281     struct pci_device *dev;
282    
283     if (!pci_bus)
284     return NULL;
285    
286     if ((dev = pci_dev_lookup_local(pci_bus,device,function)) != NULL) {
287     fprintf(stderr,"pci_dev_add: bus %s, device %d, function %d already "
288     "registered (device '%s').\n",
289     pci_bus->name,device,function,dev->name);
290     return NULL;
291     }
292    
293     /* we can create safely the new device */
294     if (!(dev = malloc(sizeof(*dev)))) {
295     fprintf(stderr,"pci_dev_add: unable to create new PCI device.\n");
296     return NULL;
297     }
298    
299     memset(dev,0,sizeof(*dev));
300     dev->name = name;
301     dev->vendor_id = vendor_id;
302     dev->product_id = product_id;
303     dev->pci_bus = pci_bus;
304     dev->device = device;
305     dev->function = function;
306     dev->irq = irq;
307     dev->priv_data = priv_data;
308     dev->init = init;
309     dev->read_register = read_register;
310     dev->write_register = write_register;
311    
312     /* Insert the device in the double-linked list */
313     dev->next = pci_bus->dev_list;
314     dev->pprev = &pci_bus->dev_list;
315    
316     if (pci_bus->dev_list != NULL)
317     pci_bus->dev_list->pprev = &dev->next;
318    
319     pci_bus->dev_list = dev;
320    
321     if (init) init(dev);
322     return dev;
323     }
324    
325     /* Add a basic PCI device that just returns a Vendor/Product ID */
326     struct pci_device *
327     pci_dev_add_basic(struct pci_bus *pci_bus,
328     char *name,u_int vendor_id,u_int product_id,
329     int device,int function)
330     {
331     return(pci_dev_add(pci_bus,name,vendor_id,product_id,
332     device,function,-1,NULL,
333     NULL,NULL,NULL));
334     }
335    
336     /* Remove a device from the double-linked list */
337     static inline void pci_dev_remove_from_list(struct pci_device *dev)
338     {
339     if (dev->next)
340     dev->next->pprev = dev->pprev;
341    
342     if (dev->pprev)
343     *(dev->pprev) = dev->next;
344     }
345    
346     /* Remove a PCI device */
347     void pci_dev_remove(struct pci_device *dev)
348     {
349     if (dev != NULL) {
350     pci_dev_remove_from_list(dev);
351     free(dev);
352     }
353     }
354    
355     /* Remove a PCI device given its ID (bus,device,function) */
356     int pci_dev_remove_by_id(struct pci_bus *pci_bus,
357     int bus,int device,int function)
358     {
359     struct pci_device *dev;
360    
361     if (!(dev = pci_dev_lookup(pci_bus,bus,device,function)))
362     return(-1);
363    
364     pci_dev_remove(dev);
365     return(0);
366     }
367    
368     /* Remove a PCI device given its name */
369     int pci_dev_remove_by_name(struct pci_bus *pci_bus,char *name)
370     {
371     struct pci_device *dev,*next;
372     int count = 0;
373    
374     for(dev=pci_bus->dev_list;dev;dev=next) {
375     next = dev->next;
376    
377     if (!strcmp(dev->name,name)) {
378     pci_dev_remove(dev);
379     count++;
380     }
381     }
382    
383     return(count);
384     }
385    
386     /* Create a PCI bus */
387     struct pci_bus *pci_bus_create(char *name,int bus)
388     {
389     struct pci_bus *d;
390    
391     if (!(d = malloc(sizeof(*d)))) {
392     fprintf(stderr,"pci_bus_create: unable to create PCI info.\n");
393     return NULL;
394     }
395    
396     memset(d,0,sizeof(*d));
397     d->name = strdup(name);
398     d->bus = bus;
399     return d;
400     }
401    
402     /* Delete a PCI bus */
403     void pci_bus_remove(struct pci_bus *pci_bus)
404     {
405     struct pci_device *dev,*next;
406     struct pci_bridge *bridge,*next_bridge;
407    
408     if (pci_bus) {
409     /* Remove all devices */
410     for(dev=pci_bus->dev_list;dev;dev=next) {
411     next = dev->next;
412     free(dev);
413     }
414    
415     /* Remove all bridges */
416     for(bridge=pci_bus->bridge_list;bridge;bridge=next_bridge) {
417     next_bridge = bridge->next;
418     free(bridge);
419     }
420    
421     /* Free the structure itself */
422     free(pci_bus->name);
423     free(pci_bus);
424     }
425     }
426    
427     /* Read a configuration register of a PCI bridge */
428     static m_uint32_t pci_bridge_read_reg(cpu_mips_t *cpu,struct pci_device *dev,
429     int reg)
430     {
431     struct pci_bridge *bridge = dev->priv_data;
432     m_uint32_t val = 0;
433    
434     switch(reg) {
435     case 0x18:
436     return(bridge->cfg_reg_bus);
437     default:
438     if (bridge->fallback_read != NULL)
439     val = bridge->fallback_read(cpu,dev,reg);
440    
441     /* Returns appropriate PCI bridge class code if nothing defined */
442     if ((reg == 0x08) && !val)
443     val = 0x06040000;
444    
445     return(val);
446     }
447     }
448    
449     /* Write a configuration register of a PCI bridge */
450     static void pci_bridge_write_reg(cpu_mips_t *cpu,struct pci_device *dev,
451     int reg,m_uint32_t value)
452     {
453     struct pci_bridge *bridge = dev->priv_data;
454     u_int pri_bus,sec_bus,sub_bus;
455    
456     switch(reg) {
457     case 0x18:
458     bridge->cfg_reg_bus = value;
459     sub_bus = (value >> 16) & 0xFF;
460     sec_bus = (value >> 8) & 0xFF;
461     pri_bus = value & 0xFF;
462    
463     /* Modify the PCI bridge settings */
464     vm_log(cpu->vm,"PCI",
465     "PCI bridge %d,%d,%d -> pri: %2.2u, sec: %2.2u, sub: %2.2u\n",
466     dev->pci_bus->bus,dev->device,dev->function,
467     pri_bus,sec_bus,sub_bus);
468    
469     pci_bridge_set_bus_info(bridge,pri_bus,sec_bus,sub_bus);
470     break;
471    
472     default:
473     if (bridge->fallback_write != NULL)
474     bridge->fallback_write(cpu,dev,reg,value);
475     }
476     }
477    
478     /* Create a PCI bridge device */
479     struct pci_device *pci_bridge_create_dev(struct pci_bus *pci_bus,char *name,
480     u_int vendor_id,u_int product_id,
481     int device,int function,
482     struct pci_bus *sec_bus,
483     pci_reg_read_t fallback_read,
484     pci_reg_write_t fallback_write)
485     {
486     struct pci_bridge *bridge;
487     struct pci_device *dev;
488    
489     /* Create the PCI bridge structure */
490     if (!(bridge = pci_bridge_add(pci_bus)))
491     return NULL;
492    
493     /* Create the PCI device corresponding to the bridge */
494     dev = pci_dev_add(pci_bus,name,vendor_id,product_id,device,function,-1,
495     bridge,NULL,pci_bridge_read_reg,pci_bridge_write_reg);
496    
497     if (!dev)
498     goto err_pci_dev;
499    
500     /* Keep the associated PCI device for this bridge */
501     bridge->pci_dev = dev;
502    
503     /* Set the fallback functions */
504     bridge->fallback_read = fallback_read;
505     bridge->fallback_write = fallback_write;
506    
507     /* Map the secondary bus (disabled at startup) */
508     pci_bridge_map_bus(bridge,sec_bus);
509     return dev;
510    
511     err_pci_dev:
512     pci_bridge_remove(bridge);
513     return NULL;
514     }
515    
516     /* Show PCI device list of the specified bus */
517     static void pci_bus_show_dev_list(struct pci_bus *pci_bus)
518     {
519     struct pci_device *dev;
520     struct pci_bridge *bridge;
521     char bus_id[32];
522    
523     if (!pci_bus)
524     return;
525    
526     if (pci_bus->bus != -1) {
527     snprintf(bus_id,sizeof(bus_id),"%2d",pci_bus->bus);
528     } else {
529     strcpy(bus_id,"XX");
530     }
531    
532     for(dev=pci_bus->dev_list;dev;dev=dev->next) {
533     printf(" %-18s: ID %4.4x:%4.4x, Bus %s, Dev. %2d, Func. %2d",
534     dev->name,dev->vendor_id,dev->product_id,
535     bus_id,dev->device,dev->function);
536    
537     if (dev->irq != -1)
538     printf(", IRQ: %d\n",dev->irq);
539     else
540     printf("\n");
541     }
542    
543     for(bridge=pci_bus->bridge_list;bridge;bridge=bridge->next)
544     pci_bus_show_dev_list(bridge->pci_bus);
545     }
546    
547     /* Show PCI device list */
548     void pci_dev_show_list(struct pci_bus *pci_bus)
549     {
550     if (!pci_bus)
551     return;
552    
553     printf("PCI Bus \"%s\" Device list:\n",pci_bus->name);
554     pci_bus_show_dev_list(pci_bus);
555     printf("\n");
556     }

  ViewVC Help
Powered by ViewVC 1.1.26