aboutsummaryrefslogtreecommitdiff
path: root/src/runner.rs
diff options
context:
space:
mode:
authorkbleeke <[email protected]>2023-03-02 12:10:13 +0100
committerkbleeke <[email protected]>2023-03-22 15:35:02 +0100
commit20923080e6ea313278b5f3aa8ec21055c6208527 (patch)
treeb30e9545302fa9ef68dfa25748602877f838f722 /src/runner.rs
parent8b24fe3df02862991b2574f9d5c9ada7bd27706b (diff)
split lib.rs into multiple files
Diffstat (limited to 'src/runner.rs')
-rw-r--r--src/runner.rs564
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 @@
1use core::cell::Cell;
2use core::slice;
3
4use embassy_futures::yield_now;
5use embassy_net_driver_channel as ch;
6use embassy_sync::pubsub::PubSubBehavior;
7use embassy_time::{block_for, Duration, Timer};
8use embedded_hal_1::digital::OutputPin;
9
10use crate::bus::Bus;
11pub use crate::bus::SpiBusCyw43;
12use crate::consts::*;
13use crate::events::{EventQueue, EventStatus};
14use crate::nvram::NVRAM;
15use crate::structs::*;
16use crate::{events, Core, IoctlState, IoctlType, CHIP, MTU};
17
18#[cfg(feature = "firmware-logs")]
19struct LogState {
20 addr: u32,
21 last_idx: usize,
22 buf: [u8; 256],
23 buf_count: usize,
24}
25
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 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
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 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
561fn 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}