예제 #1
0
    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]
예제 #2
0
    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
예제 #3
0
    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
예제 #4
0
    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))
예제 #5
0
    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
예제 #6
0
    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")
예제 #7
0
    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]
예제 #8
0
    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]
예제 #9
0
    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)
예제 #10
0
    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")