Skip to content

Commit

Permalink
pin_controller: added api for node1 usb switch
Browse files Browse the repository at this point in the history
  • Loading branch information
svenrademakers committed Jun 14, 2024
1 parent 1ee8f5e commit 2fac14e
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 20 deletions.
19 changes: 15 additions & 4 deletions src/api/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ async fn api_entry(
("uart", true) => legacy_serial_set_handler(serial, query).await.into(),
("usb", true) => set_usb_mode(bmc, query).await.into(),
("usb", false) => get_usb_mode(bmc).await.into(),
("usb_node1", true) => set_node1_usb_mode(bmc, query).await.into(),
("usb_node1", false) => get_node1_usb_mode(bmc).await,
("info", false) => get_info().await.into(),
("cooling", false) => get_cooling_info().await.into(),
("cooling", true) => set_cooling_info(query).await.into(),
Expand Down Expand Up @@ -224,9 +226,7 @@ async fn get_about() -> impl Into<LegacyResponse> {
}

let hostname = read_hostname().await.unwrap_or_default();
let (board_model, board_revision) = read_board_model()
.await
.unwrap_or_default();
let (board_model, board_revision) = read_board_model().await.unwrap_or_default();

json!(
{
Expand Down Expand Up @@ -466,6 +466,16 @@ fn get_sdcard_info() -> LegacyResponse {
}
}

async fn set_node1_usb_mode(bmc: &BmcApplication, query: Query) -> LegacyResult<()> {
bmc.set_node1_usb_route(query.contains_key("alternative_port"))
.await
.map_err(Into::into)
}

async fn get_node1_usb_mode(bmc: &BmcApplication) -> LegacyResponse {
LegacyResponse::ok(bmc.get_node1_usb_route().await.into())
}

/// switches the USB configuration.
/// API values are mapped to the `UsbConfig` as followed:
///
Expand Down Expand Up @@ -512,7 +522,7 @@ async fn set_usb_mode(bmc: &BmcApplication, query: Query) -> LegacyResult<()> {

/// gets the USB configuration from the POV of the configured node.
async fn get_usb_mode(bmc: &BmcApplication) -> impl Into<LegacyResponse> {
let config = bmc.get_usb_mode().await;
let (config, bus_type) = bmc.get_usb_mode().await;

let (node, mode, route) = match config {
UsbConfig::UsbA(node) => (node, UsbMode::Device, UsbRoute::AlternativePort),
Expand All @@ -526,6 +536,7 @@ async fn get_usb_mode(bmc: &BmcApplication) -> impl Into<LegacyResponse> {
"mode": mode,
"node": node.to_string(),
"route": route,
"bus_type": bus_type,
}]
)
}
Expand Down
2 changes: 1 addition & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
// limitations under the License.
pub mod bmc_application;
pub mod bmc_info;
pub mod cooling_device;
pub mod event_application;
pub mod transfer_action;
pub mod upgrade_worker;
pub mod usb_gadget;
pub mod cooling_device;
22 changes: 20 additions & 2 deletions src/app/bmc_application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub const ACTIVATED_NODES_KEY: &str = "activated_nodes";
pub const USB_CONFIG: &str = "usb_config";
/// Stores information about nodes: name alias, time since powered on, and others. See [NodeInfo].
pub const NODE_INFO_KEY: &str = "node_info";
pub const NODE1_USB_MODE: &str = "node1_usb";

/// Describes the different configuration the USB bus can be setup
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -82,6 +83,7 @@ impl BmcApplication {
.register_key(ACTIVATED_NODES_KEY, &0u8)
.register_key(USB_CONFIG, &UsbConfig::UsbA(NodeId::Node1))
.register_key(NODE_INFO_KEY, &NodeInfos::default())
.register_key(NODE1_USB_MODE, &false)
.write_timeout(database_write_timeout)
.build()
.await?;
Expand Down Expand Up @@ -137,12 +139,18 @@ impl BmcApplication {
}

async fn initialize_usb_mode(&self) -> anyhow::Result<()> {
let alternative_port = self.app_db.get::<bool>(NODE1_USB_MODE).await;
self.pin_controller.set_node1_usb_route(alternative_port)?;

let config = self.app_db.get::<UsbConfig>(USB_CONFIG).await;
self.configure_usb(config).await.context("USB configure")
}

pub async fn get_usb_mode(&self) -> UsbConfig {
self.app_db.get::<UsbConfig>(USB_CONFIG).await
pub async fn get_usb_mode(&self) -> (UsbConfig, &'static str) {
(
self.app_db.get::<UsbConfig>(USB_CONFIG).await,
self.pin_controller.usb_bus_type(),
)
}

/// routine to support legacy API
Expand Down Expand Up @@ -204,6 +212,16 @@ impl BmcApplication {
.await;
}

pub async fn set_node1_usb_route(&self, alternative_port: bool) -> anyhow::Result<()> {
self.pin_controller.set_node1_usb_route(alternative_port)?;
self.app_db.set(NODE1_USB_MODE, alternative_port).await;
Ok(())
}

pub async fn get_node1_usb_route(&self) -> bool {
self.app_db.get::<bool>(NODE1_USB_MODE).await
}

pub async fn configure_usb(&self, config: UsbConfig) -> anyhow::Result<()> {
self.configure_usb_internal(config).await?;
self.app_db.set(USB_CONFIG, config).await;
Expand Down
4 changes: 3 additions & 1 deletion src/app/cooling_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ pub async fn get_cooling_state() -> Vec<CoolingDevice> {
}

pub async fn set_cooling_state(device: &str, speed: &c_ulong) -> anyhow::Result<()> {
let device_path = Path::new("/sys/class/thermal").join(device).join("cur_state");
let device_path = Path::new("/sys/class/thermal")
.join(device)
.join("cur_state");

tokio::fs::write(device_path, speed.to_string()).await?;

Expand Down
3 changes: 2 additions & 1 deletion src/app/upgrade_worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ impl UpgradeWorker {
bmc.activate_slot(node.to_inverse_bitfield(), node.to_bitfield())
.await?;
bmc.usb_boot(node, false).await?;
bmc.configure_usb(bmc.get_usb_mode().await).await?;
let (mode, _) = bmc.get_usb_mode().await;
bmc.configure_usb(mode).await?;
result
}

Expand Down
46 changes: 38 additions & 8 deletions src/hal/pin_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,6 @@ impl PinController {
let usb_switch = if has_usb_switch {
Box::new(UsbMuxSwitch::new(&chip0, &chip1)?) as Box<dyn UsbConfiguration + Send + Sync>
} else {
// the node1 switching is not yet implemented. Make sure that the
// switch routes the usb0 to the USB hub and usb2 to the the usbA
// port.
let node_source =
gpio_output_lines!(chip0, [NODE1_OUTPUT_SWITCH_V2_5, NODE1_SOURCE_SWITCH_V2_5]);
node_source.set_values(0u8)?;

Box::new(UsbHub::new(&chip0)?)
};

Expand Down Expand Up @@ -187,6 +180,15 @@ impl PinController {
Ok(())
}

pub fn set_node1_usb_route(&self, alternative_port: bool) -> Result<(), PowerControllerError> {
debug!("setting alternative port for Node 1 USB");
self.usb_switch.set_node1_usb_route(alternative_port)
}

pub fn usb_bus_type(&self) -> &'static str {
self.usb_switch.name()
}

pub async fn rtl_reset(&self) -> Result<(), PowerControllerError> {
// self.rtl_reset.set_values(1u8)?;
// sleep(Duration::from_secs(1)).await;
Expand All @@ -197,7 +199,9 @@ impl PinController {
}

trait UsbConfiguration {
fn name(&self) -> &'static str;
fn set_usb_route(&self, route: UsbRoute) -> Result<(), PowerControllerError>;
fn set_node1_usb_route(&self, alternative_port: bool) -> Result<(), PowerControllerError>;
fn configure_usb(&self, node: NodeId, mode: UsbMode) -> Result<(), PowerControllerError>;
}

Expand Down Expand Up @@ -236,6 +240,10 @@ impl UsbMuxSwitch {
}

impl UsbConfiguration for UsbMuxSwitch {
fn name(&self) -> &'static str {
"single USB bus"
}

fn set_usb_route(&self, route: UsbRoute) -> Result<(), PowerControllerError> {
match route {
UsbRoute::AlternativePort => {
Expand Down Expand Up @@ -266,20 +274,35 @@ impl UsbConfiguration for UsbMuxSwitch {
self.usb_vbus.set_values(vbus)?;
Ok(())
}

fn set_node1_usb_route(&self, _alternative_port: bool) -> Result<(), PowerControllerError> {
Err(PowerControllerError::Node1UsbNotApplicable)
}
}

struct UsbHub {
output_switch: Lines<Output>,
node1_source: Lines<Output>,
}

impl UsbHub {
pub fn new(chip: &Chip) -> Result<Self, PowerControllerError> {
let node1_source =
gpio_output_lines!(chip, [NODE1_OUTPUT_SWITCH_V2_5, NODE1_SOURCE_SWITCH_V2_5]);

let output_switch = gpio_output_lines!(chip, [USB_SWITCH_V2_5]);
Ok(Self { output_switch })
Ok(Self {
output_switch,
node1_source,
})
}
}

impl UsbConfiguration for UsbHub {
fn name(&self) -> &'static str {
"USB hub"
}

fn set_usb_route(&self, route: UsbRoute) -> Result<(), PowerControllerError> {
match route {
UsbRoute::AlternativePort => self.output_switch.set_values(0_u8),
Expand All @@ -297,10 +320,17 @@ impl UsbConfiguration for UsbHub {
// the USB hub.
Ok(())
}

fn set_node1_usb_route(&self, alternative_port: bool) -> Result<(), PowerControllerError> {
let value = if alternative_port { 0b11 } else { 0u8 };
Ok(self.node1_source.set_values(value)?)
}
}

#[derive(Debug, Error)]
pub enum PowerControllerError {
#[error("This command is only available on v2.5+ boards")]
Node1UsbNotApplicable,
#[error(
"Selecting one of the nodes as USB Host role \
is not supported by the current hardware"
Expand Down
7 changes: 6 additions & 1 deletion src/serial_service/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use super::serial_handler::Handler;
use crate::hal::NodeId;
use crate::serial_service::serial_handler::HandlerState;
use tokio_serial::{DataBits, Parity, StopBits};
use tracing::error;

/// Collection of [`crate::serial_service::serial_handler::Handler`]
#[derive(Debug)]
Expand All @@ -38,7 +39,11 @@ impl SerialConnections {
Parity::None,
StopBits::One,
);
handler.run().expect("handler run error");

if let Err(e) = handler.run() {
error!("handler run error: {}", e);
}

handler
});

Expand Down
11 changes: 9 additions & 2 deletions src/usb_boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use rusb::GlobalContext;
use std::{fmt::Display, path::PathBuf};
use thiserror::Error;
use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite};
use tracing::info;
use tracing::{info, warn};

pub trait DataTransport: AsyncRead + AsyncWrite + AsyncSeek + Send + Unpin {}
impl DataTransport for tokio::fs::File {}
Expand Down Expand Up @@ -68,11 +68,18 @@ impl NodeDrivers {
let mut backends = self.backends.iter().filter_map(|backend| {
let found = devices.iter().find(|dev| {
let Ok(descriptor) = dev.device_descriptor() else {
warn!("dropping {:?}, could not load descriptor", dev);
return false;
};

let vid_pid = (descriptor.vendor_id(), descriptor.product_id());
info!(
"trying {:#06x}:{:#06x}",
descriptor.vendor_id(),
descriptor.product_id(),
);
let supported = backend.is_supported(&vid_pid);

if supported {
info!(
"ID {:#06x}:{:#06x} {}",
Expand Down Expand Up @@ -102,7 +109,7 @@ impl NodeDrivers {

#[derive(Error, Debug)]
pub enum UsbBootError {
#[error("Compute module not supported")]
#[error("Compute module's USB interface not found or supported")]
NotSupported,
#[error("USB")]
RusbError(#[from] rusb::Error),
Expand Down

0 comments on commit 2fac14e

Please sign in to comment.