aboutsummaryrefslogtreecommitdiff
path: root/cyw43/src/runner.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cyw43/src/runner.rs')
-rw-r--r--cyw43/src/runner.rs575
1 files changed, 575 insertions, 0 deletions
diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs
new file mode 100644
index 000000000..5706696b4
--- /dev/null
+++ b/cyw43/src/runner.rs
@@ -0,0 +1,575 @@
1use embassy_futures::select::{select3, Either3};
2use embassy_net_driver_channel as ch;
3use embassy_sync::pubsub::PubSubBehavior;
4use embassy_time::{block_for, Duration, Timer};
5use embedded_hal_1::digital::OutputPin;
6
7use crate::bus::Bus;
8pub use crate::bus::SpiBusCyw43;
9use crate::consts::*;
10use crate::events::{Event, Events, Status};
11use crate::fmt::Bytes;
12use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
13use crate::nvram::NVRAM;
14use crate::structs::*;
15use crate::{events, slice8_mut, Core, CHIP, MTU};
16
17#[cfg(feature = "firmware-logs")]
18struct LogState {
19 addr: u32,
20 last_idx: usize,
21 buf: [u8; 256],
22 buf_count: usize,
23}
24
25#[cfg(feature = "firmware-logs")]
26impl 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
37pub struct Runner<'a, PWR, SPI> {
38 ch: ch::Runner<'a, MTU>,
39 bus: Bus<PWR, SPI>,
40
41 ioctl_state: &'a IoctlState,
42 ioctl_id: u16,
43 sdpcm_seq: u8,
44 sdpcm_seq_max: u8,
45
46 events: &'a Events,
47
48 #[cfg(feature = "firmware-logs")]
49 log: LogState,
50}
51
52impl<'a, PWR, SPI> Runner<'a, PWR, SPI>
53where
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 IoctlState,
61 events: &'a Events,
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 debug!("waiting for clock...");
84 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {}
85 debug!("clock ok");
86
87 let chip_id = self.bus.bp_read16(0x1800_0000).await;
88 debug!("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 debug!("loading fw");
99 self.bus.bp_write(ram_addr, firmware).await;
100
101 debug!("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 debug!("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 self.bus
125 .write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE)
126 .await;
127
128 // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped."
129 // Sounds scary...
130 self.bus
131 .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32)
132 .await;
133
134 // wait for wifi startup
135 debug!("waiting for wifi init...");
136 while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {}
137
138 // Some random configs related to sleep.
139 // These aren't needed if we don't want to sleep the bus.
140 // TODO do we need to sleep the bus to read the irq line, due to
141 // being on the same pin as MOSI/MISO?
142
143 /*
144 let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL).await;
145 val |= 0x02; // WAKE_TILL_HT_AVAIL
146 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL, val).await;
147 self.bus.write8(FUNC_BUS, 0xF0, 0x08).await; // SDIOD_CCCR_BRCM_CARDCAP.CMD_NODEC = 1
148 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x02).await; // SBSDIO_FORCE_HT
149
150 let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR).await;
151 val |= 0x01; // SBSDIO_SLPCSR_KEEP_SDIO_ON
152 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR, val).await;
153 */
154
155 // clear pulls
156 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await;
157 let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await;
158
159 // start HT clock
160 //self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await;
161 //debug!("waiting for HT clock...");
162 //while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
163 //debug!("clock ok");
164
165 #[cfg(feature = "firmware-logs")]
166 self.log_init().await;
167
168 debug!("wifi init done");
169 }
170
171 #[cfg(feature = "firmware-logs")]
172 async fn log_init(&mut self) {
173 // Initialize shared memory for logging.
174
175 let addr = CHIP.atcm_ram_base_address + CHIP.chip_ram_size - 4 - CHIP.socram_srmem_size;
176 let shared_addr = self.bus.bp_read32(addr).await;
177 debug!("shared_addr {:08x}", shared_addr);
178
179 let mut shared = [0; SharedMemData::SIZE];
180 self.bus.bp_read(shared_addr, &mut shared).await;
181 let shared = SharedMemData::from_bytes(&shared);
182
183 self.log.addr = shared.console_addr + 8;
184 }
185
186 #[cfg(feature = "firmware-logs")]
187 async fn log_read(&mut self) {
188 // Read log struct
189 let mut log = [0; SharedMemLog::SIZE];
190 self.bus.bp_read(self.log.addr, &mut log).await;
191 let log = SharedMemLog::from_bytes(&log);
192
193 let idx = log.idx as usize;
194
195 // If pointer hasn't moved, no need to do anything.
196 if idx == self.log.last_idx {
197 return;
198 }
199
200 // Read entire buf for now. We could read only what we need, but then we
201 // run into annoying alignment issues in `bp_read`.
202 let mut buf = [0; 0x400];
203 self.bus.bp_read(log.buf, &mut buf).await;
204
205 while self.log.last_idx != idx as usize {
206 let b = buf[self.log.last_idx];
207 if b == b'\r' || b == b'\n' {
208 if self.log.buf_count != 0 {
209 let s = unsafe { core::str::from_utf8_unchecked(&self.log.buf[..self.log.buf_count]) };
210 debug!("LOGS: {}", s);
211 self.log.buf_count = 0;
212 }
213 } else if self.log.buf_count < self.log.buf.len() {
214 self.log.buf[self.log.buf_count] = b;
215 self.log.buf_count += 1;
216 }
217
218 self.log.last_idx += 1;
219 if self.log.last_idx == 0x400 {
220 self.log.last_idx = 0;
221 }
222 }
223 }
224
225 pub async fn run(mut self) -> ! {
226 let mut buf = [0; 512];
227 loop {
228 #[cfg(feature = "firmware-logs")]
229 self.log_read().await;
230
231 if self.has_credit() {
232 let ioctl = self.ioctl_state.wait_pending();
233 let tx = self.ch.tx_buf();
234 let ev = self.bus.wait_for_event();
235
236 match select3(ioctl, tx, ev).await {
237 Either3::First(PendingIoctl {
238 buf: iobuf,
239 kind,
240 cmd,
241 iface,
242 }) => {
243 self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }).await;
244 self.check_status(&mut buf).await;
245 }
246 Either3::Second(packet) => {
247 trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
248
249 let mut buf = [0; 512];
250 let buf8 = slice8_mut(&mut buf);
251
252 // There MUST be 2 bytes of padding between the SDPCM and BDC headers.
253 // And ONLY for data packets!
254 // No idea why, but the firmware will append two zero bytes to the tx'd packets
255 // otherwise. If the packet is exactly 1514 bytes (the max MTU), this makes it
256 // be oversized and get dropped.
257 // WHD adds it here https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/include/whd_sdpcm.h#L90
258 // and adds it to the header size her https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/whd_sdpcm.c#L597
259 // ¯\_(ツ)_/¯
260 const PADDING_SIZE: usize = 2;
261 let total_len = SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE + packet.len();
262
263 let seq = self.sdpcm_seq;
264 self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1);
265
266 let sdpcm_header = SdpcmHeader {
267 len: total_len as u16, // TODO does this len need to be rounded up to u32?
268 len_inv: !total_len as u16,
269 sequence: seq,
270 channel_and_flags: CHANNEL_TYPE_DATA,
271 next_length: 0,
272 header_length: (SdpcmHeader::SIZE + PADDING_SIZE) as _,
273 wireless_flow_control: 0,
274 bus_data_credit: 0,
275 reserved: [0, 0],
276 };
277
278 let bdc_header = BdcHeader {
279 flags: BDC_VERSION << BDC_VERSION_SHIFT,
280 priority: 0,
281 flags2: 0,
282 data_offset: 0,
283 };
284 trace!("tx {:?}", sdpcm_header);
285 trace!(" {:?}", bdc_header);
286
287 buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes());
288 buf8[SdpcmHeader::SIZE + PADDING_SIZE..][..BdcHeader::SIZE]
289 .copy_from_slice(&bdc_header.to_bytes());
290 buf8[SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE..][..packet.len()]
291 .copy_from_slice(packet);
292
293 let total_len = (total_len + 3) & !3; // round up to 4byte
294
295 trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)]));
296
297 self.bus.wlan_write(&buf[..(total_len / 4)]).await;
298 self.ch.tx_done();
299 self.check_status(&mut buf).await;
300 }
301 Either3::Third(()) => {
302 self.handle_irq(&mut buf).await;
303 }
304 }
305 } else {
306 warn!("TX stalled");
307 self.bus.wait_for_event().await;
308 self.handle_irq(&mut buf).await;
309 }
310 }
311 }
312
313 /// Wait for IRQ on F2 packet available
314 async fn handle_irq(&mut self, buf: &mut [u32; 512]) {
315 // Receive stuff
316 let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
317 trace!("irq{}", FormatInterrupt(irq));
318
319 if irq & IRQ_F2_PACKET_AVAILABLE != 0 {
320 self.check_status(buf).await;
321 }
322
323 if irq & IRQ_DATA_UNAVAILABLE != 0 {
324 // TODO what should we do here?
325 warn!("IRQ DATA_UNAVAILABLE, clearing...");
326 self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await;
327 }
328 }
329
330 /// Handle F2 events while status register is set
331 async fn check_status(&mut self, buf: &mut [u32; 512]) {
332 loop {
333 let status = self.bus.status();
334 trace!("check status{}", FormatStatus(status));
335
336 if status & STATUS_F2_PKT_AVAILABLE != 0 {
337 let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT;
338 self.bus.wlan_read(buf, len).await;
339 trace!("rx {:02x}", Bytes(&slice8_mut(buf)[..(len as usize).min(48)]));
340 self.rx(&mut slice8_mut(buf)[..len as usize]);
341 } else {
342 break;
343 }
344 }
345 }
346
347 fn rx(&mut self, packet: &mut [u8]) {
348 let Some((sdpcm_header, payload)) = SdpcmHeader::parse(packet) else { return };
349
350 self.update_credit(&sdpcm_header);
351
352 let channel = sdpcm_header.channel_and_flags & 0x0f;
353
354 match channel {
355 CHANNEL_TYPE_CONTROL => {
356 let Some((cdc_header, response)) = CdcHeader::parse(payload) else { return; };
357 trace!(" {:?}", cdc_header);
358
359 if cdc_header.id == self.ioctl_id {
360 if cdc_header.status != 0 {
361 // TODO: propagate error instead
362 panic!("IOCTL error {}", cdc_header.status as i32);
363 }
364
365 self.ioctl_state.ioctl_done(response);
366 }
367 }
368 CHANNEL_TYPE_EVENT => {
369 let Some((_, bdc_packet)) = BdcHeader::parse(payload) else {
370 warn!("BDC event, incomplete header");
371 return;
372 };
373
374 let Some((event_packet, evt_data)) = EventPacket::parse(bdc_packet) else {
375 warn!("BDC event, incomplete data");
376 return;
377 };
378
379 const ETH_P_LINK_CTL: u16 = 0x886c; // HPNA, wlan link local tunnel, according to linux if_ether.h
380 if event_packet.eth.ether_type != ETH_P_LINK_CTL {
381 warn!(
382 "unexpected ethernet type 0x{:04x}, expected Broadcom ether type 0x{:04x}",
383 event_packet.eth.ether_type, ETH_P_LINK_CTL
384 );
385 return;
386 }
387 const BROADCOM_OUI: &[u8] = &[0x00, 0x10, 0x18];
388 if event_packet.hdr.oui != BROADCOM_OUI {
389 warn!(
390 "unexpected ethernet OUI {:02x}, expected Broadcom OUI {:02x}",
391 Bytes(&event_packet.hdr.oui),
392 Bytes(BROADCOM_OUI)
393 );
394 return;
395 }
396 const BCMILCP_SUBTYPE_VENDOR_LONG: u16 = 32769;
397 if event_packet.hdr.subtype != BCMILCP_SUBTYPE_VENDOR_LONG {
398 warn!("unexpected subtype {}", event_packet.hdr.subtype);
399 return;
400 }
401
402 const BCMILCP_BCM_SUBTYPE_EVENT: u16 = 1;
403 if event_packet.hdr.user_subtype != BCMILCP_BCM_SUBTYPE_EVENT {
404 warn!("unexpected user_subtype {}", event_packet.hdr.subtype);
405 return;
406 }
407
408 let evt_type = events::Event::from(event_packet.msg.event_type as u8);
409 debug!(
410 "=== EVENT {:?}: {:?} {:02x}",
411 evt_type,
412 event_packet.msg,
413 Bytes(evt_data)
414 );
415
416 if self.events.mask.is_enabled(evt_type) {
417 let status = event_packet.msg.status;
418 let event_payload = match evt_type {
419 Event::ESCAN_RESULT if status == EStatus::PARTIAL => {
420 let Some((_, bss_info)) = ScanResults::parse(evt_data) else { return };
421 let Some(bss_info) = BssInfo::parse(bss_info) else { return };
422 events::Payload::BssInfo(*bss_info)
423 }
424 Event::ESCAN_RESULT => events::Payload::None,
425 _ => events::Payload::None,
426 };
427
428 // this intentionally uses the non-blocking publish immediate
429 // publish() is a deadlock risk in the current design as awaiting here prevents ioctls
430 // The `Runner` always yields when accessing the device, so consumers always have a chance to receive the event
431 // (if they are actively awaiting the queue)
432 self.events.queue.publish_immediate(events::Message::new(
433 Status {
434 event_type: evt_type,
435 status,
436 },
437 event_payload,
438 ));
439 }
440 }
441 CHANNEL_TYPE_DATA => {
442 let Some((_, packet)) = BdcHeader::parse(payload) else { return };
443 trace!("rx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
444
445 match self.ch.try_rx_buf() {
446 Some(buf) => {
447 buf[..packet.len()].copy_from_slice(packet);
448 self.ch.rx_done(packet.len())
449 }
450 None => warn!("failed to push rxd packet to the channel."),
451 }
452 }
453 _ => {}
454 }
455 }
456
457 fn update_credit(&mut self, sdpcm_header: &SdpcmHeader) {
458 if sdpcm_header.channel_and_flags & 0xf < 3 {
459 let mut sdpcm_seq_max = sdpcm_header.bus_data_credit;
460 if sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) > 0x40 {
461 sdpcm_seq_max = self.sdpcm_seq + 2;
462 }
463 self.sdpcm_seq_max = sdpcm_seq_max;
464 }
465 }
466
467 fn has_credit(&self) -> bool {
468 self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0
469 }
470
471 async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) {
472 let mut buf = [0; 512];
473 let buf8 = slice8_mut(&mut buf);
474
475 let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len();
476
477 let sdpcm_seq = self.sdpcm_seq;
478 self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1);
479 self.ioctl_id = self.ioctl_id.wrapping_add(1);
480
481 let sdpcm_header = SdpcmHeader {
482 len: total_len as u16, // TODO does this len need to be rounded up to u32?
483 len_inv: !total_len as u16,
484 sequence: sdpcm_seq,
485 channel_and_flags: CHANNEL_TYPE_CONTROL,
486 next_length: 0,
487 header_length: SdpcmHeader::SIZE as _,
488 wireless_flow_control: 0,
489 bus_data_credit: 0,
490 reserved: [0, 0],
491 };
492
493 let cdc_header = CdcHeader {
494 cmd: cmd,
495 len: data.len() as _,
496 flags: kind as u16 | (iface as u16) << 12,
497 id: self.ioctl_id,
498 status: 0,
499 };
500 trace!("tx {:?}", sdpcm_header);
501 trace!(" {:?}", cdc_header);
502
503 buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes());
504 buf8[SdpcmHeader::SIZE..][..CdcHeader::SIZE].copy_from_slice(&cdc_header.to_bytes());
505 buf8[SdpcmHeader::SIZE + CdcHeader::SIZE..][..data.len()].copy_from_slice(data);
506
507 let total_len = (total_len + 3) & !3; // round up to 4byte
508
509 trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)]));
510
511 self.bus.wlan_write(&buf[..total_len / 4]).await;
512 }
513
514 async fn core_disable(&mut self, core: Core) {
515 let base = core.base_addr();
516
517 // Dummy read?
518 let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
519
520 // Check it isn't already reset
521 let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
522 if r & AI_RESETCTRL_BIT_RESET != 0 {
523 return;
524 }
525
526 self.bus.bp_write8(base + AI_IOCTRL_OFFSET, 0).await;
527 let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
528
529 block_for(Duration::from_millis(1));
530
531 self.bus
532 .bp_write8(base + AI_RESETCTRL_OFFSET, AI_RESETCTRL_BIT_RESET)
533 .await;
534 let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
535 }
536
537 async fn core_reset(&mut self, core: Core) {
538 self.core_disable(core).await;
539
540 let base = core.base_addr();
541 self.bus
542 .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN)
543 .await;
544 let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
545
546 self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
547
548 Timer::after(Duration::from_millis(1)).await;
549
550 self.bus
551 .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN)
552 .await;
553 let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
554
555 Timer::after(Duration::from_millis(1)).await;
556 }
557
558 async fn core_is_up(&mut self, core: Core) -> bool {
559 let base = core.base_addr();
560
561 let io = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
562 if io & (AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) != AI_IOCTRL_BIT_CLOCK_EN {
563 debug!("core_is_up: returning false due to bad ioctrl {:02x}", io);
564 return false;
565 }
566
567 let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
568 if r & (AI_RESETCTRL_BIT_RESET) != 0 {
569 debug!("core_is_up: returning false due to bad resetctrl {:02x}", r);
570 return false;
571 }
572
573 true
574 }
575}