runtime: consolidate the device-manager hello into runtime.device_manager
Every supervised driver owes the device manager a hello at startup, and the retry-lookup-call-check for it had been copied into five drivers: usb.helloManager (misfiled in the USB client) plus hand-rolled twins in display, virtio-gpu, pci-bus, and usb-xhci-bus. Extract it once as a runtime client, runtime.device_manager.hello(role, device_id) ?Handle — returns the manager endpoint (bus drivers keep it to report children through), null when there is no manager or it refused the handshake, and logs the outcome itself so each call site is one line. Also correct two roles while collapsing their calls: virtio-gpu and the display driver each claim one PCI function and report no children, so they are Role.device, not Role.bus. The manager ignores role today, so this is cosmetic, but it matches the protocol's own definition (bus = reports children via child_added). Behavior-preserving otherwise: pci-bus and usb-xhci-bus move their hello logging from raw serial writes to std.log, which the kernel renders with the same "<path>: " prefix, so driver-restart still matches "usb-xhci-bus: hello acknowledged". zig build clean; 8 QEMU cases pass (driver-restart, pci-scan, usb-hid, usb-storage, virtio-gpu, display-reattach, device-list, device-manager).
This commit is contained in:
@@ -21,12 +21,15 @@ const system = runtime.system;
|
||||
const ipc = runtime.ipc;
|
||||
const display_protocol = runtime.display_protocol;
|
||||
const scanout_protocol = runtime.scanout_protocol;
|
||||
const device_manager_protocol = runtime.device_manager_protocol;
|
||||
var device_id: u64 = 0;
|
||||
|
||||
|
||||
fn initialise(endpoint: ipc.Handle) bool {
|
||||
_ = endpoint;
|
||||
// Hello the device manager (role: device — we claim one GPU's PCI function
|
||||
// and serve its display engine; we report no children). Best-effort: without a
|
||||
// manager the driver still runs standalone; when present, the manager marks us
|
||||
// up before the hello deadline and restarts us if we die.
|
||||
_ = runtime.device_manager.hello(.device, device_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,28 +103,10 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
|
||||
return false;
|
||||
};
|
||||
|
||||
// The handshake, then the scan (reports join in M19.2).
|
||||
var manager: ?runtime.ipc.Handle = null;
|
||||
var tries: u32 = 0;
|
||||
while (manager == null and tries < 100) : (tries += 1) {
|
||||
manager = runtime.ipc.lookup(.device_manager);
|
||||
if (manager == null) runtime.system.sleep(20);
|
||||
}
|
||||
const h = manager orelse {
|
||||
_ = runtime.system.write("/system/drivers/pci-bus: no device manager to hello\n");
|
||||
return false;
|
||||
};
|
||||
const hello = protocol.Hello{ .role = @intFromEnum(protocol.Role.bus), .device_id = bridge_id };
|
||||
var reply: [protocol.message_maximum]u8 = undefined;
|
||||
const n = runtime.ipc.call(h, std.mem.asBytes(&hello), &reply) catch {
|
||||
_ = runtime.system.write("/system/drivers/pci-bus: hello call failed\n");
|
||||
return false;
|
||||
};
|
||||
if (n < protocol.reply_size or std.mem.bytesToValue(protocol.HelloReply, reply[0..protocol.reply_size]).status != 0) {
|
||||
_ = runtime.system.write("/system/drivers/pci-bus: hello refused\n");
|
||||
return false;
|
||||
}
|
||||
manager_handle = h;
|
||||
// The handshake (role: bus — we enumerate PCI and report the functions we
|
||||
// find), then the scan. Keep the manager handle to report children through;
|
||||
// a supervised bus that cannot reach its manager has nothing to serve.
|
||||
manager_handle = runtime.device_manager.hello(.bus, bridge_id) orelse return false;
|
||||
|
||||
scan();
|
||||
return true;
|
||||
|
||||
@@ -72,10 +72,7 @@ pub fn main(init: runtime.process.Init) void {
|
||||
const layout = xkb.byName(init.arguments.get(2) orelse "us") orelse xkb.us;
|
||||
|
||||
// Hello the manager first (meet the spawn deadline), then open the device.
|
||||
if (!runtime.usb.helloManager(device_id)) {
|
||||
_ = runtime.system.write("/system/drivers/usb-hid/keyboard: hello to device manager failed\n");
|
||||
return;
|
||||
}
|
||||
if (runtime.device_manager.hello(.device, device_id) == null) return;
|
||||
var device = runtime.usb.open(device_id) orelse {
|
||||
std.log.info("could not open device {d}", .{device_id});
|
||||
return;
|
||||
|
||||
@@ -37,10 +37,7 @@ pub fn main(init: runtime.process.Init) void {
|
||||
return;
|
||||
};
|
||||
|
||||
if (!runtime.usb.helloManager(device_id)) {
|
||||
_ = runtime.system.write("/system/drivers/usb-hid/mouse: hello to device manager failed\n");
|
||||
return;
|
||||
}
|
||||
if (runtime.device_manager.hello(.device, device_id) == null) return;
|
||||
var device = runtime.usb.open(device_id) orelse {
|
||||
std.log.info("could not open device {d}", .{device_id});
|
||||
return;
|
||||
|
||||
@@ -69,10 +69,7 @@ var bring_up_failed = false;
|
||||
|
||||
fn initialise(endpoint: runtime.ipc.Handle) bool {
|
||||
_ = endpoint;
|
||||
if (!runtime.usb.helloManager(device_id)) {
|
||||
_ = runtime.system.write("/system/drivers/usb-storage: hello to device manager failed\n");
|
||||
return false;
|
||||
}
|
||||
if (runtime.device_manager.hello(.device, device_id) == null) return false;
|
||||
device = runtime.usb.open(device_id) orelse {
|
||||
std.log.info("could not open device {d}", .{device_id});
|
||||
return false;
|
||||
|
||||
@@ -131,32 +131,13 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The handshake: role, protocol version, assignment — inside the manager's
|
||||
// deadline (the lookup retries cover the manager still registering).
|
||||
var manager: ?runtime.ipc.Handle = null;
|
||||
var tries: u32 = 0;
|
||||
while (manager == null and tries < 100) : (tries += 1) {
|
||||
manager = runtime.ipc.lookup(.device_manager);
|
||||
if (manager == null) runtime.system.sleep(20);
|
||||
}
|
||||
const h = manager orelse {
|
||||
_ = runtime.system.write("/system/drivers/usb-xhci-bus: no device manager to hello\n");
|
||||
return false;
|
||||
};
|
||||
manager_handle = h; // the tick's hot-plug dispatch reports through this
|
||||
const hello = protocol.Hello{ .role = @intFromEnum(protocol.Role.bus), .device_id = controller_id };
|
||||
var reply: [protocol.message_maximum]u8 = undefined;
|
||||
const n = runtime.ipc.call(h, std.mem.asBytes(&hello), &reply) catch {
|
||||
_ = runtime.system.write("/system/drivers/usb-xhci-bus: hello call failed\n");
|
||||
return false;
|
||||
};
|
||||
if (n < protocol.reply_size or std.mem.bytesToValue(protocol.HelloReply, reply[0..protocol.reply_size]).status != 0) {
|
||||
_ = runtime.system.write("/system/drivers/usb-xhci-bus: hello refused\n");
|
||||
return false;
|
||||
}
|
||||
_ = runtime.system.write("/system/drivers/usb-xhci-bus: hello acknowledged\n");
|
||||
// The handshake (role: bus — we enumerate USB ports and report the devices
|
||||
// behind them), inside the manager's hello deadline. Keep the handle: the
|
||||
// tick's hot-plug dispatch reports through it.
|
||||
const handle = runtime.device_manager.hello(.bus, controller_id) orelse return false;
|
||||
manager_handle = handle;
|
||||
|
||||
scanPorts(h);
|
||||
scanPorts(handle);
|
||||
|
||||
// Arm the poll timer that drains interrupt reports from the event ring. It is
|
||||
// re-armed on each tick in onNotification; class drivers subscribe later.
|
||||
|
||||
@@ -23,7 +23,6 @@ const system = runtime.system;
|
||||
const ipc = runtime.ipc;
|
||||
const dp = runtime.display_protocol;
|
||||
const sp = runtime.scanout_protocol;
|
||||
const dm = runtime.device_manager_protocol;
|
||||
const vp = @import("virtio-pci.zig");
|
||||
const vg = @import("virtio-gpu-protocol.zig");
|
||||
|
||||
@@ -400,9 +399,10 @@ fn initialise(endpoint: ipc.Handle) bool {
|
||||
std.log.info("scanout {d}x{d} online", .{ current_width, current_height });
|
||||
|
||||
// Hello the device manager so it counts us as up (and does not stop us at the hello
|
||||
// deadline). A restarted instance re-hellos here and re-announces below — the compositor
|
||||
// re-attaches to the fresh scanout (V6).
|
||||
helloManager();
|
||||
// deadline). Role: device — we claim one PCI function and serve its scanout; we report
|
||||
// no children. A restarted instance re-hellos here and re-announces below — the compositor
|
||||
// re-attaches to the fresh scanout (V6). Best-effort: standalone bring-up has no manager.
|
||||
_ = runtime.device_manager.hello(.device, device_id);
|
||||
|
||||
// Read the monitor's EDID (best-effort, when the device offers it) — the mode list a real
|
||||
// driver derives from it; we log the preferred mode and keep our fixed offered list.
|
||||
@@ -513,31 +513,6 @@ fn presentFull() bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Hello the device manager (role: bus — we own a PCI function, though we report no children):
|
||||
/// the handshake that marks us up so the manager doesn't stop us at the hello deadline, and
|
||||
/// (as a supervised driver) restarts us if we die. Best-effort: without a manager we still run.
|
||||
fn helloManager() void {
|
||||
var tries: u32 = 0;
|
||||
const manager = while (tries < 100) : (tries += 1) {
|
||||
if (ipc.lookup(.device_manager)) |h| break h;
|
||||
system.sleep(20);
|
||||
} else {
|
||||
std.log.info("no device manager to hello", .{});
|
||||
return;
|
||||
};
|
||||
const hello = dm.Hello{ .role = @intFromEnum(dm.Role.bus), .device_id = device_id };
|
||||
var reply: [dm.reply_size]u8 = undefined;
|
||||
const n = ipc.call(manager, std.mem.asBytes(&hello), &reply) catch {
|
||||
std.log.info("hello call failed", .{});
|
||||
return;
|
||||
};
|
||||
if (n < dm.reply_size or std.mem.bytesToValue(dm.HelloReply, reply[0..dm.reply_size]).status != 0) {
|
||||
std.log.info("hello refused", .{});
|
||||
return;
|
||||
}
|
||||
std.log.info("hello acknowledged", .{});
|
||||
}
|
||||
|
||||
/// Announce the scanout to the display service so it upgrades off the GOP framebuffer: hand it
|
||||
/// the shared surface as a capability plus the geometry. Best-effort and non-fatal — without a
|
||||
/// display service (the standalone virtio-gpu bring-up test) the driver is still a valid
|
||||
|
||||
Reference in New Issue
Block a user