i915n display (KMS) on Ivy Bridge: facade 2.0, misc/drm_kms (carried Linux KMS), LinuxKPI additions #21

Merged
toasterson merged 60 commits from i915n-kms into main 2026-10-06 20:20:48 +00:00
Owner

i915n drives the display of Ivy Bridge GPUs (first hardware: ThinkPad X230, HD 4000, LVDS 1366x768). Three parts, built and tested together on illumos-drm 0e0d479:

1. Facade 2.0 in the Rust core (kms-core)

  • Linux's KMS code is carried in C. The core forwards a Linux-KMS device's mode-setting ioctls to it through drm_driver.illumos_lkms, the hooks in the new include/drm/drm_lkms.h:
    • ioctl, file_open, file_close, lastclose, register_dev, unregister_dev, mode_config;
    • KMS starts with drm_dev_illumos_lkms_register().
  • The core keeps the ioctl entry point, Linux's size rule, permissions, master/auth, client caps and GET_CAP.
  • Each file has its event queue: a 4096-byte ring with Linux's budget. drm_illumos_event_reserve, _unreserve and _deliver work in thread context and in low-level interrupt context; read(2) and chpoll(9E) serve the ring.
  • drm_device and drm_file gain fixed-size KMS areas that the C layer overlays with Linux's field names. drm_file gains Linux's client-cap and master booleans.
  • Facade major version 2. 178 drm-core host tests pass. gcc's layout on illumos matches the bindings (41 sizes, 277 offsets).

2. misc/drm_kms (package driver/graphics/drm-kms)

  • Contents: Linux v7.2's KMS object model, atomic core and its uAPI handlers, vblank, modes and EDID, the KMS/DP/HDMI/DSC/SCDC helpers, and HDMI infoframes. That is 36 TUs from the pinned tree, all MIT; drm_hdcp_helper is GPL-only and is stubbed.
  • Three kms patches:
    • no legacy load callback;
    • registered means "KMS registered", because the layer registers the device early;
    • the vblank event list is initialised in drmm_mode_config_init().
  • illumos glue:
    • event functions;
    • ioctl dispatcher;
    • stubs for bridges, leases, writeback, sysfs and panels;
    • connectors get a class device (card<N>-<connector>);
    • connector name IDs at _init.
  • Links with -z defs; exports equal drm_kms.mapfile (715 symbols).

3. LinuxKPI and i915n with display (LINUXKPI_ABI 3)

  • LinuxKPI additions: I2C core and bit-banging, kthread workers, seq_buf, int_log, DMI from SMBIOS, memremap(WB), Linux-order port output, stand-alone wound/wait mutexes (DRM's modeset locks; wait-die on the core's stamps), plus about 40 new MIT headers.
  • i915n is built with the 133 display TUs (290 in total). Excluded and replaced by generated stubs, each documented: DSI, HDCP, LPE audio and the tracepoint TU.
  • i915 patches:
    • 0011: display only on Ivy Bridge; other platforms run headless as before;
    • 0012: the drm_kms hook;
    • 0013: VBT read-only from the ACPI OpRegion;
    • 0006 now only acts without a display.
  • The licence check covers all 791 Linux inputs.

4. The illumos console on i915n (i915n-console, design note section 4, owner decision 2026-10-06)

  • i915n on Ivy Bridge creates a gfx_private console minor (gfx0, /dev/fb) before its DRM minors and keeps the firmware framebuffer where the loader left it (its own reference and GGTT pin on the initial-plane object), so tem, the virtual terminals and /dev/fb work as with vgatext; i915n is bound at boot (drmadm select new) and cannot detach while it is the console.
  • Console restore is an atomic commit of the configuration recorded at attach, queued from gfx_private's KD_TEXT, from tem's full-screen clear of a text VT, from the DRM master's file closing and from lastclose; it commits only in KD_TEXT, with no DRM master, and never over X.
  • A CB_CL_PANIC callback points the console CRTC's plane at the console framebuffer with register writes only and records what it did in i915n_con_panic_log for the crash dump.
  • The private gate interfaces (gfxp_*, fb_info, callb_*, panicstr) are declared in drivers/i915/private.mapfile; i915n links with -N misc/gfx_private, -z defs.
  • drmadm select runs with DRM modules loaded: it only edits files read at boot; the in-kernel guards keep the stacks from loading together (README, drmadm(8), G7 test updated).

On the X230 (notes/x230-i915n-kms-20261005.md in the workspace; 5 panics on serials 6–8, all fixed here; serial 9 was display, serials 11–16 the console):

  • Attach: at boot, i915n is the console (prtconf -F = /pci@0,0/display@2:gfx0), 16 VTs, 0 LinuxKPI warnings.
  • modetest -M i915: LVDS-1 at 1366x768; full modeset (FDI training, PCH DPLL, backlight); page flips at 60.13 Hz with vblank events.
  • Xorg 21.1 + lightdm: modesetting with glamor on crocus (IVB GT2), DRI3, OpenGL 4.2, glxgears at a vsynced 60 FPS, MATE session; lightdm's greeter on VT 7 without any patch.
  • VT switching: Ctrl-Alt-F1..F7 and chvt: the CRTC's framebuffer goes X (129) → console (128) → X (129), X's root window pixel-identical before and after; the owner confirmed the interactive round on the panel (serial 15). A kill -9 of Xorg brings the console back.
  • Stability: serial 15 (93f2ef4) is the laptop's default boot environment since 2026-10-06, after four unattended boots and the owner's round; openindiana (legacy stack) stays in the loader menu. Serial 17 (5ca1204, the console review's round-2 fixes; 1db4230 adds a comment) booted the same way: /dev/fb is crw------- lightdm (0600), the DRM nodes 0666.
  • Guest: run-g7-test.sh baseline, install and select-new on a fresh hephaistos guest at 5ca1204: 13 checks pass for the drmadm change.
  • Teardown: drmadm select legacy live, reboot into the legacy stack, and back.

Not covered:

  • The panic flip (reboot -d) was not watched on the panel yet; the dump record from serial 16 is for the next watched one.
  • Suspend/resume and quiesce(9E), backlight class device, display on other platforms (WI-518, WI-519).
  • vtdaemon's secure VT switching runs a root xlock over the session's locker (WI-515, test profile keeps it off); xf86-input-keyboard restores event mode after a killed X (WI-516); Xorg's CTM/mode-set errors at the first VT leave (WI-517).
i915n drives the display of Ivy Bridge GPUs (first hardware: ThinkPad X230, HD 4000, LVDS 1366x768). Three parts, built and tested together on illumos-drm `0e0d479`: **1. Facade 2.0 in the Rust core (`kms-core`)** - Linux's KMS code is carried in C. The core forwards a Linux-KMS device's mode-setting ioctls to it through `drm_driver.illumos_lkms`, the hooks in the new `include/drm/drm_lkms.h`: - `ioctl`, `file_open`, `file_close`, `lastclose`, `register_dev`, `unregister_dev`, `mode_config`; - KMS starts with `drm_dev_illumos_lkms_register()`. - The core keeps the ioctl entry point, Linux's size rule, permissions, master/auth, client caps and GET_CAP. - Each file has its event queue: a 4096-byte ring with Linux's budget. `drm_illumos_event_reserve`, `_unreserve` and `_deliver` work in thread context and in low-level interrupt context; `read(2)` and `chpoll(9E)` serve the ring. - `drm_device` and `drm_file` gain fixed-size KMS areas that the C layer overlays with Linux's field names. `drm_file` gains Linux's client-cap and master booleans. - Facade major version 2. 178 drm-core host tests pass. gcc's layout on illumos matches the bindings (41 sizes, 277 offsets). **2. `misc/drm_kms` (package `driver/graphics/drm-kms`)** - Contents: Linux v7.2's KMS object model, atomic core and its uAPI handlers, vblank, modes and EDID, the KMS/DP/HDMI/DSC/SCDC helpers, and HDMI infoframes. That is 36 TUs from the pinned tree, all MIT; `drm_hdcp_helper` is GPL-only and is stubbed. - Three kms patches: - no legacy `load` callback; - `registered` means "KMS registered", because the layer registers the device early; - the vblank event list is initialised in `drmm_mode_config_init()`. - illumos glue: - event functions; - ioctl dispatcher; - stubs for bridges, leases, writeback, sysfs and panels; - connectors get a class device (`card<N>-<connector>`); - connector name IDs at `_init`. - Links with `-z defs`; exports equal `drm_kms.mapfile` (715 symbols). **3. LinuxKPI and i915n with display (`LINUXKPI_ABI` 3)** - LinuxKPI additions: I2C core and bit-banging, kthread workers, `seq_buf`, `int_log`, DMI from SMBIOS, `memremap(WB)`, Linux-order port output, stand-alone wound/wait mutexes (DRM's modeset locks; wait-die on the core's stamps), plus about 40 new MIT headers. - i915n is built with the 133 display TUs (290 in total). Excluded and replaced by generated stubs, each documented: DSI, HDCP, LPE audio and the tracepoint TU. - i915 patches: - 0011: display only on Ivy Bridge; other platforms run headless as before; - 0012: the `drm_kms` hook; - 0013: VBT read-only from the ACPI OpRegion; - 0006 now only acts without a display. - The licence check covers all 791 Linux inputs. **4. The illumos console on i915n (`i915n-console`, design note section 4, owner decision 2026-10-06)** - i915n on Ivy Bridge creates a `gfx_private` console minor (`gfx0`, `/dev/fb`) before its DRM minors and keeps the firmware framebuffer where the loader left it (its own reference and GGTT pin on the initial-plane object), so tem, the virtual terminals and `/dev/fb` work as with vgatext; i915n is bound at boot (`drmadm select new`) and cannot detach while it is the console. - Console restore is an atomic commit of the configuration recorded at attach, queued from gfx_private's `KD_TEXT`, from tem's full-screen clear of a text VT, from the DRM master's file closing and from lastclose; it commits only in `KD_TEXT`, with no DRM master, and never over X. - A `CB_CL_PANIC` callback points the console CRTC's plane at the console framebuffer with register writes only and records what it did in `i915n_con_panic_log` for the crash dump. - The private gate interfaces (`gfxp_*`, `fb_info`, `callb_*`, `panicstr`) are declared in `drivers/i915/private.mapfile`; i915n links with `-N misc/gfx_private`, `-z defs`. - `drmadm select` runs with DRM modules loaded: it only edits files read at boot; the in-kernel guards keep the stacks from loading together (README, drmadm(8), G7 test updated). **On the X230** (`notes/x230-i915n-kms-20261005.md` in the workspace; 5 panics on serials 6–8, all fixed here; serial 9 was display, serials 11–16 the console): - **Attach:** at boot, i915n is the console (`prtconf -F` = `/pci@0,0/display@2:gfx0`), 16 VTs, 0 LinuxKPI warnings. - **`modetest -M i915`:** LVDS-1 at 1366x768; full modeset (FDI training, PCH DPLL, backlight); page flips at 60.13 Hz with vblank events. - **Xorg 21.1 + lightdm:** modesetting with glamor on crocus (IVB GT2), DRI3, OpenGL 4.2, glxgears at a vsynced 60 FPS, MATE session; lightdm's greeter on VT 7 without any patch. - **VT switching:** Ctrl-Alt-F1..F7 and `chvt`: the CRTC's framebuffer goes X (129) → console (128) → X (129), X's root window pixel-identical before and after; the owner confirmed the interactive round on the panel (serial 15). A `kill -9` of Xorg brings the console back. - **Stability:** serial 15 (`93f2ef4`) is the laptop's default boot environment since 2026-10-06, after four unattended boots and the owner's round; `openindiana` (legacy stack) stays in the loader menu. Serial 17 (`5ca1204`, the console review's round-2 fixes; `1db4230` adds a comment) booted the same way: `/dev/fb` is `crw------- lightdm` (0600), the DRM nodes 0666. - **Guest:** `run-g7-test.sh` `baseline`, `install` and `select-new` on a fresh hephaistos guest at `5ca1204`: 13 checks pass for the drmadm change. - **Teardown:** `drmadm select legacy` live, reboot into the legacy stack, and back. **Not covered:** - The panic flip (`reboot -d`) was not watched on the panel yet; the dump record from serial 16 is for the next watched one. - Suspend/resume and quiesce(9E), backlight class device, display on other platforms (WI-518, WI-519). - vtdaemon's secure VT switching runs a root xlock over the session's locker (WI-515, test profile keeps it off); xf86-input-keyboard restores event mode after a killed X (WI-516); Xorg's CTM/mode-set errors at the first VT leave (WI-517).
The headers only; the core, the bindings and the drivers follow.
drm_device and drm_file get fixed-size mode-setting areas that a Linux KMS
implementation overlays with Linux's field names (DRM_FACADE_DEVICE_KMS,
DRM_FACADE_FILE_KMS); drm_file gets Linux's client-capability booleans;
drm_driver.illumos_lkms names the hooks of drm_lkms.h (mode-setting ioctls,
file open/close, lastclose, register/unregister); the event functions let
the KMS code deliver vblank and flip events into the core's file queues.
drm_facade.h includes drm_lkms.h (drm_facade_check() takes the size of
struct drm_illumos_lkms_funcs, and the bindings are generated from the
umbrella header). Regenerated with tools/facade/generate.sh at illumos-gate
0fb1d5d8d3: drm-facade-sys (drm_device and drm_file with their KMS areas,
drm_file's client-capability booleans, drm_driver.illumos_lkms,
drm_illumos_mode_config.async_page_flip, drm_illumos_lkms_funcs and the
three event functions), both mapfiles, the layout program and xtask's
table. The size tables of misc/drm_core and drm-facade list
drm_illumos_lkms_funcs; the Rust drivers fill in the new fields (no Linux
KMS hooks, no asynchronous flips). misc/drm_core links only once it
defines the event functions (next commits).
A driver whose Driver::lkms() answers is a Linux-KMS device: every command
of the core's mode-setting table goes, after the core's permission check,
to Driver::lkms_ioctl with the kernel copy of its argument (Linux's size
rule through CoreArg; copied back for commands that write, never after a
failure; the handler's negative errno is the ioctl's). Opens run the KMS
code's file_open before the driver's open (undone with file_close if that
fails); closes run its file_close before the GEM handles, sync objects and
postclose go, and lastclose after the last file (lkms::open_file,
close_file). lkms::Registration sequences mode_config, the registration,
register_dev (undone on failure) and a single unregister_dev.

