1 |
/* |
/* |
2 |
* Cisco C7200 (Predator) Simulation Platform. |
* Cisco router simulation platform. |
3 |
* Copyright (C) 2005,2006 Christophe Fillot. All rights reserved. |
* Copyright (C) 2005,2006 Christophe Fillot. All rights reserved. |
4 |
* |
* |
5 |
* Serial Interfaces (Mueslix). |
* Serial Interfaces (Mueslix). |
36 |
#include <errno.h> |
#include <errno.h> |
37 |
#include <assert.h> |
#include <assert.h> |
38 |
|
|
39 |
#include "mips64.h" |
#include "cpu.h" |
40 |
|
#include "vm.h" |
41 |
#include "dynamips.h" |
#include "dynamips.h" |
42 |
#include "memory.h" |
#include "memory.h" |
43 |
#include "device.h" |
#include "device.h" |
96 |
#define MUESLIX_XYMEM_LEN 0x100 |
#define MUESLIX_XYMEM_LEN 0x100 |
97 |
|
|
98 |
/* Maximum packet size */ |
/* Maximum packet size */ |
99 |
#define MUESLIX_MAX_PKT_SIZE 2048 |
#define MUESLIX_MAX_PKT_SIZE 18000 |
100 |
|
|
101 |
/* Send up to 16 packets in a TX ring scan pass */ |
/* Send up to 16 packets in a TX ring scan pass */ |
102 |
#define MUESLIX_TXRING_PASS_COUNT 16 |
#define MUESLIX_TXRING_PASS_COUNT 16 |
109 |
#define MUESLIX_RXDESC_IGNORED 0x08000000 /* Ignored */ |
#define MUESLIX_RXDESC_IGNORED 0x08000000 /* Ignored */ |
110 |
#define MUESLIX_RXDESC_ABORT 0x04000000 /* Abort */ |
#define MUESLIX_RXDESC_ABORT 0x04000000 /* Abort */ |
111 |
#define MUESLIX_RXDESC_CRC 0x02000000 /* CRC error */ |
#define MUESLIX_RXDESC_CRC 0x02000000 /* CRC error */ |
112 |
#define MUESLIX_RXDESC_LEN_MASK 0xfff |
#define MUESLIX_RXDESC_LEN_MASK 0xffff |
113 |
|
|
114 |
/* TX descriptors */ |
/* TX descriptors */ |
115 |
#define MUESLIX_TXDESC_OWN 0x80000000 /* Ownership */ |
#define MUESLIX_TXDESC_OWN 0x80000000 /* Ownership */ |
121 |
#define MUESLIX_TXDESC_PAD 0x00c00000 /* Sort of padding info ? */ |
#define MUESLIX_TXDESC_PAD 0x00c00000 /* Sort of padding info ? */ |
122 |
#define MUESLIX_TXDESC_PAD_SHIFT 22 |
#define MUESLIX_TXDESC_PAD_SHIFT 22 |
123 |
|
|
124 |
#define MUESLIX_TXDESC_LEN_MASK 0xfff |
#define MUESLIX_TXDESC_LEN_MASK 0xffff |
125 |
|
|
126 |
/* RX Descriptor */ |
/* RX Descriptor */ |
127 |
struct rx_desc { |
struct rx_desc { |
141 |
/* Channel ID */ |
/* Channel ID */ |
142 |
u_int id; |
u_int id; |
143 |
|
|
|
/* RX/TX status */ |
|
|
u_int rx_tx_status; |
|
|
|
|
144 |
/* Channel status (0=disabled) */ |
/* Channel status (0=disabled) */ |
145 |
u_int status; |
u_int status; |
146 |
|
|
163 |
/* Mueslix Data */ |
/* Mueslix Data */ |
164 |
struct mueslix_data { |
struct mueslix_data { |
165 |
char *name; |
char *name; |
166 |
|
|
167 |
|
/* Lock */ |
168 |
|
pthread_mutex_t lock; |
169 |
|
|
170 |
|
/* IRQ status and mask */ |
171 |
|
m_uint32_t irq_status,irq_mask; |
172 |
|
u_int irq_clearing_count; |
173 |
|
|
174 |
/* TPU options */ |
/* TPU options */ |
175 |
m_uint32_t tpu_options; |
m_uint32_t tpu_options; |
176 |
|
|
208 |
MUESLIX_CHANNEL2_OFFSET, MUESLIX_CHANNEL3_OFFSET, |
MUESLIX_CHANNEL2_OFFSET, MUESLIX_CHANNEL3_OFFSET, |
209 |
}; |
}; |
210 |
|
|
211 |
|
/* Lock/Unlock primitives */ |
212 |
|
#define MUESLIX_LOCK(d) pthread_mutex_lock(&(d)->lock) |
213 |
|
#define MUESLIX_UNLOCK(d) pthread_mutex_unlock(&(d)->lock) |
214 |
|
|
215 |
/* Log a Mueslix message */ |
/* Log a Mueslix message */ |
216 |
#define MUESLIX_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) |
#define MUESLIX_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) |
217 |
|
|
222 |
return((d->channel_enable_mask >> (id << 1)) & 0x03); |
return((d->channel_enable_mask >> (id << 1)) & 0x03); |
223 |
} |
} |
224 |
|
|
225 |
|
/* Update IRQ status */ |
226 |
|
static inline void dev_mueslix_update_irq_status(struct mueslix_data *d) |
227 |
|
{ |
228 |
|
if (d->irq_status & d->irq_mask) |
229 |
|
pci_dev_trigger_irq(d->vm,d->pci_dev); |
230 |
|
else { |
231 |
|
if (++d->irq_clearing_count == 3) { |
232 |
|
pci_dev_clear_irq(d->vm,d->pci_dev); |
233 |
|
d->irq_clearing_count = 0; |
234 |
|
} |
235 |
|
} |
236 |
|
} |
237 |
|
|
238 |
/* |
/* |
239 |
* Access to channel registers. |
* Access to channel registers. |
240 |
*/ |
*/ |
241 |
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, |
242 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
243 |
m_uint64_t *data) |
m_uint64_t *data) |
244 |
{ |
{ |
340 |
/* |
/* |
341 |
* dev_mueslix_access() |
* dev_mueslix_access() |
342 |
*/ |
*/ |
343 |
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, |
344 |
u_int op_size,u_int op_type,m_uint64_t *data) |
u_int op_size,u_int op_type,m_uint64_t *data) |
345 |
{ |
{ |
346 |
struct mueslix_data *d = dev->priv_data; |
struct mueslix_data *d = dev->priv_data; |
|
struct mueslix_channel *channel; |
|
|
m_uint32_t irq_status; |
|
347 |
int i; |
int i; |
348 |
|
|
349 |
#if DEBUG_ACCESS >= 2 |
#if DEBUG_ACCESS >= 2 |
350 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
351 |
cpu_log(cpu,d->name,"read access to offset=0x%x, pc=0x%llx, size=%u\n", |
cpu_log(cpu,d->name,"read access to offset=0x%x, pc=0x%llx, size=%u\n", |
352 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
353 |
} else { |
} else { |
354 |
cpu_log(cpu,d->name,"write access to offset=0x%x, pc=0x%llx, " |
cpu_log(cpu,d->name,"write access to offset=0x%x, pc=0x%llx, " |
355 |
"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); |
356 |
} |
} |
357 |
#endif |
#endif |
358 |
|
|
380 |
if ((offset >= channel_offset[i]) && |
if ((offset >= channel_offset[i]) && |
381 |
(offset < (channel_offset[i] + MUESLIX_CHANNEL_LEN))) |
(offset < (channel_offset[i] + MUESLIX_CHANNEL_LEN))) |
382 |
{ |
{ |
383 |
|
MUESLIX_LOCK(d); |
384 |
dev_mueslix_chan_access(cpu,&d->channel[i], |
dev_mueslix_chan_access(cpu,&d->channel[i], |
385 |
offset - channel_offset[i], |
offset - channel_offset[i], |
386 |
op_size,op_type,data); |
op_size,op_type,data); |
387 |
|
MUESLIX_UNLOCK(d); |
388 |
return NULL; |
return NULL; |
389 |
} |
} |
390 |
|
|
391 |
|
MUESLIX_LOCK(d); |
392 |
|
|
393 |
/* Generic case */ |
/* Generic case */ |
394 |
switch(offset) { |
switch(offset) { |
395 |
/* this reg is accessed when an interrupt occurs */ |
/* this reg is accessed when an interrupt occurs */ |
396 |
case 0x0: |
case 0x0: |
397 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
398 |
irq_status = 0; |
*data = d->irq_status; |
|
|
|
|
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; |
|
399 |
} else { |
} else { |
400 |
for(i=0;i<MUESLIX_NR_CHANNELS;i++) { |
d->irq_status &= ~(*data); |
401 |
channel = &d->channel[i]; |
dev_mueslix_update_irq_status(d); |
|
channel->rx_tx_status = 0; |
|
|
} |
|
402 |
} |
} |
403 |
break; |
break; |
404 |
|
|
405 |
/* maybe interrupt mask */ |
/* Maybe interrupt mask */ |
406 |
case 0x10: |
case 0x10: |
407 |
if (op_type == MTS_READ) |
if (op_type == MTS_READ) { |
408 |
*data = 0x2FF; |
*data = d->irq_mask; |
409 |
|
} else { |
410 |
|
d->irq_mask = *data; |
411 |
|
dev_mueslix_update_irq_status(d); |
412 |
|
} |
413 |
break; |
break; |
414 |
|
|
415 |
case 0x14: |
case 0x14: |
419 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
420 |
cpu_log(cpu,d->name, |
cpu_log(cpu,d->name, |
421 |
"channel_enable_mask = 0x%5.5llx at pc=0x%llx\n", |
"channel_enable_mask = 0x%5.5llx at pc=0x%llx\n", |
422 |
*data,cpu->pc); |
*data,cpu_get_pc(cpu)); |
423 |
#endif |
#endif |
424 |
d->channel_enable_mask = *data; |
d->channel_enable_mask = *data; |
425 |
} |
} |
452 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
453 |
if (op_type == MTS_WRITE) { |
if (op_type == MTS_WRITE) { |
454 |
cpu_log(cpu,d->name,"cmd_reg = 0x%5.5llx at pc=0x%llx\n", |
cpu_log(cpu,d->name,"cmd_reg = 0x%5.5llx at pc=0x%llx\n", |
455 |
*data,cpu->pc); |
*data,cpu_get_pc(cpu)); |
456 |
} |
} |
457 |
#endif |
#endif |
458 |
switch(d->chip_mode) { |
switch(d->chip_mode) { |
479 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
480 |
cpu_log(cpu,d->name, |
cpu_log(cpu,d->name, |
481 |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
482 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
483 |
} else { |
} else { |
484 |
cpu_log(cpu,d->name, |
cpu_log(cpu,d->name, |
485 |
"write to unknown addr 0x%x, value=0x%llx, " |
"write to unknown addr 0x%x, value=0x%llx, " |
486 |
"pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); |
"pc=0x%llx (size=%u)\n", |
487 |
|
offset,*data,cpu_get_pc(cpu),op_size); |
488 |
} |
} |
489 |
#endif |
#endif |
490 |
} |
} |
491 |
|
|
492 |
|
MUESLIX_UNLOCK(d); |
493 |
return NULL; |
return NULL; |
494 |
} |
} |
495 |
|
|
658 |
/* Indicate that we have a frame ready (XXX something to do ?) */ |
/* Indicate that we have a frame ready (XXX something to do ?) */ |
659 |
|
|
660 |
/* Generate IRQ on CPU */ |
/* Generate IRQ on CPU */ |
661 |
channel->rx_tx_status |= MUESLIX_CHANNEL_STATUS_RX; |
d->irq_status |= MUESLIX_RX_IRQ << channel->id; |
662 |
pci_dev_trigger_irq(d->vm,d->pci_dev); |
dev_mueslix_update_irq_status(d); |
663 |
} |
} |
664 |
|
|
665 |
/* Handle the Mueslix RX ring of the specified channel */ |
/* Handle the Mueslix RX ring of the specified channel */ |
666 |
static int dev_mueslix_handle_rxring(netio_desc_t *nio, |
static int dev_mueslix_handle_rxring(netio_desc_t *nio, |
667 |
u_char *pkt,ssize_t pkt_len, |
u_char *pkt,ssize_t pkt_len, |
668 |
struct mueslix_channel *channel) |
struct mueslix_channel *channel) |
669 |
{ |
{ |
|
#if DEBUG_RECEIVE |
|
670 |
struct mueslix_data *d = channel->parent; |
struct mueslix_data *d = channel->parent; |
671 |
|
|
672 |
|
#if DEBUG_RECEIVE |
673 |
MUESLIX_LOG(d,"channel %u: receiving a packet of %d bytes\n", |
MUESLIX_LOG(d,"channel %u: receiving a packet of %d bytes\n", |
674 |
channel->id,pkt_len); |
channel->id,pkt_len); |
675 |
mem_dump(log_file,pkt,pkt_len); |
mem_dump(log_file,pkt,pkt_len); |
676 |
#endif |
#endif |
677 |
|
|
678 |
dev_mueslix_receive_pkt(channel,pkt,pkt_len); |
MUESLIX_LOCK(d); |
679 |
|
if (dev_mueslix_is_rx_tx_enabled(d,channel->id) & MUESLIX_RX_ENABLE) |
680 |
|
dev_mueslix_receive_pkt(channel,pkt,pkt_len); |
681 |
|
MUESLIX_UNLOCK(d); |
682 |
return(TRUE); |
return(TRUE); |
683 |
} |
} |
684 |
|
|
816 |
physmem_copy_u32_to_vm(d->vm,tx_start,0); |
physmem_copy_u32_to_vm(d->vm,tx_start,0); |
817 |
|
|
818 |
/* Interrupt on completion ? */ |
/* Interrupt on completion ? */ |
819 |
channel->rx_tx_status |= MUESLIX_CHANNEL_STATUS_TX; |
d->irq_status |= MUESLIX_TX_IRQ << channel->id; |
820 |
pci_dev_trigger_irq(d->vm,d->pci_dev); |
dev_mueslix_update_irq_status(d); |
821 |
return(TRUE); |
return(TRUE); |
822 |
} |
} |
823 |
|
|
824 |
/* Handle the TX ring of a specific channel */ |
/* Handle the TX ring of a specific channel */ |
825 |
static int dev_mueslix_handle_txring(struct mueslix_channel *channel) |
static int dev_mueslix_handle_txring(struct mueslix_channel *channel) |
826 |
{ |
{ |
827 |
int i; |
struct mueslix_data *d = channel->parent; |
828 |
|
int res,i; |
829 |
|
|
830 |
for(i=0;i<MUESLIX_TXRING_PASS_COUNT;i++) |
if (!dev_mueslix_is_rx_tx_enabled(d,channel->id) & MUESLIX_TX_ENABLE) |
831 |
if (!dev_mueslix_handle_txring_single(channel)) |
return(FALSE); |
832 |
|
|
833 |
|
for(i=0;i<MUESLIX_TXRING_PASS_COUNT;i++) { |
834 |
|
MUESLIX_LOCK(d); |
835 |
|
res = dev_mueslix_handle_txring_single(channel); |
836 |
|
MUESLIX_UNLOCK(d); |
837 |
|
|
838 |
|
if (!res) |
839 |
break; |
break; |
840 |
|
} |
841 |
|
|
842 |
return(TRUE); |
return(TRUE); |
843 |
} |
} |
844 |
|
|
845 |
/* pci_mueslix_read() */ |
/* pci_mueslix_read() */ |
846 |
static m_uint32_t pci_mueslix_read(cpu_mips_t *cpu,struct pci_device *dev, |
static m_uint32_t pci_mueslix_read(cpu_gen_t *cpu,struct pci_device *dev, |
847 |
int reg) |
int reg) |
848 |
{ |
{ |
849 |
struct mueslix_data *d = dev->priv_data; |
struct mueslix_data *d = dev->priv_data; |
859 |
} |
} |
860 |
|
|
861 |
/* pci_mueslix_write() */ |
/* pci_mueslix_write() */ |
862 |
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, |
863 |
int reg,m_uint32_t value) |
int reg,m_uint32_t value) |
864 |
{ |
{ |
865 |
struct mueslix_data *d = dev->priv_data; |
struct mueslix_data *d = dev->priv_data; |
889 |
} |
} |
890 |
|
|
891 |
memset(d,0,sizeof(*d)); |
memset(d,0,sizeof(*d)); |
892 |
|
pthread_mutex_init(&d->lock,NULL); |
893 |
d->chip_mode = chip_mode; |
d->chip_mode = chip_mode; |
894 |
|
|
895 |
for(i=0;i<MUESLIX_NR_CHANNELS;i++) |
for(i=0;i<MUESLIX_NR_CHANNELS;i++) |