📄 dev_dec21140.c
字号:
/* * Cisco C7200 (Predator) DEC21140 Module. * Copyright (C) 2005,2006 Christophe Fillot. All rights reserved. * * DEC21140 FastEthernet chip emulation. * * It allows to emulate a C7200-IO-FE card with 1 port and PA-FE-TX cards. * * Many many thanks to mtve (aka "Mtv Europe") for his great work on * this stuff. * * Manuals: * * DECchip 21140 PCI fast Ethernet LAN controller Hardware reference manual * http://ftp.nluug.nl/NetBSD/misc/dec-docs/ec-qc0cb-te.ps.gz * * National DP83840 PHY * http://www.rezrov.net/docs/DP83840A.pdf * * Remark: only Big-endian mode is supported. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <unistd.h>#include <time.h>#include <errno.h>#include <assert.h>#include "crc.h"#include "utils.h"#include "mips64.h"#include "dynamips.h"#include "memory.h"#include "device.h"#include "net.h"#include "net_io.h"#include "ptask.h"#include "dev_dec21140.h"/* Debugging flags */#define DEBUG_MII_REGS 0#define DEBUG_CSR_REGS 0#define DEBUG_PCI_REGS 0#define DEBUG_TRANSMIT 0#define DEBUG_RECEIVE 0/* DEC21140 PCI vendor/product codes */#define DEC21140_PCI_VENDOR_ID 0x1011#define DEC21140_PCI_PRODUCT_ID 0x0009/* DEC21140 PCI registers */#define DEC21140_PCI_CFID_REG_OFFSET 0x00#define DEC21140_PCI_CFCS_REG_OFFSET 0x04#define DEC21140_PCI_CFRV_REG_OFFSET 0x08#define DEC21140_PCI_CFLT_REG_OFFSET 0x0C#define DEC21140_PCI_CBIO_REG_OFFSET 0x10#define DEC21140_PCI_CBMA_REG_OFFSET 0x14#define DEC21140_PCI_CFIT_REG_OFFSET 0x3C#define DEC21140_PCI_CFDA_REG_OFFSET 0x40/* Number of CSR registers */#define DEC21140_CSR_NR 16/* CSR5: Status Register */#define DEC21140_CSR5_TI 0x00000001#define DEC21140_CSR5_RI 0x00000040#define DEC21140_CSR5_RS_SHIFT 17#define DEC21140_CSR5_TS_SHIFT 20/* CSR6: Operating Mode Register */#define DEC21140_CSR6_START_RX 0x00000002#define DEC21140_CSR6_START_TX 0x00002000#define DEC21140_CSR6_PROMISC 0x00000040/* CSR9: Serial EEPROM and MII */#define DEC21140_CSR9_RX_BIT 0x00080000#define DEC21140_CSR9_MII_READ 0x00040000#define DEC21140_CSR9_TX_BIT 0x00020000#define DEC21140_CSR9_MDC_CLOCK 0x00010000#define DEC21140_CSR9_READ 0x00004000#define DEC21140_CSR9_WRITE 0x00002000/* Maximum packet size */#define DEC21140_MAX_PKT_SIZE 2048/* 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/* RX descriptors */#define DEC21140_RXDESC_OWN 0x80000000 /* Ownership */#define DEC21140_RXDESC_LS 0x00000100 /* Last Segment */#define DEC21140_RXDESC_FS 0x00000200 /* First Segment */#define DEC21140_RXDESC_MF 0x00000400 /* Multicast Frame */#define DEC21140_RXDESC_DE 0x00004000 /* Descriptor Error */#define DEC21140_RXDESC_RCH 0x01000000 /* Sec. Addr. Chained */#define DEC21140_RXDESC_RER 0x02000000 /* Receive End of Ring */#define DEC21140_RXDESC_FL_SHIFT 16#define DEC21140_RXDESC_LEN_MASK 0x7ff/* TX descriptors */#define DEC21140_TXDESC_OWN 0x80000000 /* Ownership */#define DEC21140_TXDESC_TCH 0x01000000 /* Sec. Addr. Chained */#define DEC21140_TXDESC_TER 0x02000000 /* Transmit End of Ring */#define DEC21140_TXDESC_SET 0x08000000 /* Setup frame */#define DEC21140_TXDESC_FS 0x20000000 /* First Segment */#define DEC21140_TXDESC_LS 0x40000000 /* Last Segment */#define DEC21140_TXDESC_IC 0x80000000 /* IRQ on completion */#define DEC21140_TXDESC_LEN_MASK 0x7ff/* RX Descriptor */struct rx_desc { m_uint32_t rdes[4];};/* TX Descriptor */struct tx_desc { m_uint32_t tdes[4];};/* DEC21140 Data */struct dec21140_data { char *name; /* Physical addresses of current RX and TX descriptors */ m_uint32_t rx_current; m_uint32_t tx_current; /* CSR registers */ m_uint32_t csr[DEC21140_CSR_NR]; /* MII registers */ m_uint32_t mii_state; m_uint32_t mii_phy; m_uint32_t mii_reg; m_uint32_t mii_data; m_uint32_t mii_outbits; m_uint16_t mii_regs[32][32]; /* Ethernet unicast addresses */ n_eth_addr_t mac_addr[16]; u_int mac_addr_count; /* Device information */ struct vdevice *dev; /* PCI device information */ struct pci_device *pci_dev; /* Virtual machine */ vm_instance_t *vm; /* NetIO descriptor */ netio_desc_t *nio; /* TX ring scanner task id */ ptask_id_t tx_tid;};/* 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){ n_eth_hdr_t *hdr = (n_eth_hdr_t *)pkt; int i; /* Accept systematically frames if we are running is promiscuous mode */ if (d->csr[6] & DEC21140_CSR6_PROMISC) return(TRUE); /* Accept systematically all multicast frames */ if (eth_addr_is_mcast(&hdr->daddr)) return(TRUE); /* Accept frames directly for us, discard others */ for(i=0;i<d->mac_addr_count;i++) if (!memcmp(&d->mac_addr[i],&hdr->daddr,N_ETH_ALEN)) return(TRUE); return(FALSE);}/* Update MAC addresses */static void dec21140_update_mac_addr(struct dec21140_data *d, u_char *setup_frame){ n_eth_addr_t addr; int i,nb_addr,addr_size; d->mac_addr_count = 0; addr_size = N_ETH_ALEN * 2; nb_addr = DEC21140_SETUP_FRAME_SIZE / addr_size; for(i=0;i<nb_addr;i++) { addr.eth_addr_byte[0] = setup_frame[(i * addr_size) + 0]; addr.eth_addr_byte[1] = setup_frame[(i * addr_size) + 1]; addr.eth_addr_byte[2] = setup_frame[(i * addr_size) + 4]; addr.eth_addr_byte[3] = setup_frame[(i * addr_size) + 5]; addr.eth_addr_byte[4] = setup_frame[(i * addr_size) + 8]; addr.eth_addr_byte[5] = setup_frame[(i * addr_size) + 9]; if (!eth_addr_is_mcast(&addr)) { memcpy(&d->mac_addr[d->mac_addr_count],&addr,N_ETH_ALEN); DEC21140_LOG(d,"unicast MAC address: " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", addr.eth_addr_byte[0],addr.eth_addr_byte[1], addr.eth_addr_byte[2],addr.eth_addr_byte[3], addr.eth_addr_byte[4],addr.eth_addr_byte[5]); d->mac_addr_count++; } }}/* Get a PCI register name */static char *pci_cfgreg_name(int reg){ static char *name[] = { "FID", "FCS", "FRV", "FLT", "BIO", "BMA", "?", "?", "?", "?", "?", "?", "?", "?", "?", "FIT", "FDA" }; return((reg>=0) && (reg<=DEC21140_CSR_NR*4) && ((reg&3)==0) ? name[reg>>2] : "?");}/* * read from register of DP83840A PHY */ static m_uint16_t mii_reg_read(struct dec21140_data *d){#if DEBUG_MII_REGS DEC21140_LOG(d,"MII PHY read %d reg %d\n",d->mii_phy,d->mii_reg);#endif /* * if it's BASIC MODE STATUS REGISTER (BMSR) at address 0x1 * then tell them that "Link Status" is up and no troubles. */ if (d->mii_reg == 1) { if (d->nio != NULL) return(0x04); else return(0x00); } return(d->mii_regs[d->mii_phy][d->mii_reg]);}/* * write to register of DP83840A PHY */ static void mii_reg_write(struct dec21140_data *d){#if DEBUG_MII_REGS DEC21140_LOG(d,"MII PHY write %d reg %d value %04x\n", d->mii_phy,d->mii_reg,d->mii_data);#endif assert(d->mii_phy < 32); assert(d->mii_reg < 32); d->mii_regs[d->mii_phy][d->mii_reg] = d->mii_data;}/* * process new bit sent by IOS to PHY. */static void mii_newbit(struct dec21140_data *d,int newbit){#if DEBUG_MII_REGS DEC21140_LOG(d,"MII state was %d\n",d->mii_state);#endif switch (d->mii_state) { case 0: /* init */ d->mii_state = newbit ? 0 : 1; d->mii_phy = 0; d->mii_reg = 0; d->mii_data = 0; break; case 1: /* already got 0 */ d->mii_state = newbit ? 2 : 0; break; case 2: /* already got attention */ d->mii_state = newbit ? 3 : 4; break; case 3: /* probably it's read */ d->mii_state = newbit ? 0 : 10; break; case 4: /* probably it's write */ d->mii_state = newbit ? 20 : 0; break; case 10: case 11: case 12: case 13: case 14: case 20: case 21: case 22: case 23: case 24: /* read or write state, read 5 bits of phy */ d->mii_phy <<= 1; d->mii_phy |= newbit; d->mii_state++; break; case 15: case 16: case 17: case 18: case 19: case 25: case 26: case 27: case 28: case 29: /* read or write state, read 5 bits of reg */ d->mii_reg <<= 1; d->mii_reg |= newbit; d->mii_state++; if (d->mii_state == 20) { /* read state, got everything */ d->mii_outbits = mii_reg_read (d) << 15; /* first bit will * be thrown away! */ d->mii_state = 0; } break; case 30: /* write state, read first waiting bit */ d->mii_state = newbit ? 31 : 0; break; case 31: /* write state, read second waiting bit */ d->mii_state = newbit ? 0 : 32; break; case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: /* write state, read 16 bits of data */ d->mii_data <<= 1; d->mii_data |= newbit; d->mii_state++; if (d->mii_state == 48) { /* write state, got everything */ mii_reg_write (d); d->mii_state = 0; } break; default: DEC21140_LOG(d,"MII impossible state\n"); }#if DEBUG_MII_REGS DEC21140_LOG(d,"MII state now %d\n",d->mii_state);#endif}/* * dev_dec21140_access() */void *dev_dec21140_access(cpu_mips_t *cpu,struct vdevice *dev, m_uint32_t offset,u_int op_size,u_int op_type, m_uint64_t *data){ struct dec21140_data *d = dev->priv_data; u_int reg; /* which CSR register ? */ reg = offset / 8; if ((reg >= DEC21140_CSR_NR) || (offset % 8) != 0) { cpu_log(cpu,d->name,"invalid access to offset 0x%x\n",offset); return NULL; } if (op_type == MTS_READ) {#if DEBUG_CSR_REGS cpu_log(cpu,d->name,"read CSR%u value 0x%x\n",reg,d->csr[reg]);#endif 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); break; 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->rx_current = d->csr[reg]; break; case 4: d->tx_current = d->csr[reg]; break; case 9: /* * CSR9, probably they want to mess with MII PHY * The protocol to PHY is like serial over one bit. * We will ignore clock 0 of read or write. * * This whole code is needed only to tell IOS that "Link Status" * bit in BMSR register of DP83840A PHY is set. * * Also it makes "sh contr f0/0" happy. */ if ((*data&~DEC21140_CSR9_TX_BIT) == (DEC21140_CSR9_MII_READ| DEC21140_CSR9_READ|DEC21140_CSR9_MDC_CLOCK)) { /* * read, pop one bit from mii_outbits */ if (d->mii_outbits & (1<<31)) d->csr[9] |= DEC21140_CSR9_RX_BIT; else d->csr[9] &= ~DEC21140_CSR9_RX_BIT; d->mii_outbits <<= 1; } else if((*data&~DEC21140_CSR9_TX_BIT) == (DEC21140_CSR9_WRITE|DEC21140_CSR9_MDC_CLOCK)) { /* * write, we've got input, do state machine */ mii_newbit(d,(*data&DEC21140_CSR9_TX_BIT) ? 1 : 0); } break; } } return NULL;}/* * Get the address of the next RX descriptor. */static m_uint32_t rxdesc_get_next(struct dec21140_data *d,m_uint32_t rxd_addr, struct rx_desc *rxd){ m_uint32_t nrxd_addr; /* go to the next descriptor */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -