diff options
| author | kbleeke <[email protected]> | 2023-03-02 12:10:13 +0100 |
|---|---|---|
| committer | kbleeke <[email protected]> | 2023-03-22 15:35:02 +0100 |
| commit | 20923080e6ea313278b5f3aa8ec21055c6208527 (patch) | |
| tree | b30e9545302fa9ef68dfa25748602877f838f722 /src/runner.rs | |
| parent | 8b24fe3df02862991b2574f9d5c9ada7bd27706b (diff) | |
split lib.rs into multiple files
Diffstat (limited to 'src/runner.rs')
| -rw-r--r-- | src/runner.rs | 564 |
1 files changed, 564 insertions, 0 deletions
diff --git a/src/runner.rs b/src/runner.rs new file mode 100644 index 000000000..5d840bc59 --- /dev/null +++ b/src/runner.rs | |||
| @@ -0,0 +1,564 @@ | |||
| 1 | use core::cell::Cell; | ||
| 2 | use core::slice; | ||
| 3 | |||
| 4 | use embassy_futures::yield_now; | ||
| 5 | use embassy_net_driver_channel as ch; | ||
| 6 | use embassy_sync::pubsub::PubSubBehavior; | ||
| 7 | use embassy_time::{block_for, Duration, Timer}; | ||
| 8 | use embedded_hal_1::digital::OutputPin; | ||
| 9 | |||
| 10 | use crate::bus::Bus; | ||
| 11 | pub use crate::bus::SpiBusCyw43; | ||
| 12 | use crate::consts::*; | ||
| 13 | use crate::events::{EventQueue, EventStatus}; | ||
| 14 | use crate::nvram::NVRAM; | ||
| 15 | use crate::structs::*; | ||
| 16 | use crate::{events, Core, IoctlState, IoctlType, CHIP, MTU}; | ||
| 17 | |||
| 18 | #[cfg(feature = "firmware-logs")] | ||
| 19 | struct LogState { | ||
| 20 | addr: u32, | ||
| 21 | last_idx: usize, | ||
| 22 | buf: [u8; 256], | ||
| 23 | buf_count: usize, | ||
| 24 | } | ||
| 25 | |||
| 26 | impl Default for LogState { | ||
| 27 | fn default() -> Self { | ||
| 28 | Self { | ||
| 29 | addr: Default::default(), | ||
| 30 | last_idx: Default::default(), | ||
| 31 | buf: [0; 256], | ||
| 32 | buf_count: Default::default(), | ||
| 33 | } | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | pub struct Runner<'a, PWR, SPI> { | ||
| 38 | ch: ch::Runner<'a, MTU>, | ||
| 39 | bus: Bus<PWR, SPI>, | ||
| 40 | |||
| 41 | ioctl_state: &'a Cell<IoctlState>, | ||
| 42 | ioctl_id: u16, | ||
| 43 | sdpcm_seq: u8, | ||
| 44 | sdpcm_seq_max: u8, | ||
| 45 | |||
| 46 | events: &'a EventQueue, | ||
| 47 | |||
| 48 | #[cfg(feature = "firmware-logs")] | ||
| 49 | log: LogState, | ||
| 50 | } | ||
| 51 | |||
| 52 | impl<'a, PWR, SPI> Runner<'a, PWR, SPI> | ||
| 53 | where | ||
| 54 | PWR: OutputPin, | ||
| 55 | SPI: SpiBusCyw43, | ||
| 56 | { | ||
| 57 | pub(crate) fn new( | ||
| 58 | ch: ch::Runner<'a, MTU>, | ||
| 59 | bus: Bus<PWR, SPI>, | ||
| 60 | ioctl_state: &'a Cell<IoctlState>, | ||
| 61 | events: &'a EventQueue, | ||
| 62 | ) -> Self { | ||
| 63 | Self { | ||
| 64 | ch, | ||
| 65 | bus, | ||
| 66 | ioctl_state, | ||
| 67 | ioctl_id: 0, | ||
| 68 | sdpcm_seq: 0, | ||
| 69 | sdpcm_seq_max: 1, | ||
| 70 | events, | ||
| 71 | #[cfg(feature = "firmware-logs")] | ||
| 72 | log: LogState::default(), | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | pub(crate) async fn init(&mut self, firmware: &[u8]) { | ||
| 77 | self.bus.init().await; | ||
| 78 | |||
| 79 | // Init ALP (Active Low Power) clock | ||
| 80 | self.bus | ||
| 81 | .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ) | ||
| 82 | .await; | ||
| 83 | info!("waiting for clock..."); | ||
| 84 | while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {} | ||
| 85 | info!("clock ok"); | ||
| 86 | |||
| 87 | let chip_id = self.bus.bp_read16(0x1800_0000).await; | ||
| 88 | info!("chip ID: {}", chip_id); | ||
| 89 | |||
| 90 | // Upload firmware. | ||
| 91 | self.core_disable(Core::WLAN).await; | ||
| 92 | self.core_reset(Core::SOCSRAM).await; | ||
| 93 | self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await; | ||
| 94 | self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await; | ||
| 95 | |||
| 96 | let ram_addr = CHIP.atcm_ram_base_address; | ||
| 97 | |||
| 98 | info!("loading fw"); | ||
| 99 | self.bus.bp_write(ram_addr, firmware).await; | ||
| 100 | |||
| 101 | info!("loading nvram"); | ||
| 102 | // Round up to 4 bytes. | ||
| 103 | let nvram_len = (NVRAM.len() + 3) / 4 * 4; | ||
| 104 | self.bus | ||
| 105 | .bp_write(ram_addr + CHIP.chip_ram_size - 4 - nvram_len as u32, NVRAM) | ||
| 106 | .await; | ||
| 107 | |||
| 108 | let nvram_len_words = nvram_len as u32 / 4; | ||
| 109 | let nvram_len_magic = (!nvram_len_words << 16) | nvram_len_words; | ||
| 110 | self.bus | ||
| 111 | .bp_write32(ram_addr + CHIP.chip_ram_size - 4, nvram_len_magic) | ||
| 112 | .await; | ||
| 113 | |||
| 114 | // Start core! | ||
| 115 | info!("starting up core..."); | ||
| 116 | self.core_reset(Core::WLAN).await; | ||
| 117 | assert!(self.core_is_up(Core::WLAN).await); | ||
| 118 | |||
| 119 | while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} | ||
| 120 | |||
| 121 | // "Set up the interrupt mask and enable interrupts" | ||
| 122 | self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await; | ||
| 123 | |||
| 124 | // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped." | ||
| 125 | // Sounds scary... | ||
| 126 | self.bus | ||
| 127 | .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32) | ||
| 128 | .await; | ||
| 129 | |||
| 130 | // wait for wifi startup | ||
| 131 | info!("waiting for wifi init..."); | ||
| 132 | while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {} | ||
| 133 | |||
| 134 | // Some random configs related to sleep. | ||
| 135 | // These aren't needed if we don't want to sleep the bus. | ||
| 136 | // TODO do we need to sleep the bus to read the irq line, due to | ||
| 137 | // being on the same pin as MOSI/MISO? | ||
| 138 | |||
| 139 | /* | ||
| 140 | let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL).await; | ||
| 141 | val |= 0x02; // WAKE_TILL_HT_AVAIL | ||
| 142 | self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL, val).await; | ||
| 143 | self.bus.write8(FUNC_BUS, 0xF0, 0x08).await; // SDIOD_CCCR_BRCM_CARDCAP.CMD_NODEC = 1 | ||
| 144 | self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x02).await; // SBSDIO_FORCE_HT | ||
| 145 | |||
| 146 | let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR).await; | ||
| 147 | val |= 0x01; // SBSDIO_SLPCSR_KEEP_SDIO_ON | ||
| 148 | self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR, val).await; | ||
| 149 | */ | ||
| 150 | |||
| 151 | // clear pulls | ||
| 152 | self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await; | ||
| 153 | let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await; | ||
| 154 | |||
| 155 | // start HT clock | ||
| 156 | //self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await; | ||
| 157 | //info!("waiting for HT clock..."); | ||
| 158 | //while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} | ||
| 159 | //info!("clock ok"); | ||
| 160 | |||
| 161 | #[cfg(feature = "firmware-logs")] | ||
| 162 | self.log_init().await; | ||
| 163 | |||
| 164 | info!("init done "); | ||
| 165 | } | ||
| 166 | |||
| 167 | #[cfg(feature = "firmware-logs")] | ||
| 168 | async fn log_init(&mut self) { | ||
| 169 | // Initialize shared memory for logging. | ||
| 170 | |||
| 171 | let addr = CHIP.atcm_ram_base_address + CHIP.chip_ram_size - 4 - CHIP.socram_srmem_size; | ||
| 172 | let shared_addr = self.bus.bp_read32(addr).await; | ||
| 173 | info!("shared_addr {:08x}", shared_addr); | ||
| 174 | |||
| 175 | let mut shared = [0; SharedMemData::SIZE]; | ||
| 176 | self.bus.bp_read(shared_addr, &mut shared).await; | ||
| 177 | let shared = SharedMemData::from_bytes(&shared); | ||
| 178 | info!("shared: {:08x}", shared); | ||
| 179 | |||
| 180 | self.log.addr = shared.console_addr + 8; | ||
| 181 | } | ||
| 182 | |||
| 183 | #[cfg(feature = "firmware-logs")] | ||
| 184 | async fn log_read(&mut self) { | ||
| 185 | // Read log struct | ||
| 186 | let mut log = [0; SharedMemLog::SIZE]; | ||
| 187 | self.bus.bp_read(self.log.addr, &mut log).await; | ||
| 188 | let log = SharedMemLog::from_bytes(&log); | ||
| 189 | |||
| 190 | let idx = log.idx as usize; | ||
| 191 | |||
| 192 | // If pointer hasn't moved, no need to do anything. | ||
| 193 | if idx == self.log.last_idx { | ||
| 194 | return; | ||
| 195 | } | ||
| 196 | |||
| 197 | // Read entire buf for now. We could read only what we need, but then we | ||
| 198 | // run into annoying alignment issues in `bp_read`. | ||
| 199 | let mut buf = [0; 0x400]; | ||
| 200 | self.bus.bp_read(log.buf, &mut buf).await; | ||
| 201 | |||
| 202 | while self.log.last_idx != idx as usize { | ||
| 203 | let b = buf[self.log.last_idx]; | ||
| 204 | if b == b'\r' || b == b'\n' { | ||
| 205 | if self.log.buf_count != 0 { | ||
| 206 | let s = unsafe { core::str::from_utf8_unchecked(&self.log.buf[..self.log.buf_count]) }; | ||
| 207 | debug!("LOGS: {}", s); | ||
| 208 | self.log.buf_count = 0; | ||
| 209 | } | ||
| 210 | } else if self.log.buf_count < self.log.buf.len() { | ||
| 211 | self.log.buf[self.log.buf_count] = b; | ||
| 212 | self.log.buf_count += 1; | ||
| 213 | } | ||
| 214 | |||
| 215 | self.log.last_idx += 1; | ||
| 216 | if self.log.last_idx == 0x400 { | ||
| 217 | self.log.last_idx = 0; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | pub async fn run(mut self) -> ! { | ||
| 223 | let mut buf = [0; 512]; | ||
| 224 | loop { | ||
| 225 | #[cfg(feature = "firmware-logs")] | ||
| 226 | self.log_read().await; | ||
| 227 | |||
| 228 | // Send stuff | ||
| 229 | // TODO flow control not yet complete | ||
| 230 | if !self.has_credit() { | ||
| 231 | warn!("TX stalled"); | ||
| 232 | } else { | ||
| 233 | if let IoctlState::Pending { kind, cmd, iface, buf } = self.ioctl_state.get() { | ||
| 234 | self.send_ioctl(kind, cmd, iface, unsafe { &*buf }).await; | ||
| 235 | self.ioctl_state.set(IoctlState::Sent { buf }); | ||
| 236 | } | ||
| 237 | if !self.has_credit() { | ||
| 238 | warn!("TX stalled"); | ||
| 239 | } else { | ||
| 240 | if let Some(packet) = self.ch.try_tx_buf() { | ||
| 241 | trace!("tx pkt {:02x}", &packet[..packet.len().min(48)]); | ||
| 242 | |||
| 243 | let mut buf = [0; 512]; | ||
| 244 | let buf8 = slice8_mut(&mut buf); | ||
| 245 | |||
| 246 | let total_len = SdpcmHeader::SIZE + BcdHeader::SIZE + packet.len(); | ||
| 247 | |||
| 248 | let seq = self.sdpcm_seq; | ||
| 249 | self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1); | ||
| 250 | |||
| 251 | let sdpcm_header = SdpcmHeader { | ||
| 252 | len: total_len as u16, // TODO does this len need to be rounded up to u32? | ||
| 253 | len_inv: !total_len as u16, | ||
| 254 | sequence: seq, | ||
| 255 | channel_and_flags: CHANNEL_TYPE_DATA, | ||
| 256 | next_length: 0, | ||
| 257 | header_length: SdpcmHeader::SIZE as _, | ||
| 258 | wireless_flow_control: 0, | ||
| 259 | bus_data_credit: 0, | ||
| 260 | reserved: [0, 0], | ||
| 261 | }; | ||
| 262 | |||
| 263 | let bcd_header = BcdHeader { | ||
| 264 | flags: BDC_VERSION << BDC_VERSION_SHIFT, | ||
| 265 | priority: 0, | ||
| 266 | flags2: 0, | ||
| 267 | data_offset: 0, | ||
| 268 | }; | ||
| 269 | trace!("tx {:?}", sdpcm_header); | ||
| 270 | trace!(" {:?}", bcd_header); | ||
| 271 | |||
| 272 | buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes()); | ||
| 273 | buf8[SdpcmHeader::SIZE..][..BcdHeader::SIZE].copy_from_slice(&bcd_header.to_bytes()); | ||
| 274 | buf8[SdpcmHeader::SIZE + BcdHeader::SIZE..][..packet.len()].copy_from_slice(packet); | ||
| 275 | |||
| 276 | let total_len = (total_len + 3) & !3; // round up to 4byte | ||
| 277 | |||
| 278 | trace!(" {:02x}", &buf8[..total_len.min(48)]); | ||
| 279 | |||
| 280 | self.bus.wlan_write(&buf[..(total_len / 4)]).await; | ||
| 281 | self.ch.tx_done(); | ||
| 282 | } | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | // Receive stuff | ||
| 287 | let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; | ||
| 288 | |||
| 289 | if irq & IRQ_F2_PACKET_AVAILABLE != 0 { | ||
| 290 | let mut status = 0xFFFF_FFFF; | ||
| 291 | while status == 0xFFFF_FFFF { | ||
| 292 | status = self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await; | ||
| 293 | } | ||
| 294 | |||
| 295 | if status & STATUS_F2_PKT_AVAILABLE != 0 { | ||
| 296 | let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT; | ||
| 297 | self.bus.wlan_read(&mut buf, len).await; | ||
| 298 | trace!("rx {:02x}", &slice8_mut(&mut buf)[..(len as usize).min(48)]); | ||
| 299 | self.rx(&slice8_mut(&mut buf)[..len as usize]); | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | // TODO use IRQs | ||
| 304 | yield_now().await; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | fn rx(&mut self, packet: &[u8]) { | ||
| 309 | if packet.len() < SdpcmHeader::SIZE { | ||
| 310 | warn!("packet too short, len={}", packet.len()); | ||
| 311 | return; | ||
| 312 | } | ||
| 313 | |||
| 314 | let sdpcm_header = SdpcmHeader::from_bytes(packet[..SdpcmHeader::SIZE].try_into().unwrap()); | ||
| 315 | trace!("rx {:?}", sdpcm_header); | ||
| 316 | if sdpcm_header.len != !sdpcm_header.len_inv { | ||
| 317 | warn!("len inv mismatch"); | ||
| 318 | return; | ||
| 319 | } | ||
| 320 | if sdpcm_header.len as usize != packet.len() { | ||
| 321 | // TODO: is this guaranteed?? | ||
| 322 | warn!("len from header doesn't match len from spi"); | ||
| 323 | return; | ||
| 324 | } | ||
| 325 | |||
| 326 | self.update_credit(&sdpcm_header); | ||
| 327 | |||
| 328 | let channel = sdpcm_header.channel_and_flags & 0x0f; | ||
| 329 | |||
| 330 | let payload = &packet[sdpcm_header.header_length as _..]; | ||
| 331 | |||
| 332 | match channel { | ||
| 333 | CHANNEL_TYPE_CONTROL => { | ||
| 334 | if payload.len() < CdcHeader::SIZE { | ||
| 335 | warn!("payload too short, len={}", payload.len()); | ||
| 336 | return; | ||
| 337 | } | ||
| 338 | |||
| 339 | let cdc_header = CdcHeader::from_bytes(payload[..CdcHeader::SIZE].try_into().unwrap()); | ||
| 340 | trace!(" {:?}", cdc_header); | ||
| 341 | |||
| 342 | if let IoctlState::Sent { buf } = self.ioctl_state.get() { | ||
| 343 | if cdc_header.id == self.ioctl_id { | ||
| 344 | if cdc_header.status != 0 { | ||
| 345 | // TODO: propagate error instead | ||
| 346 | panic!("IOCTL error {=i32}", cdc_header.status as i32); | ||
| 347 | } | ||
| 348 | |||
| 349 | let resp_len = cdc_header.len as usize; | ||
| 350 | info!("IOCTL Response: {:02x}", &payload[CdcHeader::SIZE..][..resp_len]); | ||
| 351 | |||
| 352 | (unsafe { &mut *buf }[..resp_len]).copy_from_slice(&payload[CdcHeader::SIZE..][..resp_len]); | ||
| 353 | self.ioctl_state.set(IoctlState::Done { resp_len }); | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } | ||
| 357 | CHANNEL_TYPE_EVENT => { | ||
| 358 | let bcd_header = BcdHeader::from_bytes(&payload[..BcdHeader::SIZE].try_into().unwrap()); | ||
| 359 | trace!(" {:?}", bcd_header); | ||
| 360 | |||
| 361 | let packet_start = BcdHeader::SIZE + 4 * bcd_header.data_offset as usize; | ||
| 362 | |||
| 363 | if packet_start + EventPacket::SIZE > payload.len() { | ||
| 364 | warn!("BCD event, incomplete header"); | ||
| 365 | return; | ||
| 366 | } | ||
| 367 | let bcd_packet = &payload[packet_start..]; | ||
| 368 | trace!(" {:02x}", &bcd_packet[..(bcd_packet.len() as usize).min(36)]); | ||
| 369 | |||
| 370 | let mut event_packet = EventPacket::from_bytes(&bcd_packet[..EventPacket::SIZE].try_into().unwrap()); | ||
| 371 | event_packet.byteswap(); | ||
| 372 | |||
| 373 | const ETH_P_LINK_CTL: u16 = 0x886c; // HPNA, wlan link local tunnel, according to linux if_ether.h | ||
| 374 | if event_packet.eth.ether_type != ETH_P_LINK_CTL { | ||
| 375 | warn!( | ||
| 376 | "unexpected ethernet type 0x{:04x}, expected Broadcom ether type 0x{:04x}", | ||
| 377 | event_packet.eth.ether_type, ETH_P_LINK_CTL | ||
| 378 | ); | ||
| 379 | return; | ||
| 380 | } | ||
| 381 | const BROADCOM_OUI: &[u8] = &[0x00, 0x10, 0x18]; | ||
| 382 | if event_packet.hdr.oui != BROADCOM_OUI { | ||
| 383 | warn!( | ||
| 384 | "unexpected ethernet OUI {:02x}, expected Broadcom OUI {:02x}", | ||
| 385 | event_packet.hdr.oui, BROADCOM_OUI | ||
| 386 | ); | ||
| 387 | return; | ||
| 388 | } | ||
| 389 | const BCMILCP_SUBTYPE_VENDOR_LONG: u16 = 32769; | ||
| 390 | if event_packet.hdr.subtype != BCMILCP_SUBTYPE_VENDOR_LONG { | ||
| 391 | warn!("unexpected subtype {}", event_packet.hdr.subtype); | ||
| 392 | return; | ||
| 393 | } | ||
| 394 | |||
| 395 | const BCMILCP_BCM_SUBTYPE_EVENT: u16 = 1; | ||
| 396 | if event_packet.hdr.user_subtype != BCMILCP_BCM_SUBTYPE_EVENT { | ||
| 397 | warn!("unexpected user_subtype {}", event_packet.hdr.subtype); | ||
| 398 | return; | ||
| 399 | } | ||
| 400 | |||
| 401 | if event_packet.msg.datalen as usize >= (bcd_packet.len() - EventMessage::SIZE) { | ||
| 402 | warn!("BCD event, incomplete data"); | ||
| 403 | return; | ||
| 404 | } | ||
| 405 | |||
| 406 | let evt_type = events::Event::from(event_packet.msg.event_type as u8); | ||
| 407 | let evt_data = &bcd_packet[EventMessage::SIZE..][..event_packet.msg.datalen as usize]; | ||
| 408 | debug!("=== EVENT {}: {} {:02x}", evt_type, event_packet.msg, evt_data); | ||
| 409 | |||
| 410 | if evt_type == events::Event::AUTH || evt_type == events::Event::JOIN { | ||
| 411 | self.events.publish_immediate(EventStatus { | ||
| 412 | status: event_packet.msg.status, | ||
| 413 | event_type: evt_type, | ||
| 414 | }); | ||
| 415 | } | ||
| 416 | } | ||
| 417 | CHANNEL_TYPE_DATA => { | ||
| 418 | let bcd_header = BcdHeader::from_bytes(&payload[..BcdHeader::SIZE].try_into().unwrap()); | ||
| 419 | trace!(" {:?}", bcd_header); | ||
| 420 | |||
| 421 | let packet_start = BcdHeader::SIZE + 4 * bcd_header.data_offset as usize; | ||
| 422 | if packet_start > payload.len() { | ||
| 423 | warn!("packet start out of range."); | ||
| 424 | return; | ||
| 425 | } | ||
| 426 | let packet = &payload[packet_start..]; | ||
| 427 | trace!("rx pkt {:02x}", &packet[..(packet.len() as usize).min(48)]); | ||
| 428 | |||
| 429 | match self.ch.try_rx_buf() { | ||
| 430 | Some(buf) => { | ||
| 431 | buf[..packet.len()].copy_from_slice(packet); | ||
| 432 | self.ch.rx_done(packet.len()) | ||
| 433 | } | ||
| 434 | None => warn!("failed to push rxd packet to the channel."), | ||
| 435 | } | ||
| 436 | } | ||
| 437 | _ => {} | ||
| 438 | } | ||
| 439 | } | ||
| 440 | |||
| 441 | fn update_credit(&mut self, sdpcm_header: &SdpcmHeader) { | ||
| 442 | if sdpcm_header.channel_and_flags & 0xf < 3 { | ||
| 443 | let mut sdpcm_seq_max = sdpcm_header.bus_data_credit; | ||
| 444 | if sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) > 0x40 { | ||
| 445 | sdpcm_seq_max = self.sdpcm_seq + 2; | ||
| 446 | } | ||
| 447 | self.sdpcm_seq_max = sdpcm_seq_max; | ||
| 448 | } | ||
| 449 | } | ||
| 450 | |||
| 451 | fn has_credit(&self) -> bool { | ||
| 452 | self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0 | ||
| 453 | } | ||
| 454 | |||
| 455 | async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) { | ||
| 456 | let mut buf = [0; 512]; | ||
| 457 | let buf8 = slice8_mut(&mut buf); | ||
| 458 | |||
| 459 | let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); | ||
| 460 | |||
| 461 | let sdpcm_seq = self.sdpcm_seq; | ||
| 462 | self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1); | ||
| 463 | self.ioctl_id = self.ioctl_id.wrapping_add(1); | ||
| 464 | |||
| 465 | let sdpcm_header = SdpcmHeader { | ||
| 466 | len: total_len as u16, // TODO does this len need to be rounded up to u32? | ||
| 467 | len_inv: !total_len as u16, | ||
| 468 | sequence: sdpcm_seq, | ||
| 469 | channel_and_flags: CHANNEL_TYPE_CONTROL, | ||
| 470 | next_length: 0, | ||
| 471 | header_length: SdpcmHeader::SIZE as _, | ||
| 472 | wireless_flow_control: 0, | ||
| 473 | bus_data_credit: 0, | ||
| 474 | reserved: [0, 0], | ||
| 475 | }; | ||
| 476 | |||
| 477 | let cdc_header = CdcHeader { | ||
| 478 | cmd: cmd, | ||
| 479 | len: data.len() as _, | ||
| 480 | flags: kind as u16 | (iface as u16) << 12, | ||
| 481 | id: self.ioctl_id, | ||
| 482 | status: 0, | ||
| 483 | }; | ||
| 484 | trace!("tx {:?}", sdpcm_header); | ||
| 485 | trace!(" {:?}", cdc_header); | ||
| 486 | |||
| 487 | buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes()); | ||
| 488 | buf8[SdpcmHeader::SIZE..][..CdcHeader::SIZE].copy_from_slice(&cdc_header.to_bytes()); | ||
| 489 | buf8[SdpcmHeader::SIZE + CdcHeader::SIZE..][..data.len()].copy_from_slice(data); | ||
| 490 | |||
| 491 | let total_len = (total_len + 3) & !3; // round up to 4byte | ||
| 492 | |||
| 493 | trace!(" {:02x}", &buf8[..total_len.min(48)]); | ||
| 494 | |||
| 495 | self.bus.wlan_write(&buf[..total_len / 4]).await; | ||
| 496 | } | ||
| 497 | |||
| 498 | async fn core_disable(&mut self, core: Core) { | ||
| 499 | let base = core.base_addr(); | ||
| 500 | |||
| 501 | // Dummy read? | ||
| 502 | let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; | ||
| 503 | |||
| 504 | // Check it isn't already reset | ||
| 505 | let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; | ||
| 506 | if r & AI_RESETCTRL_BIT_RESET != 0 { | ||
| 507 | return; | ||
| 508 | } | ||
| 509 | |||
| 510 | self.bus.bp_write8(base + AI_IOCTRL_OFFSET, 0).await; | ||
| 511 | let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; | ||
| 512 | |||
| 513 | block_for(Duration::from_millis(1)); | ||
| 514 | |||
| 515 | self.bus | ||
| 516 | .bp_write8(base + AI_RESETCTRL_OFFSET, AI_RESETCTRL_BIT_RESET) | ||
| 517 | .await; | ||
| 518 | let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; | ||
| 519 | } | ||
| 520 | |||
| 521 | async fn core_reset(&mut self, core: Core) { | ||
| 522 | self.core_disable(core).await; | ||
| 523 | |||
| 524 | let base = core.base_addr(); | ||
| 525 | self.bus | ||
| 526 | .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) | ||
| 527 | .await; | ||
| 528 | let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; | ||
| 529 | |||
| 530 | self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await; | ||
| 531 | |||
| 532 | Timer::after(Duration::from_millis(1)).await; | ||
| 533 | |||
| 534 | self.bus | ||
| 535 | .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN) | ||
| 536 | .await; | ||
| 537 | let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; | ||
| 538 | |||
| 539 | Timer::after(Duration::from_millis(1)).await; | ||
| 540 | } | ||
| 541 | |||
| 542 | async fn core_is_up(&mut self, core: Core) -> bool { | ||
| 543 | let base = core.base_addr(); | ||
| 544 | |||
| 545 | let io = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; | ||
| 546 | if io & (AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) != AI_IOCTRL_BIT_CLOCK_EN { | ||
| 547 | debug!("core_is_up: returning false due to bad ioctrl {:02x}", io); | ||
| 548 | return false; | ||
| 549 | } | ||
| 550 | |||
| 551 | let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; | ||
| 552 | if r & (AI_RESETCTRL_BIT_RESET) != 0 { | ||
| 553 | debug!("core_is_up: returning false due to bad resetctrl {:02x}", r); | ||
| 554 | return false; | ||
| 555 | } | ||
| 556 | |||
| 557 | true | ||
| 558 | } | ||
| 559 | } | ||
| 560 | |||
| 561 | fn slice8_mut(x: &mut [u32]) -> &mut [u8] { | ||
| 562 | let len = x.len() * 4; | ||
| 563 | unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } | ||
| 564 | } | ||
