manage reg_d2h errors
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 20 Jan 2015 16:14:01 +0000 (17:14 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 20 Jan 2015 18:28:56 +0000 (19:28 +0100)
litesata/common.py
litesata/core/command/__init__.py
litesata/frontend/bist.py
test/bist.py
test/tools.py

index 90f7c23c47d8fab17b82316343c8c14dfeb5e6b1..19e62fb11e6c49dace5839ed70eb04b34b6abe7d 100644 (file)
@@ -184,6 +184,19 @@ regs = {
        "IDENTIFY_DEVICE"               : 0xEC
 }
 
+reg_d2h_status = {
+       "bsy"   :       7,
+       "drdy"  :       6,
+       "df"    :       5,
+       "se"    :       5,
+       "dwe"   :       4,
+       "drq"   :       3,
+       "ae"    :       2,
+       "sns"   :       1,
+       "cc"    :       0,
+       "err"   :       0
+}
+
 def command_tx_description(dw):
        layout = [
                ("write", 1),
index 130b5fc3174e7cdde787db59dd3444e1936f387a..2241ea7fb6ee8beec057e0f06ceea6f23a5c0869 100644 (file)
@@ -8,7 +8,8 @@ tx_to_rx = [
 ]
 
 rx_to_tx = [
-       ("dma_activate", 1)
+       ("dma_activate", 1),
+       ("d2h_error", 1)
 ]
 
 class LiteSATACommandTX(Module):
@@ -64,6 +65,9 @@ class LiteSATACommandTX(Module):
                        dwords_counter.reset.eq(1),
                        If(from_rx.dma_activate,
                                NextState("SEND_DATA")
+                       ).Elif(from_rx.d2h_error,
+                               sink.ack.eq(1),
+                               NextState("IDLE")
                        )
                )
                fsm.act("SEND_DATA",
@@ -145,10 +149,21 @@ class LiteSATACommandRX(Module):
                        )
                self.comb += read_done.eq(self.dwords_counter.value == read_ndwords)
 
+               d2h_error = Signal()
+               clr_d2h_error = Signal()
+               set_d2h_error = Signal()
+               self.sync += \
+                       If(clr_d2h_error,
+                               d2h_error.eq(0)
+                       ).Elif(set_d2h_error,
+                               d2h_error.eq(1)
+                       )
+
                self.fsm = fsm = FSM(reset_state="IDLE")
                fsm.act("IDLE",
                        self.dwords_counter.reset.eq(1),
                        transport.source.ack.eq(1),
+                       clr_d2h_error.eq(1),
                        If(from_tx.write,
                                NextState("WAIT_WRITE_ACTIVATE_OR_REG_D2H")
                        ).Elif(from_tx.read,
@@ -167,7 +182,7 @@ class LiteSATACommandRX(Module):
                                If(test_type("DMA_ACTIVATE_D2H"),
                                        dma_activate.eq(1),
                                ).Elif(test_type("REG_D2H"),
-                                       # XXX: use status and error fields of REG_D2H
+                                       set_d2h_error.eq(transport.source.status[reg_d2h_status["err"]]),
                                        NextState("PRESENT_WRITE_RESPONSE")
                                )
                        )
@@ -176,8 +191,8 @@ class LiteSATACommandRX(Module):
                        cmd_buffer.sink.stb.eq(1),
                        cmd_buffer.sink.write.eq(1),
                        cmd_buffer.sink.last.eq(1),
-                       cmd_buffer.sink.success.eq(~transport.source.error),
-                       cmd_buffer.sink.failed.eq(transport.source.error),
+                       cmd_buffer.sink.success.eq(~transport.source.error & ~d2h_error),
+                       cmd_buffer.sink.failed.eq(transport.source.error | d2h_error),
                        If(cmd_buffer.sink.stb & cmd_buffer.sink.ack,
                                NextState("IDLE")
                        )
@@ -189,7 +204,7 @@ class LiteSATACommandRX(Module):
                                If(test_type("DATA"),
                                        NextState("PRESENT_READ_DATA")
                                ).Elif(test_type("REG_D2H"),
-                                       # XXX: use status and error fields of REG_D2H
+                                       set_d2h_error.eq(transport.source.status[reg_d2h_status["err"]]),
                                        NextState("PRESENT_READ_RESPONSE")
                                )
                        )
@@ -205,7 +220,6 @@ class LiteSATACommandRX(Module):
                )
                fsm.act("PRESENT_PIO_SETUP_D2H",
                        transport.source.ack.eq(1),
-                       # XXX : Check error/ status
                        If(transport.source.stb & transport.source.eop,
                                NextState("WAIT_READ_DATA_OR_REG_D2H")
                        )
@@ -242,8 +256,8 @@ class LiteSATACommandRX(Module):
                        cmd_buffer.sink.read.eq(~identify),
                        cmd_buffer.sink.identify.eq(identify),
                        cmd_buffer.sink.last.eq(read_done | identify),
-                       cmd_buffer.sink.success.eq(~read_error),
-                       cmd_buffer.sink.failed.eq(read_error),
+                       cmd_buffer.sink.success.eq(~read_error & ~d2h_error),
+                       cmd_buffer.sink.failed.eq(read_error | d2h_error),
                        If(cmd_buffer.sink.stb & cmd_buffer.sink.ack,
                                If(cmd_buffer.sink.failed,
                                        data_buffer.reset.eq(1)
@@ -301,6 +315,7 @@ class LiteSATACommandRX(Module):
 
                self.comb += [
                        to_tx.dma_activate.eq(dma_activate),
+                       to_tx.d2h_error.eq(d2h_error)
                ]
 
 class LiteSATACommand(Module):
index be994cb4b1cd390f38c1ff0fb4cf93eccc6d5d27..02abd3b9cabe33fae850ffbcf28a3e26009e7082 100644 (file)
@@ -12,6 +12,7 @@ class LiteSATABISTGenerator(Module):
                self.random = Signal()
 
                self.done = Signal()
+               self.aborted = Signal()
                self.errors = Signal(32) # Note: Not used for writes
 
                ###
@@ -61,6 +62,7 @@ class LiteSATABISTGenerator(Module):
                                NextState("IDLE")
                        )
                )
+               self.sync += If(sink.stb & sink.ack, self.aborted.eq(sink.failed))
 
 class LiteSATABISTChecker(Module):
        def __init__(self, sata_master_port):
@@ -70,6 +72,7 @@ class LiteSATABISTChecker(Module):
                self.random = Signal()
 
                self.done = Signal()
+               self.aborted = Signal()
                self.errors = Signal(32)
 
                ###
@@ -136,6 +139,7 @@ class LiteSATABISTChecker(Module):
                                )
                        )
                )
