📄 dev_dec21140.c
字号:
if (rxd->rdes[1] & DEC21140_RXDESC_RER) nrxd_addr = d->csr[3]; else { if (rxd->rdes[1] & DEC21140_RXDESC_RCH) nrxd_addr = rxd->rdes[3]; else nrxd_addr = rxd_addr + sizeof(struct rx_desc); } return(nrxd_addr);}/* Read a RX descriptor */static void rxdesc_read(struct dec21140_data *d,m_uint32_t rxd_addr, struct rx_desc *rxd){ /* get the next descriptor from VM physical RAM */ physmem_copy_from_vm(d->vm,rxd,rxd_addr,sizeof(struct rx_desc)); /* byte-swapping */ rxd->rdes[0] = vmtoh32(rxd->rdes[0]); rxd->rdes[1] = vmtoh32(rxd->rdes[1]); rxd->rdes[2] = vmtoh32(rxd->rdes[2]); rxd->rdes[3] = vmtoh32(rxd->rdes[3]);}/* * Try to acquire the specified RX descriptor. Returns TRUE if we have it. * It assumes that the byte-swapping is done. */static inline int rxdesc_acquire(m_uint32_t rdes0){ return(rdes0 & DEC21140_RXDESC_OWN);}/* Put a packet in buffer(s) of a descriptor */static void rxdesc_put_pkt(struct dec21140_data *d,struct rx_desc *rxd, u_char **pkt,ssize_t *pkt_len){ ssize_t len1,len2,cp_len; /* get rbs1 and rbs2 */ len1 = rxd->rdes[1] & DEC21140_RXDESC_LEN_MASK; len2 = (rxd->rdes[1] >> 10) & DEC21140_RXDESC_LEN_MASK; /* try with buffer #1 */ if (len1 != 0) { /* compute the data length to copy */ cp_len = m_min(len1,*pkt_len); /* copy packet data to the VM physical RAM */ physmem_copy_to_vm(d->vm,*pkt,rxd->rdes[2],cp_len); *pkt += cp_len; *pkt_len -= cp_len; } /* try with buffer #2 */ if ((len2 != 0) && !(rxd->rdes[1] & DEC21140_RXDESC_RCH)) { /* compute the data length to copy */ cp_len = m_min(len2,*pkt_len); /* copy packet data to the VM physical RAM */ physmem_copy_to_vm(d->vm,*pkt,rxd->rdes[3],cp_len); *pkt += cp_len; *pkt_len -= cp_len; }}/* * Put a packet in the RX ring of the DEC21140. */static int dev_dec21140_receive_pkt(struct dec21140_data *d, u_char *pkt,ssize_t pkt_len){ m_uint32_t rx_start,rxdn_addr,rxdn_rdes0; struct rx_desc rxd0,rxdn,*rxdc; ssize_t tot_len = pkt_len; u_char *pkt_ptr = pkt; n_eth_hdr_t *hdr; int i; /* Truncate the packet if it is too big */ pkt_len = m_min(pkt_len,DEC21140_MAX_PKT_SIZE); /* Copy the current rxring descriptor */ rxdesc_read(d,d->rx_current,&rxd0); /* We must have the first descriptor... */ if (!rxdesc_acquire(rxd0.rdes[0])) return(FALSE); /* Remember the first RX descriptor address */ rx_start = d->rx_current; for(i=0,rxdc=&rxd0;tot_len>0;i++) { /* Put data into the descriptor buffers */ rxdesc_put_pkt(d,rxdc,&pkt_ptr,&tot_len); /* Get address of the next descriptor */ rxdn_addr = rxdesc_get_next(d,d->rx_current,rxdc); /* We have finished if the complete packet has been stored */ if (tot_len == 0) { rxdc->rdes[0] = DEC21140_RXDESC_LS; rxdc->rdes[0] |= (pkt_len + 4) << DEC21140_RXDESC_FL_SHIFT; /* if this is a multicast frame, set the appropriate bit */ hdr = (n_eth_hdr_t *)pkt; if (eth_addr_is_mcast(&hdr->daddr)) rxdc->rdes[0] |= DEC21140_RXDESC_MF; if (i != 0) physmem_copy_u32_to_vm(d->vm,d->rx_current,rxdc->rdes[0]); d->rx_current = rxdn_addr; break; } /* Get status of the next descriptor to see if we can acquire it */ rxdn_rdes0 = physmem_copy_u32_from_vm(d->vm,rxdn_addr); if (!rxdesc_acquire(rxdn_rdes0)) rxdc->rdes[0] = DEC21140_RXDESC_LS | DEC21140_RXDESC_DE; else rxdc->rdes[0] = 0; /* ok, no special flag */ /* Update the new status (only if we are not on the first desc) */ if (i != 0) physmem_copy_u32_to_vm(d->vm,d->rx_current,rxdc->rdes[0]); /* Update the RX pointer */ d->rx_current = rxdn_addr; if (rxdc->rdes[0] != 0) break; /* Read the next descriptor from VM physical RAM */ rxdesc_read(d,rxdn_addr,&rxdn); rxdc = &rxdn; } /* Update the first RX descriptor */ rxd0.rdes[0] |= DEC21140_RXDESC_FS; physmem_copy_u32_to_vm(d->vm,rx_start,rxd0.rdes[0]); /* 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); return(TRUE);}/* Handle the DEC21140 RX ring */static int dev_dec21140_handle_rxring(netio_desc_t *nio, u_char *pkt,ssize_t pkt_len, struct dec21140_data *d){ /* * Don't start receive if the RX ring address has not been set * and if the SR bit in CSR6 is not set yet. */ if ((d->csr[3] == 0) || !(d->csr[6] & DEC21140_CSR6_START_RX)) return(FALSE);#if DEBUG_RECEIVE DEC21140_LOG(d,"receiving a packet of %d bytes\n",pkt_len); mem_dump(log_file,pkt,pkt_len);#endif /* * Receive only multicast/broadcast trafic + unicast traffic * for this virtual machine. */ if (dec21140_handle_mac_addr(d,pkt)) return(dev_dec21140_receive_pkt(d,pkt,pkt_len)); return(FALSE);}/* Read a TX descriptor */static void txdesc_read(struct dec21140_data *d,m_uint32_t txd_addr, struct tx_desc *txd){ /* get the descriptor from VM physical RAM */ physmem_copy_from_vm(d->vm,txd,txd_addr,sizeof(struct tx_desc)); /* byte-swapping */ txd->tdes[0] = vmtoh32(txd->tdes[0]); txd->tdes[1] = vmtoh32(txd->tdes[1]); txd->tdes[2] = vmtoh32(txd->tdes[2]); txd->tdes[3] = vmtoh32(txd->tdes[3]);}/* Set the address of the next TX descriptor */static void txdesc_set_next(struct dec21140_data *d,struct tx_desc *txd){ if (txd->tdes[1] & DEC21140_TXDESC_TER) d->tx_current = d->csr[4]; else { if (txd->tdes[1] & DEC21140_TXDESC_TCH) d->tx_current = txd->tdes[3]; else d->tx_current += sizeof(struct tx_desc); }}/* Handle the TX ring (single packet) */static int dev_dec21140_handle_txring_single(struct dec21140_data *d){ u_char pkt[DEC21140_MAX_PKT_SIZE],*pkt_ptr; u_char setup_frame[DEC21140_SETUP_FRAME_SIZE]; m_uint32_t tx_start,len1,len2,clen,tot_len; struct tx_desc txd0,ctxd,*ptxd; int done = FALSE; /* * Don't start transmit if the txring address has not been set * and if the ST bit in CSR6 is not set yet. */ if ((d->csr[4] == 0) || (!(d->csr[6] & DEC21140_CSR6_START_TX))) return(FALSE); /* Copy the current txring descriptor */ tx_start = d->tx_current; ptxd = &txd0; txdesc_read(d,tx_start,ptxd); /* If we don't own the first descriptor, we cannot transmit */ if (!(txd0.tdes[0] & DEC21140_TXDESC_OWN)) return(FALSE); /* * Ignore setup frames (clear the own bit and skip). * We extract unicast MAC addresses to allow only appropriate traffic * to pass. */ if (!(txd0.tdes[1] & (DEC21140_TXDESC_FS|DEC21140_TXDESC_LS))) { len1 = ptxd->tdes[1] & DEC21140_TXDESC_LEN_MASK; len2 = (ptxd->tdes[1] >> 11) & DEC21140_TXDESC_LEN_MASK; if (txd0.tdes[1] & DEC21140_TXDESC_SET) { physmem_copy_from_vm(d->vm,setup_frame,ptxd->tdes[2], sizeof(setup_frame)); dec21140_update_mac_addr(d,setup_frame); } txdesc_set_next(d,ptxd); goto clear_txd0_own_bit; }#if DEBUG_TRANSMIT DEC21140_LOG(d,"dec21140_handle_txring: 1st desc: " "tdes[0]=0x%x, tdes[1]=0x%x, tdes[2]=0x%x, tdes[3]=0x%x\n", ptxd->tdes[0],ptxd->tdes[1],ptxd->tdes[2],ptxd->tdes[3]);#endif /* Empty packet for now */ pkt_ptr = pkt; tot_len = 0; do {#if DEBUG_TRANSMIT DEC21140_LOG(d,"dec21140_handle_txring: loop: " "tdes[0]=0x%x, tdes[1]=0x%x, tdes[2]=0x%x, tdes[3]=0x%x\n", ptxd->tdes[0],ptxd->tdes[1],ptxd->tdes[2],ptxd->tdes[3]);#endif if (!(ptxd->tdes[0] & DEC21140_TXDESC_OWN)) { DEC21140_LOG(d,"dec21140_handle_txring: descriptor not owned!\n"); return(FALSE); } len1 = ptxd->tdes[1] & DEC21140_TXDESC_LEN_MASK; len2 = (ptxd->tdes[1] >> 11) & DEC21140_TXDESC_LEN_MASK; clen = len1 + len2; /* Be sure that we have either len1 or len2 not null */ if (clen != 0) { if (len1 != 0) physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->tdes[2],len1); if ((len2 != 0) && !(ptxd->tdes[1] & DEC21140_TXDESC_TCH)) physmem_copy_from_vm(d->vm,pkt_ptr+len1,ptxd->tdes[3],len2); } pkt_ptr += clen; tot_len += clen; /* Clear the OWN bit if this is not the first descriptor */ if (!(ptxd->tdes[1] & DEC21140_TXDESC_FS)) physmem_copy_u32_to_vm(d->vm,d->tx_current,0); /* Go to the next descriptor */ txdesc_set_next(d,ptxd); /* * Copy the next txring descriptor (ignore setup frames that * have both FS and LS bit cleared). */ if (!(ptxd->tdes[1] & (DEC21140_TXDESC_LS|DEC21140_TXDESC_SET))) { txdesc_read(d,d->tx_current,&ctxd); ptxd = &ctxd; } else done = TRUE; }while(!done); if (tot_len != 0) {#if DEBUG_TRANSMIT DEC21140_LOG(d,"sending packet of %u bytes\n",tot_len); mem_dump(log_file,pkt,tot_len);#endif /* rewrite ISL header if required */ dec21140_isl_rewrite(pkt,tot_len); /* send it on wire */ netio_send(d->nio,pkt,tot_len); } 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)) { d->csr[5] |= DEC21140_CSR5_TI; pci_dev_trigger_irq(d->vm,d->pci_dev); } return(TRUE);}/* Handle the TX ring */static int dev_dec21140_handle_txring(struct dec21140_data *d){ int i; for(i=0;i<DEC21140_TXRING_PASS_COUNT;i++) if (!dev_dec21140_handle_txring_single(d)) break; return(TRUE);}/* * pci_dec21140_read() * * Read a PCI register. */static m_uint32_t pci_dec21140_read(cpu_mips_t *cpu,struct pci_device *dev, int reg){ struct dec21140_data *d = dev->priv_data;#if DEBUG_PCI_REGS DEC21140_LOG(d,"read C%s(%u)\n",pci_cfgreg_name(reg),reg);#endif switch (reg) { case DEC21140_PCI_CFID_REG_OFFSET: return(0x00091011); case DEC21140_PCI_CFRV_REG_OFFSET: return(0x02000011); case DEC21140_PCI_CBMA_REG_OFFSET: return(d->dev->phys_addr); default: return(0); }}/* * pci_dec21140_write() * * Write a PCI register. */static void pci_dec21140_write(cpu_mips_t *cpu,struct pci_device *dev, int reg,m_uint32_t value){ struct dec21140_data *d = dev->priv_data;#if DEBUG_PCI_REGS DEC21140_LOG(d,"write C%s(%u) value 0x%x\n",pci_cfgreg_name(reg),reg,value);#endif switch(reg) { case DEC21140_PCI_CBMA_REG_OFFSET: vm_map_device(cpu->vm,d->dev,(m_uint64_t)value); DEC21140_LOG(d,"registers are mapped at 0x%x\n",value); break; }}/* * dev_dec21140_init() * * Generic DEC21140 initialization code. */struct dec21140_data *dev_dec21140_init(vm_instance_t *vm,char *name, struct pci_bus *pci_bus,int pci_device, int irq){ struct dec21140_data *d; struct pci_device *pci_dev; struct vdevice *dev; /* Allocate the private data structure for DEC21140 */ if (!(d = malloc(sizeof(*d)))) { fprintf(stderr,"%s (DEC21140): out of memory\n",name); return NULL; } memset(d,0,sizeof(*d)); /* Add as PCI device */ pci_dev = pci_dev_add(pci_bus,name, DEC21140_PCI_VENDOR_ID,DEC21140_PCI_PRODUCT_ID, pci_device,0,irq, d,NULL,pci_dec21140_read,pci_dec21140_write); if (!pci_dev) { fprintf(stderr,"%s (DEC21140): unable to create PCI device.\n",name); goto err_pci_dev; } /* Create the device itself */ if (!(dev = dev_create(name))) { fprintf(stderr,"%s (DEC21140): unable to create device.\n",name); goto err_dev; } d->name = name; d->vm = vm; d->pci_dev = pci_dev; d->dev = dev; /* Basic register setup */ d->csr[0] = 0xfff80000; d->csr[5] = 0xfc000000; d->csr[8] = 0xfffe0000; dev->phys_addr = 0; dev->phys_len = 0x20000; dev->handler = dev_dec21140_access; dev->priv_data = d; return(d); err_dev: pci_dev_remove(pci_dev); err_pci_dev: free(d); return NULL;}/* Remove a DEC21140 device */void dev_dec21140_remove(struct dec21140_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 DEC21140 device */int dev_dec21140_set_nio(struct dec21140_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)dev_dec21140_handle_txring,d,NULL); netio_rxl_add(nio,(netio_rx_handler_t)dev_dec21140_handle_rxring,d,NULL); return(0);}/* Unbind a NIO from a DEC21140 device */void dev_dec21140_unset_nio(struct dec21140_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 + -