diff options
Diffstat (limited to '')
| -rw-r--r-- | rsnix/src/ehci.rs | 39 |
1 files changed, 30 insertions, 9 deletions
diff --git a/rsnix/src/ehci.rs b/rsnix/src/ehci.rs index 5ee11cf..0aa7e0d 100644 --- a/rsnix/src/ehci.rs +++ b/rsnix/src/ehci.rs | |||
| @@ -77,6 +77,15 @@ const MAX_DEV: usize = 4; // mouse + keyboard on each controller | |||
| 77 | const DMA_MIN: usize = 0x100_0000; // avoid <16 MiB (PCI-master hostile region) | 77 | const DMA_MIN: usize = 0x100_0000; // avoid <16 MiB (PCI-master hostile region) |
| 78 | const DMA_MAX: usize = 0x1_0000_0000; // 32-bit EHCI DMA pointers | 78 | const DMA_MAX: usize = 0x1_0000_0000; // 32-bit EHCI DMA pointers |
| 79 | 79 | ||
| 80 | // Descriptor layout. A controller with HCCPARAMS bit0 (64-bit addressing) | ||
| 81 | // reads an extra bufptr_hi[5] after the 32-bit buffer list: QH = 17 dwords | ||
| 82 | // (68 B), qTD = 13 dwords (52 B). Space every structure for that variant — | ||
| 83 | // 32-bit controllers simply ignore the tail — otherwise the HC parses the | ||
| 84 | // next qTD as a high buffer pointer and dies with a Host System Error. | ||
| 85 | const QTD_SLOT: usize = 0x40; // 64-byte qTD slots (52 B + padding) | ||
| 86 | const CTRL_QTD_OFF: usize = 0x100; // control qTDs, offset from the control QH | ||
| 87 | const HID_QTD_OFF: usize = 0x80; // HID qTD, offset from the HID QH | ||
| 88 | |||
| 80 | const BUF_DEV_DESC: usize = 0x000; // 64 B | 89 | const BUF_DEV_DESC: usize = 0x000; // 64 B |
| 81 | const BUF_CFG: usize = 0x100; // 512 B (hubs can have long configs) | 90 | const BUF_CFG: usize = 0x100; // 512 B (hubs can have long configs) |
| 82 | const BUF_HUB_DESC: usize = 0x300; // 64 B | 91 | const BUF_HUB_DESC: usize = 0x300; // 64 B |
| @@ -94,6 +103,7 @@ struct Ctrl { | |||
| 94 | framelist: *mut u32, | 103 | framelist: *mut u32, |
| 95 | qh_page: *mut u32, | 104 | qh_page: *mut u32, |
| 96 | buf_page: *mut u8, | 105 | buf_page: *mut u8, |
| 106 | caps64: bool, | ||
| 97 | } | 107 | } |
| 98 | 108 | ||
| 99 | impl Ctrl { | 109 | impl Ctrl { |
| @@ -106,6 +116,7 @@ impl Ctrl { | |||
| 106 | framelist: core::ptr::null_mut(), | 116 | framelist: core::ptr::null_mut(), |
| 107 | qh_page: core::ptr::null_mut(), | 117 | qh_page: core::ptr::null_mut(), |
| 108 | buf_page: core::ptr::null_mut(), | 118 | buf_page: core::ptr::null_mut(), |
| 119 | caps64: false, | ||
| 109 | }; | 120 | }; |
| 110 | } | 121 | } |
| 111 | 122 | ||
| @@ -282,9 +293,9 @@ unsafe fn ctl_xfer( | |||
| 282 | let head = cur_ctrl().async_head; | 293 | let head = cur_ctrl().async_head; |
| 283 | let xfer = cur_ctrl().xfer_qh; | 294 | let xfer = cur_ctrl().xfer_qh; |
| 284 | 295 | ||
| 285 | let st = xfer.add(0x40 / 4); // SETUP qtd (32-byte aligned) | 296 | let st = xfer.add(CTRL_QTD_OFF / 4); // SETUP qtd (32-byte aligned) |
| 286 | let dt = st.add(0x20 / 4); // DATA qtd | 297 | let dt = st.add(QTD_SLOT / 4); // DATA qtd |
| 287 | let sp = dt.add(0x20 / 4); // STATUS qtd | 298 | let sp = dt.add(QTD_SLOT / 4); // STATUS qtd |
| 288 | 299 | ||
| 289 | core::ptr::write_volatile(st.add(0), 0u32); | 300 | core::ptr::write_volatile(st.add(0), 0u32); |
| 290 | core::ptr::write_volatile(st.add(1), QT_TERMINATE); | 301 | core::ptr::write_volatile(st.add(1), QT_TERMINATE); |
| @@ -295,7 +306,7 @@ unsafe fn ctl_xfer( | |||
| 295 | for i in 0..5 { | 306 | for i in 0..5 { |
| 296 | core::ptr::write_volatile(st.add(3 + i), 0u32); | 307 | core::ptr::write_volatile(st.add(3 + i), 0u32); |
| 297 | } | 308 | } |
| 298 | let sbuf = xfer.add(0x110 / 4); | 309 | let sbuf = xfer.add(0x1C0 / 4); |
| 299 | let sb = core::slice::from_raw_parts_mut(sbuf.cast::<u8>(), 8); | 310 | let sb = core::slice::from_raw_parts_mut(sbuf.cast::<u8>(), 8); |
| 300 | sb.copy_from_slice(req); | 311 | sb.copy_from_slice(req); |
| 301 | core::ptr::write_volatile(st.add(3), sbuf as u32); | 312 | core::ptr::write_volatile(st.add(3), sbuf as u32); |
| @@ -434,13 +445,14 @@ unsafe fn ctl_xfer( | |||
| 434 | ); | 445 | ); |
| 435 | if !QR_SHOWN.swap(true, Ordering::Relaxed) { | 446 | if !QR_SHOWN.swap(true, Ordering::Relaxed) { |
| 436 | let l1 = alloc::format!( | 447 | let l1 = alloc::format!( |
| 437 | "EHCI fail stage={} t={}ms sp={} dev={} in={} len={}", | 448 | "EHCI fail stage={} t={}ms sp={} dev={} in={} len={} c64={}", |
| 438 | stage, | 449 | stage, |
| 439 | crate::interrupts::uptime_ms().wrapping_sub(t0), | 450 | crate::interrupts::uptime_ms().wrapping_sub(t0), |
| 440 | speed, | 451 | speed, |
| 441 | dev, | 452 | dev, |
| 442 | dir_in, | 453 | dir_in, |
| 443 | len | 454 | len, |
| 455 | cur_ctrl().caps64 as u8 | ||
| 444 | ); | 456 | ); |
| 445 | let l2 = alloc::format!("cmd={:08x} sts={:08x}", rd(op(OPCMD)), rd(op(OPSTS))); | 457 | let l2 = alloc::format!("cmd={:08x} sts={:08x}", rd(op(OPCMD)), rd(op(OPSTS))); |
| 446 | let l3 = alloc::format!( | 458 | let l3 = alloc::format!( |
| @@ -456,7 +468,14 @@ unsafe fn ctl_xfer( | |||
| 456 | core::ptr::read_volatile(qh_next_qtd(xfer)) | 468 | core::ptr::read_volatile(qh_next_qtd(xfer)) |
| 457 | ); | 469 | ); |
| 458 | let l5 = alloc::format!("setup={:08x} data={:08x} stat={:08x}", stok, dtok, ptok); | 470 | let l5 = alloc::format!("setup={:08x} data={:08x} stat={:08x}", stok, dtok, ptok); |
| 459 | let all = [l1, l2, l3, l4, l5]; | 471 | let l6 = alloc::format!( |
| 472 | "dma a={:08x} x={:08x} s={:08x} b={:08x}", | ||
| 473 | cur_ctrl().async_head as usize, | ||
| 474 | xfer as usize, | ||
| 475 | sbuf as usize, | ||
| 476 | cur_ctrl().buf_page as usize | ||
| 477 | ); | ||
| 478 | let all = [l1, l2, l3, l4, l5, l6]; | ||
| 460 | let refs: alloc::vec::Vec<&str> = all.iter().map(|s| s.as_str()).collect(); | 479 | let refs: alloc::vec::Vec<&str> = all.iter().map(|s| s.as_str()).collect(); |
| 461 | crate::gop::dump_qr(&refs); | 480 | crate::gop::dump_qr(&refs); |
| 462 | crate::gop::qr_lock(); | 481 | crate::gop::qr_lock(); |
| @@ -654,7 +673,7 @@ unsafe fn register_hid( | |||
| 654 | } | 673 | } |
| 655 | let c = ctrl_mut(ci); | 674 | let c = ctrl_mut(ci); |
| 656 | let qh = c.qh_page.add(slot * 0x100 / 4); | 675 | let qh = c.qh_page.add(slot * 0x100 / 4); |
| 657 | let iqtd = qh.add(0x40 / 4); | 676 | let iqtd = qh.add(HID_QTD_OFF / 4); |
| 658 | let report = c.buf_page.add(BUF_REPORT + slot * 64); | 677 | let report = c.buf_page.add(BUF_REPORT + slot * 64); |
| 659 | core::ptr::write_bytes(qh as *mut u8, 0, 0x100); | 678 | core::ptr::write_bytes(qh as *mut u8, 0, 0x100); |
| 660 | core::ptr::write_bytes(report, 0, 64); | 679 | core::ptr::write_bytes(report, 0, 64); |
| @@ -981,6 +1000,7 @@ unsafe fn init_one(bus: u8, dev: u8, func: u8) -> bool { | |||
| 981 | let caplen = (rd(base) & 0xff) as usize; | 1000 | let caplen = (rd(base) & 0xff) as usize; |
| 982 | let opb = base + caplen; | 1001 | let opb = base + caplen; |
| 983 | let nports = rd(base + 4) & 0xf; | 1002 | let nports = rd(base + 4) & 0xf; |
| 1003 | let caps64 = (rd(base + 8) & 1) != 0; | ||
| 984 | crate::serial_println!( | 1004 | crate::serial_println!( |
| 985 | "ehci: {:02x}:{:02x}.{} mmio={:#x} caplen={:#x} ports={} 64-bit-caps={}", | 1005 | "ehci: {:02x}:{:02x}.{} mmio={:#x} caplen={:#x} ports={} 64-bit-caps={}", |
| 986 | bus, | 1006 | bus, |
| @@ -989,7 +1009,7 @@ unsafe fn init_one(bus: u8, dev: u8, func: u8) -> bool { | |||
| 989 | base, | 1009 | base, |
| 990 | caplen, | 1010 | caplen, |
| 991 | nports, | 1011 | nports, |
| 992 | (rd(base + 8) & 1) != 0 | 1012 | caps64 |
| 993 | ); | 1013 | ); |
| 994 | 1014 | ||
| 995 | // BIOS legacy ownership: resetting the controller while SMM owns it | 1015 | // BIOS legacy ownership: resetting the controller while SMM owns it |
| @@ -1006,6 +1026,7 @@ unsafe fn init_one(bus: u8, dev: u8, func: u8) -> bool { | |||
| 1006 | c.base = base; | 1026 | c.base = base; |
| 1007 | c.opb = opb; | 1027 | c.opb = opb; |
| 1008 | c.nports = nports; | 1028 | c.nports = nports; |
| 1029 | c.caps64 = caps64; | ||
| 1009 | } | 1030 | } |
| 1010 | 1031 | ||
| 1011 | // Halt, reset, wait for reset to clear. | 1032 | // Halt, reset, wait for reset to clear. |
