📄 dev_mueslix.c
字号:
#endif } return NULL;}/* * Get the address of the next RX descriptor. */static m_uint32_t rxdesc_get_next(struct mueslix_channel *channel, m_uint32_t rxd_addr){ m_uint32_t nrxd_addr; switch(channel->parent->chip_mode) { case 0: nrxd_addr = rxd_addr + sizeof(struct rx_desc); if (nrxd_addr == channel->rx_end) nrxd_addr = channel->rx_start; break; case 1: default: if (rxd_addr == channel->rx_end) nrxd_addr = channel->rx_start; else nrxd_addr = rxd_addr + sizeof(struct rx_desc); break; } return(nrxd_addr);}/* Read an RX descriptor */static void rxdesc_read(struct mueslix_data *d,m_uint32_t rxd_addr, struct rx_desc *rxd){#if DEBUG_RECEIVE MUESLIX_LOG(d,"reading RX descriptor at address 0x%x\n",rxd_addr);#endif /* 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]);}/* * 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 & MUESLIX_RXDESC_OWN);}/* Put a packet in buffer of a descriptor */static ssize_t rxdesc_put_pkt(struct mueslix_data *d,struct rx_desc *rxd, u_char **pkt,ssize_t *pkt_len){ ssize_t len,cp_len; len = rxd->rdes[0] & MUESLIX_RXDESC_LEN_MASK; /* compute the data length to copy */ cp_len = m_min(len,*pkt_len);#if DEBUG_RECEIVE MUESLIX_LOG(d,"copying %d bytes at 0x%x\n",cp_len,rxd->rdes[1]);#endif /* copy packet data to the VM physical RAM */ physmem_copy_to_vm(d->vm,*pkt,rxd->rdes[1],cp_len); *pkt += cp_len; *pkt_len -= cp_len; return(cp_len);}/* * Put a packet in the RX ring of the Mueslix specified channel. */static void dev_mueslix_receive_pkt(struct mueslix_channel *channel, u_char *pkt,ssize_t pkt_len){ struct mueslix_data *d = channel->parent; m_uint32_t rx_start,rxdn_addr,rxdn_rdes0; struct rx_desc rxd0,rxdn,*rxdc; ssize_t cp_len,tot_len = pkt_len; u_char *pkt_ptr = pkt; int i; if ((channel->rx_start == 0) || (channel->status == 0) || (channel->nio == NULL)) return; /* Don't make anything if RX is not enabled for this channel */ if (!(dev_mueslix_is_rx_tx_enabled(d,channel->id) & MUESLIX_RX_ENABLE)) return; /* Truncate the packet if it is too big */ pkt_len = m_min(pkt_len,MUESLIX_MAX_PKT_SIZE); /* Copy the current rxring descriptor */ rxdesc_read(d,channel->rx_current,&rxd0); /* We must have the first descriptor... */ if (!rxdesc_acquire(rxd0.rdes[0])) return; /* Remember the first RX descriptor address */ rx_start = channel->rx_current; for(i=0,rxdc=&rxd0;tot_len>0;i++) { /* Put data into the descriptor buffers */ cp_len = rxdesc_put_pkt(d,rxdc,&pkt_ptr,&tot_len); /* Get address of the next descriptor */ rxdn_addr = rxdesc_get_next(channel,channel->rx_current); /* We have finished if the complete packet has been stored */ if (tot_len == 0) { rxdc->rdes[0] = MUESLIX_RXDESC_LS; rxdc->rdes[0] |= cp_len; if (i != 0) physmem_copy_u32_to_vm(d->vm,channel->rx_current,rxdc->rdes[0]); channel->rx_current = rxdn_addr; break; }#if DEBUG_RECEIVE MUESLIX_LOG(d,"trying to acquire new descriptor at 0x%x\n",rxdn_addr);#endif /* 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] = MUESLIX_RXDESC_LS | MUESLIX_RXDESC_OVERRUN; else rxdc->rdes[0] = 0x00000000; /* ok, no special flag */ rxdc->rdes[0] |= cp_len; /* Update the new status (only if we are not on the first desc) */ if (i != 0) physmem_copy_u32_to_vm(d->vm,channel->rx_current,rxdc->rdes[0]); /* Update the RX pointer */ channel->rx_current = rxdn_addr; if (rxdc->rdes[0] & MUESLIX_RXDESC_LS) 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] |= MUESLIX_RXDESC_FS; physmem_copy_u32_to_vm(d->vm,rx_start,rxd0.rdes[0]); /* Indicate that we have a frame ready (XXX something to do ?) */ /* Generate IRQ on CPU */ channel->rx_tx_status |= MUESLIX_CHANNEL_STATUS_RX; pci_dev_trigger_irq(d->vm,d->pci_dev);}/* Handle the Mueslix RX ring of the specified channel */static int dev_mueslix_handle_rxring(netio_desc_t *nio, u_char *pkt,ssize_t pkt_len, struct mueslix_channel *channel){#if DEBUG_RECEIVE struct mueslix_data *d = channel->parent; MUESLIX_LOG(d,"channel %u: receiving a packet of %d bytes\n", channel->id,pkt_len); mem_dump(log_file,pkt,pkt_len);#endif dev_mueslix_receive_pkt(channel,pkt,pkt_len); return(TRUE);}/* Read a TX descriptor */static void txdesc_read(struct mueslix_data *d,m_uint32_t txd_addr, struct tx_desc *txd){ /* get the next 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]);}/* Set the address of the next TX descriptor */static void txdesc_set_next(struct mueslix_channel *channel){ switch(channel->parent->chip_mode) { case 0: channel->tx_current += sizeof(struct tx_desc); if (channel->tx_current == channel->tx_end) channel->tx_current = channel->tx_start; break; case 1: default: if (channel->tx_current == channel->tx_end) channel->tx_current = channel->tx_start; else channel->tx_current += sizeof(struct tx_desc); }}/* Handle the TX ring of a specific channel (single packet) */static int dev_mueslix_handle_txring_single(struct mueslix_channel *channel){ struct mueslix_data *d = channel->parent; u_char pkt[MUESLIX_MAX_PKT_SIZE],*pkt_ptr; m_uint32_t tx_start,clen,sub_len,tot_len,pad; struct tx_desc txd0,ctxd,*ptxd; int done = FALSE; if ((channel->tx_start == 0) || (channel->status == 0)) return(FALSE); /* Copy the current txring descriptor */ tx_start = channel->tx_current; ptxd = &txd0; txdesc_read(d,channel->tx_current,ptxd); /* If we don't own the descriptor, we cannot transmit */ if (!(txd0.tdes[0] & MUESLIX_TXDESC_OWN)) return(FALSE);#if DEBUG_TRANSMIT MUESLIX_LOG(d,"mueslix_handle_txring: 1st desc: " "tdes[0]=0x%x, tdes[1]=0x%x\n", ptxd->tdes[0],ptxd->tdes[1]);#endif pkt_ptr = pkt; tot_len = 0; do {#if DEBUG_TRANSMIT MUESLIX_LOG(d,"mueslix_handle_txring: loop: " "tdes[0]=0x%x, tdes[1]=0x%x\n", ptxd->tdes[0],ptxd->tdes[1]);#endif if (!(ptxd->tdes[0] & MUESLIX_TXDESC_OWN)) { MUESLIX_LOG(d,"mueslix_handle_txring: descriptor not owned!\n"); return(FALSE); } switch(channel->parent->chip_mode) { case 0: clen = ptxd->tdes[0] & MUESLIX_TXDESC_LEN_MASK; break; case 1: default: clen = (ptxd->tdes[0] & MUESLIX_TXDESC_LEN_MASK) << 2; if (ptxd->tdes[0] & MUESLIX_TXDESC_SUB) { sub_len = ptxd->tdes[0] & MUESLIX_TXDESC_SUB_LEN; sub_len >>= MUESLIX_TXDESC_SUB_SHIFT; clen -= sub_len; } } /* Be sure that we have length not null */ if (clen != 0) { //printf("pkt_ptr = %p, ptxd->tdes[1] = 0x%x, clen = %d\n", //pkt_ptr, ptxd->tdes[1], clen); physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->tdes[1],clen); } pkt_ptr += clen; tot_len += clen; /* Clear the OWN bit if this is not the first descriptor */ if (!(ptxd->tdes[0] & MUESLIX_TXDESC_FS)) physmem_copy_u32_to_vm(d->vm,channel->tx_current,0); /* Go to the next descriptor */ txdesc_set_next(channel); /* Copy the next txring descriptor */ if (!(ptxd->tdes[0] & MUESLIX_TXDESC_LS)) { txdesc_read(d,channel->tx_current,&ctxd); ptxd = &ctxd; } else done = TRUE; }while(!done); if (tot_len != 0) {#if DEBUG_TRANSMIT MUESLIX_LOG(d,"sending packet of %u bytes (flags=0x%4.4x)\n", tot_len,txd0.tdes[0]); mem_dump(log_file,pkt,tot_len);#endif pad = ptxd->tdes[0] & MUESLIX_TXDESC_PAD; pad >>= MUESLIX_TXDESC_PAD_SHIFT; tot_len += (pad - 1) & 0x03; /* send it on wire */ netio_send(channel->nio,pkt,tot_len); } /* Clear the OWN flag of the first descriptor */ physmem_copy_u32_to_vm(d->vm,tx_start,0); /* Interrupt on completion ? */ channel->rx_tx_status |= MUESLIX_CHANNEL_STATUS_TX; pci_dev_trigger_irq(d->vm,d->pci_dev); return(TRUE);}/* Handle the TX ring of a specific channel */static int dev_mueslix_handle_txring(struct mueslix_channel *channel){ int i; for(i=0;i<MUESLIX_TXRING_PASS_COUNT;i++) if (!dev_mueslix_handle_txring_single(channel)) break; return(TRUE);}/* pci_mueslix_read() */static m_uint32_t pci_mueslix_read(cpu_mips_t *cpu,struct pci_device *dev, int reg){ struct mueslix_data *d = dev->priv_data; switch(reg) { case 0x08: /* Rev ID */ return(0x2800001); case PCI_REG_BAR0: return(d->dev->phys_addr); default: return(0); }}/* pci_mueslix_write() */static void pci_mueslix_write(cpu_mips_t *cpu,struct pci_device *dev, int reg,m_uint32_t value){ struct mueslix_data *d = dev->priv_data; switch(reg) { case PCI_REG_BAR0: vm_map_device(cpu->vm,d->dev,(m_uint64_t)value); MUESLIX_LOG(d,"registers are mapped at 0x%x\n",value); break; }}/* Initialize a Mueslix chip */struct mueslix_data *dev_mueslix_init(vm_instance_t *vm,char *name,int chip_mode, struct pci_bus *pci_bus,int pci_device,int irq){ struct pci_device *pci_dev; struct mueslix_data *d; struct vdevice *dev; int i; /* Allocate the private data structure for Mueslix chip */ if (!(d = malloc(sizeof(*d)))) { fprintf(stderr,"%s (Mueslix): out of memory\n",name); return NULL; } memset(d,0,sizeof(*d)); d->chip_mode = chip_mode; for(i=0;i<MUESLIX_NR_CHANNELS;i++) d->channel[i].id = i; /* Add as PCI device */ pci_dev = pci_dev_add(pci_bus,name, MUESLIX_PCI_VENDOR_ID,MUESLIX_PCI_PRODUCT_ID, pci_device,0,irq, d,NULL,pci_mueslix_read,pci_mueslix_write); if (!pci_dev) { fprintf(stderr,"%s (Mueslix): unable to create PCI device.\n",name); return NULL; } /* Create the device itself */ if (!(dev = dev_create(name))) { fprintf(stderr,"%s (Mueslix): unable to create device.\n",name); return NULL; } d->name = name; d->pci_dev = pci_dev; d->vm = vm; dev->phys_addr = 0; dev->phys_len = 0x4000; dev->handler = dev_mueslix_access; dev->priv_data = d; /* Store device info */ dev->priv_data = d; d->dev = dev; return(d);}/* Remove a Mueslix device */void dev_mueslix_remove(struct mueslix_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 a Mueslix channel */int dev_mueslix_set_nio(struct mueslix_data *d,u_int channel_id, netio_desc_t *nio){ struct mueslix_channel *channel; if (channel_id >= MUESLIX_NR_CHANNELS) return(-1); channel = &d->channel[channel_id]; /* check that a NIO is not already bound */ if (channel->nio != NULL) return(-1); /* define the new NIO */ channel->nio = nio; channel->parent = d; channel->tx_tid = ptask_add((ptask_callback)dev_mueslix_handle_txring, channel,NULL); netio_rxl_add(nio,(netio_rx_handler_t)dev_mueslix_handle_rxring, channel,NULL); return(0);}/* Unbind a NIO from a Mueslix channel */int dev_mueslix_unset_nio(struct mueslix_data *d,u_int channel_id){ struct mueslix_channel *channel; if (channel_id >= MUESLIX_NR_CHANNELS) return(-1); channel = &d->channel[channel_id]; if (channel->nio) { ptask_remove(channel->tx_tid); netio_rxl_remove(channel->nio); channel->nio = NULL; } return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -