def test_sq_cq_around(nvme0): cq = IOCQ(nvme0, 1, 3, PRP()) sq = IOSQ(nvme0, 1, 2, PRP(), cqid=1) # send commands sq[0] = SQE(4<<16+0, 1); sq.tail = 1 sq[1] = SQE(3<<16+0, 1); sq.tail = 0 sq[0] = SQE(2<<16+0, 1); sq.tail = 1 sq[1] = SQE(1<<16+0, 1); sq.tail = 0 # check cq time.sleep(0.1) assert cq[0][3] == 0x10004 assert cq[1][3] == 0x10003 assert cq[2][3] == 0 cq.head = 1 assert cq[0][3] == 0x10004 assert cq[2][3] == 0x10002 cq.head = 2 assert cq[2][3] == 0x10002 assert cq[1][3] == 0x10003 assert cq[0][3] == 0x00001 sq.delete() cq.delete()
def test_cq_p_phase_bit(nvme0): cq = IOCQ(nvme0, 1, 3, PRP()) sq = IOSQ(nvme0, 1, 5, PRP(), cqid=1) # send commands sq[0] = SQE(4 << 16 + 0, 1) sq[1] = SQE(3 << 16 + 0, 1) sq[2] = SQE(2 << 16 + 0, 1) sq[3] = SQE(1 << 16 + 0, 1) sq.tail = 4 # check cq time.sleep(0.1) assert cq[0][3] == 0x10004 assert cq[1][3] == 0x10003 assert cq[2][3] == 0 cq.head = 1 time.sleep(0.1) assert cq[2][3] == 0x10002 assert cq[0][3] == 0x10004 cq.head = 2 time.sleep(0.1) # p-bit changed to 0 assert cq[0][3] == 0x00001
def test_sq_cq_another_sq(nvme0): cq = IOCQ(nvme0, 1, 3, PRP()) # send commands in sq1 sq = IOSQ(nvme0, 1, 3, PRP(), cqid=1) sq[0] = SQE(4 << 16 + 0, 1) sq[1] = SQE(3 << 16 + 0, 1) sq.tail = 2 sq2 = IOSQ(nvme0, 2, 3, PRP(), cqid=1) sq2[0] = SQE(2 << 16 + 0, 1) sq2[1] = SQE(1 << 16 + 0, 1) sq2.tail = 2 # check cq time.sleep(0.1) assert cq[0][3] == 0x10004 assert cq[1][3] == 0x10003 assert cq[2][3] == 0 cq.head = 1 time.sleep(0.1) assert cq[2][3] == 0x10002 assert cq[0][3] == 0x10004 cq.head = 2 time.sleep(0.1) assert cq[0][3] == 0x00001 sq.delete() sq2.delete() cq.delete()
def test_cq_sqhd(nvme0): cq = IOCQ(nvme0, 1, 3, PRP()) sq = IOSQ(nvme0, 1, 2, PRP(), cqid=1) # send commands, and check cqe sq[0] = SQE(4 << 16 + 0, 1) sq.tail = 1 time.sleep(0.1) assert cq[0][2] == 0x10001 assert cq[0][3] == 0x10004 assert cq[1][2] == 0 assert cq[2][2] == 0 # send commands, and check cqe sq[1] = SQE(3 << 16 + 0, 1) sq.tail = 0 time.sleep(0.1) assert cq[0][2] == 0x10001 assert cq[0][3] == 0x10004 assert cq[1][2] == 0x10000 assert cq[1][3] == 0x10003 assert cq[2][2] == 0 # send commands, and check cqe sq[0] = SQE(2 << 16 + 0, 1) sq.tail = 1 time.sleep(0.1) assert cq[0][2] == 0x10001 assert cq[0][3] == 0x10004 assert cq[1][2] == 0x10000 assert cq[1][3] == 0x10003 assert cq[2][2] == 0 # free one cqe before get 3rd cqe cq.head = 1 time.sleep(0.1) assert cq[2][2] == 0x10001 assert cq[2][3] == 0x10002 # send commands, and check cqe sq[1] = SQE(1 << 16 + 0, 1) sq.tail = 0 time.sleep(0.1) cq.head = 2 time.sleep(0.1) assert cq[0][2] == 0x10000 assert cq[0][3] == 0x00001 assert cq[1][2] == 0x10000 assert cq[1][3] == 0x10003 assert cq[2][2] == 0x10001 assert cq[2][3] == 0x10002
def test_cid_conflict(nvme0): mdts_lba = nvme0.mdts // 512 cq = IOCQ(nvme0, 1, 20, PRP()) sq = IOSQ(nvme0, 1, 20, PRP(), cqid=1) # prp for the long buffer write_buf_1 = PRP(ptype=32, pvalue=0xaaaaaaaa) pages = mdts_lba // 8 pages -= 1 prp_list = PRPList() prp_list_head = prp_list while pages: logging.info(pages) for i in range(63): if pages: prp_list[i] = PRP() pages -= 1 logging.debug(pages) if pages > 1: tmp = PRPList() prp_list[63] = tmp prp_list = tmp logging.debug("prp_list") elif pages == 1: prp_list[63] = PRP() pages -= 1 logging.debug(pages) #send first cmd w1 = SQE((1 << 16) + 1, 1) w1.prp1 = write_buf_1 w1.prp2 = prp_list_head w1[12] = mdts_lba - 1 # 0based, nlba sq[0] = w1 sq[1] = w1 logging.info(sq[0]) logging.info(sq[1]) assert sq[0][0] >> 16 == 1 assert sq[1][0] >> 16 == 1 sq.tail = 2 time.sleep(1) logging.info(cq[0]) logging.info(cq[1]) cqe = CQE(cq[0]) assert cqe.p == 1 status = (cqe[3] >> 17) & 0x3ff assert status == 0 or status == 0x0003 cqe = CQE(cq[1]) assert cqe.p == 1 status = (cqe[3] >> 17) & 0x3ff assert status == 0 or status == 0x0003 cq.head = 2 sq.delete() cq.delete()
def test_cq_doorbell_invalid(nvme0, head): cq = IOCQ(nvme0, 1, 5, PRP()) sq = IOSQ(nvme0, 1, 2, PRP(), cqid=1) sq.tail = 1 time.sleep(0.1) cq.head = head #Invalid Doorbell Write Value with pytest.warns(UserWarning, match="AER notification is triggered: 0x10100"): nvme0.getfeatures(7).waitdone() sq.delete() cq.delete()
def test_write_mdts(nvme0, mdts): cq = IOCQ(nvme0, 1, 2, PRP()) sq = IOSQ(nvme0, 1, 2, PRP(), cqid=1) # prp for the long buffer write_buf_1 = PRP(ptype=32, pvalue=0xaaaaaaaa) pages = mdts // 8 pages -= 1 prp_list = PRPList() prp_list_head = prp_list while pages: for i in range(511): if pages: prp_list[i] = PRP() pages -= 1 logging.debug(pages) if pages > 1: tmp = PRPList() prp_list[511] = tmp prp_list = tmp logging.debug("prp_list") elif pages == 1: prp_list[511] = PRP() pages -= 1 logging.debug(pages) w1 = SQE(1, 1) w1.prp1 = write_buf_1 w1.prp2 = prp_list_head w1[12] = mdts - 1 # 0based, nlba w1.cid = 0x123 sq[0] = w1 sq.tail = 1 time.sleep(1) cqe = CQE(cq[0]) logging.info(cqe) assert cqe.p == 1 assert cqe.cid == 0x123 assert cqe.sqhd == 1 logging.info("cqe status is {}".format(cqe.status)) assert cqe.status == 0 or cqe.status == 2 cq.head = 1 sq.delete() cq.delete()
def test_pcie_link_control_aspm(nvme0, pcie, aspm): #1:0 linkctrl_addr = pcie.cap_offset(0x10) + 16 linkctrl = pcie.register(linkctrl_addr, 2) logging.info("link control register [0x%x]= 0x%x" % (linkctrl_addr, linkctrl)) # set ASPM control pcie[linkctrl_addr] = (linkctrl & 0xfc) | aspm linkctrl = pcie.register(linkctrl_addr, 2) logging.info("link control register [0x%x]= 0x%x" % (linkctrl_addr, linkctrl)) # IO queue for read commands cq = IOCQ(nvme0, 1, 16, PRP()) sq = IOSQ(nvme0, 1, 16, PRP(), cqid=1) # read lba 0 for 1000 times, interleaved with delays read_cmd = SQE(2, 1) read_cmd.prp1 = PRPList() pbit = 1 for i in range(100): logging.debug(i) slot = i % 16 if slot == 0: pbit = not pbit next_slot = slot + 1 if next_slot == 16: next_slot = 0 sq[slot] = read_cmd sq.tail = next_slot while cq[slot].p == pbit: pass cq.head = next_slot # delay to trigger ASPM time.sleep(0.01) sq.delete() cq.delete() time.sleep(1) #return ASPM L0 pcie[linkctrl_addr] = (linkctrl & 0xfc) | 0
def test_invalid_offset_prp_in_list(nvme0): cq = IOCQ(nvme0, 1, 10, PRP()) sq = IOSQ(nvme0, 1, 10, PRP(), cqid=1) buf = PRP(ptype=32, pvalue=0xffffffff) buf.offset = 0x10 prp_list = PRPList() prp_list.offset = 0x20 for i in range(8): tmp = PRP(ptype=32, pvalue=0xffffffff) tmp.offset = 0x10 prp_list[i] = tmp logging.info(prp_list.dump(64)) print(buf.dump(32)) for i in range(8): print(prp_list[i].dump(32)) cmd = SQE(2, 1) cmd.prp1 = buf cmd.prp2 = prp_list cmd[12] = 0x4000001f sq[0] = cmd logging.info(sq[0]) sq.tail = 1 while CQE(cq[0]).p == 0: pass cq.head = 1 logging.info(cq[0]) logging.info(hex(cq[0][3] >> 17)) print(buf.dump(32)) for i in range(8): print(prp_list[i].dump(32)) status = (cq[0][3] >> 17) & 0x3ff assert status == 0x0013 or status == 0 sq.delete() cq.delete()
def test_p_invert_after_cq_2_pass(nvme0): """ The value of the Phase Tag is inverted each pass filling the Complete Queue. """ # cqid: 1, PC, depth: 2 cq = IOCQ(nvme0, 1, 2, PRP()) # create four SQ, both use the same CQ sq3 = IOSQ(nvme0, 3, 10, PRP(), cqid=1) # IO command templates: opcode and namespace write_cmd = SQE(1, 1) # write in sq3 w1 = SQE(*write_cmd) write_buf = PRP(ptype=32, pvalue=0xaaaaaaaa) w1.prp1 = write_buf w1[10] = 1 w1[12] = 1 # 0based w1.cid = 0x123 sq3[0] = w1 sq3.tail = 1 # add some delay, so ssd should finish w1 before w2 time.sleep(0.1) # write in sq5 w1.cid = 0x567 sq3[1] = w1 sq3.tail = 2 logging.info("aaa") # cqe for w1 while CQE(cq[0]).p == 0: pass cqe = CQE(cq[0]) assert cqe.cid == 0x123 assert cqe.sqid == 3 assert cqe.sqhd == 1 cq.head = 1 # cqe for w2 logging.info("bbb") while CQE(cq[1]).p == 0: pass logging.info("ccc") cqe = CQE(cq[1]) assert cqe.cid == 0x567 assert cqe.sqid == 3 assert cqe.sqhd == 2 cq.head = 0 assert CQE(cq[0]).p == 1 assert CQE(cq[1]).p == 1 # write in sq3 w1.cid = 0x147 sq3[2] = w1 sq3.tail = 3 # add some delay, so ssd should finish w1 before w2 time.sleep(0.1) # write in sq5 w1.cid = 0x167 sq3[3] = w1 sq3.tail = 4 # cqe for w3 while CQE(cq[0]).p == 1: pass cqe = CQE(cq[0]) assert cqe.cid == 0x147 assert cqe.sqid == 3 assert cqe.sqhd == 3 cq.head = 1 # cqe for w4 while CQE(cq[1]).p == 1: pass cqe = CQE(cq[1]) assert cqe.cid == 0x167 assert cqe.sqid == 3 assert cqe.sqhd == 4 cq.head = 0 assert CQE(cq[0]).p == 0 assert CQE(cq[1]).p == 0
def test_controller_mdts(nvme0,nvme0n1): if nvme0.mdts == 1024*1024: # up to 1MB pytest.skip("mdts is maximum") mps_min = (nvme0.cap>>48) & 0xf logging.info("mps_min:{}".format(mps_min)) mdts=nvme0.id_data(77,77) logging.info("mdts:{}".format(mdts)) max_data_size=(2**mdts)*(2**(12+mps_min)) logging.info(max_data_size) max_pages=max_data_size//4//1024 pages=max_pages-1 max_lba=max_data_size//512 cq = IOCQ(nvme0, 1, 5, PRP()) sq = IOSQ(nvme0, 1, 5, PRP(), cqid=1) # prp for the long buffer write_buf_1 = PRP(ptype=32, pvalue=0xaaaaaaaa) prp_list = PRPList() prp_list_head = prp_list while pages: for i in range(511): if pages: prp_list[i] = PRP() pages -= 1 logging.debug(pages) if pages>1: tmp = PRPList() prp_list[511] = tmp prp_list = tmp logging.debug("prp_list") elif pages==1: prp_list[511] = PRP() pages -= 1 logging.debug(pages) w1 = SQE(1, 1) w1.prp1 = write_buf_1 w1.prp2 = prp_list_head w1[12] = max_lba-1 # 0based, nlba w1.cid = 0x123 sq[0] = w1 sq.tail = 1 time.sleep(1) cqe = CQE(cq[0]) logging.info(cqe) assert cqe.p == 1 assert cqe.cid == 0x123 assert cqe.sqhd == 1 assert cqe.status == 0 cq.head = 1 w2 = SQE(1, 1) w2.prp1 = write_buf_1 w2.prp2 = prp_list_head w2[12] = max_lba # 0based, nlba w2.cid = 0x234 sq[1] = w2 sq.tail = 2 time.sleep(1) cqe = CQE(cq[1]) logging.info(cqe) assert cqe.p == 1 assert cqe.cid == 0x234 assert cqe.sqhd == 2 assert cqe.status == 2 cq.head = 2 r1 = SQE(2, 1) r1.prp1 = write_buf_1 r1.prp2 = prp_list_head r1[12] = max_lba # 0based, nlba r1.cid = 0x345 sq[2] = r1 sq.tail = 3 time.sleep(1) cqe = CQE(cq[2]) logging.info(cqe) assert cqe.p == 1 assert cqe.cid == 0x345 assert cqe.sqhd == 3 assert cqe.status == 2 cq.head = 3 r2 = SQE(2, 1) r2.prp1 = write_buf_1 r2.prp2 = prp_list_head r2[12] = max_lba-1 # 0based, nlba r2.cid = 0x456 sq[3] = r2 sq.tail = 4 time.sleep(1) cqe = CQE(cq[3]) logging.info(cqe) assert cqe.p == 1 assert cqe.cid == 0x456 assert cqe.sqhd == 4 assert cqe.status == 0 cq.head = 4 sq.delete() cq.delete()