/* SPDX-License-Identifier: GPL-2.0-only */ /* * GSP vGPU-IO Driver - BAR Emulation */ #include "gsp_core.h" #include #include /* BAR Emulation Ops */ static int gsp_bar_trap_handler(struct gsp_vf *vf, struct gsp_bar_trap_payload *trap) { struct gsp_bar_state *bar = &vf->bar_state; struct gsp_bar_trap_response resp = {0}; size_t resp_size = sizeof(resp); int ret; /* Validate BAR index (we only support BAR1) */ if (trap->bar_index != 1) return -EINVAL; /* Validate offset */ if (trap->offset >= bar->aperture_size) return -ERANGE; /* Check ForceBarAccess */ if (bar->force_access && vf->id != bar->force_vf) return -EPERM; /* In emulation mode, handle locally */ if (emulation_mode) { /* Simulate BAR trap handling */ if (trap->trap_type == GSP_BAR_WRITE) { /* Config write - update aperture */ bar->aperture_offset = trap->offset; bar->aperture_size = trap->value; } else if (trap->trap_type == GSP_BAR_ATOMIC) { /* Force access control */ bar->force_access = trap->offset ? true : false; bar->force_vf = trap->offset ? vf->id : 0; } resp.value = 0; return 0; } /* Forward to GSP BAR trap handler (0x04CB8188) */ ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_BAR_TRAP, trap, sizeof(*trap), &resp, &resp_size); return ret; } /* Aperture Configuration */ static int gsp_bar_config_aperture(struct gsp_vf *vf, uint64_t offset, uint64_t size) { struct gsp_bar_state *bar = &vf->bar_state; struct gsp_bar_trap_payload payload = {0}; struct gsp_bar_trap_response resp = {0}; size_t resp_size = sizeof(resp); int ret; /* Validate alignment (4KB) */ if (offset & 0xFFF || size & 0xFFF) return -EINVAL; /* Validate max size (256KB per firmware) */ if (size > 0x40000) return -EINVAL; /* In emulation mode, handle locally */ if (emulation_mode) { bar->aperture_offset = offset; bar->aperture_size = size; return 0; } payload.bar_index = 1; payload.trap_type = GSP_BAR_WRITE; /* Config write */ payload.offset = offset; payload.value = size; payload.size = 8; payload.vf_id = vf->id; ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_BAR_TRAP, &payload, sizeof(payload), &resp, &resp_size); if (!ret) { bar->aperture_offset = offset; bar->aperture_size = size; } return ret; } /* ForceBarAccess Control */ int gsp_bar_force_access(struct gsp_vf *vf, bool enable) { struct gsp_bar_state *bar = &vf->bar_state; struct gsp_bar_trap_payload payload = {0}; struct gsp_bar_trap_response resp = {0}; size_t resp_size = sizeof(resp); int ret; /* In emulation mode, handle locally */ if (emulation_mode) { bar->force_access = enable; bar->force_vf = enable ? vf->id : 0; return 0; } payload.bar_index = 1; payload.trap_type = GSP_BAR_ATOMIC; /* Force access control */ payload.offset = enable ? 1 : 0; payload.value = enable ? vf->id : 0; payload.size = 8; payload.vf_id = vf->id; ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_BAR_TRAP, &payload, sizeof(payload), &resp, &resp_size); if (!ret) { bar->force_access = enable; bar->force_vf = enable ? vf->id : 0; } return ret; } /* State Save for Migration */ static int gsp_bar_save_state(struct gsp_vf *vf, void *buf, size_t *size) { struct gsp_bar_state *bar = &vf->bar_state; size_t needed = sizeof(*bar) + bar->backing_size; if (!buf || *size < needed) return -ENOSPC; memcpy(buf, bar, sizeof(*bar)); if (bar->backing_store && bar->backing_size > 0) memcpy(buf + sizeof(*bar), bar->backing_store, bar->backing_size); *size = needed; return 0; } /* State Restore for Migration */ static int gsp_bar_restore_state(struct gsp_vf *vf, void *buf, size_t size) { struct gsp_bar_state *bar = &vf->bar_state; size_t min_size = sizeof(*bar); if (!buf || size < min_size) return -EINVAL; memcpy(bar, buf, sizeof(*bar)); if (size > min_size && bar->backing_size > 0) { if (!bar->backing_store) { bar->backing_store = vzalloc(bar->backing_size); if (!bar->backing_store) return -ENOMEM; } memcpy(bar->backing_store, buf + min_size, min(size - min_size, bar->backing_size)); } /* Reconfigure BAR in GSP */ return gsp_bar_config_aperture(vf, bar->aperture_offset, bar->aperture_size); } /* VF BAR Initialization */ int gsp_vf_bar_init(struct gsp_vf *vf) { struct gsp_bar_state *bar = &vf->bar_state; int ret; /* Initialize with config values */ bar->aperture_offset = vf->bar1_offset; bar->aperture_size = vf->bar1_size; bar->force_access = false; bar->force_vf = 0; bar->backing_store = NULL; bar->backing_size = 0; /* Allocate backing store (max 256KB) */ if (bar->aperture_size > 0) { bar->backing_size = min(bar->aperture_size, (uint64_t)0x40000); bar->backing_store = vzalloc(bar->backing_size); if (!bar->backing_store) return -ENOMEM; } /* Configure aperture in GSP (skip in emulation mode) */ if (!emulation_mode) { ret = gsp_bar_config_aperture(vf, bar->aperture_offset, bar->aperture_size); if (ret) { dev_err(vf->gsp->dev, "VF %u: BAR aperture config failed: %d\n", vf->id, ret); goto err_backing; } } else { dev_info(vf->gsp->dev, "VF %u: BAR1 initialized in emulation mode [0x%llx, 0x%llx)\n", vf->id, bar->aperture_offset, bar->aperture_offset + bar->aperture_size); } dev_info(vf->gsp->dev, "VF %u: BAR1 initialized [0x%llx, 0x%llx)\n", vf->id, bar->aperture_offset, bar->aperture_offset + bar->aperture_size); return 0; err_backing: vfree(bar->backing_store); bar->backing_store = NULL; bar->backing_size = 0; return ret; } /* VF BAR Cleanup */ void gsp_vf_bar_fini(struct gsp_vf *vf) { struct gsp_bar_state *bar = &vf->bar_state; vfree(bar->backing_store); bar->backing_store = NULL; bar->backing_size = 0; dev_info(vf->gsp->dev, "VF %u: BAR1 cleaned up\n", vf->id); } /* BAR Trap Entry Point (called from ISR/notification) */ int gsp_vf_bar_trap(struct gsp_vf *vf, struct gsp_bar_trap_payload *trap) { return gsp_bar_trap_handler(vf, trap); } /* Migration Interface */ int gsp_migration_bar_save(struct gsp_vf *vf, void *buf, size_t *size) { return gsp_bar_save_state(vf, buf, size); } int gsp_migration_bar_restore(struct gsp_vf *vf, void *buf, size_t size) { return gsp_bar_restore_state(vf, buf, size); }