Source to ./dev_pa_mc8te1.c
/*
* Cisco router simulation platform.
* Copyright (C) 2005-2006 Christophe Fillot. All rights reserved.
*
* PA-MC-8TE1 card. Doesn't work at this time.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <assert.h>
#include "cpu.h"
#include "vm.h"
#include "dynamips.h"
#include "memory.h"
#include "device.h"
#include "net.h"
#include "net_io.h"
#include "ptask.h"
#include "dev_c7200.h"
#include "dev_plx.h"
/* Debugging flags */
#define DEBUG_ACCESS 1
#define DEBUG_UNKNOWN 1
#define DEBUG_TRANSMIT 1
#define DEBUG_RECEIVE 1
/* SSRAM */
#define SSRAM_START 0x10000
#define SSRAM_END 0x30000
/* PA-MC-8TE1 Data */
struct pa_mc_data {
char *name;
u_int irq;
/* Virtual machine */
vm_instance_t *vm;
/* PCI device information */
struct vdevice dev;
struct pci_device *pci_dev;
/* SSRAM device */
struct vdevice ssram_dev;
char *ssram_name;
m_uint8_t ssram_data[0x20000];
/* PLX9054 */
char *plx_name;
vm_obj_t *plx_obj;
/* NetIO descriptor */
netio_desc_t *nio;
/* TX ring scanner task id */
ptask_id_t tx_tid;
};
/* Log a PA-MC-8TE1 message */
#define PA_MC_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)
/*
* dev_ssram_access
*/
static void *dev_ssram_access(cpu_gen_t *cpu,struct vdevice *dev,
m_uint32_t offset,u_int op_size,u_int op_type,
m_uint64_t *data)
{
struct pa_mc_data *d = dev->priv_data;
if (op_type == MTS_READ)
*data = 0;
if ((offset >= SSRAM_START) && (offset < SSRAM_END))
return(&d->ssram_data[offset-SSRAM_START]);
#if DEBUG_ACCESS
if (op_type == MTS_READ) {
cpu_log(cpu,d->name,
"read access to offset = 0x%x, pc = 0x%llx (size=%u)\n",
offset,cpu_get_pc(cpu),op_size);
} else {
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, "
"val = 0x%llx (size=%u)\n",
offset,cpu_get_pc(cpu),*data,op_size);
}
#endif
switch(offset) {
case 0xfff0c:
if (op_type == MTS_READ)
*data = 0xdeadbeef;
break;
case 0xfff10:
if (op_type == MTS_READ)
*data = 0xbeeffeed;
break;
case 0x08: /* max_dsx1 */
case 0x10: /* no_buf */
case 0x18: /* ev */
if (op_type == MTS_READ)
*data = 0x0ULL;
break;
case 0x00: /* tx packets */
if (op_type == MTS_READ)
*data = 0x0;
break;
case 0x04: /* rx packets */
if (op_type == MTS_READ)
*data = 0x0;
break;
case 0x0c: /* rx drops */
if (op_type == MTS_READ)
*data = 0;
break;
}
return NULL;
}
/* Callback when PLX9054 PCI-to-Local register is written */
static void plx9054_doorbell_callback(struct plx_data *plx_data,
struct pa_mc_data *pa_data,
m_uint32_t val)
{
printf("DOORBELL: 0x%x\n",val);
/* Trigger interrupt */
//vm_set_irq(pa_data->vm,pa_data->irq);
vm_set_irq(pa_data->vm,3);
}
/*
* pa_mc8te1_access()
*/
static void *pa_mc8te1_access(cpu_gen_t *cpu,struct vdevice *dev,
m_uint32_t offset,u_int op_size,u_int op_type,
m_uint64_t *data)
{
struct pa_mc_data *d = dev->priv_data;
if (op_type == MTS_READ)
*data = 0;
#if DEBUG_ACCESS
if (op_type == MTS_READ) {
cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx\n",
offset,cpu_get_pc(cpu));
} else {
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, "
"val = 0x%llx\n",offset,cpu_get_pc(cpu),*data);
}
#endif
switch(offset) {
#if DEBUG_UNKNOWN
default:
if (op_type == MTS_READ) {
cpu_log(cpu,d->name,
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
offset,cpu_get_pc(cpu),op_size);
} else {
cpu_log(cpu,d->name,
"write to unknown addr 0x%x, value=0x%llx, "
"pc=0x%llx (size=%u)\n",
offset,*data,cpu_get_pc(cpu),op_size);
}
#endif
}
return NULL;
}
/*
* pci_pos_read()
*/
static m_uint32_t pci_pos_read(cpu_gen_t *cpu,struct pci_device *dev,int reg)
{
struct pa_mc_data *d = dev->priv_data;
#if DEBUG_ACCESS
PA_MC_LOG(d,"read PCI register 0x%x\n",reg);
#endif
switch(reg) {
case PCI_REG_BAR0:
return(d->dev.phys_addr);
default:
return(0);
}
}
/*
* pci_pos_write()
*/
static void pci_pos_write(cpu_gen_t *cpu,struct pci_device *dev,
int reg,m_uint32_t value)
{
struct pa_mc_data *d = dev->priv_data;
#if DEBUG_ACCESS
PA_MC_LOG(d,"write 0x%x to PCI register 0x%x\n",value,reg);
#endif
switch(reg) {
case PCI_REG_BAR0:
//vm_map_device(cpu->vm,&d->dev,(m_uint64_t)value);
PA_MC_LOG(d,"registers are mapped at 0x%x\n",value);
break;
}
}
/*
* dev_c7200_pa_mc8te1_init()
*
* Add a PA-MC-8TE1 port adapter into specified slot.
*/
int dev_c7200_pa_mc8te1_init(vm_instance_t *vm,struct cisco_card *card)
{
struct pa_mc_data *d;
u_int slot = card->slot_id;
/* Allocate the private data structure for PA-MC-8TE1 chip */
if (!(d = malloc(sizeof(*d)))) {
vm_error(vm,"%s: out of memory\n",card->dev_name);
return(-1);
}
memset(d,0,sizeof(*d));
d->name = card->dev_name;
d->vm = vm;
d->irq = c7200_net_irq_for_slot_port(slot,0);
/* Set the PCI bus */
card->pci_bus = vm->slots_pci_bus[slot];
/* Set the EEPROM */
cisco_card_set_eeprom(vm,card,cisco_eeprom_find_pa("PA-MC-8TE1"));
c7200_set_slot_eeprom(VM_C7200(vm),slot,&card->eeprom);
/* Create the PM7380 */
d->pci_dev = pci_dev_add(card->pci_bus,card->dev_name,
0x11f8, 0x7380,
0,0,d->irq,d,
NULL,pci_pos_read,pci_pos_write);
/* Initialize SSRAM device */
d->ssram_name = dyn_sprintf("%s_ssram",card->dev_name);
dev_init(&d->ssram_dev);
d->ssram_dev.name = d->ssram_name;
d->ssram_dev.priv_data = d;
d->ssram_dev.handler = dev_ssram_access;
/* Create the PLX9054 */
d->plx_name = dyn_sprintf("%s_plx",card->dev_name);
d->plx_obj = dev_plx9054_init(vm,d->plx_name,
card->pci_bus,1,
&d->ssram_dev,NULL);
/* Set callback function for PLX9054 PCI-To-Local doorbell */
dev_plx_set_pci2loc_doorbell_cbk(d->plx_obj->data,
(dev_plx_doorbell_cbk)
plx9054_doorbell_callback,
d);
/* Store device info into the router structure */
card->drv_info = d;
return(0);
}
/* Remove a PA-POS-OC3 from the specified slot */
int dev_c7200_pa_mc8te1_shutdown(vm_instance_t *vm,struct cisco_card *card)
{
struct pa_mc_data *d = card->drv_info;
/* Remove the PA EEPROM */
cisco_card_unset_eeprom(card);
c7200_set_slot_eeprom(VM_C7200(vm),card->slot_id,NULL);
/* Remove the PCI device */
pci_dev_remove(d->pci_dev);
/* Remove the PLX9054 chip */
vm_object_remove(vm,d->plx_obj);
/* Remove the device from the CPU address space */
//vm_unbind_device(vm,&d->dev);
vm_unbind_device(vm,&d->ssram_dev);
cpu_group_rebuild_mts(vm->cpu_group);
/* Free the device structure itself */
free(d);
return(0);
}
/* Bind a Network IO descriptor to a specific port */
int dev_c7200_pa_mc8te1_set_nio(vm_instance_t *vm,struct cisco_card *card,
u_int port_id,netio_desc_t *nio)
{
struct pa_mc_data *d = card->drv_info;
if (!d || (port_id > 0))
return(-1);
if (d->nio != NULL)
return(-1);
d->nio = nio;
//d->tx_tid = ptask_add((ptask_callback)dev_pos_oc3_handle_txring,d,NULL);
//netio_rxl_add(nio,(netio_rx_handler_t)dev_pos_oc3_handle_rxring,d,NULL);
return(0);
}
/* Bind a Network IO descriptor to a specific port */
int dev_c7200_pa_mc8te1_unset_nio(vm_instance_t *vm,struct cisco_card *card,
u_int port_id)
{
struct pa_mc_data *d = card->drv_info;
if (!d || (port_id > 0))
return(-1);
if (d->nio) {
ptask_remove(d->tx_tid);
netio_rxl_remove(d->nio);
d->nio = NULL;
}
return(0);
}
/* PA-MC-8TE1 driver */
struct cisco_card_driver dev_c7200_pa_mc8te1_driver = {
"PA-MC-8TE1", 0, 0,
dev_c7200_pa_mc8te1_init,
dev_c7200_pa_mc8te1_shutdown,
NULL,
dev_c7200_pa_mc8te1_set_nio,
dev_c7200_pa_mc8te1_unset_nio,
NULL,
};