Skip to main content

strat9_kernel/hardware/usb/
ehci.rs

1// USB EHCI (Enhanced Host Controller Interface) Driver
2// Reference: EHCI spec 1.0 (USB 2.0)
3//
4// Features:
5// - EHCI controller initialization
6// - Port management
7// - Periodic and asynchronous schedules
8// - High-speed USB 2.0 support
9
10#![allow(dead_code)]
11
12use crate::{
13    hardware::pci_client::{self as pci, Bar, ProbeCriteria},
14    memory::{allocate_zeroed_frame, paging, phys_to_virt},
15};
16use alloc::{sync::Arc, vec::Vec};
17use core::sync::atomic::{AtomicBool, Ordering};
18use spin::Mutex;
19
20const EHCI_MMIO_SIZE: usize = 0x1000;
21
22const USBCMD_RUN_STOP: u32 = 1 << 0;
23const USBCMD_HCRST: u32 = 1 << 1;
24const USBCMD_INTE: u32 = 1 << 2;
25const USBCMD_PSE: u32 = 1 << 4;
26const USBCMD_ASE: u32 = 1 << 5;
27
28const USBSTS_INT: u32 = 1 << 0;
29const USBSTS_ERR: u32 = 1 << 1;
30const USBSTS_PCD: u32 = 1 << 2;
31const USBSTS_HCH: u32 = 1 << 12;
32
33const PORTSC_CCS: u32 = 1 << 0;
34const PORTSC_CSC: u32 = 1 << 1;
35const PORTSC_PE: u32 = 1 << 2;
36const PORTSC_PEC: u32 = 1 << 3;
37const PORTSC_OCA: u32 = 1 << 4;
38const PORTSC_OCC: u32 = 1 << 5;
39const PORTSC_FPR: u32 = 1 << 6;
40const PORTSC_SUSP: u32 = 1 << 7;
41const PORTSC_PR: u32 = 1 << 8;
42const PORTSC_PP: u32 = 1 << 12;
43const PORTSC_SPEED_SHIFT: u32 = 26;
44const PORTSC_SPEED_MASK: u32 = 0x03 << PORTSC_SPEED_SHIFT;
45
46const SPEED_FULL: u32 = 0;
47const SPEED_LOW: u32 = 1;
48const SPEED_HIGH: u32 = 2;
49
50#[repr(C)]
51struct EhciCapRegisters {
52    caplength: u8,
53    _reserved: u8,
54    hciversion: u16,
55    hcsparams1: u32,
56    hcsparams2: u32,
57    hccparams: u32,
58}
59
60#[repr(C)]
61struct EhciOpRegisters {
62    usbcmd: u32,
63    usbsts: u32,
64    usbintr: u32,
65    frindex: u32,
66    ctrl_ds_seg: u32,
67    periodic_list_base: u32,
68    async_list_base: u32,
69    _reserved: [u32; 9],
70    config_flag: u32,
71}
72
73#[repr(C)]
74struct EhciPortRegisters {
75    portsc: [u32; 16],
76}
77
78pub struct EhciPort {
79    port_num: usize,
80    enabled: bool,
81    connected: bool,
82    speed: u8,
83}
84
85pub struct EhciController {
86    mmio_base: usize,
87    cap_regs: *const EhciCapRegisters,
88    op_regs: *mut EhciOpRegisters,
89    port_regs: *mut EhciPortRegisters,
90    max_ports: usize,
91    ports: Vec<EhciPort>,
92    periodic_list: *mut u32,
93    periodic_list_phys: u64,
94    async_list: *mut u32,
95    async_list_phys: u64,
96}
97
98unsafe impl Send for EhciController {}
99unsafe impl Sync for EhciController {}
100
101impl EhciController {
102    /// Creates a new instance.
103    pub unsafe fn new(pci_dev: pci::PciDevice) -> Result<Arc<Self>, &'static str> {
104        let bar = match pci_dev.read_bar(0) {
105            Some(Bar::Memory32 { addr, .. }) => addr as u64,
106            _ => return Err("Invalid BAR"),
107        };
108
109        paging::ensure_identity_map_range(bar, EHCI_MMIO_SIZE as u64);
110
111        let mmio_base = phys_to_virt(bar) as usize;
112        let cap_regs = mmio_base as *const EhciCapRegisters;
113        let caplength = (*cap_regs).caplength;
114        let op_regs = (mmio_base + caplength as usize) as *mut EhciOpRegisters;
115        let port_regs = (mmio_base + caplength as usize + 0x44) as *mut EhciPortRegisters;
116
117        let max_ports = ((*cap_regs).hcsparams1 as usize) & 0xF;
118
119        let mut controller = Self {
120            mmio_base,
121            cap_regs,
122            op_regs,
123            port_regs,
124            max_ports,
125            ports: Vec::new(),
126            periodic_list: core::ptr::null_mut(),
127            periodic_list_phys: 0,
128            async_list: core::ptr::null_mut(),
129            async_list_phys: 0,
130        };
131
132        controller.init()?;
133        Ok(Arc::new(controller))
134    }
135
136    /// Performs the init operation.
137    fn init(&mut self) -> Result<(), &'static str> {
138        unsafe {
139            let cmd = core::ptr::addr_of_mut!((*self.op_regs).usbcmd);
140            let sts = core::ptr::addr_of!((*self.op_regs).usbsts);
141            let intr = core::ptr::addr_of_mut!((*self.op_regs).usbintr);
142            let cfg = core::ptr::addr_of_mut!((*self.op_regs).config_flag);
143
144            // Stop the controller
145            cmd.write_volatile(cmd.read_volatile() & !USBCMD_RUN_STOP);
146            for _ in 0..100_000u32 {
147                if sts.read_volatile() & USBSTS_HCH != 0 {
148                    break;
149                }
150                core::hint::spin_loop();
151            }
152            if sts.read_volatile() & USBSTS_HCH == 0 {
153                return Err("EHCI: halt timeout");
154            }
155
156            // Reset the controller
157            cmd.write_volatile(cmd.read_volatile() | USBCMD_HCRST);
158            for _ in 0..100_000u32 {
159                if cmd.read_volatile() & USBCMD_HCRST == 0 {
160                    break;
161                }
162                core::hint::spin_loop();
163            }
164            if cmd.read_volatile() & USBCMD_HCRST != 0 {
165                return Err("EHCI: reset timeout");
166            }
167
168            // Initialize ports
169            for i in 0..self.max_ports {
170                let portsc = self.read_portsc(i);
171                self.ports.push(EhciPort {
172                    port_num: i,
173                    enabled: (portsc & PORTSC_PE) != 0,
174                    connected: (portsc & PORTSC_CCS) != 0,
175                    speed: ((portsc >> PORTSC_SPEED_SHIFT) & 0x03) as u8,
176                });
177            }
178
179            // Initialize schedules
180            self.init_schedules()?;
181
182            // Enable interrupts
183            intr.write_volatile(USBSTS_INT | USBSTS_ERR | USBSTS_PCD);
184
185            // Start the controller
186            cmd.write_volatile(
187                cmd.read_volatile() | USBCMD_RUN_STOP | USBCMD_PSE | USBCMD_ASE | USBCMD_INTE,
188            );
189            cfg.write_volatile(1);
190        }
191        Ok(())
192    }
193
194    /// Initializes schedules.
195    unsafe fn init_schedules(&mut self) -> Result<(), &'static str> {
196        // Allocate periodic list (4KB aligned, 1024 entries)
197        let periodic_frame = allocate_zeroed_frame().ok_or("Failed to allocate periodic list")?;
198        self.periodic_list_phys = periodic_frame.start_address.as_u64();
199        self.periodic_list = phys_to_virt(self.periodic_list_phys) as *mut u32;
200        core::ptr::write_bytes(self.periodic_list as *mut u8, 0, 4096);
201
202        // Allocate async list (32-byte aligned)
203        let async_frame = allocate_zeroed_frame().ok_or("Failed to allocate async list")?;
204        self.async_list_phys = async_frame.start_address.as_u64();
205        self.async_list = phys_to_virt(self.async_list_phys) as *mut u32;
206        core::ptr::write_bytes(self.async_list as *mut u8, 0, 4096);
207
208        // Set up async list (empty, points to itself)
209        core::ptr::write_volatile(self.async_list, (self.async_list_phys as u32) & 0xFFFFFFE0);
210
211        let plb = core::ptr::addr_of_mut!((*self.op_regs).periodic_list_base);
212        let alb = core::ptr::addr_of_mut!((*self.op_regs).async_list_base);
213        plb.write_volatile(self.periodic_list_phys as u32);
214        alb.write_volatile(self.async_list_phys as u32);
215
216        Ok(())
217    }
218
219    /// Reads portsc.
220    unsafe fn read_portsc(&self, port: usize) -> u32 {
221        let portsc_ptr = core::ptr::addr_of!((*self.port_regs).portsc[port]) as *const u32;
222        portsc_ptr.read_volatile()
223    }
224
225    /// Writes portsc.
226    unsafe fn write_portsc(&self, port: usize, val: u32) {
227        let portsc_ptr = core::ptr::addr_of!((*self.port_regs).portsc[port]) as *mut u32;
228        portsc_ptr.write_volatile(val);
229    }
230
231    /// Performs the port count operation.
232    pub fn port_count(&self) -> usize {
233        self.max_ports
234    }
235
236    /// Returns whether port connected.
237    pub fn is_port_connected(&self, port: usize) -> bool {
238        if port >= self.ports.len() {
239            return false;
240        }
241        self.ports[port].connected
242    }
243
244    /// Returns port speed.
245    pub fn get_port_speed(&self, port: usize) -> u8 {
246        if port >= self.ports.len() {
247            return 0;
248        }
249        self.ports[port].speed
250    }
251
252    /// Reset a port and wait for enable.
253    unsafe fn reset_port(&self, port: usize) -> bool {
254        let mut portsc = self.read_portsc(port);
255        if portsc & PORTSC_CCS == 0 {
256            return false;
257        }
258
259        // Port reset
260        portsc = self.read_portsc(port);
261        self.write_portsc(port, portsc | PORTSC_PR);
262        for _ in 0..10_000u32 {
263            core::hint::spin_loop();
264        }
265        portsc = self.read_portsc(port);
266        self.write_portsc(port, portsc & !PORTSC_PR);
267        for _ in 0..10_000u32 {
268            core::hint::spin_loop();
269        }
270
271        // Wait for port enable
272        for _ in 0..100_000u32 {
273            portsc = self.read_portsc(port);
274            if portsc & PORTSC_PE != 0 {
275                return true;
276            }
277            if portsc & PORTSC_CCS == 0 {
278                return false;
279            }
280            core::hint::spin_loop();
281        }
282        false
283    }
284
285    /// Execute a USB control transfer on the async schedule.
286    ///
287    /// Builds a QH + TD chain, inserts into the async schedule, and polls
288    /// for completion.
289    unsafe fn ctrl_transfer(
290        &self,
291        _port: usize,
292        setup_data: &[u8; 8],
293        data_buf: Option<&mut [u8]>,
294        data_len: usize,
295        device_addr: u8,
296        max_packet: u32,
297    ) -> Result<usize, &'static str> {
298        let qh_frame = allocate_zeroed_frame().ok_or("EHCI: QH alloc failed")?;
299        let qh_phys = qh_frame.start_address.as_u64();
300        let qh_virt = phys_to_virt(qh_phys) as *mut u32;
301
302        let td_frame = allocate_zeroed_frame().ok_or("EHCI: TD alloc failed")?;
303        let td_phys = td_frame.start_address.as_u64();
304        let td_virt = phys_to_virt(td_phys) as *mut u32;
305
306        let setup_frame = allocate_zeroed_frame().ok_or("EHCI: setup buf alloc failed")?;
307        let setup_buf_phys = setup_frame.start_address.as_u64();
308        let setup_buf_virt = phys_to_virt(setup_buf_phys) as *mut u8;
309        core::ptr::copy_nonoverlapping(setup_data.as_ptr(), setup_buf_virt, 8);
310
311        let dir_in = (setup_data[0] & 0x80) != 0;
312        let has_data = data_buf.is_some();
313
314        // EHCI QH (48 bytes, 32-byte aligned):
315        //   +0x00: horizontal link pointer
316        //   +0x04: endpoint characteristics
317        //   +0x08: endpoint capabilities
318        //   +0x0C: current TD pointer
319        //   +0x10: next TD pointer
320        //   +0x14: alternate next TD pointer
321        qh_virt.add(0).write_volatile(0x0000_0002); // horizontal: terminate
322        qh_virt.add(1).write_volatile(
323            (device_addr as u32 & 0x7F)            // bits 6:0 = device address
324            | ((max_packet & 0x7FF) << 16), // bits 26:16 = max packet size
325        );
326        qh_virt.add(2).write_volatile(0); // endpoint capabilities
327        qh_virt.add(3).write_volatile(td_phys as u32); // current TD
328        qh_virt.add(4).write_volatile(td_phys as u32); // next TD
329
330        // EHCI TD (32 bytes, 32-byte aligned):
331        //   +0x00: next TD pointer
332        //   +0x04: alternate next TD pointer
333        //   +0x08: token
334        //   +0x0C..+0x18: buffer pointer 0-3
335        //
336        // Token bits (EHCI spec ยง3.3.2):
337        //   31    = Active
338        //   30    = Data Toggle
339        //   29:28 = CERR (error count)
340        //   27:26 = Current Page
341        //   25    = IOC (Interrupt On Complete)
342        //   30:16 = Total bytes to transfer (NOTE: overlaps Data Toggle bit)
343        //   15:0  = PID code
344        //
345        // Encoding: Active(1) | Toggle(0/1) | Bytes(15b) | IOC(1) | CERR(2b) | Page(2b) | PID(16b)
346        //   = (1<<31) | (toggle<<30) | (bytes<<16) | (ioc<<25) | (cerr<<26) | (page<<26) | pid
347
348        // --- Setup TD: PID_SETUP=0x2D, 8 bytes, DATA0 (toggle=0) ---
349        let setup_token = (1u32 << 31)              // Active
350            | (0u32 << 30)                          // Data Toggle = 0 (DATA0)
351            | ((8u32 & 0x7FFF) << 16)               // Total bytes = 8
352            | (0u32 << 25)                          // IOC = 0
353            | (3u32 << 26)                          // CERR = 3
354            | (0x2Du32); // PID = SETUP
355        td_virt.add(0).write_volatile(0x0000_0002); // next: terminate
356        td_virt.add(1).write_volatile(0x0000_0002); // alt next: terminate
357        td_virt.add(2).write_volatile(setup_token);
358        td_virt.add(3).write_volatile(setup_buf_phys as u32);
359
360        if has_data && data_len > 0 {
361            let data_frame = allocate_zeroed_frame().ok_or("EHCI: data buf alloc failed")?;
362            let data_buf_phys = data_frame.start_address.as_u64();
363            let data_buf_virt = phys_to_virt(data_buf_phys) as *mut u8;
364
365            if !dir_in {
366                if let Some(ref buf) = data_buf {
367                    core::ptr::copy_nonoverlapping(buf.as_ptr(), data_buf_virt, data_len);
368                }
369            }
370
371            // --- Data TD: toggle=1 (DATA1), PID IN/OUT ---
372            let data_pid: u32 = if dir_in { 0x69 } else { 0xE1 };
373            let data_token = (1u32 << 31)           // Active
374                | (1u32 << 30)                      // Data Toggle = 1 (DATA1)
375                | (((data_len as u32) & 0x7FFF) << 16) // Total bytes
376                | (0u32 << 25)                      // IOC = 0
377                | (3u32 << 26)                      // CERR = 3
378                | data_pid; // PID = IN/OUT
379            let data_td_virt = (td_virt as *mut u8).add(0x20) as *mut u32;
380            data_td_virt.add(0).write_volatile(0x0000_0002);
381            data_td_virt.add(1).write_volatile(0x0000_0002);
382            data_td_virt.add(2).write_volatile(data_token);
383            data_td_virt.add(3).write_volatile(data_buf_phys as u32);
384
385            // --- Status TD: toggle=0, 0 bytes, IOC=1 ---
386            let status_token = (1u32 << 31)        // Active
387                | (0u32 << 30)                      // Data Toggle = 0
388                | (0u32 << 16)                      // Total bytes = 0
389                | (1u32 << 25)                      // IOC = 1
390                | (3u32 << 26)                      // CERR = 3
391                | (0u32); // PID = OUT (for IN transfer status)
392            let status_td_virt = (td_virt as *mut u8).add(0x40) as *mut u32;
393            status_td_virt.add(0).write_volatile(0x0000_0002);
394            status_td_virt.add(1).write_volatile(0x0000_0002);
395            status_td_virt.add(2).write_volatile(status_token);
396            status_td_virt.add(3).write_volatile(0);
397
398            // Chain: setup -> data -> status
399            td_virt.add(0).write_volatile((td_phys + 0x20) as u32);
400            data_td_virt.add(0).write_volatile((td_phys + 0x40) as u32);
401        } else {
402            // --- Status-only TD: toggle=1, 0 bytes, IOC=1 ---
403            let status_token = (1u32 << 31)
404                | (1u32 << 30)                      // Data Toggle = 1 (status stage)
405                | (0u32 << 16)
406                | (1u32 << 25)                      // IOC = 1
407                | (3u32 << 26)
408                | (0x69u32); // PID = IN (for OUT transfer status)
409            let status_td_virt = (td_virt as *mut u8).add(0x20) as *mut u32;
410            status_td_virt.add(0).write_volatile(0x0000_0002);
411            status_td_virt.add(1).write_volatile(0x0000_0002);
412            status_td_virt.add(2).write_volatile(status_token);
413            status_td_virt.add(3).write_volatile(0);
414
415            td_virt.add(0).write_volatile((td_phys + 0x20) as u32);
416        }
417
418        // Insert QH at head of async schedule
419        let async_head = self.async_list;
420        let old_head = core::ptr::read_volatile(async_head);
421        qh_virt.add(0).write_volatile(old_head & 0xFFFFFFE0 | 0x02);
422        core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
423        core::ptr::write_volatile(async_head, (qh_phys as u32 & 0xFFFFFFE0) | 0x02);
424
425        // Enable async schedule
426        let cmd = core::ptr::addr_of!((*self.op_regs).usbcmd);
427        core::ptr::write_volatile(cmd as *mut u32, cmd.read_volatile() | USBCMD_ASE);
428        for _ in 0..10_000u32 {
429            core::hint::spin_loop();
430        }
431
432        // Poll status TD for completion
433        let status_td_virt = if has_data && data_len > 0 {
434            (td_virt as *mut u8).add(0x40) as *mut u32
435        } else {
436            (td_virt as *mut u8).add(0x20) as *mut u32
437        };
438
439        let mut transferred = 0;
440        for _ in 0..1_000_000u32 {
441            let token = core::ptr::read_volatile(status_td_virt.add(2));
442            if token & (1u32 << 31) == 0 {
443                if dir_in && has_data && data_len > 0 {
444                    if let Some(buf) = data_buf {
445                        let data_td = (td_virt as *mut u8).add(0x20) as *const u32;
446                        let buf_phys = core::ptr::read_volatile(data_td.add(3));
447                        let src = phys_to_virt(buf_phys as u64) as *const u8;
448                        core::ptr::copy_nonoverlapping(src, buf.as_mut_ptr(), data_len);
449                        transferred = data_len;
450                    }
451                }
452                break;
453            }
454            core::hint::spin_loop();
455        }
456
457        // Disable async schedule and restore head
458        core::ptr::write_volatile(cmd as *mut u32, cmd.read_volatile() & !USBCMD_ASE);
459        for _ in 0..10_000u32 {
460            core::hint::spin_loop();
461        }
462        core::ptr::write_volatile(async_head, old_head);
463
464        Ok(transferred)
465    }
466
467    /// Enumerate connected ports and hand off HID devices.
468    fn enumerate_all_ports(&self) {
469        let mut usb_address: u8 = 1;
470
471        for port in 0..self.max_ports {
472            let portsc = unsafe { self.read_portsc(port) };
473            if portsc & PORTSC_CCS == 0 {
474                continue;
475            }
476
477            log::info!("[EHCI] Port {} connected, resetting...", port);
478
479            if !unsafe { self.reset_port(port) } {
480                log::warn!("[EHCI] Port {} reset failed", port);
481                continue;
482            }
483
484            let speed = unsafe { ((self.read_portsc(port) >> PORTSC_SPEED_SHIFT) & 0x03) as u8 };
485            let max_packet: u32 = if speed as u32 == SPEED_HIGH { 64 } else { 8 };
486            log::info!(
487                "[EHCI] Port {} speed={} max_pkt={}",
488                port,
489                speed,
490                max_packet
491            );
492
493            // Phase 1: SET_ADDRESS at address 0 (default)
494            let addr = usb_address;
495            let set_addr = [0x00u8, 0x05, addr, 0x00, 0x00, 0x00, 0x00, 0x00];
496            if unsafe { self.ctrl_transfer(port, &set_addr, None, 0, 0, max_packet) }.is_err() {
497                log::warn!("[EHCI] Port {} set address failed", port);
498                continue;
499            }
500
501            // Phase 2: GET_DESCRIPTOR (first 8 bytes at new address to learn max_packet0)
502            let get_desc_8 = [0x80u8, 0x06, 0x00, 0x01, 0x00, 0x00, 8, 0x00];
503            let mut desc8 = [0u8; 8];
504            if unsafe {
505                self.ctrl_transfer(port, &get_desc_8, Some(&mut desc8), 8, addr, max_packet)
506            }
507            .is_err()
508            {
509                log::warn!("[EHCI] Port {} get desc (8) failed", addr);
510                usb_address += 1;
511                continue;
512            }
513
514            let vid = u16::from_le_bytes([desc8[2], desc8[3]]);
515            let pid = u16::from_le_bytes([desc8[4], desc8[5]]);
516            let max_pkt0 = desc8[7] as u32;
517            log::info!(
518                "[EHCI] Port {} device VID={:04x} PID={:04x} max_pkt0={}",
519                port,
520                vid,
521                pid,
522                max_pkt0
523            );
524
525            // Phase 3: GET_DESCRIPTOR (full 18 bytes with real max_packet0)
526            let mut desc18 = [0u8; 18];
527            let get_desc_18 = [0x80u8, 0x06, 0x00, 0x01, 0x00, 0x00, 18, 0x00];
528            let _ = unsafe {
529                self.ctrl_transfer(port, &get_desc_18, Some(&mut desc18), 18, addr, max_pkt0)
530            };
531
532            let dev_class = desc18[4];
533            log::info!("[EHCI] Port {} class={:02x}", port, dev_class);
534
535            // Phase 4: SET_CONFIGURATION (value=1)
536            let set_config = [0x00u8, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
537            let _ = unsafe { self.ctrl_transfer(port, &set_config, None, 0, addr, max_pkt0) };
538
539            // Phase 5: Hand off to HID driver
540            crate::hardware::usb::hid::enumerate_device(port, addr, &desc18);
541
542            usb_address += 1;
543        }
544    }
545}
546
547static EHCI_CONTROLLERS: Mutex<Vec<Arc<EhciController>>> = Mutex::new(Vec::new());
548static EHCI_INITIALIZED: AtomicBool = AtomicBool::new(false);
549
550/// Performs the init operation.
551pub fn init() {
552    log::info!("[EHCI] Scanning for EHCI controllers...");
553
554    let candidates = pci::probe_all(ProbeCriteria {
555        vendor_id: None,
556        device_id: None,
557        class_code: Some(0x0C),
558        subclass: Some(0x03),
559        prog_if: Some(0x20),
560    });
561
562    for pci_dev in candidates.into_iter() {
563        log::info!(
564            "EHCI: Found controller at {:?} (VEN:{:04x} DEV:{:04x})",
565            pci_dev.address,
566            pci_dev.vendor_id,
567            pci_dev.device_id
568        );
569
570        pci_dev.enable_bus_master();
571
572        match unsafe { EhciController::new(pci_dev) } {
573            Ok(controller) => {
574                log::info!("[EHCI] Initialized with {} ports", controller.port_count());
575                controller.enumerate_all_ports();
576                EHCI_CONTROLLERS.lock().push(controller);
577            }
578            Err(e) => {
579                log::warn!("EHCI: Failed to initialize controller: {}", e);
580            }
581        }
582    }
583
584    EHCI_INITIALIZED.store(true, Ordering::SeqCst);
585    log::info!(
586        "[EHCI] Found {} controller(s)",
587        EHCI_CONTROLLERS.lock().len()
588    );
589}
590
591/// Returns controller.
592pub fn get_controller(index: usize) -> Option<Arc<EhciController>> {
593    EHCI_CONTROLLERS.lock().get(index).cloned()
594}
595
596/// Returns whether available.
597pub fn is_available() -> bool {
598    EHCI_INITIALIZED.load(Ordering::Relaxed)
599}