--- upstream/dynamips-0.2.5/dev_dec21140.c 2007/10/06 16:01:44 1 +++ upstream/dynamips-0.2.8-RC1/dev_dec21140.c 2007/10/06 16:33:40 11 @@ -1,5 +1,5 @@ /* - * Cisco C7200 (Predator) DEC21140 Module. + * Cisco router simlation platform. * Copyright (C) 2005,2006 Christophe Fillot. All rights reserved. * * DEC21140 FastEthernet chip emulation. @@ -31,7 +31,8 @@ #include "crc.h" #include "utils.h" -#include "mips64.h" +#include "cpu.h" +#include "vm.h" #include "dynamips.h" #include "memory.h" #include "device.h" @@ -65,8 +66,28 @@ #define DEC21140_CSR_NR 16 /* CSR5: Status Register */ -#define DEC21140_CSR5_TI 0x00000001 -#define DEC21140_CSR5_RI 0x00000040 +#define DEC21140_CSR5_TI 0x00000001 /* TX Interrupt */ +#define DEC21140_CSR5_TPS 0x00000002 /* TX Process Stopped */ +#define DEC21140_CSR5_TU 0x00000004 /* TX Buffer Unavailable */ +#define DEC21140_CSR5_TJT 0x00000008 /* TX Jabber Timeout */ +#define DEC21140_CSR5_UNF 0x00000020 /* TX Underflow */ +#define DEC21140_CSR5_RI 0x00000040 /* RX Interrupt */ +#define DEC21140_CSR5_RU 0x00000080 /* RX Buffer Unavailable */ +#define DEC21140_CSR5_RPS 0x00000100 /* RX Process Stopped */ +#define DEC21140_CSR5_RWT 0x00000200 /* RX Watchdog Timeout */ +#define DEC21140_CSR5_GTE 0x00000800 /* Gen Purpose Timer Expired */ +#define DEC21140_CSR5_FBE 0x00002000 /* Fatal Bus Error */ +#define DEC21140_CSR5_AIS 0x00008000 /* Abnormal Interrupt Summary */ +#define DEC21140_CSR5_NIS 0x00010000 /* Normal Interrupt Summary */ + +#define DEC21140_NIS_BITS \ + (DEC21140_CSR5_TI|DEC21140_CSR5_RI|DEC21140_CSR5_TU) + +#define DEC21140_AIS_BITS \ + (DEC21140_CSR5_TPS|DEC21140_CSR5_TJT|DEC21140_CSR5_UNF| \ + DEC21140_CSR5_RU|DEC21140_CSR5_RPS|DEC21140_CSR5_RWT| \ + DEC21140_CSR5_GTE|DEC21140_CSR5_FBE) + #define DEC21140_CSR5_RS_SHIFT 17 #define DEC21140_CSR5_TS_SHIFT 20 @@ -86,8 +107,8 @@ /* Maximum packet size */ #define DEC21140_MAX_PKT_SIZE 2048 -/* Send up to 16 packets in a TX ring scan pass */ -#define DEC21140_TXRING_PASS_COUNT 16 +/* Send up to 32 packets in a TX ring scan pass */ +#define DEC21140_TXRING_PASS_COUNT 32 /* Setup frame size */ #define DEC21140_SETUP_FRAME_SIZE 192 @@ -166,39 +187,6 @@ /* Log a dec21140 message */ #define DEC21140_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) -/* - * 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; - } -} - /* Check if a packet must be delivered to the emulated chip */ static inline int dec21140_handle_mac_addr(struct dec21140_data *d, m_uint8_t *pkt) @@ -206,11 +194,6 @@ n_eth_hdr_t *hdr = (n_eth_hdr_t *)pkt; int i; - /* Ignore traffic sent by us */ - for(i=0;imac_addr_count;i++) - if (!memcmp(&d->mac_addr[i],&hdr->saddr,N_ETH_ALEN)) - return(FALSE); - /* Accept systematically frames if we are running is promiscuous mode */ if (d->csr[6] & DEC21140_CSR6_PROMISC) return(TRUE); @@ -397,10 +380,40 @@ #endif } +/* Update the interrupt status */ +static inline void dev_dec21140_update_irq_status(struct dec21140_data *d) +{ + int trigger = FALSE; + m_uint32_t csr5; + + /* Work on a temporary copy of csr5 */ + csr5 = d->csr[5]; + + /* Compute Interrupt Summary */ + csr5 &= ~(DEC21140_CSR5_AIS|DEC21140_CSR5_NIS); + + if (csr5 & DEC21140_NIS_BITS) { + csr5 |= DEC21140_CSR5_NIS; + trigger = TRUE; + } + + if (csr5 & DEC21140_AIS_BITS) { + csr5 |= DEC21140_CSR5_AIS; + trigger = TRUE; + } + + d->csr[5] = csr5; + + if (trigger) + pci_dev_trigger_irq(d->vm,d->pci_dev); + else + pci_dev_clear_irq(d->vm,d->pci_dev); +} + /* * dev_dec21140_access() */ -void *dev_dec21140_access(cpu_mips_t *cpu,struct vdevice *dev, +void *dev_dec21140_access(cpu_gen_t *cpu,struct vdevice *dev, m_uint32_t offset,u_int op_size,u_int op_type, m_uint64_t *data) { @@ -419,38 +432,46 @@ #if DEBUG_CSR_REGS cpu_log(cpu,d->name,"read CSR%u value 0x%x\n",reg,d->csr[reg]); #endif - - /* Dynamically construct CSR5 */ - if (reg == 5) { - *data = 0; - - if (d->csr[6] & DEC21140_CSR6_START_RX) - *data |= 0x03 << DEC21140_CSR5_RS_SHIFT; - - if (d->csr[6] & DEC21140_CSR6_START_TX) - *data |= 0x03 << DEC21140_CSR5_TS_SHIFT; + switch(reg) { + case 5: + /* Dynamically construct CSR5 */ + *data = 0; + + if (d->csr[6] & DEC21140_CSR6_START_RX) + *data |= 0x03 << DEC21140_CSR5_RS_SHIFT; + + if (d->csr[6] & DEC21140_CSR6_START_TX) + *data |= 0x03 << DEC21140_CSR5_TS_SHIFT; - *data |= d->csr[5] & (DEC21140_CSR5_TI|DEC21140_CSR5_RI); - } - else - *data = d->csr[reg]; + *data |= d->csr[5]; + break; - /* CSR8 is cleared when read */ - if (reg == 8) - d->csr[reg] = 0; + case 8: + /* CSR8 is cleared when read (missed frame counter) */ + d->csr[reg] = 0; + *data = 0; + break; + + default: + *data = d->csr[reg]; + } } else { #if DEBUG_CSR_REGS cpu_log(cpu,d->name,"write CSR%u value 0x%x\n",reg,(m_uint32_t)*data); #endif - d->csr[reg] = *data; - switch(reg) { case 3: + d->csr[reg] = *data; d->rx_current = d->csr[reg]; break; case 4: + d->csr[reg] = *data; d->tx_current = d->csr[reg]; break; + case 5: + d->csr[reg] &= ~(*data); + dev_dec21140_update_irq_status(d); + break; case 9: /* * CSR9, probably they want to mess with MII PHY @@ -462,7 +483,9 @@ * * Also it makes "sh contr f0/0" happy. */ - if ((*data&~DEC21140_CSR9_TX_BIT) == (DEC21140_CSR9_MII_READ| + d->csr[reg] = *data; + + if ((*data & ~DEC21140_CSR9_TX_BIT) == (DEC21140_CSR9_MII_READ| DEC21140_CSR9_READ|DEC21140_CSR9_MDC_CLOCK)) { /* * read, pop one bit from mii_outbits @@ -480,6 +503,9 @@ mii_newbit(d,(*data&DEC21140_CSR9_TX_BIT) ? 1 : 0); } break; + + default: + d->csr[reg] = *data; } } @@ -507,7 +533,7 @@ return(nrxd_addr); } -/* Read an RX descriptor */ +/* Read a RX descriptor */ static void rxdesc_read(struct dec21140_data *d,m_uint32_t rxd_addr, struct rx_desc *rxd) { @@ -647,9 +673,7 @@ /* Indicate that we have a frame ready */ d->csr[5] |= DEC21140_CSR5_RI; - - /* Generate IRQ on CPU */ - pci_dev_trigger_irq(d->vm,d->pci_dev); + dev_dec21140_update_irq_status(d); return(TRUE); } @@ -675,9 +699,9 @@ * for this virtual machine. */ if (dec21140_handle_mac_addr(d,pkt)) - dev_dec21140_receive_pkt(d,pkt,pkt_len); + return(dev_dec21140_receive_pkt(d,pkt,pkt_len)); - return(TRUE); + return(FALSE); } /* Read a TX descriptor */ @@ -726,7 +750,7 @@ /* Copy the current txring descriptor */ tx_start = d->tx_current; ptxd = &txd0; - txdesc_read(d,d->tx_current,ptxd); + txdesc_read(d,tx_start,ptxd); /* If we don't own the first descriptor, we cannot transmit */ if (!(txd0.tdes[0] & DEC21140_TXDESC_OWN)) @@ -815,7 +839,7 @@ mem_dump(log_file,pkt,tot_len); #endif /* rewrite ISL header if required */ - dec21140_isl_rewrite(pkt,tot_len); + cisco_isl_rewrite(pkt,tot_len); /* send it on wire */ netio_send(d->nio,pkt,tot_len); @@ -824,11 +848,11 @@ clear_txd0_own_bit: /* Clear the OWN flag of the first descriptor */ physmem_copy_u32_to_vm(d->vm,tx_start,0); - + /* Interrupt on completion ? */ - if (!(txd0.tdes[1] & DEC21140_TXDESC_IC)) { + if (txd0.tdes[1] & DEC21140_TXDESC_IC) { d->csr[5] |= DEC21140_CSR5_TI; - pci_dev_trigger_irq(d->vm,d->pci_dev); + dev_dec21140_update_irq_status(d); } return(TRUE); @@ -851,7 +875,7 @@ * * Read a PCI register. */ -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, int reg) { struct dec21140_data *d = dev->priv_data; @@ -877,7 +901,7 @@ * * Write a PCI register. */ -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, int reg,m_uint32_t value) { struct dec21140_data *d = dev->priv_data; @@ -939,6 +963,7 @@ /* Basic register setup */ d->csr[0] = 0xfff80000; + d->csr[5] = 0xfc000000; d->csr[8] = 0xfffe0000; dev->phys_addr = 0;