aic8800 0.2.9

OS-independent AIC8800 Wi-Fi driver core
use alloc::sync::Arc;
use core::sync::atomic::{AtomicU64, Ordering};

use ringbuf::{HeapCons, HeapProd, HeapRb, traits::Split};
use sdmmc_protocol::sdio::{HostEvent, HostEventKind};

use crate::{ControlRequest, IrqSnapshot, SdioFailure, rdif::owner::AicOwner};

const IRQ_CARD: u8 = 1 << 0;
const IRQ_TRANSFER: u8 = 1 << 1;
const IRQ_ERROR: u8 = 1 << 2;
const IRQ_FLAG_BITS: u32 = 3;
const IRQ_FLAG_MASK: u64 = (1 << IRQ_FLAG_BITS) - 1;
const IRQ_SEQUENCE_MASK: u64 = u64::MAX >> IRQ_FLAG_BITS;

/// Preallocated hard-IRQ to owner snapshot latch.
pub(crate) struct IrqLatch {
    state: AtomicU64,
}

impl IrqLatch {
    pub(crate) const fn new() -> Self {
        Self {
            state: AtomicU64::new(0),
        }
    }

    pub(crate) fn publish(&self, event: &impl HostEvent) -> bool {
        let mut flags = 0;
        if event.card_interrupt() {
            flags |= IRQ_CARD;
        }
        match event.kind() {
            HostEventKind::None => {}
            HostEventKind::TransferComplete
            | HostEventKind::CommandComplete
            | HostEventKind::ReceiveReady
            | HostEventKind::TransmitReady
            | HostEventKind::Other => flags |= IRQ_TRANSFER,
            HostEventKind::CardInterrupt => flags |= IRQ_CARD,
            HostEventKind::Error => flags |= IRQ_ERROR,
            _ => flags |= IRQ_TRANSFER,
        }
        if flags == 0 {
            return false;
        }
        let mut current = self.state.load(Ordering::Relaxed);
        loop {
            let sequence = ((current >> IRQ_FLAG_BITS).wrapping_add(1)) & IRQ_SEQUENCE_MASK;
            let next = (sequence << IRQ_FLAG_BITS) | ((current & IRQ_FLAG_MASK) | u64::from(flags));
            match self.state.compare_exchange_weak(
                current,
                next,
                Ordering::Release,
                Ordering::Relaxed,
            ) {
                Ok(_) => break,
                Err(observed) => current = observed,
            }
        }
        true
    }

    pub(crate) fn take(&self) -> Option<IrqSnapshot> {
        self.take_with_before_clear(|| {})
    }

    fn take_with_before_clear(&self, before_clear: impl FnOnce()) -> Option<IrqSnapshot> {
        let mut current = self.state.load(Ordering::Acquire);
        let mut before_clear = Some(before_clear);
        loop {
            let flags = (current & IRQ_FLAG_MASK) as u8;
            if flags == 0 {
                return None;
            }
            if let Some(before_clear) = before_clear.take() {
                before_clear();
            }
            match self.state.compare_exchange_weak(
                current,
                current & !IRQ_FLAG_MASK,
                Ordering::AcqRel,
                Ordering::Acquire,
            ) {
                Ok(_) => {
                    return Some(IrqSnapshot {
                        sequence: current >> IRQ_FLAG_BITS,
                        card_interrupt: flags & IRQ_CARD != 0,
                        transfer_complete: flags & IRQ_TRANSFER != 0,
                        error: (flags & IRQ_ERROR != 0).then_some(SdioFailure::Bus),
                    });
                }
                Err(observed) => current = observed,
            }
        }
    }

    pub(crate) fn has_pending(&self) -> bool {
        self.state.load(Ordering::Acquire) & IRQ_FLAG_MASK != 0
    }
}

/// Lock-free MAC publication from owner startup to the general control port.
pub(crate) struct MacAddressState(AtomicU64);

