drtio: rewrite/fix reset and link bringup/teardown

This commit is contained in:
Sebastien Bourdeauducq 2018-02-20 17:26:01 +08:00
parent bfabf3c906
commit ad2c9590d0
7 changed files with 77 additions and 106 deletions

View File

@ -54,11 +54,10 @@ pub mod drtio {
} }
} }
fn reset_phy(linkno: u8) { fn link_reset(linkno: u8) {
let linkno = linkno as usize; let linkno = linkno as usize;
unsafe { unsafe {
(csr::DRTIO[linkno].reset_phy_write)(1); (csr::DRTIO[linkno].reset_write)(1);
while (csr::DRTIO[linkno].o_wait_read)() == 1 {}
} }
} }
@ -70,12 +69,9 @@ pub mod drtio {
} }
} }
fn init_link(linkno: u8) { fn init_buffer_space(linkno: u8) {
let linkidx = linkno as usize; let linkidx = linkno as usize;
unsafe { unsafe {
(csr::DRTIO[linkidx].reset_write)(1);
while (csr::DRTIO[linkidx].o_wait_read)() == 1 {}
(csr::DRTIO[linkidx].o_get_buffer_space_write)(1); (csr::DRTIO[linkidx].o_get_buffer_space_write)(1);
while (csr::DRTIO[linkidx].o_wait_read)() == 1 {} while (csr::DRTIO[linkidx].o_wait_read)() == 1 {}
info!("[LINK#{}] buffer space is {}", info!("[LINK#{}] buffer space is {}",
@ -83,12 +79,6 @@ pub mod drtio {
} }
} }
pub fn init() {
for linkno in 0..csr::DRTIO.len() {
init_link(linkno as u8);
}
}
fn ping_remote(linkno: u8, io: &Io) -> u32 { fn ping_remote(linkno: u8, io: &Io) -> u32 {
let mut count = 0; let mut count = 0;
loop { loop {
@ -114,7 +104,7 @@ pub mod drtio {
(csr::DRTIO[linkidx].protocol_error_write)(errors); (csr::DRTIO[linkidx].protocol_error_write)(errors);
} }
if errors != 0 { if errors != 0 {
error!("[LINK#{}] found error(s)", linkno); error!("[LINK#{}] error(s) found (0x{:02x}):", linkno, errors);
if errors & 1 != 0 { if errors & 1 != 0 {
error!("[LINK#{}] received packet of an unknown type", linkno); error!("[LINK#{}] received packet of an unknown type", linkno);
} }
@ -148,21 +138,8 @@ pub mod drtio {
loop { loop {
for linkno in 0..csr::DRTIO.len() { for linkno in 0..csr::DRTIO.len() {
let linkno = linkno as u8; let linkno = linkno as u8;
if !link_up[linkno as usize] { if link_up[linkno as usize] {
if link_rx_up(linkno) { /* link was previously up */
info!("[LINK#{}] link RX became up, pinging", linkno);
let ping_count = ping_remote(linkno, &io);
if ping_count > 0 {
info!("[LINK#{}] remote replied after {} packets", linkno, ping_count);
init_link(linkno); // clear all FIFOs first
reset_phy(linkno);
sync_tsc(linkno);
info!("[LINK#{}] link initialization completed", linkno);
link_up[linkno as usize] = true;
} else {
info!("[LINK#{}] ping failed", linkno);
}
} else {
if link_rx_up(linkno) { if link_rx_up(linkno) {
process_local_errors(linkno); process_local_errors(linkno);
process_aux_errors(linkno); process_aux_errors(linkno);
@ -170,12 +147,31 @@ pub mod drtio {
info!("[LINK#{}] link is down", linkno); info!("[LINK#{}] link is down", linkno);
link_up[linkno as usize] = false; link_up[linkno as usize] = false;
} }
} else {
/* link was previously down */
if link_rx_up(linkno) {
info!("[LINK#{}] link RX became up, pinging", linkno);
link_reset(linkno);
let ping_count = ping_remote(linkno, &io);
if ping_count > 0 {
info!("[LINK#{}] remote replied after {} packets", linkno, ping_count);
init_buffer_space(linkno);
sync_tsc(linkno);
info!("[LINK#{}] link initialization completed", linkno);
link_up[linkno as usize] = true;
} else {
info!("[LINK#{}] ping failed", linkno);
}
} }
} }
} }
io.sleep(200).unwrap(); io.sleep(200).unwrap();
} }
} }
pub fn init() {
// TODO: send reset commands (over aux) to every link that is up
}
} }
#[cfg(not(has_drtio))] #[cfg(not(has_drtio))]

View File

@ -193,6 +193,14 @@ fn drtio_link_is_up() -> bool {
} }
} }
fn drtio_reset(reset: bool) {
let reset = if reset { 1 } else { 0 };
unsafe {
(csr::DRTIO[0].reset_write)(reset);
(csr::DRTIO[0].reset_phy_write)(reset);
}
}
fn startup() { fn startup() {
board::clock::init(); board::clock::init();
info!("ARTIQ satellite manager starting..."); info!("ARTIQ satellite manager starting...");
@ -216,10 +224,12 @@ fn startup() {
} }
info!("link is up, switching to recovered clock"); info!("link is up, switching to recovered clock");
si5324::select_ext_input(true).expect("failed to switch clocks"); si5324::select_ext_input(true).expect("failed to switch clocks");
drtio_reset(false);
while drtio_link_is_up() { while drtio_link_is_up() {
process_errors(); process_errors();
process_aux_packets(); process_aux_packets();
} }
drtio_reset(true);
info!("link is down, switching to local crystal clock"); info!("link is down, switching to local crystal clock");
si5324::select_ext_input(false).expect("failed to switch clocks"); si5324::select_ext_input(false).expect("failed to switch clocks");
} }

View File

@ -2,6 +2,7 @@ from types import SimpleNamespace
from migen import * from migen import *
from migen.genlib.cdc import ElasticBuffer from migen.genlib.cdc import ElasticBuffer
from migen.genlib.resetsync import AsyncResetSynchronizer
from misoc.interconnect.csr import * from misoc.interconnect.csr import *
from artiq.gateware.rtio.sed.core import * from artiq.gateware.rtio.sed.core import *
@ -54,14 +55,36 @@ class GenericRXSynchronizer(Module):
class DRTIOSatellite(Module): class DRTIOSatellite(Module):
def __init__(self, chanif, channels, rx_synchronizer=None, fine_ts_width=3, def __init__(self, chanif, channels, rx_synchronizer=None, fine_ts_width=3,
lane_count=8, fifo_depth=128): lane_count=8, fifo_depth=128):
if rx_synchronizer is None: self.reset = CSRStorage(reset=1)
rx_synchronizer = GenericRXSynchronizer() self.reset_phy = CSRStorage(reset=1)
self.submodules += rx_synchronizer
self.clock_domains.cd_rio = ClockDomain()
self.clock_domains.cd_rio_phy = ClockDomain()
self.comb += [
self.cd_rio.clk.eq(ClockSignal("rtio")),
self.cd_rio_phy.clk.eq(ClockSignal("rtio"))
]
reset = Signal()
reset_phy = Signal()
reset.attr.add("no_retiming")
reset_phy.attr.add("no_retiming")
self.sync += [
reset.eq(self.reset.storage),
reset_phy.eq(self.reset_phy.storage)
]
self.specials += [
AsyncResetSynchronizer(self.cd_rio, reset),
AsyncResetSynchronizer(self.cd_rio_phy, reset_phy)
]
self.submodules.link_layer = link_layer.LinkLayer( self.submodules.link_layer = link_layer.LinkLayer(
chanif.encoder, chanif.decoders) chanif.encoder, chanif.decoders)
self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready) self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready)
if rx_synchronizer is None:
rx_synchronizer = GenericRXSynchronizer()
self.submodules += rx_synchronizer
link_layer_sync = SimpleNamespace( link_layer_sync = SimpleNamespace(
tx_aux_frame=self.link_layer.tx_aux_frame, tx_aux_frame=self.link_layer.tx_aux_frame,
tx_aux_data=self.link_layer.tx_aux_data, tx_aux_data=self.link_layer.tx_aux_data,
@ -80,6 +103,7 @@ class DRTIOSatellite(Module):
self.submodules.link_stats = link_layer.LinkLayerStats(link_layer_sync, "rtio") self.submodules.link_stats = link_layer.LinkLayerStats(link_layer_sync, "rtio")
self.submodules.rt_packet = ClockDomainsRenamer("rtio")( self.submodules.rt_packet = ClockDomainsRenamer("rtio")(
rt_packet_satellite.RTPacketSatellite(link_layer_sync)) rt_packet_satellite.RTPacketSatellite(link_layer_sync))
self.comb += self.rt_packet.reset.eq(self.cd_rio.rst)
coarse_ts = Signal(64 - fine_ts_width) coarse_ts = Signal(64 - fine_ts_width)
self.sync.rtio += \ self.sync.rtio += \
@ -106,20 +130,12 @@ class DRTIOSatellite(Module):
self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite(
self.rt_packet, self.outputs) self.rt_packet, self.outputs)
self.clock_domains.cd_rio = ClockDomain()
self.clock_domains.cd_rio_phy = ClockDomain()
self.comb += [
self.cd_rio.clk.eq(ClockSignal("rtio")),
self.cd_rio.rst.eq(self.rt_packet.reset),
self.cd_rio_phy.clk.eq(ClockSignal("rtio")),
self.cd_rio_phy.rst.eq(self.rt_packet.reset_phy),
]
self.submodules.aux_controller = aux_controller.AuxController( self.submodules.aux_controller = aux_controller.AuxController(
self.link_layer) self.link_layer)
def get_csrs(self): def get_csrs(self):
return (self.link_layer.get_csrs() + self.link_stats.get_csrs() + return ([self.reset, self.reset_phy] +
self.link_layer.get_csrs() + self.link_stats.get_csrs() +
self.rt_errors.get_csrs() + self.aux_controller.get_csrs()) self.rt_errors.get_csrs() + self.aux_controller.get_csrs())

View File

@ -13,14 +13,14 @@ from artiq.gateware.rtio import cri
class _CSRs(AutoCSR): class _CSRs(AutoCSR):
def __init__(self): def __init__(self):
self.reset = CSR()
self.protocol_error = CSR(3) self.protocol_error = CSR(3)
self.tsc_correction = CSRStorage(64) self.tsc_correction = CSRStorage(64)
self.set_time = CSR() self.set_time = CSR()
self.underflow_margin = CSRStorage(16, reset=200) self.underflow_margin = CSRStorage(16, reset=200)
self.reset = CSR()
self.reset_phy = CSR()
self.o_get_buffer_space = CSR() self.o_get_buffer_space = CSR()
self.o_dbg_buffer_space = CSRStatus(16) self.o_dbg_buffer_space = CSRStatus(16)
@ -51,6 +51,19 @@ class RTController(Module):
self.csrs = _CSRs() self.csrs = _CSRs()
self.cri = cri.Interface() self.cri = cri.Interface()
# reset
local_reset = Signal(reset=1)
self.sync += local_reset.eq(self.csrs.reset.re)
local_reset.attr.add("no_retiming")
self.clock_domains.cd_sys_with_rst = ClockDomain()
self.clock_domains.cd_rtio_with_rst = ClockDomain()
self.comb += [
self.cd_sys_with_rst.clk.eq(ClockSignal()),
self.cd_sys_with_rst.rst.eq(local_reset)
]
self.comb += self.cd_rtio_with_rst.clk.eq(ClockSignal("rtio"))
self.specials += AsyncResetSynchronizer(self.cd_rtio_with_rst, local_reset)
# protocol errors # protocol errors
err_unknown_packet_type = Signal() err_unknown_packet_type = Signal()
err_packet_truncated = Signal() err_packet_truncated = Signal()
@ -85,31 +98,6 @@ class RTController(Module):
If(self.csrs.set_time.re, rt_packet.set_time_stb.eq(1)) If(self.csrs.set_time.re, rt_packet.set_time_stb.eq(1))
] ]
# reset
self.sync += [
If(rt_packet.reset_ack, rt_packet.reset_stb.eq(0)),
If(self.csrs.reset.re,
rt_packet.reset_stb.eq(1),
rt_packet.reset_phy.eq(0)
),
If(self.csrs.reset_phy.re,
rt_packet.reset_stb.eq(1),
rt_packet.reset_phy.eq(1)
),
]
local_reset = Signal(reset=1)
self.sync += local_reset.eq(self.csrs.reset.re)
local_reset.attr.add("no_retiming")
self.clock_domains.cd_sys_with_rst = ClockDomain()
self.clock_domains.cd_rtio_with_rst = ClockDomain()
self.comb += [
self.cd_sys_with_rst.clk.eq(ClockSignal()),
self.cd_sys_with_rst.rst.eq(local_reset)
]
self.comb += self.cd_rtio_with_rst.clk.eq(ClockSignal("rtio"))
self.specials += AsyncResetSynchronizer(self.cd_rtio_with_rst, local_reset)
# common packet fields # common packet fields
chan_sel = self.cri.chan_sel[:16] chan_sel = self.cri.chan_sel[:16]
rt_packet_buffer_request = Signal() rt_packet_buffer_request = Signal()

View File

@ -111,11 +111,6 @@ class RTPacketMaster(Module):
# a set_time request pending # a set_time request pending
self.tsc_value = Signal(64) self.tsc_value = Signal(64)
# reset interface
self.reset_stb = Signal()
self.reset_ack = Signal()
self.reset_phy = Signal()
# rx errors # rx errors
self.err_unknown_packet_type = Signal() self.err_unknown_packet_type = Signal()
self.err_packet_truncated = Signal() self.err_packet_truncated = Signal()
@ -221,13 +216,6 @@ class RTPacketMaster(Module):
self.set_time_stb, self.set_time_ack, None, self.set_time_stb, self.set_time_ack, None,
set_time_stb, set_time_ack, None) set_time_stb, set_time_ack, None)
reset_stb = Signal()
reset_ack = Signal()
reset_phy = Signal()
self.submodules += _CrossDomainRequest("rtio",
self.reset_stb, self.reset_ack, self.reset_phy,
reset_stb, reset_ack, reset_phy)
echo_stb = Signal() echo_stb = Signal()
echo_ack = Signal() echo_ack = Signal()
self.submodules += _CrossDomainRequest("rtio", self.submodules += _CrossDomainRequest("rtio",
@ -287,8 +275,6 @@ class RTPacketMaster(Module):
).Elif(set_time_stb, ).Elif(set_time_stb,
tsc_value_load.eq(1), tsc_value_load.eq(1),
NextState("SET_TIME") NextState("SET_TIME")
).Elif(reset_stb,
NextState("RESET")
) )
) )
) )
@ -344,13 +330,6 @@ class RTPacketMaster(Module):
NextState("IDLE") NextState("IDLE")
) )
) )
tx_fsm.act("RESET",
tx_dp.send("reset", phy=reset_phy),
If(tx_dp.packet_last,
reset_ack.eq(1),
NextState("IDLE")
)
)
# RX FSM # RX FSM
rx_fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="INPUT")) rx_fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="INPUT"))

