Skip to content

Commit 7194e7a

Browse files
committed
feature: removed refCell, use an arrat of Cell<CmdEntry>
1 parent 30a1900 commit 7194e7a

2 files changed

Lines changed: 59 additions & 53 deletions

File tree

chips/x86_q35/src/cmd_fifo.rs

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,73 +11,87 @@
1111
// By requiring `T: FifoItem` with a `const EMPTY`, we can do `[T::EMPTY; N]`
1212
// and safely build the FIFO at compile time
1313

14+
use core::cell::Cell;
15+
1416
pub(crate) trait FifoItem: Copy {
1517
/// Const zero/empty value used to initialize the backing array.
1618
const EMPTY: Self;
1719
}
1820

19-
pub(crate) struct Fifo<T: FifoItem, const N: usize> {
20-
buf: [T; N],
21-
head: usize,
22-
tail: usize,
23-
len: usize,
21+
pub struct Fifo<T: Copy + FifoItem, const N: usize> {
22+
buf: [Cell<T>; N],
23+
head: Cell<usize>,
24+
tail: Cell<usize>,
25+
len: Cell<usize>,
2426
}
2527

26-
impl<T: FifoItem, const N: usize> Fifo<T, N> {
28+
impl<T: Copy + FifoItem, const N: usize> Fifo<T, N> {
2729
pub(crate) const fn new() -> Self {
2830
Self {
29-
buf: [T::EMPTY; N],
30-
head: 0,
31-
tail: 0,
32-
len: 0,
31+
buf: [const { Cell::new(T::EMPTY) }; N],
32+
head: Cell::new(0),
33+
tail: Cell::new(0),
34+
len: Cell::new(0),
3335
}
3436
}
3537

3638
#[inline]
3739
pub(crate) fn is_empty(&self) -> bool {
38-
self.len == 0
40+
self.len.get() == 0
3941
}
42+
4043
#[inline]
4144
pub(crate) fn is_full(&self) -> bool {
42-
self.len == N
45+
self.len.get() == N
4346
}
47+
48+
/// Push at head; returns Err(item) if full
4449
#[inline]
45-
pub(crate) fn push(&mut self, item: T) -> Result<(), ()> {
50+
pub(crate) fn push(&self, item: T) -> Result<(), T> {
4651
if self.is_full() {
47-
return Err(());
52+
return Err(item);
4853
}
49-
self.buf[self.head] = item;
50-
self.head = (self.head + 1) % N;
51-
self.len += 1;
54+
let h = self.head.get();
55+
self.buf[h].set(item);
56+
self.head.set((h + 1) % N);
57+
self.len.set(self.len.get() + 1);
5258
Ok(())
5359
}
5460

61+
/// Copy the current head entry (None if empty).
5562
#[inline]
56-
pub(crate) fn peek(&self) -> Option<&T> {
63+
pub(crate) fn peek_copy(&self) -> Option<T> {
5764
if self.is_empty() {
5865
None
5966
} else {
60-
Some(&self.buf[self.tail])
67+
Some(self.buf[self.tail.get()].get())
6168
}
6269
}
6370

71+
/// Read-modify-write the current head entry; returns closure result.
6472
#[inline]
65-
pub(crate) fn peek_mut(&mut self) -> Option<&mut T> {
73+
pub(crate) fn peek_update<R>(&self, f: impl FnOnce(&mut T) -> R) -> Option<R> {
6674
if self.is_empty() {
6775
None
6876
} else {
69-
Some(&mut self.buf[self.tail])
77+
let t = self.tail.get();
78+
let mut v = self.buf[t].get();
79+
let r = f(&mut v);
80+
self.buf[t].set(v);
81+
Some(r)
7082
}
7183
}
7284

85+
/// Pop from tail; returns a copy of the removed item.
7386
#[inline]
74-
pub(crate) fn pop(&mut self) -> Option<T> {
87+
pub(crate) fn pop(&self) -> Option<T> {
7588
if self.is_empty() {
7689
return None;
7790
}
78-
let item = self.buf[self.tail];
79-
self.tail = (self.tail + 1) % N;
80-
self.len -= 1;
91+
let t = self.tail.get();
92+
let item = self.buf[t].get();
93+
self.tail.set((t + 1) % N);
94+
self.len.set(self.len.get() - 1);
8195
Some(item)
8296
}
8397
}

chips/x86_q35/src/keyboard.rs

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
use crate::cmd_fifo::Fifo as CmdFifo;
1717
use crate::ps2::Ps2Client;
1818
use crate::ps2::Ps2Controller;
19-
use core::cell::{Cell, RefCell};
19+
use core::cell::Cell;
2020
use kernel::utilities::cells::OptionalCell;
2121

2222
/// Set-2 scancode constants used for decoding
@@ -131,8 +131,8 @@ pub struct Keyboard<'a> {
131131
shift_r: Cell<bool>,
132132
caps: Cell<bool>,
133133

134-
// command engine queue (ring FIFO)
135-
cmd_q: RefCell<CmdFifo<CmdEntry, CMDQ_LEN>>,
134+
// command engine queue (ring FIFO) - interior mutable via Cells inside
135+
cmd_q: CmdFifo<CmdEntry, CMDQ_LEN>,
136136

137137
in_flight: Cell<bool>, // waiting for ACK/RESEND to the last sent byte
138138
retries_left: Cell<u8>, // remaining entries for the current byte
@@ -158,7 +158,7 @@ impl<'a> Keyboard<'a> {
158158
shift_r: Cell::new(false),
159159
caps: Cell::new(false),
160160

161-
cmd_q: RefCell::new(CmdFifo::new()),
161+
cmd_q: CmdFifo::new(),
162162

163163
in_flight: Cell::new(false),
164164
retries_left: Cell::new(0),
@@ -305,12 +305,10 @@ impl<'a> Keyboard<'a> {
305305
let Some(entry) = CmdEntry::try_from_bytes(seq) else {
306306
return false;
307307
};
308-
let mut q = self.cmd_q.borrow_mut();
309-
if q.is_full() {
308+
if self.cmd_q.is_full() {
310309
return false;
311310
}
312-
let _ = q.push(entry);
313-
drop(q);
311+
let _ = self.cmd_q.push(entry);
314312
self.drive_tx();
315313
true
316314
}
@@ -322,20 +320,17 @@ impl<'a> Keyboard<'a> {
322320
}
323321

324322
// Peek current command
325-
let (byte_opt, done_opt) = {
326-
let q = self.cmd_q.borrow();
327-
match q.peek() {
328-
None => (None, None), // empty
329-
Some(e) if e.is_done() => (None, Some(true)),
330-
Some(e) => (Some(e.bytes[e.idx as usize]), Some(false)),
331-
}
323+
let (byte_opt, done_opt) = match self.cmd_q.peek_copy() {
324+
None => (None, None),
325+
Some(e) if e.is_done() => (None, Some(true)),
326+
Some(e) => (Some(e.bytes[e.idx as usize]), Some(false)),
332327
};
333328

334329
match done_opt {
335330
None => return, // queue empty
336331
Some(true) => {
337332
// finished entry => pop and try next
338-
self.cmd_q.borrow_mut().pop();
333+
self.cmd_q.pop();
339334
self.drive_tx();
340335
return;
341336
}
@@ -361,20 +356,17 @@ impl<'a> Keyboard<'a> {
361356
}
362357

363358
fn advance_idx_after_ack(&self) {
364-
let mut finished = false;
365-
{
366-
let mut q = self.cmd_q.borrow_mut();
367-
if let Some(e) = q.peek_mut() {
359+
let finished = self
360+
.cmd_q
361+
.peek_update(|e| {
368362
if !e.is_done() {
369363
e.idx = e.idx.saturating_add(1);
370364
}
371-
if e.is_done() {
372-
finished = true;
373-
}
374-
}
375-
if finished {
376-
q.pop();
377-
}
365+
e.is_done()
366+
})
367+
.unwrap_or(false);
368+
if finished {
369+
self.cmd_q.pop();
378370
}
379371
// New byte will get a fresh retry budget on first send
380372
self.retries_left.set(0);
@@ -468,7 +460,7 @@ impl Ps2Client for Keyboard<'_> {
468460
// Give up on this command
469461
self.cmd_drops.set(self.cmd_drops.get().wrapping_add(1));
470462
self.in_flight.set(false);
471-
self.cmd_q.borrow_mut().pop();
463+
self.cmd_q.pop();
472464
self.retries_left.set(0); // clear for the next new byte
473465
self.drive_tx();
474466
}

0 commit comments

Comments
 (0)