1 |
/* |
/* |
2 |
* Cisco C7200 (Predator) DEC21140 Module. |
* Cisco router simlation platform. |
3 |
* Copyright (C) 2005,2006 Christophe Fillot. All rights reserved. |
* Copyright (C) 2005,2006 Christophe Fillot. All rights reserved. |
4 |
* |
* |
5 |
* DEC21140 FastEthernet chip emulation. |
* DEC21140 FastEthernet chip emulation. |
31 |
|
|
32 |
#include "crc.h" |
#include "crc.h" |
33 |
#include "utils.h" |
#include "utils.h" |
34 |
#include "mips64.h" |
#include "cpu.h" |
35 |
|
#include "vm.h" |
36 |
#include "dynamips.h" |
#include "dynamips.h" |
37 |
#include "memory.h" |
#include "memory.h" |
38 |
#include "device.h" |
#include "device.h" |
66 |
#define DEC21140_CSR_NR 16 |
#define DEC21140_CSR_NR 16 |
67 |
|
|
68 |
/* CSR5: Status Register */ |
/* CSR5: Status Register */ |
69 |
#define DEC21140_CSR5_TI 0x00000001 |
#define DEC21140_CSR5_TI 0x00000001 /* TX Interrupt */ |
70 |
#define DEC21140_CSR5_RI 0x00000040 |
#define DEC21140_CSR5_TPS 0x00000002 /* TX Process Stopped */ |
71 |
|
#define DEC21140_CSR5_TU 0x00000004 /* TX Buffer Unavailable */ |
72 |
|
#define DEC21140_CSR5_TJT 0x00000008 /* TX Jabber Timeout */ |
73 |
|
#define DEC21140_CSR5_UNF 0x00000020 /* TX Underflow */ |
74 |
|
#define DEC21140_CSR5_RI 0x00000040 /* RX Interrupt */ |
75 |
|
#define DEC21140_CSR5_RU 0x00000080 /* RX Buffer Unavailable */ |
76 |
|
#define DEC21140_CSR5_RPS 0x00000100 /* RX Process Stopped */ |
77 |
|
#define DEC21140_CSR5_RWT 0x00000200 /* RX Watchdog Timeout */ |
78 |
|
#define DEC21140_CSR5_GTE 0x00000800 /* Gen Purpose Timer Expired */ |
79 |
|
#define DEC21140_CSR5_FBE 0x00002000 /* Fatal Bus Error */ |
80 |
|
#define DEC21140_CSR5_AIS 0x00008000 /* Abnormal Interrupt Summary */ |
81 |
|
#define DEC21140_CSR5_NIS 0x00010000 /* Normal Interrupt Summary */ |
82 |
|
|
83 |
|
#define DEC21140_NIS_BITS \ |
84 |
|
(DEC21140_CSR5_TI|DEC21140_CSR5_RI|DEC21140_CSR5_TU) |
85 |
|
|
86 |
|
#define DEC21140_AIS_BITS \ |
87 |
|
(DEC21140_CSR5_TPS|DEC21140_CSR5_TJT|DEC21140_CSR5_UNF| \ |
88 |
|
DEC21140_CSR5_RU|DEC21140_CSR5_RPS|DEC21140_CSR5_RWT| \ |
89 |
|
DEC21140_CSR5_GTE|DEC21140_CSR5_FBE) |
90 |
|
|
91 |
#define DEC21140_CSR5_RS_SHIFT 17 |
#define DEC21140_CSR5_RS_SHIFT 17 |
92 |
#define DEC21140_CSR5_TS_SHIFT 20 |
#define DEC21140_CSR5_TS_SHIFT 20 |
93 |
|
|
187 |
/* Log a dec21140 message */ |
/* Log a dec21140 message */ |
188 |
#define DEC21140_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) |
#define DEC21140_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) |
189 |
|
|
|
/* |
|
|
* ISL rewrite. |
|
|
* |
|
|
* See: http://www.cisco.com/en/US/tech/tk389/tk390/technologies_tech_note09186a0080094665.shtml |
|
|
*/ |
|
|
static void dec21140_isl_rewrite(m_uint8_t *pkt,m_uint32_t tot_len) |
|
|
{ |
|
|
static m_uint8_t isl_xaddr[N_ETH_ALEN] = { 0x01,0x00,0x0c,0x00,0x10,0x00 }; |
|
|
u_int real_offset,real_len; |
|
|
n_eth_hdr_t *hdr; |
|
|
m_uint32_t ifcs; |
|
|
|
|
|
hdr = (n_eth_hdr_t *)pkt; |
|
|
if (!memcmp(&hdr->daddr,isl_xaddr,N_ETH_ALEN)) { |
|
|
real_offset = N_ETH_HLEN + N_ISL_HDR_SIZE; |
|
|
real_len = ntohs(hdr->type); |
|
|
real_len -= (N_ISL_HDR_SIZE + 4); |
|
|
|
|
|
if ((real_offset+real_len) > tot_len) |
|
|
return; |
|
|
|
|
|
/* Rewrite the destination MAC address */ |
|
|
hdr->daddr.eth_addr_byte[4] = 0x00; |
|
|
|
|
|
/* Compute the internal FCS on the encapsulated packet */ |
|
|
ifcs = crc32_compute(0xFFFFFFFF,pkt+real_offset,real_len); |
|
|
pkt[tot_len-4] = ifcs & 0xff; |
|
|
pkt[tot_len-3] = (ifcs >> 8) & 0xff; |
|
|
pkt[tot_len-2] = (ifcs >> 16) & 0xff; |
|
|
pkt[tot_len-1] = ifcs >> 24; |
|
|
} |
|
|
} |
|
|
|
|
190 |
/* Check if a packet must be delivered to the emulated chip */ |
/* Check if a packet must be delivered to the emulated chip */ |
191 |
static inline int dec21140_handle_mac_addr(struct dec21140_data *d, |
static inline int dec21140_handle_mac_addr(struct dec21140_data *d, |
192 |
m_uint8_t *pkt) |
m_uint8_t *pkt) |
380 |
#endif |
#endif |
381 |
} |
} |
382 |
|
|
383 |
|
/* Update the interrupt status */ |
384 |
|
static inline void dev_dec21140_update_irq_status(struct dec21140_data *d) |
385 |
|
{ |
386 |
|
int trigger = FALSE; |
387 |
|
m_uint32_t csr5; |
388 |
|
|
389 |
|
/* Work on a temporary copy of csr5 */ |
390 |
|
csr5 = d->csr[5]; |
391 |
|
|
392 |
|
/* Compute Interrupt Summary */ |
393 |
|
csr5 &= ~(DEC21140_CSR5_AIS|DEC21140_CSR5_NIS); |
394 |
|
|
395 |
|
if (csr5 & DEC21140_NIS_BITS) { |
396 |
|
csr5 |= DEC21140_CSR5_NIS; |
397 |
|
trigger = TRUE; |
398 |
|
} |
399 |
|
|
400 |
|
if (csr5 & DEC21140_AIS_BITS) { |
401 |
|
csr5 |= DEC21140_CSR5_AIS; |
402 |
|
trigger = TRUE; |
403 |
|
} |
404 |
|
|
405 |
|
d->csr[5] = csr5; |
406 |
|
|
407 |
|
if (trigger) |
408 |
|
pci_dev_trigger_irq(d->vm,d->pci_dev); |
409 |
|
else |
410 |
|
pci_dev_clear_irq(d->vm,d->pci_dev); |
411 |
|
} |
412 |
|
|
413 |
/* |
/* |
414 |
* dev_dec21140_access() |
* dev_dec21140_access() |
415 |
*/ |
*/ |
416 |
void *dev_dec21140_access(cpu_mips_t *cpu,struct vdevice *dev, |
void *dev_dec21140_access(cpu_gen_t *cpu,struct vdevice *dev, |
417 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
418 |
m_uint64_t *data) |
m_uint64_t *data) |
419 |
{ |
{ |
443 |
if (d->csr[6] & DEC21140_CSR6_START_TX) |
if (d->csr[6] & DEC21140_CSR6_START_TX) |
444 |
*data |= 0x03 << DEC21140_CSR5_TS_SHIFT; |
*data |= 0x03 << DEC21140_CSR5_TS_SHIFT; |
445 |
|
|
446 |
*data |= d->csr[5] & (DEC21140_CSR5_TI|DEC21140_CSR5_RI); |
*data |= d->csr[5]; |
447 |
break; |
break; |
448 |
|
|
449 |
case 8: |
case 8: |
459 |
#if DEBUG_CSR_REGS |
#if DEBUG_CSR_REGS |
460 |
cpu_log(cpu,d->name,"write CSR%u value 0x%x\n",reg,(m_uint32_t)*data); |
cpu_log(cpu,d->name,"write CSR%u value 0x%x\n",reg,(m_uint32_t)*data); |
461 |
#endif |
#endif |
|
d->csr[reg] = *data; |
|
|
|
|
462 |
switch(reg) { |
switch(reg) { |
463 |
case 3: |
case 3: |
464 |
|
d->csr[reg] = *data; |
465 |
d->rx_current = d->csr[reg]; |
d->rx_current = d->csr[reg]; |
466 |
break; |
break; |
467 |
case 4: |
case 4: |
468 |
|
d->csr[reg] = *data; |
469 |
d->tx_current = d->csr[reg]; |
d->tx_current = d->csr[reg]; |
470 |
break; |
break; |
471 |
|
case 5: |
472 |
|
d->csr[reg] &= ~(*data); |
473 |
|
dev_dec21140_update_irq_status(d); |
474 |
|
break; |
475 |
case 9: |
case 9: |
476 |
/* |
/* |
477 |
* CSR9, probably they want to mess with MII PHY |
* CSR9, probably they want to mess with MII PHY |
483 |
* |
* |
484 |
* Also it makes "sh contr f0/0" happy. |
* Also it makes "sh contr f0/0" happy. |
485 |
*/ |
*/ |
486 |
if ((*data&~DEC21140_CSR9_TX_BIT) == (DEC21140_CSR9_MII_READ| |
d->csr[reg] = *data; |
487 |
|
|
488 |
|
if ((*data & ~DEC21140_CSR9_TX_BIT) == (DEC21140_CSR9_MII_READ| |
489 |
DEC21140_CSR9_READ|DEC21140_CSR9_MDC_CLOCK)) { |
DEC21140_CSR9_READ|DEC21140_CSR9_MDC_CLOCK)) { |
490 |
/* |
/* |
491 |
* read, pop one bit from mii_outbits |
* read, pop one bit from mii_outbits |
503 |
mii_newbit(d,(*data&DEC21140_CSR9_TX_BIT) ? 1 : 0); |
mii_newbit(d,(*data&DEC21140_CSR9_TX_BIT) ? 1 : 0); |
504 |
} |
} |
505 |
break; |
break; |
506 |
|
|
507 |
|
default: |
508 |
|
d->csr[reg] = *data; |
509 |
} |
} |
510 |
} |
} |
511 |
|
|
673 |
|
|
674 |
/* Indicate that we have a frame ready */ |
/* Indicate that we have a frame ready */ |
675 |
d->csr[5] |= DEC21140_CSR5_RI; |
d->csr[5] |= DEC21140_CSR5_RI; |
676 |
|
dev_dec21140_update_irq_status(d); |
|
/* Generate IRQ on CPU */ |
|
|
pci_dev_trigger_irq(d->vm,d->pci_dev); |
|
677 |
return(TRUE); |
return(TRUE); |
678 |
} |
} |
679 |
|
|
839 |
mem_dump(log_file,pkt,tot_len); |
mem_dump(log_file,pkt,tot_len); |
840 |
#endif |
#endif |
841 |
/* rewrite ISL header if required */ |
/* rewrite ISL header if required */ |
842 |
dec21140_isl_rewrite(pkt,tot_len); |
cisco_isl_rewrite(pkt,tot_len); |
843 |
|
|
844 |
/* send it on wire */ |
/* send it on wire */ |
845 |
netio_send(d->nio,pkt,tot_len); |
netio_send(d->nio,pkt,tot_len); |
848 |
clear_txd0_own_bit: |
clear_txd0_own_bit: |
849 |
/* Clear the OWN flag of the first descriptor */ |
/* Clear the OWN flag of the first descriptor */ |
850 |
physmem_copy_u32_to_vm(d->vm,tx_start,0); |
physmem_copy_u32_to_vm(d->vm,tx_start,0); |
851 |
|
|
852 |
/* Interrupt on completion ? */ |
/* Interrupt on completion ? */ |
853 |
if (!(txd0.tdes[1] & DEC21140_TXDESC_IC)) { |
if (txd0.tdes[1] & DEC21140_TXDESC_IC) { |
854 |
d->csr[5] |= DEC21140_CSR5_TI; |
d->csr[5] |= DEC21140_CSR5_TI; |
855 |
pci_dev_trigger_irq(d->vm,d->pci_dev); |
dev_dec21140_update_irq_status(d); |
856 |
} |
} |
857 |
|
|
858 |
return(TRUE); |
return(TRUE); |
875 |
* |
* |
876 |
* Read a PCI register. |
* Read a PCI register. |
877 |
*/ |
*/ |
878 |
static m_uint32_t pci_dec21140_read(cpu_mips_t *cpu,struct pci_device *dev, |
static m_uint32_t pci_dec21140_read(cpu_gen_t *cpu,struct pci_device *dev, |
879 |
int reg) |
int reg) |
880 |
{ |
{ |
881 |
struct dec21140_data *d = dev->priv_data; |
struct dec21140_data *d = dev->priv_data; |
901 |
* |
* |
902 |
* Write a PCI register. |
* Write a PCI register. |
903 |
*/ |
*/ |
904 |
static void pci_dec21140_write(cpu_mips_t *cpu,struct pci_device *dev, |
static void pci_dec21140_write(cpu_gen_t *cpu,struct pci_device *dev, |
905 |
int reg,m_uint32_t value) |
int reg,m_uint32_t value) |
906 |
{ |
{ |
907 |
struct dec21140_data *d = dev->priv_data; |
struct dec21140_data *d = dev->priv_data; |