impl MacAddressState {
    pub(crate) fn new(address: [u8; 6]) -> Self {
        Self(AtomicU64::new(encode_mac(address)))
    }

    pub(crate) fn publish(&self, address: [u8; 6]) {
        self.0.store(encode_mac(address), Ordering::Release);
    }

    pub(crate) fn load(&self) -> [u8; 6] {
        decode_mac(self.0.load(Ordering::Acquire))
    }
}

fn encode_mac(address: [u8; 6]) -> u64 {
    let mut raw = [0; 8];
    raw[..6].copy_from_slice(&address);
    u64::from_le_bytes(raw)
}

fn decode_mac(value: u64) -> [u8; 6] {
    let raw = value.to_le_bytes();
    [raw[0], raw[1], raw[2], raw[3], raw[4], raw[5]]
}

pub(crate) type OwnerSender<H> = HeapProd<AicOwner<H>>;
pub(crate) type OwnerReceiver<H> = HeapCons<AicOwner<H>>;

pub(crate) struct OwnerChannels<H: sdmmc_protocol::sdio::SdMmcIrqHost + 'static> {
    pub(crate) sender: OwnerSender<H>,
    pub(crate) receiver: OwnerReceiver<H>,
}

impl<H: sdmmc_protocol::sdio::SdMmcIrqHost + 'static> OwnerChannels<H> {
    pub(crate) fn new() -> Self {
        let ring = HeapRb::new(1);
        let (sender, receiver) = ring.split();
        Self { sender, receiver }
    }
}

pub(crate) type WifiRequestSender = HeapProd<ControlRequest>;
pub(crate) type WifiRequestReceiver = HeapCons<ControlRequest>;
pub(crate) type WifiProgressSender =
    HeapProd<Result<rdif_eth::WifiControlProgress, crate::AicError>>;
pub(crate) type WifiProgressReceiver =
    HeapCons<Result<rdif_eth::WifiControlProgress, crate::AicError>>;

pub(crate) struct WifiChannels {
    pub(crate) requests_tx: WifiRequestSender,
    pub(crate) requests_rx: WifiRequestReceiver,
    pub(crate) progress_tx: WifiProgressSender,
    pub(crate) progress_rx: WifiProgressReceiver,
}

impl WifiChannels {
    pub(crate) fn new() -> Self {
        let requests = HeapRb::new(2);
        let progress = HeapRb::new(8);
        let (requests_tx, requests_rx) = requests.split();
        let (progress_tx, progress_rx) = progress.split();
        Self {
            requests_tx,
            requests_rx,
            progress_tx,
            progress_rx,
        }
    }
}

pub(crate) fn shared_irq_latch() -> Arc<IrqLatch> {
    Arc::new(IrqLatch::new())
}

#[cfg(test)]
mod tests {
    use super::*;

    struct TestEvent(HostEventKind);

    impl HostEvent for TestEvent {
        fn kind(&self) -> HostEventKind {
            self.0
        }
    }

    #[test]
    fn irq_published_while_snapshot_is_taken_is_never_hidden_by_the_same_sequence() {
        let latch = IrqLatch::new();
        assert!(latch.publish(&TestEvent(HostEventKind::TransferComplete)));

        let first = latch
            .take_with_before_clear(|| {
                assert!(latch.publish(&TestEvent(HostEventKind::CardInterrupt)));
            })
            .unwrap();
        let second = latch.take();

        let coalesced = first.transfer_complete && first.card_interrupt;
        let separately_ordered = second
            .is_some_and(|snapshot| snapshot.card_interrupt && snapshot.sequence > first.sequence);
        assert!(coalesced || separately_ordered);
    }

    #[test]
    fn mac_publication_round_trips_all_six_bytes() {
        let state = MacAddressState::new([2, 1, 2, 3, 4, 5]);
        assert_eq!(state.load(), [2, 1, 2, 3, 4, 5]);
        state.publish([6, 7, 8, 9, 10, 11]);
        assert_eq!(state.load(), [6, 7, 8, 9, 10, 11]);
    }
}