1 |
/* |
/* |
2 |
* Cisco C7200 (Predator) Simulation Platform. |
* Cisco router Simulation Platform. |
3 |
* Copyright (C) 2005-2006 Christophe Fillot. All rights reserved. |
* Copyright (c) 2005-2007 Christophe Fillot. All rights reserved. |
4 |
* |
* |
5 |
* EEPROM types: |
* EEPROM types: |
6 |
* - 0x95: PA-POS-OC3SMI |
* - 0x95: PA-POS-OC3SMI |
7 |
* - 0x96: PA-POS-OC3MM |
* - 0x96: PA-POS-OC3MM |
8 |
* |
* |
9 |
* Just an experimentation (I don't have any PA-POS-OC3). It basically works, |
* Just an experimentation (I don't have any PA-POS-OC3). |
|
* on NPE-400. There is something strange with the buffer addresses in TX ring, |
|
|
* preventing this driver working with platforms using SRAM. |
|
10 |
*/ |
*/ |
11 |
|
|
12 |
#include <stdio.h> |
#include <stdio.h> |
17 |
#include <pthread.h> |
#include <pthread.h> |
18 |
#include <assert.h> |
#include <assert.h> |
19 |
|
|
20 |
#include "mips64.h" |
#include "cpu.h" |
21 |
|
#include "vm.h" |
22 |
#include "dynamips.h" |
#include "dynamips.h" |
23 |
#include "memory.h" |
#include "memory.h" |
24 |
#include "device.h" |
#include "device.h" |
26 |
#include "net_io.h" |
#include "net_io.h" |
27 |
#include "ptask.h" |
#include "ptask.h" |
28 |
#include "dev_c7200.h" |
#include "dev_c7200.h" |
29 |
|
#include "dev_plx.h" |
30 |
|
|
31 |
/* Debugging flags */ |
/* Debugging flags */ |
32 |
#define DEBUG_ACCESS 0 |
#define DEBUG_ACCESS 0 |
33 |
#define DEBUG_UNKNOWN 1 |
#define DEBUG_UNKNOWN 0 |
34 |
#define DEBUG_TRANSMIT 0 |
#define DEBUG_TRANSMIT 0 |
35 |
#define DEBUG_RECEIVE 0 |
#define DEBUG_RECEIVE 0 |
36 |
|
|
52 |
#define POS_OC3_TXDESC_WRAP 0x40000000 /* Wrap ring */ |
#define POS_OC3_TXDESC_WRAP 0x40000000 /* Wrap ring */ |
53 |
#define POS_OC3_TXDESC_CONT 0x08000000 /* Packet continues */ |
#define POS_OC3_TXDESC_CONT 0x08000000 /* Packet continues */ |
54 |
#define POS_OC3_TXDESC_LEN_MASK 0x1fff |
#define POS_OC3_TXDESC_LEN_MASK 0x1fff |
|
#define POS_OC3_TXDESC_ADDR_MASK 0x3fffffff /* Buffer address (?) */ |
|
55 |
|
|
56 |
/* RX Descriptor */ |
/* RX Descriptor */ |
57 |
struct rx_desc { |
struct rx_desc { |
67 |
struct pos_oc3_data { |
struct pos_oc3_data { |
68 |
char *name; |
char *name; |
69 |
|
|
70 |
|
/* IRQ clearing count */ |
71 |
|
u_int irq_clearing_count; |
72 |
|
|
73 |
|
/* Control register #1 */ |
74 |
|
m_uint16_t ctrl_reg1; |
75 |
|
|
76 |
|
/* CRC size */ |
77 |
|
u_int crc_size; |
78 |
|
|
79 |
/* physical addresses for start and end of RX/TX rings */ |
/* physical addresses for start and end of RX/TX rings */ |
80 |
m_uint32_t rx_start,rx_end,tx_start,tx_end; |
m_uint32_t rx_start,rx_end,tx_start,tx_end; |
81 |
|
|
101 |
ptask_id_t tx_tid; |
ptask_id_t tx_tid; |
102 |
}; |
}; |
103 |
|
|
|
/* EEPROM definition */ |
|
|
static const m_uint16_t eeprom_pos_oc3_data[64] = { |
|
|
0x0196, 0x0202, 0xffff, 0xffff, 0x490C, 0x7806, 0x0000, 0x0000, |
|
|
0x5000, 0x0000, 0x0208, 0x1900, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, |
|
|
}; |
|
|
|
|
|
static const struct c7200_eeprom eeprom_pos_oc3 = { |
|
|
"PA-POS-OC3MM", (m_uint16_t *)eeprom_pos_oc3_data, |
|
|
sizeof(eeprom_pos_oc3_data)/2, |
|
|
}; |
|
|
|
|
104 |
/* Log a PA-POS-OC3 message */ |
/* Log a PA-POS-OC3 message */ |
105 |
#define POS_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) |
#define POS_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) |
106 |
|
|
107 |
/* |
/* |
108 |
* pos_access() |
* pos_access() |
109 |
*/ |
*/ |
110 |
static void *dev_pos_access(cpu_mips_t *cpu,struct vdevice *dev, |
static void *dev_pos_access(cpu_gen_t *cpu,struct vdevice *dev, |
111 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
112 |
m_uint64_t *data) |
m_uint64_t *data) |
113 |
{ |
{ |
114 |
struct pos_oc3_data *d = dev->priv_data; |
struct pos_oc3_data *d = dev->priv_data; |
115 |
|
|
119 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
120 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
121 |
cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n", |
cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n", |
122 |
offset,cpu->pc); |
offset,cpu_get_pc(cpu)); |
123 |
} else { |
} else { |
124 |
if (offset != 0x404) |
if (offset != 0x404) |
125 |
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
126 |
"val = 0x%llx\n",offset,cpu->pc,*data); |
"val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); |
127 |
} |
} |
128 |
#endif |
#endif |
129 |
|
|
146 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
147 |
cpu_log(cpu,d->name, |
cpu_log(cpu,d->name, |
148 |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
149 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
150 |
} else { |
} else { |
151 |
cpu_log(cpu,d->name, |
cpu_log(cpu,d->name, |
152 |
"write to unknown addr 0x%x, value=0x%llx, " |
"write to unknown addr 0x%x, value=0x%llx, " |
153 |
"pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); |
"pc=0x%llx (size=%u)\n", |
154 |
|
offset,*data,cpu_get_pc(cpu),op_size); |
155 |
} |
} |
156 |
#endif |
#endif |
157 |
} |
} |
162 |
/* |
/* |
163 |
* pos_rx_access() |
* pos_rx_access() |
164 |
*/ |
*/ |
165 |
static void *dev_pos_rx_access(cpu_mips_t *cpu,struct vdevice *dev, |
static void *dev_pos_rx_access(cpu_gen_t *cpu,struct vdevice *dev, |
166 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
167 |
m_uint64_t *data) |
m_uint64_t *data) |
168 |
{ |
{ |
174 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
175 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
176 |
cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n", |
cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n", |
177 |
offset,cpu->pc); |
offset,cpu_get_pc(cpu)); |
178 |
} else { |
} else { |
179 |
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
180 |
"val = 0x%llx\n",offset,cpu->pc,*data); |
"val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); |
181 |
} |
} |
182 |
#endif |
#endif |
183 |
|
|
201 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
202 |
cpu_log(cpu,d->rx_name, |
cpu_log(cpu,d->rx_name, |
203 |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
204 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
205 |
} else { |
} else { |
206 |
cpu_log(cpu,d->rx_name, |
cpu_log(cpu,d->rx_name, |
207 |
"write to unknown addr 0x%x, value=0x%llx, " |
"write to unknown addr 0x%x, value=0x%llx, " |
208 |
"pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); |
"pc=0x%llx (size=%u)\n", |
209 |
|
offset,*data,cpu_get_pc(cpu),op_size); |
210 |
} |
} |
211 |
#endif |
#endif |
212 |
} |
} |
217 |
/* |
/* |
218 |
* pos_tx_access() |
* pos_tx_access() |
219 |
*/ |
*/ |
220 |
static void *dev_pos_tx_access(cpu_mips_t *cpu,struct vdevice *dev, |
static void *dev_pos_tx_access(cpu_gen_t *cpu,struct vdevice *dev, |
221 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
222 |
m_uint64_t *data) |
m_uint64_t *data) |
223 |
{ |
{ |
229 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
230 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
231 |
cpu_log(cpu,d->tx_name,"read access to offset = 0x%x, pc = 0x%llx\n", |
cpu_log(cpu,d->tx_name,"read access to offset = 0x%x, pc = 0x%llx\n", |
232 |
offset,cpu->pc); |
offset,cpu_get_pc(cpu)); |
233 |
} else { |
} else { |
234 |
cpu_log(cpu,d->tx_name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
cpu_log(cpu,d->tx_name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
235 |
"val = 0x%llx\n",offset,cpu->pc,*data); |
"val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); |
236 |
} |
} |
237 |
#endif |
#endif |
238 |
|
|
256 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
257 |
cpu_log(cpu,d->tx_name, |
cpu_log(cpu,d->tx_name, |
258 |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
259 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
260 |
} else { |
} else { |
261 |
cpu_log(cpu,d->tx_name, |
cpu_log(cpu,d->tx_name, |
262 |
"write to unknown addr 0x%x, value=0x%llx, " |
"write to unknown addr 0x%x, value=0x%llx, " |
263 |
"pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); |
"pc=0x%llx (size=%u)\n", |
264 |
|
offset,*data,cpu_get_pc(cpu),op_size); |
265 |
} |
} |
266 |
#endif |
#endif |
267 |
} |
} |
272 |
/* |
/* |
273 |
* pos_cs_access() |
* pos_cs_access() |
274 |
*/ |
*/ |
275 |
static void *dev_pos_cs_access(cpu_mips_t *cpu,struct vdevice *dev, |
static void *dev_pos_cs_access(cpu_gen_t *cpu,struct vdevice *dev, |
276 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
277 |
m_uint64_t *data) |
m_uint64_t *data) |
278 |
{ |
{ |
284 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
285 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
286 |
cpu_log(cpu,d->cs_name,"read access to offset = 0x%x, pc = 0x%llx\n", |
cpu_log(cpu,d->cs_name,"read access to offset = 0x%x, pc = 0x%llx\n", |
287 |
offset,cpu->pc); |
offset,cpu_get_pc(cpu)); |
288 |
} else { |
} else { |
289 |
cpu_log(cpu,d->cs_name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
cpu_log(cpu,d->cs_name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
290 |
"val = 0x%llx\n",offset,cpu->pc,*data); |
"val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); |
291 |
} |
} |
292 |
#endif |
#endif |
293 |
|
|
295 |
case 0x300000: |
case 0x300000: |
296 |
case 0x300004: |
case 0x300004: |
297 |
case 0x30001c: |
case 0x30001c: |
298 |
if (op_type == MTS_READ) |
if (op_type == MTS_READ) { |
299 |
*data = 0x00000FFF; |
*data = 0x00000FFF; |
300 |
|
|
301 |
|
/* Add a delay before clearing the IRQ */ |
302 |
|
if (++d->irq_clearing_count == 20) { |
303 |
|
pci_dev_clear_irq(d->vm,d->pci_dev); |
304 |
|
d->irq_clearing_count = 0; |
305 |
|
} |
306 |
|
} |
307 |
break; |
break; |
308 |
|
|
309 |
case 0x300008: |
case 0x300008: |
311 |
*data = 0x000007F; |
*data = 0x000007F; |
312 |
break; |
break; |
313 |
|
|
314 |
|
case 0x300028: |
315 |
|
if (op_type == MTS_READ) { |
316 |
|
*data = d->ctrl_reg1; |
317 |
|
} else { |
318 |
|
d->ctrl_reg1 = *data; |
319 |
|
|
320 |
|
switch(*data) { |
321 |
|
case 0x06: |
322 |
|
d->crc_size = 2; |
323 |
|
break; |
324 |
|
case 0x07: |
325 |
|
d->crc_size = 4; |
326 |
|
break; |
327 |
|
default: |
328 |
|
d->crc_size = 2; |
329 |
|
cpu_log(cpu,d->cs_name, |
330 |
|
"unknown value 0x%4.4llx written in ctrl_reg1\n", |
331 |
|
*data); |
332 |
|
} |
333 |
|
cpu_log(cpu,d->cs_name,"CRC size set to 0x%4.4x\n",d->crc_size); |
334 |
|
} |
335 |
|
break; |
336 |
|
|
337 |
#if DEBUG_UNKNOWN |
#if DEBUG_UNKNOWN |
338 |
default: |
default: |
339 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
340 |
cpu_log(cpu,d->cs_name, |
cpu_log(cpu,d->cs_name, |
341 |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
342 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
343 |
} else { |
} else { |
344 |
cpu_log(cpu,d->cs_name, |
cpu_log(cpu,d->cs_name, |
345 |
"write to unknown addr 0x%x, value=0x%llx, " |
"write to unknown addr 0x%x, value=0x%llx, " |
346 |
"pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); |
"pc=0x%llx (size=%u)\n", |
347 |
|
offset,*data,cpu_get_pc(cpu),op_size); |
348 |
} |
} |
349 |
#endif |
#endif |
350 |
} |
} |
454 |
|
|
455 |
/* We have finished if the complete packet has been stored */ |
/* We have finished if the complete packet has been stored */ |
456 |
if (tot_len == 0) { |
if (tot_len == 0) { |
457 |
rxdc->rdes[0] = cp_len + 4; |
rxdc->rdes[0] = (cp_len + d->crc_size); |
458 |
|
|
459 |
if (i != 0) |
if (i != 0) |
460 |
physmem_copy_u32_to_vm(d->vm,d->rx_current,rxdc->rdes[0]); |
physmem_copy_u32_to_vm(d->vm,d->rx_current,rxdc->rdes[0]); |
537 |
static int dev_pos_oc3_handle_txring(struct pos_oc3_data *d) |
static int dev_pos_oc3_handle_txring(struct pos_oc3_data *d) |
538 |
{ |
{ |
539 |
u_char pkt[POS_OC3_MAX_PKT_SIZE],*pkt_ptr; |
u_char pkt[POS_OC3_MAX_PKT_SIZE],*pkt_ptr; |
540 |
m_uint32_t tx_start,clen,tot_len,addr; |
m_uint32_t clen,tot_len,norm_len; |
541 |
|
m_uint32_t tx_start,addr; |
542 |
struct tx_desc txd0,ctxd,*ptxd; |
struct tx_desc txd0,ctxd,*ptxd; |
543 |
int i,done = FALSE; |
int i,done = FALSE; |
544 |
|
|
580 |
if (clen != 0) { |
if (clen != 0) { |
581 |
addr = ptxd->tdes[1]; |
addr = ptxd->tdes[1]; |
582 |
|
|
583 |
/* ugly hack, to allow this to work with SRAM platforms */ |
norm_len = normalize_size(clen,4,0); |
584 |
if ((addr & ~POS_OC3_TXDESC_ADDR_MASK) == 0xc0000000) |
physmem_copy_from_vm(d->vm,pkt_ptr,addr,norm_len); |
585 |
addr = ptxd->tdes[1] & POS_OC3_TXDESC_ADDR_MASK; |
mem_bswap32(pkt_ptr,norm_len); |
|
|
|
|
physmem_copy_from_vm(d->vm,pkt_ptr,addr,clen); |
|
586 |
} |
} |
587 |
|
|
588 |
pkt_ptr += clen; |
pkt_ptr += clen; |
626 |
/* |
/* |
627 |
* pci_pos_read() |
* pci_pos_read() |
628 |
*/ |
*/ |
629 |
static m_uint32_t pci_pos_read(cpu_mips_t *cpu,struct pci_device *dev,int reg) |
static m_uint32_t pci_pos_read(cpu_gen_t *cpu,struct pci_device *dev,int reg) |
630 |
{ |
{ |
631 |
struct pos_oc3_data *d = dev->priv_data; |
struct pos_oc3_data *d = dev->priv_data; |
632 |
|
|
645 |
/* |
/* |
646 |
* pci_pos_write() |
* pci_pos_write() |
647 |
*/ |
*/ |
648 |
static void pci_pos_write(cpu_mips_t *cpu,struct pci_device *dev, |
static void pci_pos_write(cpu_gen_t *cpu,struct pci_device *dev, |
649 |
int reg,m_uint32_t value) |
int reg,m_uint32_t value) |
650 |
{ |
{ |
651 |
struct pos_oc3_data *d = dev->priv_data; |
struct pos_oc3_data *d = dev->priv_data; |
667 |
* |
* |
668 |
* Add a PA-POS port adapter into specified slot. |
* Add a PA-POS port adapter into specified slot. |
669 |
*/ |
*/ |
670 |
int dev_c7200_pa_pos_init(c7200_t *router,char *name,u_int pa_bay) |
int dev_c7200_pa_pos_init(vm_instance_t *vm,struct cisco_card *card) |
671 |
{ |
{ |
|
struct pci_bus *pci_bus; |
|
672 |
struct pos_oc3_data *d; |
struct pos_oc3_data *d; |
673 |
|
u_int slot = card->slot_id; |
674 |
|
|
675 |
/* Allocate the private data structure for PA-POS-OC3 chip */ |
/* Allocate the private data structure for PA-POS-OC3 chip */ |
676 |
if (!(d = malloc(sizeof(*d)))) { |
if (!(d = malloc(sizeof(*d)))) { |
677 |
fprintf(stderr,"%s (PA-POS-OC3): out of memory\n",name); |
vm_error(vm,"%s: out of memory\n",card->dev_name); |
678 |
return(-1); |
return(-1); |
679 |
} |
} |
680 |
|
|
681 |
memset(d,0,sizeof(*d)); |
memset(d,0,sizeof(*d)); |
682 |
d->name = name; |
d->name = card->dev_name; |
683 |
d->vm = router->vm; |
d->vm = vm; |
684 |
|
|
685 |
/* Set the EEPROM */ |
/* Set the PCI bus */ |
686 |
c7200_pa_set_eeprom(router,pa_bay,&eeprom_pos_oc3); |
card->pci_bus = vm->slots_pci_bus[slot]; |
687 |
|
|
688 |
/* Get the appropriate PCI bus */ |
/* Set the EEPROM */ |
689 |
pci_bus = router->pa_bay[pa_bay].pci_map; |
cisco_card_set_eeprom(vm,card,cisco_eeprom_find_pa("PA-POS-OC3")); |
690 |
|
c7200_set_slot_eeprom(VM_C7200(vm),slot,&card->eeprom); |
691 |
|
|
692 |
/* Initialize RX device */ |
/* Initialize RX device */ |
693 |
d->rx_name = dyn_sprintf("%s_RX",name); |
d->rx_name = dyn_sprintf("%s_RX",card->dev_name); |
694 |
dev_init(&d->rx_dev); |
dev_init(&d->rx_dev); |
695 |
d->rx_dev.name = d->rx_name; |
d->rx_dev.name = d->rx_name; |
696 |
d->rx_dev.priv_data = d; |
d->rx_dev.priv_data = d; |
697 |
d->rx_dev.handler = dev_pos_rx_access; |
d->rx_dev.handler = dev_pos_rx_access; |
|
vm_bind_device(d->vm,&d->rx_dev); |
|
698 |
|
|
699 |
/* Initialize TX device */ |
/* Initialize TX device */ |
700 |
d->tx_name = dyn_sprintf("%s_TX",name); |
d->tx_name = dyn_sprintf("%s_TX",card->dev_name); |
701 |
dev_init(&d->tx_dev); |
dev_init(&d->tx_dev); |
702 |
d->tx_dev.name = d->tx_name; |
d->tx_dev.name = d->tx_name; |
703 |
d->tx_dev.priv_data = d; |
d->tx_dev.priv_data = d; |
704 |
d->tx_dev.handler = dev_pos_tx_access; |
d->tx_dev.handler = dev_pos_tx_access; |
|
vm_bind_device(d->vm,&d->tx_dev); |
|
705 |
|
|
706 |
/* Initialize CS device */ |
/* Initialize CS device */ |
707 |
d->cs_name = dyn_sprintf("%s_CS",name); |
d->cs_name = dyn_sprintf("%s_CS",card->dev_name); |
708 |
dev_init(&d->cs_dev); |
dev_init(&d->cs_dev); |
709 |
d->cs_dev.name = d->cs_name; |
d->cs_dev.name = d->cs_name; |
710 |
d->cs_dev.priv_data = d; |
d->cs_dev.priv_data = d; |
711 |
d->cs_dev.handler = dev_pos_cs_access; |
d->cs_dev.handler = dev_pos_cs_access; |
|
vm_bind_device(d->vm,&d->cs_dev); |
|
712 |
|
|
713 |
/* Initialize PLX9060 for RX part */ |
/* Initialize PLX9060 for RX part */ |
714 |
d->rx_obj = dev_plx9060_init(d->vm,d->rx_name,pci_bus,0,&d->rx_dev); |
d->rx_obj = dev_plx9060_init(vm,d->rx_name,card->pci_bus,0,&d->rx_dev); |
715 |
|
|
716 |
/* Initialize PLX9060 for TX part */ |
/* Initialize PLX9060 for TX part */ |
717 |
d->tx_obj = dev_plx9060_init(d->vm,d->tx_name,pci_bus,1,&d->tx_dev); |
d->tx_obj = dev_plx9060_init(vm,d->tx_name,card->pci_bus,1,&d->tx_dev); |
718 |
|
|
719 |
/* Initialize PLX9060 for CS part (CS=card status, chip status, ... ?) */ |
/* Initialize PLX9060 for CS part (CS=card status, chip status, ... ?) */ |
720 |
d->cs_obj = dev_plx9060_init(d->vm,d->cs_name,pci_bus,2,&d->cs_dev); |
d->cs_obj = dev_plx9060_init(vm,d->cs_name,card->pci_bus,2,&d->cs_dev); |
721 |
|
|
722 |
/* Unknown PCI device here (will be mapped at 0x30000) */ |
/* Unknown PCI device here (will be mapped at 0x30000) */ |
723 |
dev_init(&d->dev); |
dev_init(&d->dev); |
724 |
d->dev.name = name; |
d->dev.name = card->dev_name; |
725 |
d->dev.priv_data = d; |
d->dev.priv_data = d; |
726 |
d->dev.phys_len = 0x10000; |
d->dev.phys_len = 0x10000; |
727 |
d->dev.handler = dev_pos_access; |
d->dev.handler = dev_pos_access; |
|
vm_bind_device(d->vm,&d->dev); |
|
728 |
|
|
729 |
d->pci_dev = pci_dev_add(pci_bus,name,0,0,3,0,C7200_NETIO_IRQ, |
d->pci_dev = pci_dev_add(card->pci_bus,card->dev_name,0,0,3,0, |
730 |
|
c7200_net_irq_for_slot_port(slot,0), |
731 |
d,NULL,pci_pos_read,pci_pos_write); |
d,NULL,pci_pos_read,pci_pos_write); |
732 |
|
|
733 |
/* Store device info into the router structure */ |
/* Store device info into the router structure */ |
734 |
return(c7200_pa_set_drvinfo(router,pa_bay,d)); |
card->drv_info = d; |
735 |
|
return(0); |
736 |
} |
} |
737 |
|
|
738 |
/* Remove a PA-POS-OC3 from the specified slot */ |
/* Remove a PA-POS-OC3 from the specified slot */ |
739 |
int dev_c7200_pa_pos_shutdown(c7200_t *router,u_int pa_bay) |
int dev_c7200_pa_pos_shutdown(vm_instance_t *vm,struct cisco_card *card) |
740 |
{ |
{ |
741 |
struct c7200_pa_bay *bay; |
struct pos_oc3_data *d = card->drv_info; |
|
struct pos_oc3_data *d; |
|
|
|
|
|
if (!(bay = c7200_pa_get_info(router,pa_bay))) |
|
|
return(-1); |
|
|
|
|
|
d = bay->drv_info; |
|
742 |
|
|
743 |
/* Remove the PA EEPROM */ |
/* Remove the PA EEPROM */ |
744 |
c7200_pa_unset_eeprom(router,pa_bay); |
cisco_card_unset_eeprom(card); |
745 |
|
c7200_set_slot_eeprom(VM_C7200(vm),card->slot_id,NULL); |
746 |
|
|
747 |
/* Remove the PCI device */ |
/* Remove the PCI device */ |
748 |
pci_dev_remove(d->pci_dev); |
pci_dev_remove(d->pci_dev); |
749 |
|
|
750 |
/* Remove the PLX9060 chips */ |
/* Remove the PLX9060 chips */ |
751 |
vm_object_remove(d->vm,d->rx_obj); |
vm_object_remove(vm,d->rx_obj); |
752 |
vm_object_remove(d->vm,d->tx_obj); |
vm_object_remove(vm,d->tx_obj); |
753 |
vm_object_remove(d->vm,d->cs_obj); |
vm_object_remove(vm,d->cs_obj); |
754 |
|
|
755 |
/* Remove the device from the CPU address space */ |
/* Remove the devices from the CPU address space */ |
756 |
vm_unbind_device(router->vm,&d->dev); |
vm_unbind_device(vm,&d->rx_dev); |
757 |
cpu_group_rebuild_mts(router->vm->cpu_group); |
vm_unbind_device(vm,&d->tx_dev); |
758 |
|
vm_unbind_device(vm,&d->cs_dev); |
759 |
|
|
760 |
|
vm_unbind_device(vm,&d->dev); |
761 |
|
cpu_group_rebuild_mts(vm->cpu_group); |
762 |
|
|
763 |
/* Free the device structure itself */ |
/* Free the device structure itself */ |
764 |
free(d); |
free(d); |
766 |
} |
} |
767 |
|
|
768 |
/* Bind a Network IO descriptor to a specific port */ |
/* Bind a Network IO descriptor to a specific port */ |
769 |
int dev_c7200_pa_pos_set_nio(c7200_t *router,u_int pa_bay,u_int port_id, |
int dev_c7200_pa_pos_set_nio(vm_instance_t *vm,struct cisco_card *card, |
770 |
netio_desc_t *nio) |
u_int port_id,netio_desc_t *nio) |
771 |
{ |
{ |
772 |
struct pos_oc3_data *d; |
struct pos_oc3_data *d = card->drv_info; |
773 |
|
|
774 |
if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) |
if (!d || (port_id > 0)) |
775 |
return(-1); |
return(-1); |
776 |
|
|
777 |
if (d->nio != NULL) |
if (d->nio != NULL) |
784 |
} |
} |
785 |
|
|
786 |
/* Bind a Network IO descriptor to a specific port */ |
/* Bind a Network IO descriptor to a specific port */ |
787 |
int dev_c7200_pa_pos_unset_nio(c7200_t *router,u_int pa_bay,u_int port_id) |
int dev_c7200_pa_pos_unset_nio(vm_instance_t *vm,struct cisco_card *card, |
788 |
|
u_int port_id) |
789 |
{ |
{ |
790 |
struct pos_oc3_data *d; |
struct pos_oc3_data *d = card->drv_info; |
791 |
|
|
792 |
if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) |
if (!d || (port_id > 0)) |
793 |
return(-1); |
return(-1); |
794 |
|
|
795 |
if (d->nio) { |
if (d->nio) { |
801 |
} |
} |
802 |
|
|
803 |
/* PA-POS-OC3 driver */ |
/* PA-POS-OC3 driver */ |
804 |
struct c7200_pa_driver dev_c7200_pa_pos_oc3_driver = { |
struct cisco_card_driver dev_c7200_pa_pos_oc3_driver = { |
805 |
"PA-POS-OC3", 1, |
"PA-POS-OC3", 1, 0, |
806 |
dev_c7200_pa_pos_init, |
dev_c7200_pa_pos_init, |
807 |
dev_c7200_pa_pos_shutdown, |
dev_c7200_pa_pos_shutdown, |
808 |
|
NULL, |
809 |
dev_c7200_pa_pos_set_nio, |
dev_c7200_pa_pos_set_nio, |
810 |
dev_c7200_pa_pos_unset_nio, |
dev_c7200_pa_pos_unset_nio, |
811 |
|
NULL, |
812 |
}; |
}; |