Each file of a Linux-KMS device has an event queue with Linux's
4096-byte budget: reserve/unreserve charge it, deliver copies an event into
a preallocated 4096-byte ring (delivered plus reserved bytes never exceed
the budget, so delivery never allocates), read(2) returns whole events as
drm_read() and gives the space back, chpoll(9E) reports POLLIN|POLLRDNORM
while events are queued. A closing file loses its queued events and its
later deliveries; files that are not master are bounded to 256 KiB per
device, as R3. The lock is an adaptive mutex (with the fence priority when
the driver set one), never held while calling C code; readers and pollers
are woken after it is released.

GET_CAP reports DRM_CAP_ASYNC_PAGE_FLIP from ModeConfig.async_page_flip.
SET_CLIENT_CAP, SET_MASTER and DROP_MASTER pass the file's FileFlags (client
capabilities, is_master, was_master) to Driver::file_flags under the state
lock; FileFlags::store writes them into the facade drm_file as Linux's
booleans. Device::abandon undoes an attach whose register_dev failed.

Host tests: dispatch through a mock (permission before forwarding, the
size rule both ways, copy back only after success, errnos), open/close/
lastclose and register/unregister order, the event budget, reserve,
unreserve, deliver, partial and wrapping reads, a closing file, the
device bound and the master exemption, master tracking and the drm_file
mirror.
drm_dev_alloc refuses a table with both illumos_rkms and illumos_lkms, or
an illumos_lkms without one of its required hooks (-EINVAL).

drm_dev_register takes the features from drm_device.driver_features (the
device's: i915 clears DRIVER_MODESET on hardware without a display), and a
device with DRIVER_MODESET whose table has illumos_lkms becomes a
Linux-KMS device: the KMS code's mode_config fills the GET_CAP limits
before the device is created, register_dev ends a successful registration
and its failure undoes it (without the driver's detach hooks).
drm_dev_unregister runs unregister_dev once its checks have passed, after
the device left the device table and before the minor nodes go;
drm_dev_illumos_unplug runs it as Linux's drm_dev_unplug() does, before
the driver's remove and release, so the last put owes nothing.
drm_dev_illumos_set_mode_config keeps async_page_flip off (R3 has no
asynchronous flips).

The facade driver forwards the mode-setting commands to the KMS code's
ioctl hook inside an ioctl frame (its copy_to_user and friends find the
data model), runs file_open between the core's set-up and the driver's
open, file_close, lastclose, and mirrors client capabilities and master
status into every drm_file (initialised at open).

drm_illumos_event_reserve, _unreserve and _deliver find the file from its
marks and the device through its publication, and work on the device's
event queues without blocking, allocating or calling C code.
The layer's drm_device.h defines DRM_FACADE_DEVICE_KMS (vblank, vbl_lock,
max_vblank_count, vblank_event_list, mode_config) when Linux's KMS headers
are on the include path (misc/drm_kms and i915n), with Linux's
drm_mode_config.h complete before the facade's struct drm_device;
drm_file.h defines DRM_FACADE_FILE_KMS (fbs, fbs_lock, blobs,
pending_event_list), Linux's struct drm_pending_event (MIT, from Linux's
drm_file.h) and the event functions misc/drm_kms implements. Static
assertions check that the fields fit the facade's KMS areas.

