--- upstream/dynamips-0.2.7-RC1/dev_mueslix.c 2007/10/06 16:23:47 7 +++ trunk/dev_mueslix.c 2007/10/06 16:45:40 12 @@ -96,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 @@ -109,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 */ @@ -121,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 { @@ -141,12 +141,15 @@ /* Channel ID */ u_int id; - /* RX/TX status */ - u_int rx_tx_status; - /* Channel status (0=disabled) */ u_int status; + /* CRC control register */ + u_int crc_ctrl_reg; + + /* CRC size */ + u_int crc_size; + /* NetIO descriptor */ netio_desc_t *nio; @@ -166,7 +169,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; @@ -204,6 +214,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) @@ -214,6 +228,19 @@ 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. */ @@ -222,6 +249,31 @@ m_uint64_t *data) { switch(offset) { + case 0x00: /* CRC control register ? */ + if (op_type == MTS_READ) { + *data = channel->crc_ctrl_reg; + } else { + channel->crc_ctrl_reg = *data; + + switch(channel->crc_ctrl_reg) { + case 0x08: + case 0x0a: + channel->crc_size = channel->crc_ctrl_reg - 0x06; + break; + + default: + MUESLIX_LOG(channel->parent,"channel %u: unknown value " + "for CRC ctrl reg 0x%4.4x\n", + channel->id,channel->crc_ctrl_reg); + + channel->crc_size = 2; + } + MUESLIX_LOG(channel->parent, + "channel %u: CRC size set to 0x%4.4x\n", + channel->id,channel->crc_size); + } + break; + case 0x60: /* signals ? */ if ((op_type == MTS_READ) && (channel->nio != NULL)) *data = 0xFFFFFFFF; @@ -323,8 +375,6 @@ 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 @@ -361,52 +411,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: @@ -486,6 +520,7 @@ #endif } + MUESLIX_UNLOCK(d); return NULL; } @@ -609,7 +644,7 @@ /* We have finished if the complete packet has been stored */ if (tot_len == 0) { rxdc->rdes[0] = MUESLIX_RXDESC_LS; - rxdc->rdes[0] |= cp_len; + rxdc->rdes[0] |= cp_len + channel->crc_size + 1; if (i != 0) physmem_copy_u32_to_vm(d->vm,channel->rx_current,rxdc->rdes[0]); @@ -654,24 +689,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); } @@ -768,7 +806,7 @@ /* Be sure that we have length not null */ if (clen != 0) { //printf("pkt_ptr = %p, ptxd->tdes[1] = 0x%x, clen = %d\n", - //pkt_ptr, ptxd->tdes[1], clen); + // pkt_ptr, ptxd->tdes[1], clen); physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->tdes[1],clen); } @@ -799,8 +837,8 @@ pad = ptxd->tdes[0] & MUESLIX_TXDESC_PAD; pad >>= MUESLIX_TXDESC_PAD_SHIFT; - tot_len += (pad - 1) & 0x03; - + tot_len -= (4 - pad) & 0x03; + /* send it on wire */ netio_send(channel->nio,pkt,tot_len); } @@ -809,19 +847,28 @@ 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;ilock,NULL); d->chip_mode = chip_mode; - for(i=0;ichannel[i].id = i; + d->channel[i].parent = d; + } /* Add as PCI device */ pci_dev = pci_dev_add(pci_bus,name, @@ -939,7 +989,6 @@ /* define the new NIO */ channel->nio = nio; - channel->parent = d; channel->tx_tid = ptask_add((ptask_callback)dev_mueslix_handle_txring, channel,NULL); netio_rxl_add(nio,(netio_rx_handler_t)dev_mueslix_handle_rxring,