📄 dev_c7200_pos.c
字号:
/* * Cisco router Simulation Platform. * Copyright (c) 2005-2007 Christophe Fillot. All rights reserved. * * EEPROM types: * - 0x95: PA-POS-OC3SMI * - 0x96: PA-POS-OC3MM * * Just an experimentation (I don't have any PA-POS-OC3). */#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 0#define DEBUG_UNKNOWN 0#define DEBUG_TRANSMIT 0#define DEBUG_RECEIVE 0/* PCI vendor/product codes */#define POS_OC3_PCI_VENDOR_ID 0x10b5#define POS_OC3_PCI_PRODUCT_ID 0x9060/* Maximum packet size */#define POS_OC3_MAX_PKT_SIZE 8192/* RX descriptors */#define POS_OC3_RXDESC_OWN 0x80000000 /* Ownership */#define POS_OC3_RXDESC_WRAP 0x40000000 /* Wrap ring */#define POS_OC3_RXDESC_CONT 0x08000000 /* Packet continues */#define POS_OC3_RXDESC_LEN_MASK 0x1fff/* TX descriptors */#define POS_OC3_TXDESC_OWN 0x80000000 /* Ownership */#define POS_OC3_TXDESC_WRAP 0x40000000 /* Wrap ring */#define POS_OC3_TXDESC_CONT 0x08000000 /* Packet continues */#define POS_OC3_TXDESC_LEN_MASK 0x1fff/* RX Descriptor */struct rx_desc { m_uint32_t rdes[2];};/* TX Descriptor */struct tx_desc { m_uint32_t tdes[2];};/* PA-POS-OC3 Data */struct pos_oc3_data { char *name; /* IRQ clearing count */ u_int irq_clearing_count; /* Control register #1 */ m_uint16_t ctrl_reg1; /* CRC size */ u_int crc_size; /* physical addresses for start and end of RX/TX rings */ m_uint32_t rx_start,rx_end,tx_start,tx_end; /* physical addresses of current RX and TX descriptors */ m_uint32_t rx_current,tx_current; /* Virtual machine */ vm_instance_t *vm; /* Virtual devices */ char *rx_name,*tx_name,*cs_name; vm_obj_t *rx_obj,*tx_obj,*cs_obj; struct vdevice rx_dev,tx_dev,cs_dev; /* PCI device information */ struct vdevice dev; struct pci_device *pci_dev; /* NetIO descriptor */ netio_desc_t *nio; /* TX ring scanner task id */ ptask_id_t tx_tid;};/* Log a PA-POS-OC3 message */#define POS_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)/* * pos_access() */static void *dev_pos_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 pos_oc3_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 { if (offset != 0x404) 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) { case 0x404: if (op_type == MTS_READ) *data = 0xFFFFFFFF; break; case 0x406: if (op_type == MTS_READ) *data = 0xFFFFFFFF; break; case 0x407: if (op_type == MTS_READ) *data = 0xFFFFFFFF; break;#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;}/* * pos_rx_access() */static void *dev_pos_rx_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 pos_oc3_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) { case 0x04: if (op_type == MTS_READ) *data = d->rx_start; else d->rx_start = *data; break; case 0x08: if (op_type == MTS_READ) *data = d->rx_current; else d->rx_current = *data; break;#if DEBUG_UNKNOWN default: if (op_type == MTS_READ) { cpu_log(cpu,d->rx_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->rx_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;}/* * pos_tx_access() */static void *dev_pos_tx_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 pos_oc3_data *d = dev->priv_data; if (op_type == MTS_READ) *data = 0;#if DEBUG_ACCESS if (op_type == MTS_READ) { cpu_log(cpu,d->tx_name,"read access to offset = 0x%x, pc = 0x%llx\n", offset,cpu_get_pc(cpu)); } else { cpu_log(cpu,d->tx_name,"write access to vaddr = 0x%x, pc = 0x%llx, " "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); }#endif switch(offset) { case 0x04: if (op_type == MTS_READ) *data = d->tx_start; else d->tx_start = *data; break; case 0x08: if (op_type == MTS_READ) *data = d->tx_current; else d->tx_current = *data; break;#if DEBUG_UNKNOWN default: if (op_type == MTS_READ) { cpu_log(cpu,d->tx_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->tx_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;}/* * pos_cs_access() */static void *dev_pos_cs_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 pos_oc3_data *d = dev->priv_data; if (op_type == MTS_READ) *data = 0;#if DEBUG_ACCESS if (op_type == MTS_READ) { cpu_log(cpu,d->cs_name,"read access to offset = 0x%x, pc = 0x%llx\n", offset,cpu_get_pc(cpu)); } else { cpu_log(cpu,d->cs_name,"write access to vaddr = 0x%x, pc = 0x%llx, " "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data); }#endif switch(offset) { case 0x300000: case 0x300004: case 0x30001c: if (op_type == MTS_READ) { *data = 0x00000FFF; /* Add a delay before clearing the IRQ */ if (++d->irq_clearing_count == 20) { pci_dev_clear_irq(d->vm,d->pci_dev); d->irq_clearing_count = 0; } } break; case 0x300008: if (op_type == MTS_READ) *data = 0x000007F; break; case 0x300028: if (op_type == MTS_READ) { *data = d->ctrl_reg1; } else { d->ctrl_reg1 = *data; switch(*data) { case 0x06: d->crc_size = 2; break; case 0x07: d->crc_size = 4; break; default: d->crc_size = 2; cpu_log(cpu,d->cs_name, "unknown value 0x%4.4llx written in ctrl_reg1\n", *data); } cpu_log(cpu,d->cs_name,"CRC size set to 0x%4.4x\n",d->crc_size); } break;#if DEBUG_UNKNOWN default: if (op_type == MTS_READ) { cpu_log(cpu,d->cs_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->cs_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;}/* * Get the address of the next RX descriptor. */static m_uint32_t rxdesc_get_next(struct pos_oc3_data *d,m_uint32_t rxd_addr, struct rx_desc *rxd){ m_uint32_t nrxd_addr; if (rxd->rdes[0] & POS_OC3_RXDESC_WRAP) nrxd_addr = d->rx_start; else nrxd_addr = rxd_addr + sizeof(struct rx_desc); return(nrxd_addr);}/* Read an RX descriptor */static void rxdesc_read(struct pos_oc3_data *d,m_uint32_t rxd_addr, struct rx_desc *rxd){#if DEBUG_RECEIVE POS_LOG(d,"reading RX descriptor at address 0x%x\n",rxd_addr);#endif /* get the next descriptor from VM physical RAM */ physmem_copy_from_vm(d->vm,rxd,rxd_addr,sizeof(struct rx_desc)); /* byte-swapping */ rxd->rdes[0] = vmtoh32(rxd->rdes[0]); rxd->rdes[1] = vmtoh32(rxd->rdes[1]);}/* * Try to acquire the specified RX descriptor. Returns TRUE if we have it. * It assumes that the byte-swapping is done. */static inline int rxdesc_acquire(m_uint32_t rdes0){ return(rdes0 & POS_OC3_RXDESC_OWN);}/* Put a packet in buffer of a descriptor */static ssize_t rxdesc_put_pkt(struct pos_oc3_data *d,struct rx_desc *rxd, u_char **pkt,ssize_t *pkt_len){ ssize_t len,cp_len; len = rxd->rdes[0] & POS_OC3_RXDESC_LEN_MASK; /* compute the data length to copy */ cp_len = m_min(len,*pkt_len);#if DEBUG_RECEIVE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -