From ae72e3a51efaf472eca899b704109b50c9503508 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 14 Sep 2018 20:26:39 +0800 Subject: [PATCH] firmware: add support for moninj and kern_hwreq over DRTIO switching --- artiq/firmware/libboard_artiq/drtioaux.rs | 29 +- .../firmware/libproto_artiq/drtioaux_proto.rs | 66 +++-- artiq/firmware/runtime/kern_hwreq.rs | 255 ++++++----------- artiq/firmware/runtime/main.rs | 18 +- artiq/firmware/runtime/moninj.rs | 264 +++++++++--------- artiq/firmware/runtime/session.rs | 28 +- artiq/firmware/satman/main.rs | 54 +++- 7 files changed, 332 insertions(+), 382 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtioaux.rs b/artiq/firmware/libboard_artiq/drtioaux.rs index d176e67da..a0465b230 100644 --- a/artiq/firmware/libboard_artiq/drtioaux.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -10,9 +10,6 @@ pub use proto_artiq::drtioaux_proto::Packet; // this is parametric over T because there's no impl Fail for !. #[derive(Fail, Debug)] pub enum Error { - #[fail(display = "invalid node number")] - NoRoute, - #[fail(display = "gateware reported error")] GatewareError, #[fail(display = "packet CRC failed")] @@ -25,6 +22,9 @@ pub enum Error { #[fail(display = "unexpected reply")] UnexpectedReply, + #[fail(display = "routing error")] + RoutingError, + #[fail(display = "protocol error: {}", _0)] Protocol(#[cause] ProtocolError) } @@ -150,26 +150,3 @@ pub fn send_link(linkno: u8, packet: &Packet) -> Result<(), Error> { Ok(writer.position()) }) } - -// TODO: routing -fn get_linkno(nodeno: u8) -> Result> { - if nodeno == 0 || nodeno as usize > DRTIOAUX.len() { - return Err(Error::NoRoute) - } - Ok(nodeno - 1) -} - -pub fn recv(nodeno: u8) -> Result, Error> { - let linkno = get_linkno(nodeno)?; - recv_link(linkno) -} - -pub fn recv_timeout(nodeno: u8, timeout_ms: Option) -> Result> { - let linkno = get_linkno(nodeno)?; - recv_timeout_link(linkno, timeout_ms) -} - -pub fn send(nodeno: u8, packet: &Packet) -> Result<(), Error> { - let linkno = get_linkno(nodeno)?; - send_link(linkno, packet) -} diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 288913282..3d526734d 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -33,24 +33,24 @@ pub enum Packet { RoutingSetRank { rank: u8 }, RoutingAck, - MonitorRequest { channel: u16, probe: u8 }, + MonitorRequest { destination: u8, channel: u16, probe: u8 }, MonitorReply { value: u32 }, - InjectionRequest { channel: u16, overrd: u8, value: u8 }, - InjectionStatusRequest { channel: u16, overrd: u8 }, + InjectionRequest { destination: u8, channel: u16, overrd: u8, value: u8 }, + InjectionStatusRequest { destination: u8, channel: u16, overrd: u8 }, InjectionStatusReply { value: u8 }, - I2cStartRequest { busno: u8 }, - I2cRestartRequest { busno: u8 }, - I2cStopRequest { busno: u8 }, - I2cWriteRequest { busno: u8, data: u8 }, + I2cStartRequest { destination: u8, busno: u8 }, + I2cRestartRequest { destination: u8, busno: u8 }, + I2cStopRequest { destination: u8, busno: u8 }, + I2cWriteRequest { destination: u8, busno: u8, data: u8 }, I2cWriteReply { succeeded: bool, ack: bool }, - I2cReadRequest { busno: u8, ack: bool }, + I2cReadRequest { destination: u8, busno: u8, ack: bool }, I2cReadReply { succeeded: bool, data: u8 }, I2cBasicReply { succeeded: bool }, - SpiSetConfigRequest { busno: u8, flags: u8, length: u8, div: u8, cs: u8 }, - SpiWriteRequest { busno: u8, data: u32 }, - SpiReadRequest { busno: u8 }, + SpiSetConfigRequest { destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8 }, + SpiWriteRequest { destination: u8, busno: u8, data: u32 }, + SpiReadRequest { destination: u8, busno: u8 }, SpiReadReply { succeeded: bool, data: u32 }, SpiBasicReply { succeeded: bool }, } @@ -98,6 +98,7 @@ impl Packet { 0x32 => Packet::RoutingAck, 0x40 => Packet::MonitorRequest { + destination: reader.read_u8()?, channel: reader.read_u16()?, probe: reader.read_u8()? }, @@ -105,11 +106,13 @@ impl Packet { value: reader.read_u32()? }, 0x50 => Packet::InjectionRequest { + destination: reader.read_u8()?, channel: reader.read_u16()?, overrd: reader.read_u8()?, value: reader.read_u8()? }, 0x51 => Packet::InjectionStatusRequest { + destination: reader.read_u8()?, channel: reader.read_u16()?, overrd: reader.read_u8()? }, @@ -118,15 +121,19 @@ impl Packet { }, 0x80 => Packet::I2cStartRequest { + destination: reader.read_u8()?, busno: reader.read_u8()? }, 0x81 => Packet::I2cRestartRequest { + destination: reader.read_u8()?, busno: reader.read_u8()? }, 0x82 => Packet::I2cStopRequest { + destination: reader.read_u8()?, busno: reader.read_u8()? }, 0x83 => Packet::I2cWriteRequest { + destination: reader.read_u8()?, busno: reader.read_u8()?, data: reader.read_u8()? }, @@ -135,6 +142,7 @@ impl Packet { ack: reader.read_bool()? }, 0x85 => Packet::I2cReadRequest { + destination: reader.read_u8()?, busno: reader.read_u8()?, ack: reader.read_bool()? }, @@ -147,6 +155,7 @@ impl Packet { }, 0x90 => Packet::SpiSetConfigRequest { + destination: reader.read_u8()?, busno: reader.read_u8()?, flags: reader.read_u8()?, length: reader.read_u8()?, @@ -155,10 +164,12 @@ impl Packet { }, /* 0x91: was Packet::SpiSetXferRequest */ 0x92 => Packet::SpiWriteRequest { + destination: reader.read_u8()?, busno: reader.read_u8()?, data: reader.read_u32()? }, 0x93 => Packet::SpiReadRequest { + destination: reader.read_u8()?, busno: reader.read_u8()? }, 0x94 => Packet::SpiReadReply { @@ -223,8 +234,9 @@ impl Packet { Packet::RoutingAck => writer.write_u8(0x32)?, - Packet::MonitorRequest { channel, probe } => { + Packet::MonitorRequest { destination, channel, probe } => { writer.write_u8(0x40)?; + writer.write_u8(destination)?; writer.write_u16(channel)?; writer.write_u8(probe)?; }, @@ -232,14 +244,16 @@ impl Packet { writer.write_u8(0x41)?; writer.write_u32(value)?; }, - Packet::InjectionRequest { channel, overrd, value } => { + Packet::InjectionRequest { destination, channel, overrd, value } => { writer.write_u8(0x50)?; + writer.write_u8(destination)?; writer.write_u16(channel)?; writer.write_u8(overrd)?; writer.write_u8(value)?; }, - Packet::InjectionStatusRequest { channel, overrd } => { + Packet::InjectionStatusRequest { destination, channel, overrd } => { writer.write_u8(0x51)?; + writer.write_u8(destination)?; writer.write_u16(channel)?; writer.write_u8(overrd)?; }, @@ -248,20 +262,24 @@ impl Packet { writer.write_u8(value)?; }, - Packet::I2cStartRequest { busno } => { + Packet::I2cStartRequest { destination, busno } => { writer.write_u8(0x80)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; }, - Packet::I2cRestartRequest { busno } => { + Packet::I2cRestartRequest { destination, busno } => { writer.write_u8(0x81)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; }, - Packet::I2cStopRequest { busno } => { + Packet::I2cStopRequest { destination, busno } => { writer.write_u8(0x82)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; }, - Packet::I2cWriteRequest { busno, data } => { + Packet::I2cWriteRequest { destination, busno, data } => { writer.write_u8(0x83)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; writer.write_u8(data)?; }, @@ -270,8 +288,9 @@ impl Packet { writer.write_bool(succeeded)?; writer.write_bool(ack)?; }, - Packet::I2cReadRequest { busno, ack } => { + Packet::I2cReadRequest { destination, busno, ack } => { writer.write_u8(0x85)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; writer.write_bool(ack)?; }, @@ -285,21 +304,24 @@ impl Packet { writer.write_bool(succeeded)?; }, - Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => { + Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { writer.write_u8(0x90)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; writer.write_u8(flags)?; writer.write_u8(length)?; writer.write_u8(div)?; writer.write_u8(cs)?; }, - Packet::SpiWriteRequest { busno, data } => { + Packet::SpiWriteRequest { destination, busno, data } => { writer.write_u8(0x92)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; writer.write_u32(data)?; }, - Packet::SpiReadRequest { busno } => { + Packet::SpiReadRequest { destination, busno } => { writer.write_u8(0x93)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; }, Packet::SpiReadReply { succeeded, data } => { diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index c1bfbf7b0..00d20be3b 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -2,13 +2,16 @@ use kernel_proto as kern; use sched::{Io, Error as SchedError}; use session::{kern_acknowledge, kern_send, Error}; use rtio_mgt; +use board_artiq::drtio_routing; +use board_artiq::i2c as local_i2c; +use board_artiq::spi as local_spi; #[cfg(has_drtio)] -mod drtio_i2c { +mod remote_i2c { use drtioaux; - fn basic_reply(nodeno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout(nodeno, None) { + fn basic_reply(linkno: u8) -> Result<(), ()> { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } @@ -23,39 +26,49 @@ mod drtio_i2c { } } - pub fn start(nodeno: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cStartRequest { busno: busno }; - if drtioaux::send(nodeno, &request).is_err() { + pub fn start(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let request = drtioaux::Packet::I2cStartRequest { + destination: destination, + busno: busno + }; + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn restart(nodeno: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cRestartRequest { busno: busno }; - if drtioaux::send(nodeno, &request).is_err() { + pub fn restart(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let request = drtioaux::Packet::I2cRestartRequest { + destination: destination, + busno: busno + }; + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn stop(nodeno: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cStopRequest { busno: busno }; - if drtioaux::send(nodeno, &request).is_err() { + pub fn stop(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let request = drtioaux::Packet::I2cStopRequest { + destination: destination, + busno: busno + }; + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn write(nodeno: u8, busno: u8, data: u8) -> Result { + pub fn write(linkno: u8, destination: u8, busno: u8, data: u8) -> Result { let request = drtioaux::Packet::I2cWriteRequest { + destination: destination, busno: busno, data: data }; - if drtioaux::send(nodeno, &request).is_err() { + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::I2cWriteReply { succeeded, ack }) => { if succeeded { Ok(ack) } else { Err(()) } } @@ -70,15 +83,16 @@ mod drtio_i2c { } } - pub fn read(nodeno: u8, busno: u8, ack: bool) -> Result { + pub fn read(linkno: u8, destination: u8, busno: u8, ack: bool) -> Result { let request = drtioaux::Packet::I2cReadRequest { + destination: destination, busno: busno, ack: ack }; - if drtioaux::send(nodeno, &request).is_err() { + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::I2cReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } @@ -94,90 +108,12 @@ mod drtio_i2c { } } -#[cfg(not(has_drtio))] -mod drtio_i2c { - pub fn start(_nodeno: u8, _busno: u8) -> Result<(), ()> { - Err(()) - } - - pub fn restart(_nodeno: u8, _busno: u8) -> Result<(), ()> { - Err(()) - } - - pub fn stop(_nodeno: u8, _busno: u8) -> Result<(), ()> { - Err(()) - } - - pub fn write(_nodeno: u8, _busno: u8, _data: u8) -> Result { - Err(()) - } - - pub fn read(_nodeno: u8, _busno: u8, _ack: bool) -> Result { - Err(()) - } -} - -mod i2c { - use board_artiq::i2c as local_i2c; - use super::drtio_i2c; - - pub fn start(busno: u32) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::start(node_busno) - } else { - drtio_i2c::start(nodeno, node_busno) - } - } - - pub fn restart(busno: u32) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::restart(node_busno) - } else { - drtio_i2c::restart(nodeno, node_busno) - } - } - - pub fn stop(busno: u32) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::stop(node_busno) - } else { - drtio_i2c::stop(nodeno, node_busno) - } - } - - pub fn write(busno: u32, data: u8) -> Result { - let nodeno = (busno >> 16 )as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::write(node_busno, data) - } else { - drtio_i2c::write(nodeno, node_busno, data) - } - } - - pub fn read(busno: u32, ack: bool) -> Result { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::read(node_busno, ack) - } else { - drtio_i2c::read(nodeno, node_busno, ack) - } - } -} - #[cfg(has_drtio)] -mod drtio_spi { +mod remote_spi { use drtioaux; - fn basic_reply(nodeno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout(nodeno, None) { + fn basic_reply(linkno: u8) -> Result<(), ()> { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } @@ -192,37 +128,42 @@ mod drtio_spi { } } - pub fn set_config(nodeno: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { + pub fn set_config(linkno: u8, destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { let request = drtioaux::Packet::SpiSetConfigRequest { + destination: destination, busno: busno, flags: flags, length: length, div: div, cs: cs }; - if drtioaux::send(nodeno, &request).is_err() { + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn write(nodeno: u8, busno: u8, data: u32) -> Result<(), ()> { + pub fn write(linkno: u8, destination: u8, busno: u8, data: u32) -> Result<(), ()> { let request = drtioaux::Packet::SpiWriteRequest { + destination: destination, busno: busno, data: data }; - if drtioaux::send(nodeno, &request).is_err() { + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn read(nodeno: u8, busno: u8) -> Result { - let request = drtioaux::Packet::SpiReadRequest { busno: busno }; - if drtioaux::send(nodeno, &request).is_err() { + pub fn read(linkno: u8, destination: u8, busno: u8) -> Result { + let request = drtioaux::Packet::SpiReadRequest { + destination: destination, + busno: busno + }; + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::SpiReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } @@ -238,58 +179,32 @@ mod drtio_spi { } } + +#[cfg(has_drtio)] +macro_rules! dispatch { + ($mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ + let destination = ($busno >> 16) as u8; + let busno = $busno as u8; + let hop = $routing_table.0[destination as usize][0]; + if hop == 0 { + $mod_local::$func(busno, $($param, )*) + } else { + let linkno = hop - 1; + $mod_remote::$func(linkno, destination, busno, $($param, )*) + } + }} +} + #[cfg(not(has_drtio))] -mod drtio_spi { - pub fn set_config(_nodeno: u8, _busno: u8, _flags: u8, - _length: u8, _div: u8, _cs: u8) -> Result<(), ()> { - Err(()) - } - - pub fn write(_nodeno: u8, _busno: u8, _data: u32) -> Result<(), ()> { - Err(()) - } - - pub fn read(_nodeno: u8, _busno: u8) -> Result { - Err(()) - } +macro_rules! dispatch { + ($mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ + let busno = $busno as u8; + $mod_local::$func(busno, $($param, )*) + }} } -mod spi { - use board_artiq::spi as local_spi; - use super::drtio_spi; - - pub fn set_config(busno: u32, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_spi::set_config(node_busno, flags, length, div, cs) - } else { - drtio_spi::set_config(nodeno, node_busno, flags, length, div, cs) - } - } - - pub fn write(busno: u32, data: u32) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_spi::write(node_busno, data) - } else { - drtio_spi::write(nodeno, node_busno, data) - } - } - - pub fn read(busno: u32) -> Result { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_spi::read(node_busno) - } else { - drtio_spi::read(nodeno, node_busno) - } - } -} - -pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result> { +pub fn process_kern_hwreq(io: &Io, _routing_table: &drtio_routing::RoutingTable, + request: &kern::Message) -> Result> { match request { &kern::RtioInitRequest => { info!("resetting RTIO"); @@ -303,40 +218,42 @@ pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result { - let succeeded = i2c::start(busno).is_ok(); + let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, start).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cRestartRequest { busno } => { - let succeeded = i2c::restart(busno).is_ok(); + let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, restart).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cStopRequest { busno } => { - let succeeded = i2c::stop(busno).is_ok(); + let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, stop).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cWriteRequest { busno, data } => { - match i2c::write(busno, data) { + match dispatch!(local_i2c, remote_i2c, _routing_table, busno, write, data) { Ok(ack) => kern_send(io, &kern::I2cWriteReply { succeeded: true, ack: ack }), Err(_) => kern_send(io, &kern::I2cWriteReply { succeeded: false, ack: false }) } } &kern::I2cReadRequest { busno, ack } => { - match i2c::read(busno, ack) { + match dispatch!(local_i2c, remote_i2c, _routing_table, busno, read, ack) { Ok(data) => kern_send(io, &kern::I2cReadReply { succeeded: true, data: data }), Err(_) => kern_send(io, &kern::I2cReadReply { succeeded: false, data: 0xff }) } } &kern::SpiSetConfigRequest { busno, flags, length, div, cs } => { - let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); + let succeeded = dispatch!(local_spi, remote_spi, _routing_table, busno, + set_config, flags, length, div, cs).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) }, &kern::SpiWriteRequest { busno, data } => { - let succeeded = spi::write(busno, data).is_ok(); + let succeeded = dispatch!(local_spi, remote_spi, _routing_table, busno, + write, data).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) } &kern::SpiReadRequest { busno } => { - match spi::read(busno) { + match dispatch!(local_spi, remote_spi, _routing_table, busno, read) { Ok(data) => kern_send(io, &kern::SpiReadReply { succeeded: true, data: data }), Err(_) => kern_send(io, &kern::SpiReadReply { succeeded: false, data: 0 }) } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 555f5adce..16f0fca05 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -282,22 +282,28 @@ fn startup_ethernet() { .ip_addrs([IpCidr::new(protocol_addr, 0)]) .finalize(); - #[cfg(has_drtio_routing)] + #[cfg(has_drtio)] let drtio_routing_table = urc::Urc::new(RefCell::new( drtio_routing::config_routing_table(csr::DRTIO.len()))); + #[cfg(not(has_drtio))] + let drtio_routing_table = urc::Urc::new(RefCell::new( + drtio_routing::RoutingTable::default_empty())); let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); - #[cfg(has_drtio_routing)] rtio_mgt::startup(&io, &drtio_routing_table); - #[cfg(not(has_drtio_routing))] - rtio_mgt::startup(&io, &drtio_routing::RoutingTable::default_empty()); io.spawn(4096, mgmt::thread); - io.spawn(16384, session::thread); + { + let drtio_routing_table = drtio_routing_table.clone(); + io.spawn(16384, move |io| { session::thread(io, &drtio_routing_table) }); + } #[cfg(any(has_rtio_moninj, has_drtio))] - io.spawn(4096, moninj::thread); + { + let drtio_routing_table = drtio_routing_table.clone(); + io.spawn(4096, move |io| { moninj::thread(io, &drtio_routing_table) }); + } #[cfg(has_rtio_analyzer)] io.spawn(4096, analyzer::thread); diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index 665927e39..a1a0765ac 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -1,151 +1,137 @@ use alloc::btree_map::BTreeMap; +use core::cell::RefCell; use io::Error as IoError; use moninj_proto::*; use sched::{Io, TcpListener, TcpStream, Error as SchedError}; -use board_misoc::{clock, csr}; -#[cfg(has_drtio)] -use drtioaux; +use urc::Urc; +use board_misoc::clock; +use board_artiq::drtio_routing; #[cfg(has_rtio_moninj)] -fn read_probe_local(channel: u16, probe: u8) -> u32 { - unsafe { - csr::rtio_moninj::mon_chan_sel_write(channel as _); - csr::rtio_moninj::mon_probe_sel_write(probe); - csr::rtio_moninj::mon_value_update_write(1); - csr::rtio_moninj::mon_value_read() as u32 +mod local_moninj { + use board_misoc::csr; + + pub fn read_probe(channel: u16, probe: u8) -> u32 { + unsafe { + csr::rtio_moninj::mon_chan_sel_write(channel as _); + csr::rtio_moninj::mon_probe_sel_write(probe); + csr::rtio_moninj::mon_value_update_write(1); + csr::rtio_moninj::mon_value_read() as u32 + } + } + + pub fn inject(channel: u16, overrd: u8, value: u8) { + unsafe { + csr::rtio_moninj::inj_chan_sel_write(channel as _); + csr::rtio_moninj::inj_override_sel_write(overrd); + csr::rtio_moninj::inj_value_write(value); + } + } + + pub fn read_injection_status(channel: u16, overrd: u8) -> u8 { + unsafe { + csr::rtio_moninj::inj_chan_sel_write(channel as _); + csr::rtio_moninj::inj_override_sel_write(overrd); + csr::rtio_moninj::inj_value_read() + } + } +} + +#[cfg(not(has_rtio_moninj))] +mod local_moninj { + pub fn read_probe(_channel: u16, _probe: u8) -> u32 { 0 } + + pub fn inject(_channel: u16, _overrd: u8, _value: u8) { } + + pub fn read_injection_status(_channel: u16, _overrd: u8) -> u8 { 0 } +} + +#[cfg(has_drtio)] +mod remote_moninj { + use drtioaux; + + pub fn read_probe(linkno: u8, destination: u8, channel: u16, probe: u8) -> u32 { + let request = drtioaux::Packet::MonitorRequest { + destination: destination, + channel: channel, + probe: probe + }; + match drtioaux::send_link(linkno, &request) { + Ok(_) => (), + Err(e) => { + error!("aux packet error ({})", e); + return 0; + } + } + match drtioaux::recv_timeout_link(linkno, None) { + Ok(drtioaux::Packet::MonitorReply { value }) => return value, + Ok(_) => error!("received unexpected aux packet"), + Err(e) => error!("aux packet error ({})", e) + } + 0 + } + + pub fn inject(linkno: u8, destination: u8, channel: u16, overrd: u8, value: u8) { + let request = drtioaux::Packet::InjectionRequest { + destination: destination, + channel: channel, + overrd: overrd, + value: value + }; + match drtioaux::send_link(linkno, &request) { + Ok(_) => (), + Err(e) => error!("aux packet error ({})", e) + } + } + + pub fn read_injection_status(linkno: u8, destination: u8, channel: u16, overrd: u8) -> u8 { + let request = drtioaux::Packet::InjectionStatusRequest { + destination: destination, + channel: channel, + overrd: overrd + }; + match drtioaux::send_link(linkno, &request) { + Ok(_) => (), + Err(e) => { + error!("aux packet error ({})", e); + return 0; + } + } + match drtioaux::recv_timeout_link(linkno, None) { + Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, + Ok(_) => error!("received unexpected aux packet"), + Err(e) => error!("aux packet error ({})", e) + } + 0 } } #[cfg(has_drtio)] -fn read_probe_drtio(nodeno: u8, channel: u16, probe: u8) -> u32 { - let request = drtioaux::Packet::MonitorRequest { channel: channel, probe: probe }; - match drtioaux::send(nodeno, &request) { - Ok(_) => (), - Err(e) => { - error!("aux packet error ({})", e); - return 0; +macro_rules! dispatch { + ($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ + let destination = ($channel >> 16) as u8; + let channel = $channel as u16; + let hop = $routing_table.0[destination as usize][0]; + if hop == 0 { + local_moninj::$func(channel, $($param, )*) + } else { + let linkno = hop - 1; + remote_moninj::$func(linkno, destination, channel, $($param, )*) } - } - match drtioaux::recv_timeout(nodeno, None) { - Ok(drtioaux::Packet::MonitorReply { value }) => return value, - Ok(_) => error!("received unexpected aux packet"), - Err(e) => error!("aux packet error ({})", e) - } - 0 + }} } -fn read_probe(channel: u32, probe: u8) -> u32 { - let nodeno = (channel >> 16) as u8; - let node_channel = channel as u16; - #[cfg(has_rtio_moninj)] - { - if nodeno == 0 { - return read_probe_local(node_channel, probe) - } - } - #[cfg(has_drtio)] - { - if nodeno != 0 { - return read_probe_drtio(nodeno, node_channel, probe) - } - } - error!("read_probe: unrecognized channel number {}", channel); - 0 +#[cfg(not(has_drtio))] +macro_rules! dispatch { + ($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ + let channel = $channel as u8; + local_moninj::$func(channel, $($param, )*) + }} } -#[cfg(has_rtio_moninj)] -fn inject_local(channel: u16, overrd: u8, value: u8) { - unsafe { - csr::rtio_moninj::inj_chan_sel_write(channel as _); - csr::rtio_moninj::inj_override_sel_write(overrd); - csr::rtio_moninj::inj_value_write(value); - } -} - -#[cfg(has_drtio)] -fn inject_drtio(nodeno: u8, channel: u16, overrd: u8, value: u8) { - let request = drtioaux::Packet::InjectionRequest { - channel: channel, - overrd: overrd, - value: value - }; - match drtioaux::send(nodeno, &request) { - Ok(_) => (), - Err(e) => error!("aux packet error ({})", e) - } -} - -fn inject(channel: u32, overrd: u8, value: u8) { - let nodeno = (channel >> 16) as u8; - let node_channel = channel as u16; - #[cfg(has_rtio_moninj)] - { - if nodeno == 0 { - inject_local(node_channel, overrd, value); - return - } - } - #[cfg(has_drtio)] - { - if nodeno != 0 { - inject_drtio(nodeno, node_channel, overrd, value); - return - } - } - error!("inject: unrecognized channel number {}", channel); -} - -#[cfg(has_rtio_moninj)] -fn read_injection_status_local(channel: u16, overrd: u8) -> u8 { - unsafe { - csr::rtio_moninj::inj_chan_sel_write(channel as _); - csr::rtio_moninj::inj_override_sel_write(overrd); - csr::rtio_moninj::inj_value_read() - } -} - -#[cfg(has_drtio)] -fn read_injection_status_drtio(nodeno: u8, channel: u16, overrd: u8) -> u8 { - let request = drtioaux::Packet::InjectionStatusRequest { - channel: channel, - overrd: overrd - }; - match drtioaux::send(nodeno, &request) { - Ok(_) => (), - Err(e) => { - error!("aux packet error ({})", e); - return 0; - } - } - match drtioaux::recv_timeout(nodeno, None) { - Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, - Ok(_) => error!("received unexpected aux packet"), - Err(e) => error!("aux packet error ({})", e) - } - 0 -} - -fn read_injection_status(channel: u32, probe: u8) -> u8 { - let nodeno = (channel >> 16) as u8; - let node_channel = channel as u16; - #[cfg(has_rtio_moninj)] - { - if nodeno == 0 { - return read_injection_status_local(node_channel, probe) - } - } - #[cfg(has_drtio)] - { - if nodeno != 0 { - return read_injection_status_drtio(nodeno, node_channel, probe) - } - } - error!("read_injection_status: unrecognized channel number {}", channel); - 0 -} - -fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error> { +fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, + mut stream: &mut TcpStream) -> Result<(), Error> { let mut probe_watch_list = BTreeMap::new(); let mut inject_watch_list = BTreeMap::new(); let mut next_check = 0; @@ -173,9 +159,9 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error inject(channel, overrd, value), + HostMessage::Inject { channel, overrd, value } => dispatch!(_routing_table, channel, inject, overrd, value), HostMessage::GetInjectionStatus { channel, overrd } => { - let value = read_injection_status(channel, overrd); + let value = dispatch!(_routing_table, channel, read_injection_status, overrd); let reply = DeviceMessage::InjectionStatus { channel: channel, overrd: overrd, @@ -192,7 +178,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error next_check { for (&(channel, probe), previous) in probe_watch_list.iter_mut() { - let current = read_probe(channel, probe); + let current = dispatch!(_routing_table, channel, read_probe, probe); if previous.is_none() || previous.unwrap() != current { let message = DeviceMessage::MonitorStatus { channel: channel, @@ -207,7 +193,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error Result<(), Error>) { let listener = TcpListener::new(&io, 2047); listener.listen(1383).expect("moninj: cannot listen"); loop { + let routing_table = routing_table.clone(); let stream = listener.accept().expect("moninj: cannot accept").into_handle(); io.spawn(16384, move |io| { + let routing_table = routing_table.borrow(); let mut stream = TcpStream::from_handle(&io, stream); - match connection_worker(&io, &mut stream) { + match connection_worker(&io, &routing_table, &mut stream) { Ok(()) => {}, Err(err) => error!("moninj aborted: {}", err) } diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index d5a2722d2..4c081810e 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -12,6 +12,7 @@ use rtio_dma::Manager as DmaManager; use cache::Cache; use kern_hwreq; use watchdog::WatchdogSet; +use board_artiq::drtio_routing; use rpc_proto as rpc; use session_proto as host; @@ -323,7 +324,8 @@ fn process_host_message(io: &Io, Ok(()) } -fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, +fn process_kern_message(io: &Io, routing_table: &drtio_routing::RoutingTable, + mut stream: Option<&mut TcpStream>, session: &mut Session) -> Result> { kern_recv_notrace(io, |request| { match (request, session.kernel_state) { @@ -341,7 +343,7 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, kern_recv_dotrace(request); - if kern_hwreq::process_kern_hwreq(io, request)? { + if kern_hwreq::process_kern_hwreq(io, routing_table, request)? { return Ok(false) } @@ -490,7 +492,7 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, }) } -fn host_kernel_worker(io: &Io, +fn host_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, stream: &mut TcpStream, congress: &mut Congress) -> Result<(), Error> { let mut session = Session::new(congress); @@ -507,7 +509,7 @@ fn host_kernel_worker(io: &Io, } if mailbox::receive() != 0 { - process_kern_message(io, Some(stream), &mut session)?; + process_kern_message(io, routing_table, Some(stream), &mut session)?; } if session.kernel_state == KernelState::Running { @@ -526,7 +528,7 @@ fn host_kernel_worker(io: &Io, } } -fn flash_kernel_worker(io: &Io, +fn flash_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, congress: &mut Congress, config_key: &str) -> Result<(), Error> { let mut session = Session::new(congress); @@ -549,7 +551,7 @@ fn flash_kernel_worker(io: &Io, } if mailbox::receive() != 0 { - if process_kern_message(io, None, &mut session)? { + if process_kern_message(io, routing_table, None, &mut session)? { return Ok(()) } } @@ -581,7 +583,7 @@ fn respawn(io: &Io, handle: &mut Option, f: F) *handle = Some(io.spawn(16384, f)) } -pub fn thread(io: Io) { +pub fn thread(io: Io, routing_table: &Urc>) { let listener = TcpListener::new(&io, 65535); listener.listen(1381).expect("session: cannot listen"); info!("accepting network sessions"); @@ -590,11 +592,13 @@ pub fn thread(io: Io) { let mut kernel_thread = None; { + let routing_table = routing_table.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { + let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); info!("running startup kernel"); - match flash_kernel_worker(&io, &mut congress, "startup_kernel") { + match flash_kernel_worker(&io, &routing_table, &mut congress, "startup_kernel") { Ok(()) => info!("startup kernel finished"), Err(Error::KernelNotFound) => @@ -623,12 +627,14 @@ pub fn thread(io: Io) { } info!("new connection from {}", stream.remote_endpoint()); + let routing_table = routing_table.clone(); let congress = congress.clone(); let stream = stream.into_handle(); respawn(&io, &mut kernel_thread, move |io| { + let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); let mut stream = TcpStream::from_handle(&io, stream); - match host_kernel_worker(&io, &mut stream, &mut *congress) { + match host_kernel_worker(&io, &routing_table, &mut stream, &mut *congress) { Ok(()) => (), Err(Error::Protocol(host::Error::Io(IoError::UnexpectedEnd))) => info!("connection closed"), @@ -646,10 +652,12 @@ pub fn thread(io: Io) { if kernel_thread.as_ref().map_or(true, |h| h.terminated()) { info!("no connection, starting idle kernel"); + let routing_table = routing_table.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { + let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); - match flash_kernel_worker(&io, &mut *congress, "idle_kernel") { + match flash_kernel_worker(&io, &routing_table, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), Err(Error::Protocol(host::Error::Io( diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 8e3b22e7d..1bb4c6155 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -46,6 +46,27 @@ fn drtiosat_tsc_loaded() -> bool { } } + +#[cfg(has_drtio_routing)] +macro_rules! forward { + ($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr) => {{ + let hop = $routing_table.0[$destination as usize][$rank as usize]; + if hop != 0 { + let repno = (hop - 1) as usize; + if repno < $repeaters.len() { + return $repeaters[repno].aux_forward($packet); + } else { + return Err(drtioaux::Error::RoutingError); + } + } + }} +} + +#[cfg(not(has_drtio_routing))] +macro_rules! forward { + ($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr) => {} +} + fn process_aux_packet(_repeaters: &mut [repeater::Repeater], _routing_table: &mut drtio_routing::RoutingTable, _rank: &mut u8, packet: drtioaux::Packet) -> Result<(), drtioaux::Error> { @@ -174,7 +195,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) } - drtioaux::Packet::MonitorRequest { channel, probe } => { + drtioaux::Packet::MonitorRequest { destination, channel, probe } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let value; #[cfg(has_rtio_moninj)] unsafe { @@ -190,7 +212,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], let reply = drtioaux::Packet::MonitorReply { value: value as u32 }; drtioaux::send_link(0, &reply) }, - drtioaux::Packet::InjectionRequest { channel, overrd, value } => { + drtioaux::Packet::InjectionRequest { destination, channel, overrd, value } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); #[cfg(has_rtio_moninj)] unsafe { csr::rtio_moninj::inj_chan_sel_write(channel as _); @@ -199,7 +222,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } Ok(()) }, - drtioaux::Packet::InjectionStatusRequest { channel, overrd } => { + drtioaux::Packet::InjectionStatusRequest { destination, channel, overrd } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let value; #[cfg(has_rtio_moninj)] unsafe { @@ -214,19 +238,23 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::send_link(0, &drtioaux::Packet::InjectionStatusReply { value: value }) }, - drtioaux::Packet::I2cStartRequest { busno } => { + drtioaux::Packet::I2cStartRequest { destination, busno } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::start(busno).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cRestartRequest { busno } => { + drtioaux::Packet::I2cRestartRequest { destination, busno } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::restart(busno).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cStopRequest { busno } => { + drtioaux::Packet::I2cStopRequest { destination, busno } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::stop(busno).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cWriteRequest { busno, data } => { + drtioaux::Packet::I2cWriteRequest { destination, busno, data } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); match i2c::write(busno, data) { Ok(ack) => drtioaux::send_link(0, &drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }), @@ -234,7 +262,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], &drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }) } } - drtioaux::Packet::I2cReadRequest { busno, ack } => { + drtioaux::Packet::I2cReadRequest { destination, busno, ack } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); match i2c::read(busno, ack) { Ok(data) => drtioaux::send_link(0, &drtioaux::Packet::I2cReadReply { succeeded: true, data: data }), @@ -243,17 +272,20 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } } - drtioaux::Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => { + drtioaux::Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) }, - drtioaux::Packet::SpiWriteRequest { busno, data } => { + drtioaux::Packet::SpiWriteRequest { destination, busno, data } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = spi::write(busno, data).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) } - drtioaux::Packet::SpiReadRequest { busno } => { + drtioaux::Packet::SpiReadRequest { destination, busno } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); match spi::read(busno) { Ok(data) => drtioaux::send_link(0, &drtioaux::Packet::SpiReadReply { succeeded: true, data: data }),