Also: drm_facade.h includes drm_lkms.h before the facade's (whose
drm_facade_check() needs struct drm_illumos_lkms_funcs complete),
drm_info_printer() takes Linux's struct device, drm_dev_has_vblank() is
drm_vblank.c's function again.
Adapters with bus numbers, i2c_transfer()/__i2c_transfer() with the bus
lock, retries and timeout, i2c_get/put_adapter(), and an independent
implementation of the I2C master protocol over the line callbacks
(i2c_bit_algo, i2c_bit_add_bus()): start/repeated start/stop, ACK
handling, clock stretching with timeout, I2C_M_* flags. For DDC/EDID,
DP AUX I2C, SDVO and i915's GMBUS fallback. Self-test with a simulated
slave (st_i2c.c).
kthread_create/run_worker, kthread_queue/flush/cancel work and
kthread_destroy_worker over the layer's kthreads (DRM's vblank works);
seq_buf (EDID and i915 display logging); intlog2/intlog10 in 8.24 fixed
point (i915's link bandwidth code).
MIT headers (independent declarations) for what the DRM KMS code and the
133 display TUs include and illumos lacks or implements differently: DRM
sysfs/writeback/debugfs/GEM atomic helper/MIPI DSI, i915's HDCP
interface types, backlight, PWM, DMI, VGA arbiter, OF/fwnode, platform
devices, CEC, ACPI video/button, iopoll, video timing and command line,
fb pixel clock conversion; plus small additions (__GENMASK, U64_C,
mem_is_zero, int_pow, in_range32, guid helpers, PCI bridge control,
WQ_UNBOUND_MAX_ACTIVE, WARN_RATELIMIT). struct device gains of_node and
fwnode (always NULL) and struct hrtimer Linux's node.expires: LINUXKPI_ABI 2.

drivers/i915/display-tus.txt: the display TUs (145 minus DSI, HDCP, LPE
audio and the GPL tracepoint TU).
facade_layout.illumos.out: facade 2.0 as gcc 15.3.0 lays it out on
illumos (oibuild, 41 sizes, 277 offsets, 318 lines; cargo xtask
facade-check finds no difference). README: what facade 2.0 does for
Linux-KMS devices (hooks, ioctl forwarding, registration and the unplug
path, the drm_file mirror, the event queues and their contexts, the
version), and what was verified.
dmi_get_system_info(), dmi_check_system(), dmi_first_match() and
dmi_match() over the system, board, BIOS and chassis strings of ksmbios,
copied when the layer loads: i915's display quirk tables match against
them. The SMBIOS functions are non-DDI (private.d/dmi.txt).
fetch-and-patch.sh applies carried/drm_kms/patches after i915's series,
licence-checks carried/drm_kms/tus.txt (Linux's KMS closure of i915's
display: 35 MIT files of drm.ko, drm_kms_helper and drm_display_helper,
without the GPL drm_hdcp_helper.c, plus drivers/video/hdmi.c), replaces
the GPL drm_dp_mst_topology_internal.h by an MIT declaration header and
stubs drm_trace.h and intel_display_trace.h like i915's tracepoint
headers; the series copies are kept in application order. mit-headers.txt
gains the MIT KMS, DP, DSC, HDCP, HDMI and SCDC headers. gen-config.py
also reads the DRM headers and drm_kms' TUs and turns the backlight class
device, AGP, panel bridges, ZONE_DEVICE and sysrq off (config.h
regenerated).

Patch kms 0001: drm_mode_object.c reads no legacy load callback (the
facade's drm_driver has none).
carried/drm_kms/build.sh compiles the 36 Linux TUs of tus.txt from the
tree fetch-and-patch.sh prepared and the illumos sources, with i915n's
flags and configuration, licence-checks every Linux file the compiler
read, generates the export list (what the sources EXPORT_SYMBOL and the
objects define; drm_kms.mapfile, compared with the committed one) and
links misc/drm_kms with -N misc/drm_core -N misc/linuxkpi
-N misc/drm_helpers -z defs -B reduce; its global symbols must be exactly
drm_kms.mapfile's.

illumos sources (MIT):
- drm_kms_mod.c: module linkage, facade and LinuxKPI checks at _init;
- drm_kms_event.c: Linux's event functions (reserve, cancel, send with
  completion, fence timestamp and a file closed before delivery) over
  the core's event queue (drm_lkms.h);
- drm_kms_lkms.c: drm_kms_illumos_funcs, the facade 2.0 hooks: Linux's
  mode-setting rows of drm_ioctls[] by number (no leases), file
  open/close (pending events, framebuffers, user blobs), register
  (drm_modeset_register_all), mode_config for GET_CAP;
- drm_kms_stubs.c: bridges, leases, sysfs, writeback, panels, panel
  orientation quirks and the GPL HDCP helper as documented no-ops or
  refusals; GEM handle references and drm_gem_print_info over the
  facade; drm_gem_plane_helper_prepare_fb (implicit write fence).

private.mapfile: memcmp, memmove, strlcat, mod_miscops (genunix).
gen-license.sh writes the module's licence file with MODULE=drm_kms.
drm-kms.p5m delivers kernel/misc/amd64/drm_kms with its generated
licence file (the carried Linux files' notices) and requires drm-core,
linuxkpi and drm-helpers. drmadm's new-stack package list gains it.
The layer registers a devm_drm_dev_alloc() device early, before the
driver's mode configuration exists; lkpi_drm_dev_register(), where a
Linux driver calls drm_dev_register(), now calls the facade's
drm_dev_illumos_lkms_register() (declared in drm_lkms.h as the core side
defines it), which starts the KMS hooks for a DRIVER_MODESET device and
does nothing otherwise, and returns its error. linuxkpi/build.sh takes
FACADE_MAPFILE.
drm_dev_register() no longer starts a Linux-KMS driver's mode setting:
the LinuxKPI layer registers i915's device in devm_drm_dev_alloc(), before
i915's mode configuration exists and before it clears DRIVER_MODESET on
display-less hardware. The new drm_dev_illumos_lkms_register() (drm_lkms.h,
both mapfiles, bindings) does, where i915 calls Linux's drm_dev_register():
it reads drm_device.driver_features then, and with DRIVER_MODESET and
illumos_lkms calls mode_config and register_dev. It returns 0 (also, doing
nothing, without DRIVER_MODESET or illumos_lkms), -EINVAL for a device that
is not registered or unplugged, -EBUSY for a second call or while a file
is open (not counted as the call), or register_dev's error (mode setting
stays off, the device stays registered). unregister_dev still runs once,
at unplug or unregister, and only after a successful register_dev.

A Linux-KMS driver's device gets its event queues at registration. Until
mode setting starts, GET_CAP and SET_CLIENT_CAP answer as for a device
without DRIVER_MODESET and DRIVER_ATOMIC (lkms::caps_view) and the
mode-setting ioctls fail with EOPNOTSUPP; afterwards only files the KMS
code opened (file_open, recorded per file) are forwarded and get
file_close, and lastclose follows the last file. drm_dev_register()'s
mode_config/register_dev sequencing and Device::abandon are gone;
Registration::start replaces Registration::register.

drm_lkms.h and drm_drv.h describe the new order. Host tests: start and
unregister order, a failed start, the capability view before and after
the start, the per-file flag (drm-core: 178).
The generated scope mapfile needs local: * for -B reduce to localise the
Linux functions the module does not export (found on oibuild: 840
globals for 715 exports). README: a misc/drm_kms section (what it
carries, licences, how it is built).
The facade's drm_facade.h includes drm_lkms.h since kms-core.
What i915's display needs at run time beyond the link:

- memremap(MEMREMAP_WB) over vmap_pfn(): physical memory outside the
  driver's BARs (the ACPI OpRegion and its VBT). Write-back only (a WC
  alias of RAM would give a frame two cache types); frames above the
  CPU's physical address width (CPUID 0x80000008), zero, wrapping and
  over-1-GiB ranges are refused, so a bad firmware address cannot make
  a page-table entry with reserved bits. memunmap() takes the returned
  address.
