📄 dev_mueslix.c
字号:
/* * Cisco C7200 (Predator) Simulation Platform. * Copyright (C) 2005,2006 Christophe Fillot. All rights reserved. * * Serial Interfaces (Mueslix). * * Note: "debug serial mueslix" gives more technical info. * * Chip mode: Cisco models 36xx and 72xx don't seem to use the same microcode, * so there are code variants to make things work properly. * * Chip mode 0 => 3600 * Chip mode 1 => 7200 * * 2 points noticed until now: * - RX/TX ring wrapping checks are done differently, * - TX packet sizes are not specified in the same way. * * Test methodology: * - Connect two virtual routers together ; * - Do pings by sending 10 packets by 10 packets. If this stops working, * count the number of transmitted packets and check with RX/TX rings * sizes. This is problably a ring wrapping problem. * - Do multiple pings with various sizes (padding checks); * - Check if CDP is working, with various hostname sizes. Since CDP * contains a checksum, it is a good way to determine if packets are * sent/received correctly. * - Do a Telnet from both virtual router to the other one, and do a * "sh run". */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <assert.h>#include "mips64.h"#include "dynamips.h"#include "memory.h"#include "device.h"#include "net.h"#include "net_io.h"#include "ptask.h"#include "dev_mueslix.h"/* Debugging flags */#define DEBUG_ACCESS 0#define DEBUG_UNKNOWN 0#define DEBUG_PCI_REGS 0#define DEBUG_TRANSMIT 0#define DEBUG_RECEIVE 0/* Mueslix PCI vendor/product codes */#define MUESLIX_PCI_VENDOR_ID 0x1137#define MUESLIX_PCI_PRODUCT_ID 0x0001/* Number of channels (4 interfaces) */#define MUESLIX_NR_CHANNELS 4#define MUESLIX_CHANNEL_LEN 0x100/* RX/TX status for a channel */#define MUESLIX_CHANNEL_STATUS_RX 0x01#define MUESLIX_CHANNEL_STATUS_TX 0x02/* RX/TX enable masks (XXX check if bit position is correct) */#define MUESLIX_TX_ENABLE 0x01#define MUESLIX_RX_ENABLE 0x02/* RX/TX IRQ masks */#define MUESLIX_TX_IRQ 0x01#define MUESLIX_RX_IRQ 0x10/* Addresses of ports */#define MUESLIX_CHANNEL0_OFFSET 0x100#define MUESLIX_CHANNEL1_OFFSET 0x200#define MUESLIX_CHANNEL2_OFFSET 0x300#define MUESLIX_CHANNEL3_OFFSET 0x400/* TPU Registers */#define MUESLIX_TPU_CMD_OFFSET 0x2c24#define MUESLIX_TPU_CMD_RSP_OFFSET 0x2c2c/* General and channels registers */#define MUESLIX_GEN_CHAN_LEN 0x500/* TPU microcode */#define MUESLIX_UCODE_OFFSET 0x2000#define MUESLIX_UCODE_LEN 0x800/* TPU Xmem and YMem */#define MUESLIX_XMEM_OFFSET 0x2a00#define MUESLIX_YMEM_OFFSET 0x2b00#define MUESLIX_XYMEM_LEN 0x100/* Maximum packet size */#define MUESLIX_MAX_PKT_SIZE 2048/* Send up to 16 packets in a TX ring scan pass */#define MUESLIX_TXRING_PASS_COUNT 16/* RX descriptors */#define MUESLIX_RXDESC_OWN 0x80000000 /* Ownership */#define MUESLIX_RXDESC_FS 0x40000000 /* First Segment */#define MUESLIX_RXDESC_LS 0x20000000 /* Last Segment */#define MUESLIX_RXDESC_OVERRUN 0x10000000 /* Overrun */#define MUESLIX_RXDESC_IGNORED 0x08000000 /* Ignored */#define MUESLIX_RXDESC_ABORT 0x04000000 /* Abort */#define MUESLIX_RXDESC_CRC 0x02000000 /* CRC error */#define MUESLIX_RXDESC_LEN_MASK 0xfff/* TX descriptors */#define MUESLIX_TXDESC_OWN 0x80000000 /* Ownership */#define MUESLIX_TXDESC_FS 0x40000000 /* First Segment */#define MUESLIX_TXDESC_LS 0x20000000 /* Last Segment */#define MUESLIX_TXDESC_SUB 0x00100000 /* Length substractor ? */#define MUESLIX_TXDESC_SUB_LEN 0x03000000 /* Length substrator ? */#define MUESLIX_TXDESC_SUB_SHIFT 24#define MUESLIX_TXDESC_PAD 0x00c00000 /* Sort of padding info ? */#define MUESLIX_TXDESC_PAD_SHIFT 22#define MUESLIX_TXDESC_LEN_MASK 0xfff/* RX Descriptor */struct rx_desc { m_uint32_t rdes[2];};/* TX Descriptor */struct tx_desc { m_uint32_t tdes[2];};/* Forward declaration of Mueslix data */typedef struct mueslix_data mueslix_data_t;/* Mueslix channel */struct mueslix_channel { /* Channel ID */ u_int id; /* RX/TX status */ u_int rx_tx_status; /* Channel status (0=disabled) */ u_int status; /* NetIO descriptor */ netio_desc_t *nio; /* TX ring scanners task id */ ptask_id_t tx_tid; /* 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; /* Parent mueslix structure */ mueslix_data_t *parent;};/* Mueslix Data */struct mueslix_data { char *name; /* TPU options */ m_uint32_t tpu_options; /* Virtual machine */ vm_instance_t *vm; /* Virtual device */ struct vdevice *dev; /* PCI device information */ struct pci_device *pci_dev; /* Chip mode: * * 0=increment ring pointers before check + direct TX size, * 1=increment ring pointers after check + "complex" TX size. */ int chip_mode; /* Channels */ struct mueslix_channel channel[MUESLIX_NR_CHANNELS]; m_uint32_t channel_enable_mask; /* TPU microcode */ u_char ucode[MUESLIX_UCODE_LEN]; /* TPU Xmem and Ymem */ u_char xmem[MUESLIX_XYMEM_LEN]; u_char ymem[MUESLIX_XYMEM_LEN];};/* Offsets of the 4 channels */static m_uint32_t channel_offset[MUESLIX_NR_CHANNELS] = { MUESLIX_CHANNEL0_OFFSET, MUESLIX_CHANNEL1_OFFSET, MUESLIX_CHANNEL2_OFFSET, MUESLIX_CHANNEL3_OFFSET,};/* Log a Mueslix message */#define MUESLIX_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)/* Returns TRUE if RX/TX is enabled for a channel */static inline int dev_mueslix_is_rx_tx_enabled(struct mueslix_data *d,u_int id){ /* 2 bits for RX/TX, 4 channels max */ return((d->channel_enable_mask >> (id << 1)) & 0x03);}/* * Access to channel registers. */void dev_mueslix_chan_access(cpu_mips_t *cpu,struct mueslix_channel *channel, m_uint32_t offset,u_int op_size,u_int op_type, m_uint64_t *data){ switch(offset) { case 0x60: /* signals ? */ if ((op_type == MTS_READ) && (channel->nio != NULL)) *data = 0xFFFFFFFF; break; case 0x64: /* port status - cable type and probably other things */ if (op_type == MTS_READ) *data = 0x7B; break; case 0x90: /* has influence on clock rate */ if (op_type == MTS_READ) *data = 0x11111111; break; case 0x80: /* TX start */ if (op_type == MTS_WRITE) channel->tx_start = channel->tx_current = *data; else *data = channel->tx_start; break; case 0x84: /* TX end */ if (op_type == MTS_WRITE) channel->tx_end = *data; else *data = channel->tx_end; break; case 0x88: /* RX start */ if (op_type == MTS_WRITE) channel->rx_start = channel->rx_current = *data; else *data = channel->rx_start; break; case 0x8c: /* RX end */ if (op_type == MTS_WRITE) channel->rx_end = *data; else *data = channel->rx_end; break; }}/* Handle TPU commands for chip mode 0 (3600) */static void tpu_cm0_handle_cmd(struct mueslix_data *d,u_int cmd){ struct mueslix_channel *channel; u_int opcode,channel_id; opcode = (cmd >> 12) & 0xFF; channel_id = cmd & 0x03; channel = &d->channel[channel_id]; switch(opcode) { case 0x10: MUESLIX_LOG(d,"channel %u disabled\n",channel_id); channel->status = 0; break; case 0x00: MUESLIX_LOG(d,"channel %u enabled\n",channel_id); channel->status = 1; break; default: MUESLIX_LOG(d,"unknown command 0x%5x\n",cmd); }}/* Handle TPU commands for chip mode 1 (7200) */static void tpu_cm1_handle_cmd(struct mueslix_data *d,u_int cmd){ struct mueslix_channel *channel; u_int opcode,channel_id; opcode = (cmd >> 12) & 0xFF; channel_id = cmd & 0x03; channel = &d->channel[channel_id]; switch(opcode) { case 0x50: case 0x30: MUESLIX_LOG(d,"channel %u disabled\n",channel_id); channel->status = 0; break; case 0x00: MUESLIX_LOG(d,"channel %u enabled\n",channel_id); channel->status = 1; break; default: MUESLIX_LOG(d,"unknown command 0x%5x\n",cmd); }}/* * dev_mueslix_access() */void *dev_mueslix_access(cpu_mips_t *cpu,struct vdevice *dev,m_uint32_t offset, u_int op_size,u_int op_type,m_uint64_t *data){ struct mueslix_data *d = dev->priv_data; struct mueslix_channel *channel; m_uint32_t irq_status; int i;#if DEBUG_ACCESS >= 2 if (op_type == MTS_READ) { cpu_log(cpu,d->name,"read access to offset=0x%x, pc=0x%llx, size=%u\n", offset,cpu->pc,op_size); } else { cpu_log(cpu,d->name,"write access to offset=0x%x, pc=0x%llx, " "val=0x%llx, size=%u\n",offset,cpu->pc,*data,op_size); }#endif /* Returns 0 if we don't know the offset */ if (op_type == MTS_READ) *data = 0x00000000; /* Handle microcode access */ if ((offset >= MUESLIX_UCODE_OFFSET) && (offset < (MUESLIX_UCODE_OFFSET + MUESLIX_UCODE_LEN))) return(d->ucode + offset - MUESLIX_UCODE_OFFSET); /* Handle TPU XMem access */ if ((offset >= MUESLIX_XMEM_OFFSET) && (offset < (MUESLIX_XMEM_OFFSET + MUESLIX_XYMEM_LEN))) return(d->xmem + offset - MUESLIX_XMEM_OFFSET); /* Handle TPU YMem access */ if ((offset >= MUESLIX_YMEM_OFFSET) && (offset < (MUESLIX_YMEM_OFFSET + MUESLIX_XYMEM_LEN))) return(d->ymem + offset - MUESLIX_YMEM_OFFSET); /* Handle channel access */ for(i=0;i<MUESLIX_NR_CHANNELS;i++) if ((offset >= channel_offset[i]) && (offset < (channel_offset[i] + MUESLIX_CHANNEL_LEN))) { dev_mueslix_chan_access(cpu,&d->channel[i], offset - channel_offset[i], op_size,op_type,data); return NULL; } /* Generic case */ switch(offset) { /* this reg is accessed when an interrupt occurs */ case 0x0: if (op_type == MTS_READ) { irq_status = 0; for(i=0;i<MUESLIX_NR_CHANNELS;i++) { channel = &d->channel[i]; if ((dev_mueslix_is_rx_tx_enabled(d,i) & MUESLIX_TX_ENABLE) && (channel->rx_tx_status & MUESLIX_CHANNEL_STATUS_RX)) irq_status |= MUESLIX_RX_IRQ << i; if ((dev_mueslix_is_rx_tx_enabled(d,i) & MUESLIX_TX_ENABLE) && (channel->rx_tx_status & MUESLIX_CHANNEL_STATUS_TX)) irq_status |= MUESLIX_TX_IRQ << i; } /* * Hack: we re-trigger an interrupt here. This was necessary * because the Mueslix driver was not working properly with * a C3620 platform. */ if (irq_status) pci_dev_trigger_irq(d->vm,d->pci_dev); *data = irq_status; } else { for(i=0;i<MUESLIX_NR_CHANNELS;i++) { channel = &d->channel[i]; channel->rx_tx_status = 0; } } break; /* maybe interrupt mask */ case 0x10: if (op_type == MTS_READ) *data = 0x2FF; break; case 0x14: if (op_type == MTS_READ) *data = d->channel_enable_mask; else {#if DEBUG_ACCESS cpu_log(cpu,d->name, "channel_enable_mask = 0x%5.5llx at pc=0x%llx\n", *data,cpu->pc);#endif d->channel_enable_mask = *data; } break; case 0x18: if (op_type == MTS_READ) *data = 0x7F7F7F7F; break; case 0x48: if (op_type == MTS_READ) *data = 0x00000000; break; case 0x7c: if (op_type == MTS_READ) *data = 0x492; break; case 0x2c00: if (op_type == MTS_READ) *data = d->tpu_options; else d->tpu_options = *data; break; /* cmd reg */ case MUESLIX_TPU_CMD_OFFSET:#if DEBUG_ACCESS if (op_type == MTS_WRITE) { cpu_log(cpu,d->name,"cmd_reg = 0x%5.5llx at pc=0x%llx\n", *data,cpu->pc); }#endif switch(d->chip_mode) { case 0: /* 3600 */ tpu_cm0_handle_cmd(d,*data); break; case 1: /* 7200 */ tpu_cm1_handle_cmd(d,*data); break; } break; /* * cmd_rsp reg, it seems that 0xFFFF means OK * (seen on a "sh contr se1/0" with "debug serial mueslix" enabled). */ case MUESLIX_TPU_CMD_RSP_OFFSET: if (op_type == MTS_READ) *data = 0xFFFF; 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->pc,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->pc,op_size); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -