/[dynamips]/upstream/dynamips-0.2.6-RC3/dev_c7200.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.6-RC3/dev_c7200.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations)
Sat Oct 6 16:03:58 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC1/dev_c7200.c
File MIME type: text/plain
File size: 63762 byte(s)
import dynamips-0.2.6-RC1

1 dpavlin 1 /*
2     * Cisco 7200 (Predator) simulation platform.
3     * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4     *
5     * Generic Cisco 7200 routines and definitions (EEPROM,...).
6     */
7    
8     #include <stdio.h>
9     #include <stdlib.h>
10     #include <string.h>
11     #include <unistd.h>
12     #include <sys/types.h>
13     #include <assert.h>
14    
15     #include "mips64.h"
16     #include "dynamips.h"
17     #include "memory.h"
18     #include "device.h"
19     #include "pci_io.h"
20     #include "cisco_eeprom.h"
21     #include "dev_c7200.h"
22     #include "dev_vtty.h"
23     #include "registry.h"
24     #include "net.h"
25    
26     /* ======================================================================== */
27     /* CPU EEPROM definitions */
28     /* ======================================================================== */
29    
30     /* NPE-100 */
31     static m_uint16_t eeprom_cpu_npe100_data[16] = {
32     0x0135, 0x0203, 0xffff, 0xffff, 0x4906, 0x0004, 0x0000, 0x0000,
33     0x6000, 0x0000, 0x9901, 0x0600, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
34     };
35    
36     /* NPE-150 */
37     static m_uint16_t eeprom_cpu_npe150_data[16] = {
38     0x0115, 0x0203, 0xffff, 0xffff, 0x4906, 0x0004, 0x0000, 0x0000,
39     0x6000, 0x0000, 0x9901, 0x0600, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
40     };
41    
42     /* NPE-175 */
43     static m_uint16_t eeprom_cpu_npe175_data[16] = {
44     0x01C2, 0x0203, 0xffff, 0xffff, 0x4906, 0x0004, 0x0000, 0x0000,
45     0x6000, 0x0000, 0x9901, 0x0600, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
46     };
47    
48     /* NPE-200 */
49     static m_uint16_t eeprom_cpu_npe200_data[16] = {
50     0x0169, 0x0200, 0xffff, 0xffff, 0x4909, 0x8902, 0x0000, 0x0000,
51     0x6800, 0x0000, 0x9710, 0x2200, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
52     };
53    
54     /* NPE-225 (same as NPE-175) */
55     static m_uint16_t eeprom_cpu_npe225_data[16] = {
56     0x01C2, 0x0203, 0xffff, 0xffff, 0x4906, 0x0004, 0x0000, 0x0000,
57     0x6000, 0x0000, 0x9901, 0x0600, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
58     };
59    
60     /* NPE-300 */
61     static m_uint16_t eeprom_cpu_npe300_data[16] = {
62     0x01AE, 0x0402, 0xffff, 0xffff, 0x490D, 0x5108, 0x0000, 0x0000,
63     0x5000, 0x0000, 0x0012, 0x1000, 0x0000, 0xFFFF, 0xFFFF, 0xFF00,
64     };
65    
66     /* NPE-400 */
67     static m_uint16_t eeprom_cpu_npe400_data[64] = {
68     0x04FF, 0x4001, 0xF841, 0x0100, 0xC046, 0x0320, 0x001F, 0xC802,
69     0x8249, 0x14BC, 0x0242, 0x4230, 0xC18B, 0x3131, 0x3131, 0x3131,
70     0x3131, 0x0000, 0x0004, 0x0002, 0x0285, 0x1C0F, 0xF602, 0xCB87,
71     0x4E50, 0x452D, 0x3430, 0x3080, 0x0000, 0x0000, 0xFFFF, 0xFFFF,
72     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
73     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
74     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
75     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
76     };
77    
78     /* NPE-G1 */
79     static m_uint16_t eeprom_cpu_npeg1_data[64] = {
80     0x04FF, 0x4003, 0x5B41, 0x0200, 0xC046, 0x0320, 0x0049, 0xD00B,
81     0x8249, 0x1B4C, 0x0B42, 0x4130, 0xC18B, 0x3131, 0x3131, 0x3131,
82     0x3131, 0x0000, 0x0004, 0x0002, 0x0985, 0x1C13, 0xDA09, 0xCB86,
83     0x4E50, 0x452D, 0x4731, 0x8000, 0x0000, 0x00FF, 0xFFFF, 0xFFFF,
84     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
85     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
86     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
87     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
88     };
89    
90     /*
91     * CPU EEPROM array.
92     */
93     static struct c7200_eeprom c7200_cpu_eeprom[] = {
94     { "npe-100", eeprom_cpu_npe100_data, sizeof(eeprom_cpu_npe100_data)/2 },
95     { "npe-150", eeprom_cpu_npe150_data, sizeof(eeprom_cpu_npe150_data)/2 },
96     { "npe-175", eeprom_cpu_npe175_data, sizeof(eeprom_cpu_npe175_data)/2 },
97     { "npe-200", eeprom_cpu_npe200_data, sizeof(eeprom_cpu_npe200_data)/2 },
98     { "npe-225", eeprom_cpu_npe225_data, sizeof(eeprom_cpu_npe225_data)/2 },
99     { "npe-300", eeprom_cpu_npe300_data, sizeof(eeprom_cpu_npe300_data)/2 },
100     { "npe-400", eeprom_cpu_npe400_data, sizeof(eeprom_cpu_npe400_data)/2 },
101     { "npe-g1" , eeprom_cpu_npeg1_data , sizeof(eeprom_cpu_npeg1_data)/2 },
102     { NULL, NULL, 0 },
103     };
104    
105     /* ======================================================================== */
106     /* Midplane EEPROM definitions */
107     /* ======================================================================== */
108    
109     /* Standard Midplane EEPROM contents */
110     static m_uint16_t eeprom_midplane_data[32] = {
111     0x0106, 0x0101, 0xffff, 0xffff, 0x4906, 0x0303, 0xFFFF, 0xFFFF,
112     0xFFFF, 0x0400, 0x0000, 0x0000, 0x4C09, 0x10B0, 0xFFFF, 0x00FF,
113     0x0000, 0x0000, 0x6335, 0x8B28, 0x631D, 0x0000, 0x608E, 0x6D1C,
114     0x62BB, 0x0000, 0x6335, 0x8B28, 0x0000, 0x0000, 0x6335, 0x8B28,
115     };
116    
117     /* VXR Midplane EEPROM contents */
118     static m_uint16_t eeprom_vxr_midplane_data[32] = {
119     0x0106, 0x0201, 0xffff, 0xffff, 0x4906, 0x0303, 0xFFFF, 0xFFFF,
120     0xFFFF, 0x0400, 0x0000, 0x0000, 0x4C09, 0x10B0, 0xFFFF, 0x00FF,
121     0x0000, 0x0000, 0x6335, 0x8B28, 0x631D, 0x0000, 0x608E, 0x6D1C,
122     0x62BB, 0x0000, 0x6335, 0x8B28, 0x0000, 0x0000, 0x6335, 0x8B28,
123     };
124    
125     /*
126     * Midplane EEPROM array.
127     */
128     static struct c7200_eeprom c7200_midplane_eeprom[] = {
129     { "std", eeprom_midplane_data, sizeof(eeprom_midplane_data)/2 },
130     { "vxr", eeprom_vxr_midplane_data, sizeof(eeprom_vxr_midplane_data)/2 },
131     { NULL, NULL, 0 },
132     };
133    
134     /* ======================================================================== */
135     /* PEM EEPROM definitions (for NPE-175 and NPE-225) */
136     /* ======================================================================== */
137    
138     /* NPE-175 */
139     static m_uint16_t eeprom_pem_npe175_data[16] = {
140     0x01C3, 0x0100, 0xFFFF, 0xFFFF, 0x490D, 0x8A04, 0x0000, 0x0000,
141     0x5000, 0x0000, 0x9906, 0x0400, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF,
142     };
143    
144     /* NPE-225 */
145     static m_uint16_t eeprom_pem_npe225_data[16] = {
146     0x01D5, 0x0100, 0xFFFF, 0xFFFF, 0x490D, 0x8A04, 0x0000, 0x0000,
147     0x5000, 0x0000, 0x9906, 0x0400, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF,
148     };
149    
150     /*
151     * PEM EEPROM array.
152     */
153     static struct c7200_eeprom c7200_pem_eeprom[] = {
154     { "npe-175", eeprom_pem_npe175_data, sizeof(eeprom_pem_npe175_data)/2 },
155     { "npe-225", eeprom_pem_npe225_data, sizeof(eeprom_pem_npe225_data)/2 },
156     { NULL, NULL, 0 },
157     };
158    
159     /* ======================================================================== */
160     /* Port Adapter Drivers */
161     /* ======================================================================== */
162     static struct c7200_pa_driver *pa_drivers[] = {
163     &dev_c7200_io_fe_driver,
164     &dev_c7200_pa_fe_tx_driver,
165     &dev_c7200_pa_4e_driver,
166     &dev_c7200_pa_8e_driver,
167     &dev_c7200_pa_4t_driver,
168     &dev_c7200_pa_8t_driver,
169     &dev_c7200_pa_a1_driver,
170     &dev_c7200_pa_pos_oc3_driver,
171     &dev_c7200_pa_4b_driver,
172     NULL,
173     };
174    
175     /* ======================================================================== */
176     /* NPE Drivers */
177     /* ======================================================================== */
178     #define DECLARE_NPE(type) \
179     int (c7200_init_##type)(c7200_t *router)
180    
181     DECLARE_NPE(npe100);
182     DECLARE_NPE(npe150);
183     DECLARE_NPE(npe175);
184     DECLARE_NPE(npe200);
185     DECLARE_NPE(npe225);
186     DECLARE_NPE(npe300);
187     DECLARE_NPE(npe400);
188     DECLARE_NPE(npeg1);
189    
190     static struct c7200_npe_driver npe_drivers[] = {
191     { "npe-100" , c7200_init_npe100, 256, 1, C7200_NVRAM_ADDR, 0, 5, 0, 6 },
192     { "npe-150" , c7200_init_npe150, 256, 1, C7200_NVRAM_ADDR, 0, 5, 0, 6 },
193     { "npe-175" , c7200_init_npe175, 256, 1, C7200_NVRAM_ADDR, 2, 16, 1, 0 },
194     { "npe-200" , c7200_init_npe200, 256, 1, C7200_NVRAM_ADDR, 0, 5, 0, 6 },
195     { "npe-225" , c7200_init_npe225, 256, 1, C7200_NVRAM_ADDR, 2, 16, 1, 0 },
196     { "npe-300" , c7200_init_npe300, 256, 1, C7200_NVRAM_ADDR, 2, 16, 1, 0 },
197     { "npe-400" , c7200_init_npe400, 512, 1, C7200_NVRAM_ADDR, 2, 16, 1, 0 },
198     { "npe-g1" , c7200_init_npeg1, 1024, 0,
199     C7200_NPEG1_NVRAM_ADDR, 17, 16, 16, 0 },
200     { NULL , NULL },
201     };
202    
203     /* ======================================================================== */
204     /* Empty EEPROM for PAs */
205     /* ======================================================================== */
206     static const m_uint16_t eeprom_pa_empty[64] = {
207     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
208     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
209     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
210     0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
211     };
212    
213     /* ======================================================================== */
214     /* Cisco 7200 router instances */
215     /* ======================================================================== */
216    
217     /* Directly extract the configuration from the NVRAM device */
218     ssize_t c7200_nvram_extract_config(vm_instance_t *vm,char **buffer)
219     {
220     struct vdevice *nvram_dev;
221     m_uint32_t start,end,clen,nvlen;
222     m_uint16_t magic1,magic2;
223     m_uint64_t addr;
224    
225     if (!(nvram_dev = dev_get_by_name(vm,"nvram")))
226     return(-1);
227    
228     addr = nvram_dev->phys_addr + vm->nvram_rom_space;
229     magic1 = physmem_copy_u16_from_vm(vm,addr+0x06);
230     magic2 = physmem_copy_u16_from_vm(vm,addr+0x08);
231    
232     if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) {
233     vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n",
234     magic1,magic2);
235     return(-1);
236     }
237    
238     start = physmem_copy_u32_from_vm(vm,addr+0x10) + 1;
239     end = physmem_copy_u32_from_vm(vm,addr+0x14);
240     nvlen = physmem_copy_u32_from_vm(vm,addr+0x18);
241     clen = end - start;
242    
243     if ((clen + 1) != nvlen) {
244     vm_error(vm,"invalid configuration size (0x%x)\n",nvlen);
245     return(-1);
246     }
247    
248     if ((start <= nvram_dev->phys_addr) || (end <= nvram_dev->phys_addr) ||
249     (end <= start))
250     {
251     vm_error(vm,"invalid configuration markers (start=0x%x,end=0x%x)\n",
252     start,end);
253     return(-1);
254     }
255    
256     if (!(*buffer = malloc(clen+1))) {
257     vm_error(vm,"unable to allocate config buffer (%u bytes)\n",clen);
258     return(-1);
259     }
260    
261     physmem_copy_from_vm(vm,*buffer,start,clen);
262     (*buffer)[clen] = 0;
263     return(clen);
264     }
265    
266     /* Directly push the IOS configuration to the NVRAM device */
267     int c7200_nvram_push_config(vm_instance_t *vm,char *buffer,size_t len)
268     {
269     struct vdevice *nvram_dev;
270 dpavlin 2 m_uint64_t addr,cfg_addr;
271     m_uint32_t cklen;
272     m_uint16_t cksum;
273 dpavlin 1
274     if (!(nvram_dev = dev_get_by_name(vm,"nvram")))
275     return(-1);
276    
277     addr = nvram_dev->phys_addr + vm->nvram_rom_space;
278 dpavlin 2 cfg_addr = addr + 0x2c;
279 dpavlin 1
280     /* Write IOS tag, uncompressed config... */
281     physmem_copy_u16_to_vm(vm,addr+0x06,0xF0A5);
282     physmem_copy_u16_to_vm(vm,addr+0x08,0xABCD); /* Magic number */
283     physmem_copy_u16_to_vm(vm,addr+0x0a,0x0001); /* ??? */
284     physmem_copy_u16_to_vm(vm,addr+0x0c,0x0000); /* zero */
285 dpavlin 2 physmem_copy_u16_to_vm(vm,addr+0x0e,0x0000); /* IOS version */
286 dpavlin 1
287     /* Store file contents to NVRAM */
288     physmem_copy_to_vm(vm,buffer,cfg_addr,len);
289    
290     /* Write config addresses + size */
291 dpavlin 2 physmem_copy_u32_to_vm(vm,addr+0x10,cfg_addr);
292     physmem_copy_u32_to_vm(vm,addr+0x14,cfg_addr + len);
293     physmem_copy_u32_to_vm(vm,addr+0x18,len);
294    
295     /* Compute the checksum */
296     cklen = nvram_dev->phys_len - (vm->nvram_rom_space + 0x08);
297     cksum = nvram_cksum(vm,addr+0x08,cklen);
298     physmem_copy_u16_to_vm(vm,addr+0x0c,cksum);
299 dpavlin 1 return(0);
300     }
301    
302     /* Find an EEPROM in the specified array */
303     struct c7200_eeprom *c7200_get_eeprom(struct c7200_eeprom *eeproms,char *name)
304     {
305     int i;
306    
307     for(i=0;eeproms[i].name;i++)
308     if (!strcmp(eeproms[i].name,name))
309     return(&eeproms[i]);
310    
311     return NULL;
312     }
313    
314     /* Get an EEPROM for a given NPE model */
315     struct c7200_eeprom *c7200_get_cpu_eeprom(char *npe_name)
316     {
317     return(c7200_get_eeprom(c7200_cpu_eeprom,npe_name));
318     }
319    
320     /* Get an EEPROM for a given midplane model */
321     struct c7200_eeprom *c7200_get_midplane_eeprom(char *midplane_name)
322     {
323     return(c7200_get_eeprom(c7200_midplane_eeprom,midplane_name));
324     }
325    
326     /* Get a PEM EEPROM for a given NPE model */
327     struct c7200_eeprom *c7200_get_pem_eeprom(char *npe_name)
328     {
329     return(c7200_get_eeprom(c7200_pem_eeprom,npe_name));
330     }
331    
332     /* Set the base MAC address of the chassis */
333     static int c7200_burn_mac_addr(m_uint16_t *data,size_t data_len,
334     n_eth_addr_t *addr)
335     {
336     m_uint8_t eeprom_ver;
337    
338     /* Read EEPROM format version */
339     cisco_eeprom_get_byte(data,data_len,0,&eeprom_ver);
340    
341     if (eeprom_ver != 1) {
342     fprintf(stderr,"c7200_burn_mac_addr: unable to handle "
343     "EEPROM version %u\n",eeprom_ver);
344     return(-1);
345     }
346    
347     cisco_eeprom_set_region(data,data_len,12,addr->eth_addr_byte,6);
348     return(0);
349     }
350    
351     /* Free specific hardware resources used by C7200 */
352     static void c7200_free_hw_ressources(c7200_t *router)
353     {
354     /* Shutdown all Port Adapters */
355     c7200_pa_shutdown_all(router);
356    
357     /* Inactivate the PCMCIA bus */
358     router->pcmcia_bus = NULL;
359    
360     /* Remove the hidden I/O bridge */
361     if (router->io_pci_bridge != NULL) {
362     pci_bridge_remove(router->io_pci_bridge);
363     router->io_pci_bridge = NULL;
364     }
365     }
366    
367     /* Create a new router instance */
368     c7200_t *c7200_create_instance(char *name,int instance_id)
369     {
370     c7200_t *router;
371    
372     if (!(router = malloc(sizeof(*router)))) {
373     fprintf(stderr,"C7200 '%s': Unable to create new instance!\n",name);
374     return NULL;
375     }
376    
377     memset(router,0,sizeof(*router));
378    
379     if (!(router->vm = vm_create(name,instance_id,VM_TYPE_C7200))) {
380     fprintf(stderr,"C7200 '%s': unable to create VM instance!\n",name);
381     goto err_vm;
382     }
383    
384     c7200_init_defaults(router);
385     router->vm->hw_data = router;
386     router->vm->elf_machine_id = C7200_ELF_MACHINE_ID;
387     return router;
388    
389     err_vm:
390     free(router);
391     return NULL;
392     }
393    
394     /* Free resources used by a router instance */
395     static int c7200_free_instance(void *data,void *arg)
396     {
397     vm_instance_t *vm = data;
398     c7200_t *router;
399     int i;
400    
401     if (vm->type == VM_TYPE_C7200) {
402     router = VM_C7200(vm);
403    
404     /* Stop all CPUs */
405     if (vm->cpu_group != NULL) {
406     vm_stop(vm);
407    
408     if (cpu_group_sync_state(vm->cpu_group) == -1) {
409     vm_error(vm,"unable to sync with system CPUs.\n");
410     return(FALSE);
411     }
412     }
413    
414     /* Remove NIO bindings */
415     for(i=0;i<C7200_MAX_PA_BAYS;i++)
416     c7200_pa_remove_all_nio_bindings(router,i);
417    
418     /* Free specific HW resources */
419     c7200_free_hw_ressources(router);
420    
421     /* Free all resources used by VM */
422     vm_free(vm);
423    
424     /* Free the router structure */
425     free(router);
426     return(TRUE);
427     }
428    
429     return(FALSE);
430     }
431    
432     /* Delete a router instance */
433     int c7200_delete_instance(char *name)
434     {
435     return(registry_delete_if_unused(name,OBJ_TYPE_VM,
436     c7200_free_instance,NULL));
437     }
438    
439     /* Delete all router instances */
440     int c7200_delete_all_instances(void)
441     {
442     return(registry_delete_type(OBJ_TYPE_VM,c7200_free_instance,NULL));
443     }
444    
445     /* Save configuration of a C7200 instance */
446     void c7200_save_config(c7200_t *router,FILE *fd)
447     {
448     vm_instance_t *vm = router->vm;
449     struct c7200_nio_binding *nb;
450     struct c7200_pa_bay *bay;
451     int i;
452    
453     /* General settings */
454     fprintf(fd,"c7200 create %s %u\n",vm->name,vm->instance_id);
455    
456     fprintf(fd,"c7200 set_npe %s %s\n",vm->name,router->npe_driver->npe_type);
457     fprintf(fd,"c7200 set_midplane %s %s\n",vm->name,router->midplane_type);
458    
459     /* VM configuration */
460     vm_save_config(vm,fd);
461    
462     /* Port Adapter settings */
463     for(i=0;i<C7200_MAX_PA_BAYS;i++) {
464     if (!(bay = c7200_pa_get_info(router,i)))
465     continue;
466    
467     if (bay->dev_type) {
468     fprintf(fd,"c7200 add_pa_binding %s %u %s\n",
469     vm->name,i,bay->dev_type);
470     }
471    
472     for(nb=bay->nio_list;nb;nb=nb->next) {
473     fprintf(fd,"c7200 add_nio_binding %s %u %u %s\n",
474     vm->name,i,nb->port_id,nb->nio->name);
475     }
476     }
477    
478     fprintf(fd,"\n");
479     }
480    
481     /* Save configurations of all C7200 instances */
482     static void c7200_reg_save_config(registry_entry_t *entry,void *opt,int *err)
483     {
484     vm_instance_t *vm = entry->data;
485     c7200_t *router = VM_C7200(vm);
486    
487     if (vm->type == VM_TYPE_C7200)
488     c7200_save_config(router,(FILE *)opt);
489     }
490    
491     void c7200_save_config_all(FILE *fd)
492     {
493     registry_foreach_type(OBJ_TYPE_VM,c7200_reg_save_config,fd,NULL);
494     }
495    
496     /* Set NPE eeprom definition */
497     static int c7200_npe_set_eeprom(c7200_t *router)
498     {
499     struct c7200_eeprom *eeprom;
500    
501     if (!(eeprom = c7200_get_cpu_eeprom(router->npe_driver->npe_type))) {
502     vm_error(router->vm,"unknown NPE \"%s\" (internal error)!\n",
503     router->npe_driver->npe_type);
504     return(-1);
505     }
506    
507     router->cpu_eeprom.data = eeprom->data;
508     router->cpu_eeprom.data_len = eeprom->len;
509     return(0);
510     }
511    
512     /* Set PEM eeprom definition */
513     static int c7200_pem_set_eeprom(c7200_t *router)
514     {
515     struct c7200_eeprom *eeprom;
516    
517     if (!(eeprom = c7200_get_pem_eeprom(router->npe_driver->npe_type))) {
518     vm_error(router->vm,"no PEM EEPROM found for NPE type \"%s\"!\n",
519     router->npe_driver->npe_type);
520     return(-1);
521     }
522    
523     router->pem_eeprom.data = eeprom->data;
524     router->pem_eeprom.data_len = eeprom->len;
525     return(0);
526     }
527    
528     /* Set PA EEPROM definition */
529     int c7200_pa_set_eeprom(c7200_t *router,u_int pa_bay,
530     const struct c7200_eeprom *eeprom)
531     {
532     if (pa_bay >= C7200_MAX_PA_BAYS) {
533     vm_error(router->vm,"c7200_pa_set_eeprom: invalid PA Bay %u.\n",pa_bay);
534     return(-1);
535     }
536    
537     router->pa_bay[pa_bay].eeprom.data = eeprom->data;
538     router->pa_bay[pa_bay].eeprom.data_len = eeprom->len;
539     return(0);
540     }
541    
542     /* Unset PA EEPROM definition (empty bay) */
543     int c7200_pa_unset_eeprom(c7200_t *router,u_int pa_bay)
544     {
545     if (pa_bay >= C7200_MAX_PA_BAYS) {
546     vm_error(router->vm,"c7200_pa_set_eeprom: invalid PA Bay %u.\n",pa_bay);
547     return(-1);
548     }
549    
550     router->pa_bay[pa_bay].eeprom.data = (m_uint16_t *)eeprom_pa_empty;
551     router->pa_bay[pa_bay].eeprom.data_len = sizeof(eeprom_pa_empty)/2;
552     return(0);
553     }
554    
555     /* Check if a bay has a port adapter */
556     int c7200_pa_check_eeprom(c7200_t *router,u_int pa_bay)
557     {
558     struct nmc93c46_eeprom_def *def;
559    
560     if (!pa_bay || (pa_bay >= C7200_MAX_PA_BAYS))
561     return(0);
562    
563     def = &router->pa_bay[pa_bay].eeprom;
564    
565     if (def->data == eeprom_pa_empty)
566     return(0);
567    
568     return(1);
569     }
570    
571     /* Get bay info */
572     struct c7200_pa_bay *c7200_pa_get_info(c7200_t *router,u_int pa_bay)
573     {
574     if (pa_bay >= C7200_MAX_PA_BAYS)
575     return NULL;
576    
577     return(&router->pa_bay[pa_bay]);
578     }
579    
580     /* Get PA type */
581     char *c7200_pa_get_type(c7200_t *router,u_int pa_bay)
582     {
583     struct c7200_pa_bay *bay;
584    
585     bay = c7200_pa_get_info(router,pa_bay);
586     return((bay != NULL) ? bay->dev_type : NULL);
587     }
588    
589     /* Get driver info about the specified slot */
590     void *c7200_pa_get_drvinfo(c7200_t *router,u_int pa_bay)
591     {
592     struct c7200_pa_bay *bay;
593    
594     bay = c7200_pa_get_info(router,pa_bay);
595     return((bay != NULL) ? bay->drv_info : NULL);
596     }
597    
598     /* Set driver info for the specified slot */
599     int c7200_pa_set_drvinfo(c7200_t *router,u_int pa_bay,void *drv_info)
600     {
601     struct c7200_pa_bay *bay;
602    
603     if (!(bay = c7200_pa_get_info(router,pa_bay)))
604     return(-1);
605    
606     bay->drv_info = drv_info;
607     return(0);
608     }
609    
610     /* Get a PA driver */
611     static struct c7200_pa_driver *c7200_pa_get_driver(char *dev_type)
612     {
613     int i;
614    
615     for(i=0;pa_drivers[i];i++)
616     if (!strcmp(pa_drivers[i]->dev_type,dev_type))
617     return pa_drivers[i];
618    
619     return NULL;
620     }
621    
622     /* Add a PA binding */
623     int c7200_pa_add_binding(c7200_t *router,char *dev_type,u_int pa_bay)
624     {
625     struct c7200_pa_driver *pa_driver;
626     struct c7200_pa_bay *bay;
627    
628     if (!(bay = c7200_pa_get_info(router,pa_bay)))
629     return(-1);
630    
631     /* check that this bay is empty */
632     if (bay->dev_type != NULL) {
633     vm_error(router->vm,"a PA already exists in slot %u.\n",pa_bay);
634     return(-1);
635     }
636    
637     /* find the PA driver */
638     if (!(pa_driver = c7200_pa_get_driver(dev_type))) {
639     vm_error(router->vm,"unknown PA type '%s'.\n",dev_type);
640     return(-1);
641     }
642    
643     bay->dev_type = pa_driver->dev_type;
644     bay->pa_driver = pa_driver;
645     return(0);
646     }
647    
648     /* Remove a PA binding */
649     int c7200_pa_remove_binding(c7200_t *router,u_int pa_bay)
650     {
651     struct c7200_pa_bay *bay;
652    
653     if (!(bay = c7200_pa_get_info(router,pa_bay)))
654     return(-1);
655    
656     /* stop if this bay is still active */
657     if (bay->drv_info != NULL) {
658     vm_error(router->vm,"slot %u still active.\n",pa_bay);
659     return(-1);
660     }
661    
662     /* check that this bay is not empty */
663     if (bay->dev_type == NULL) {
664     vm_error(router->vm,"slot %u is empty.\n",pa_bay);
665     return(-1);
666     }
667    
668     /* remove all NIOs bindings */
669     c7200_pa_remove_all_nio_bindings(router,pa_bay);
670    
671     bay->dev_type = NULL;
672     bay->pa_driver = NULL;
673     return(0);
674     }
675    
676     /* Find a NIO binding */
677     struct c7200_nio_binding *
678     c7200_pa_find_nio_binding(c7200_t *router,u_int pa_bay,u_int port_id)
679     {
680     struct c7200_nio_binding *nb;
681     struct c7200_pa_bay *bay;
682    
683     if (!(bay = c7200_pa_get_info(router,pa_bay)))
684     return NULL;
685    
686     for(nb=bay->nio_list;nb;nb=nb->next)
687     if (nb->port_id == port_id)
688     return nb;
689    
690     return NULL;
691     }
692    
693     /* Add a network IO binding */
694     int c7200_pa_add_nio_binding(c7200_t *router,u_int pa_bay,u_int port_id,
695     char *nio_name)
696     {
697     struct c7200_nio_binding *nb;
698     struct c7200_pa_bay *bay;
699     netio_desc_t *nio;
700    
701     if (!(bay = c7200_pa_get_info(router,pa_bay)))
702     return(-1);
703    
704     /* check that a NIO is not already bound to this port */
705     if (c7200_pa_find_nio_binding(router,pa_bay,port_id) != NULL) {
706     vm_error(router->vm,"a NIO already exists for interface %u/%u\n",
707     pa_bay,port_id);
708     return(-1);
709     }
710    
711     /* acquire a reference on the NIO object */
712     if (!(nio = netio_acquire(nio_name))) {
713     vm_error(router->vm,"unable to find NIO '%s'.\n",nio_name);
714     return(-1);
715     }
716    
717     /* create a new binding */
718     if (!(nb = malloc(sizeof(*nb)))) {
719     vm_error(router->vm,"unable to create NIO binding "
720     "for interface %u/%u.\n",pa_bay,port_id);
721     netio_release(nio_name);
722     return(-1);
723     }
724    
725     memset(nb,0,sizeof(*nb));
726     nb->nio = nio;
727     nb->port_id = port_id;
728     nb->next = bay->nio_list;
729     if (nb->next) nb->next->prev = nb;
730     bay->nio_list = nb;
731     return(0);
732     }
733    
734     /* Remove a NIO binding */
735     int c7200_pa_remove_nio_binding(c7200_t *router,u_int pa_bay,u_int port_id)
736     {
737     struct c7200_nio_binding *nb;
738     struct c7200_pa_bay *bay;
739    
740     if (!(bay = c7200_pa_get_info(router,pa_bay)))
741     return(-1);
742    
743     if (!(nb = c7200_pa_find_nio_binding(router,pa_bay,port_id)))
744     return(-1); /* no nio binding for this slot/port */
745    
746     /* tell the PA driver to stop using this NIO */
747     if (bay->pa_driver)
748     bay->pa_driver->pa_unset_nio(router,pa_bay,port_id);
749    
750     /* remove this entry from the double linked list */
751     if (nb->next)
752     nb->next->prev = nb->prev;
753    
754     if (nb->prev) {
755     nb->prev->next = nb->next;
756     } else {
757     bay->nio_list = nb->next;
758     }
759    
760     /* unreference NIO object */
761     netio_release(nb->nio->name);
762     free(nb);
763     return(0);
764     }
765    
766     /* Remove all NIO bindings for the specified PA */
767     int c7200_pa_remove_all_nio_bindings(c7200_t *router,u_int pa_bay)
768     {
769     struct c7200_nio_binding *nb,*next;
770     struct c7200_pa_bay *bay;
771    
772     if (!(bay = c7200_pa_get_info(router,pa_bay)))
773     return(-1);
774    
775     for(nb=bay->nio_list;nb;nb=next) {
776     next = nb->next;
777    
778     /* tell the PA driver to stop using this NIO */
779     if (bay->pa_driver)
780     bay->pa_driver->pa_unset_nio(router,pa_bay,nb->port_id);
781    
782     /* unreference NIO object */
783     netio_release(nb->nio->name);
784     free(nb);
785     }
786    
787     bay->nio_list = NULL;
788     return(0);
789     }
790    
791     /* Enable a Network IO descriptor for a Port Adapter */
792     int c7200_pa_enable_nio(c7200_t *router,u_int pa_bay,u_int port_id)
793     {
794     struct c7200_nio_binding *nb;
795     struct c7200_pa_bay *bay;
796    
797     if (!(bay = c7200_pa_get_info(router,pa_bay)))
798     return(-1);
799    
800     /* check that we have an NIO binding for this interface */
801     if (!(nb = c7200_pa_find_nio_binding(router,pa_bay,port_id)))
802     return(-1);
803    
804     /* check that the driver is defined and successfully initialized */
805     if (!bay->pa_driver || !bay->drv_info)
806     return(-1);
807    
808     return(bay->pa_driver->pa_set_nio(router,pa_bay,port_id,nb->nio));
809     }
810    
811     /* Disable Network IO descriptor of a Port Adapter */
812     int c7200_pa_disable_nio(c7200_t *router,u_int pa_bay,u_int port_id)
813     {
814     struct c7200_pa_bay *bay;
815    
816     if (!(bay = c7200_pa_get_info(router,pa_bay)))
817     return(-1);
818    
819     /* check that the driver is defined and successfully initialized */
820     if (!bay->pa_driver || !bay->drv_info)
821     return(-1);
822    
823     return(bay->pa_driver->pa_unset_nio(router,pa_bay,port_id));
824     }
825    
826     /* Enable all NIO of the specified PA */
827     int c7200_pa_enable_all_nio(c7200_t *router,u_int pa_bay)
828     {
829     struct c7200_nio_binding *nb;
830     struct c7200_pa_bay *bay;
831    
832     if (!(bay = c7200_pa_get_info(router,pa_bay)))
833     return(-1);
834    
835     /* check that the driver is defined and successfully initialized */
836     if (!bay->pa_driver || !bay->drv_info)
837     return(-1);
838    
839     for(nb=bay->nio_list;nb;nb=nb->next)
840     bay->pa_driver->pa_set_nio(router,pa_bay,nb->port_id,nb->nio);
841    
842     return(0);
843     }
844    
845     /* Disable all NIO of the specified PA */
846     int c7200_pa_disable_all_nio(c7200_t *router,u_int pa_bay)
847     {
848     struct c7200_nio_binding *nb;
849     struct c7200_pa_bay *bay;
850    
851     if (!(bay = c7200_pa_get_info(router,pa_bay)))
852     return(-1);
853    
854     /* check that the driver is defined and successfully initialized */
855     if (!bay->pa_driver || !bay->drv_info)
856     return(-1);
857    
858     for(nb=bay->nio_list;nb;nb=nb->next)
859     bay->pa_driver->pa_unset_nio(router,pa_bay,nb->port_id);
860    
861     return(0);
862     }
863    
864     /* Initialize a Port Adapter */
865     int c7200_pa_init(c7200_t *router,u_int pa_bay)
866     {
867     struct c7200_pa_bay *bay;
868     size_t len;
869    
870     if (!(bay = c7200_pa_get_info(router,pa_bay)))
871     return(-1);
872    
873     /* Check that a device type is defined for this bay */
874     if (!bay->dev_type || !bay->pa_driver) {
875     vm_error(router->vm,"trying to init empty slot %u.\n",pa_bay);
876     return(-1);
877     }
878    
879     /* Allocate device name */
880     len = strlen(bay->dev_type) + 10;
881     if (!(bay->dev_name = malloc(len))) {
882     vm_error(router->vm,"unable to allocate device name.\n");
883     return(-1);
884     }
885    
886     snprintf(bay->dev_name,len,"%s(%u)",bay->dev_type,pa_bay);
887    
888     /* Initialize PA driver */
889     if (bay->pa_driver->pa_init(router,bay->dev_name,pa_bay) == 1) {
890     vm_error(router->vm,"unable to initialize PA %u.\n",pa_bay);
891     return(-1);
892     }
893    
894     /* Enable all NIO */
895     c7200_pa_enable_all_nio(router,pa_bay);
896     return(0);
897     }
898    
899     /* Shutdown a Port Adapter */
900     int c7200_pa_shutdown(c7200_t *router,u_int pa_bay)
901     {
902     struct c7200_pa_bay *bay;
903    
904     if (!(bay = c7200_pa_get_info(router,pa_bay)))
905     return(-1);
906    
907     /* Check that a device type is defined for this bay */
908     if (!bay->dev_type || !bay->pa_driver) {
909     vm_error(router->vm,"trying to shut down an empty bay %u.\n",pa_bay);
910     return(-1);
911     }
912    
913     /* Disable all NIO */
914     c7200_pa_disable_all_nio(router,pa_bay);
915    
916     /* Shutdown the PA driver */
917     if (bay->drv_info && (bay->pa_driver->pa_shutdown(router,pa_bay) == -1)) {
918     vm_error(router->vm,"unable to shutdown PA %u.\n",pa_bay);
919     return(-1);
920     }
921    
922     free(bay->dev_name);
923     bay->dev_name = NULL;
924     bay->drv_info = NULL;
925     return(0);
926     }
927    
928     /* Shutdown all PA of a router */
929     int c7200_pa_shutdown_all(c7200_t *router)
930     {
931     int i;
932    
933     for(i=0;i<C7200_MAX_PA_BAYS;i++) {
934     if (!router->pa_bay[i].dev_type)
935     continue;
936    
937     c7200_pa_shutdown(router,i);
938     }
939    
940     return(0);
941     }
942    
943 dpavlin 2 /* Show info about all NMs */
944     int c7200_pa_show_all_info(c7200_t *router)
945     {
946     struct c7200_pa_bay *bay;
947     int i;
948    
949     for(i=0;i<C7200_MAX_PA_BAYS;i++) {
950     if (!(bay = c7200_pa_get_info(router,i)) || !bay->pa_driver)
951     continue;
952    
953     if (bay->pa_driver->pa_show_info != NULL)
954     bay->pa_driver->pa_show_info(router,i);
955     }
956    
957     return(0);
958     }
959    
960 dpavlin 1 /* Maximum number of tokens in a PA description */
961     #define PA_DESC_MAX_TOKENS 8
962    
963     /* Create a Port Adapter (command line) */
964     int c7200_cmd_pa_create(c7200_t *router,char *str)
965     {
966     char *tokens[PA_DESC_MAX_TOKENS];
967     int i,count,res;
968     u_int pa_bay;
969    
970     /* A port adapter description is like "1:PA-FE-TX" */
971     if ((count = m_strsplit(str,':',tokens,PA_DESC_MAX_TOKENS)) != 2) {
972     vm_error(router->vm,"unable to parse PA description '%s'.\n",str);
973     return(-1);
974     }
975    
976     /* Parse the PA bay id */
977     pa_bay = atoi(tokens[0]);
978    
979     /* Add this new PA to the current PA list */
980     res = c7200_pa_add_binding(router,tokens[1],pa_bay);
981    
982     /* The complete array was cleaned by strsplit */
983     for(i=0;i<PA_DESC_MAX_TOKENS;i++)
984     free(tokens[i]);
985    
986     return(res);
987     }
988    
989     /* Add a Network IO descriptor binding (command line) */
990     int c7200_cmd_add_nio(c7200_t *router,char *str)
991     {
992     char *tokens[PA_DESC_MAX_TOKENS];
993     int i,count,nio_type,res=-1;
994     u_int pa_bay,port_id;
995     netio_desc_t *nio;
996     char nio_name[128];
997    
998     /* A port adapter description is like "1:3:tap:tap0" */
999     if ((count = m_strsplit(str,':',tokens,PA_DESC_MAX_TOKENS)) < 3) {
1000     vm_error(router->vm,"unable to parse NIO description '%s'.\n",str);
1001     return(-1);
1002     }
1003    
1004     /* Parse the PA bay */
1005     pa_bay = atoi(tokens[0]);
1006    
1007     /* Parse the PA port id */
1008     port_id = atoi(tokens[1]);
1009    
1010     /* Autogenerate a NIO name */
1011     snprintf(nio_name,sizeof(nio_name),"c7200-i%u/%u/%u",
1012     router->vm->instance_id,pa_bay,port_id);
1013    
1014     /* Create the Network IO descriptor */
1015     nio = NULL;
1016     nio_type = netio_get_type(tokens[2]);
1017    
1018     switch(nio_type) {
1019     case NETIO_TYPE_UNIX:
1020     if (count != 5) {
1021     vm_error(router->vm,
1022     "invalid number of arguments for UNIX NIO '%s'\n",str);
1023     goto done;
1024     }
1025    
1026     nio = netio_desc_create_unix(nio_name,tokens[3],tokens[4]);
1027     break;
1028    
1029     case NETIO_TYPE_VDE:
1030     if (count != 5) {
1031     vm_error(router->vm,
1032     "invalid number of arguments for VDE NIO '%s'\n",str);
1033     goto done;
1034     }
1035    
1036     nio = netio_desc_create_vde(nio_name,tokens[3],tokens[4]);
1037     break;
1038    
1039     case NETIO_TYPE_TAP:
1040     if (count != 4) {
1041     vm_error(router->vm,
1042     "invalid number of arguments for TAP NIO '%s'\n",str);
1043     goto done;
1044     }
1045    
1046     nio = netio_desc_create_tap(nio_name,tokens[3]);
1047     break;
1048    
1049     case NETIO_TYPE_UDP:
1050     if (count != 6) {
1051     vm_error(router->vm,
1052     "invalid number of arguments for UDP NIO '%s'\n",str);
1053     goto done;
1054     }
1055    
1056     nio = netio_desc_create_udp(nio_name,atoi(tokens[3]),
1057     tokens[4],atoi(tokens[5]));
1058     break;
1059    
1060     case NETIO_TYPE_TCP_CLI:
1061     if (count != 5) {
1062     vm_error(router->vm,
1063     "invalid number of arguments for TCP CLI NIO '%s'\n",str);
1064     goto done;
1065     }
1066    
1067     nio = netio_desc_create_tcp_cli(nio_name,tokens[3],tokens[4]);
1068     break;
1069    
1070     case NETIO_TYPE_TCP_SER:
1071     if (count != 4) {
1072     vm_error(router->vm,
1073     "invalid number of arguments for TCP SER NIO '%s'\n",str);
1074     goto done;
1075     }
1076    
1077     nio = netio_desc_create_tcp_ser(nio_name,tokens[3]);
1078     break;
1079    
1080     case NETIO_TYPE_NULL:
1081     nio = netio_desc_create_null(nio_name);
1082     break;
1083    
1084     #ifdef LINUX_ETH
1085     case NETIO_TYPE_LINUX_ETH:
1086     if (count != 4) {
1087     vm_error(router->vm,
1088     "invalid number of arguments for Linux Eth NIO '%s'\n",
1089     str);
1090     goto done;
1091     }
1092    
1093     nio = netio_desc_create_lnxeth(nio_name,tokens[3]);
1094     break;
1095     #endif
1096    
1097     #ifdef GEN_ETH
1098     case NETIO_TYPE_GEN_ETH:
1099     if (count != 4) {
1100     vm_error(router->vm,"invalid number of "
1101     "arguments for Generic Eth NIO '%s'\n",str);
1102     goto done;
1103     }
1104    
1105     nio = netio_desc_create_geneth(nio_name,tokens[3]);
1106     break;
1107     #endif
1108    
1109     default:
1110     vm_error(router->vm,"unknown NETIO type '%s'\n",tokens[2]);
1111     goto done;
1112     }
1113    
1114     if (!nio) {
1115     fprintf(stderr,"c7200_cmd_add_nio: unable to create NETIO "
1116     "descriptor for PA bay %u\n",pa_bay);
1117     goto done;
1118     }
1119    
1120     if (c7200_pa_add_nio_binding(router,pa_bay,port_id,nio_name) == -1) {
1121     vm_error(router->vm,"unable to add NETIO binding for slot %u\n",pa_bay);
1122     netio_release(nio_name);
1123     netio_delete(nio_name);
1124     goto done;
1125     }
1126    
1127     netio_release(nio_name);
1128     res = 0;
1129    
1130     done:
1131     /* The complete array was cleaned by strsplit */
1132     for(i=0;i<PA_DESC_MAX_TOKENS;i++)
1133     free(tokens[i]);
1134    
1135     return(res);
1136     }
1137    
1138     /* Show the list of available PA drivers */
1139     void c7200_pa_show_drivers(void)
1140     {
1141     int i;
1142    
1143     printf("Available C7200 Port Adapter drivers:\n");
1144    
1145     for(i=0;pa_drivers[i];i++) {
1146     printf(" * %s %s\n",
1147     pa_drivers[i]->dev_type,
1148     !pa_drivers[i]->supported ? "(NOT WORKING)" : "");
1149     }
1150    
1151     printf("\n");
1152     }
1153    
1154     /* Get an NPE driver */
1155     struct c7200_npe_driver *c7200_npe_get_driver(char *npe_type)
1156     {
1157     int i;
1158    
1159     for(i=0;npe_drivers[i].npe_type;i++)
1160     if (!strcmp(npe_drivers[i].npe_type,npe_type))
1161     return(&npe_drivers[i]);
1162    
1163     return NULL;
1164     }
1165    
1166     /* Set the NPE type */
1167     int c7200_npe_set_type(c7200_t *router,char *npe_type)
1168     {
1169     struct c7200_npe_driver *driver;
1170    
1171     if (router->vm->status == VM_STATUS_RUNNING) {
1172     vm_error(router->vm,"unable to change NPE type when online.\n");
1173     return(-1);
1174     }
1175    
1176     if (!(driver = c7200_npe_get_driver(npe_type))) {
1177     vm_error(router->vm,"unknown NPE type '%s'.\n",npe_type);
1178     return(-1);
1179     }
1180    
1181     router->npe_driver = driver;
1182    
1183     if (c7200_npe_set_eeprom(router) == -1) {
1184     vm_error(router->vm,"unable to find NPE '%s' EEPROM!\n",
1185     router->npe_driver->npe_type);
1186     return(-1);
1187     }
1188    
1189     return(0);
1190     }
1191    
1192     /* Show the list of available NPE drivers */
1193     void c7200_npe_show_drivers(void)
1194     {
1195     int i;
1196    
1197     printf("Available C7200 NPE drivers:\n");
1198    
1199     for(i=0;npe_drivers[i].npe_type;i++) {
1200     printf(" * %s %s\n",
1201     npe_drivers[i].npe_type,
1202     !npe_drivers[i].supported ? "(NOT WORKING)" : "");
1203     }
1204    
1205     printf("\n");
1206     }
1207    
1208     /* Set Midplane type */
1209     int c7200_midplane_set_type(c7200_t *router,char *midplane_type)
1210     {
1211     struct c7200_eeprom *eeprom;
1212     m_uint8_t version;
1213    
1214     if (router->vm->status == VM_STATUS_RUNNING) {
1215     vm_error(router->vm,"unable to change Midplane type when online.\n");
1216     return(-1);
1217     }
1218    
1219     /* Set EEPROM */
1220     if (!(eeprom = c7200_get_midplane_eeprom(midplane_type))) {
1221     vm_error(router->vm,"unknown Midplane \"%s\"!\n",midplane_type);
1222     return(-1);
1223     }
1224    
1225     memcpy(router->mp_eeprom_data,eeprom->data,eeprom->len << 1);
1226    
1227     /* Set the chassis base MAC address */
1228     c7200_burn_mac_addr(router->mp_eeprom_data,sizeof(router->mp_eeprom_data),
1229     &router->mac_addr);
1230    
1231     router->mp_eeprom.data = router->mp_eeprom_data;
1232     router->mp_eeprom.data_len = eeprom->len;
1233     router->midplane_type = eeprom->name;
1234    
1235     /* Get the midplane version */
1236     cisco_eeprom_get_byte(router->mp_eeprom.data,router->mp_eeprom.data_len*2,
1237     2,&version);
1238     router->midplane_version = version;
1239     return(0);
1240     }
1241    
1242     /* Set chassis MAC address */
1243     int c7200_midplane_set_mac_addr(c7200_t *router,char *mac_addr)
1244     {
1245     if (parse_mac_addr(&router->mac_addr,mac_addr) == -1) {
1246     vm_error(router->vm,"unable to parse MAC address '%s'.\n",mac_addr);
1247     return(-1);
1248     }
1249    
1250     /* Set the chassis base MAC address */
1251     c7200_burn_mac_addr(router->mp_eeprom_data,sizeof(router->mp_eeprom_data),
1252     &router->mac_addr);
1253     return(0);
1254     }
1255    
1256     /* Create the main PCI bus for a GT64010 based system */
1257     static int c7200_init_gt64010(c7200_t *router)
1258     {
1259     vm_instance_t *vm = router->vm;
1260    
1261     if (!(vm->pci_bus[0] = pci_bus_create("MB0/MB1/MB2",0))) {
1262     vm_error(vm,"unable to create PCI data.\n");
1263     return(-1);
1264     }
1265    
1266     return(dev_gt64010_init(vm,"gt64010",C7200_GT64K_ADDR,0x1000,
1267     C7200_GT64K_IRQ));
1268     }
1269    
1270     /* Create the two main PCI busses for a GT64120 based system */
1271     static int c7200_init_gt64120(c7200_t *router)
1272     {
1273     vm_instance_t *vm = router->vm;
1274    
1275     vm->pci_bus[0] = pci_bus_create("MB0/MB1",0);
1276     vm->pci_bus[1] = pci_bus_create("MB2",0);
1277    
1278     if (!vm->pci_bus[0] || !vm->pci_bus[1]) {
1279     vm_error(vm,"unable to create PCI data.\n");
1280     return(-1);
1281     }
1282    
1283     return(dev_gt64120_init(vm,"gt64120",C7200_GT64K_ADDR,0x1000,
1284     C7200_GT64K_IRQ));
1285     }
1286    
1287     /* Create the two main PCI busses for a dual GT64120 system */
1288     static int c7200_init_dual_gt64120(c7200_t *router)
1289     {
1290     vm_instance_t *vm = router->vm;
1291    
1292     vm->pci_bus[0] = pci_bus_create("MB0/MB1",0);
1293     vm->pci_bus[1] = pci_bus_create("MB2",0);
1294    
1295     if (!vm->pci_bus[0] || !vm->pci_bus[1]) {
1296     vm_error(vm,"unable to create PCI data.\n",vm->name);
1297     return(-1);
1298     }
1299    
1300     /* Initialize the first GT64120 at 0x14000000 */
1301     if (dev_gt64120_init(vm,"gt64120(1)",C7200_GT64K_ADDR,0x1000,
1302     C7200_GT64K_IRQ) == -1)
1303     return(-1);
1304    
1305     /* Initialize the second GT64120 at 0x15000000 */
1306     if (dev_gt64120_init(vm,"gt64120(2)",C7200_GT64K_SEC_ADDR,0x1000,
1307     C7200_GT64K_IRQ) == -1)
1308     return(-1);
1309    
1310     return(0);
1311     }
1312    
1313     /* Create the PA PCI busses */
1314     static int c7200_pa_create_pci_busses(c7200_t *router)
1315     {
1316     vm_instance_t *vm = router->vm;
1317     char bus_name[128];
1318     int i;
1319    
1320     for(i=1;i<C7200_MAX_PA_BAYS;i++) {
1321     snprintf(bus_name,sizeof(bus_name),"PA Slot %d",i);
1322     vm->pci_bus_pool[i] = pci_bus_create(bus_name,-1);
1323    
1324     if (!vm->pci_bus_pool[i])
1325     return(-1);
1326     }
1327    
1328     return(0);
1329     }
1330    
1331     /* Create a PA bridge, depending on the midplane */
1332     static int c7200_pa_init_pci_bridge(c7200_t *router,u_int pa_bay,
1333     struct pci_bus *pci_bus,int pci_device)
1334     {
1335     switch(router->midplane_version) {
1336     case 0:
1337     case 1:
1338     dev_dec21050_init(pci_bus,pci_device,router->pa_bay[pa_bay].pci_map);
1339     break;
1340     default:
1341     dev_dec21150_init(pci_bus,pci_device,router->pa_bay[pa_bay].pci_map);
1342     }
1343     return(0);
1344     }
1345    
1346     /*
1347     * Hidden "I/O" PCI bridge hack for PCMCIA controller.
1348     *
1349     * On NPE-175, NPE-225, NPE-300 and NPE-400, PCMCIA controller is
1350     * identified on PCI as Bus=2,Device=16. On NPE-G1, this is Bus=17,Device=16.
1351     *
1352     * However, I don't understand how the bridging between PCI bus 1 and 2
1353     * is done (16 and 17 on NPE-G1).
1354     *
1355     * Maybe I'm missing something about PCI-to-PCI bridge mechanism, or there
1356     * is a special hidden device that does the job silently (it should be
1357     * visible on the PCI bus...)
1358     *
1359     * BTW, it works.
1360     */
1361     static int
1362     c7200_create_io_pci_bridge(c7200_t *router,struct pci_bus *parent_bus)
1363     {
1364     vm_instance_t *vm = router->vm;
1365    
1366     /* Create the PCI bus where the PCMCIA controller will seat */
1367     if (!(vm->pci_bus_pool[16] = pci_bus_create("I/O secondary bus",-1)))
1368     return(-1);
1369    
1370     /* Create the hidden bridge with "special" handling... */
1371     if (!(router->io_pci_bridge = pci_bridge_add(parent_bus)))
1372     return(-1);
1373    
1374     router->io_pci_bridge->skip_bus_check = TRUE;
1375     pci_bridge_map_bus(router->io_pci_bridge,vm->pci_bus_pool[16]);
1376    
1377     router->pcmcia_bus = vm->pci_bus_pool[16];
1378     return(0);
1379     }
1380    
1381     /* Initialize an NPE-100 board */
1382     int c7200_init_npe100(c7200_t *router)
1383     {
1384     vm_instance_t *vm = router->vm;
1385     int i;
1386    
1387     /* Set the processor type: R4600 */
1388     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R4600);
1389    
1390     /* Initialize the Galileo GT-64010 system controller */
1391     if (c7200_init_gt64010(router) == -1)
1392     return(-1);
1393    
1394     /* PCMCIA controller is on bus 0 */
1395     router->pcmcia_bus = vm->pci_bus[0];
1396    
1397     /* Initialize the PA PCI busses */
1398     if (c7200_pa_create_pci_busses(router) == -1)
1399     return(-1);
1400    
1401     /* Create PCI busses for PA Bays 1,3,5 and PA Bays 2,4,6 */
1402     vm->pci_bus_pool[24] = pci_bus_create("PA Slots 1,3,5",-1);
1403     vm->pci_bus_pool[25] = pci_bus_create("PA Slots 2,4,6",-1);
1404    
1405     /* PCI bridges (MB0/MB1, MB0/MB2) */
1406     dev_dec21050_init(vm->pci_bus[0],1,NULL);
1407     dev_dec21050_init(vm->pci_bus[0],2,vm->pci_bus_pool[24]);
1408     dev_dec21050_init(vm->pci_bus[0],3,NULL);
1409     dev_dec21050_init(vm->pci_bus[0],4,vm->pci_bus_pool[25]);
1410    
1411     /* Map the PA PCI busses */
1412     router->pa_bay[0].pci_map = vm->pci_bus[0];
1413    
1414     for(i=1;i<C7200_MAX_PA_BAYS;i++)
1415     router->pa_bay[i].pci_map = vm->pci_bus_pool[i];
1416    
1417     /* PCI bridges for PA Bays 1 to 6 */
1418     c7200_pa_init_pci_bridge(router,1,vm->pci_bus_pool[24],1);
1419     c7200_pa_init_pci_bridge(router,3,vm->pci_bus_pool[24],2);
1420     c7200_pa_init_pci_bridge(router,5,vm->pci_bus_pool[24],3);
1421    
1422     c7200_pa_init_pci_bridge(router,2,vm->pci_bus_pool[25],1);
1423     c7200_pa_init_pci_bridge(router,4,vm->pci_bus_pool[25],2);
1424     c7200_pa_init_pci_bridge(router,6,vm->pci_bus_pool[25],3);
1425     return(0);
1426     }
1427    
1428     /* Initialize an NPE-150 board */
1429     int c7200_init_npe150(c7200_t *router)
1430     {
1431     vm_instance_t *vm = router->vm;
1432     m_uint32_t bank_size;
1433     int i;
1434    
1435     /* Set the processor type: R4700 */
1436     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R4700);
1437    
1438     /* Initialize the Galileo GT-64010 system controller */
1439     if (c7200_init_gt64010(router) == -1)
1440     return(-1);
1441    
1442     /* PCMCIA controller is on bus 0 */
1443     router->pcmcia_bus = vm->pci_bus[0];
1444    
1445     /* Initialize the PA PCI busses */
1446     if (c7200_pa_create_pci_busses(router) == -1)
1447     return(-1);
1448    
1449     /* Create PCI busses for PA Bays 1,3,5 and PA Bays 2,4,6 */
1450     vm->pci_bus_pool[24] = pci_bus_create("PA Slots 1,3,5",-1);
1451     vm->pci_bus_pool[25] = pci_bus_create("PA Slots 2,4,6",-1);
1452    
1453     /* PCI bridges (MB0/MB1, MB0/MB2) */
1454     dev_dec21050_init(vm->pci_bus[0],1,NULL);
1455     dev_dec21050_init(vm->pci_bus[0],2,vm->pci_bus_pool[24]);
1456     dev_dec21050_init(vm->pci_bus[0],3,NULL);
1457     dev_dec21050_init(vm->pci_bus[0],4,vm->pci_bus_pool[25]);
1458    
1459     /* Map the PA PCI busses */
1460     router->pa_bay[0].pci_map = vm->pci_bus[0];
1461    
1462     for(i=1;i<C7200_MAX_PA_BAYS;i++)
1463     router->pa_bay[i].pci_map = vm->pci_bus_pool[i];
1464    
1465     /* PCI bridges for PA Bays 1 to 6 */
1466     c7200_pa_init_pci_bridge(router,1,vm->pci_bus_pool[24],1);
1467     c7200_pa_init_pci_bridge(router,3,vm->pci_bus_pool[24],2);
1468     c7200_pa_init_pci_bridge(router,5,vm->pci_bus_pool[24],3);
1469    
1470     c7200_pa_init_pci_bridge(router,2,vm->pci_bus_pool[25],1);
1471     c7200_pa_init_pci_bridge(router,4,vm->pci_bus_pool[25],2);
1472     c7200_pa_init_pci_bridge(router,6,vm->pci_bus_pool[25],3);
1473    
1474     /* Packet SRAM: 1 Mb */
1475     bank_size = 0x80000;
1476    
1477     dev_c7200_sram_init(vm,"sram0",C7200_SRAM_ADDR,bank_size,
1478     vm->pci_bus_pool[24],0);
1479    
1480     dev_c7200_sram_init(vm,"sram1",C7200_SRAM_ADDR+bank_size,bank_size,
1481     vm->pci_bus_pool[25],0);
1482     return(0);
1483     }
1484    
1485     /* Initialize an NPE-175 board */
1486     int c7200_init_npe175(c7200_t *router)
1487     {
1488     vm_instance_t *vm = router->vm;
1489     int i;
1490    
1491     /* Set the processor type: R5271 */
1492     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R527x);
1493    
1494     /* Initialize the Galileo GT-64120 PCI controller */
1495     if (c7200_init_gt64120(router) == -1)
1496     return(-1);
1497    
1498     /* Initialize the PA PCI busses */
1499     if (c7200_pa_create_pci_busses(router) == -1)
1500     return(-1);
1501    
1502     /* Create PCI bus for PA Bay 0 (I/O Card, PCMCIA, Interfaces) */
1503     vm->pci_bus_pool[0] = pci_bus_create("PA Slot 0",-1);
1504    
1505     /* PCI bridge for I/O card device on MB0 */
1506     dev_dec21150_init(vm->pci_bus[0],1,vm->pci_bus_pool[0]);
1507    
1508     /* Create the hidden "I/O" PCI bridge for PCMCIA controller */
1509     c7200_create_io_pci_bridge(router,vm->pci_bus_pool[0]);
1510    
1511     /* Map the PA PCI busses */
1512     for(i=0;i<C7200_MAX_PA_BAYS;i++)
1513     router->pa_bay[i].pci_map = vm->pci_bus_pool[i];
1514    
1515     /* PCI bridges for PA Bays 1 to 6 */
1516     c7200_pa_init_pci_bridge(router,1,vm->pci_bus[0],7);
1517     c7200_pa_init_pci_bridge(router,3,vm->pci_bus[0],8);
1518     c7200_pa_init_pci_bridge(router,5,vm->pci_bus[0],9);
1519    
1520     c7200_pa_init_pci_bridge(router,2,vm->pci_bus[1],7);
1521     c7200_pa_init_pci_bridge(router,4,vm->pci_bus[1],8);
1522     c7200_pa_init_pci_bridge(router,6,vm->pci_bus[1],9);
1523    
1524     /* Enable PEM EEPROM */
1525     c7200_pem_set_eeprom(router);
1526     return(0);
1527     }
1528    
1529     /* Initialize an NPE-200 board */
1530     int c7200_init_npe200(c7200_t *router)
1531     {
1532     vm_instance_t *vm = router->vm;
1533     m_uint32_t bank_size;
1534     int i;
1535    
1536     /* Set the processor type: R5000 */
1537     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R5000);
1538    
1539     /* Initialize the Galileo GT-64010 PCI controller */
1540     if (c7200_init_gt64010(router) == -1)
1541     return(-1);
1542    
1543     /* PCMCIA controller is on bus 0 */
1544     router->pcmcia_bus = vm->pci_bus[0];
1545    
1546     /* Initialize the PA PCI busses */
1547     if (c7200_pa_create_pci_busses(router) == -1)
1548     return(-1);
1549    
1550     /* Create PCI busses for PA Bays 1,3,5 and PA Bays 2,4,6 */
1551     vm->pci_bus_pool[24] = pci_bus_create("PA Slots 1,3,5",-1);
1552     vm->pci_bus_pool[25] = pci_bus_create("PA Slots 2,4,6",-1);
1553    
1554     /* PCI bridges (MB0/MB1, MB0/MB2) */
1555     dev_dec21050_init(vm->pci_bus[0],1,NULL);
1556     dev_dec21050_init(vm->pci_bus[0],2,vm->pci_bus_pool[24]);
1557     dev_dec21050_init(vm->pci_bus[0],3,NULL);
1558     dev_dec21050_init(vm->pci_bus[0],4,vm->pci_bus_pool[25]);
1559    
1560     /* Map the PA PCI busses */
1561     router->pa_bay[0].pci_map = vm->pci_bus[0];
1562    
1563     for(i=1;i<C7200_MAX_PA_BAYS;i++)
1564     router->pa_bay[i].pci_map = vm->pci_bus_pool[i];
1565    
1566     /* PCI bridges for PA Bays 1 to 6 */
1567     c7200_pa_init_pci_bridge(router,1,vm->pci_bus_pool[24],1);
1568     c7200_pa_init_pci_bridge(router,3,vm->pci_bus_pool[24],2);
1569     c7200_pa_init_pci_bridge(router,5,vm->pci_bus_pool[24],3);
1570    
1571     c7200_pa_init_pci_bridge(router,2,vm->pci_bus_pool[25],1);
1572     c7200_pa_init_pci_bridge(router,4,vm->pci_bus_pool[25],2);
1573     c7200_pa_init_pci_bridge(router,6,vm->pci_bus_pool[25],3);
1574    
1575     /* Packet SRAM: 4 Mb */
1576     bank_size = 0x200000;
1577    
1578     dev_c7200_sram_init(vm,"sram0",C7200_SRAM_ADDR,bank_size,
1579     vm->pci_bus_pool[24],0);
1580    
1581     dev_c7200_sram_init(vm,"sram1",C7200_SRAM_ADDR+bank_size,bank_size,
1582     vm->pci_bus_pool[25],0);
1583     return(0);
1584     }
1585    
1586     /* Initialize an NPE-225 board */
1587     int c7200_init_npe225(c7200_t *router)
1588     {
1589     vm_instance_t *vm = router->vm;
1590     int i;
1591    
1592     /* Set the processor type: R5271 */
1593     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R527x);
1594    
1595     /* Initialize the Galileo GT-64120 PCI controller */
1596     if (c7200_init_gt64120(router) == -1)
1597     return(-1);
1598    
1599     /* Initialize the PA PCI busses */
1600     if (c7200_pa_create_pci_busses(router) == -1)
1601     return(-1);
1602    
1603     /* Create PCI bus for PA Bay 0 (I/O Card, PCMCIA, Interfaces) */
1604     vm->pci_bus_pool[0] = pci_bus_create("PA Slot 0",-1);
1605    
1606     /* PCI bridge for I/O card device on MB0 */
1607     dev_dec21150_init(vm->pci_bus[0],1,vm->pci_bus_pool[0]);
1608    
1609     /* Create the hidden "I/O" PCI bridge for PCMCIA controller */
1610     c7200_create_io_pci_bridge(router,vm->pci_bus_pool[0]);
1611    
1612     /* Map the PA PCI busses */
1613     for(i=0;i<C7200_MAX_PA_BAYS;i++)
1614     router->pa_bay[i].pci_map = vm->pci_bus_pool[i];
1615    
1616     /* PCI bridges for PA Bays 1 to 6 */
1617     c7200_pa_init_pci_bridge(router,1,vm->pci_bus[0],7);
1618     c7200_pa_init_pci_bridge(router,3,vm->pci_bus[0],8);
1619     c7200_pa_init_pci_bridge(router,5,vm->pci_bus[0],9);
1620    
1621     c7200_pa_init_pci_bridge(router,2,vm->pci_bus[1],7);
1622     c7200_pa_init_pci_bridge(router,4,vm->pci_bus[1],8);
1623     c7200_pa_init_pci_bridge(router,6,vm->pci_bus[1],9);
1624    
1625     /* Enable PEM EEPROM */
1626     c7200_pem_set_eeprom(router);
1627     return(0);
1628     }
1629    
1630     /* Initialize an NPE-300 board */
1631     int c7200_init_npe300(c7200_t *router)
1632     {
1633     vm_instance_t *vm = router->vm;
1634     int i;
1635    
1636     /* Set the processor type: R7000 */
1637     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R7000);
1638    
1639     /* 32 Mb of I/O memory */
1640     vm->iomem_size = 32;
1641     dev_ram_init(vm,"iomem",vm->ram_mmap,C7200_IOMEM_ADDR,32*1048576);
1642    
1643     /* Initialize the two Galileo GT-64120 system controllers */
1644     if (c7200_init_dual_gt64120(router) == -1)
1645     return(-1);
1646    
1647     /* Initialize the PA PCI busses */
1648     if (c7200_pa_create_pci_busses(router) == -1)
1649     return(-1);
1650    
1651     /* Create PCI bus for PA Bay 0 (I/O Card, PCMCIA, Interfaces) */
1652     vm->pci_bus_pool[0] = pci_bus_create("PA Slot 0",-1);
1653    
1654     /* Create PCI busses for PA Bays 1,3,5 and PA Bays 2,4,6 */
1655     vm->pci_bus_pool[24] = pci_bus_create("PA Slots 1,3,5",-1);
1656     vm->pci_bus_pool[25] = pci_bus_create("PA Slots 2,4,6",-1);
1657    
1658     /* PCI bridge for I/O card device on MB0 */
1659     dev_dec21150_init(vm->pci_bus[0],1,vm->pci_bus_pool[0]);
1660    
1661     /* Create the hidden "I/O" PCI bridge for PCMCIA controller */
1662     c7200_create_io_pci_bridge(router,vm->pci_bus_pool[0]);
1663    
1664     /* PCI bridges for PA PCI "Head" Busses */
1665     dev_dec21150_init(vm->pci_bus[0],2,vm->pci_bus_pool[24]);
1666     dev_dec21150_init(vm->pci_bus[1],1,vm->pci_bus_pool[25]);
1667    
1668     /* Map the PA PCI busses */
1669     for(i=0;i<C7200_MAX_PA_BAYS;i++)
1670     router->pa_bay[i].pci_map = vm->pci_bus_pool[i];
1671    
1672     /* PCI bridges for PA Bays 1 to 6 */
1673     c7200_pa_init_pci_bridge(router,1,vm->pci_bus_pool[24],1);
1674     c7200_pa_init_pci_bridge(router,3,vm->pci_bus_pool[24],2);
1675     c7200_pa_init_pci_bridge(router,5,vm->pci_bus_pool[24],3);
1676    
1677     c7200_pa_init_pci_bridge(router,2,vm->pci_bus_pool[25],1);
1678     c7200_pa_init_pci_bridge(router,4,vm->pci_bus_pool[25],2);
1679     c7200_pa_init_pci_bridge(router,6,vm->pci_bus_pool[25],3);
1680     return(0);
1681     }
1682    
1683     /* Initialize an NPE-400 board */
1684     int c7200_init_npe400(c7200_t *router)
1685     {
1686     vm_instance_t *vm = router->vm;
1687     int i;
1688    
1689     /* Set the processor type: R7000 */
1690     mips64_set_prid(vm->boot_cpu,MIPS_PRID_R7000);
1691    
1692     /*
1693     * Add supplemental memory (as "iomem") if we have more than 256 Mb.
1694     */
1695     if (vm->ram_size > C7200_BASE_RAM_LIMIT) {
1696     vm->iomem_size = vm->ram_size - C7200_BASE_RAM_LIMIT;
1697     vm->ram_size = C7200_BASE_RAM_LIMIT;
1698     dev_ram_init(vm,"ram1",vm->ram_mmap,
1699     C7200_IOMEM_ADDR,vm->iomem_size*1048576);
1700     }
1701    
1702     /* Initialize the Galileo GT-64120 system controller */
1703     if (c7200_init_gt64120(router) == -1)
1704     return(-1);
1705    
1706     /* Initialize the PA PCI busses */
1707     if (c7200_pa_create_pci_busses(router) == -1)
1708     return(-1);
1709    
1710     /* Create PCI bus for PA Bay 0 (I/O Card, PCMCIA, Interfaces) */
1711     vm->pci_bus_pool[0] = pci_bus_create("PA Slot 0",-1);
1712    
1713     /* PCI bridge for I/O card device on MB0 */
1714     dev_dec21050_init(vm->pci_bus[0],1,vm->pci_bus_pool[0]);
1715    
1716     /* Create the hidden "I/O" PCI bridge for PCMCIA controller */
1717     c7200_create_io_pci_bridge(router,vm->pci_bus_pool[0]);
1718    
1719     /* Map the PA PCI busses */
1720     for(i=0;i<C7200_MAX_PA_BAYS;i++)
1721     router->pa_bay[i].pci_map = vm->pci_bus_pool[i];
1722    
1723     /* PCI bridges for PA Bays 1 to 6 */
1724     c7200_pa_init_pci_bridge(router,1,vm->pci_bus[0],7);
1725     c7200_pa_init_pci_bridge(router,3,vm->pci_bus[0],8);
1726     c7200_pa_init_pci_bridge(router,5,vm->pci_bus[0],9);
1727    
1728     c7200_pa_init_pci_bridge(router,2,vm->pci_bus[1],7);
1729     c7200_pa_init_pci_bridge(router,4,vm->pci_bus[1],8);
1730     c7200_pa_init_pci_bridge(router,6,vm->pci_bus[1],9);
1731     return(0);
1732     }
1733    
1734     /* Initialize an NPE-G1 board (XXX not working) */
1735     int c7200_init_npeg1(c7200_t *router)
1736     {
1737     vm_instance_t *vm = router->vm;
1738     int i;
1739    
1740     /* Just some tests */
1741     mips64_set_prid(vm->boot_cpu,MIPS_PRID_BCM1250);
1742     vm->pci_bus[0] = pci_bus_create("HT/PCI bus",0);
1743    
1744     /* SB-1 System control devices */
1745     dev_sb1_init(vm);
1746    
1747     /* SB-1 I/O devices */
1748     dev_sb1_io_init(vm,C7200_DUART_IRQ);
1749    
1750     /* SB-1 PCI bus configuration zone */
1751     dev_sb1_pci_init(vm,"pci_cfg",0xFE000000ULL);
1752    
1753     /* Initialize the PA PCI busses */
1754     if (c7200_pa_create_pci_busses(router) == -1)
1755     return(-1);
1756    
1757     /* Create PCI bus for PA Bay 0 (I/O Card, PCMCIA, Interfaces) */
1758     vm->pci_bus_pool[0] = pci_bus_create("PA Slot 0",-1);
1759    
1760     /* Create PCI busses for PA Bays 1,3,5 and PA Bays 2,4,6 */
1761     vm->pci_bus_pool[24] = pci_bus_create("PA Slots 1,3,5",-1);
1762     vm->pci_bus_pool[25] = pci_bus_create("PA Slots 2,4,6",-1);
1763    
1764     /* HyperTransport/PCI bridges */
1765     dev_ap1011_init(vm->pci_bus_pool[28],0,NULL);
1766     dev_ap1011_init(vm->pci_bus_pool[28],1,vm->pci_bus_pool[24]);
1767     dev_ap1011_init(vm->pci_bus_pool[28],2,vm->pci_bus_pool[25]);
1768    
1769     /* PCI bridge for I/O card device on MB0 */
1770     dev_dec21150_init(vm->pci_bus[0],3,vm->pci_bus_pool[0]);
1771    
1772     /* Create the hidden "I/O" PCI bridge for PCMCIA controller */
1773     c7200_create_io_pci_bridge(router,vm->pci_bus_pool[0]);
1774    
1775     /* Map the PA PCI busses */
1776     router->pa_bay[0].pci_map = vm->pci_bus[0];
1777    
1778     for(i=1;i<C7200_MAX_PA_BAYS;i++)
1779     router->pa_bay[i].pci_map = vm->pci_bus_pool[i];
1780    
1781     /* PCI bridges for PA Bays 1 to 6 */
1782     c7200_pa_init_pci_bridge(router,1,vm->pci_bus_pool[24],1);
1783     c7200_pa_init_pci_bridge(router,3,vm->pci_bus_pool[24],2);
1784     c7200_pa_init_pci_bridge(router,5,vm->pci_bus_pool[24],3);
1785    
1786     c7200_pa_init_pci_bridge(router,2,vm->pci_bus_pool[25],1);
1787     c7200_pa_init_pci_bridge(router,4,vm->pci_bus_pool[25],2);
1788     c7200_pa_init_pci_bridge(router,6,vm->pci_bus_pool[25],3);
1789     return(0);
1790     }
1791    
1792     /* Show C7200 hardware info */
1793     void c7200_show_hardware(c7200_t *router)
1794     {
1795     vm_instance_t *vm = router->vm;
1796    
1797     printf("C7200 instance '%s' (id %d):\n",vm->name,vm->instance_id);
1798    
1799     printf(" VM Status : %d\n",vm->status);
1800     printf(" RAM size : %u Mb\n",vm->ram_size);
1801     printf(" IOMEM size : %u Mb\n",vm->iomem_size);
1802     printf(" NVRAM size : %u Kb\n",vm->nvram_size);
1803     printf(" NPE model : %s\n",router->npe_driver->npe_type);
1804     printf(" Midplane : %s\n",router->midplane_type);
1805     printf(" IOS image : %s\n\n",vm->ios_image);
1806    
1807     if (vm->debug_level > 0) {
1808     dev_show_list(vm);
1809     pci_dev_show_list(vm->pci_bus[0]);
1810     pci_dev_show_list(vm->pci_bus[1]);
1811     printf("\n");
1812     }
1813     }
1814    
1815     /* Initialize default parameters for a C7200 */
1816     void c7200_init_defaults(c7200_t *router)
1817     {
1818     vm_instance_t *vm = router->vm;
1819     n_eth_addr_t *m;
1820     m_uint16_t pid;
1821    
1822     pid = (m_uint16_t)getpid();
1823    
1824     /* Generate a chassis MAC address based on the instance ID */
1825     m = &router->mac_addr;
1826     m->eth_addr_byte[0] = 0xCA;
1827     m->eth_addr_byte[1] = vm->instance_id & 0xFF;
1828     m->eth_addr_byte[2] = pid >> 8;
1829     m->eth_addr_byte[3] = pid & 0xFF;
1830     m->eth_addr_byte[4] = 0x00;
1831     m->eth_addr_byte[5] = 0x00;
1832    
1833     c7200_init_eeprom_groups(router);
1834     c7200_npe_set_type(router,C7200_DEFAULT_NPE_TYPE);
1835     c7200_midplane_set_type(router,C7200_DEFAULT_MIDPLANE);
1836    
1837     vm->ram_mmap = C7200_DEFAULT_RAM_MMAP;
1838     vm->ram_size = C7200_DEFAULT_RAM_SIZE;
1839     vm->rom_size = C7200_DEFAULT_ROM_SIZE;
1840     vm->nvram_size = C7200_DEFAULT_NVRAM_SIZE;
1841     vm->iomem_size = 0;
1842     vm->conf_reg_setup = C7200_DEFAULT_CONF_REG;
1843     vm->clock_divisor = C7200_DEFAULT_CLOCK_DIV;
1844     vm->nvram_rom_space = C7200_NVRAM_ROM_RES_SIZE;
1845    
1846     vm->pcmcia_disk_size[0] = C7200_DEFAULT_DISK0_SIZE;
1847     vm->pcmcia_disk_size[1] = C7200_DEFAULT_DISK1_SIZE;
1848     }
1849    
1850     /* Run the checklist */
1851     int c7200_checklist(c7200_t *router)
1852     {
1853     struct vm_instance *vm = router->vm;
1854     int res = 0;
1855    
1856     res += vm_object_check(vm,"ram");
1857     res += vm_object_check(vm,"rom");
1858     res += vm_object_check(vm,"nvram");
1859     res += vm_object_check(vm,"zero");
1860    
1861     if (res < 0)
1862     vm_error(vm,"incomplete initialization (no memory?)\n");
1863    
1864     return(res);
1865     }
1866    
1867     /* Initialize the C7200 Platform */
1868     int c7200_init_platform(c7200_t *router)
1869     {
1870     struct vm_instance *vm = router->vm;
1871     struct c7200_pa_bay *pa_bay;
1872     cpu_mips_t *cpu0;
1873     int i;
1874    
1875     /* Copy config register setup into "active" config register */
1876     vm->conf_reg = vm->conf_reg_setup;
1877    
1878     /* Create Console and AUX ports */
1879     vm_init_vtty(vm);
1880    
1881     /* Check that the amount of RAM is valid */
1882     if (vm->ram_size > router->npe_driver->max_ram_size) {
1883     vm_error(vm,"%u is not a valid RAM size for this NPE. "
1884     "Fallback to %u Mb.\n\n",
1885     vm->ram_size,router->npe_driver->max_ram_size);
1886    
1887     vm->ram_size = router->npe_driver->max_ram_size;
1888     }
1889    
1890     /* Create a CPU group */
1891     vm->cpu_group = cpu_group_create("System CPU");
1892    
1893     /* Initialize the virtual MIPS processor */
1894     if (!(cpu0 = cpu_create(vm,0))) {
1895     vm_error(vm,"unable to create CPU0!\n");
1896     return(-1);
1897     }
1898    
1899     /* Add this CPU to the system CPU group */
1900     cpu_group_add(vm->cpu_group,cpu0);
1901     vm->boot_cpu = cpu0;
1902    
1903     /* Mark the Network IO interrupt as high priority */
1904     cpu0->irq_idle_preempt[C7200_NETIO_IRQ] = TRUE;
1905    
1906     /* Copy some parameters from VM to CPU0 (idle PC, ...) */
1907     cpu0->idle_pc = vm->idle_pc;
1908    
1909     if (vm->timer_irq_check_itv)
1910     cpu0->timer_irq_check_itv = vm->timer_irq_check_itv;
1911    
1912     /*
1913     * On the C7200, bit 33 of physical addresses is used to bypass L2 cache.
1914     * We clear it systematically.
1915     */
1916     cpu0->addr_bus_mask = C7200_ADDR_BUS_MASK;
1917    
1918     /* Remote emulator control */
1919     dev_remote_control_init(vm,0x16000000,0x1000);
1920    
1921     /* Bootflash */
1922     dev_bootflash_init(vm,"bootflash",C7200_BOOTFLASH_ADDR,(8 * 1048576));
1923    
1924     /* NVRAM and calendar */
1925     dev_nvram_init(vm,"nvram",router->npe_driver->nvram_addr,
1926     vm->nvram_size*1024,&vm->conf_reg);
1927    
1928     /* Bit-bucket zone */
1929     dev_zero_init(vm,"zero",C7200_BITBUCKET_ADDR,0xc00000);
1930    
1931     /* Midplane FPGA */
1932     dev_c7200_mpfpga_init(router,C7200_MPFPGA_ADDR,0x1000);
1933    
1934     /* IO FPGA */
1935     if (dev_c7200_iofpga_init(router,C7200_IOFPGA_ADDR,0x1000) == -1)
1936     return(-1);
1937    
1938     /* Initialize the NPE board */
1939     if (router->npe_driver->npe_init(router) == -1)
1940     return(-1);
1941    
1942     /* Initialize RAM */
1943     dev_ram_init(vm,"ram",vm->ram_mmap,0x00000000ULL,vm->ram_size*1048576);
1944    
1945     /* Initialize ROM */
1946     if (!vm->rom_filename) {
1947     /* use embedded ROM */
1948     dev_rom_init(vm,"rom",C7200_ROM_ADDR,vm->rom_size*1048576);
1949     } else {
1950     /* use alternate ROM */
1951     dev_ram_init(vm,"rom",TRUE,C7200_ROM_ADDR,vm->rom_size*1048576);
1952     }
1953    
1954     /* PCI IO space */
1955     if (!(vm->pci_io_space = pci_io_data_init(vm,C7200_PCI_IO_ADDR)))
1956     return(-1);
1957    
1958     /* Cirrus Logic PD6729 (PCI-to-PCMCIA host adapter) */
1959     dev_clpd6729_init(vm,router->pcmcia_bus,
1960     router->npe_driver->clpd6729_pci_dev,
1961     vm->pci_io_space,0x402,0x403);
1962    
1963     /* Initialize Port Adapters */
1964     for(i=0;i<C7200_MAX_PA_BAYS;i++) {
1965     pa_bay = &router->pa_bay[i];
1966    
1967     if (!pa_bay->dev_type)
1968     continue;
1969    
1970     if (c7200_pa_init(router,i) == -1) {
1971     vm_error(vm,"unable to create Port Adapter \"%s\"\n",
1972     pa_bay->dev_type);
1973     return(-1);
1974     }
1975     }
1976    
1977     /* By default, initialize a C7200-IO-FE in slot 0 if nothing found */
1978     if (!router->pa_bay[0].drv_info) {
1979     c7200_pa_add_binding(router,"C7200-IO-FE",0);
1980     c7200_pa_init(router,0);
1981     }
1982    
1983     /* Enable NVRAM operations to load/store configs */
1984     vm->nvram_extract_config = c7200_nvram_extract_config;
1985     vm->nvram_push_config = c7200_nvram_push_config;
1986    
1987     /* Verify the check list */
1988     if (c7200_checklist(router) == -1)
1989     return(-1);
1990    
1991     /* Show device list */
1992     c7200_show_hardware(router);
1993     return(0);
1994     }
1995    
1996     /* Boot the IOS image */
1997     int c7200_boot_ios(c7200_t *router)
1998     {
1999     vm_instance_t *vm = router->vm;
2000    
2001     if (!vm->boot_cpu)
2002     return(-1);
2003    
2004     /* Suspend CPU activity since we will restart directly from ROM */
2005     vm_suspend(vm);
2006    
2007     /* Check that CPU activity is really suspended */
2008     if (cpu_group_sync_state(vm->cpu_group) == -1) {
2009     vm_error(vm,"unable to sync with system CPUs.\n");
2010     return(-1);
2011     }
2012    
2013     /* Reset the boot CPU */
2014     mips64_reset(vm->boot_cpu);
2015    
2016     /* Load IOS image */
2017     if (mips64_load_elf_image(vm->boot_cpu,vm->ios_image,
2018     &vm->ios_entry_point) < 0)
2019     {
2020     vm_error(vm,"failed to load Cisco IOS image '%s'.\n",vm->ios_image);
2021     return(-1);
2022     }
2023    
2024     /* Launch the simulation */
2025     printf("\nC7200 '%s': starting simulation (CPU0 PC=0x%llx), "
2026     "JIT %sabled.\n",
2027     vm->name,vm->boot_cpu->pc,vm->jit_use ? "en":"dis");
2028    
2029     vm_log(vm,"C7200_BOOT",
2030     "starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s)\n",
2031     vm->boot_cpu->pc,vm->boot_cpu->idle_pc,vm->jit_use ? "on":"off");
2032    
2033     /* Start main CPU */
2034     vm->status = VM_STATUS_RUNNING;
2035     cpu_start(vm->boot_cpu);
2036     return(0);
2037     }
2038    
2039     /* Initialize a Cisco 7200 instance */
2040     int c7200_init_instance(c7200_t *router)
2041     {
2042     vm_instance_t *vm = router->vm;
2043     m_uint32_t rom_entry_point;
2044     cpu_mips_t *cpu0;
2045    
2046     /* Initialize the C7200 platform */
2047     if (c7200_init_platform(router) == -1) {
2048     vm_error(vm,"unable to initialize the platform hardware.\n");
2049     return(-1);
2050     }
2051    
2052     /* Load IOS configuration file */
2053     if (vm->ios_config != NULL) {
2054     vm_nvram_push_config(vm,vm->ios_config);
2055     vm->conf_reg &= ~0x40;
2056     }
2057    
2058     /* Load ROM (ELF image or embedded) */
2059     cpu0 = vm->boot_cpu;
2060     rom_entry_point = (m_uint32_t)MIPS_ROM_PC;
2061    
2062     if ((vm->rom_filename != NULL) &&
2063     (mips64_load_elf_image(cpu0,vm->rom_filename,&rom_entry_point) < 0))
2064     {
2065     vm_error(vm,"unable to load alternate ROM '%s', "
2066     "fallback to embedded ROM.\n\n",vm->rom_filename);
2067     vm->rom_filename = NULL;
2068     }
2069    
2070     /* Load symbol file */
2071     if (vm->sym_filename) {
2072     mips64_sym_load_file(cpu0,vm->sym_filename);
2073     cpu0->sym_trace = 1;
2074     }
2075    
2076     return(c7200_boot_ios(router));
2077     }
2078    
2079     /* Stop a Cisco 7200 instance */
2080     int c7200_stop_instance(c7200_t *router)
2081     {
2082     vm_instance_t *vm = router->vm;
2083    
2084     printf("\nC7200 '%s': stopping simulation.\n",vm->name);
2085     vm_log(vm,"C7200_STOP","stopping simulation.\n");
2086    
2087     /* Stop all CPUs */
2088     if (vm->cpu_group != NULL) {
2089     vm_stop(vm);
2090    
2091     if (cpu_group_sync_state(vm->cpu_group) == -1) {
2092     vm_error(vm,"unable to sync with system CPUs.\n");
2093     return(-1);
2094     }
2095     }
2096    
2097     /* Free resources that were used during execution to emulate hardware */
2098     c7200_free_hw_ressources(router);
2099     vm_hardware_shutdown(vm);
2100     return(0);
2101     }
2102    
2103     /* Trigger an OIR event */
2104     int c7200_trigger_oir_event(c7200_t *router,u_int slot_mask)
2105     {
2106     /* An OIR IRQ without reason could lead to stop the system */
2107     if (!slot_mask) return(-1);
2108    
2109     router->oir_status = slot_mask;
2110     vm_set_irq(router->vm,C7200_OIR_IRQ);
2111     return(0);
2112     }
2113    
2114     /* Initialize a new PA while the virtual router is online (OIR) */
2115     int c7200_pa_init_online(c7200_t *router,u_int pa_bay)
2116     {
2117     vm_instance_t *vm = router->vm;
2118    
2119     if (!pa_bay) {
2120     vm_error(vm,"OIR not supported on slot 0.\n");
2121     return(-1);
2122     }
2123    
2124     /*
2125     * Suspend CPU activity while adding new hardware (since we change the
2126     * memory maps).
2127     */
2128     vm_suspend(vm);
2129    
2130     /* Check that CPU activity is really suspended */
2131     if (cpu_group_sync_state(vm->cpu_group) == -1) {
2132     vm_error(vm,"unable to sync with system CPUs.\n");
2133     return(-1);
2134     }
2135    
2136     /* Add the new hardware elements */
2137     if (c7200_pa_init(router,pa_bay) == -1)
2138     return(-1);
2139    
2140     /* Resume normal operations */
2141     vm_resume(vm);
2142    
2143     /* Now, we can safely trigger the OIR event */
2144     c7200_trigger_oir_event(router,1 << pa_bay);
2145     return(0);
2146     }
2147    
2148     /* Stop a PA while the virtual router is online (OIR) */
2149     int c7200_pa_stop_online(c7200_t *router,u_int pa_bay)
2150     {
2151     vm_instance_t *vm = router->vm;
2152     struct c7200_pa_bay *bay;
2153    
2154     if (!pa_bay) {
2155     vm_error(vm,"OIR not supported on slot 0.\n");
2156     return(-1);
2157     }
2158    
2159     if (!(bay = c7200_pa_get_info(router,pa_bay)))
2160     return(-1);
2161    
2162     /* The PA driver must be initialized */
2163     if (!bay->dev_type || !bay->pa_driver) {
2164     vm_error(vm,"trying to shut down empty slot %u.\n",pa_bay);
2165     return(-1);
2166     }
2167    
2168     /* Disable all NIOs to stop traffic forwarding */
2169     c7200_pa_disable_all_nio(router,pa_bay);
2170    
2171     /* We can safely trigger the OIR event */
2172     c7200_trigger_oir_event(router,1 << pa_bay);
2173    
2174     /*
2175     * Suspend CPU activity while removing the hardware (since we change the
2176     * memory maps).
2177     */
2178     vm_suspend(vm);
2179    
2180     /* Device removal */
2181     c7200_pa_shutdown(router,pa_bay);
2182    
2183     /* Resume normal operations */
2184     vm_resume(vm);
2185     return(0);
2186     }

  ViewVC Help
Powered by ViewVC 1.1.26