+               self.sync += If(sink.stb & sink.ack, self.aborted.eq(sink.failed))
 
 class LiteSATABISTUnitCSR(Module, AutoCSR):
        def __init__(self, bist_unit):
@@ -144,6 +148,7 @@ class LiteSATABISTUnitCSR(Module, AutoCSR):
                self._count = CSRStorage(16)
                self._random = CSRStorage()
                self._done = CSRStatus()
+               self._aborted = CSRStatus()
                self._errors = CSRStatus(32)
                self._cycles = CSRStatus(32)
 
@@ -157,6 +162,7 @@ class LiteSATABISTUnitCSR(Module, AutoCSR):
                        bist_unit.random.eq(self._random.storage),
 
                        self._done.status.eq(bist_unit.done),
+                       self._aborted.status.eq(bist_unit.aborted),
                        self._errors.status.eq(bist_unit.errors)
                ]
 
index a1f60473bad99ce0914af1f42f365a1cd2ac57fe..464954d29b7fa5a3ccc0e6bcaabf420bdf9deb81 100644 (file)
@@ -15,20 +15,26 @@ class LiteSATABISTUnitDriver:
                self.name = name
                self.frequency = regs.identifier_frequency.read()
                self.time = 0
-               for s in ["start", "sector", "count", "random", "done", "errors", "cycles"]:
+               for s in ["start", "sector", "count", "random", "done", "aborted", "errors", "cycles"]:
                        setattr(self, s, getattr(regs, name + "_"+ s))
 
-       def run(self, sector, count, random):
+       def run(self, sector, count, random, blocking=True):
                self.sector.write(sector)
                self.count.write(count)
                self.random.write(random)
                self.start.write(1)
-               while (self.done.read() == 0):
-                       pass
-               self.time = self.cycles.read()/self.frequency
-               speed = (count*logical_sector_size)/self.time
-               errors = self.errors.read()
-               return (speed, errors)
+               if blocking:
+                       while (self.done.read() == 0):
+                               pass
+               aborted = self.aborted.read()
+               if not aborted:
+                       self.time = self.cycles.read()/self.frequency
+                       speed = (count*logical_sector_size)/self.time
+                       errors = self.errors.read()
+               else:
+                       speed = 0
+                       errors = -1
+               return (aborted, errors, speed)
 
 class LiteSATABISTGeneratorDriver(LiteSATABISTUnitDriver):
        def __init__(self, regs, name):