- outb()/outw()/outl() in Linux's order (value, port). The prologue's
  <sys/sunddi.h> declares illumos' port-first versions, so intel_vga.c's
  VGA sequencer writes compiled against them and would have written the
  port number to the port the value names.
- component_add()/component_add_typed() succeed and leave the component
  unbound, as on Linux without the aggregate driver (i915's display
  audio logged "failed to add audio component" at every attach).
- vga_switcheroo_register_client() succeeds as on Linux without
  CONFIG_VGA_SWITCHEROO (the "Failed to register vga switcheroo!" error
  line of the X230 attaches).

LINUXKPI_ABI 3: this branch's layer had reused 2, the number main gave
PR 18's layout change, for the facade 2.0 and KMS headers.
- 0011: intel_display_device_probe() takes Linux's no_display path on
  every platform but Ivy Bridge and logs "display on <platform> is not
  supported on illumos; running headless"; i915's runtime init then
  clears DRIVER_MODESET/DRIVER_ATOMIC, so the core starts no mode
  setting there.
- 0012: the display build (I915N_DISPLAY) sets
  i915_drm_driver.illumos_lkms = &drm_kms_illumos_funcs (misc/drm_kms).
- 0013: intel_bios_get_vbt() asks i915_illumos_opregion_vbt() after the
  (absent) ACPI OpRegion code: illumos/i915_illumos_vbt.c copies the VBT
  out of the OpRegion (RVDA/RVDS, else mailbox 4, validated with
  intel_bios_is_valid_vbt()) through memremap(MEMREMAP_WB) and never
  writes to it.
- 0006 (description) and i915_illumos.c: the display-engine interrupt
  helpers act only on a device without display (headless build, or a
  platform patch 0011 makes headless); with a display they leave the
  reset and postinstall to Linux's display code and call Linux's
  ilk_display_irq_master_disable()/_enable() in the handler.
build.sh builds i915n with display by default (I915_DISPLAY=1): tus.txt
plus display-tus.txt, whose "-" lines take the headless stubs out
(i915_nodisplay.c, and the KMS helper stubs, now i915_nokms.c, which
misc/drm_kms provides), compiled with -DI915N_DISPLAY and linked with
-N misc/drm_kms -M carried/drm_kms/drm_kms.mapfile. I915_DISPLAY=0
builds R5c's headless i915n. Both lists are licence-checked by
fetch-and-patch.sh and the build's dependency check; gen-license.sh
covers display-tus.txt without an inputs list.

display-tus.txt: 132 Linux TUs (i915_panic.c out) and two illumos
sources. illumos/gen-nodisplay.py --excluded writes
illumos/i915_excluded.c: the DSI, HDCP and LPE audio functions the
display objects call, each with the answer the real function gives on
Ivy Bridge and the reason read from its callers (no default answer), and
the panic interface, whose alloc must succeed because
intel_framebuffer_init() fails every framebuffer without it.

