//Section 4.6.8 private void InitTx() { //CRC offload and small packet padding SetFlags(IxgbeDefs.HLREG0, IxgbeDefs.HLREG0_TXCRCEN | IxgbeDefs.HLREG0_TXPADEN); //Set default buffer size allocations (section 4.6.11.3.4) SetReg(IxgbeDefs.TXPBSIZE(0), IxgbeDefs.TXPBSIZE_40KB); for (uint i = 1; i < 8; i++) { SetReg(IxgbeDefs.TXPBSIZE(i), 0); } //Required when not using DCB/VTd SetReg(IxgbeDefs.DTXMXSZRQ, 0xFFFF); ClearFlags(IxgbeDefs.RTTDCS, IxgbeDefs.RTTDCS_ARBDIS); //Per queue config for all queues for (uint i = 0; i < TxQueues.Length; i++) { Log.Notice("Initializing TX queue {0}", i); //Section 7.1.9 - Setup descriptor ring uint ringSizeBytes = NumTxQueueEntries * TxDescriptorSize; var dmaMem = MemoryHelper.AllocateDmaC(ringSizeBytes, true); //TODO : The C version sets the allocated memory to -1 here SetReg(IxgbeDefs.TDBAL(i), (uint)(dmaMem.PhysicalAddress & 0xFFFFFFFFL)); SetReg(IxgbeDefs.TDBAH(i), (uint)(dmaMem.PhysicalAddress >> 32)); SetReg(IxgbeDefs.TDLEN(i), (uint)ringSizeBytes); Log.Notice("TX ring {0} physical addr: {1}", i, dmaMem.PhysicalAddress); Log.Notice("TX ring {0} virtual addr: {1}", i, dmaMem.VirtualAddress); //Descriptor writeback magic values, important to get good performance and low PCIe overhead //See sec. 7.2.3.4.1 and 7.2.3.5 uint txdctl = GetReg(IxgbeDefs.TXDCTL(i)); //Seems like overflow is irrelevant here unchecked { //Clear bits txdctl &= (uint)(~(0x3F | (0x3F << 8) | (0x3F << 16))); //From DPDK txdctl |= (36 | (8 << 8) | (4 << 16)); } SetReg(IxgbeDefs.TXDCTL(i), txdctl); var queue = new IxgbeTxQueue(NumTxQueueEntries); queue.Index = 0; queue.DescriptorsAddr = dmaMem.VirtualAddress; TxQueues[i] = queue; } //Enable DMA SetReg(IxgbeDefs.DMATXCTL, IxgbeDefs.DMATXCTL_TE); }
private void InitRx() { //Disable RX while re-configuring ClearFlags(IxgbeDefs.RXCTRL, IxgbeDefs.RXCTRL_RXEN); //No DCB or VT, just a single 128kb packet buffer SetReg(IxgbeDefs.RXPBSIZE(0), IxgbeDefs.RXPBSIZE_128KB); for (uint i = 1; i < 8; i++) { SetReg(IxgbeDefs.RXPBSIZE(i), 0); } //Always enable CRC offloading SetFlags(IxgbeDefs.HLREG0, IxgbeDefs.HLREG0_RXCRCSTRP); SetFlags(IxgbeDefs.RDRXCTL, IxgbeDefs.RDRXCTL_CRCSTRIP); //Accept broadcast packets SetFlags(IxgbeDefs.FCTRL, IxgbeDefs.FCTRL_BAM); //Per queue config for (uint i = 0; i < RxQueues.Length; i++) { Log.Notice("Initializing rx queue {0}", i); //Enable advanced rx descriptors SetReg(IxgbeDefs.SRRCTL(i), (GetReg(IxgbeDefs.SRRCTL(i)) & ~IxgbeDefs.SRRCTL_DESCTYPE_MASK) | IxgbeDefs.SRRCTL_DESCTYPE_ADV_ONEBUF); //DROP_EN causes the NIC to drop packets if no descriptors are available instead of buffering them //A single overflowing queue can fill up the whole buffer and impact operations if not setting this SetFlags(IxgbeDefs.SRRCTL(i), IxgbeDefs.SRRCTL_DROP_EN); //Sec 7.1.9 - Set up descriptor ring int ringSizeBytes = NumRxQueueEntries * RxDescriptorSize; var dmaMem = MemoryHelper.AllocateDmaC((uint)ringSizeBytes, true); //TODO : The C version sets the allocated memory to -1 here SetReg(IxgbeDefs.RDBAL(i), (uint)(dmaMem.PhysicalAddress & 0xFFFFFFFFL)); SetReg(IxgbeDefs.RDBAH(i), (uint)(dmaMem.PhysicalAddress >> 32)); SetReg(IxgbeDefs.RDLEN(i), (uint)ringSizeBytes); Log.Notice("RX ring {0} physical address: {1}", i, dmaMem.PhysicalAddress); Log.Notice("RX ring {0} virtual address: {1}", i, dmaMem.VirtualAddress); //Set ring to empty SetReg(IxgbeDefs.RDH(i), 0); SetReg(IxgbeDefs.RDT(i), 0); var queue = new IxgbeRxQueue(NumRxQueueEntries); queue.Index = 0; queue.DescriptorsAddr = dmaMem.VirtualAddress; RxQueues[i] = queue; } //Section 4.6.7 - set some magic bits SetFlags(IxgbeDefs.CTRL_EXT, IxgbeDefs.CTRL_EXT_NS_DIS); //This flag probably refers to a broken feature: It's reserved and initialized as '1' but it must be '0' for (uint i = 0; i < RxQueues.Length; i++) { ClearFlags(IxgbeDefs.DCA_RXCTRL(i), 1 << 12); } //Start RX SetFlags(IxgbeDefs.RXCTRL, IxgbeDefs.RXCTRL_RXEN); }