--- upstream/dynamips-0.2.6-RC2/dev_mueslix.c 2007/10/06 16:05:34 3 +++ upstream/dynamips-0.2.7/dev_mueslix.c 2007/10/06 16:29:14 10 @@ -1,5 +1,5 @@ /* - * Cisco C7200 (Predator) Simulation Platform. + * Cisco router simulation platform. * Copyright (C) 2005,2006 Christophe Fillot. All rights reserved. * * Serial Interfaces (Mueslix). @@ -36,7 +36,8 @@ #include #include -#include "mips64.h" +#include "cpu.h" +#include "vm.h" #include "dynamips.h" #include "memory.h" #include "device.h" @@ -95,7 +96,7 @@ #define MUESLIX_XYMEM_LEN 0x100 /* Maximum packet size */ -#define MUESLIX_MAX_PKT_SIZE 2048 +#define MUESLIX_MAX_PKT_SIZE 18000 /* Send up to 16 packets in a TX ring scan pass */ #define MUESLIX_TXRING_PASS_COUNT 16 @@ -108,7 +109,7 @@ #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 +#define MUESLIX_RXDESC_LEN_MASK 0xffff /* TX descriptors */ #define MUESLIX_TXDESC_OWN 0x80000000 /* Ownership */ @@ -120,7 +121,7 @@ #define MUESLIX_TXDESC_PAD 0x00c00000 /* Sort of padding info ? */ #define MUESLIX_TXDESC_PAD_SHIFT 22 -#define MUESLIX_TXDESC_LEN_MASK 0xfff +#define MUESLIX_TXDESC_LEN_MASK 0xffff /* RX Descriptor */ struct rx_desc { @@ -140,9 +141,6 @@ /* Channel ID */ u_int id; - /* RX/TX status */ - u_int rx_tx_status; - /* Channel status (0=disabled) */ u_int status; @@ -165,7 +163,14 @@ /* Mueslix Data */ struct mueslix_data { char *name; - + + /* Lock */ + pthread_mutex_t lock; + + /* IRQ status and mask */ + m_uint32_t irq_status,irq_mask; + u_int irq_clearing_count; + /* TPU options */ m_uint32_t tpu_options; @@ -203,6 +208,10 @@ MUESLIX_CHANNEL2_OFFSET, MUESLIX_CHANNEL3_OFFSET, }; +/* Lock/Unlock primitives */ +#define MUESLIX_LOCK(d) pthread_mutex_lock(&(d)->lock) +#define MUESLIX_UNLOCK(d) pthread_mutex_unlock(&(d)->lock) + /* Log a Mueslix message */ #define MUESLIX_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) @@ -213,10 +222,23 @@ return((d->channel_enable_mask >> (id << 1)) & 0x03); } +/* Update IRQ status */ +static inline void dev_mueslix_update_irq_status(struct mueslix_data *d) +{ + if (d->irq_status & d->irq_mask) + pci_dev_trigger_irq(d->vm,d->pci_dev); + else { + if (++d->irq_clearing_count == 3) { + pci_dev_clear_irq(d->vm,d->pci_dev); + d->irq_clearing_count = 0; + } + } +} + /* * Access to channel registers. */ -void dev_mueslix_chan_access(cpu_mips_t *cpu,struct mueslix_channel *channel, +void dev_mueslix_chan_access(cpu_gen_t *cpu,struct mueslix_channel *channel, m_uint32_t offset,u_int op_size,u_int op_type, m_uint64_t *data) { @@ -318,21 +340,19 @@ /* * dev_mueslix_access() */ -void *dev_mueslix_access(cpu_mips_t *cpu,struct vdevice *dev,m_uint32_t offset, +void *dev_mueslix_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 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); + offset,cpu_get_pc(cpu),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); + "val=0x%llx, size=%u\n",offset,cpu_get_pc(cpu),*data,op_size); } #endif @@ -360,52 +380,36 @@ if ((offset >= channel_offset[i]) && (offset < (channel_offset[i] + MUESLIX_CHANNEL_LEN))) { + MUESLIX_LOCK(d); dev_mueslix_chan_access(cpu,&d->channel[i], offset - channel_offset[i], op_size,op_type,data); + MUESLIX_UNLOCK(d); return NULL; } + MUESLIX_LOCK(d); + /* 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;ichannel[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; + *data = d->irq_status; } else { - for(i=0;ichannel[i]; - channel->rx_tx_status = 0; - } + d->irq_status &= ~(*data); + dev_mueslix_update_irq_status(d); } break; - /* maybe interrupt mask */ + /* Maybe interrupt mask */ case 0x10: - if (op_type == MTS_READ) - *data = 0x2FF; + if (op_type == MTS_READ) { + *data = d->irq_mask; + } else { + d->irq_mask = *data; + dev_mueslix_update_irq_status(d); + } break; case 0x14: @@ -415,7 +419,7 @@ #if DEBUG_ACCESS cpu_log(cpu,d->name, "channel_enable_mask = 0x%5.5llx at pc=0x%llx\n", - *data,cpu->pc); + *data,cpu_get_pc(cpu)); #endif d->channel_enable_mask = *data; } @@ -448,7 +452,7 @@ #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); + *data,cpu_get_pc(cpu)); } #endif switch(d->chip_mode) { @@ -475,15 +479,17 @@ 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); + 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->pc,op_size); + "pc=0x%llx (size=%u)\n", + offset,*data,cpu_get_pc(cpu),op_size); } #endif } + MUESLIX_UNLOCK(d); return NULL; } @@ -652,24 +658,27 @@ /* Indicate that we have a frame ready (XXX something to do ?) */ /* Generate IRQ on CPU */ - channel->rx_tx_status |= MUESLIX_CHANNEL_STATUS_RX; - pci_dev_trigger_irq(d->vm,d->pci_dev); + d->irq_status |= MUESLIX_RX_IRQ << channel->id; + dev_mueslix_update_irq_status(d); } /* Handle the Mueslix RX ring of the specified channel */ static int dev_mueslix_handle_rxring(netio_desc_t *nio, u_char *pkt,ssize_t pkt_len, struct mueslix_channel *channel) -{ -#if DEBUG_RECEIVE +{ struct mueslix_data *d = channel->parent; +#if DEBUG_RECEIVE MUESLIX_LOG(d,"channel %u: receiving a packet of %d bytes\n", channel->id,pkt_len); mem_dump(log_file,pkt,pkt_len); #endif - dev_mueslix_receive_pkt(channel,pkt,pkt_len); + MUESLIX_LOCK(d); + if (dev_mueslix_is_rx_tx_enabled(d,channel->id) & MUESLIX_RX_ENABLE) + dev_mueslix_receive_pkt(channel,pkt,pkt_len); + MUESLIX_UNLOCK(d); return(TRUE); } @@ -807,25 +816,34 @@ physmem_copy_u32_to_vm(d->vm,tx_start,0); /* Interrupt on completion ? */ - channel->rx_tx_status |= MUESLIX_CHANNEL_STATUS_TX; - pci_dev_trigger_irq(d->vm,d->pci_dev); + d->irq_status |= MUESLIX_TX_IRQ << channel->id; + dev_mueslix_update_irq_status(d); return(TRUE); } /* Handle the TX ring of a specific channel */ static int dev_mueslix_handle_txring(struct mueslix_channel *channel) { - int i; + struct mueslix_data *d = channel->parent; + int res,i; - for(i=0;iid) & MUESLIX_TX_ENABLE) + return(FALSE); + + for(i=0;ipriv_data; @@ -841,7 +859,7 @@ } /* pci_mueslix_write() */ -static void pci_mueslix_write(cpu_mips_t *cpu,struct pci_device *dev, +static void pci_mueslix_write(cpu_gen_t *cpu,struct pci_device *dev, int reg,m_uint32_t value) { struct mueslix_data *d = dev->priv_data; @@ -871,6 +889,7 @@ } memset(d,0,sizeof(*d)); + pthread_mutex_init(&d->lock,NULL); d->chip_mode = chip_mode; for(i=0;i