fix: bits_pthread cbindgen needs stddef.h for size_t type

The generated bits/pthread.h uses size_t but had no includes.
Also added openat cache vars to m4 recipe for gnulib cross-compilation.
This commit is contained in:
2026-06-01 17:00:53 +03:00
parent d0dfa2ba5e
commit a52632f69d
61 changed files with 699 additions and 1201 deletions
+1 -1
View File
@@ -154,7 +154,7 @@ redbear-session-launch = {}
seatd = {}
redbear-greeter = {}
sddm = {}
amdgpu = {}
#amdgpu = {} # TODO: fix conflicting idr_* defs with linux-kpi headers
# Core Red Bear umbrella package
redbear-meta = {}
+4 -5
View File
@@ -66,16 +66,15 @@ export ac_cv_type_ptrdiff_t=yes
export ac_cv_type_nlink_t=yes
export ac_cv_type_mbstate_t=yes
export ac_cv_type_time_t=yes
export ac_cv_type_sigset_t=yes
export ac_cv_type_posix_spawnattr_t=yes
export ac_cv_type_posix_spawn_file_actions_t=yes
export gl_cv_type_intmax_t=yes
export gl_cv_type_ptrdiff_t_signed=yes
export gl_cv_header_inttypes_h=yes
export gl_cv_header_stdint_h=yes
export gl_cv_header_inttypes_h_with_uintmax=yes
export ac_cv_have_inttypes_h_with_uintmax=yes
# openat: Redox doesn't have /proc/self/fd — skip gnulib replacement
export ac_cv_func_openat=yes
export gl_cv_func_openat_works=yes
# m4-specific gnulib function checks
export ac_cv_func___freadahead=yes
export ac_cv_have_decl___freadahead=yes
@@ -299,6 +299,21 @@ impl PciDevice {
})
}
/// Create a PciDevice that uses x86 I/O ports directly, without attempting
/// the scheme file path. Use this when a trusted caller (e.g. pcid-spawner)
/// has already enabled the PCI device via the channel interface and the
/// driver only needs config space access for capability scanning or BAR
/// probing — not for device enablement.
#[cfg(target_arch = "x86_64")]
pub fn open_io_ports(loc: &PciLocation) -> Result<Self> {
ensure_io_port_access()?;
log::debug!("PCI: using I/O port access directly for {}", loc);
Ok(PciDevice {
location: *loc,
access: ConfigAccess::IoPorts,
})
}
pub fn from_info(info: &PciDeviceInfo) -> Result<Self> {
Self::open_location(&info.location)
}
@@ -5,6 +5,48 @@ use crate::kms::{ConnectorInfo, ModeInfo};
pub type Result<T> = std::result::Result<T, DriverError>;
pub type ContextHandle = u32;
pub type SyncobjHandle = u32;
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
pub struct IntelGemExecObject2 {
pub handle: u32,
pub flags: u64,
pub offset: u64,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
pub struct IntelGemExecbuffer2 {
pub buffer_count: u32,
pub batch_len: u32,
pub flags: u64,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct IntelGemExecbuffer2Result {
pub seqno: u64,
pub fence_handle: SyncobjHandle,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
pub struct IntelGemRelocationEntry {
pub target_handle: u32,
pub offset: u64,
pub presumed_offset: u64,
pub delta: u32,
}
pub const EXEC_OBJECT_PINNED: u64 = 1 << 4;
pub const EXEC_OBJECT_WRITE: u64 = 1 << 2;
pub const I915_EXEC_RENDER: u64 = 1 << 0;
pub const I915_EXEC_BLT: u64 = 1 << 2;
pub const I915_EXEC_BSD: u64 = 1 << 4;
pub const I915_EXEC_VEBOX: u64 = 1 << 6;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DriverEvent {
Vblank { crtc_id: u32, count: u64 },
@@ -754,42 +754,6 @@ impl GpuDriver for AmdDriver {
"property not supported for this object",
))
}
};
if !irq_event {
return Ok(None);
}
let irq = self
.irq_handle
.lock()
.ok()
.and_then(|guard| guard.as_ref().map(|h| h.irq()));
match self.process_irq()? {
Some(DriverEvent::Vblank { crtc_id, count }) => {
debug!(
"redox-drm: handled AMD vblank IRQ for {} CRTC {} count={} irq={:?}",
self.info.location, crtc_id, count, irq
);
Ok(Some(DriverEvent::Vblank { crtc_id, count }))
}
Some(DriverEvent::Hotplug { connector_id }) => {
debug!(
"redox-drm: handled AMD hotplug IRQ for {} connector {} irq={:?}",
self.info.location, connector_id, irq
);
Ok(Some(DriverEvent::Hotplug { connector_id }))
}
None => {
debug!(
"redox-drm: handled AMD IRQ for {} with no decoded source irq={:?}",
self.info.location, irq
);
Ok(None)
}
}
}
}
fn detect_display_topology(display: &DisplayCore) -> Result<(Vec<Connector>, Vec<Encoder>)> {
@@ -89,8 +89,10 @@ impl IntelPpgtt {
pub fn init(&mut self) -> Result<()> {
let pdp_size = (PDE_ENTRIES * std::mem::size_of::<u64>()) as u64;
// Allocate PDP from GGTT — the GTT allocator returns GPU-accessible addresses
// backed by GEM-allocated physical pages. No separate map_range needed for
// GTT-internal page table allocations.
let pdp_addr = self.gtt.alloc_range(pdp_size)?;
self.gtt.map_range(pdp_addr, 0, pdp_size, PPGTT_PTE_PRESENT | PPGTT_PTE_RW)?;
let mut pdp = PageTable::new(GEN8_PPGTT_PDP_OFFSET);
pdp.gpu_addr = pdp_addr;
@@ -147,7 +149,7 @@ impl IntelPpgtt {
}
fn set_pte(&mut self, page: u64, value: u64) -> Result<()> {
ensure_tables(&mut self.tables, page);
self.ensure_tables(page)?;
let pte_idx = (page % PTE_ENTRIES as u64) as usize;
let pt_idx = ((page / PTE_ENTRIES as u64) % PDE_ENTRIES as u64) as usize;
let pd_idx = ((page / (PDE_ENTRIES * PTE_ENTRIES) as u64) % PDE_ENTRIES as u64) as usize;
@@ -217,25 +219,45 @@ impl IntelPpgtt {
pub fn total_mapped(&self) -> u64 {
self.total_allocated
}
}
fn ensure_tables(tables: &mut BTreeMap<usize, PageTable>, page: u64) {
let pt_idx = ((page / PTE_ENTRIES as u64) % PDE_ENTRIES as u64) as usize;
let pd_idx = ((page / (PDE_ENTRIES * PTE_ENTRIES) as u64) % PDE_ENTRIES as u64) as usize;
let pdp_idx = ((page / (PDE_ENTRIES * PDE_ENTRIES * PTE_ENTRIES) as u64) % PDE_ENTRIES as u64) as usize;
let pt_key = GEN8_PPGTT_PT_OFFSET as usize * 1000_000 + pd_idx * 1000 + pt_idx;
if !tables.contains_key(&pt_key) {
let mut pt = PageTable::new(GEN8_PPGTT_PTE_OFFSET);
pt.gpu_addr = 0;
tables.insert(pt_key, pt);
fn write_pde(&mut self, table_key: usize, index: u64, value: u64) -> Result<()> {
let table = self.tables.get_mut(&table_key).ok_or_else(|| {
DriverError::NotFound(format!("PPGTT table {:#x} not found", table_key))
})?;
table.set_entry(index as usize, value);
Ok(())
}
let pd_key = GEN8_PPGTT_PD_OFFSET as usize * 1000 + pd_idx;
if !tables.contains_key(&pd_key) {
let mut pd = PageTable::new(GEN8_PPGTT_PD_OFFSET);
pd.gpu_addr = 0;
tables.insert(pd_key, pd);
fn ensure_tables(&mut self, page: u64) -> Result<()> {
let pt_idx = ((page / PTE_ENTRIES as u64) % PDE_ENTRIES as u64) as usize;
let pd_idx = ((page / (PDE_ENTRIES * PTE_ENTRIES) as u64) % PDE_ENTRIES as u64) as usize;
let _pdp_idx = ((page / (PDE_ENTRIES * PDE_ENTRIES * PTE_ENTRIES) as u64) % PDE_ENTRIES as u64) as usize;
let pd_key = GEN8_PPGTT_PD_OFFSET as usize * 1000 + pd_idx;
if !self.tables.contains_key(&pd_key) {
let pd_size = (PDE_ENTRIES * std::mem::size_of::<u64>()) as u64;
let pd_addr = self.gtt.alloc_range(pd_size)?;
let pd_pte_val = pd_addr | PPGTT_PTE_PRESENT | PPGTT_PTE_RW;
self.write_pde(GEN8_PPGTT_PDP_OFFSET, pd_idx as u64, pd_pte_val)?;
let mut pd = PageTable::new(GEN8_PPGTT_PD_OFFSET);
pd.gpu_addr = pd_addr;
self.tables.insert(pd_key, pd);
}
let pt_key = GEN8_PPGTT_PT_OFFSET as usize * 1000_000 + pd_idx * 1000 + pt_idx;
if !self.tables.contains_key(&pt_key) {
let pt_size = (PTE_ENTRIES * std::mem::size_of::<u64>()) as u64;
let pt_addr = self.gtt.alloc_range(pt_size)?;
let pt_pte_val = pt_addr | PPGTT_PTE_PRESENT | PPGTT_PTE_RW;
self.write_pde(pd_key, pt_idx as u64, pt_pte_val)?;
let mut pt = PageTable::new(GEN8_PPGTT_PTE_OFFSET);
pt.gpu_addr = pt_addr;
self.tables.insert(pt_key, pt);
}
Ok(())
}
}
@@ -62,8 +62,8 @@ impl IntelDisplay {
pub fn detect_pipes(mmio: &MmioRegion, regs: &dyn IntelRegs) -> Result<Vec<DisplayPipe>> {
let mut pipes = Vec::with_capacity(PIPE_COUNT);
let pp_status = read32(mmio, regs.pp_status()).unwrap_or(0);
let connected_ports = connected_ports(mmio, regs);
let pp_status = read32(mmio, regs.pp_status())?;
let connected_ports = connected_ports(mmio, regs)?;
for index in 0..PIPE_COUNT {
let conf = read32(mmio, regs.pipeconf(index as u8))?;
@@ -94,19 +94,19 @@ impl IntelDisplay {
}
pub fn detect_connectors(&self) -> Result<Vec<ConnectorInfo>> {
let pp_status = self.read32(self.regs.pp_status()).unwrap_or(0);
let pp_status = self.read32(self.regs.pp_status())?;
let pipes = self.refresh_pipes()?;
let mut connectors = Vec::with_capacity(PORT_COUNT);
for port in 0..PORT_COUNT as u8 {
let status = self.read32(self.regs.ddi_buf_ctl(port)).unwrap_or(0);
let status = self.read32(self.regs.ddi_buf_ctl(port))?;
let connected = status & DDI_BUF_CTL_ENABLE != 0
|| pipes
.iter()
.any(|pipe| pipe.port == Some(port) && pipe.enabled)
|| (port == 0 && pp_status != 0);
let connector_type = connector_type_for_port(port, pp_status);
let modes = self.modes_for_port(port, connector_type);
let modes = self.modes_for_port(port, connector_type)?;
connectors.push(ConnectorInfo {
id: port as u32 + 1,
@@ -133,6 +133,10 @@ impl IntelDisplay {
.saturating_sub(1)
.min((PORT_COUNT - 1) as u32) as u8;
self.modes_for_port(port, connector.connector_type)
.unwrap_or_else(|e| {
info!("redox-drm: failed to detect modes for connector {}: {e}", connector.id);
vec![ModeInfo::default_1080p()]
})
}
pub fn read_edid(&self, port: u8) -> Vec<u8> {
@@ -167,14 +171,14 @@ impl IntelDisplay {
))
}
pub fn read_dpcd(&self, port: u8) -> Vec<u8> {
let status = self.read32(self.regs.ddi_buf_ctl(port)).unwrap_or(0);
pub fn read_dpcd(&self, port: u8) -> Result<Vec<u8>> {
let status = self.read32(self.regs.ddi_buf_ctl(port))?;
if status & DDI_BUF_CTL_ENABLE == 0 {
return Vec::new();
return Ok(Vec::new());
}
debug!("redox-drm: Intel DPCD not yet implemented for port {}", port);
Vec::new()
Ok(Vec::new())
}
pub fn set_mode(&self, pipe: &DisplayPipe, mode: &ModeInfo) -> Result<()> {
@@ -286,10 +290,10 @@ impl IntelDisplay {
Ok(())
}
fn modes_for_port(&self, port: u8, connector_type: ConnectorType) -> Vec<ModeInfo> {
fn modes_for_port(&self, port: u8, connector_type: ConnectorType) -> Result<Vec<ModeInfo>> {
let mut modes = match connector_type {
ConnectorType::DisplayPort | ConnectorType::EDP => {
modes_from_dpcd(&self.read_dpcd(port))
modes_from_dpcd(&self.read_dpcd(port)?)
}
_ => ModeInfo::from_edid(&self.read_edid(port)),
};
@@ -297,10 +301,8 @@ impl IntelDisplay {
if modes.is_empty() {
modes = ModeInfo::from_edid(&synthetic_edid());
}
if modes.is_empty() {
modes.push(ModeInfo::default_1080p());
}
modes
debug!("redox-drm: auto-detected {} mode(s) for port {}", modes.len(), port);
Ok(modes)
}
fn read32(&self, offset: usize) -> Result<u32> {
@@ -312,14 +314,14 @@ impl IntelDisplay {
}
}
fn connected_ports(mmio: &MmioRegion, regs: &dyn IntelRegs) -> Vec<u8> {
fn connected_ports(mmio: &MmioRegion, regs: &dyn IntelRegs) -> Result<Vec<u8>> {
let mut ports = Vec::new();
for port in 0..PORT_COUNT as u8 {
if read32(mmio, regs.ddi_buf_ctl(port)).unwrap_or(0) & DDI_BUF_CTL_ENABLE != 0 {
if read32(mmio, regs.ddi_buf_ctl(port))? & DDI_BUF_CTL_ENABLE != 0 {
ports.push(port);
}
}
ports
Ok(ports)
}
fn read32(mmio: &MmioRegion, offset: usize) -> Result<u32> {
@@ -85,15 +85,53 @@ impl DisplayPll {
}
pub fn get_pll_for_clock(&self, pixel_clock_khz: u32) -> Result<DpllConfig> {
// Reference clock for Gen9 WRPLL is 24 MHz (24000 kHz)
// VCO = refclk * Kdiv / (Pdiv * Qdiv)
// Target: VCO between 2400 MHz and 5000 MHz for WRPLL
const REFCLK_KHZ: u32 = 24_000;
const VCO_MIN_KHZ: u32 = 2_400_000;
const VCO_MAX_KHZ: u32 = 5_000_000;
// Try common PLL configurations to find one where VCO is in range
for &kdiv in &[1, 2, 3, 4, 5, 6, 7] {
for &qdiv in &[1, 2, 3, 4, 5, 6, 7] {
for &pdiv in &[1, 2, 3, 4, 5, 6, 7] {
// VCO = refclk * kdiv / (pdiv * qdiv)
// Output = VCO = refclk * kdiv / (pdiv * qdiv)
let vco = (REFCLK_KHZ as u64 * kdiv as u64) / (pdiv as u64 * qdiv as u64);
// Pixel clock = VCO / (some divider for this DDI)
// For WRPLL, the output divider is 1
let output = vco as u32;
if output >= pixel_clock_khz.saturating_sub(500)
&& output <= pixel_clock_khz.saturating_add(500)
&& vco >= VCO_MIN_KHZ as u64
&& vco <= VCO_MAX_KHZ as u64
{
info!("redox-drm-intel: PLL config: ref={}kHz pdiv={} qdiv={} kdiv={} vco={}kHz target={}kHz",
REFCLK_KHZ, pdiv, qdiv, kdiv, vco, pixel_clock_khz);
return Ok(DpllConfig {
id: 0,
frequency_khz: output,
pdiv,
qdiv,
kdiv,
});
}
}
}
}
// Fallback: use a simple configuration
let pdiv = if pixel_clock_khz > 300_000 { 2 } else { 1 };
let qdiv = 1;
let kdiv = 0;
warn!("redox-drm-intel: no exact PLL match for {} kHz, using pdiv={} qdiv=1 kdiv=1",
pixel_clock_khz, pdiv);
Ok(DpllConfig {
id: 0,
frequency_khz: pixel_clock_khz,
pdiv,
qdiv,
kdiv,
qdiv: 1,
kdiv: 1,
})
}
@@ -19,7 +19,7 @@ const EDP_PSR_TP1_TIME_SHIFT: u32 = 5;
const EDP_PSR_TP2_TP3_TIME_SHIFT: u32 = 8;
const EDP_PSR_MAX_SLEEP_TIME_SHIFT: u32 = 20;
const DP_PSR_EN_CFG: u16 = 0x0170;
const DP_PSR_EN_CFG: u32 = 0x0170;
const DP_PSR_ENABLE_SINK: u8 = 1 << 0;
const DP_PSR_CRC_VERIFY: u8 = 1 << 2;
const DP_PSR_FRAME_CAPTURE: u8 = 1 << 3;
@@ -66,13 +66,15 @@ impl<'a> ExecbufferContext<'a> {
let ring = self.select_ring(exec.flags)?;
ring.submit_batch(&batch_data_to_u32s(batch_data)?)?;
let seqno = ring.last_seqno();
let ring_type = ring.ring_type();
drop(ring);
let fence_handle = self.allocate_fence(seqno)?;
debug!(
"redox-drm-intel: execbuffer2 submitted — {} objects, {} batch bytes, ring {:?}, seqno {}, fence {}",
objects.len(),
batch_data.len(),
ring.ring_type(),
ring_type,
seqno,
fence_handle
);
@@ -107,13 +107,13 @@ impl IntelGtManager {
return Ok(());
}
let ack_bit = if self.device_info.generation.is_gen12_or_later() {
let ack_bit = if self.device_info.is_gen12_or_later() {
FORCEWAKE_ACK
} else {
FORCEWAKE_ACK_HSW
};
let fw_req = if self.device_info.generation.is_gen12_or_later() {
let fw_req = if self.device_info.is_gen12_or_later() {
FORCEWAKE_MT
} else {
FORCEWAKE_RENDER
@@ -121,7 +121,7 @@ impl IntelGtManager {
let fw_ack = FORCEWAKE_MT_ACK;
let mut val = self.mmio.read32(fw_req);
if self.device_info.generation.is_gen12_or_later() {
if self.device_info.is_gen12_or_later() {
val &= !0xFFFF;
val |= 0x0001;
} else {
@@ -184,14 +184,14 @@ impl IntelGtManager {
return Ok(());
}
let fw_req = if self.device_info.generation.is_gen12_or_later() {
let fw_req = if self.device_info.is_gen12_or_later() {
FORCEWAKE_MT
} else {
0xA18C
};
let mut val = self.mmio.read32(fw_req);
if self.device_info.generation.is_gen12_or_later() {
if self.device_info.is_gen12_or_later() {
val &= !0x0001;
} else {
val &= !FORCEWAKE_KERNEL;
@@ -222,12 +222,12 @@ impl IntelGtManager {
let cm0 = self.mmio.read32(CACHE_MODE_0);
self.mmio.write32(CACHE_MODE_0, cm0 | (1 << 3));
count += 1;
if self.device_info.generation.is_gen9_or_later() {
if self.device_info.is_gen9_or_later() {
let hsc2 = self.mmio.read32(HALF_SLICE_CHICKEN2);
self.mmio.write32(HALF_SLICE_CHICKEN2, hsc2 | (1 << 14));
count += 1;
}
if self.device_info.generation.is_gen12_or_later() {
if self.device_info.is_gen12_or_later() {
let l3cfg = self.mmio.read32(L3_GENERAL_CFG);
self.mmio.write32(L3_GENERAL_CFG, l3cfg | L3_PREFETCH_DISABLE);
count += 1;
@@ -280,7 +280,7 @@ impl IntelGtManager {
self.mmio.write32(L3SQCREG4, conv_val);
// Cache Mode 1: enable 48-bit PPGTT for Gen8+
if self.device_info.generation.is_gen9_or_later() {
if self.device_info.is_gen9_or_later() {
let cm1 = self.mmio.read32(CACHE_MODE_1);
self.mmio.write32(CACHE_MODE_1, cm1 | (1 << 16));
}
@@ -138,7 +138,7 @@ impl GpuHangDetector {
let tail = self.read_ring_reg(RING_TAIL_OFFSET).unwrap_or(0);
let ctl = self.read_ring_reg(0x3C).unwrap_or(0);
let start_lo = self.read_ring_reg(0x38).unwrap_or(0);
let start_hi = self.read_ring_reg(0x3C).unwrap_or(0);
let start_hi = self.read_ring_reg(0x40).unwrap_or(0);
let acthd_lo = self.read_ring_reg(RING_ACTHD_OFFSET).unwrap_or(0);
let acthd_hi = self.read_ring_reg(RING_ACTHD_OFFSET + 4).unwrap_or(0);
error!(
@@ -74,6 +74,8 @@ pub struct IntelDeviceInfo {
pub has_dbuf_slice: bool,
pub has_separate_transcoder: bool,
pub dmc_fw_key: Option<&'static str>,
pub guc_fw_key: Option<&'static str>,
pub has_guc: bool,
pub platform_name: &'static str,
}
@@ -99,60 +101,72 @@ struct DeviceIdEntry {
gen: IntelGeneration,
platform_name: &'static str,
dmc_fw_key: Option<&'static str>,
guc_fw_key: Option<&'static str>,
}
const DEVICE_ID_TABLE: &[DeviceIdEntry] = &[
DeviceIdEntry { device_id: 0x1912, gen: IntelGeneration::Gen9, platform_name: "Skylake DT GT2", dmc_fw_key: Some("SKL") },
DeviceIdEntry { device_id: 0x1916, gen: IntelGeneration::Gen9, platform_name: "Skylake ULT GT2", dmc_fw_key: Some("SKL") },
DeviceIdEntry { device_id: 0x191B, gen: IntelGeneration::Gen9, platform_name: "Skylake DT GT2", dmc_fw_key: Some("SKL") },
DeviceIdEntry { device_id: 0x191D, gen: IntelGeneration::Gen9, platform_name: "Skylake DT GT2", dmc_fw_key: Some("SKL") },
DeviceIdEntry { device_id: 0x191E, gen: IntelGeneration::Gen9, platform_name: "Skylake ULX GT2", dmc_fw_key: Some("SKL") },
DeviceIdEntry { device_id: 0x1921, gen: IntelGeneration::Gen9, platform_name: "Skylake ULT GT2", dmc_fw_key: Some("SKL") },
DeviceIdEntry { device_id: 0x1923, gen: IntelGeneration::Gen9, platform_name: "Skylake ULT GT2", dmc_fw_key: Some("SKL") },
DeviceIdEntry { device_id: 0x1926, gen: IntelGeneration::Gen9, platform_name: "Skylake ULT GT3", dmc_fw_key: Some("SKL") },
DeviceIdEntry { device_id: 0x1927, gen: IntelGeneration::Gen9, platform_name: "Skylake ULT GT3", dmc_fw_key: Some("SKL") },
DeviceIdEntry { device_id: 0x5912, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake DT GT2", dmc_fw_key: Some("KBL") },
DeviceIdEntry { device_id: 0x5916, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake ULT GT2", dmc_fw_key: Some("KBL") },
DeviceIdEntry { device_id: 0x591B, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake DT GT2", dmc_fw_key: Some("KBL") },
DeviceIdEntry { device_id: 0x591D, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake DT GT2", dmc_fw_key: Some("KBL") },
DeviceIdEntry { device_id: 0x5921, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake ULT GT2", dmc_fw_key: Some("KBL") },
DeviceIdEntry { device_id: 0x5923, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake ULT GT2", dmc_fw_key: Some("KBL") },
DeviceIdEntry { device_id: 0x5926, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake ULT GT3", dmc_fw_key: Some("KBL") },
DeviceIdEntry { device_id: 0x5927, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake ULT GT3", dmc_fw_key: Some("KBL") },
DeviceIdEntry { device_id: 0x3E90, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake DT GT2", dmc_fw_key: Some("CFL") },
DeviceIdEntry { device_id: 0x3E91, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake DT GT2", dmc_fw_key: Some("CFL") },
DeviceIdEntry { device_id: 0x3E92, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake DT GT2", dmc_fw_key: Some("CFL") },
DeviceIdEntry { device_id: 0x3E96, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake DT GT2", dmc_fw_key: Some("CFL") },
DeviceIdEntry { device_id: 0x3E98, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake DT GT2", dmc_fw_key: Some("CFL") },
DeviceIdEntry { device_id: 0x3E9A, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake DT GT2", dmc_fw_key: Some("CFL") },
DeviceIdEntry { device_id: 0x3EA5, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake ULT GT3", dmc_fw_key: Some("CFL") },
DeviceIdEntry { device_id: 0x3EA6, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake ULT GT3", dmc_fw_key: Some("CFL") },
DeviceIdEntry { device_id: 0x3EA7, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake ULT GT3", dmc_fw_key: Some("CFL") },
DeviceIdEntry { device_id: 0x3EA8, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake ULT GT3", dmc_fw_key: Some("CFL") },
DeviceIdEntry { device_id: 0x8A56, gen: IntelGeneration::Gen9_5, platform_name: "Ice Lake ULT GT2", dmc_fw_key: Some("ICL") },
DeviceIdEntry { device_id: 0x8A52, gen: IntelGeneration::Gen9_5, platform_name: "Ice Lake ULT GT2", dmc_fw_key: Some("ICL") },
DeviceIdEntry { device_id: 0x4500, gen: IntelGeneration::Gen9_5, platform_name: "Elkhart Lake", dmc_fw_key: Some("EHL") },
DeviceIdEntry { device_id: 0x4571, gen: IntelGeneration::Gen9_5, platform_name: "Elkhart Lake", dmc_fw_key: Some("EHL") },
DeviceIdEntry { device_id: 0x9A49, gen: IntelGeneration::Gen12, platform_name: "Tiger Lake ULT GT2", dmc_fw_key: Some("TGL") },
DeviceIdEntry { device_id: 0x9A40, gen: IntelGeneration::Gen12, platform_name: "Tiger Lake ULT GT2", dmc_fw_key: Some("TGL") },
DeviceIdEntry { device_id: 0x9A78, gen: IntelGeneration::Gen12, platform_name: "Tiger Lake H GT2", dmc_fw_key: Some("TGL") },
DeviceIdEntry { device_id: 0x46A6, gen: IntelGeneration::Gen12, platform_name: "Alder Lake-P GT2", dmc_fw_key: Some("ADLP") },
DeviceIdEntry { device_id: 0x4626, gen: IntelGeneration::Gen12, platform_name: "Alder Lake-P GT2", dmc_fw_key: Some("ADLP") },
DeviceIdEntry { device_id: 0x46A8, gen: IntelGeneration::Gen12, platform_name: "Alder Lake-P GT2", dmc_fw_key: Some("ADLP") },
DeviceIdEntry { device_id: 0x4628, gen: IntelGeneration::Gen12, platform_name: "Alder Lake-P GT2", dmc_fw_key: Some("ADLP") },
DeviceIdEntry { device_id: 0x46B3, gen: IntelGeneration::Gen12, platform_name: "Alder Lake-P GT2", dmc_fw_key: Some("ADLP") },
DeviceIdEntry { device_id: 0x5690, gen: IntelGeneration::Gen12, platform_name: "DG2 Alchemist G10", dmc_fw_key: Some("DG2") },
DeviceIdEntry { device_id: 0x5698, gen: IntelGeneration::Gen12, platform_name: "DG2 Alchemist G11", dmc_fw_key: Some("DG2") },
DeviceIdEntry { device_id: 0x56A0, gen: IntelGeneration::Gen12, platform_name: "DG2 Alchemist G12", dmc_fw_key: Some("DG2") },
DeviceIdEntry { device_id: 0x7D55, gen: IntelGeneration::Gen12_7, platform_name: "Meteor Lake", dmc_fw_key: Some("MTL") },
DeviceIdEntry { device_id: 0x7D60, gen: IntelGeneration::Gen12_7, platform_name: "Meteor Lake", dmc_fw_key: Some("MTL") },
DeviceIdEntry { device_id: 0x7D45, gen: IntelGeneration::Gen12_7, platform_name: "Meteor Lake", dmc_fw_key: Some("MTL") },
DeviceIdEntry { device_id: 0x7D67, gen: IntelGeneration::Gen12_7, platform_name: "Meteor Lake", dmc_fw_key: Some("MTL") },
DeviceIdEntry { device_id: 0x7D41, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-U", dmc_fw_key: Some("ARL") },
DeviceIdEntry { device_id: 0x7D51, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-P Arc Pro 130T/140T", dmc_fw_key: Some("ARL") },
DeviceIdEntry { device_id: 0x7D67, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-S", dmc_fw_key: Some("ARL") },
DeviceIdEntry { device_id: 0x7DD1, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-P", dmc_fw_key: Some("ARL") },
DeviceIdEntry { device_id: 0xB640, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-H", dmc_fw_key: Some("ARL") },
DeviceIdEntry { device_id: 0x1912, gen: IntelGeneration::Gen9, platform_name: "Skylake DT GT2", dmc_fw_key: Some("SKL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x1916, gen: IntelGeneration::Gen9, platform_name: "Skylake ULT GT2", dmc_fw_key: Some("SKL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x191B, gen: IntelGeneration::Gen9, platform_name: "Skylake DT GT2", dmc_fw_key: Some("SKL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x191D, gen: IntelGeneration::Gen9, platform_name: "Skylake DT GT2", dmc_fw_key: Some("SKL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x191E, gen: IntelGeneration::Gen9, platform_name: "Skylake ULX GT2", dmc_fw_key: Some("SKL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x1921, gen: IntelGeneration::Gen9, platform_name: "Skylake ULT GT2", dmc_fw_key: Some("SKL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x1923, gen: IntelGeneration::Gen9, platform_name: "Skylake ULT GT2", dmc_fw_key: Some("SKL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x1926, gen: IntelGeneration::Gen9, platform_name: "Skylake ULT GT3", dmc_fw_key: Some("SKL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x1927, gen: IntelGeneration::Gen9, platform_name: "Skylake ULT GT3", dmc_fw_key: Some("SKL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x5912, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake DT GT2", dmc_fw_key: Some("KBL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x5916, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake ULT GT2", dmc_fw_key: Some("KBL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x591B, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake DT GT2", dmc_fw_key: Some("KBL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x591D, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake DT GT2", dmc_fw_key: Some("KBL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x5921, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake ULT GT2", dmc_fw_key: Some("KBL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x5923, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake ULT GT2", dmc_fw_key: Some("KBL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x5926, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake ULT GT3", dmc_fw_key: Some("KBL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x5927, gen: IntelGeneration::Gen9, platform_name: "Kaby Lake ULT GT3", dmc_fw_key: Some("KBL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x3E90, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake DT GT2", dmc_fw_key: Some("CFL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x3E91, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake DT GT2", dmc_fw_key: Some("CFL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x3E92, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake DT GT2", dmc_fw_key: Some("CFL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x3E96, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake DT GT2", dmc_fw_key: Some("CFL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x3E98, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake DT GT2", dmc_fw_key: Some("CFL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x3E9A, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake DT GT2", dmc_fw_key: Some("CFL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x3EA5, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake ULT GT3", dmc_fw_key: Some("CFL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x3EA6, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake ULT GT3", dmc_fw_key: Some("CFL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x3EA7, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake ULT GT3", dmc_fw_key: Some("CFL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x3EA8, gen: IntelGeneration::Gen9, platform_name: "Coffee Lake ULT GT3", dmc_fw_key: Some("CFL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x8A56, gen: IntelGeneration::Gen9_5, platform_name: "Ice Lake ULT GT2", dmc_fw_key: Some("ICL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x8A52, gen: IntelGeneration::Gen9_5, platform_name: "Ice Lake ULT GT2", dmc_fw_key: Some("ICL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x4500, gen: IntelGeneration::Gen9_5, platform_name: "Elkhart Lake", dmc_fw_key: Some("EHL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x4571, gen: IntelGeneration::Gen9_5, platform_name: "Elkhart Lake", dmc_fw_key: Some("EHL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x9A49, gen: IntelGeneration::Gen12, platform_name: "Tiger Lake ULT GT2", dmc_fw_key: Some("TGL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x9A40, gen: IntelGeneration::Gen12, platform_name: "Tiger Lake ULT GT2", dmc_fw_key: Some("TGL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x9A78, gen: IntelGeneration::Gen12, platform_name: "Tiger Lake H GT2", dmc_fw_key: Some("TGL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x46A6, gen: IntelGeneration::Gen12, platform_name: "Alder Lake-P GT2", dmc_fw_key: Some("ADLP"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x4626, gen: IntelGeneration::Gen12, platform_name: "Alder Lake-P GT2", dmc_fw_key: Some("ADLP"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x46A8, gen: IntelGeneration::Gen12, platform_name: "Alder Lake-P GT2", dmc_fw_key: Some("ADLP"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x4628, gen: IntelGeneration::Gen12, platform_name: "Alder Lake-P GT2", dmc_fw_key: Some("ADLP"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x46B3, gen: IntelGeneration::Gen12, platform_name: "Alder Lake-P GT2", dmc_fw_key: Some("ADLP"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x5690, gen: IntelGeneration::Gen12, platform_name: "DG2 Alchemist G10", dmc_fw_key: Some("DG2"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x5698, gen: IntelGeneration::Gen12, platform_name: "DG2 Alchemist G11", dmc_fw_key: Some("DG2"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x56A0, gen: IntelGeneration::Gen12, platform_name: "DG2 Alchemist G12", dmc_fw_key: Some("DG2"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x7D55, gen: IntelGeneration::Gen12_7, platform_name: "Meteor Lake", dmc_fw_key: Some("MTL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x7D60, gen: IntelGeneration::Gen12_7, platform_name: "Meteor Lake", dmc_fw_key: Some("MTL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x7D45, gen: IntelGeneration::Gen12_7, platform_name: "Meteor Lake", dmc_fw_key: Some("MTL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x7D67, gen: IntelGeneration::Gen12_7, platform_name: "Meteor Lake", dmc_fw_key: Some("MTL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x7D41, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-U", dmc_fw_key: Some("ARL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x7D51, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-P Arc Pro 130T/140T", dmc_fw_key: Some("ARL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x7D67, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-S", dmc_fw_key: Some("ARL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x7DD1, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-P", dmc_fw_key: Some("ARL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0xB640, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-H", dmc_fw_key: Some("ARL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x6420, gen: IntelGeneration::GenXe2, platform_name: "Lunar Lake", dmc_fw_key: Some("LNL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x64A0, gen: IntelGeneration::GenXe2, platform_name: "Lunar Lake", dmc_fw_key: Some("LNL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0x64B0, gen: IntelGeneration::GenXe2, platform_name: "Lunar Lake", dmc_fw_key: Some("LNL"), guc_fw_key: None },
DeviceIdEntry { device_id: 0xE202, gen: IntelGeneration::GenXe2, platform_name: "Battlemage G21", dmc_fw_key: Some("BMG"), guc_fw_key: None },
DeviceIdEntry { device_id: 0xE20B, gen: IntelGeneration::GenXe2, platform_name: "Battlemage G21", dmc_fw_key: Some("BMG"), guc_fw_key: None },
DeviceIdEntry { device_id: 0xE20C, gen: IntelGeneration::GenXe2, platform_name: "Battlemage G21", dmc_fw_key: Some("BMG"), guc_fw_key: None },
DeviceIdEntry { device_id: 0xE20D, gen: IntelGeneration::GenXe2, platform_name: "Battlemage G21", dmc_fw_key: Some("BMG"), guc_fw_key: None },
DeviceIdEntry { device_id: 0xE210, gen: IntelGeneration::GenXe2, platform_name: "Battlemage G21", dmc_fw_key: Some("BMG"), guc_fw_key: None },
DeviceIdEntry { device_id: 0xE212, gen: IntelGeneration::GenXe2, platform_name: "Battlemage G21", dmc_fw_key: Some("BMG"), guc_fw_key: None },
DeviceIdEntry { device_id: 0xE216, gen: IntelGeneration::GenXe2, platform_name: "Battlemage G21", dmc_fw_key: Some("BMG"), guc_fw_key: None },
DeviceIdEntry { device_id: 0xE220, gen: IntelGeneration::GenXe2, platform_name: "Battlemage G21", dmc_fw_key: Some("BMG"), guc_fw_key: None },
];
pub fn device_info_from_id(device_id: u16) -> IntelDeviceInfo {
@@ -173,6 +187,8 @@ pub fn device_info_from_id(device_id: u16) -> IntelDeviceInfo {
has_dbuf_slice: gen == IntelGeneration::Gen12 || gen == IntelGeneration::Gen12_7 || gen == IntelGeneration::GenXe2,
has_separate_transcoder: gen == IntelGeneration::Gen12 || gen == IntelGeneration::Gen12_7 || gen == IntelGeneration::GenXe2,
dmc_fw_key: entry.dmc_fw_key,
guc_fw_key: entry.guc_fw_key,
has_guc: entry.guc_fw_key.is_some(),
platform_name: entry.platform_name,
};
}
@@ -193,6 +209,8 @@ pub fn device_info_from_id(device_id: u16) -> IntelDeviceInfo {
has_dbuf_slice: false,
has_separate_transcoder: false,
dmc_fw_key: None,
guc_fw_key: None,
has_guc: false,
platform_name: "Unknown (Gen9 default)",
}
}
@@ -0,0 +1,75 @@
use log::info;
use crate::driver::{DriverError, Result};
const DG2_DEVICE_IDS: &[u16] = &[
0x5690, 0x5691, 0x5692, 0x5693, 0x5694, 0x5695, 0x5696, 0x5697,
0x56A0, 0x56A1, 0x56A2, 0x56A3, 0x56A4, 0x56A5, 0x56A6,
0x56B0, 0x56B1, 0x56B2, 0x56B3, 0x56BA, 0x56BB, 0x56BC,
0x56BD, 0x56BE, 0x56BF, 0x56C0, 0x56C1,
];
const BMG_DEVICE_IDS: &[u16] = &[
0xE202, 0xE209, 0xE20B, 0xE20C, 0xE20D, 0xE210, 0xE211,
0xE212, 0xE216, 0xE220, 0xE221, 0xE222, 0xE223,
];
pub fn is_discrete_gpu(device_id: u16) -> bool {
DG2_DEVICE_IDS.contains(&device_id) || BMG_DEVICE_IDS.contains(&device_id)
}
pub struct IntelLmem {
bar_addr: u64,
bar_size: u64,
next_offset: u64,
}
impl IntelLmem {
pub fn probe(bar_addr: u64, bar_size: u64) -> Result<Self> {
if bar_size == 0 {
return Err(DriverError::Initialization(
"Intel discrete GPU reports zero-size LMEM BAR".into(),
));
}
info!(
"redox-drm-intel: LMEM BAR probed — {:#x} bytes at {:#010x}",
bar_size, bar_addr
);
Ok(Self {
bar_addr,
bar_size,
next_offset: 0,
})
}
pub fn alloc(&mut self, size: u64, alignment: u64) -> Result<u64> {
let aligned = align_up(self.next_offset, alignment);
let end = aligned
.checked_add(size)
.ok_or_else(|| DriverError::Buffer("Intel LMEM allocation overflow".into()))?;
if end > self.bar_size {
return Err(DriverError::Buffer(format!(
"Intel LMEM exhausted: need {:#x} at offset {:#x}, have {:#x}",
size, aligned, self.bar_size
)));
}
self.next_offset = end;
let vram_addr = self.bar_addr + aligned;
Ok(vram_addr)
}
pub fn bar_size(&self) -> u64 {
self.bar_size
}
pub fn bar_addr(&self) -> u64 {
self.bar_addr
}
}
fn align_up(value: u64, alignment: u64) -> u64 {
if alignment == 0 {
return value;
}
(value + alignment - 1) & !(alignment - 1)
}
@@ -1,30 +1,43 @@
pub mod backlight;
pub mod batch;
pub mod context;
pub mod cursor;
pub mod ddi_buf_trans;
pub mod display;
pub mod display_cdclk;
pub mod display_combo_phy;
pub mod display_dmc;
pub mod display_dpll;
pub mod display_power;
pub mod display_psr;
pub mod display_transcoder;
pub mod display_watermark;
pub mod dp_aux;
pub mod dp_link;
pub mod execbuffer;
pub mod execlists;
pub mod fence;
pub mod gamma;
pub mod gmbus;
pub mod gt;
pub mod gtt;
pub mod guc;
pub mod hangcheck;
pub mod hdmi;
pub mod hotplug;
pub mod info;
pub mod lmem;
pub mod panel_pps;
pub mod regs;
pub mod regs_gen9;
pub mod regs_gen12;
pub mod regs_xe2;
pub mod ring;
pub mod syncobj;
pub mod vbt;
use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Mutex};
use log::{debug, info, warn};
@@ -51,16 +64,23 @@ use self::display_transcoder::{TransDdiMode, Transcoder};
use self::display_watermark::DisplayWatermark;
use self::dp_aux::DpAux;
use self::gmbus::GmbusController;
use self::gt::IntelGtManager;
use self::gtt::IntelGtt;
use self::guc::GucFirmware;
use self::hotplug::HotplugHandler;
use self::info::{IntelDeviceInfo, IntelGeneration, device_info_from_id};
use self::lmem::{IntelLmem, is_discrete_gpu};
use self::regs::IntelRegs;
use self::regs_gen9::Gen9Regs;
use self::regs_gen12::Gen12Regs;
use self::regs_xe2::Xe2Regs;
use self::backlight::Backlight;
use self::context::ContextManager;
use self::display_psr::PsrState;
use self::hangcheck::GpuHangDetector;
use self::panel_pps::PanelPowerSequencer;
use self::ring::{IntelRing, RingType};
const FORCEWAKE: usize = 0xA18C;
use self::syncobj::SyncobjManager;
const RENDER_RING_BASE: usize = 0x02000;
const RING_TAIL_OFFSET: usize = 0x30;
@@ -87,9 +107,19 @@ pub struct IntelDriver {
watermark: DisplayWatermark,
dpll: DisplayPll,
dmc: DmcFirmware,
guc: GucFirmware,
cdclk: DisplayClock,
cursor: CursorPlane,
hotplug: HotplugHandler,
gt_manager: IntelGtManager,
vblank_count: AtomicU64,
backlight: Mutex<Backlight>,
context_manager: Mutex<ContextManager>,
psr: Mutex<PsrState>,
hang_detector: Mutex<GpuHangDetector>,
panel_pps: Mutex<PanelPowerSequencer>,
syncobj_mgr: Mutex<SyncobjManager>,
lmem: Option<IntelLmem>,
}
impl IntelDriver {
@@ -125,6 +155,29 @@ impl IntelDriver {
let gtt_bar = find_memory_bar(&info, 0, "GGTT BAR0")?;
let mmio_bar = find_memory_bar(&info, 2, "MMIO BAR2")?;
let lmem = if is_discrete_gpu(info.device_id) {
if let Some(lmem_bar) = info.find_memory_bar(4) {
match IntelLmem::probe(lmem_bar.addr, lmem_bar.size) {
Ok(lmem) => {
info!(
"redox-drm-intel: discrete GPU LMEM — {:#x} bytes at {:#010x}",
lmem.bar_size(), lmem.bar_addr()
);
Some(lmem)
}
Err(e) => {
warn!("redox-drm-intel: discrete GPU LMEM probe failed: {}", e);
None
}
}
} else {
info!("redox-drm-intel: discrete GPU detected but no LMEM BAR4 found");
None
}
} else {
None
};
// Determine device generation early for register-correct init ordering
let device_info = device_info_from_id(info.device_id);
info!(
@@ -152,10 +205,12 @@ impl IntelDriver {
let gtt_control_mmio = map_bar(&mut device, &mmio_bar, "Intel GGTT control MMIO")?;
let gtt_mmio = map_bar(&mut device, &gtt_bar, "Intel GGTT BAR0")?;
enable_forcewake(&mmio, regs)?;
let mmio_arc = Arc::new(mmio);
let display_mmio_arc = Arc::new(display_mmio);
let mut gt_manager = IntelGtManager::new(mmio_arc.clone(), &device_info);
gt_manager.init()?;
let gmbus = if device_info.has_gmbus {
let ctrl = GmbusController::new(display_mmio_arc.clone(), regs);
ctrl.init()?;
@@ -224,6 +279,17 @@ impl IntelDriver {
let mut ring = IntelRing::create(ring_mmio, RingType::Render)?;
ring.bind_gtt(&mut gtt)?;
let mut guc = GucFirmware::new(mmio_arc.clone());
if let Some(guc_key) = device_info.guc_fw_key {
guc.init_wopcm()?;
if let Some(fw_data) = firmware.get(guc_key) {
info!("redox-drm-intel: loading GuC firmware for {guc_key}");
guc.upload(fw_data)?;
} else {
warn!("redox-drm-intel: GuC firmware key '{guc_key}' not in cache, continuing without");
}
}
let edid_source: Option<&[DpAux]> = if device_info.generation == IntelGeneration::GenXe2 {
Some(&dp_aux)
} else {
@@ -234,6 +300,23 @@ impl IntelDriver {
let hotplug = HotplugHandler::new(mmio_arc.clone(), &device_info);
hotplug.init()?;
let mut backlight = Backlight::new(mmio_arc.clone(), &device_info);
backlight.init()?;
let context_manager = Mutex::new(ContextManager::new());
let psr = Mutex::new(PsrState::new(mmio_arc.clone(), 0));
let hang_detector = Mutex::new(GpuHangDetector::new(mmio_arc.clone(), RENDER_RING_BASE));
let panel_pps = {
let pps = PanelPowerSequencer::new(mmio_arc.clone(), &device_info);
pps.init()?;
Mutex::new(pps)
};
let syncobj_mgr = Mutex::new(SyncobjManager::new());
let (connectors, encoders) = detect_display_topology(&display, edid_source)?;
let crtcs = build_crtcs(&display)?;
@@ -288,9 +371,19 @@ impl IntelDriver {
watermark,
dpll,
dmc,
guc,
cdclk,
cursor,
hotplug,
gt_manager,
vblank_count: AtomicU64::new(0),
backlight: Mutex::new(backlight),
context_manager,
psr,
hang_detector,
panel_pps,
syncobj_mgr,
lmem,
})
}
}
@@ -302,15 +395,18 @@ fn enable_d2d_links(mmio: &MmioRegion, regs: &dyn IntelRegs, num_ports: u8) -> R
const D2D_TIMEOUT_MS: u64 = 10;
for port in 0..num_ports {
let ddi_ctl = regs.ddi_buf_ctl(port);
let current = mmio.read32(ddi_ctl);
let d2d_ctl = regs.d2d_link_ctl(port);
if d2d_ctl == 0 {
continue;
}
let current = mmio.read32(d2d_ctl);
if current & D2D_LINK_STATE != 0 {
continue;
}
mmio.write32(ddi_ctl, current | D2D_LINK_ENABLE);
mmio.write32(d2d_ctl, current | D2D_LINK_ENABLE);
let deadline = Instant::now() + Duration::from_millis(D2D_TIMEOUT_MS);
loop {
let status = mmio.read32(ddi_ctl);
let status = mmio.read32(d2d_ctl);
if status & D2D_LINK_STATE != 0 {
info!("redox-drm-intel: D2D link enabled on port {}", port);
break;
@@ -408,25 +504,56 @@ impl IntelDriver {
}
}
if let Some(crtc_id) = self.active_crtc_id()? {
let pipe = self.display.pipe_for_crtc(crtc_id)?;
let pipe_idx = u8::from(pipe.index);
let pipestat = self.mmio.read32(self.regs.pipestat(pipe_idx));
let vblank_mask = self.regs.pipestat_vblank_mask();
let vsync_mask = self.regs.pipestat_vsync_mask();
if pipestat & vblank_mask != 0 {
self.mmio.write32(self.regs.pipestat(pipe_idx), vblank_mask);
let count = self.vblank_count.fetch_add(1, Ordering::Relaxed) + 1;
debug!(
"redox-drm: Intel vblank IRQ crtc={} count={}",
crtc_id, count
);
return Ok(Some(DriverEvent::Vblank { crtc_id, count }));
}
if pipestat & vsync_mask != 0 {
self.mmio.write32(self.regs.pipestat(pipe_idx), vsync_mask);
}
let count = self.read_pipeframe(crtc_id)?;
debug!(
"redox-drm: Intel poll-based display event crtc={} ring_checked=true",
crtc_id
);
return Ok(Some(DriverEvent::Vblank { crtc_id, count }));
}
let ring_busy = self
.ring
.lock()
.map_err(|_| DriverError::Initialization("Intel ring state poisoned".into()))?
.has_activity()?;
if let Some(crtc_id) = self.active_crtc_id()? {
let count = self.read_pipeframe(crtc_id)?;
debug!(
"redox-drm: Intel IRQ decoded as display event crtc={} ring_busy={}",
crtc_id, ring_busy
);
return Ok(Some(DriverEvent::Vblank { crtc_id, count }));
}
if ring_busy {
debug!("redox-drm: Intel IRQ signaled command stream activity without active CRTC");
}
// Poll hangcheck detector for GPU hangs
{
let mut hang = self
.hang_detector
.lock()
.map_err(|_| DriverError::Initialization("Intel hangcheck state poisoned".into()))?;
if hang.poll()? {
warn!("redox-drm: Intel GPU hang detected and reset attempted");
}
}
Ok(None)
}
@@ -448,6 +575,18 @@ impl IntelDriver {
.map(|pipe| u32::from(pipe.index) + 1))
}
fn enable_pipe_interrupts(&self, pipe: &DisplayPipe) -> Result<()> {
let pipe_idx = u8::from(pipe.index);
let pipestat = self.regs.pipestat(pipe_idx);
let mask = self.regs.pipestat_vblank_mask() | self.regs.pipestat_vsync_mask();
self.mmio.write32(pipestat, mask);
let de_ier = self.regs.de_ier();
let current = self.mmio.read32(de_ier);
self.mmio.write32(de_ier, current | (1u32 << (13 + pipe_idx as u32)));
debug!("redox-drm-intel: enabled pipe {} interrupts", pipe_idx);
Ok(())
}
fn ensure_gem_gpu_mapping(&self, handle: GemHandle) -> Result<u64> {
{
let gem = self
@@ -556,7 +695,10 @@ impl IntelDriver {
info.push_str(&format!(" GMBUS available: {}\n", self.gmbus.is_some()));
info.push_str(&format!(" Connectors detected: {}\n", self.cached_connectors().len()));
info.push_str(&format!(" CRTCs: {}\n",
self.crtcs.lock().map(|c| c.len()).unwrap_or(0)));
self.crtcs.lock().map(|c| c.len()).unwrap_or_else(|e| {
warn!("redox-drm-intel: crtcs mutex poisoned: {e}");
0
})));
if let Ok(connectors) = self.connectors.lock() {
for conn in connectors.iter() {
info.push_str(&format!(" Connector {}: {:?} (status {:?}), {} modes\n",
@@ -649,15 +791,27 @@ impl GpuDriver for IntelDriver {
let pipe = self.display.pipe_for_crtc(crtc_id)?;
self.display.page_flip(&pipe, fb_addr)?;
let mut ring = self
.ring
.lock()
.map_err(|_| DriverError::Initialization("Intel ring state poisoned".into()))?;
ring.flush()?;
Ok(ring.last_seqno())
self.enable_pipe_interrupts(&pipe)?;
let seqno = {
let mut ring = self
.ring
.lock()
.map_err(|_| DriverError::Initialization("Intel ring state poisoned".into()))?;
let has_pending = ring.has_activity().unwrap_or(false);
if has_pending {
ring.flush()?;
}
ring.last_seqno()
};
Ok(seqno)
}
fn get_vblank(&self, crtc_id: u32) -> Result<u64> {
let count = self.vblank_count.load(Ordering::Relaxed);
if count > 0 {
return Ok(count);
}
self.read_pipeframe(crtc_id)
}
@@ -766,6 +920,21 @@ impl GpuDriver for IntelDriver {
) -> Result<RedoxPrivateCsSubmitResult> {
let src_addr = self.ensure_gem_gpu_mapping(submit.src_handle)?;
let gem_size = self.gem_size(submit.src_handle)?;
if submit.src_offset.checked_add(submit.byte_count).ok_or_else(|| {
DriverError::InvalidArgument("cs_submit: src_offset + byte_count overflow")
})? > gem_size {
return Err(DriverError::InvalidArgument(
"cs_submit: byte_count + src_offset exceeds GEM object size",
));
}
if submit.byte_count % 4 != 0 {
return Err(DriverError::InvalidArgument(
"cs_submit: byte_count must be DWORD-aligned",
));
}
let cmds_ptr = (src_addr + submit.src_offset) as *const u32;
let dword_count = (submit.byte_count / 4) as usize;
let cmds = unsafe {
@@ -775,8 +944,16 @@ impl GpuDriver for IntelDriver {
let mut ring = self.ring.lock()
.map_err(|_| DriverError::Initialization("Intel ring state poisoned".into()))?;
ring.submit_batch(cmds)?;
let seqno = ring.last_seqno();
drop(ring);
Ok(RedoxPrivateCsSubmitResult { seqno: 0 })
{
let syncobj = self.syncobj_mgr.lock()
.map_err(|_| DriverError::Initialization("Intel syncobj state poisoned".into()))?;
syncobj.hardware_signal_completion(src_addr, seqno);
}
Ok(RedoxPrivateCsSubmitResult { seqno })
}
fn cursor_set(
@@ -888,23 +1065,6 @@ fn connector_status_changed(previous: &[ConnectorInfo], current: &[ConnectorInfo
})
}
fn enable_forcewake(mmio: &MmioRegion, regs: &dyn IntelRegs) -> Result<()> {
let offset = regs.forcewake_req();
let end = offset
.checked_add(core::mem::size_of::<u32>())
.ok_or_else(|| DriverError::Mmio("Intel FORCEWAKE offset overflow".into()))?;
if end > mmio.size() {
return Err(DriverError::Mmio(format!(
"Intel FORCEWAKE register outside MMIO aperture: end={end:#x} size={:#x}",
mmio.size()
)));
}
mmio.write32(offset, 1);
let _ = mmio.read32(offset);
Ok(())
}
fn validate_intel_bars(
info: &PciDeviceInfo,
gtt_bar: &PciBarInfo,
@@ -938,7 +1098,7 @@ fn validate_intel_bars(
}
let required_mmio_end = [
FORCEWAKE + core::mem::size_of::<u32>(),
regs.forcewake_req() + core::mem::size_of::<u32>(),
regs.pp_status() + core::mem::size_of::<u32>(),
regs.gfx_flsh_cntl() + core::mem::size_of::<u32>(),
RENDER_RING_BASE + RING_TAIL_OFFSET + core::mem::size_of::<u32>(),
@@ -946,7 +1106,7 @@ fn validate_intel_bars(
]
.into_iter()
.max()
.unwrap_or(0);
.expect("required register list is non-empty");
if mmio_bar.size < required_mmio_end as u64 {
return Err(DriverError::Pci(format!(
@@ -1,981 +0,0 @@
pub mod batch;
pub mod cursor;
pub mod display;
pub mod display_cdclk;
pub mod display_combo_phy;
pub mod display_dmc;
pub mod display_dpll;
pub mod display_power;
pub mod display_transcoder;
pub mod display_watermark;
pub mod dp_aux;
pub mod dp_link;
pub mod execlists;
pub mod fence;
pub mod gmbus;
pub mod gtt;
pub mod hdmi;
pub mod hotplug;
pub mod info;
pub mod regs;
pub mod regs_gen9;
pub mod regs_gen12;
pub mod regs_xe2;
pub mod ring;
pub mod vbt;
use std::collections::HashMap;
use std::sync::Mutex;
use log::{debug, info, warn};
use redox_driver_sys::memory::MmioRegion;
use redox_driver_sys::pci::{PciBarInfo, PciDevice, PciDeviceInfo};
use redox_driver_sys::quirks::PciQuirkFlags;
use crate::driver::{DriverError, DriverEvent, GpuDriver, Result, RedoxPrivateCsSubmit, RedoxPrivateCsSubmitResult};
use crate::drivers::interrupt::InterruptHandle;
use crate::gem::{GemHandle, GemManager};
use crate::kms::connector::{synthetic_edid, Connector};
use crate::kms::crtc::Crtc;
use crate::kms::encoder::Encoder;
use crate::kms::{ConnectorInfo, ConnectorType, ModeInfo};
use self::cursor::CursorPlane;
use self::display::{DisplayPipe, IntelDisplay};
use self::display_cdclk::DisplayClock;
use self::display_combo_phy::ComboPhy;
use self::display_dmc::DmcFirmware;
use self::display_dpll::DisplayPll;
use self::display_power::DisplayPower;
use self::display_transcoder::{TransDdiMode, Transcoder};
use self::display_watermark::DisplayWatermark;
use self::dp_aux::DpAux;
use self::gmbus::GmbusController;
use self::gtt::IntelGtt;
use self::hotplug::HotplugHandler;
use self::info::{IntelDeviceInfo, IntelGeneration, device_info_from_id};
use self::regs::IntelRegs;
use self::regs_gen9::Gen9Regs;
use self::regs_gen12::Gen12Regs;
use self::regs_xe2::Xe2Regs;
use self::ring::{IntelRing, RingType};
const FORCEWAKE: usize = 0xA18C;
const self.regs.pp_status(): usize = 0xC7200;
const self.regs.pipeconf(0): usize = 0x70008;
const self.regs.pipe_stride(): usize = 0x1000;
const self.regs.pipeframe_reg(pipe): usize = 0x70040;
const self.regs.pipeframe_count_mask(): u32 = 0x00FFFFFF;
const self.regs.ddi_buf_ctl(0): usize = 0x64000;
const self.regs.ddi_port_stride(): usize = 0x100;
const self.regs.gfx_flsh_cntl(): usize = 0x101008;
const RENDER_RING_BASE: usize = 0x02000;
const RING_TAIL_OFFSET: usize = 0x30;
const RING_HEAD_OFFSET: usize = 0x34;
pub struct IntelDriver {
info: PciDeviceInfo,
device_info: IntelDeviceInfo,
mmio: Arc<MmioRegion>,
regs: &'static dyn IntelRegs,
irq_handle: Mutex<Option<InterruptHandle>>,
display: IntelDisplay,
gem: Mutex<GemManager>,
connectors: Mutex<Vec<Connector>>,
crtcs: Mutex<Vec<Crtc>>,
encoders: Mutex<Vec<Encoder>>,
gtt: Mutex<IntelGtt>,
ring: Mutex<IntelRing>,
gmbus: Option<GmbusController>,
dp_aux: Vec<DpAux>,
combo_phy: Option<ComboPhy>,
display_power: DisplayPower,
transcoder: Transcoder,
watermark: DisplayWatermark,
dpll: DisplayPll,
dmc: DmcFirmware,
cdclk: DisplayClock,
cursor: CursorPlane,
hotplug: HotplugHandler,
}
impl IntelDriver {
pub fn new(info: PciDeviceInfo, firmware: HashMap<String, Vec<u8>>) -> Result<Self> {
if !info.is_intel_gpu() {
return Err(DriverError::Pci(format!(
"device {} is not an Intel display-class GPU",
info.location
)));
}
let quirks = info.quirks();
if !quirks.is_empty() {
info!(
"redox-drm: Intel init for {} using quirk policy {:?}",
info.location, quirks
);
}
if quirks.contains(PciQuirkFlags::DISABLE_ACCEL) {
return Err(DriverError::Pci(format!(
"device {:#06x}:{:#06x} at {} has DISABLE_ACCEL quirk — refusing Intel init",
info.vendor_id, info.device_id, info.location
)));
}
if quirks.contains(PciQuirkFlags::NEED_FIRMWARE) {
info!(
"redox-drm: Intel device {} entered init with explicit firmware policy and {} cached blob(s)",
info.location,
firmware.len()
);
}
let gtt_bar = find_memory_bar(&info, 0, "GGTT BAR0")?;
let mmio_bar = find_memory_bar(&info, 2, "MMIO BAR2")?;
validate_intel_bars(&info, &gtt_bar, &mmio_bar)?;
let mut device = PciDevice::open_location(&info.location)
.map_err(|e| DriverError::Pci(format!("failed to re-open PCI device: {e}")))?;
device
.enable_device()
.map_err(|e| DriverError::Pci(format!("enable_device failed: {e}")))?;
let mmio = map_bar(&mut device, &mmio_bar, "Intel MMIO BAR2")?;
let display_mmio = map_bar(&mut device, &mmio_bar, "Intel display MMIO")?;
let ring_mmio = map_bar(&mut device, &mmio_bar, "Intel ring MMIO")?;
let gtt_control_mmio = map_bar(&mut device, &mmio_bar, "Intel GGTT control MMIO")?;
let gtt_mmio = map_bar(&mut device, &gtt_bar, "Intel GGTT BAR0")?;
enable_forcewake(&mmio)?;
let device_info = device_info_from_id(info.device_id);
info!(
"redox-drm: Intel {} detected (device {:#06x}, display ver {}, gen {:?})",
device_info.platform_name, info.device_id, device_info.display_version, device_info.generation
);
let regs: &'static dyn IntelRegs = match device_info.generation {
IntelGeneration::GenXe2 => &Xe2Regs,
IntelGeneration::Gen12 | IntelGeneration::Gen12_7 => &Gen12Regs,
_ => &Gen9Regs,
};
let mmio_arc = Arc::new(mmio);
let display_mmio_arc = Arc::new(display_mmio);
let gmbus = if device_info.has_gmbus {
let ctrl = GmbusController::new(display_mmio_arc.clone(), regs);
ctrl.init()?;
Some(ctrl)
} else {
info!("redox-drm-intel: Xe2 platform — skipping GMBUS (uses DP AUX for EDID)");
None
};
let dp_aux: Vec<DpAux> = (0..device_info.num_ports)
.map(|port| DpAux::new(mmio_arc.clone(), port))
.collect();
info!("redox-drm-intel: initialized {} DP AUX channels", dp_aux.len());
if device_info.generation == IntelGeneration::GenXe2 {
enable_d2d_links(&mmio_arc, regs, device_info.num_ports)?;
}
let combo_phy = if device_info.has_combo_phy {
let phy = ComboPhy::new(mmio_arc.clone());
phy.init_all(device_info.num_ports as usize)?;
Some(phy)
} else {
None
};
let display_power = DisplayPower::new(mmio_arc.clone(), regs, &device_info);
display_power.init_domains()?;
let transcoder = Transcoder::new(mmio_arc.clone(), &device_info);
let watermark = DisplayWatermark::new(mmio_arc.clone(), &device_info);
watermark.init()?;
let dmc = DmcFirmware::new(mmio_arc.clone(), regs);
if let Some(dmc_key) = device_info.dmc_fw_key {
if let Some(fw_data) = firmware.get(dmc_key) {
info!("redox-drm-intel: loading DMC firmware for {}", dmc_key);
dmc.upload(fw_data)?;
} else {
warn!("redox-drm-intel: DMC firmware key '{}' not found in cache", dmc_key);
}
}
let cdclk = DisplayClock::new(mmio_arc.clone(), regs, &device_info);
let cdclk_state = cdclk.init()?;
info!(
"redox-drm-intel: CDCLK = {} kHz (voltage level {})",
cdclk_state.frequency_khz, cdclk_state.voltage_level
);
let dpll = DisplayPll::new(mmio_arc.clone(), &device_info);
dpll.init()?;
if device_info.generation == IntelGeneration::GenXe2 {
for port in 0..device_info.num_ports {
if port < dp_aux.len() as u8 {
let _ = dp_link::train_dp_link(&mmio_arc, &dp_aux[port as usize], port);
}
}
}
let display_gmbus = gmbus.clone();
let display = IntelDisplay::new(display_mmio, regs, display_gmbus)?;
let mut gtt = IntelGtt::init(gtt_mmio, gtt_control_mmio)?;
let mut ring = IntelRing::create(ring_mmio, RingType::Render)?;
ring.bind_gtt(&mut gtt)?;
let edid_source: Option<&[DpAux]> = if device_info.generation == IntelGeneration::GenXe2 {
Some(&dp_aux)
} else {
None
};
let cursor = CursorPlane::new(mmio_arc.clone(), regs);
let hotplug = HotplugHandler::new(mmio_arc.clone(), &device_info);
hotplug.init()?;
let (connectors, encoders) = detect_display_topology(&display, edid_source)?;
let crtcs = build_crtcs(&display)?;
let irq_handle = match InterruptHandle::setup(&info, &mut device) {
Ok(handle) => Some(handle),
Err(e) => {
warn!(
"redox-drm: Intel device {} interrupt setup failed: {e}",
info.location
);
None
}
};
let irq_mode = irq_handle
.as_ref()
.map(|handle| handle.mode_name())
.unwrap_or("none");
if !firmware.is_empty() {
info!(
"redox-drm: Intel startup firmware cache populated with {} blob(s) for {}",
firmware.len(),
info.location
);
}
info!(
"redox-drm: Intel driver ready for {} with {} connector(s), IRQ mode {}",
info.location,
connectors.len(),
irq_mode
);
Ok(Self {
info,
device_info,
mmio: mmio_arc,
regs,
irq_handle: Mutex::new(irq_handle),
display,
gem: Mutex::new(GemManager::new()),
connectors: Mutex::new(connectors),
crtcs: Mutex::new(crtcs),
encoders: Mutex::new(encoders),
gtt: Mutex::new(gtt),
ring: Mutex::new(ring),
gmbus,
dp_aux,
combo_phy,
display_power,
transcoder,
watermark,
dpll,
dmc,
cdclk,
cursor,
hotplug,
})
}
}
fn enable_d2d_links(mmio: &Arc<MmioRegion>, regs: &dyn IntelRegs, num_ports: u8) -> Result<()> {
use std::time::{Duration, Instant};
const D2D_LINK_ENABLE: u32 = 1 << 29;
const D2D_LINK_STATE: u32 = 1 << 28;
const D2D_TIMEOUT_MS: u64 = 10;
for port in 0..num_ports {
let ddi_ctl = regs.ddi_buf_ctl(port);
let current = mmio.read_u32(ddi_ctl);
if current & D2D_LINK_STATE != 0 {
continue;
}
mmio.write_u32(ddi_ctl, current | D2D_LINK_ENABLE);
let deadline = Instant::now() + Duration::from_millis(D2D_TIMEOUT_MS);
loop {
let status = mmio.read_u32(ddi_ctl);
if status & D2D_LINK_STATE != 0 {
info!("redox-drm-intel: D2D link enabled on port {}", port);
break;
}
if Instant::now() > deadline {
warn!("redox-drm-intel: D2D link timeout on port {}", port);
break;
}
std::hint::spin_loop();
}
}
Ok(())
}
fn refresh_connectors(&self) -> Result<Vec<ConnectorInfo>> {
let edid_source: Option<&[DpAux]> = if self.device_info.generation == IntelGeneration::GenXe2 {
Some(&self.dp_aux)
} else {
None
};
let (connectors, encoders) = detect_display_topology(&self.display, edid_source)?;
let infos = connectors
.iter()
.map(|connector| connector.info.clone())
.collect();
{
let mut connector_state = self.connectors.lock().map_err(|_| {
DriverError::Initialization("Intel connector state poisoned".into())
})?;
*connector_state = connectors;
}
{
let mut encoder_state = self
.encoders
.lock()
.map_err(|_| DriverError::Initialization("Intel encoder state poisoned".into()))?;
*encoder_state = encoders;
}
Ok(infos)
}
fn cached_connectors(&self) -> Vec<ConnectorInfo> {
match self.connectors.lock() {
Ok(connectors) => connectors
.iter()
.map(|connector| connector.info.clone())
.collect(),
Err(poisoned) => {
warn!("redox-drm: Intel connector state poisoned; using inner state");
poisoned
.into_inner()
.iter()
.map(|connector| connector.info.clone())
.collect()
}
}
}
fn connector_port(&self, connector_id: u32) -> Result<u8> {
let connectors = self
.connectors
.lock()
.map_err(|_| DriverError::Initialization("Intel connector state poisoned".into()))?;
let connector = connectors
.iter()
.find(|connector| connector.info.id == connector_id)
.ok_or_else(|| DriverError::NotFound(format!("unknown connector {connector_id}")))?;
Ok(connector.info.connector_type_id.saturating_sub(1) as u8)
}
fn process_irq(&self) -> Result<Option<DriverEvent>> {
let previous = self.cached_connectors();
let current = self.refresh_connectors()?;
if connector_status_changed(&previous, &current) {
info!(
"redox-drm: Intel hotplug event detected on {}",
self.info.location
);
if let Some(connector) = current.iter().find(|connector| {
previous
.iter()
.find(|old| old.id == connector.id)
.map(|old| old.connection != connector.connection)
.unwrap_or(true)
}) {
return Ok(Some(DriverEvent::Hotplug {
connector_id: connector.id,
}));
}
}
let ring_busy = self
.ring
.lock()
.map_err(|_| DriverError::Initialization("Intel ring state poisoned".into()))?
.has_activity()?;
if let Some(crtc_id) = self.active_crtc_id()? {
let count = self.read_pipeframe(crtc_id)?;
debug!(
"redox-drm: Intel IRQ decoded as display event crtc={} ring_busy={}",
crtc_id, ring_busy
);
return Ok(Some(DriverEvent::Vblank { crtc_id, count }));
}
if ring_busy {
debug!("redox-drm: Intel IRQ signaled command stream activity without active CRTC");
}
Ok(None)
}
fn active_crtc_id(&self) -> Result<Option<u32>> {
let crtcs = self
.crtcs
.lock()
.map_err(|_| DriverError::Initialization("Intel CRTC state poisoned".into()))?;
if let Some(active) = crtcs.iter().find(|crtc| crtc.mode.is_some()) {
return Ok(Some(active.id));
}
Ok(self
.display
.pipes()?
.into_iter()
.find(|pipe| pipe.enabled)
.map(|pipe| u32::from(pipe.index) + 1))
}
fn ensure_gem_gpu_mapping(&self, handle: GemHandle) -> Result<u64> {
{
let gem = self
.gem
.lock()
.map_err(|_| DriverError::Buffer("Intel GEM manager poisoned".into()))?;
if let Some(gpu_addr) = gem.gpu_addr(handle)? {
return Ok(gpu_addr);
}
}
let (phys_addr, size) = {
let gem = self
.gem
.lock()
.map_err(|_| DriverError::Buffer("Intel GEM manager poisoned".into()))?;
let object = gem.object(handle)?;
(object.phys_addr as u64, object.size)
};
let gpu_addr = {
let mut gtt = self
.gtt
.lock()
.map_err(|_| DriverError::Initialization("Intel GGTT state poisoned".into()))?;
let gpu_addr = gtt.alloc_range(size)?;
if let Err(error) = gtt.map_range(gpu_addr, phys_addr, size, 1 << 1) {
let _ = gtt.release_range(gpu_addr, size);
return Err(error);
}
gpu_addr
};
if let Err(error) = self
.gem
.lock()
.map_err(|_| DriverError::Buffer("Intel GEM manager poisoned".into()))?
.set_gpu_addr(handle, gpu_addr)
{
let mut gtt = self
.gtt
.lock()
.map_err(|_| DriverError::Initialization("Intel GGTT state poisoned".into()))?;
let _ = gtt.unmap_range(gpu_addr, size);
let _ = gtt.release_range(gpu_addr, size);
return Err(error);
}
Ok(gpu_addr)
}
fn read_mmio(&self, offset: usize) -> Result<u32> {
let end = offset
.checked_add(core::mem::size_of::<u32>())
.ok_or_else(|| {
DriverError::Mmio(format!("Intel MMIO offset overflow at {offset:#x}"))
})?;
if end > self.mmio.size() {
return Err(DriverError::Mmio(format!(
"Intel MMIO read outside BAR2 aperture: end={end:#x} size={:#x}",
self.mmio.size()
)));
}
Ok(self.mmio.read32(offset))
}
fn read_pipeframe(&self, crtc_id: u32) -> Result<u64> {
let pipe_index = crtc_id
.checked_sub(1)
.ok_or_else(|| DriverError::InvalidArgument("invalid Intel CRTC id"))?
as usize;
let offset = self.regs.pipeframe_reg(pipe) + pipe_index * self.regs.pipe_stride();
let end = offset
.checked_add(core::mem::size_of::<u32>())
.ok_or_else(|| DriverError::Mmio("Intel PIPEFRAME offset overflow".into()))?;
if end > self.mmio.size() {
return Err(DriverError::Mmio(format!(
"Intel PIPEFRAME read outside MMIO aperture: end={end:#x} size={:#x}",
self.mmio.size()
)));
}
let frame_count = self.mmio.read32(offset) & self.regs.pipeframe_count_mask();
Ok(u64::from(frame_count))
}
}
impl GpuDriver for IntelDriver {
fn driver_name(&self) -> &str {
"i915-redox"
}
fn driver_desc(&self) -> &str {
"Intel i915-class DRM/KMS backend for Redox"
}
fn driver_date(&self) -> &str {
"2026-05-30"
}
let mut info = String::new();
info.push_str(&format!("Intel GPU: {} (device {:#06x})\n",
self.device_info.platform_name, self.info.device_id));
info.push_str(&format!(" Generation: {:?}, display ver {}, GT ver {}\n",
self.device_info.generation, self.device_info.display_version,
self.device_info.gt_version));
info.push_str(&format!(" Pipes: {}, Ports: {}, Memory: {} MB\n",
self.device_info.num_pipes, self.device_info.num_ports, 256));
info.push_str(&format!(" DDI: {}, DP AUX: {}, GMBUS: {}, DMC: {}\n",
self.device_info.has_ddi, self.device_info.has_dp_aux,
self.device_info.has_gmbus, self.device_info.has_dmc));
info.push_str(&format!(" Combo PHY: {}, DBUF: {}, Sep Transcoder: {}\n",
self.device_info.has_combo_phy, self.device_info.has_dbuf_slice,
self.device_info.has_separate_transcoder));
info.push_str(&format!(" DMC FW key: {:?}\n", self.device_info.dmc_fw_key));
info.push_str(&format!(" Power wells ready: {}\n", self.display_power.is_display_ready()));
info.push_str(&format!(" Forcewake: enabled\n"));
info.push_str(&format!(" DP AUX channels: {}\n", self.dp_aux.len()));
info.push_str(&format!(" GMBUS available: {}\n", self.gmbus.is_some()));
info.push_str(&format!(" Connectors detected: {}\n", self.cached_connectors().len()));
info.push_str(&format!(" CRTCs: {}\n",
self.crtcs.lock().map(|c| c.len()).unwrap_or(0)));
if let Ok(connectors) = self.connectors.lock() {
for conn in connectors.iter() {
info.push_str(&format!(" Connector {}: {:?} (status {:?}), {} modes\n",
conn.info.id, conn.info.connector_type, conn.info.status,
conn.info.modes.len()));
}
}
match &self.irq_handle.lock() {
Ok(handle) if handle.is_some() => {
info.push_str(&format!(" IRQ: {} mode\n",
handle.as_ref().map(|h| h.mode_name()).unwrap_or("none")));
}
_ => info.push_str(" IRQ: not configured\n"),
}
info
}
fn detect_connectors(&self) -> Vec<ConnectorInfo> {
match self.refresh_connectors() {
Ok(connectors) => connectors,
Err(error) => {
warn!("redox-drm: Intel connector refresh failed: {}", error);
self.cached_connectors()
}
}
}
fn get_modes(&self, connector_id: u32) -> Vec<ModeInfo> {
self.detect_connectors()
.into_iter()
.find(|connector| connector.id == connector_id)
.map(|connector| connector.modes)
.unwrap_or_default()
}
fn set_crtc(
&self,
crtc_id: u32,
fb_handle: u32,
connectors: &[u32],
mode: &ModeInfo,
) -> Result<()> {
if connectors.is_empty() {
return Err(DriverError::InvalidArgument(
"set_crtc requires at least one connector",
));
}
let fb_addr = self.ensure_gem_gpu_mapping(fb_handle)?;
let mut pipe = self.display.pipe_for_crtc(crtc_id)?;
pipe.port = Some(self.connector_port(connectors[0])?);
self.display.set_mode(&pipe, mode)?;
if let Some(port) = pipe.port {
self.transcoder.configure(pipe.index, port, TransDdiMode::Dp, 4)?;
}
self.watermark.program_for_mode(pipe.index, mode, true)?;
self.display.page_flip(&pipe, fb_addr)?;
let mut crtcs = self
.crtcs
.lock()
.map_err(|_| DriverError::Initialization("Intel CRTC state poisoned".into()))?;
let crtc = crtcs
.iter_mut()
.find(|crtc| crtc.id == crtc_id)
.ok_or_else(|| DriverError::NotFound(format!("unknown CRTC {crtc_id}")))?;
crtc.program(fb_handle, connectors, mode)
}
fn page_flip(&self, crtc_id: u32, fb_handle: u32, _flags: u32) -> Result<u64> {
let fb_addr = self.ensure_gem_gpu_mapping(fb_handle)?;
let pipe = self.display.pipe_for_crtc(crtc_id)?;
self.display.page_flip(&pipe, fb_addr)?;
let mut ring = self
.ring
.lock()
.map_err(|_| DriverError::Initialization("Intel ring state poisoned".into()))?;
ring.flush()?;
Ok(ring.last_seqno())
}
fn get_vblank(&self, crtc_id: u32) -> Result<u64> {
self.read_pipeframe(crtc_id)
}
fn gem_create(&self, size: u64, _width: u32, _height: u32) -> Result<GemHandle> {
let handle = {
let mut gem = self
.gem
.lock()
.map_err(|_| DriverError::Buffer("Intel GEM manager poisoned".into()))?;
gem.create(size)?
};
if let Err(error) = self.ensure_gem_gpu_mapping(handle) {
let _ = self
.gem
.lock()
.map_err(|_| DriverError::Buffer("Intel GEM manager poisoned".into()))?
.close(handle);
return Err(error);
}
Ok(handle)
}
fn gem_close(&self, handle: GemHandle) -> Result<()> {
let (gpu_addr, size) = {
let gem = self
.gem
.lock()
.map_err(|_| DriverError::Buffer("Intel GEM manager poisoned".into()))?;
let object = gem.object(handle)?;
(object.gpu_addr, object.size)
};
if let Some(gpu_addr) = gpu_addr {
let mut gtt = self
.gtt
.lock()
.map_err(|_| DriverError::Initialization("Intel GGTT state poisoned".into()))?;
gtt.unmap_range(gpu_addr, size)?;
gtt.release_range(gpu_addr, size)?;
}
self.gem
.lock()
.map_err(|_| DriverError::Buffer("Intel GEM manager poisoned".into()))?
.close(handle)
}
fn gem_mmap(&self, handle: GemHandle) -> Result<usize> {
let gem = self
.gem
.lock()
.map_err(|_| DriverError::Buffer("Intel GEM manager poisoned".into()))?;
gem.mmap(handle)
}
fn gem_size(&self, handle: GemHandle) -> Result<u64> {
let gem = self
.gem
.lock()
.map_err(|_| DriverError::Buffer("Intel GEM manager poisoned".into()))?;
Ok(gem.object(handle)?.size)
}
fn get_edid(&self, connector_id: u32) -> Vec<u8> {
match self.connectors.lock() {
Ok(connectors) => connectors
.iter()
.find(|connector| connector.info.id == connector_id)
.map(|connector| connector.edid.clone())
.unwrap_or_default(),
Err(poisoned) => poisoned
.into_inner()
.iter()
.find(|connector| connector.info.id == connector_id)
.map(|connector| connector.edid.clone())
.unwrap_or_default(),
}
}
fn handle_irq(&self) -> Result<Option<DriverEvent>> {
let irq_event = {
let mut irq_handle = self
.irq_handle
.lock()
.map_err(|_| DriverError::Initialization("Intel IRQ state poisoned".into()))?;
match irq_handle.as_mut() {
Some(handle) => handle
.try_wait()
.map_err(|e| DriverError::Io(format!("Intel IRQ poll failed: {e}")))?,
None => return Ok(None),
}
};
if !irq_event {
return Ok(None);
}
self.process_irq()
}
fn redox_private_cs_submit(
&self,
submit: &RedoxPrivateCsSubmit,
) -> Result<RedoxPrivateCsSubmitResult> {
let src_addr = self.ensure_gem_gpu_mapping(submit.src_handle)?;
let cmds_ptr = (src_addr + submit.src_offset) as *const u32;
let dword_count = (submit.byte_count / 4) as usize;
let cmds = unsafe {
std::slice::from_raw_parts(cmds_ptr, dword_count)
};
let mut ring = self.ring.lock()
.map_err(|_| DriverError::Initialization("Intel ring state poisoned".into()))?;
ring.submit_batch(cmds)?;
Ok(RedoxPrivateCsSubmitResult { seqno: 0 })
}
fn cursor_set(
&self,
crtc_id: u32,
fb_handle: u32,
hot_x: u32,
hot_y: u32,
) -> Result<()> {
let fb_addr = self.ensure_gem_gpu_mapping(fb_handle)?;
let pipe = self.display.pipe_for_crtc(crtc_id)?;
let gtt_offset = fb_addr as u32;
self.cursor.set_surface(pipe.index, gtt_offset)?;
self.cursor.enable(pipe.index)?;
debug!("redox-drm-intel: cursor set on CRTC {} (pipe {}, fb {:#010x}, hot {},{})",
crtc_id, pipe.index, gtt_offset, hot_x, hot_y);
Ok(())
}
fn cursor_move(&self, crtc_id: u32, x: i32, y: i32) -> Result<()> {
let pipe = self.display.pipe_for_crtc(crtc_id)?;
let ux = x.max(0).min(8191) as u16;
let uy = y.max(0).min(8191) as u16;
self.cursor.set_position(pipe.index, ux, uy)?;
Ok(())
}
}
fn detect_display_topology(display: &IntelDisplay, edid_source: Option<&[DpAux]>) -> Result<(Vec<Connector>, Vec<Encoder>)> {
let detected = display.detect_connectors()?;
let mut connectors = Vec::with_capacity(detected.len());
let mut encoders = Vec::with_capacity(detected.len());
for connector in detected {
let port = connector.connector_type_id.saturating_sub(1) as u8;
let edid = match edid_source {
Some(dp_aux_channels) if (port as usize) < dp_aux_channels.len() => {
match dp_aux_channels[port as usize].read_edid() {
Ok(data) => {
info!("redox-drm-intel: read {} byte EDID via DP AUX port {}", data.len(), port);
data
}
Err(e) => {
debug!("redox-drm-intel: DP AUX EDID read failed on port {}: {}", port, e);
display.read_edid(port)
}
}
}
_ => display.read_edid(port),
};
encoders.push(Encoder::new(
connector.encoder_id,
pipe_id_for_port(display, port),
));
connectors.push(Connector {
edid: if edid.is_empty() {
synthetic_edid()
} else {
edid
},
info: ConnectorInfo {
modes: display.modes_for_connector(&connector),
..connector
},
});
}
Ok((connectors, encoders))
}
fn build_crtcs(display: &IntelDisplay) -> Result<Vec<Crtc>> {
let mut crtcs: Vec<Crtc> = display
.pipes()?
.into_iter()
.map(|pipe| Crtc::new(u32::from(pipe.index) + 1))
.collect();
if crtcs.is_empty() {
crtcs.push(Crtc::new(1));
}
Ok(crtcs)
}
fn pipe_id_for_port(display: &IntelDisplay, port: u8) -> u32 {
display
.pipes()
.ok()
.and_then(|pipes| {
pipes
.into_iter()
.find(|pipe| pipe.port == Some(port))
.map(|pipe| u32::from(pipe.index) + 1)
})
.unwrap_or(1)
}
fn connector_status_changed(previous: &[ConnectorInfo], current: &[ConnectorInfo]) -> bool {
if previous.len() != current.len() {
return true;
}
previous.iter().zip(current.iter()).any(|(old, new)| {
old.id != new.id
|| old.connection != new.connection
|| old.connector_type != new.connector_type
})
}
fn enable_forcewake(mmio: &MmioRegion) -> Result<()> {
let end = FORCEWAKE
.checked_add(core::mem::size_of::<u32>())
.ok_or_else(|| DriverError::Mmio("Intel FORCEWAKE offset overflow".into()))?;
if end > mmio.size() {
return Err(DriverError::Mmio(format!(
"Intel FORCEWAKE register outside MMIO aperture: end={end:#x} size={:#x}",
mmio.size()
)));
}
mmio.write32(regs.forcewake_req(), 1);
let _ = mmio.read32(regs.forcewake_req());
Ok(())
}
fn validate_intel_bars(
info: &PciDeviceInfo,
gtt_bar: &PciBarInfo,
mmio_bar: &PciBarInfo,
) -> Result<()> {
if !gtt_bar.is_memory() {
return Err(DriverError::Pci(format!(
"device {} GGTT BAR{} is not a memory BAR",
info.location, gtt_bar.index
)));
}
if !mmio_bar.is_memory() {
return Err(DriverError::Pci(format!(
"device {} MMIO BAR{} is not a memory BAR",
info.location, mmio_bar.index
)));
}
if gtt_bar.size < core::mem::size_of::<u64>() as u64 {
return Err(DriverError::Pci(format!(
"device {} GGTT BAR{} is too small ({:#x})",
info.location, gtt_bar.index, gtt_bar.size
)));
}
if gtt_bar.size % core::mem::size_of::<u64>() as u64 != 0 {
return Err(DriverError::Pci(format!(
"device {} GGTT BAR{} size {:#x} is not 8-byte aligned",
info.location, gtt_bar.index, gtt_bar.size
)));
}
let required_mmio_end = [
FORCEWAKE + core::mem::size_of::<u32>(),
self.regs.pp_status() + core::mem::size_of::<u32>(),
self.regs.gfx_flsh_cntl() + core::mem::size_of::<u32>(),
RENDER_RING_BASE + RING_TAIL_OFFSET + core::mem::size_of::<u32>(),
RENDER_RING_BASE + RING_HEAD_OFFSET + core::mem::size_of::<u32>(),
]
.into_iter()
.max()
.unwrap_or(0);
if mmio_bar.size < required_mmio_end as u64 {
return Err(DriverError::Pci(format!(
"device {} MMIO BAR{} is too small ({:#x}) for required register window ending at {:#x}",
info.location, mmio_bar.index, mmio_bar.size, required_mmio_end
)));
}
Ok(())
}
fn find_memory_bar(info: &PciDeviceInfo, index: usize, name: &str) -> Result<PciBarInfo> {
info.find_memory_bar(index)
.copied()
.ok_or_else(|| DriverError::Pci(format!("device {} has no {}", info.location, name)))
}
fn map_bar(device: &mut PciDevice, bar: &PciBarInfo, name: &str) -> Result<MmioRegion> {
device
.map_bar(bar.index, bar.addr, bar.size as usize)
.map_err(|e| DriverError::Mmio(format!("failed to map {name}: {e}")))
}
#[allow(dead_code)]
fn ddi_buf_ctl(port: u8) -> usize {
self.regs.ddi_buf_ctl(0) + usize::from(port) * self.regs.ddi_port_stride()
}
#[allow(dead_code)]
fn pipeconf(pipe: &DisplayPipe) -> usize {
self.regs.pipeconf(0) + usize::from(pipe.index) * self.regs.pipe_stride()
}
@@ -47,7 +47,22 @@ pub trait IntelRegs: Send + Sync {
fn pipeframe_reg(&self, pipe: u8) -> usize;
fn pipeframe_count_mask(&self) -> u32;
fn pipestat(&self, pipe: u8) -> usize;
fn de_iir(&self) -> usize;
fn de_imr(&self) -> usize;
fn de_ier(&self) -> usize;
fn pipestat_vblank_mask(&self) -> u32;
fn pipestat_vsync_mask(&self) -> u32;
fn gfx_flsh_cntl(&self) -> usize;
fn pp_status(&self) -> usize;
/// D2D link control register offset per port. Xe2 has D2D links; Gen9/Gen12 do not.
/// Returns 0 if the platform does not support D2D links.
fn d2d_link_ctl(&self, _port: u8) -> usize { 0 }
/// DE_CAP register for display engine capability discovery (Xe2 only).
/// Returns 0 if the platform does not have a DE_CAP register.
fn de_cap(&self) -> usize { 0 }
}
@@ -83,6 +83,15 @@ impl IntelRegs for Gen12Regs {
}
fn pipeframe_count_mask(&self) -> u32 { 0x00FFFFFF }
fn pipestat(&self, pipe: u8) -> usize {
0x70024 + (pipe as usize) * 0x1000
}
fn de_iir(&self) -> usize { 0x44408 }
fn de_imr(&self) -> usize { 0x4440C }
fn de_ier(&self) -> usize { 0x44410 }
fn pipestat_vblank_mask(&self) -> u32 { 1 << 0 }
fn pipestat_vsync_mask(&self) -> u32 { 1 << 1 }
fn gfx_flsh_cntl(&self) -> usize { 0x101008 }
fn pp_status(&self) -> usize { 0xC7200 }
@@ -83,6 +83,15 @@ impl IntelRegs for Gen9Regs {
}
fn pipeframe_count_mask(&self) -> u32 { 0x00FFFFFF }
fn pipestat(&self, pipe: u8) -> usize {
0x70024 + (pipe as usize) * 0x1000
}
fn de_iir(&self) -> usize { 0x44408 }
fn de_imr(&self) -> usize { 0x4440C }
fn de_ier(&self) -> usize { 0x44410 }
fn pipestat_vblank_mask(&self) -> u32 { 1 << 0 }
fn pipestat_vsync_mask(&self) -> u32 { 1 << 1 }
fn gfx_flsh_cntl(&self) -> usize { 0x101008 }
fn pp_status(&self) -> usize { 0xC7200 }
@@ -83,9 +83,24 @@ impl IntelRegs for Xe2Regs {
}
fn pipeframe_count_mask(&self) -> u32 { 0x00FFFFFF }
fn pipestat(&self, pipe: u8) -> usize {
0x70024 + (pipe as usize) * 0x1000
}
fn de_iir(&self) -> usize { 0x44408 }
fn de_imr(&self) -> usize { 0x4440C }
fn de_ier(&self) -> usize { 0x44410 }
fn pipestat_vblank_mask(&self) -> u32 { 1 << 0 }
fn pipestat_vsync_mask(&self) -> u32 { 1 << 1 }
fn gfx_flsh_cntl(&self) -> usize { 0x101008 }
fn pp_status(&self) -> usize { 0xC7200 }
fn d2d_link_ctl(&self, port: u8) -> usize {
0x64200 + (port as usize) * 0x100
}
fn de_cap(&self) -> usize { 0x41100 }
}
pub struct Xe2LpdRegs {
@@ -26,6 +26,7 @@ const RING_CTL_SIZE_MASK: u32 = !0x0FFF;
const MI_NOOP: u32 = 0x0000_0000;
const MI_FLUSH_DW: u32 = 0x0200_0000;
const MI_USER_INTERRUPT: u32 = 0x0200_0000;
#[derive(Clone, Copy, Debug)]
pub enum RingType {
@@ -107,12 +108,13 @@ impl IntelRing {
));
}
self.wait_for_space(buffer.len())?;
self.wait_for_space(buffer.len() + 1)?;
for &dword in buffer {
self.write_dword(dword)?;
}
self.write_dword(MI_USER_INTERRUPT)?;
self.publish_tail()?;
self.last_seqno = self.last_seqno.saturating_add(1);
debug!(
@@ -166,6 +168,10 @@ impl IntelRing {
self.last_seqno
}
pub fn ring_type(&self) -> RingType {
self.ring_type
}
fn program_ring_registers(&mut self, gpu_addr: u64) -> Result<()> {
self.write_reg(RBHEAD, 0)?;
self.write_reg(RBTAIL, 0)?;
@@ -81,11 +81,12 @@ impl VirtioDriver {
)));
}
let mut pci = PciDevice::open_location(&info.location).map_err(|e| {
DriverError::Pci(format!("failed to re-open VirtIO GPU PCI config: {e}"))
// pcid-spawner already called enable_device() via the pcid channel
// before spawning this process. Use I/O ports directly for config
// space access — the pcid scheme has no "config" file handle.
let mut pci = PciDevice::open_io_ports(&info.location).map_err(|e| {
DriverError::Pci(format!("VirtIO I/O port config access failed for {}: {e}", info.location))
})?;
pci.enable_device()
.map_err(|e| DriverError::Pci(format!("VirtIO enable_device failed: {e}")))?;
let irq_handle = match InterruptHandle::setup(&info, &mut pci) {
Ok(handle) => Some(handle),
+14 -3
View File
@@ -296,6 +296,9 @@ const INTEL_CNL_DMC_KEYS: &[&str] = &["i915/cnl_dmc_ver1_07.bin", "i915/cnl_dmc_
const INTEL_ICL_DMC_KEYS: &[&str] = &["i915/icl_dmc_ver1_09.bin", "i915/icl_dmc_ver1_07.bin"];
const INTEL_GLK_DMC_KEYS: &[&str] = &["i915/glk_dmc_ver1_04.bin"];
const INTEL_RKL_DMC_KEYS: &[&str] = &["i915/rkl_dmc_ver2_03.bin", "i915/rkl_dmc_ver2_02.bin"];
const INTEL_ARL_DMC_KEYS: &[&str] = &["i915/mtl_dmc.bin"];
const INTEL_LNL_DMC_KEYS: &[&str] = &["i915/lnl_dmc.bin"];
const INTEL_BMG_DMC_KEYS: &[&str] = &["i915/bmg_dmc.bin"];
fn intel_display_firmware_keys(device_id: u16) -> Option<&'static [&'static str]> {
match device_id {
// Gen12+ (Tiger Lake and newer)
@@ -307,9 +310,17 @@ fn intel_display_firmware_keys(device_id: u16) -> Option<&'static [&'static str]
| 0x56BA | 0x56BB | 0x56BC | 0x56BD | 0x56BE | 0x56BF | 0x56C0 | 0x56C1 => {
Some(INTEL_DG2_DMC_KEYS)
}
0x7D40 | 0x7D41 | 0x7D45 | 0x7D51 | 0x7D55 | 0x7D60 | 0x7D67 | 0x7DD1 | 0x7DD5 => {
Some(INTEL_MTL_DMC_KEYS)
}
// Meteor Lake proper (display IP 12.7)
0x7D40 | 0x7D45 | 0x7D55 | 0x7D60 | 0x7DD5 => Some(INTEL_MTL_DMC_KEYS),
// Arrow Lake (display IP 14.0 — shares DMC firmware with MTL)
0x7D41 | 0x7D51 | 0x7D67 | 0x7DD1 => Some(INTEL_ARL_DMC_KEYS),
// Lunar Lake (display IP 20.0)
0x6420 | 0x64A0 | 0x64B0 => Some(INTEL_LNL_DMC_KEYS),
// Battlemage (display IP 14.0, discrete)
0xE202 | 0xE209 | 0xE20B | 0xE20C | 0xE20D | 0xE210 | 0xE211 | 0xE212 | 0xE216
| 0xE220 | 0xE221 | 0xE222 | 0xE223 => Some(INTEL_BMG_DMC_KEYS),
// Alder Lake-P Gen12 extended IDs
0x4626 | 0x46A8 | 0x4628 | 0x46B3 => Some(INTEL_ADLP_DMC_KEYS),
// Gen9 (Ice Lake / Rocket Lake / Cannon Lake)
0x4905 | 0x4906 | 0x4907 | 0x4908 | 0x4909 => Some(INTEL_ICL_DMC_KEYS),
0x4C80 | 0x4C8A | 0x4C8B | 0x4C8C | 0x4C90 | 0x4C9A => Some(INTEL_RKL_DMC_KEYS),
@@ -12,7 +12,7 @@ use syscall::flag::{EventFlags, MapFlags, MunmapFlags, MODE_CHR};
use syscall::schemev2::NewFdFlags;
use crate::driver::{
DriverEvent, GpuDriver, RedoxPrivateCsSubmit, RedoxPrivateCsSubmitResult, RedoxPrivateCsWait,
DriverError, DriverEvent, GpuDriver, RedoxPrivateCsSubmit, RedoxPrivateCsSubmitResult, RedoxPrivateCsWait,
RedoxPrivateCsWaitResult,
};
use crate::gem::GemHandle;
@@ -1302,10 +1302,10 @@ impl DrmScheme {
out = bytes_of(&response);
for (value, name) in [
(0, b"On\0"),
(1, b"Standby\0"),
(2, b"Suspend\0"),
(3, b"Off\0"),
(0u64, b"On\0" as &[u8]),
(1u64, b"Standby\0" as &[u8]),
(2u64, b"Suspend\0" as &[u8]),
(3u64, b"Off\0" as &[u8]),
] {
let mut e = DrmModePropertyEnumWire::default();
e.value = value;
@@ -57,7 +57,7 @@ add_subdirectory(src)
# Enable unit testing
if (BUILD_TESTING)
################################################################### add_subdirectory(autotests)
#################################################################### add_subdirectory(autotests)
add_subdirectory(tests)
endif ()
@@ -151,6 +151,7 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
# shall we use DBus?
# enabled per default on Linux & BSD systems
@@ -129,6 +129,7 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].")
@@ -120,6 +120,7 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(KF6Codecs ${KF_DEP_VERSION} REQUIRED)
find_package(KF6Config ${KF_DEP_VERSION} REQUIRED)
@@ -123,6 +123,7 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
# shall we use DBus?
# enabled per default on Linux & BSD systems
@@ -32,7 +32,7 @@ find_package(KF6GuiAddons ${KF_DEP_VERSION} REQUIRED)
if(NOT WIN32 AND NOT APPLE AND NOT ANDROID AND NOT REDOX)
########################################################################################## find_package(KF6GlobalAccel ${KF_DEP_VERSION} REQUIRED)
########################################################################################### find_package(KF6GlobalAccel ${KF_DEP_VERSION} REQUIRED)
set(HAVE_KGLOBALACCEL TRUE)
else()
set(HAVE_KGLOBALACCEL FALSE)
@@ -143,6 +143,7 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6Svg ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
# shall we use DBus?
@@ -38,7 +38,7 @@ set_package_properties(Qt6Qml PROPERTIES
)
if (TARGET Qt6::Qml)
##################################################################### include(ECMQmlModule)
###################################################################### include(ECMQmlModule)
endif()
set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].")
@@ -1,6 +1,6 @@
add_subdirectory(core)
if (TARGET Qt6::Qml)
#################################################################### add_subdirectory(qml)
##################################################################### add_subdirectory(qml)
endif()
ecm_qt_install_logging_categories(
@@ -109,6 +109,7 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].")
@@ -109,6 +109,7 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
if(NOT WIN32 AND NOT APPLE AND NOT ANDROID AND NOT HAIKU)
option(WITH_X11 "Build with support for QX11Info::appUserTime()" ON)
@@ -124,6 +124,7 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED)
if (WITH_TEXT_TO_SPEECH)
find_package(Qt6 ${REQUIRED_QT_VERSION} CONFIG REQUIRED TextToSpeech)
@@ -129,6 +129,7 @@ find_package(Qt6WaylandClientPrivate REQUIRED)
find_package(Qt6WaylandClientPrivate REQUIRED)
find_package(Qt6WaylandClientPrivate REQUIRED)
find_package(Qt6WaylandClientPrivate REQUIRED)
find_package(Qt6WaylandClientPrivate REQUIRED)
set_package_properties(Wayland PROPERTIES
TYPE REQUIRED
)
@@ -74,10 +74,10 @@ void initializeLanguages()
// Ideally setting the LANGUAGE would change the default QLocale too
// but unfortunately this is too late since the QCoreApplication constructor
// already created a QLocale at this stage so we need to set the reset it
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // by triggering the creation and destruction of a QSystemLocale
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // by triggering the creation and destruction of a QSystemLocale
// this is highly dependent on Qt internals, so may break, but oh well
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// QSystemLocale *dummy = new QSystemLocale();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// delete dummy;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// QSystemLocale *dummy = new QSystemLocale();
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// delete dummy;
}
}
@@ -65,9 +65,9 @@ ecm_set_disabled_deprecation_versions(
)
add_subdirectory( src )
########################################if (BUILD_TESTING)
######################################## add_subdirectory( autotests )
########################################endif()
#########################################if (BUILD_TESTING)
######################################### add_subdirectory( autotests )
#########################################endif()
if (BUILD_QCH)
ecm_install_qch_export(
@@ -78,7 +78,7 @@ set_package_properties(PList PROPERTIES
if (CMAKE_SYSTEM_NAME MATCHES Linux)
# Used by the UDisks backend on Linux
###########################################################################################################find_package(LibMount)
############################################################################################################find_package(LibMount)
set_package_properties(LibMount PROPERTIES
TYPE REQUIRED)
endif()
@@ -135,6 +135,7 @@
#include <libudev.h>
#include <libudev.h>
#include <libudev.h>
#include <libudev.h>
#include "config-kwin.h"
@@ -1,2 +1,2 @@
################################################################################################################################add_subdirectory(killer) # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only
#################################################################################################################################add_subdirectory(killer) # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only # disabled: X11-only
add_subdirectory(wayland_wrapper)
@@ -382,6 +382,9 @@
#ifndef SUN_LEN
#define SUN_LEN(s) (sizeof(*(s)) - sizeof((s)->sun_path) + strnlen((s)->sun_path, sizeof((s)->sun_path)))
#endif
#ifndef SUN_LEN
#define SUN_LEN(s) (sizeof(*(s)) - sizeof((s)->sun_path) + strnlen((s)->sun_path, sizeof((s)->sun_path)))
#endif
/*
KWin - the KDE window manager
This file is part of the KDE project.
@@ -10,5 +10,5 @@ target_link_libraries(systembell PRIVATE
KF6::GlobalAccel
KF6::I18n
$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,Canberra::Canberra,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>
$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,$<IF:$<BOOL:${Canberra_FOUND}>,Canberra::Canberra,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>
)
@@ -135,6 +135,7 @@
#include <libudev.h>
#include <libudev.h>
#include <libudev.h>
#include <libudev.h>
#include "backends/libinput/device.h"
#include "core/inputdevice.h"
@@ -766,6 +766,12 @@
#define F_SEAL_SHRINK 0x0002
#define F_SEAL_GROW 0x0004
#define F_SEAL_WRITE 0x0008
#define F_ADD_SEALS 1033
#define F_GET_SEALS 1034
#define F_SEAL_SEAL 0x0001
#define F_SEAL_SHRINK 0x0002
#define F_SEAL_GROW 0x0004
#define F_SEAL_WRITE 0x0008
/*
KWin - the KDE window manager
This file is part of the KDE project.
@@ -294,6 +294,14 @@
#endif
#endif
#ifdef Q_OS_REDOX
#undef QT_USE_XOPEN_LFS_EXTENSIONS
#undef QT_LARGEFILE_SUPPORT
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
#endif
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
@@ -1459,6 +1459,13 @@ qt_internal_extend_target(Core CONDITION REDOX
io/qstorageinfo_unix.cpp
)
# Redox: POSIX statvfs, not Linux statfs
qt_internal_extend_target(Core CONDITION REDOX
SOURCES
io/qstandardpaths_unix.cpp
io/qstorageinfo_unix.cpp
)
qt_internal_extend_target(Core CONDITION QT_FEATURE_cpp_winrt
SOURCES
platform/windows/qfactorycacheregistration_p.h
@@ -1746,6 +1753,13 @@ qt_internal_extend_target(Core CONDITION REDOX
io/qstorageinfo_unix.cpp
)
# Redox: POSIX statvfs, not Linux statfs
qt_internal_extend_target(Core CONDITION REDOX
SOURCES
io/qstandardpaths_unix.cpp
io/qstorageinfo_unix.cpp
)
qt_internal_extend_target(Core CONDITION QT_FEATURE_itemmodel
SOURCES
itemmodels/qabstractitemmodel.cpp itemmodels/qabstractitemmodel.h itemmodels/qabstractitemmodel_p.h
@@ -214,6 +214,7 @@ static_assert(std::is_signed_v<qint128>,
#include <assert.h>
#include <assert.h>
#include <assert.h>
#include <assert.h>
#ifndef static_assert
#define static_assert _Static_assert
#endif
@@ -1158,6 +1158,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
#ifdef IPV6_HOPLIMIT
#ifdef IPV6_HOPLIMIT
#ifdef IPV6_HOPLIMIT
#ifdef IPV6_HOPLIMIT
#ifdef IPV6_HOPLIMIT
if (header.hopLimit != -1) {
msg.msg_controllen += CMSG_SPACE(sizeof(int));
@@ -1203,6 +1204,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
#endif
#endif
#endif
#endif
#endif
if (header.ifindex != 0 || !header.senderAddress.isNull()) {
struct in6_pktinfo *data = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsgptr));
@@ -58,6 +58,7 @@
#include <sys/ioctl.h>
#include <sys/ioctl.h>
#include <sys/ioctl.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#if defined(Q_OS_VXWORKS)
@@ -88,6 +88,7 @@ public:
#if QT_CONFIG(opengl)
#if QT_CONFIG(opengl)
#if QT_CONFIG(opengl)
#if QT_CONFIG(opengl)
#if QT_CONFIG(opengl)
virtual QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const = 0;
#endif /* QT_CONFIG(opengl) */
@@ -126,6 +127,7 @@ public:
#endif /* QT_CONFIG(opengl) */
#endif /* QT_CONFIG(opengl) */
#endif /* QT_CONFIG(opengl) */
#endif /* QT_CONFIG(opengl) */
#endif /* QT_CONFIG(opengl) */
virtual bool canCreatePlatformOffscreenSurface() const { return false; }
#if QT_CONFIG(opengl)
@@ -175,6 +177,7 @@ public:
#if QT_CONFIG(opengl)
#if QT_CONFIG(opengl)
#if QT_CONFIG(opengl)
#if QT_CONFIG(opengl)
#if QT_CONFIG(opengl)
virtual void *nativeResourceForContext(NativeResource /*resource*/, QPlatformOpenGLContext */*context*/) { return nullptr; }
#endif /* QT_CONFIG(opengl) */
@@ -214,6 +217,7 @@ public:
#endif /* QT_CONFIG(opengl) */
#endif /* QT_CONFIG(opengl) */
#endif /* QT_CONFIG(opengl) */
#endif /* QT_CONFIG(opengl) */
};
}
@@ -76,7 +76,6 @@ fn detect_vendor(cpu: u32) -> Vendor {
fn detect_cpus() -> Vec<u32> {
// Try /scheme/sys/cpu first for CPU count
if let Ok(d) = fs::read_to_string("/scheme/sys/cpu") {
let mut v = Vec::new();
for line in d.lines() {
if line.starts_with("CPUs: ") {
if let Ok(count) = line[6..].trim().parse::<u32>() {
Submodule local/sources/base updated: 48872298aa...d1a0400e84
Submodule local/sources/kernel updated: 51b15a181a...502f5c5190
Submodule local/sources/relibc updated: 33f77f4172...188e3dacd6
Binary file not shown.
Binary file not shown.
Binary file not shown.
+6 -1
View File
@@ -11,7 +11,12 @@ if [ "${COOKBOOK_HOST_SYSROOT}" = "/usr" ] && command -v rustup >/dev/null 2>&1;
popd
fi
export CARGO=${CARGO:-env -u CARGO cargo}
# Override CARGO to preserve RUSTUP_TOOLCHAIN for correct nightly
export CARGO="env -u CARGO cargo"
export RUSTUP_TOOLCHAIN=nightly-2025-11-15
export REDOXER_TOOLCHAIN=""
# Allow unused mut (edition 2024 migration noise)
export RUSTCFLAGS="-A unused_mut"
"${COOKBOOK_MAKE}" \
-C "${COOKBOOK_SOURCE}" \
-j"${COOKBOOK_MAKE_JOBS}" \
+24 -2
View File
@@ -11,6 +11,8 @@ esac
CONFIG_NAME="redbear-mini"
ARCH="x86_64"
ALLOW_UPSTREAM=0
NO_CACHE=0
DISTCLEAN=0
usage() {
cat <<EOF
@@ -19,8 +21,12 @@ Usage: $(basename "$0") [OPTIONS] [CONFIG_NAME] [ARCH]
Build a Red Bear OS live ISO for real bare metal.
Options:
--upstream Allow Redox/upstream recipe source refresh during build
-h, --help Show this help
--upstream Allow Redox/upstream recipe source refresh during build
--no-cache Rebuild from scratch, discarding recipe build caches and
package repository (preserves cross-compiler toolchain)
--no-cache-distclean Full rebuild including cross-compiler toolchain
(use when toolchain itself is broken or outdated)
-h, --help Show this help
Supported targets:
redbear-full Full desktop ISO (Wayland + KDE + GPU drivers)
@@ -39,6 +45,12 @@ while [ $# -gt 0 ]; do
--upstream)
ALLOW_UPSTREAM=1
;;
--no-cache)
NO_CACHE=1
;;
--no-cache-distclean)
DISTCLEAN=1
;;
-h|--help)
usage
exit 0
@@ -86,6 +98,16 @@ fi
echo "Building Red Bear OS ISO for real bare metal"
echo " config: ${CONFIG_NAME}"
echo " arch: ${ARCH}"
if [ "$DISTCLEAN" -eq 1 ]; then
echo " cache: full distclean (rebuilding toolchain + packages)"
make clean
elif [ "$NO_CACHE" -eq 1 ]; then
echo " cache: disabled (rebuilding packages, preserving toolchain)"
make repo_clean
rm -rf repo
# Also clean local recipe targets that repo_clean misses
find local/recipes -maxdepth 4 -name "target" -type d -exec rm -rf {} + 2>/dev/null || true
fi
if [ "$ALLOW_UPSTREAM" -eq 1 ]; then
echo " upstream recipe refresh: enabled"
REPO_OFFLINE=0 COOKBOOK_OFFLINE=false make live CONFIG_NAME="${CONFIG_NAME}" ARCH="${ARCH}"