View File

@ -9,15 +9,14 @@ from artiq.gateware.drtio.rt_serializer import *
class RTPacketSatellite(Module): class RTPacketSatellite(Module):
def __init__(self, link_layer): def __init__(self, link_layer):
self.reset = Signal()
self.unknown_packet_type = Signal() self.unknown_packet_type = Signal()
self.packet_truncated = Signal() self.packet_truncated = Signal()
self.tsc_load = Signal() self.tsc_load = Signal()
self.tsc_load_value = Signal(64) self.tsc_load_value = Signal(64)
self.reset = Signal(reset=1)
self.reset_phy = Signal(reset=1)
self.cri = cri.Interface() self.cri = cri.Interface()
# # # # # #
@ -97,13 +96,6 @@ class RTPacketSatellite(Module):
Cat(rx_dp.packet_as["write"].short_data, write_data_buffer)), Cat(rx_dp.packet_as["write"].short_data, write_data_buffer)),
] ]
reset = Signal()
reset_phy = Signal()
self.sync += [
self.reset.eq(reset),
self.reset_phy.eq(reset_phy)
]
rx_fsm = FSM(reset_state="INPUT") rx_fsm = FSM(reset_state="INPUT")
self.submodules += rx_fsm self.submodules += rx_fsm
@ -120,7 +112,6 @@ class RTPacketSatellite(Module):
# mechanism # mechanism
rx_plm.types["echo_request"]: echo_req.eq(1), rx_plm.types["echo_request"]: echo_req.eq(1),
rx_plm.types["set_time"]: NextState("SET_TIME"), rx_plm.types["set_time"]: NextState("SET_TIME"),
rx_plm.types["reset"]: NextState("RESET"),
rx_plm.types["write"]: NextState("WRITE"), rx_plm.types["write"]: NextState("WRITE"),
rx_plm.types["buffer_space_request"]: NextState("BUFFER_SPACE"), rx_plm.types["buffer_space_request"]: NextState("BUFFER_SPACE"),
rx_plm.types["read_request"]: NextState("READ_REQUEST"), rx_plm.types["read_request"]: NextState("READ_REQUEST"),
@ -138,14 +129,6 @@ class RTPacketSatellite(Module):
self.tsc_load.eq(1), self.tsc_load.eq(1),
NextState("INPUT") NextState("INPUT")
) )
rx_fsm.act("RESET",
If(rx_dp.packet_as["reset"].phy,
reset_phy.eq(1)
).Else(
reset.eq(1)
),
NextState("INPUT")
)
rx_fsm.act("WRITE", rx_fsm.act("WRITE",
If(write_data_buffer_cnt == rx_dp.packet_as["write"].extra_data_cnt, If(write_data_buffer_cnt == rx_dp.packet_as["write"].extra_data_cnt,

View File

@ -47,7 +47,6 @@ def get_m2s_layouts(alignment):
plm.add_type("echo_request") plm.add_type("echo_request")
plm.add_type("set_time", ("timestamp", 64)) plm.add_type("set_time", ("timestamp", 64))
plm.add_type("reset", ("phy", 1))
plm.add_type("write", ("timestamp", 64), plm.add_type("write", ("timestamp", 64),
("channel", 16), ("channel", 16),