""" Copyright 2019, The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of The Regents of the University of California. """ import datetime from collections import deque import cocotb from cocotb.log import SimLog from cocotb.queue import Queue from cocotb.triggers import Event, Edge, RisingEdge from cocotbext.axi import Window import struct MQNIC_MAX_EVENT_RINGS = 1 MQNIC_MAX_TX_RINGS = 32 MQNIC_MAX_TX_CPL_RINGS = 32 MQNIC_MAX_RX_RINGS = 8 MQNIC_MAX_RX_CPL_RINGS = 8 # Register blocks MQNIC_RB_REG_TYPE = 0x00 MQNIC_RB_REG_VER = 0x04 MQNIC_RB_REG_NEXT_PTR = 0x08 MQNIC_RB_FW_ID_TYPE = 0xFFFFFFFF MQNIC_RB_FW_ID_VER = 0x00000100 MQNIC_RB_FW_ID_REG_FPGA_ID = 0x0C MQNIC_RB_FW_ID_REG_FW_ID = 0x10 MQNIC_RB_FW_ID_REG_FW_VER = 0x14 MQNIC_RB_FW_ID_REG_BOARD_ID = 0x18 MQNIC_RB_FW_ID_REG_BOARD_VER = 0x1C MQNIC_RB_FW_ID_REG_BUILD_DATE = 0x20 MQNIC_RB_FW_ID_REG_GIT_HASH = 0x24 MQNIC_RB_FW_ID_REG_REL_INFO = 0x28 MQNIC_RB_GPIO_TYPE = 0x0000C100 MQNIC_RB_GPIO_VER = 0x00000100 MQNIC_RB_GPIO_REG_GPIO_IN = 0x0C MQNIC_RB_GPIO_REG_GPIO_OUT = 0x10 MQNIC_RB_I2C_TYPE = 0x0000C110 MQNIC_RB_I2C_VER = 0x00000100 MQNIC_RB_I2C_REG_CTRL = 0x0C MQNIC_RB_SPI_FLASH_TYPE = 0x0000C120 MQNIC_RB_SPI_FLASH_VER = 0x00000100 MQNIC_RB_SPI_FLASH_REG_FORMAT = 0x0C MQNIC_RB_SPI_FLASH_REG_CTRL_0 = 0x10 MQNIC_RB_SPI_FLASH_REG_CTRL_1 = 0x14 MQNIC_RB_BPI_FLASH_TYPE = 0x0000C121 MQNIC_RB_BPI_FLASH_VER = 0x00000100 MQNIC_RB_BPI_FLASH_REG_FORMAT = 0x0C MQNIC_RB_BPI_FLASH_REG_ADDR = 0x10 MQNIC_RB_BPI_FLASH_REG_DATA = 0x14 MQNIC_RB_BPI_FLASH_REG_CTRL = 0x18 MQNIC_RB_ALVEO_BMC_TYPE = 0x0000C140 MQNIC_RB_ALVEO_BMC_VER = 0x00000100 MQNIC_RB_ALVEO_BMC_REG_ADDR = 0x0C MQNIC_RB_ALVEO_BMC_REG_DATA = 0x10 MQNIC_RB_GECKO_BMC_TYPE = 0x0000C141 MQNIC_RB_GECKO_BMC_VER = 0x00000100 MQNIC_RB_GECKO_BMC_REG_STATUS = 0x0C MQNIC_RB_GECKO_BMC_REG_DATA = 0x10 MQNIC_RB_GECKO_BMC_REG_CMD = 0x14 MQNIC_RB_STATS_TYPE = 0x0000C004 MQNIC_RB_STATS_VER = 0x00000100 MQNIC_RB_STATS_REG_OFFSET = 0x0C MQNIC_RB_STATS_REG_COUNT = 0x10 MQNIC_RB_STATS_REG_STRIDE = 0x14 MQNIC_RB_STATS_REG_FLAGS = 0x18 MQNIC_RB_PHC_TYPE = 0x0000C080 MQNIC_RB_PHC_VER = 0x00000100 MQNIC_RB_PHC_REG_CTRL = 0x0C MQNIC_RB_PHC_REG_CUR_FNS = 0x10 MQNIC_RB_PHC_REG_CUR_NS = 0x14 MQNIC_RB_PHC_REG_CUR_SEC_L = 0x18 MQNIC_RB_PHC_REG_CUR_SEC_H = 0x1C MQNIC_RB_PHC_REG_GET_FNS = 0x20 MQNIC_RB_PHC_REG_GET_NS = 0x24 MQNIC_RB_PHC_REG_GET_SEC_L = 0x28 MQNIC_RB_PHC_REG_GET_SEC_H = 0x2C MQNIC_RB_PHC_REG_SET_FNS = 0x30 MQNIC_RB_PHC_REG_SET_NS = 0x34 MQNIC_RB_PHC_REG_SET_SEC_L = 0x38 MQNIC_RB_PHC_REG_SET_SEC_H = 0x3C MQNIC_RB_PHC_REG_PERIOD_FNS = 0x40 MQNIC_RB_PHC_REG_PERIOD_NS = 0x44 MQNIC_RB_PHC_REG_NOM_PERIOD_FNS = 0x48 MQNIC_RB_PHC_REG_NOM_PERIOD_NS = 0x4C MQNIC_RB_PHC_REG_ADJ_FNS = 0x50 MQNIC_RB_PHC_REG_ADJ_NS = 0x54 MQNIC_RB_PHC_REG_ADJ_COUNT = 0x58 MQNIC_RB_PHC_REG_ADJ_ACTIVE = 0x5C MQNIC_RB_PHC_PEROUT_TYPE = 0x0000C081 MQNIC_RB_PHC_PEROUT_VER = 0x00000100 MQNIC_RB_PHC_PEROUT_REG_CTRL = 0x0C MQNIC_RB_PHC_PEROUT_REG_START_FNS = 0x10 MQNIC_RB_PHC_PEROUT_REG_START_NS = 0x14 MQNIC_RB_PHC_PEROUT_REG_START_SEC_L = 0x18 MQNIC_RB_PHC_PEROUT_REG_START_SEC_H = 0x1C MQNIC_RB_PHC_PEROUT_REG_PERIOD_FNS = 0x20 MQNIC_RB_PHC_PEROUT_REG_PERIOD_NS = 0x24 MQNIC_RB_PHC_PEROUT_REG_PERIOD_SEC_L = 0x28 MQNIC_RB_PHC_PEROUT_REG_PERIOD_SEC_H = 0x2C MQNIC_RB_PHC_PEROUT_REG_WIDTH_FNS = 0x30 MQNIC_RB_PHC_PEROUT_REG_WIDTH_NS = 0x34 MQNIC_RB_PHC_PEROUT_REG_WIDTH_SEC_L = 0x38 MQNIC_RB_PHC_PEROUT_REG_WIDTH_SEC_H = 0x3C MQNIC_RB_IF_TYPE = 0x0000C000 MQNIC_RB_IF_VER = 0x00000100 MQNIC_RB_IF_REG_OFFSET = 0x0C MQNIC_RB_IF_REG_COUNT = 0x10 MQNIC_RB_IF_REG_STRIDE = 0x14 MQNIC_RB_IF_REG_CSR_OFFSET = 0x18 MQNIC_RB_IF_CTRL_TYPE = 0x0000C001 MQNIC_RB_IF_CTRL_VER = 0x00000400 MQNIC_RB_IF_CTRL_REG_FEATURES = 0x0C MQNIC_RB_IF_CTRL_REG_PORT_COUNT = 0x10 MQNIC_RB_IF_CTRL_REG_SCHED_COUNT = 0x14 MQNIC_RB_IF_CTRL_REG_MAX_TX_MTU = 0x20 MQNIC_RB_IF_CTRL_REG_MAX_RX_MTU = 0x24 MQNIC_RB_IF_CTRL_REG_TX_MTU = 0x28 MQNIC_RB_IF_CTRL_REG_RX_MTU = 0x2C MQNIC_IF_FEATURE_RSS = (1 << 0) MQNIC_IF_FEATURE_PTP_TS = (1 << 4) MQNIC_IF_FEATURE_TX_CSUM = (1 << 8) MQNIC_IF_FEATURE_RX_CSUM = (1 << 9) MQNIC_IF_FEATURE_RX_HASH = (1 << 10) MQNIC_RB_RX_QUEUE_MAP_TYPE = 0x0000C090 MQNIC_RB_RX_QUEUE_MAP_VER = 0x00000100 MQNIC_RB_RX_QUEUE_MAP_REG_PORTS = 0x0C MQNIC_RB_RX_QUEUE_MAP_CH_OFFSET = 0x10 MQNIC_RB_RX_QUEUE_MAP_CH_STRIDE = 0x10 MQNIC_RB_RX_QUEUE_MAP_CH_REG_OFFSET = 0x00 MQNIC_RB_RX_QUEUE_MAP_CH_REG_RSS_MASK = 0x04 MQNIC_RB_RX_QUEUE_MAP_CH_REG_APP_MASK = 0x08 MQNIC_RB_EVENT_QM_TYPE = 0x0000C010 MQNIC_RB_EVENT_QM_VER = 0x00000100 MQNIC_RB_EVENT_QM_REG_OFFSET = 0x0C MQNIC_RB_EVENT_QM_REG_COUNT = 0x10 MQNIC_RB_EVENT_QM_REG_STRIDE = 0x14 MQNIC_RB_TX_QM_TYPE = 0x0000C020 MQNIC_RB_TX_QM_VER = 0x00000100 MQNIC_RB_TX_QM_REG_OFFSET = 0x0C MQNIC_RB_TX_QM_REG_COUNT = 0x10 MQNIC_RB_TX_QM_REG_STRIDE = 0x14 MQNIC_RB_TX_CQM_TYPE = 0x0000C030 MQNIC_RB_TX_CQM_VER = 0x00000100 MQNIC_RB_TX_CQM_REG_OFFSET = 0x0C MQNIC_RB_TX_CQM_REG_COUNT = 0x10 MQNIC_RB_TX_CQM_REG_STRIDE = 0x14 MQNIC_RB_RX_QM_TYPE = 0x0000C021 MQNIC_RB_RX_QM_VER = 0x00000100 MQNIC_RB_RX_QM_REG_OFFSET = 0x0C MQNIC_RB_RX_QM_REG_COUNT = 0x10 MQNIC_RB_RX_QM_REG_STRIDE = 0x14 MQNIC_RB_RX_CQM_TYPE = 0x0000C031 MQNIC_RB_RX_CQM_VER = 0x00000100 MQNIC_RB_RX_CQM_REG_OFFSET = 0x0C MQNIC_RB_RX_CQM_REG_COUNT = 0x10 MQNIC_RB_RX_CQM_REG_STRIDE = 0x14 MQNIC_RB_PORT_TYPE = 0x0000C002 MQNIC_RB_PORT_VER = 0x00000200 MQNIC_RB_PORT_REG_OFFSET = 0x0C MQNIC_RB_PORT_CTRL_TYPE = 0x0000C003 MQNIC_RB_PORT_CTRL_VER = 0x00000200 MQNIC_RB_PORT_CTRL_REG_FEATURES = 0x0C MQNIC_RB_PORT_CTRL_REG_TX_STATUS = 0x10 MQNIC_RB_PORT_CTRL_REG_RX_STATUS = 0x14 MQNIC_RB_SCHED_BLOCK_TYPE = 0x0000C004 MQNIC_RB_SCHED_BLOCK_VER = 0x00000300 MQNIC_RB_SCHED_BLOCK_REG_OFFSET = 0x0C MQNIC_RB_SCHED_RR_TYPE = 0x0000C040 MQNIC_RB_SCHED_RR_VER = 0x00000100 MQNIC_RB_SCHED_RR_REG_OFFSET = 0x0C MQNIC_RB_SCHED_RR_REG_CH_COUNT = 0x10 MQNIC_RB_SCHED_RR_REG_CH_STRIDE = 0x14 MQNIC_RB_SCHED_RR_REG_CTRL = 0x18 MQNIC_RB_SCHED_RR_REG_DEST = 0x1C MQNIC_RB_SCHED_CTRL_TDMA_TYPE = 0x0000C050 MQNIC_RB_SCHED_CTRL_TDMA_VER = 0x00000100 MQNIC_RB_SCHED_CTRL_TDMA_REG_OFFSET = 0x0C MQNIC_RB_SCHED_CTRL_TDMA_REG_CH_COUNT = 0x10 MQNIC_RB_SCHED_CTRL_TDMA_REG_CH_STRIDE = 0x14 MQNIC_RB_SCHED_CTRL_TDMA_REG_CTRL = 0x18 MQNIC_RB_SCHED_CTRL_TDMA_REG_TS_COUNT = 0x1C MQNIC_RB_TDMA_SCH_TYPE = 0x0000C060 MQNIC_RB_TDMA_SCH_VER = 0x00000100 MQNIC_RB_TDMA_SCH_REG_TS_COUNT = 0x0C MQNIC_RB_TDMA_SCH_REG_CTRL = 0x10 MQNIC_RB_TDMA_SCH_REG_STATUS = 0x14 MQNIC_RB_TDMA_SCH_REG_SCH_START_FNS = 0x20 MQNIC_RB_TDMA_SCH_REG_SCH_START_NS = 0x24 MQNIC_RB_TDMA_SCH_REG_SCH_START_SEC_L = 0x28 MQNIC_RB_TDMA_SCH_REG_SCH_START_SEC_H = 0x2C MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_FNS = 0x30 MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_NS = 0x34 MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_SEC_L = 0x38 MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_SEC_H = 0x3C MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_FNS = 0x40 MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_NS = 0x44 MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_SEC_L = 0x48 MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_SEC_H = 0x4C MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_FNS = 0x50 MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_NS = 0x54 MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_SEC_L = 0x58 MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_SEC_H = 0x5C MQNIC_RB_APP_INFO_TYPE = 0x0000C005 MQNIC_RB_APP_INFO_VER = 0x00000200 MQNIC_RB_APP_INFO_REG_ID = 0x0C MQNIC_QUEUE_BASE_ADDR_REG = 0x00 MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG = 0x08 MQNIC_QUEUE_CPL_QUEUE_INDEX_REG = 0x0C MQNIC_QUEUE_HEAD_PTR_REG = 0x10 MQNIC_QUEUE_TAIL_PTR_REG = 0x18 MQNIC_QUEUE_ACTIVE_MASK = 0x80000000 MQNIC_CPL_QUEUE_BASE_ADDR_REG = 0x00 MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG = 0x08 MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG = 0x0C MQNIC_CPL_QUEUE_HEAD_PTR_REG = 0x10 MQNIC_CPL_QUEUE_TAIL_PTR_REG = 0x18 MQNIC_CPL_QUEUE_ACTIVE_MASK = 0x80000000 MQNIC_CPL_QUEUE_ARM_MASK = 0x80000000 MQNIC_CPL_QUEUE_CONT_MASK = 0x40000000 MQNIC_EVENT_QUEUE_BASE_ADDR_REG = 0x00 MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG = 0x08 MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG = 0x0C MQNIC_EVENT_QUEUE_HEAD_PTR_REG = 0x10 MQNIC_EVENT_QUEUE_TAIL_PTR_REG = 0x18 MQNIC_EVENT_QUEUE_ACTIVE_MASK = 0x80000000 MQNIC_EVENT_QUEUE_ARM_MASK = 0x80000000 MQNIC_EVENT_QUEUE_CONT_MASK = 0x40000000 MQNIC_EVENT_TYPE_TX_CPL = 0x0000 MQNIC_EVENT_TYPE_RX_CPL = 0x0001 MQNIC_DESC_SIZE = 16 MQNIC_CPL_SIZE = 32 MQNIC_EVENT_SIZE = 32 class RegBlock(Window): def __init__(self, parent, offset, size, base=0, **kwargs): super().__init__(parent, offset, size, base, **kwargs) self._offset = offset self.type = 0 self.version = 0 class RegBlockList: def __init__(self): self.blocks = [] async def enumerate_reg_blocks(self, window, offset=0): while True: rb_type = await window.read_dword(offset+MQNIC_RB_REG_TYPE) rb_version = await window.read_dword(offset+MQNIC_RB_REG_VER) rb = window.create_window(offset, window_type=RegBlock) rb.type = rb_type rb.version = rb_version print(f"Block ID {rb_type:#010x} version {rb_version:#010x} at offset {offset:#010x}") self.blocks.append(rb) offset = await window.read_dword(offset+MQNIC_RB_REG_NEXT_PTR) if offset == 0: return assert offset & 0x3 == 0, "Register block not aligned" for block in self.blocks: assert block.offset != offset, "Register blocks form a loop" def find(self, rb_type, version=None, index=0): for block in self.blocks: if block.type == rb_type and (not version or block.version == version): if index <= 0: return block else: index -= 1 return None def __getitem__(self, key): return self.blocks[key] def __len__(self): return len(self.blocks) class Packet: def __init__(self, data=b''): self.data = data self.queue = None self.timestamp_s = None self.timestamp_ns = None self.rx_checksum = None def __repr__(self): return ( f'{type(self).__name__}(data={self.data}, ' f'queue={self.queue}, ' f'timestamp_s={self.timestamp_s}, ' f'timestamp_ns={self.timestamp_ns}, ' f'rx_checksum={self.rx_checksum:#06x})' ) def __iter__(self): return self.data.__iter__() def __len__(self): return len(self.data) def __bytes__(self): return bytes(self.data) class EqRing: def __init__(self, interface, size, stride, index, hw_regs): self.interface = interface self.log = interface.log self.driver = interface.driver self.log_size = size.bit_length() - 1 self.size = 2**self.log_size self.size_mask = self.size-1 self.stride = stride self.index = index self.interrupt_index = 0 self.head_ptr = 0 self.tail_ptr = 0 self.hw_ptr_mask = 0xffff self.hw_regs = hw_regs async def init(self): self.log.info("Init EqRing %d (interface %d)", self.index, self.interface.index) self.buf_size = self.size*self.stride self.buf_region = self.driver.pool.alloc_region(self.buf_size) self.buf_dma = self.buf_region.get_absolute_address(0) self.buf = self.buf_region.mem await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG, 0) # interrupt index await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size async def activate(self, int_index): self.log.info("Activate EqRing %d (interface %d)", self.index, self.interface.index) self.interrupt_index = int_index await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG, int_index) # interrupt index await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size | MQNIC_EVENT_QUEUE_ACTIVE_MASK) # active, log size async def deactivate(self): await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG, self.interrupt_index) # interrupt index def empty(self): return self.head_ptr == self.tail_ptr def full(self): return self.head_ptr - self.tail_ptr >= self.size async def read_head_ptr(self): val = await self.hw_regs.read_dword(MQNIC_EVENT_QUEUE_HEAD_PTR_REG) self.head_ptr += (val - self.head_ptr) & self.hw_ptr_mask async def write_tail_ptr(self): await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) async def arm(self): await self.hw_regs.write_dword(MQNIC_EVENT_QUEUE_INTERRUPT_INDEX_REG, self.interrupt_index | MQNIC_EVENT_QUEUE_ARM_MASK) # interrupt index async def process(self): if not self.interface.port_up: return self.log.info("Process event queue") await self.read_head_ptr() eq_tail_ptr = self.tail_ptr eq_index = eq_tail_ptr & self.size_mask self.log.info("%d events in queue", self.head_ptr - eq_tail_ptr) while (self.head_ptr != eq_tail_ptr): event_data = struct.unpack_from("> 32) # base address await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG, 0) # event index await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size async def activate(self, int_index): self.log.info("Activate CqRing %d (interface %d)", self.index, self.interface.index) self.interrupt_index = int_index await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG, int_index) # event index await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size | MQNIC_CPL_QUEUE_ACTIVE_MASK) # active, log size async def deactivate(self): await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_size) # active, log size await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG, self.interrupt_index) # event index def empty(self): return self.head_ptr == self.tail_ptr def full(self): return self.head_ptr - self.tail_ptr >= self.size async def read_head_ptr(self): val = await self.hw_regs.read_dword(MQNIC_CPL_QUEUE_HEAD_PTR_REG) self.head_ptr += (val - self.head_ptr) & self.hw_ptr_mask async def write_tail_ptr(self): await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) async def arm(self): await self.hw_regs.write_dword(MQNIC_CPL_QUEUE_INTERRUPT_INDEX_REG, self.interrupt_index | MQNIC_CPL_QUEUE_ARM_MASK) # event index class TxRing: def __init__(self, interface, size, stride, index, hw_regs): self.interface = interface self.log = interface.log self.driver = interface.driver self.log_queue_size = size.bit_length() - 1 self.log_desc_block_size = int(stride/MQNIC_DESC_SIZE).bit_length() - 1 self.desc_block_size = 2**self.log_desc_block_size self.size = 2**self.log_queue_size self.size_mask = self.size-1 self.full_size = self.size >> 1 self.stride = stride self.index = index self.cpl_index = 0 self.head_ptr = 0 self.tail_ptr = 0 self.clean_tail_ptr = 0 self.clean_event = Event() self.packets = 0 self.bytes = 0 self.hw_ptr_mask = 0xffff self.hw_regs = hw_regs async def init(self): self.log.info("Init TxRing %d (interface %d)", self.index, self.interface.index) self.tx_info = [None]*self.size self.buf_size = self.size*self.stride self.buf_region = self.driver.pool.alloc_region(self.buf_size) self.buf_dma = self.buf_region.get_absolute_address(0) self.buf = self.buf_region.mem await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size await self.hw_regs.write_dword(MQNIC_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address await self.hw_regs.write_dword(MQNIC_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address await self.hw_regs.write_dword(MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, 0) # completion queue index await self.hw_regs.write_dword(MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer await self.hw_regs.write_dword(MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size async def activate(self, cpl_index): self.log.info("Activate TxRing %d (interface %d)", self.index, self.interface.index) self.cpl_index = cpl_index await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size await self.hw_regs.write_dword(MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, cpl_index) # completion queue index await self.hw_regs.write_dword(MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer await self.hw_regs.write_dword(MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8) | MQNIC_QUEUE_ACTIVE_MASK) # active, log desc block size, log queue size async def deactivate(self): await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size def empty(self): return self.head_ptr == self.clean_tail_ptr def full(self): return self.head_ptr - self.clean_tail_ptr >= self.full_size async def read_tail_ptr(self): val = await self.hw_regs.read_dword(MQNIC_QUEUE_TAIL_PTR_REG) self.tail_ptr += (val - self.tail_ptr) & self.hw_ptr_mask async def write_head_ptr(self): await self.hw_regs.write_dword(MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) def free_desc(self, index): pkt = self.tx_info[index] self.driver.free_pkt(pkt) self.tx_info[index] = None def free_buf(self): while not self.empty(): index = self.clean_tail_ptr & self.size_mask self.free_desc(index) self.clean_tail_ptr += 1 class RxRing: def __init__(self, interface, size, stride, index, hw_regs): self.interface = interface self.log = interface.log self.driver = interface.driver self.log_queue_size = size.bit_length() - 1 self.log_desc_block_size = int(stride/MQNIC_DESC_SIZE).bit_length() - 1 self.desc_block_size = 2**self.log_desc_block_size self.size = 2**self.log_queue_size self.size_mask = self.size-1 self.full_size = self.size >> 1 self.stride = stride self.index = index self.cpl_index = 0 self.head_ptr = 0 self.tail_ptr = 0 self.clean_tail_ptr = 0 self.packets = 0 self.bytes = 0 self.hw_ptr_mask = 0xffff self.hw_regs = hw_regs async def init(self): self.log.info("Init RxRing %d (interface %d)", self.index, self.interface.index) self.rx_info = [None]*self.size self.buf_size = self.size*self.stride self.buf_region = self.driver.pool.alloc_region(self.buf_size) self.buf_dma = self.buf_region.get_absolute_address(0) self.buf = self.buf_region.mem await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size await self.hw_regs.write_dword(MQNIC_QUEUE_BASE_ADDR_REG, self.buf_dma & 0xffffffff) # base address await self.hw_regs.write_dword(MQNIC_QUEUE_BASE_ADDR_REG+4, self.buf_dma >> 32) # base address await self.hw_regs.write_dword(MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, 0) # completion queue index await self.hw_regs.write_dword(MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer await self.hw_regs.write_dword(MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size async def activate(self, cpl_index): self.log.info("Activate RxRing %d (interface %d)", self.index, self.interface.index) self.cpl_index = cpl_index await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, 0) # active, log size await self.hw_regs.write_dword(MQNIC_QUEUE_CPL_QUEUE_INDEX_REG, cpl_index) # completion queue index await self.hw_regs.write_dword(MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) # head pointer await self.hw_regs.write_dword(MQNIC_QUEUE_TAIL_PTR_REG, self.tail_ptr & self.hw_ptr_mask) # tail pointer await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8) | MQNIC_QUEUE_ACTIVE_MASK) # active, log desc block size, log queue size await self.refill_buffers() async def deactivate(self): await self.hw_regs.write_dword(MQNIC_QUEUE_ACTIVE_LOG_SIZE_REG, self.log_queue_size | (self.log_desc_block_size << 8)) # active, log desc block size, log queue size def empty(self): return self.head_ptr == self.clean_tail_ptr def full(self): return self.head_ptr - self.clean_tail_ptr >= self.full_size async def read_tail_ptr(self): val = await self.hw_regs.read_dword(MQNIC_QUEUE_TAIL_PTR_REG) self.tail_ptr += (val - self.tail_ptr) & self.hw_ptr_mask async def write_head_ptr(self): await self.hw_regs.write_dword(MQNIC_QUEUE_HEAD_PTR_REG, self.head_ptr & self.hw_ptr_mask) def free_desc(self, index): pkt = self.rx_info[index] self.driver.free_pkt(pkt) self.rx_info[index] = None def free_buf(self): while not self.empty(): index = self.clean_tail_ptr & self.size_mask self.free_desc(index) self.clean_tail_ptr += 1 def prepare_desc(self, index): pkt = self.driver.alloc_pkt() self.rx_info[index] = pkt length = pkt.size ptr = pkt.get_absolute_address(0) offset = 0 # write descriptors for k in range(0, self.desc_block_size): seg = min(length-offset, 4096) if k < self.desc_block_size-1 else length-offset struct.pack_into(" 1 else length-offset struct.pack_into("