@@ -55,13 +61,14 @@ class LiteSATABISTIdentifyDriver:
                        self.data += [word_lsb, word_msb]
                        self.source_ack.write(1)
 
-       def run(self):
+       def run(self, blocking=True):
                self.read_fifo() # flush the fifo before we start
                self.start.write(1)
-               while (self.done.read() == 0):
-                       pass
-               self.read_fifo()
-               self.decode()
+               if blocking:
+                       while (self.done.read() == 0):
+                               pass
+                       self.read_fifo()
+                       self.decode()
 
        def decode(self):
                self.serial_number = ""
@@ -102,7 +109,7 @@ def _get_args():
                description="""\
 SATA BIST utility.
 """)
-       parser.add_argument("-s", "--transfer_size", default=4, help="transfer sizes (in MB, up to 16MB)")
+       parser.add_argument("-s", "--transfer_size", default=1024, help="transfer sizes (in KB, up to 16MB)")
        parser.add_argument("-l", "--total_length", default=256, help="total transfer length (in MB, up to HDD capacity)")
        parser.add_argument("-r", "--random", action="store_true", help="use random data")
        parser.add_argument("-c", "--continuous", action="store_true", help="continuous mode (Escape to exit)")
@@ -122,24 +129,36 @@ if __name__ == "__main__":
 
        if not int(args.identify):
                sector = 0
-               count = int(args.transfer_size)*MB//logical_sector_size
+               count = int(args.transfer_size)*KB//logical_sector_size
                length = int(args.total_length)*MB
                random = int(args.random)
                continuous = int(args.continuous)
                try:
                        while ((sector*logical_sector_size < length) or continuous) and (sector < identify.total_sectors):
+                               retry = 0
                                # generator (write data to HDD)
-                               write_speed, write_errors = generator.run(sector, count, random)
+                               write_done = False
+                               while not write_done:
+                                       write_aborted, write_errors, write_speed = generator.run(sector, count, random)
+                                       write_done = not write_aborted
+                                       if not write_done:
+                                               retry += 1
 
                                # checker (read and check data from HDD)
-                               read_speed, read_errors = checker.run(sector, count, random)
-
-                               print("sector=%d(%dMB) wr_speed=%4.2fMB/sec rd_speed=%4.2fMB/sec errors=%d" %(
+                               read_done = False
+                               while not read_done:
+                                       read_aborted, read_errors, read_speed = checker.run(sector, count, random)
+                                       read_done = not read_aborted
+                                       if not read_done:
+                                               retry += 1
+
+                               print("sector=%d(%dMB) wr_speed=%4.2fMB/s rd_speed=%4.2fMB/s errors=%d retry=%d" %(
                                        sector,
                                        sector*logical_sector_size/MB,
                                        write_speed/MB,
                                        read_speed/MB,
-                                       write_errors + read_errors))
+                                       write_errors + read_errors,
+                                       retry))
                                sector += count
 
                except KeyboardInterrupt:
index 1e8411af6bf9fb6eb3339b752afa32f41e08fa59..93f54ff5b88ec06bbda2f6cd325cc7c758868e13 100644 (file)
@@ -23,7 +23,8 @@ def decode_primitive(dword):
                        return k
        return ""
 
-def print_link_trace(mila, tx_data_name, rx_data_name):
+def link_trace(mila, tx_data_name, rx_data_name):
+       r = ""
        dump = Dump()
        dump.add_from_layout(mila.layout, mila.dat)
 
@@ -33,7 +34,6 @@ def print_link_trace(mila, tx_data_name, rx_data_name):
                if var.name == rx_data_name:
                        rx_data = var.values
 
-       print("")
        for i in range(len(tx_data)):
                tx = "%08x " %tx_data[i]
                tx += decode_primitive(tx_data[i])
@@ -43,4 +43,6 @@ def print_link_trace(mila, tx_data_name, rx_data_name):
                rx += decode_primitive(rx_data[i])
                rx += " "*(16-len(rx))
 
-               print(tx + rx)
+               r += tx + rx + "\n"
+
+       return r