private.mapfile: memmove (the display code).
i915n links -N misc/drm_kms; the package requires and incorporates
drm-kms, and its licence file covers the display's Linux inputs
(build.sh's linux-inputs.txt).
What the display build of i915n is and what was verified at f3a60ab on
oibuild: every new-stack module from one revision, i915n with display
linked -z defs, the seven packages as one p5p (serial 6). Nothing of the
display has run yet. Also drops a trailing blank line from
i915_illumos.c (cstyle).
ww_mutex_init() made a lock every operation refused, because the layer
only had the core's reservation locks; drm_modeset_lock (class
crtc_ww_class) needs stand-alone ones. They are now the layer's: holder in
ww_mutex.ctx, state under one of 64 hashed bucket mutexes, waiters on the
bucket's condition variable, wait-die with the core's stamps (shared
with reservation transactions, so one acquire context may take both
kinds). Found at the first i915n display attach on the X230 (one warning
per mode-setting lock).
drm_connector_ida_init() is Linux's drm_core_init(); without it every
drm_connector_init() failed on the zeroed per-type IDA, the connector's
probed-mode list stayed uninitialised and i915's LVDS setup faulted on it
(X230 panic, intel_panel_add_edid_preferred_mode). kms patch 0002: the
carried checks of dev->registered read drm_kms_dev_registered(dev), set
around drm_modeset_register_all(), because the LinuxKPI layer registers
the device with the core early.
Linux initialises dev->vblank_event_list in drm_dev_init(), which on
illumos is the Rust core's and leaves the KMS area zeroed. The first armed
vblank event (i915's initial commit at attach) dereferenced the zeroed
list (X230 panic in drm_crtc_arm_vblank_event).
misc/drm_kms: connectors get their class device (connector->kdev)
Some checks failed
ci / check-hosted (pull_request) Successful in 10m10s
ci / kmod-illumos (pull_request) Has been cancelled
0e0d479f8f
drm_sysfs_connector_add() made no device, so connector->kdev stayed NULL;
i915's DP connectors dereference it at registration (kdev->kobj.name in a
debug message, the AUX channel's I2C bus parent): X230 panic in
intel_dp_connector_register(). The stub now makes a LinuxKPI device named
card<N>-<connector>, child of the DRM device's, released by
drm_sysfs_connector_remove(). Still no sysfs and no uevents.
i915's intel_panel_register() allocates a panel for every eDP and DSI
connector in its late_register hook and fails the registration if the
allocation fails, so -ENODEV failed the KMS start on every eDP laptop.
Allocate a zeroed container of the requested size with the panel at the
offset, set up as drm_panel_init() does, with one reference that a
managed action on the device drops. add/remove/prepare/unprepare stay
no-ops: there are no panel followers.
drm_kms_ioctl() returned the carried handlers' results unchanged, so
-ERESTARTSYS (512) and the other kernel-internal numbers reached user
space. Map them with lkpi_errno() as the layer's ioctl trampoline does.
The core's from_neg() now turns any number from 512 to 4095 that still
gets through into EIO, and misc/drm_core warns when it sees one. Tests:
ERESTARTSYS->EINTR in the host tests of lkpi_errno(), EINTR and a leaked
-512 in the forward tests (the test that accepted 4095 is gone).
A reader holds a 120-byte event that wraps around the ring's end while
the rest of the budget is reserved and delivered (wrapping too); the
held bytes are unchanged before end_read. A threaded variant copies each
held event slowly without the lock while another thread delivers as
fast as the budget allows (20000 events). Comment that a refused
delivery keeps its reservation.
linuxkpi: concurrency tests of stand-alone ww_mutexes and kthread workers
Some checks failed
ci / check-hosted (pull_request) Has been cancelled
ci / kmod-illumos (pull_request) Has been cancelled
d90270345d
The stand-alone wound/wait mutexes move from lkpi_resv.c into
lkpi_ww_mutex.c (prototypes in lkpi_ww_mutex.h), so that the host tests
can build them: trylock/is_locked, -EALREADY on relock, the younger
transaction's -EDEADLK and its recovery with the slow lock while the
older one waits, an unlock waking a blocked waiter, an interrupted wait,
and 2x20000 opposite-order transactions (host condition variables over
pthreads, with a per-thread pending signal).

New linuxkpi_selftest cases (in-kernel, with the core's stamps):
st_ww.c covers the same for stand-alone locks plus a cycle of a
reservation lock and a stand-alone lock both ways round and 2x2000
mixed opposite-order transactions; st_kthread.c covers worker ordering,
the flush of a running work, kthread_cancel_work_sync() of a running
self-requeueing work (the requeue during the cancel is refused) and
the destroy of a never-started worker with and without a queued work.
st_sched.c's helper-thread functions are shared through st.h.

ww_mutex.h's header comment no longer says stand-alone locks are
unsupported, and the fairness difference from Linux (no ordered waiter
queue: an unlock wakes all waiters of the bucket) is documented.
drm_kms_lkms.c had a CLOSEFB row that no command reached: the core's
mode-setting table did not know the number. drm-uapi gains Linux v7.2's
struct drm_mode_closefb and DRM_IOCTL_MODE_CLOSEFB (nr 0xD0, libdrm
2.4.109 predates it) and DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, written by hand
in linux_newer.rs. The core's table has CLOSEFB for any file on the
primary node, as Linux; a Linux-KMS device forwards it, R3 answers
ENOTTY (as a kernel before 6.8; R3 has no plane state that CLOSEFB
could keep apart from RMFB's, and libdrm users fall back to RMFB).
GET_CAP answers ATOMIC_ASYNC_PAGE_FLIP as Linux: the configuration's
async_page_flip, only with atomic mode setting.
drm_kms_register_dev() now calls drm_mode_config_validate() first, as
Linux's drm_dev_register() does for a driver without load.

The core copies each forwarded command's argument with its own table's
size (libdrm 2.4.109 structures) and the carried handlers use Linux
v7.2's. drm_kms_lkms.c lists the core's size of every forwarded command
in DRM_KMS_ARG() lines, each a _Static_assert against Linux's structure,
and the drm-core test lkms::tests::c_argument_sizes checks the list
against the core's table (one line per command, the core's size).
After the i915n step has fetched and patched the pinned Linux tree, run
carried/drm_kms/build.sh all: licence check and compile of the carried
KMS TUs, the export list against the committed drm_kms.mapfile, the
-z defs link and the global-symbol check.
Linux's intel_dp_hdcp_init() returns 0 when is_hdcp_supported() is
false. The DP MST connector init calls it for every connector; -ENODEV
only produced a debug message, but the stub should give Linux's answer.
i915_excluded.c regenerated with gen-nodisplay.py --excluded.
misc/drm_kms carries three patches, not one. State that only Ivy Bridge
has run the display build on hardware, so its headless path on other
platforms (the MacBook Pro's gen9.5) is untested, and that the selftest
files added for the display build (st_i2c.c, st_ww.c, st_kthread.c) are
built but have not run in a guest. List the new host tests.
drm_dev_illumos_lkms_register() counted a call that lkms_start refused
with EBUSY for a file opened meanwhile, although drm_lkms.h says such a
call is not counted. lkms::Registration records whether its hooks ran,
and a call refused before them is not counted; a failed register_dev
is. The device's driver_features are masked with the table's, as
Linux's drm_core_check_feature(), both for the core's features and for
the DRIVER_MODESET check of lkms registration; drm_lkms.h says so.
Clippy: field_reassign_with_default in a state.rs test.
The log directory was emptied at every run, so 'build.sh link' after a
compile deleted the compile's logs. Only a compile clears them now.
The LinuxKPI layer registers the device in devm_drm_dev_alloc(), before
the driver allocates its interrupts, and the fence priority can only be
set before registration; so the core's event lock is an adaptive mutex
without an interrupt cookie, which a low-level handler (the only kind
request_irq() accepts) may take. Said in lkms::dev and lkpi_drm.c.
- lkpi/prologue.h: outb()/outw()/outl() without <linux/io.h> fail to
  compile (an error-attributed call) instead of reaching illumos'
  port-first functions with Linux's arguments; <linux/io.h> replaces
  the guard with the Linux-order wrappers.
- i2c-algo-bit: no address retries for an I2C_M_IGNORE_NAK message, as
  Linux's bit_doAddress(); st_i2c.c checks that the address is sent once.
- DMI: a string the firmware leaves empty or blank in a structure it
  provides is "" as on Linux, not NULL (absent structures stay NULL).
- <linux/iopoll.h>: the poll macros rewritten as one loop over a small
  poll state with inline helpers (MIT, own structure); same contract.
- memremap(): note the write-back/uncached alias with ACPICA's mapping
  of firmware memory and why the read-only users accept it.
- lkpi_device_init()/lkpi_device_fini() are declared in <linux/device.h>
  for illumos glue (misc/drm_kms redeclared them).
drm_kms_mod.c's header said the connector name IDs are the module's only
global state and had an over-long line; it now says what _init sets up.
drm_kms_stubs.c takes lkpi_device_init()/_fini() from <linux/device.h>
and lkpi_dev_dip() from the prologue instead of redeclaring them.
i915n: VBT reader as Linux (DMI quirk, RVDA check), shared prototype, naming
Some checks failed
ci / check-hosted (pull_request) Successful in 9m2s
ci / kmod-illumos (pull_request) Failing after 26m6s
a342d09d0f
- i915_illumos_vbt.c applies Linux's intel_no_opregion_vbt DMI quirk
  (ThinkCentre A57: no OpRegion VBT), reports an OpRegion 2.1+ RVDA that
  points into the OpRegion (used as Linux uses it), and says why its
  write-back mapping may alias ACPICA's uncached one.
- Its prototype is in illumos/i915_illumos_vbt.h, which patch 0013
  includes (build.sh adds drivers/i915/illumos to the include path, last).
- Comments name the build variable (I915_DISPLAY) and the macro it sets
  (I915N_DISPLAY) consistently (i915_illumos.c, patch 0012).
- build.sh: link keeps the compile logs, as carried/drm_kms/build.sh.
illumos fixes its console at boot: consconfig opens the first minor node
of the display device, and tem drives it with VIS_DEVINIT, VIS_CONS* and
KDSETMODE (polled vector at panic); virtual terminals exist only with
such a framebuffer console. As the legacy i915 did, i915n on Ivy Bridge
now attaches gfx_private on its own node and creates the console minor
gfx<instance> (DDI_NT_DISPLAY) before its DRM minors, routes that minor's
open/close/ioctl/devmap/segmap to gfx_private and the rest to the DRM
core, and keeps the console framebuffer: the firmware framebuffer that
the loader describes (fb_info) and i915 inherits as the initial plane,
held by a framebuffer reference and an extra GGTT pin so that the
aperture range gfx_private draws through keeps backing it.

KD_TEXT (switch to a text VT, X exiting or dying) and DRM lastclose queue
an atomic commit of the console configuration recorded at attach (its
CRTC, mode and connectors, the console framebuffer on the primary plane,
everything else off); the work re-checks KD_TEXT with every modeset lock
held, so it never overrides X, which sets KD_GRAPHICS before its own
commit. A CB_CL_PANIC callback points the console plane back at the
console framebuffer with register writes and switches gfx_private to
KD_TEXT, so a panic is visible under X. A console device refuses detach.
Without a usable firmware framebuffer the console minor goes before
consconfig sees it and the device has no console.

private.mapfile: gfx_private's functions, fb_info, callb_add/delete,
panicstr, and documented DDI symbols missing from ddi.mapfile.
The mirror of fb_info had the colour fields the other way round, so the
check for a 32-bit XRGB framebuffer failed and i915n created no console
minor (X230: /dev/fb went to card0, serial console fallback).
X killed on its VT: illumos' VT driver destroys that VT's terminal state
without resetting the mode, so nothing sends KD_TEXT and the screen stays
dark (X230: CRTC with no framebuffer after kill -9 Xorg). When the master's
file closes in KD_GRAPHICS, i915n now switches gfx_private to KD_TEXT
itself (which repaints the console from its shadow and queues the restore);
in KD_TEXT it queues the restore directly.
ci: libdrm uAPI headers for the C builds when the runner image lacks them
Some checks failed
ci / check-hosted (pull_request) Has been cancelled
ci / kmod-illumos (pull_request) Has been cancelled
b8da67bae3
kmod-illumos failed at cdrmnull ("missing /usr/include/drm/drm.h") on
main and on every PR: the runner image has no developer/header-drm. A
step builds target/sysinc (/usr/include, plus drm.h and drm_mode.h from
gfx-drm at the commit OpenIndiana ships when they are missing) and the C
builds use it.
i915n console: restore on a text VT's repaint, never while a DRM client is master
Some checks failed
ci / check-hosted (pull_request) Successful in 3m47s
ci / kmod-illumos (pull_request) Has been cancelled
c65b3a186e
X230, Ctrl-Alt-F2 from a MATE session: VT 2 became active but the panel
kept X's last frame. tem had X's VT 7 in text mode again (after X
acknowledged an earlier switch), so the switch 7 -> 2 was text to text
and sent no KDSETMODE; only KDSETMODE triggered the restore. tem repaints
a text VT that becomes active with a full VIS_CONSCLEAR: that now queues
the restore too. The restore work, with every modeset lock held, does
nothing while a file holds the DRM master (X takes it before its own
commit and drops it when it leaves its VT), while the console is in
KD_GRAPHICS, or when the console configuration is on the display already.
The panic callback flips the plane whatever the KD mode, for the same
reason.
i915n console: review round fixes (closing master, gfx_private before VIS_DEVINIT, KD mode)
All checks were successful
ci / check-hosted (pull_request) Successful in 23m16s
ci / kmod-illumos (pull_request) Successful in 28m59s
93f2ef4e4d
- The restore queued when the DRM master's file closes no longer depends
  on lastclose: the core unlinks the closing file from filelist only after
  the KMS close hook, so the work ignores that file in its master check.
- The driver calls gfx_private's KDSETMODE (X's file closing, panic) only
  after tem's VIS_DEVINIT: before it gfx_private has no console state and
  its KD_TEXT dereferences NULL (Xorg without VTs opens /dev/fb itself).
  tem's VIS_CONS* commands and VIS_DEVFINI are refused from user space;
  gfx_private trusts their coordinates and data pointer.
- The KD mode is gfx_private's (KDGETMODE): KD_RESETTEXT and the driver's
  own KDSETMODE change it without always calling the hook. The master-gone
  path queues the restore directly.
- packaging: the console minor gfx<N> (/dev/fb) is 0600 root sys, as
  vgatext's; the DRM nodes stay 0666.
- The restore decision's safety argument in i915_illumos_con_kms.c;
  connectors beyond the eighth are logged; callb_delete dropped from the
  imports; ci: rm -rf of a stale sysinc/drm; patch 0012's message.
With i915n as the system console (and the legacy i915 with its gfx
console) the running stack can never be unloaded, so "drmadm select
legacy" refused in every console boot environment and the way back was
only through another boot environment. A selection only edits files read
at boot (update_drv -n attaches and detaches nothing; the other core is
excluded from the next boot on), so it now proceeds and says that the
loaded modules stay until the reboot. Verified on the X230 (i915n console
BE): select legacy, then select new again, with i915n attached as the
console. run-g7-test.sh checks the new behaviour (not rerun in a guest).
README: drmadm select runs with DRM modules loaded
Some checks failed
ci / check-hosted (pull_request) Has been cancelled
ci / kmod-illumos (pull_request) Has been cancelled
1799fb9084
i915n has no CTF, so a dump could only show the console's KD mode
(vmdump.7 of 2026-10-06: KD_TEXT, which X's VT in text mode gives as
well). i915n_con_panic_log now records the runs of the panic callback,
the KD mode it found, whether the plane was written and the surface
address: read with i915n_con_panic_log/4U.
i915n console: review round 2 fixes (kd_mode has one writer, panic always sets KD_TEXT, gfx0 perms order)
Some checks failed
ci / check-hosted (pull_request) Has been cancelled
ci / kmod-illumos (pull_request) Has been cancelled
5ca120489b
- i915n_con_text_mode() no longer stores gfx_private's answer into
  kd_mode: that store ran outside gfx_private's lock and could overwrite
  the KD_GRAPHICS the hook recorded for X's EnterVT with an older
  KD_TEXT, after which the panic callback would have skipped KDSETMODE
  and the VIS_CONSCLEAR filter would have kept a restore back. The hook
  is the only writer; the panic callback sets KD_TEXT unconditionally
  (gfx_private ignores a KDSETMODE of the mode it is in).
- i915n.p5m lists the catch-all 0666 perms first and gfx* 0600 last:
  devfsadm applies the last matching minor_perm entry. On the X230
  /dev/fb is crw------- (0600, chowned to the console user) with the
  installed minor_perm in that order.
- The closing-master comment states the address-reuse case (one flash).
i915n console: the VIS_CONSCLEAR filter reads kd_mode outside gfx_private's lock (comment)
All checks were successful
ci / kmod-illumos (pull_request) Successful in 48m51s
ci / check-hosted (pull_request) Successful in 3h3m25s
1db423043b
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
illumos/illumos-drm!21
No description provided.