?? pcnet.c
字號:
/* * QEMU AMD PC-Net II (Am79C970A) emulation * * Copyright (c) 2004 Antony T Curtis * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. *//* This software was written to be compatible with the specification: * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 *//* * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also * produced as NCR89C100. See * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt * and * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt */#include "hw.h"#include "pci.h"#include "net.h"#include "qemu-timer.h"//#define PCNET_DEBUG//#define PCNET_DEBUG_IO//#define PCNET_DEBUG_BCR//#define PCNET_DEBUG_CSR//#define PCNET_DEBUG_RMD//#define PCNET_DEBUG_TMD//#define PCNET_DEBUG_MATCH#define PCNET_IOPORT_SIZE 0x20#define PCNET_PNPMMIO_SIZE 0x20typedef struct PCNetState_st PCNetState;struct PCNetState_st { PCIDevice dev; PCIDevice *pci_dev; VLANClientState *vc; NICInfo *nd; QEMUTimer *poll_timer; int mmio_index, rap, isr, lnkst; uint32_t rdra, tdra; uint8_t prom[16]; uint16_t csr[128]; uint16_t bcr[32]; uint64_t timer; int xmit_pos, recv_pos; uint8_t buffer[4096]; int tx_busy; qemu_irq irq; void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); void *dma_opaque;};struct qemu_ether_header { uint8_t ether_dhost[6]; uint8_t ether_shost[6]; uint16_t ether_type;};/* BUS CONFIGURATION REGISTERS */#define BCR_MSRDA 0#define BCR_MSWRA 1#define BCR_MC 2#define BCR_LNKST 4#define BCR_LED1 5#define BCR_LED2 6#define BCR_LED3 7#define BCR_FDC 9#define BCR_BSBC 18#define BCR_EECAS 19#define BCR_SWS 20#define BCR_PLAT 22#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080)#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100)#define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF)#define CSR_INIT(S) !!(((S)->csr[0])&0x0001)#define CSR_STRT(S) !!(((S)->csr[0])&0x0002)#define CSR_STOP(S) !!(((S)->csr[0])&0x0004)#define CSR_TDMD(S) !!(((S)->csr[0])&0x0008)#define CSR_TXON(S) !!(((S)->csr[0])&0x0010)#define CSR_RXON(S) !!(((S)->csr[0])&0x0020)#define CSR_INEA(S) !!(((S)->csr[0])&0x0040)#define CSR_BSWP(S) !!(((S)->csr[3])&0x0004)#define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020)#define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040)#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800)#define CSR_DPOLL(S) !!(((S)->csr[4])&0x1000)#define CSR_SPND(S) !!(((S)->csr[5])&0x0001)#define CSR_LTINTEN(S) !!(((S)->csr[5])&0x4000)#define CSR_TOKINTD(S) !!(((S)->csr[5])&0x8000)#define CSR_DRX(S) !!(((S)->csr[15])&0x0001)#define CSR_DTX(S) !!(((S)->csr[15])&0x0002)#define CSR_LOOP(S) !!(((S)->csr[15])&0x0004)#define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000)#define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000)#define CSR_PROM(S) !!(((S)->csr[15])&0x8000)#define CSR_CRBC(S) ((S)->csr[40])#define CSR_CRST(S) ((S)->csr[41])#define CSR_CXBC(S) ((S)->csr[42])#define CSR_CXST(S) ((S)->csr[43])#define CSR_NRBC(S) ((S)->csr[44])#define CSR_NRST(S) ((S)->csr[45])#define CSR_POLL(S) ((S)->csr[46])#define CSR_PINT(S) ((S)->csr[47])#define CSR_RCVRC(S) ((S)->csr[72])#define CSR_XMTRC(S) ((S)->csr[74])#define CSR_RCVRL(S) ((S)->csr[76])#define CSR_XMTRL(S) ((S)->csr[78])#define CSR_MISSC(S) ((S)->csr[112])#define CSR_IADR(S) ((S)->csr[ 1] | ((S)->csr[ 2] << 16))#define CSR_CRBA(S) ((S)->csr[18] | ((S)->csr[19] << 16))#define CSR_CXBA(S) ((S)->csr[20] | ((S)->csr[21] << 16))#define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16))#define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16))#define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16))#define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16))#define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16))#define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16))#define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16))#define CSR_NNRD(S) ((S)->csr[36] | ((S)->csr[37] << 16))#define CSR_NNXD(S) ((S)->csr[38] | ((S)->csr[39] << 16))#define CSR_PXDA(S) ((S)->csr[60] | ((S)->csr[61] << 16))#define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16))#define PHYSADDR(S,A) \ (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16))struct pcnet_initblk16 { uint16_t mode; uint16_t padr[3]; uint16_t ladrf[4]; uint32_t rdra; uint32_t tdra;};struct pcnet_initblk32 { uint16_t mode; uint8_t rlen; uint8_t tlen; uint16_t padr[3]; uint16_t _res; uint16_t ladrf[4]; uint32_t rdra; uint32_t tdra;};struct pcnet_TMD { uint32_t tbadr; int16_t length; int16_t status; uint32_t misc; uint32_t res;};#define TMDL_BCNT_MASK 0x0fff#define TMDL_BCNT_SH 0#define TMDL_ONES_MASK 0xf000#define TMDL_ONES_SH 12#define TMDS_BPE_MASK 0x0080#define TMDS_BPE_SH 7#define TMDS_ENP_MASK 0x0100#define TMDS_ENP_SH 8#define TMDS_STP_MASK 0x0200#define TMDS_STP_SH 9#define TMDS_DEF_MASK 0x0400#define TMDS_DEF_SH 10#define TMDS_ONE_MASK 0x0800#define TMDS_ONE_SH 11#define TMDS_LTINT_MASK 0x1000#define TMDS_LTINT_SH 12#define TMDS_NOFCS_MASK 0x2000#define TMDS_NOFCS_SH 13#define TMDS_ERR_MASK 0x4000#define TMDS_ERR_SH 14#define TMDS_OWN_MASK 0x8000#define TMDS_OWN_SH 15#define TMDM_TRC_MASK 0x0000000f#define TMDM_TRC_SH 0#define TMDM_TDR_MASK 0x03ff0000#define TMDM_TDR_SH 16#define TMDM_RTRY_MASK 0x04000000#define TMDM_RTRY_SH 26#define TMDM_LCAR_MASK 0x08000000#define TMDM_LCAR_SH 27#define TMDM_LCOL_MASK 0x10000000#define TMDM_LCOL_SH 28#define TMDM_EXDEF_MASK 0x20000000#define TMDM_EXDEF_SH 29#define TMDM_UFLO_MASK 0x40000000#define TMDM_UFLO_SH 30#define TMDM_BUFF_MASK 0x80000000#define TMDM_BUFF_SH 31struct pcnet_RMD { uint32_t rbadr; int16_t buf_length; int16_t status; uint32_t msg_length; uint32_t res;};#define RMDL_BCNT_MASK 0x0fff#define RMDL_BCNT_SH 0#define RMDL_ONES_MASK 0xf000#define RMDL_ONES_SH 12#define RMDS_BAM_MASK 0x0010#define RMDS_BAM_SH 4#define RMDS_LFAM_MASK 0x0020#define RMDS_LFAM_SH 5#define RMDS_PAM_MASK 0x0040#define RMDS_PAM_SH 6#define RMDS_BPE_MASK 0x0080#define RMDS_BPE_SH 7#define RMDS_ENP_MASK 0x0100#define RMDS_ENP_SH 8#define RMDS_STP_MASK 0x0200#define RMDS_STP_SH 9#define RMDS_BUFF_MASK 0x0400#define RMDS_BUFF_SH 10#define RMDS_CRC_MASK 0x0800#define RMDS_CRC_SH 11#define RMDS_OFLO_MASK 0x1000#define RMDS_OFLO_SH 12#define RMDS_FRAM_MASK 0x2000#define RMDS_FRAM_SH 13#define RMDS_ERR_MASK 0x4000#define RMDS_ERR_SH 14#define RMDS_OWN_MASK 0x8000#define RMDS_OWN_SH 15#define RMDM_MCNT_MASK 0x00000fff#define RMDM_MCNT_SH 0#define RMDM_ZEROS_MASK 0x0000f000#define RMDM_ZEROS_SH 12#define RMDM_RPC_MASK 0x00ff0000#define RMDM_RPC_SH 16#define RMDM_RCC_MASK 0xff000000#define RMDM_RCC_SH 24#define SET_FIELD(regp, name, field, value) \ (*(regp) = (*(regp) & ~(name ## _ ## field ## _MASK)) \ | ((value) << name ## _ ## field ## _SH))#define GET_FIELD(reg, name, field) \ (((reg) & name ## _ ## field ## _MASK) >> name ## _ ## field ## _SH)#define PRINT_TMD(T) printf( \ "TMD0 : TBADR=0x%08x\n" \ "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \ "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \ " BPE=%d, BCNT=%d\n" \ "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \ "LCA=%d, RTR=%d,\n" \ " TDR=%d, TRC=%d\n", \ (T)->tbadr, \ GET_FIELD((T)->status, TMDS, OWN), \ GET_FIELD((T)->status, TMDS, ERR), \ GET_FIELD((T)->status, TMDS, NOFCS), \ GET_FIELD((T)->status, TMDS, LTINT), \ GET_FIELD((T)->status, TMDS, ONE), \ GET_FIELD((T)->status, TMDS, DEF), \ GET_FIELD((T)->status, TMDS, STP), \ GET_FIELD((T)->status, TMDS, ENP), \ GET_FIELD((T)->status, TMDS, BPE), \ 4096-GET_FIELD((T)->length, TMDL, BCNT), \ GET_FIELD((T)->misc, TMDM, BUFF), \ GET_FIELD((T)->misc, TMDM, UFLO), \ GET_FIELD((T)->misc, TMDM, EXDEF), \ GET_FIELD((T)->misc, TMDM, LCOL), \ GET_FIELD((T)->misc, TMDM, LCAR), \ GET_FIELD((T)->misc, TMDM, RTRY), \ GET_FIELD((T)->misc, TMDM, TDR), \ GET_FIELD((T)->misc, TMDM, TRC))#define PRINT_RMD(R) printf( \ "RMD0 : RBADR=0x%08x\n" \ "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \ "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \ "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \ "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \ (R)->rbadr, \ GET_FIELD((R)->status, RMDS, OWN), \ GET_FIELD((R)->status, RMDS, ERR), \ GET_FIELD((R)->status, RMDS, FRAM), \ GET_FIELD((R)->status, RMDS, OFLO), \ GET_FIELD((R)->status, RMDS, CRC), \ GET_FIELD((R)->status, RMDS, BUFF), \ GET_FIELD((R)->status, RMDS, STP), \ GET_FIELD((R)->status, RMDS, ENP), \ GET_FIELD((R)->status, RMDS, BPE), \ GET_FIELD((R)->status, RMDS, PAM), \ GET_FIELD((R)->status, RMDS, LFAM), \ GET_FIELD((R)->status, RMDS, BAM), \ GET_FIELD((R)->buf_length, RMDL, ONES), \ 4096-GET_FIELD((R)->buf_length, RMDL, BCNT), \ GET_FIELD((R)->msg_length, RMDM, RCC), \ GET_FIELD((R)->msg_length, RMDM, RPC), \ GET_FIELD((R)->msg_length, RMDM, MCNT), \ GET_FIELD((R)->msg_length, RMDM, ZEROS))static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr){ if (!BCR_SSIZE32(s)) { struct { uint32_t tbadr; int16_t length; int16_t status; } xda; s->phys_mem_read(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0); tmd->tbadr = le32_to_cpu(xda.tbadr) & 0xffffff; tmd->length = le16_to_cpu(xda.length); tmd->status = (le32_to_cpu(xda.tbadr) >> 16) & 0xff00; tmd->misc = le16_to_cpu(xda.status) << 16; tmd->res = 0; } else { s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, sizeof(*tmd), 0); le32_to_cpus(&tmd->tbadr); le16_to_cpus((uint16_t *)&tmd->length); le16_to_cpus((uint16_t *)&tmd->status); le32_to_cpus(&tmd->misc); le32_to_cpus(&tmd->res); if (BCR_SWSTYLE(s) == 3) { uint32_t tmp = tmd->tbadr; tmd->tbadr = tmd->misc; tmd->misc = tmp; } }}static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd, target_phys_addr_t addr){ if (!BCR_SSIZE32(s)) { struct { uint32_t tbadr; int16_t length; int16_t status; } xda; xda.tbadr = cpu_to_le32((tmd->tbadr & 0xffffff) | ((tmd->status & 0xff00) << 16)); xda.length = cpu_to_le16(tmd->length); xda.status = cpu_to_le16(tmd->misc >> 16); s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0); } else { struct { uint32_t tbadr; int16_t length; int16_t status; uint32_t misc; uint32_t res; } xda; xda.tbadr = cpu_to_le32(tmd->tbadr); xda.length = cpu_to_le16(tmd->length); xda.status = cpu_to_le16(tmd->status); xda.misc = cpu_to_le32(tmd->misc); xda.res = cpu_to_le32(tmd->res); if (BCR_SWSTYLE(s) == 3) { uint32_t tmp = xda.tbadr; xda.tbadr = xda.misc; xda.misc = tmp; } s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0); }}static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr){ if (!BCR_SSIZE32(s)) { struct { uint32_t rbadr; int16_t buf_length; int16_t msg_length; } rda; s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0); rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff; rmd->buf_length = le16_to_cpu(rda.buf_length); rmd->status = (le32_to_cpu(rda.rbadr) >> 16) & 0xff00; rmd->msg_length = le16_to_cpu(rda.msg_length); rmd->res = 0; } else { s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, sizeof(*rmd), 0);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -