📄 dev_am79c971.c
字号:
/* Update rmd1 to store change of OWN bit */ physmem_copy_u32_to_vm(d->vm,rx_current+4,rxdc->rmd[1]); /* Read the next descriptor from VM physical RAM */ rxdesc_read(d,rx_next,&rxdn); rxdc = &rxdn; rx_current = rx_next; } /* Update the first RX descriptor */ rxd0.rmd[1] &= ~AM79C971_RMD1_OWN; rxd0.rmd[1] |= AM79C971_RMD1_STP; physmem_copy_u32_to_vm(d->vm,rx_start+4,rxd0.rmd[1]); d->csr[0] |= AM79C971_CSR0_RINT; am79c971_update_irq_status(d); return(TRUE);}/* Handle the RX ring */static int am79c971_handle_rxring(netio_desc_t *nio, u_char *pkt,ssize_t pkt_len, struct am79c971_data *d){ n_eth_hdr_t *hdr; /* * Don't start receive if the RX ring address has not been set * and if RX ON is not set. */ if ((d->rx_start == 0) || !(d->csr[0] & AM79C971_CSR0_RXON)) return(FALSE);#if DEBUG_RECEIVE AM79C971_LOG(d,"receiving a packet of %d bytes\n",pkt_len); mem_dump(log_file,pkt,pkt_len);#endif AM79C971_LOCK(d); /* * Receive only multicast/broadcast trafic + unicast traffic * for this virtual machine. */ hdr = (n_eth_hdr_t *)pkt; if (am79c971_handle_mac_addr(d,pkt)) am79c971_receive_pkt(d,pkt,pkt_len); AM79C971_UNLOCK(d); return(TRUE);}/* Read a TX descriptor */static int txdesc_read(struct am79c971_data *d,m_uint32_t txd_addr, struct tx_desc *txd){ m_uint32_t buf[4]; m_uint8_t sw_style; /* Get the software style */ sw_style = d->bcr[20]; /* Read the descriptor from VM physical RAM */ physmem_copy_from_vm(d->vm,&buf,txd_addr,sizeof(struct tx_desc)); switch(sw_style) { case 2: txd->tmd[0] = vmtoh32(buf[0]); /* tb addr */ txd->tmd[1] = vmtoh32(buf[1]); /* own flag, ... */ txd->tmd[2] = vmtoh32(buf[2]); /* buff, uflo, ... */ txd->tmd[3] = vmtoh32(buf[3]); /* user */ break; case 3: txd->tmd[0] = vmtoh32(buf[2]); /* tb addr */ txd->tmd[1] = vmtoh32(buf[1]); /* own flag, ... */ txd->tmd[2] = vmtoh32(buf[0]); /* buff, uflo, ... */ txd->tmd[3] = vmtoh32(buf[3]); /* user */ break; default: AM79C971_LOG(d,"invalid software style %u!\n",sw_style); return(-1); } return(0);}/* Set the address of the next TX descriptor */static inline void txdesc_set_next(struct am79c971_data *d){ d->tx_pos++; if (d->tx_pos == d->tx_len) d->tx_pos = 0;}/* Compute the address of the current TX descriptor */static inline m_uint32_t txdesc_get_current(struct am79c971_data *d){ return(d->tx_start + (d->tx_pos * sizeof(struct tx_desc)));}/* Handle the TX ring (single packet) */static int am79c971_handle_txring_single(struct am79c971_data *d){ u_char pkt[AM79C971_MAX_PKT_SIZE],*pkt_ptr; struct tx_desc txd0,ctxd,ntxd,*ptxd; m_uint32_t tx_start,tx_current; m_uint32_t clen,tot_len; if ((d->tx_start == 0) || !(d->csr[0] & AM79C971_CSR0_TXON)) return(FALSE); /* Copy the current txring descriptor */ tx_start = tx_current = txdesc_get_current(d); ptxd = &txd0; txdesc_read(d,tx_start,ptxd); /* If we don't own the first descriptor, we cannot transmit */ if (!(ptxd->tmd[1] & AM79C971_TMD1_OWN)) return(FALSE); #if DEBUG_TRANSMIT AM79C971_LOG(d,"am79c971_handle_txring: 1st desc: " "tmd[0]=0x%x, tmd[1]=0x%x, tmd[2]=0x%x, tmd[3]=0x%x\n", ptxd->tmd[0],ptxd->tmd[1],ptxd->tmd[2],ptxd->tmd[3]);#endif /* Empty packet for now */ pkt_ptr = pkt; tot_len = 0; for(;;) {#if DEBUG_TRANSMIT AM79C971_LOG(d,"am79c971_handle_txring: loop: " "tmd[0]=0x%x, tmd[1]=0x%x, tmd[2]=0x%x, tmd[3]=0x%x\n", ptxd->tmd[0],ptxd->tmd[1],ptxd->tmd[2],ptxd->tmd[3]);#endif /* Copy packet data */ clen = ~((ptxd->tmd[1] & AM79C971_TMD1_LEN) - 1); clen &= AM79C971_TMD1_LEN; physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->tmd[0],clen); pkt_ptr += clen; tot_len += clen; /* Clear the OWN bit if this is not the first descriptor */ if (!(ptxd->tmd[1] & AM79C971_TMD1_STP)) { ptxd->tmd[1] &= ~AM79C971_TMD1_OWN; physmem_copy_u32_to_vm(d->vm,tx_current+4,ptxd->tmd[1]); } /* Set the next descriptor */ txdesc_set_next(d); /* Stop now if end of packet has been reached */ if (ptxd->tmd[1] & AM79C971_TMD1_ENP) break; /* Read the next descriptor and try to acquire it */ tx_current = txdesc_get_current(d); txdesc_read(d,tx_current,&ntxd); if (!(ntxd.tmd[1] & AM79C971_TMD1_OWN)) { AM79C971_LOG(d,"am79c971_handle_txring: UNDERFLOW!\n"); return(FALSE); } memcpy(&ctxd,&ntxd,sizeof(struct tx_desc)); ptxd = &ctxd; } if (tot_len != 0) {#if DEBUG_TRANSMIT AM79C971_LOG(d,"sending packet of %u bytes\n",tot_len); mem_dump(log_file,pkt,tot_len);#endif /* rewrite ISL header if required */ cisco_isl_rewrite(pkt,tot_len); /* send it on wire */ netio_send(d->nio,pkt,tot_len); } /* Clear the OWN flag of the first descriptor */ txd0.tmd[1] &= ~AM79C971_TMD1_OWN; physmem_copy_u32_to_vm(d->vm,tx_start+4,txd0.tmd[1]); /* Generate TX interrupt */ d->csr[0] |= AM79C971_CSR0_TINT; am79c971_update_irq_status(d); return(TRUE);}/* Handle the TX ring */static int am79c971_handle_txring(struct am79c971_data *d){ int i; AM79C971_LOCK(d); for(i=0;i<AM79C971_TXRING_PASS_COUNT;i++) if (!am79c971_handle_txring_single(d)) break; AM79C971_UNLOCK(d); return(TRUE);}/* * pci_am79c971_read() * * Read a PCI register. */static m_uint32_t pci_am79c971_read(cpu_gen_t *cpu,struct pci_device *dev, int reg){ struct am79c971_data *d = dev->priv_data;#if DEBUG_PCI_REGS AM79C971_LOG(d,"read PCI register 0x%x\n",reg);#endif switch (reg) { case 0x00: return((AM79C971_PCI_PRODUCT_ID << 16) | AM79C971_PCI_VENDOR_ID); case 0x08: return(0x02000002); case PCI_REG_BAR1: return(d->dev->phys_addr); default: return(0); }}/* * pci_am79c971_write() * * Write a PCI register. */static void pci_am79c971_write(cpu_gen_t *cpu,struct pci_device *dev, int reg,m_uint32_t value){ struct am79c971_data *d = dev->priv_data;#if DEBUG_PCI_REGS AM79C971_LOG(d,"write PCI register 0x%x, value 0x%x\n",reg,value);#endif switch(reg) { case PCI_REG_BAR1: vm_map_device(cpu->vm,d->dev,(m_uint64_t)value); AM79C971_LOG(d,"registers are mapped at 0x%x\n",value); break; }}/* * dev_am79c971_init() * * Generic AMD Am79c971 initialization code. */struct am79c971_data *dev_am79c971_init(vm_instance_t *vm,char *name,int interface_type, struct pci_bus *pci_bus,int pci_device,int irq){ struct am79c971_data *d; struct pci_device *pci_dev; struct vdevice *dev; /* Allocate the private data structure for AM79C971 */ if (!(d = malloc(sizeof(*d)))) { fprintf(stderr,"%s (AM79C971): out of memory\n",name); return NULL; } memset(d,0,sizeof(*d)); memcpy(d->mii_regs[0],mii_reg_values,sizeof(mii_reg_values)); pthread_mutex_init(&d->lock,NULL); /* Add as PCI device */ pci_dev = pci_dev_add(pci_bus,name, AM79C971_PCI_VENDOR_ID,AM79C971_PCI_PRODUCT_ID, pci_device,0,irq, d,NULL,pci_am79c971_read,pci_am79c971_write); if (!pci_dev) { fprintf(stderr,"%s (AM79C971): unable to create PCI device.\n",name); goto err_pci_dev; } /* Create the device itself */ if (!(dev = dev_create(name))) { fprintf(stderr,"%s (AM79C971): unable to create device.\n",name); goto err_dev; } d->name = name; d->vm = vm; d->type = interface_type; d->pci_dev = pci_dev; d->dev = dev; dev->phys_addr = 0; dev->phys_len = 0x4000; dev->handler = dev_am79c971_access; dev->priv_data = d; return(d); err_dev: pci_dev_remove(pci_dev); err_pci_dev: free(d); return NULL;}/* Remove an AMD Am79c971 device */void dev_am79c971_remove(struct am79c971_data *d){ if (d != NULL) { pci_dev_remove(d->pci_dev); vm_unbind_device(d->vm,d->dev); cpu_group_rebuild_mts(d->vm->cpu_group); free(d->dev); free(d); }}/* Bind a NIO to an AMD Am79c971 device */int dev_am79c971_set_nio(struct am79c971_data *d,netio_desc_t *nio){ /* check that a NIO is not already bound */ if (d->nio != NULL) return(-1); d->nio = nio; d->tx_tid = ptask_add((ptask_callback)am79c971_handle_txring,d,NULL); netio_rxl_add(nio,(netio_rx_handler_t)am79c971_handle_rxring,d,NULL); return(0);}/* Unbind a NIO from an AMD Am79c971 device */void dev_am79c971_unset_nio(struct am79c971_data *d){ if (d->nio != NULL) { ptask_remove(d->tx_tid); netio_rxl_remove(d->nio); d->nio = NULL; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -