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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26