Skip to content

Commit

Permalink
runtime: fix DRTIO aux channel race condition
Browse files Browse the repository at this point in the history
  • Loading branch information
sbourdeauducq committed Sep 19, 2018
1 parent 970d1bf commit 6264295
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 201 deletions.
186 changes: 97 additions & 89 deletions artiq/firmware/runtime/kern_hwreq.rs
@@ -1,6 +1,6 @@
use core::cell::RefCell;
use kernel_proto as kern;
use sched::{Io, Error as SchedError};
use sched::{Io, Mutex, Error as SchedError};
use session::{kern_acknowledge, kern_send, Error};
use rtio_mgt;
use urc::Urc;
Expand All @@ -11,14 +11,20 @@ use board_artiq::spi as local_spi;
#[cfg(has_drtio)]
mod remote_i2c {
use drtioaux;
use rtio_mgt::drtio;
use sched::{Io, Mutex};

fn basic_reply(linkno: u8) -> Result<(), ()> {
match drtioaux::recv_timeout(linkno, None) {
pub fn start(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), ()> {
let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cStartRequest {
destination: destination,
busno: busno
});
match reply {
Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => {
if succeeded { Ok(()) } else { Err(()) }
}
Ok(_) => {
error!("received unexpected aux packet");
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Err(())
}
Err(e) => {
Expand All @@ -28,49 +34,53 @@ mod remote_i2c {
}
}

pub fn start(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> {
let request = drtioaux::Packet::I2cStartRequest {
pub fn restart(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), ()> {
let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cRestartRequest {
destination: destination,
busno: busno
};
if drtioaux::send(linkno, &request).is_err() {
return Err(())
}
basic_reply(linkno)
}

pub fn restart(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> {
let request = drtioaux::Packet::I2cRestartRequest {
destination: destination,
busno: busno
};
if drtioaux::send(linkno, &request).is_err() {
return Err(())
});
match reply {
Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => {
if succeeded { Ok(()) } else { Err(()) }
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Err(())
}
Err(e) => {
error!("aux packet error ({})", e);
Err(())
}
}
basic_reply(linkno)
}

pub fn stop(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> {
let request = drtioaux::Packet::I2cStopRequest {
pub fn stop(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), ()> {
let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cStopRequest {
destination: destination,
busno: busno
};
if drtioaux::send(linkno, &request).is_err() {
return Err(())
});
match reply {
Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => {
if succeeded { Ok(()) } else { Err(()) }
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Err(())
}
Err(e) => {
error!("aux packet error ({})", e);
Err(())
}
}
basic_reply(linkno)
}

pub fn write(linkno: u8, destination: u8, busno: u8, data: u8) -> Result<bool, ()> {
let request = drtioaux::Packet::I2cWriteRequest {
pub fn write(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, data: u8) -> Result<bool, ()> {
let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cWriteRequest {
destination: destination,
busno: busno,
data: data
};
if drtioaux::send(linkno, &request).is_err() {
return Err(())
}
match drtioaux::recv_timeout(linkno, None) {
});
match reply {
Ok(drtioaux::Packet::I2cWriteReply { succeeded, ack }) => {
if succeeded { Ok(ack) } else { Err(()) }
}
Expand All @@ -85,16 +95,13 @@ mod remote_i2c {
}
}

pub fn read(linkno: u8, destination: u8, busno: u8, ack: bool) -> Result<u8, ()> {
let request = drtioaux::Packet::I2cReadRequest {
pub fn read(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, ack: bool) -> Result<u8, ()> {
let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cReadRequest {
destination: destination,
busno: busno,
ack: ack
};
if drtioaux::send(linkno, &request).is_err() {
return Err(())
}
match drtioaux::recv_timeout(linkno, None) {
});
match reply {
Ok(drtioaux::Packet::I2cReadReply { succeeded, data }) => {
if succeeded { Ok(data) } else { Err(()) }
}
Expand All @@ -113,14 +120,24 @@ mod remote_i2c {
#[cfg(has_drtio)]
mod remote_spi {
use drtioaux;
use rtio_mgt::drtio;
use sched::{Io, Mutex};

fn basic_reply(linkno: u8) -> Result<(), ()> {
match drtioaux::recv_timeout(linkno, None) {
pub fn set_config(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> {
let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::SpiSetConfigRequest {
destination: destination,
busno: busno,
flags: flags,
length: length,
div: div,
cs: cs
});
match reply {
Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => {
if succeeded { Ok(()) } else { Err(()) }
}
Ok(_) => {
error!("received unexpected aux packet");
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Err(())
}
Err(e) => {
Expand All @@ -130,47 +147,38 @@ mod remote_spi {
}
}

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(linkno, &request).is_err() {
return Err(())
}
basic_reply(linkno)
}

pub fn write(linkno: u8, destination: u8, busno: u8, data: u32) -> Result<(), ()> {
let request = drtioaux::Packet::SpiWriteRequest {
pub fn write(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, data: u32) -> Result<(), ()> {
let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::SpiWriteRequest {
destination: destination,
busno: busno,
data: data
};
if drtioaux::send(linkno, &request).is_err() {
return Err(())
});
match reply {
Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => {
if succeeded { Ok(()) } else { Err(()) }
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Err(())
}
Err(e) => {
error!("aux packet error ({})", e);
Err(())
}
}
basic_reply(linkno)
}

pub fn read(linkno: u8, destination: u8, busno: u8) -> Result<u32, ()> {
let request = drtioaux::Packet::SpiReadRequest {
pub fn read(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<u32, ()> {
let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::SpiReadRequest {
destination: destination,
busno: busno
};
if drtioaux::send(linkno, &request).is_err() {
return Err(())
}
match drtioaux::recv_timeout(linkno, None) {
});
match reply {
Ok(drtioaux::Packet::SpiReadReply { succeeded, data }) => {
if succeeded { Ok(data) } else { Err(()) }
}
Ok(_) => {
error!("received unexpected aux packet");
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Err(())
}
Err(e) => {
Expand All @@ -184,35 +192,35 @@ mod remote_spi {

#[cfg(has_drtio)]
macro_rules! dispatch {
($mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{
($io:ident, $aux_mutex:ident, $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, )*)
$mod_remote::$func($io, $aux_mutex, linkno, destination, busno, $($param, )*)
}
}}
}

#[cfg(not(has_drtio))]
macro_rules! dispatch {
($mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{
($io:ident, $aux_mutex:ident,$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, )*)
}}
}

pub fn process_kern_hwreq(io: &Io,
pub fn process_kern_hwreq(io: &Io, aux_mutex: &Mutex,
_routing_table: &drtio_routing::RoutingTable,
_up_destinations: &Urc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
request: &kern::Message) -> Result<bool, Error<SchedError>> {
match request {
&kern::RtioInitRequest => {
info!("resetting RTIO");
rtio_mgt::init_core(false);
rtio_mgt::init_core(io, aux_mutex, false);
kern_acknowledge()
}

Expand All @@ -228,42 +236,42 @@ pub fn process_kern_hwreq(io: &Io,
}

&kern::I2cStartRequest { busno } => {
let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, start).is_ok();
let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, start).is_ok();
kern_send(io, &kern::I2cBasicReply { succeeded: succeeded })
}
&kern::I2cRestartRequest { busno } => {
let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, restart).is_ok();
let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, restart).is_ok();
kern_send(io, &kern::I2cBasicReply { succeeded: succeeded })
}
&kern::I2cStopRequest { busno } => {
let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, stop).is_ok();
let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, stop).is_ok();
kern_send(io, &kern::I2cBasicReply { succeeded: succeeded })
}
&kern::I2cWriteRequest { busno, data } => {
match dispatch!(local_i2c, remote_i2c, _routing_table, busno, write, data) {
match dispatch!(io, aux_mutex, 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 dispatch!(local_i2c, remote_i2c, _routing_table, busno, read, ack) {
match dispatch!(io, aux_mutex, 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 = dispatch!(local_spi, remote_spi, _routing_table, busno,
let succeeded = dispatch!(io, aux_mutex, 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 = dispatch!(local_spi, remote_spi, _routing_table, busno,
let succeeded = dispatch!(io, aux_mutex, local_spi, remote_spi, _routing_table, busno,
write, data).is_ok();
kern_send(io, &kern::SpiBasicReply { succeeded: succeeded })
}
&kern::SpiReadRequest { busno } => {
match dispatch!(local_spi, remote_spi, _routing_table, busno, read) {
match dispatch!(io, aux_mutex, 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 })
}
Expand Down
9 changes: 6 additions & 3 deletions artiq/firmware/runtime/main.rs
Expand Up @@ -289,22 +289,25 @@ fn startup_ethernet() {
drtio_routing::RoutingTable::default_empty()));
let up_destinations = urc::Urc::new(RefCell::new(
[false; drtio_routing::DEST_COUNT]));
let aux_mutex = sched::Mutex::new();

let mut scheduler = sched::Scheduler::new();
let io = scheduler.io();

rtio_mgt::startup(&io, &drtio_routing_table, &up_destinations);
rtio_mgt::startup(&io, &aux_mutex, &drtio_routing_table, &up_destinations);

io.spawn(4096, mgmt::thread);
{
let aux_mutex = aux_mutex.clone();
let drtio_routing_table = drtio_routing_table.clone();
let up_destinations = up_destinations.clone();
io.spawn(16384, move |io| { session::thread(io, &drtio_routing_table, &up_destinations) });
io.spawn(16384, move |io| { session::thread(io, &aux_mutex, &drtio_routing_table, &up_destinations) });
}
#[cfg(any(has_rtio_moninj, has_drtio))]
{
let aux_mutex = aux_mutex.clone();
let drtio_routing_table = drtio_routing_table.clone();
io.spawn(4096, move |io| { moninj::thread(io, &drtio_routing_table) });
io.spawn(4096, move |io| { moninj::thread(io, &aux_mutex, &drtio_routing_table) });
}
#[cfg(has_rtio_analyzer)]
io.spawn(4096, analyzer::thread);
Expand Down

0 comments on commit 6264295

Please sign in to comment.