Difference between revisions of "RPC Message Format"
(Remove unpaired blockquote tags left by reference cleanup) |
m (Re-sync page from tracked wiki source: fix cross-document links and diagram; refresh status) |
||
| Line 1: | Line 1: | ||
= GSP RPC Message Format Specification = | = GSP RPC Message Format Specification = | ||
< | <blockquote>'''Historical document — superseded.''' This page describes the legacy BAR0 mailbox RPC model: the 64-byte <code>GSPR</code> magic header and the 12-type model below are '''not''' the path the guest driver uses. The live GSP-RM path is a message queue in guest system memory with 4 KB queue elements and a 32-byte RPC header (signature <code>0x43505256</code>, header version <code>0x03000000</code>); functions are a flat enum (<code>SET_GUEST_SYSTEM_INFO</code> 1, <code>FREE</code> 10, <code>GET_GSP_STATIC_INFO</code> 65, <code>GSP_RM_CONTROL</code> 76, <code>GSP_RM_ALLOC</code> 103, ...). Canonical documentation: [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/03-gsp-and-gsp-rm.md <code>../docs/03-architecture/03-gsp-and-gsp-rm.md</code>] and [https://git.vgpu.io/open-iov/blob/master/docs/03-architecture/06-host-module-and-hybrid-model.md <code>../docs/03-architecture/06-host-module-and-hybrid-model.md</code>].</blockquote> | ||
== Overview == | == Overview == | ||
| Line 10: | Line 10: | ||
* '''Secondary''' (0x04ED39DC): Branch-based dispatch for all 11 types | * '''Secondary''' (0x04ED39DC): Branch-based dispatch for all 11 types | ||
== Primary Dispatcher Call Convention == | == Primary Dispatcher Call Convention == | ||
=== Entry Point === | === Entry Point === | ||
| Line 26: | Line 24: | ||
uint8_t *out_c // param_8: Echoes flags_c | uint8_t *out_c // param_8: Echoes flags_c | ||
) -> int64_t</pre> | ) -> int64_t</pre> | ||
=== RPC Type to Sub-Command Mapping === | === RPC Type to Sub-Command Mapping === | ||
The primary dispatcher validates RPC type, then indexes into the 32-entry jump table at '''0x057A3AD8'''. | The primary dispatcher validates RPC type, then indexes into the 32-entry jump table at '''0x057A3AD8'''. | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
| Line 45: | Line 44: | ||
| FREE | | FREE | ||
| 0-31 | | 0-31 | ||
| | | | ||
|- | |- | ||
| 0x03 | | 0x03 | ||
| Line 98: | Line 97: | ||
|} | |} | ||
=== Sub-Command Descriptor (Returned by Jump Table Handlers) === | === Sub-Command Descriptor (Returned by Jump Table Handlers) === | ||
Each sub-command handler at the jump table returns: | Each sub-command handler at the jump table returns: | ||
< | <pre>typedef struct { | ||
uint32_t subcmd_id; // Constant ID (e.g., 0x10, 0x14, 0x40) | uint32_t subcmd_id; // Constant ID (e.g., 0x10, 0x14, 0x40) | ||
uint8_t echo_flags_b; // Copy of input flags_b | uint8_t echo_flags_b; // Copy of input flags_b | ||
uint8_t echo_flags_a; // Copy of input flags_a | uint8_t echo_flags_a; // Copy of input flags_a | ||
uint8_t echo_flags_c; // Copy of input flags_c | uint8_t echo_flags_c; // Copy of input flags_c | ||
} __attribute__((packed)) subcmd_descriptor_t;</ | } __attribute__((packed)) subcmd_descriptor_t;</pre> | ||
'''Example: Subcmd 3 (0x057A1BCC)''' | '''Example: Subcmd 3 (0x057A1BCC)''' | ||
< | <pre>// Returns ID = 0x10 | ||
*out_subcmd_id = 0x10; | *out_subcmd_id = 0x10; | ||
*out_a = flags_b; | *out_a = flags_b; | ||
*out_b = flags_a; | *out_b = flags_a; | ||
*out_c = flags_c; | *out_c = flags_c; | ||
return 0;</ | return 0;</pre> | ||
'''Example: Subcmd 0 (0x057A1DB4)''' | '''Example: Subcmd 0 (0x057A1DB4)''' | ||
< | <pre>// Returns ID = 0x40 | ||
*out_subcmd_id = 0x40; | *out_subcmd_id = 0x40; | ||
*out_a = flags_b; | *out_a = flags_b; | ||
*out_b = flags_a; | *out_b = flags_a; | ||
*out_c = flags_c; | *out_c = flags_c; | ||
return 0;</ | return 0;</pre> | ||
== Secondary Dispatcher Call Convention == | == Secondary Dispatcher Call Convention == | ||
=== Entry Point === | === Entry Point === | ||
<pre>FUN_ram_04ed39dc(rpc_message_t *msg) -> int64_t</pre> | <pre>FUN_ram_04ed39dc(rpc_message_t *msg) -> int64_t</pre> | ||
=== Message Structure (Inferred) === | === Message Structure (Inferred) === | ||
< | <pre>typedef struct { | ||
uint32_t rpc_type; // 0x01-0x0B | uint32_t rpc_type; // 0x01-0x0B | ||
uint32_t sub_type; // Sub-operation code | uint32_t sub_type; // Sub-operation code | ||
| Line 144: | Line 143: | ||
uint32_t sequence; // Sequence number | uint32_t sequence; // Sequence number | ||
uint32_t reserved; | uint32_t reserved; | ||
} __attribute__((packed)) rpc_message_t;</ | } __attribute__((packed)) rpc_message_t;</pre> | ||
=== Branch-Based Dispatch === | === Branch-Based Dispatch === | ||
Secondary dispatcher uses <code>bgeu</code>/<code>bltu</code> branches on <code>rpc_type</code> register: | Secondary dispatcher uses <code>bgeu</code>/<code>bltu</code> branches on <code>rpc_type</code> register: | ||
<pre | <pre># Pseudocode | ||
if (rpc_type >= 0x0C) goto error; | if (rpc_type >= 0x0C) goto error; | ||
switch(rpc_type): | switch(rpc_type): | ||
| Line 161: | Line 160: | ||
case 0x09: call NOTIFY_handler_A; | case 0x09: call NOTIFY_handler_A; | ||
case 0x0A: call BAR_TRAP_handler (0x057675B7);</pre> | case 0x0A: call BAR_TRAP_handler (0x057675B7);</pre> | ||
== RPC-Specific Payloads == | == RPC-Specific Payloads == | ||
=== ALLOC (0x01) - Via 0x057E94EC === | === ALLOC (0x01) - Via 0x057E94EC === | ||
< | <pre>typedef struct { | ||
uint64_t size; // Allocation size in bytes | uint64_t size; // Allocation size in bytes | ||
uint32_t type; // Memory type (VRAM, sysmem, etc.) | uint32_t type; // Memory type (VRAM, sysmem, etc.) | ||
| Line 179: | Line 177: | ||
uint64_t *out_va; // Output: mapped virtual address | uint64_t *out_va; // Output: mapped virtual address | ||
uint64_t *out_pa; // Output: physical address | uint64_t *out_pa; // Output: physical address | ||
} alloc_payload_t;</ | } alloc_payload_t;</pre> | ||
=== MAP (0x03) - Handlers 0x05766AB7 / 0x05778A37 === | === MAP (0x03) - Handlers 0x05766AB7 / 0x05778A37 === | ||
< | <pre>typedef struct { | ||
uint64_t handle; // Allocation handle from ALLOC | uint64_t handle; // Allocation handle from ALLOC | ||
uint64_t va; // Target virtual address | uint64_t va; // Target virtual address | ||
| Line 191: | Line 189: | ||
uint32_t vf_id; // Target VF | uint32_t vf_id; // Target VF | ||
uint32_t reserved; | uint32_t reserved; | ||
} map_payload_t;</ | } map_payload_t;</pre> | ||
=== PIN (0x05) - Handler 0x04ED34B8 === | === PIN (0x05) - Handler 0x04ED34B8 === | ||
< | <pre>typedef struct { | ||
uint64_t handle; // Allocation handle | uint64_t handle; // Allocation handle | ||
uint64_t offset; // Offset within allocation | uint64_t offset; // Offset within allocation | ||
| Line 202: | Line 200: | ||
uint32_t flags; // PIN_WRITE, PIN_READ, PIN_LONGTERM | uint32_t flags; // PIN_WRITE, PIN_READ, PIN_LONGTERM | ||
uint64_t *out_dma_addr; // Output: DMA address for device | uint64_t *out_dma_addr; // Output: DMA address for device | ||
} pin_payload_t;</ | } pin_payload_t;</pre> | ||
=== SCHEDULE (0x07) - Via 0x051EFBF4 / 0x05767F37 === | === SCHEDULE (0x07) - Via 0x051EFBF4 / 0x05767F37 === | ||
< | <pre>typedef struct { | ||
uint32_t vf_id; // VF to schedule | uint32_t vf_id; // VF to schedule | ||
uint32_t priority; // Scheduling priority | uint32_t priority; // Scheduling priority | ||
| Line 212: | Line 210: | ||
uint32_t flags; // PREEMPTIBLE, REALTIME, etc. | uint32_t flags; // PREEMPTIBLE, REALTIME, etc. | ||
uint32_t reserved; | uint32_t reserved; | ||
} schedule_payload_t;</ | } schedule_payload_t;</pre> | ||
=== BAR_TRAP (0x0A) - Handler 0x04CB8188 === | === BAR_TRAP (0x0A) - Handler 0x04CB8188 === | ||
< | <pre>typedef struct { | ||
uint32_t bar_index; // BAR number (0-5) | uint32_t bar_index; // BAR number (0-5) | ||
uint32_t trap_type; // READ, WRITE, ATOMIC | uint32_t trap_type; // READ, WRITE, ATOMIC | ||
| Line 224: | Line 222: | ||
uint32_t vf_id; // Trapping VF | uint32_t vf_id; // Trapping VF | ||
uint64_t *out_value; // Output: read value | uint64_t *out_value; // Output: read value | ||
} bar_trap_payload_t;</ | } bar_trap_payload_t;</pre> | ||
=== MIGRATE (0x0B) - Dual Jump Tables === | === MIGRATE (0x0B) - Dual Jump Tables === | ||
< | <pre>typedef struct { | ||
uint32_t phase; // 0=prepare, 1=transfer, 2=commit, 3=cleanup | uint32_t phase; // 0=prepare, 1=transfer, 2=commit, 3=cleanup | ||
uint32_t subcmd; // Sub-command index (0-15 for each table) | uint32_t subcmd; // Sub-command index (0-15 for each table) | ||
| Line 237: | Line 235: | ||
uint32_t flags; // LIVE, POSTCOPY, etc. | uint32_t flags; // LIVE, POSTCOPY, etc. | ||
uint32_t reserved; | uint32_t reserved; | ||
} migrate_payload_t;</ | } migrate_payload_t;</pre> | ||
== Wire Format (Host → GSP) == | == Wire Format (Host → GSP) == | ||
'''Legacy BAR0 mailbox format — not used by the guest driver.''' The current msgq header/element facts are in the note at the top of this page. | <blockquote>'''Legacy BAR0 mailbox format — not used by the guest driver.''' The current msgq header/element facts are in the note at the top of this page.</blockquote> | ||
=== Message Header (64 bytes) === | === Message Header (64 bytes) === | ||
< | <pre>typedef struct { | ||
uint32_t magic; // 0x47535052 ("GSPR") | uint32_t magic; // 0x47535052 ("GSPR") | ||
uint32_t version; // Protocol version (1) | uint32_t version; // Protocol version (1) | ||
| Line 256: | Line 253: | ||
uint64_t correlation_id;// For async matching | uint64_t correlation_id;// For async matching | ||
uint64_t reserved[3]; // Padding to 64 bytes | uint64_t reserved[3]; // Padding to 64 bytes | ||
} __attribute__((packed)) rpc_header_t;</ | } __attribute__((packed)) rpc_header_t;</pre> | ||
=== Complete Message === | === Complete Message === | ||
| Line 267: | Line 264: | ||
| padding to 256B | (alignment) | | padding to 256B | (alignment) | ||
+------------------+</pre> | +------------------+</pre> | ||
== Response Format == | == Response Format == | ||
=== Synchronous Response === | === Synchronous Response === | ||
< | <pre>typedef struct { | ||
int64_t status; // 0 = success, negative = error | int64_t status; // 0 = success, negative = error | ||
uint32_t rpc_type; // Echo of request | uint32_t rpc_type; // Echo of request | ||
| Line 280: | Line 276: | ||
uint32_t payload_size; // Response payload size | uint32_t payload_size; // Response payload size | ||
uint32_t reserved; | uint32_t reserved; | ||
} __attribute__((packed)) rpc_response_header_t;</ | } __attribute__((packed)) rpc_response_header_t;</pre> | ||
=== Error Codes === | === Error Codes === | ||
| Line 359: | Line 355: | ||
|} | |} | ||
== Kernel Client Implementation == | == Kernel Client Implementation == | ||
=== Message Builder === | === Message Builder === | ||
< | <pre>static int gsp_rpc_send(gsp_client_t *client, uint32_t rpc_type, | ||
void *payload, size_t payload_size, | void *payload, size_t payload_size, | ||
void *response, size_t *response_size) { | void *response, size_t *response_size) { | ||
rpc_header_t hdr = {.magic = 0x47535052,.version = 1,.rpc_type = rpc_type,.sequence = atomic_inc(&client- | rpc_header_t hdr = { | ||
.magic = 0x47535052, | |||
.version = 1, | |||
.rpc_type = rpc_type, | |||
.sequence = atomic_inc(&client->seq), | |||
.timestamp_ns = ktime_get_ns(), | |||
.payload_size = payload_size, | |||
.flags = MSG_SYNC, | |||
}; | }; | ||
// Build complete message | // Build complete message | ||
uint8_t msg[256]; | uint8_t msg[256]; | ||
memcpy(msg, &hdr, sizeof(hdr)); | memcpy(msg, &hdr, sizeof(hdr)); | ||
memcpy(msg + 64, payload, payload_size); | memcpy(msg + 64, payload, payload_size); | ||
// Submit to GSP doorbell | // Submit to GSP doorbell | ||
return gsp_doorbell_ring(client- | return gsp_doorbell_ring(client->gsp, msg, sizeof(msg)); | ||
}</ | }</pre> | ||
=== Doorbell Mechanism === | === Doorbell Mechanism === | ||
< | <pre>// GSP doorbell register (PCIe BAR0 + offset) | ||
#define GSP_DOORBELL_OFFSET 0x1000 | #define GSP_DOORBELL_OFFSET 0x1000 | ||
| Line 388: | Line 389: | ||
// Copy message to shared memory ring | // Copy message to shared memory ring | ||
// Ring GSP doorbell | // Ring GSP doorbell | ||
writel(1, gsp- | writel(1, gsp->bar0 + GSP_DOORBELL_OFFSET); | ||
}</ | }</pre> | ||
== Async Completion == | == Async Completion == | ||
=== Notification Mechanism === | === Notification Mechanism === | ||
< | <pre>typedef struct { | ||
uint32_t rpc_type; | uint32_t rpc_type; | ||
uint32_t sequence; | uint32_t sequence; | ||
| Line 405: | Line 405: | ||
} async_completion_t; | } async_completion_t; | ||
// Delivered via MSI-X or GSP notification queue</ | // Delivered via MSI-X or GSP notification queue</pre> | ||
---- | |||
== Reference == | == Reference == | ||
Revision as of 04:10, 12 October 2026
GSP RPC Message Format Specification
Historical document — superseded. This page describes the legacy BAR0 mailbox RPC model: the 64-byte
GSPRmagic header and the 12-type model below are not the path the guest driver uses. The live GSP-RM path is a message queue in guest system memory with 4 KB queue elements and a 32-byte RPC header (signature0x43505256, header version0x03000000); functions are a flat enum (SET_GUEST_SYSTEM_INFO1,FREE10,GET_GSP_STATIC_INFO65,GSP_RM_CONTROL76,GSP_RM_ALLOC103, ...). Canonical documentation:../docs/03-architecture/03-gsp-and-gsp-rm.mdand../docs/03-architecture/06-host-module-and-hybrid-model.md.
Overview
The GSP firmware uses a dispatcher-based RPC system with two dispatchers:
- Primary (0x057A1AC0): ALLOC, FREE, MAP, UNMAP, PIN, UNPIN, SCHEDULE, YIELD, NOTIFY, BAR_TRAP, MIGRATE, DEBUG
- Secondary (0x04ED39DC): Branch-based dispatch for all 11 types
Primary Dispatcher Call Convention
Entry Point
FUN_ram_057a1ac0(
uint32_t rpc_type, // param_1: RPC type (0x01-0x0C)
uint8_t flags_a, // param_2
uint8_t flags_b, // param_3
uint8_t flags_c, // param_4
uint32_t *out_subcmd_id,// param_5: Returns sub-command ID
uint8_t *out_a, // param_6: Echoes flags_b
uint8_t *out_b, // param_7: Echoes flags_a
uint8_t *out_c // param_8: Echoes flags_c
) -> int64_t
RPC Type to Sub-Command Mapping
The primary dispatcher validates RPC type, then indexes into the 32-entry jump table at 0x057A3AD8.
| RPC Type | Name | Subcmd Range | Notes |
|---|---|---|---|
| 0x01 | ALLOC | 0-31 | Uses 0x057E94EC main |
| 0x02 | FREE | 0-31 | |
| 0x03 | MAP | — | Uses secondary dispatcher |
| 0x04 | UNMAP | 0-31 | Primary + secondary |
| 0x05 | PIN | — | Uses secondary dispatcher |
| 0x06 | UNPIN | — | Uses secondary dispatcher |
| 0x07 | SCHEDULE | 0-31 | Uses 0x051EFBF4 main |
| 0x08 | YIELD | — | Uses secondary dispatcher |
| 0x09 | NOTIFY | — | Uses secondary dispatcher |
| 0x0A | BAR_TRAP | — | Uses 0x04CB8188 |
| 0x0B | MIGRATE | 0-15 x2 | Dual jump tables |
| 0x0C | DEBUG | — | Unimplemented |
Sub-Command Descriptor (Returned by Jump Table Handlers)
Each sub-command handler at the jump table returns:
typedef struct {
uint32_t subcmd_id; // Constant ID (e.g., 0x10, 0x14, 0x40)
uint8_t echo_flags_b; // Copy of input flags_b
uint8_t echo_flags_a; // Copy of input flags_a
uint8_t echo_flags_c; // Copy of input flags_c
} __attribute__((packed)) subcmd_descriptor_t;
Example: Subcmd 3 (0x057A1BCC)
// Returns ID = 0x10 *out_subcmd_id = 0x10; *out_a = flags_b; *out_b = flags_a; *out_c = flags_c; return 0;
Example: Subcmd 0 (0x057A1DB4)
// Returns ID = 0x40 *out_subcmd_id = 0x40; *out_a = flags_b; *out_b = flags_a; *out_c = flags_c; return 0;
Secondary Dispatcher Call Convention
Entry Point
FUN_ram_04ed39dc(rpc_message_t *msg) -> int64_t
Message Structure (Inferred)
typedef struct {
uint32_t rpc_type; // 0x01-0x0B
uint32_t sub_type; // Sub-operation code
uint64_t payload_ptr; // Pointer to RPC-specific payload
uint32_t payload_size; // Size of payload
uint32_t flags; // Control flags
uint64_t context; // Opaque context
uint32_t sequence; // Sequence number
uint32_t reserved;
} __attribute__((packed)) rpc_message_t;
Branch-Based Dispatch
Secondary dispatcher uses bgeu/bltu branches on rpc_type register:
# Pseudocode if (rpc_type >= 0x0C) goto error; switch(rpc_type): case 0x03: call MAP_handler_A; case 0x04: call UNMAP_handler_A; case 0x05: call PIN_handler_A (0x04ED34B8); case 0x06: call UNPIN_handler_A; case 0x07: call SCHEDULE_handler_A; case 0x08: call YIELD_handler_A; case 0x09: call NOTIFY_handler_A; case 0x0A: call BAR_TRAP_handler (0x057675B7);
RPC-Specific Payloads
ALLOC (0x01) - Via 0x057E94EC
typedef struct {
uint64_t size; // Allocation size in bytes
uint32_t type; // Memory type (VRAM, sysmem, etc.)
uint32_t alignment; // Alignment requirement
uint64_t va_hint; // Virtual address hint
uint32_t flags; // CACHE_COHERENT, UNCACHED, etc.
uint32_t pid; // Process ID
uint32_t vf_id; // VF ID (for vGPU)
uint32_t reserved;
uint64_t *out_handle; // Output: allocation handle
uint64_t *out_va; // Output: mapped virtual address
uint64_t *out_pa; // Output: physical address
} alloc_payload_t;
MAP (0x03) - Handlers 0x05766AB7 / 0x05778A37
typedef struct {
uint64_t handle; // Allocation handle from ALLOC
uint64_t va; // Target virtual address
uint64_t size; // Map size
uint32_t prot; // PROT_READ|PROT_WRITE|PROT_EXEC
uint32_t flags; // MAP_FIXED, MAP_SHARED, etc.
uint32_t vf_id; // Target VF
uint32_t reserved;
} map_payload_t;
PIN (0x05) - Handler 0x04ED34B8
typedef struct {
uint64_t handle; // Allocation handle
uint64_t offset; // Offset within allocation
uint64_t size; // Size to pin
uint32_t vf_id; // Target VF
uint32_t flags; // PIN_WRITE, PIN_READ, PIN_LONGTERM
uint64_t *out_dma_addr; // Output: DMA address for device
} pin_payload_t;
SCHEDULE (0x07) - Via 0x051EFBF4 / 0x05767F37
typedef struct {
uint32_t vf_id; // VF to schedule
uint32_t priority; // Scheduling priority
uint64_t time_slice_ns; // Time slice in nanoseconds
uint32_t flags; // PREEMPTIBLE, REALTIME, etc.
uint32_t reserved;
} schedule_payload_t;
BAR_TRAP (0x0A) - Handler 0x04CB8188
typedef struct {
uint32_t bar_index; // BAR number (0-5)
uint32_t trap_type; // READ, WRITE, ATOMIC
uint64_t offset; // Offset within BAR
uint64_t value; // Value for writes
uint32_t size; // Access size (1,2,4,8)
uint32_t vf_id; // Trapping VF
uint64_t *out_value; // Output: read value
} bar_trap_payload_t;
MIGRATE (0x0B) - Dual Jump Tables
typedef struct {
uint32_t phase; // 0=prepare, 1=transfer, 2=commit, 3=cleanup
uint32_t subcmd; // Sub-command index (0-15 for each table)
uint64_t src_vf; // Source VF
uint64_t dst_vf; // Destination VF
uint64_t data_ptr; // Migration data buffer
uint64_t data_size; // Buffer size
uint32_t flags; // LIVE, POSTCOPY, etc.
uint32_t reserved;
} migrate_payload_t;
Wire Format (Host → GSP)
Legacy BAR0 mailbox format — not used by the guest driver. The current msgq header/element facts are in the note at the top of this page.
Message Header (64 bytes)
typedef struct {
uint32_t magic; // 0x47535052 ("GSPR")
uint32_t version; // Protocol version (1)
uint32_t rpc_type; // 0x01-0x0C
uint32_t sequence; // Monotonic sequence
uint64_t timestamp_ns; // Submission timestamp
uint32_t payload_size; // Size of payload
uint32_t flags; // MSG_SYNC, MSG_ASYNC, MSG_NOREPLY
uint64_t correlation_id;// For async matching
uint64_t reserved[3]; // Padding to 64 bytes
} __attribute__((packed)) rpc_header_t;
Complete Message
+------------------+ | rpc_header_t | 64 bytes +------------------+ | payload (varies) | payload_size bytes +------------------+ | padding to 256B | (alignment) +------------------+
Response Format
Synchronous Response
typedef struct {
int64_t status; // 0 = success, negative = error
uint32_t rpc_type; // Echo of request
uint32_t sequence; // Echo of request
uint64_t timestamp_ns; // Completion timestamp
uint32_t payload_size; // Response payload size
uint32_t reserved;
} __attribute__((packed)) rpc_response_header_t;
Error Codes
| Code | Name | Description |
|---|---|---|
| 0 | OK | Success |
| -1 (0xFFFF) | EPERM | Permission denied |
| -2 (0xFFFE) | ENOENT | Not found |
| -3 (0xFFFD) | EINVAL | Invalid argument |
| -6 (0xFFFA) | ENODEV | No such device |
| -12 (0xFFF4) | ENOMEM | Out of memory |
| -16 (0xFFEE) | EBUSY | Resource busy |
| -22 (0xFFEA) | EINVAL | Invalid argument |
| -28 (0xFFE4) | ENOSPC | No space left |
| -37 (0xFFDB) | ENOLCK | No locks available |
| -56 (0xFFC8) | EBADMSG | Bad message |
| -84 (0xFFAC) | EOVERFLOW | Value too large |
| -90 (0xFFA6) | ENOSTR | Not a stream |
| -91 (0xFFA5) | ENODATA | No data available |
| -94 (0xFFA2) | ENOSR | Out of streams resources |
| -97 (0xFF9F) | EPROTO | Protocol error |
| -111 (0xFF91) | ETIMEDOUT | Connection timed out |
Kernel Client Implementation
Message Builder
static int gsp_rpc_send(gsp_client_t *client, uint32_t rpc_type,
void *payload, size_t payload_size,
void *response, size_t *response_size) {
rpc_header_t hdr = {
.magic = 0x47535052,
.version = 1,
.rpc_type = rpc_type,
.sequence = atomic_inc(&client->seq),
.timestamp_ns = ktime_get_ns(),
.payload_size = payload_size,
.flags = MSG_SYNC,
};
// Build complete message
uint8_t msg[256];
memcpy(msg, &hdr, sizeof(hdr));
memcpy(msg + 64, payload, payload_size);
// Submit to GSP doorbell
return gsp_doorbell_ring(client->gsp, msg, sizeof(msg));
}
Doorbell Mechanism
// GSP doorbell register (PCIe BAR0 + offset)
#define GSP_DOORBELL_OFFSET 0x1000
static void gsp_doorbell_ring(gsp_device_t *gsp, void *msg, size_t len) {
// Copy message to shared memory ring
// Ring GSP doorbell
writel(1, gsp->bar0 + GSP_DOORBELL_OFFSET);
}
Async Completion
Notification Mechanism
typedef struct {
uint32_t rpc_type;
uint32_t sequence;
int64_t status;
uint64_t timestamp_ns;
uint32_t payload_size;
uint32_t reserved;
} async_completion_t;
// Delivered via MSI-X or GSP notification queue
Reference
- Primary Dispatcher: 0x057A1AC0
- Secondary Dispatcher: 0x04ED39DC
- Jump Table: 0x057A3AD8 (32 entries)
- RPC Type Jump Table: 0x059BFEB0 (12 types)