1 |
/* |
/* |
2 |
* Cisco C7200 (Predator) Simulation Platform. |
* Cisco router simulation platform. |
3 |
* Copyright (C) 2005,2006 Christophe Fillot. All rights reserved. |
* Copyright (C) 2005,2006 Christophe Fillot. All rights reserved. |
4 |
* |
* |
5 |
* PA-A1 ATM interface based on TI1570 and PLX 9060-ES. |
* PA-A1 ATM interface based on TI1570 and PLX 9060-ES. |
35 |
|
|
36 |
#include "crc.h" |
#include "crc.h" |
37 |
#include "atm.h" |
#include "atm.h" |
38 |
#include "mips64.h" |
#include "cpu.h" |
39 |
|
#include "vm.h" |
40 |
#include "dynamips.h" |
#include "dynamips.h" |
41 |
#include "memory.h" |
#include "memory.h" |
42 |
#include "device.h" |
#include "device.h" |
285 |
struct pa_a1_data { |
struct pa_a1_data { |
286 |
char *name; |
char *name; |
287 |
|
|
288 |
|
/* IRQ clearing counter */ |
289 |
|
u_int irq_clear_count; |
290 |
|
|
291 |
/* Control Memory pointer */ |
/* Control Memory pointer */ |
292 |
m_uint32_t *ctrl_mem_ptr; |
m_uint32_t *ctrl_mem_ptr; |
293 |
|
|
339 |
/* Reset the TI1570 (forward declaration) */ |
/* Reset the TI1570 (forward declaration) */ |
340 |
static void ti1570_reset(struct pa_a1_data *d,int clear_ctrl_mem); |
static void ti1570_reset(struct pa_a1_data *d,int clear_ctrl_mem); |
341 |
|
|
342 |
|
/* Update the interrupt status */ |
343 |
|
static inline void dev_pa_a1_update_irq_status(struct pa_a1_data *d) |
344 |
|
{ |
345 |
|
if (d->iregs[TI1570_REG_STATUS] & d->iregs[TI1570_REG_IMASK]) { |
346 |
|
pci_dev_trigger_irq(d->vm,d->pci_dev_ti); |
347 |
|
} else { |
348 |
|
pci_dev_clear_irq(d->vm,d->pci_dev_ti); |
349 |
|
} |
350 |
|
} |
351 |
|
|
352 |
/* |
/* |
353 |
* dev_pa_a1_access() |
* dev_pa_a1_access() |
354 |
*/ |
*/ |
355 |
void *dev_pa_a1_access(cpu_mips_t *cpu,struct vdevice *dev,m_uint32_t offset, |
void *dev_pa_a1_access(cpu_gen_t *cpu,struct vdevice *dev,m_uint32_t offset, |
356 |
u_int op_size,u_int op_type,m_uint64_t *data) |
u_int op_size,u_int op_type,m_uint64_t *data) |
357 |
{ |
{ |
358 |
struct pa_a1_data *d = dev->priv_data; |
struct pa_a1_data *d = dev->priv_data; |
363 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
364 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
365 |
cpu_log(cpu,"TI1570","read access to offset = 0x%x, pc = 0x%llx\n", |
cpu_log(cpu,"TI1570","read access to offset = 0x%x, pc = 0x%llx\n", |
366 |
offset,cpu->pc); |
offset,cpu_get_pc(cpu)); |
367 |
} else { |
} else { |
368 |
cpu_log(cpu,"TI1570","write access to vaddr = 0x%x, pc = 0x%llx, " |
cpu_log(cpu,"TI1570","write access to vaddr = 0x%x, pc = 0x%llx, " |
369 |
"val = 0x%llx\n",offset,cpu->pc,*data); |
"val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); |
370 |
} |
} |
371 |
#endif |
#endif |
372 |
|
|
373 |
/* Specific cases */ |
/* Specific cases */ |
374 |
switch(offset) { |
switch(offset) { |
375 |
|
/* Status register */ |
376 |
|
case 0x3204: |
377 |
|
if (op_type == MTS_READ) { |
378 |
|
*data = d->iregs[TI1570_REG_STATUS]; |
379 |
|
|
380 |
|
if (++d->irq_clear_count == 2) { |
381 |
|
d->iregs[TI1570_REG_STATUS] &= ~0x3FF; |
382 |
|
d->irq_clear_count = 0; |
383 |
|
} |
384 |
|
|
385 |
|
dev_pa_a1_update_irq_status(d); |
386 |
|
} |
387 |
|
break; |
388 |
|
|
389 |
|
/* Software Reset register */ |
390 |
case 0x3238: |
case 0x3238: |
391 |
TI1570_LOG(d,"reset issued.\n"); |
TI1570_LOG(d,"reset issued.\n"); |
392 |
ti1570_reset(d,FALSE); |
ti1570_reset(d,FALSE); |
413 |
#if DEBUG_UNKNOWN |
#if DEBUG_UNKNOWN |
414 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
415 |
cpu_log(cpu,d->name,"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
cpu_log(cpu,d->name,"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
416 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
417 |
} else { |
} else { |
418 |
cpu_log(cpu,d->name,"write to unknown addr 0x%x, value=0x%llx, " |
cpu_log(cpu,d->name,"write to unknown addr 0x%x, value=0x%llx, " |
419 |
"pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); |
"pc=0x%llx (size=%u)\n",offset,*data,cpu_get_pc(cpu),op_size); |
420 |
} |
} |
421 |
#endif |
#endif |
422 |
return NULL; |
return NULL; |
916 |
/* Generate an interrupt if required */ |
/* Generate an interrupt if required */ |
917 |
if (tde->ctrl_buf & TI1570_TX_DMA_TCR_SELECT) |
if (tde->ctrl_buf & TI1570_TX_DMA_TCR_SELECT) |
918 |
{ |
{ |
919 |
if (((d->iregs[TI1570_REG_STATUS] & TI1570_CFG_BP_SEL) && buf_end) || |
if (((d->iregs[TI1570_REG_CONFIG] & TI1570_CFG_BP_SEL) && buf_end) || |
920 |
pkt_end) |
pkt_end) |
921 |
{ |
{ |
922 |
d->iregs[TI1570_REG_STATUS] |= TI1570_STAT_CP_TX; |
d->iregs[TI1570_REG_STATUS] |= TI1570_STAT_CP_TX; |
923 |
pci_dev_trigger_irq(d->vm,d->pci_dev_ti); |
dev_pa_a1_update_irq_status(d); |
924 |
} |
} |
925 |
} |
} |
926 |
|
|
1053 |
|
|
1054 |
/* generate the appropriate IRQ */ |
/* generate the appropriate IRQ */ |
1055 |
d->iregs[TI1570_REG_STATUS] |= TI1570_STAT_CP_RX; |
d->iregs[TI1570_REG_STATUS] |= TI1570_STAT_CP_RX; |
1056 |
pci_dev_trigger_irq(d->vm,d->pci_dev_ti); |
dev_pa_a1_update_irq_status(d); |
1057 |
} else { |
} else { |
1058 |
rcr_end = (d->iregs[TI1570_REG_RX_CRING_SIZE] >> 16); |
rcr_end = (d->iregs[TI1570_REG_RX_CRING_SIZE] >> 16); |
1059 |
rcr_end &= TI1570_RCR_SIZE_MASK; |
rcr_end &= TI1570_RCR_SIZE_MASK; |
1457 |
/* |
/* |
1458 |
* pci_ti1570_read() |
* pci_ti1570_read() |
1459 |
*/ |
*/ |
1460 |
static m_uint32_t pci_ti1570_read(cpu_mips_t *cpu,struct pci_device *dev, |
static m_uint32_t pci_ti1570_read(cpu_gen_t *cpu,struct pci_device *dev, |
1461 |
int reg) |
int reg) |
1462 |
{ |
{ |
1463 |
struct pa_a1_data *d = dev->priv_data; |
struct pa_a1_data *d = dev->priv_data; |
1477 |
/* |
/* |
1478 |
* pci_ti1570_write() |
* pci_ti1570_write() |
1479 |
*/ |
*/ |
1480 |
static void pci_ti1570_write(cpu_mips_t *cpu,struct pci_device *dev, |
static void pci_ti1570_write(cpu_gen_t *cpu,struct pci_device *dev, |
1481 |
int reg,m_uint32_t value) |
int reg,m_uint32_t value) |
1482 |
{ |
{ |
1483 |
struct pa_a1_data *d = dev->priv_data; |
struct pa_a1_data *d = dev->priv_data; |
1497 |
/* |
/* |
1498 |
* pci_plx9060es_read() |
* pci_plx9060es_read() |
1499 |
*/ |
*/ |
1500 |
static m_uint32_t pci_plx9060es_read(cpu_mips_t *cpu,struct pci_device *dev, |
static m_uint32_t pci_plx9060es_read(cpu_gen_t *cpu,struct pci_device *dev, |
1501 |
int reg) |
int reg) |
1502 |
{ |
{ |
1503 |
|
struct pa_a1_data *d = dev->priv_data; |
1504 |
|
|
1505 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
1506 |
TI1570_LOG(d,"PLX9060ES","read reg 0x%x\n",reg); |
TI1570_LOG(d,"PLX9060ES","read reg 0x%x\n",reg); |
1507 |
#endif |
#endif |
1514 |
/* |
/* |
1515 |
* pci_plx9060es_write() |
* pci_plx9060es_write() |
1516 |
*/ |
*/ |
1517 |
static void pci_plx9060es_write(cpu_mips_t *cpu,struct pci_device *dev, |
static void pci_plx9060es_write(cpu_gen_t *cpu,struct pci_device *dev, |
1518 |
int reg,m_uint32_t value) |
int reg,m_uint32_t value) |
1519 |
{ |
{ |
1520 |
|
struct pa_a1_data *d = dev->priv_data; |
1521 |
|
|
1522 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
1523 |
TI1570_LOG(d,"PLX9060ES","write reg 0x%x, value 0x%x\n",reg,value); |
TI1570_LOG(d,"PLX9060ES","write reg 0x%x, value 0x%x\n",reg,value); |
1524 |
#endif |
#endif |
1544 |
* |
* |
1545 |
* Add a PA-A1 port adapter into specified slot. |
* Add a PA-A1 port adapter into specified slot. |
1546 |
*/ |
*/ |
1547 |
int dev_c7200_pa_a1_init(c7200_t *router,char *name,u_int pa_bay) |
int dev_c7200_pa_a1_init(vm_instance_t *vm,struct cisco_card *card) |
1548 |
{ |
{ |
1549 |
|
u_int slot = card->slot_id; |
1550 |
struct pci_device *pci_dev_ti,*pci_dev_plx; |
struct pci_device *pci_dev_ti,*pci_dev_plx; |
1551 |
struct pa_a1_data *d; |
struct pa_a1_data *d; |
1552 |
struct vdevice *dev; |
struct vdevice *dev; |
1554 |
|
|
1555 |
/* Allocate the private data structure for TI1570 chip */ |
/* Allocate the private data structure for TI1570 chip */ |
1556 |
if (!(d = malloc(sizeof(*d)))) { |
if (!(d = malloc(sizeof(*d)))) { |
1557 |
fprintf(stderr,"%s (TI1570): out of memory\n",name); |
vm_error(vm,"%s: out of memory\n",card->dev_name); |
1558 |
return(-1); |
return(-1); |
1559 |
} |
} |
1560 |
|
|
1561 |
memset(d,0,sizeof(*d)); |
memset(d,0,sizeof(*d)); |
1562 |
|
|
1563 |
|
/* Set the PCI bus */ |
1564 |
|
card->pci_bus = vm->slots_pci_bus[slot]; |
1565 |
|
|
1566 |
/* Set the EEPROM */ |
/* Set the EEPROM */ |
1567 |
c7200_pa_set_eeprom(router,pa_bay,cisco_eeprom_find_pa("PA-A1")); |
cisco_card_set_eeprom(vm,card,cisco_eeprom_find_pa("PA-A1")); |
1568 |
|
c7200_set_slot_eeprom(VM_C7200(vm),slot,&card->eeprom); |
1569 |
|
|
1570 |
/* Add PCI device TI1570 */ |
/* Add PCI device TI1570 */ |
1571 |
pci_dev_ti = pci_dev_add(router->pa_bay[pa_bay].pci_map,name, |
pci_dev_ti = pci_dev_add(card->pci_bus,card->dev_name, |
1572 |
TI1570_PCI_VENDOR_ID,TI1570_PCI_PRODUCT_ID, |
TI1570_PCI_VENDOR_ID,TI1570_PCI_PRODUCT_ID, |
1573 |
0,0,C7200_NETIO_IRQ,d, |
0,0,c7200_net_irq_for_slot_port(slot,0),d, |
1574 |
NULL,pci_ti1570_read,pci_ti1570_write); |
NULL,pci_ti1570_read,pci_ti1570_write); |
1575 |
|
|
1576 |
if (!pci_dev_ti) { |
if (!pci_dev_ti) { |
1577 |
fprintf(stderr,"%s (TI1570): unable to create PCI device TI1570.\n", |
vm_error(vm,"%s: unable to create PCI device TI1570.\n", |
1578 |
name); |
card->dev_name); |
1579 |
return(-1); |
return(-1); |
1580 |
} |
} |
1581 |
|
|
1582 |
/* Add PCI device PLX9060ES */ |
/* Add PCI device PLX9060ES */ |
1583 |
pci_dev_plx = pci_dev_add(router->pa_bay[pa_bay].pci_map,name, |
pci_dev_plx = pci_dev_add(card->pci_bus,card->dev_name, |
1584 |
PLX_9060ES_PCI_VENDOR_ID, |
PLX_9060ES_PCI_VENDOR_ID, |
1585 |
PLX_9060ES_PCI_PRODUCT_ID, |
PLX_9060ES_PCI_PRODUCT_ID, |
1586 |
1,0,C7200_NETIO_IRQ,d, |
1,0,-1,d, |
1587 |
NULL,pci_plx9060es_read,pci_plx9060es_write); |
NULL,pci_plx9060es_read,pci_plx9060es_write); |
1588 |
|
|
1589 |
if (!pci_dev_plx) { |
if (!pci_dev_plx) { |
1590 |
fprintf(stderr,"%s (PLX_9060ES): unable to create PCI device " |
vm_error(vm,"%s: unable to create PCI device PLX 9060ES.\n", |
1591 |
"PLX 9060ES.\n",name); |
card->dev_name); |
1592 |
return(-1); |
return(-1); |
1593 |
} |
} |
1594 |
|
|
1595 |
/* Create the TI1570 structure */ |
/* Create the TI1570 structure */ |
1596 |
d->name = name; |
d->name = card->dev_name; |
1597 |
d->vm = router->vm; |
d->vm = vm; |
1598 |
d->pci_dev_ti = pci_dev_ti; |
d->pci_dev_ti = pci_dev_ti; |
1599 |
d->pci_dev_plx = pci_dev_plx; |
d->pci_dev_plx = pci_dev_plx; |
1600 |
|
|
1601 |
/* Allocate the control memory */ |
/* Allocate the control memory */ |
1602 |
if (!(d->ctrl_mem_ptr = malloc(TI1570_CTRL_MEM_SIZE))) { |
if (!(d->ctrl_mem_ptr = malloc(TI1570_CTRL_MEM_SIZE))) { |
1603 |
fprintf(stderr,"%s (PA-A1): unable to create control memory.\n",name); |
vm_error(vm,"%s: unable to create control memory.\n",card->dev_name); |
1604 |
return(-1); |
return(-1); |
1605 |
} |
} |
1606 |
|
|
1617 |
ti1570_reset(d,TRUE); |
ti1570_reset(d,TRUE); |
1618 |
|
|
1619 |
/* Create the device itself */ |
/* Create the device itself */ |
1620 |
if (!(dev = dev_create(name))) { |
if (!(dev = dev_create(card->dev_name))) { |
1621 |
fprintf(stderr,"%s (PA-A1): unable to create device.\n",name); |
vm_error(vm,"%s: unable to create device.\n",card->dev_name); |
1622 |
return(-1); |
return(-1); |
1623 |
} |
} |
1624 |
|
|
1631 |
d->dev = dev; |
d->dev = dev; |
1632 |
|
|
1633 |
/* Store device info into the router structure */ |
/* Store device info into the router structure */ |
1634 |
return(c7200_pa_set_drvinfo(router,pa_bay,d)); |
card->drv_info = d; |
1635 |
|
return(0); |
1636 |
} |
} |
1637 |
|
|
1638 |
/* Remove a PA-A1 from the specified slot */ |
/* Remove a PA-A1 from the specified slot */ |
1639 |
int dev_c7200_pa_a1_shutdown(c7200_t *router,u_int pa_bay) |
int dev_c7200_pa_a1_shutdown(vm_instance_t *vm,struct cisco_card *card) |
1640 |
{ |
{ |
1641 |
struct c7200_pa_bay *bay; |
struct pa_a1_data *d = card->drv_info; |
|
struct pa_a1_data *d; |
|
|
|
|
|
if (!(bay = c7200_pa_get_info(router,pa_bay))) |
|
|
return(-1); |
|
|
|
|
|
d = bay->drv_info; |
|
1642 |
|
|
1643 |
/* Remove the PA EEPROM */ |
/* Remove the PA EEPROM */ |
1644 |
c7200_pa_unset_eeprom(router,pa_bay); |
cisco_card_unset_eeprom(card); |
1645 |
|
c7200_set_slot_eeprom(VM_C7200(vm),card->slot_id,NULL); |
1646 |
|
|
1647 |
/* Remove the PCI devices */ |
/* Remove the PCI devices */ |
1648 |
pci_dev_remove(d->pci_dev_ti); |
pci_dev_remove(d->pci_dev_ti); |
1649 |
pci_dev_remove(d->pci_dev_plx); |
pci_dev_remove(d->pci_dev_plx); |
1650 |
|
|
1651 |
/* Remove the device from the VM address space */ |
/* Remove the device from the VM address space */ |
1652 |
vm_unbind_device(router->vm,d->dev); |
vm_unbind_device(vm,d->dev); |
1653 |
cpu_group_rebuild_mts(router->vm->cpu_group); |
cpu_group_rebuild_mts(vm->cpu_group); |
1654 |
|
|
1655 |
/* Free the control memory */ |
/* Free the control memory */ |
1656 |
free(d->ctrl_mem_ptr); |
free(d->ctrl_mem_ptr); |
1662 |
} |
} |
1663 |
|
|
1664 |
/* Bind a Network IO descriptor to a specific port */ |
/* Bind a Network IO descriptor to a specific port */ |
1665 |
int dev_c7200_pa_a1_set_nio(c7200_t *router,u_int pa_bay,u_int port_id, |
int dev_c7200_pa_a1_set_nio(vm_instance_t *vm,struct cisco_card *card, |
1666 |
netio_desc_t *nio) |
u_int port_id,netio_desc_t *nio) |
1667 |
{ |
{ |
1668 |
struct pa_a1_data *d; |
struct pa_a1_data *d = card->drv_info; |
1669 |
|
|
1670 |
if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) |
if (!d || (port_id > 0)) |
1671 |
return(-1); |
return(-1); |
1672 |
|
|
1673 |
if (d->nio != NULL) |
if (d->nio != NULL) |
1680 |
} |
} |
1681 |
|
|
1682 |
/* Unbind a Network IO descriptor to a specific port */ |
/* Unbind a Network IO descriptor to a specific port */ |
1683 |
int dev_c7200_pa_a1_unset_nio(c7200_t *router,u_int pa_bay,u_int port_id) |
int dev_c7200_pa_a1_unset_nio(vm_instance_t *vm,struct cisco_card *card, |
1684 |
|
u_int port_id) |
1685 |
{ |
{ |
1686 |
struct pa_a1_data *d; |
struct pa_a1_data *d = card->drv_info; |
1687 |
|
|
1688 |
if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) |
if (!d || (port_id > 0)) |
1689 |
return(-1); |
return(-1); |
1690 |
|
|
1691 |
if (d->nio) { |
if (d->nio) { |
1697 |
} |
} |
1698 |
|
|
1699 |
/* PA-A1 driver */ |
/* PA-A1 driver */ |
1700 |
struct c7200_pa_driver dev_c7200_pa_a1_driver = { |
struct cisco_card_driver dev_c7200_pa_a1_driver = { |
1701 |
"PA-A1", 1, |
"PA-A1", 1, 0, |
1702 |
dev_c7200_pa_a1_init, |
dev_c7200_pa_a1_init, |
1703 |
dev_c7200_pa_a1_shutdown, |
dev_c7200_pa_a1_shutdown, |
1704 |
|
NULL, |
1705 |
dev_c7200_pa_a1_set_nio, |
dev_c7200_pa_a1_set_nio, |
1706 |
dev_c7200_pa_a1_unset_nio, |
dev_c7200_pa_a1_unset_nio, |
1707 |
NULL, |
NULL, |