async def dma_mem_read(self, addr, length, timeout=0, timeout_unit='ns'): data = b'' n = 0 while True: tlp = Tlp() if addr > 0xffffffff: tlp.fmt_type = TlpType.MEM_READ_64 else: tlp.fmt_type = TlpType.MEM_READ tlp.requester_id = PcieId(self.dev_bus_num, self.dev_device_num, 0) first_pad = addr % 4 byte_length = length - n # max read request size byte_length = min(byte_length, (128 << self.dev_max_read_req) - first_pad) # 4k address align byte_length = min(byte_length, 0x1000 - (addr & 0xfff)) tlp.set_addr_be(addr, byte_length) tlp.tag = await self.alloc_tag() await self.tx_source.send(S10PcieFrame.from_tlp(tlp)) m = 0 while True: cpl = await self.recv_cpl(tlp.tag, timeout, timeout_unit) if not cpl: raise Exception("Timeout") if cpl.status != CplStatus.SC: raise Exception("Unsuccessful completion") else: assert cpl.byte_count + 3 + (cpl.lower_address & 3) >= cpl.length * 4 assert cpl.byte_count == max(byte_length - m, 1) d = cpl.get_data() offset = cpl.lower_address & 3 data += d[offset:offset + cpl.byte_count] m += len(d) - offset if m >= byte_length: break self.release_tag(tlp.tag) n += byte_length addr += byte_length if n >= length: break return data[:length]
async def dma_io_write(self, addr, data, timeout=0, timeout_unit='ns'): n = 0 while True: tlp = Tlp() tlp.fmt_type = TlpType.IO_WRITE tlp.requester_id = PcieId(self.dev_bus_num, self.dev_device_num, 0) first_pad = addr % 4 byte_length = min(len(data) - n, 4 - first_pad) tlp.set_addr_be_data(addr, data[n:n + byte_length]) tlp.tag = await self.alloc_tag() await self.tx_source.send(S10PcieFrame.from_tlp(tlp)) cpl = await self.recv_cpl(tlp.tag, timeout, timeout_unit) self.release_tag(tlp.tag) if not cpl: raise Exception("Timeout") if cpl.status != CplStatus.SC: raise Exception("Unsuccessful completion") n += byte_length addr += byte_length if n >= len(data): break
async def dma_mem_write(self, addr, data, timeout=0, timeout_unit='ns'): n = 0 while True: tlp = Tlp() if addr > 0xffffffff: tlp.fmt_type = TlpType.MEM_WRITE_64 else: tlp.fmt_type = TlpType.MEM_WRITE tlp.requester_id = PcieId(self.dev_bus_num, self.dev_device_num, 0) first_pad = addr % 4 byte_length = len(data) - n # max payload size byte_length = min(byte_length, (128 << self.dev_max_payload) - first_pad) # 4k address align byte_length = min(byte_length, 0x1000 - (addr & 0xfff)) tlp.set_addr_be_data(addr, data[n:n + byte_length]) await self.tx_source.send(S10PcieFrame.from_tlp(tlp)) n += byte_length addr += byte_length if n >= len(data): break
async def _run_cc_logic(self): while True: tlp = Tlp_us.unpack_us_cc(await self.cc_sink.recv(), self.enable_parity) if not tlp.completer_id_enable: tlp.completer_id = PcieId(self.bus_num, self.device_num, tlp.completer_id.function) if not tlp.discontinue: await self.send(Tlp(tlp))
def to_tlp(self): hdr = bytearray() for dw in self.data[:5]: hdr.extend(struct.pack('>L', dw)) tlp = Tlp.unpack_header(hdr) for dw in self.data[tlp.get_header_size_dw():]: tlp.data.extend(struct.pack('<L', dw)) return tlp
async def _run_rq_logic(self): while True: tlp = Tlp_us.unpack_us_rq(await self.rq_sink.recv(), self.enable_parity) if not tlp.requester_id_enable: tlp.requester_id = PcieId(self.bus_num, self.device_num, tlp.requester_id.function) if not tlp.discontinue: if self.functions[tlp.requester_id.function].bus_master_enable: self.rq_seq_num.append(tlp.seq_num) await self.send(Tlp(tlp)) else: self.log.warning("Bus mastering disabled")
async def dma_io_read(self, addr, length, timeout=0, timeout_unit='ns'): data = b'' n = 0 while True: tlp = Tlp() tlp.fmt_type = TlpType.IO_READ tlp.requester_id = PcieId(self.dev_bus_num, self.dev_device_num, 0) first_pad = addr % 4 byte_length = min(length - n, 4 - first_pad) tlp.set_addr_be(addr, byte_length) tlp.tag = await self.alloc_tag() await self.tx_source.send(S10PcieFrame.from_tlp(tlp)) cpl = await self.recv_cpl(tlp.tag, timeout, timeout_unit) self.release_tag(tlp.tag) if not cpl: raise Exception("Timeout") if cpl.status != CplStatus.SC: raise Exception("Unsuccessful completion") else: d = cpl.get_data() data += d[first_pad:] n += byte_length addr += byte_length if n >= length: break return data[:length]
async def _run_rx_tlp(self): while True: frame = await self.rx_sink.recv() tlp = frame.to_tlp() self.log.debug("RX TLP: %s", repr(tlp)) if tlp.fmt_type in { TlpType.CPL, TlpType.CPL_DATA, TlpType.CPL_LOCKED, TlpType.CPL_LOCKED_DATA }: self.log.info("Completion") self.rx_cpl_queues[tlp.tag].put_nowait(tlp) self.rx_cpl_sync[tlp.tag].set() elif tlp.fmt_type == TlpType.IO_READ: self.log.info("IO read") cpl = Tlp.create_completion_data_for_tlp( tlp, PcieId(self.dev_bus_num, 0, 0)) # region = tlp.bar_id region = 3 addr = tlp.address % len(self.regions[region]) offset = 0 start_offset = None mask = tlp.first_be # perform operation data = bytearray(4) for k in range(4): if mask & (1 << k): if start_offset is None: start_offset = offset else: if start_offset is not None and offset != start_offset: data[start_offset:offset] = self.regions[region][ addr + start_offset:addr + offset] start_offset = None offset += 1 if start_offset is not None and offset != start_offset: data[start_offset:offset] = self.regions[region][ addr + start_offset:addr + offset] cpl.set_data(data) cpl.byte_count = 4 cpl.length = 1 self.log.debug("Completion: %s", repr(cpl)) await self.tx_source.send(S10PcieFrame.from_tlp(cpl)) elif tlp.fmt_type == TlpType.IO_WRITE: self.log.info("IO write") cpl = Tlp.create_completion_for_tlp( tlp, PcieId(self.dev_bus_num, 0, 0)) # region = tlp.bar_id region = 3 addr = tlp.address % len(self.regions[region]) offset = 0 start_offset = None mask = tlp.first_be # perform operation data = tlp.get_data() for k in range(4): if mask & (1 << k): if start_offset is None: start_offset = offset else: if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[ start_offset:offset] start_offset = None offset += 1 if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[start_offset:offset] self.log.debug("Completion: %s", repr(cpl)) await self.tx_source.send(S10PcieFrame.from_tlp(cpl)) elif tlp.fmt_type in {TlpType.MEM_READ, TlpType.MEM_READ_64}: self.log.info("Memory read") # perform operation region = frame.bar_range addr = tlp.address % len(self.regions[region]) offset = 0 length = tlp.length # perform read data = self.regions[region][addr:addr + length * 4] # prepare completion TLP(s) m = 0 n = 0 addr = tlp.address + tlp.get_first_be_offset() dw_length = tlp.length byte_length = tlp.get_be_byte_count() while m < dw_length: cpl = Tlp.create_completion_data_for_tlp( tlp, PcieId(self.dev_bus_num, 0, 0)) cpl_dw_length = dw_length - m cpl_byte_length = byte_length - n cpl.byte_count = cpl_byte_length if cpl_dw_length > 32 << self.dev_max_payload: # max payload size cpl_dw_length = 32 << self.dev_max_payload # RCB align cpl_dw_length -= (addr & 0x7c) >> 2 cpl.lower_address = addr & 0x7f cpl.set_data(data[m * 4:(m + cpl_dw_length) * 4]) self.log.debug("Completion: %s", repr(cpl)) await self.tx_source.send(S10PcieFrame.from_tlp(cpl)) m += cpl_dw_length n += cpl_dw_length * 4 - (addr & 3) addr += cpl_dw_length * 4 - (addr & 3) elif tlp.fmt_type in {TlpType.MEM_WRITE, TlpType.MEM_WRITE_64}: self.log.info("Memory write") # perform operation region = frame.bar_range addr = tlp.address % len(self.regions[region]) offset = 0 start_offset = None mask = tlp.first_be length = tlp.length # perform write data = tlp.get_data() # first dword for k in range(4): if mask & (1 << k): if start_offset is None: start_offset = offset else: if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[ start_offset:offset] start_offset = None offset += 1 if length > 2: # middle dwords if start_offset is None: start_offset = offset offset += (length - 2) * 4 if length > 1: # last dword mask = tlp.last_be for k in range(4): if mask & (1 << k): if start_offset is None: start_offset = offset else: if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[ start_offset:offset] start_offset = None offset += 1 if start_offset is not None and offset != start_offset: self.regions[region][addr + start_offset:addr + offset] = data[start_offset:offset]
async def upstream_recv(self, tlp): self.log.debug("Got downstream TLP: %r", tlp) if tlp.fmt_type in {TlpType.CFG_READ_0, TlpType.CFG_WRITE_0}: # config type 0 # capture address information self.bus_num = tlp.dest_id.bus # pass TLP to function for f in self.functions: if f.pcie_id == tlp.dest_id: await f.upstream_recv(tlp) return tlp.release_fc() self.log.warning( "Function not found: failed to route config type 0 TLP: %r", tlp) elif tlp.fmt_type in {TlpType.CFG_READ_1, TlpType.CFG_WRITE_1}: # config type 1 tlp.release_fc() self.log.warning( "Malformed TLP: endpoint received config type 1 TLP: %r", tlp) elif tlp.fmt_type in { TlpType.CPL, TlpType.CPL_DATA, TlpType.CPL_LOCKED, TlpType.CPL_LOCKED_DATA }: # Completion for f in self.functions: if f.pcie_id == tlp.requester_id: frame = S10PcieFrame.from_tlp(tlp) frame.func_num = tlp.requester_id.function await self.rx_queue.put(frame) tlp.release_fc() return tlp.release_fc() self.log.warning( "Unexpected completion: failed to route completion to function: %r", tlp) return # no UR response for completion elif tlp.fmt_type in {TlpType.IO_READ, TlpType.IO_WRITE}: # IO read/write for f in self.functions: bar = f.match_bar(tlp.address, True) if bar: frame = S10PcieFrame.from_tlp(tlp) frame.bar_range = 6 frame.func_num = tlp.requester_id.function await self.rx_queue.put(frame) tlp.release_fc() return tlp.release_fc() self.log.warning( "No BAR match: IO request did not match any BARs: %r", tlp) elif tlp.fmt_type in { TlpType.MEM_READ, TlpType.MEM_READ_64, TlpType.MEM_WRITE, TlpType.MEM_WRITE_64 }: # Memory read/write for f in self.functions: bar = f.match_bar(tlp.address) if bar: frame = S10PcieFrame.from_tlp(tlp) frame.bar_range = bar[0] frame.func_num = tlp.requester_id.function await self.rx_queue.put(frame) tlp.release_fc() return tlp.release_fc() if tlp.fmt_type in {TlpType.MEM_WRITE, TlpType.MEM_WRITE_64}: self.log.warning( "No BAR match: memory write request did not match any BARs: %r", tlp) return # no UR response for write request else: self.log.warning( "No BAR match: memory read request did not match any BARs: %r", tlp) else: raise Exception("TODO") # Unsupported request cpl = Tlp.create_ur_completion_for_tlp(tlp, PcieId(self.bus_num, 0, 0)) self.log.debug("UR Completion: %r", cpl) await self.upstream_send(cpl)
async def upstream_recv(self, tlp): self.log.debug("Got downstream TLP: %s", repr(tlp)) if tlp.fmt_type == TlpType.CFG_READ_0 or tlp.fmt_type == TlpType.CFG_WRITE_0: # config type 0 if not self.config_space_enable: self.log.warning("Configuraion space disabled") cpl = Tlp.create_crs_completion_for_tlp(tlp, PcieId(self.bus_num, self.device_num, 0)) self.log.debug("CRS Completion: %s", repr(cpl)) await self.upstream_send(cpl) return elif tlp.dest_id.device == self.device_num: # capture address information self.bus_num = tlp.dest_id.bus for f in self.functions: f.pci_id = f.pcie_id._replace(bus=self.bus_num) # pass TLP to function for f in self.functions: if f.function_num == tlp.dest_id.function: await f.upstream_recv(tlp) return self.log.info("Function not found") else: self.log.info("Device number mismatch") # Unsupported request cpl = Tlp.create_ur_completion_for_tlp(tlp, PcieId(self.bus_num, self.device_num, 0)) self.log.debug("UR Completion: %s", repr(cpl)) await self.upstream_send(cpl) elif (tlp.fmt_type == TlpType.CPL or tlp.fmt_type == TlpType.CPL_DATA or tlp.fmt_type == TlpType.CPL_LOCKED or tlp.fmt_type == TlpType.CPL_LOCKED_DATA): # Completion if tlp.requester_id.bus == self.bus_num and tlp.requester_id.device == self.device_num: for f in self.functions: if f.function_num == tlp.requester_id.function: tlp = Tlp_us(tlp) tlp.error_code = ErrorCode.NORMAL_TERMINATION if tlp.status != CplStatus.SC: tlp.error = ErrorCode.BAD_STATUS self.rc_queue.append(tlp) return self.log.info("Function not found") else: self.log.info("Device number mismatch") elif (tlp.fmt_type == TlpType.IO_READ or tlp.fmt_type == TlpType.IO_WRITE): # IO read/write for f in self.functions: bar = f.match_bar(tlp.address, True) if len(bar) == 1: tlp = Tlp_us(tlp) tlp.bar_id = bar[0][0] tlp.bar_aperture = (~self.functions[0].bar_mask[bar[0][0]] & 0xffffffff).bit_length() tlp.completer_id = PcieId(self.bus_num, self.device_num, f.function_num) self.cq_queue.append(tlp) return self.log.info("IO request did not match any BARs") # Unsupported request cpl = Tlp.create_ur_completion_for_tlp(tlp, PcieId(self.bus_num, self.device_num, 0)) self.log.debug("UR Completion: %s", repr(cpl)) await self.upstream_send(cpl) elif (tlp.fmt_type == TlpType.MEM_READ or tlp.fmt_type == TlpType.MEM_READ_64 or tlp.fmt_type == TlpType.MEM_WRITE or tlp.fmt_type == TlpType.MEM_WRITE_64): # Memory read/write for f in self.functions: bar = f.match_bar(tlp.address) if len(bar) == 1: tlp = Tlp_us(tlp) tlp.bar_id = bar[0][0] if self.functions[0].bar[bar[0][0]] & 4: tlp.bar_aperture = (~(self.functions[0].bar_mask[bar[0][0]] | (self.functions[0].bar_mask[bar[0][0]+1] << 32)) & 0xffffffffffffffff).bit_length() else: tlp.bar_aperture = (~self.functions[0].bar_mask[bar[0][0]] & 0xffffffff).bit_length() tlp.completer_id = PcieId(self.bus_num, self.device_num, f.function_num) self.cq_queue.append(tlp) return self.log.info("Memory request did not match any BARs") if tlp.fmt_type == TlpType.MEM_READ or tlp.fmt_type == TlpType.MEM_READ_64: # Unsupported request cpl = Tlp.create_ur_completion_for_tlp(tlp, PcieId(self.bus_num, self.device_num, 0)) self.log.debug("UR Completion: %s", repr(cpl)) await self.upstream_send(cpl) else: raise Exception("TODO")