From 14283fe73fb5e432a7af45de94961655714910f6 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Tue, 22 Sep 2026 23:32:44 -0400 Subject: kernel: FB/BUS info-list controls + PCIe link caps for the UVM path CUDA (cuInit) now reaches UVM's device create: libcuda opens nvidia-uvm, UVM calls nvGpuOpsDeviceCreate/gpuGetGpuInfo, and the driver fails at getPCIELinkRateMBps -> calculatePCIELinkRateMBps ("Unknown PCIe speed", NV_ERR_INVALID_STATE) -> nv_open_device aborts -> cuInit returns CUDA_ERROR_NOT_INITIALIZED (3). Implemented along the way: - FB_GET_INFO_V2 (0x20801303): echo the requested FB info indices and answer TU104 values (256MB RAM/heap/BAR1, GDDR6, 8 LTCs, 4MB L2, ...). Fixes the kern_mem_sys_ctrl.c:911 asserts and gives CUDA/UVM real memory sizes. - BUS_GET_INFO_V2 (0x20801823): echo indices; PCIe Gen3 x16 link caps / GEN info / link status, SYSMEM_CONNECTION_TYPE=PCIE. UVM's gpuGetSysmemLinkInfo reads SYSMEM_CONNECTION_TYPE and the nominal link bandwidth from here. - PCIe Link Capabilities in the emulated config space (0x8C/0x92) and in the BAR0 PCFG mirror (gpuReadBusConfigReg -> NV_PCFG+0x84 = BAR0+ 0x88084): MAX_SPEED=3 (8GT/s Gen3), MAX_WIDTH=0x10 (x16); link status mirror at 0x88088. Also mirrored under the VF-window/low aliases. - Temporary change-watch on PCFG[0x88084] to see if the guest overwrites it (it does not - stays 0x103). Verified: guest nvidia-smi -L still works and reports PCIe Generation Max/Current = 3. cuInit still fails; the remaining question is which address the driver's kbifGetGpuLinkCapabilities read sees as zero (the PCFG shadow holds 0x103). Guest-side kprobe tracing of that function panicked the VM (free_swap_cache page fault on a corrupted pointer) - possible guest memory corruption to investigate separately. --- kernel/bar_emulation.c | 30 +++++++ kernel/gsp_emulation.c | 12 +++ kernel/gsp_rm_emulation.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++ kernel/gsp_rm_tu104.h | 99 +++++++++++++++++++++++ kernel/main.c | 8 +- 5 files changed, 346 insertions(+), 4 deletions(-) (limited to 'kernel') diff --git a/kernel/bar_emulation.c b/kernel/bar_emulation.c index eaa006c..3448b8c 100644 --- a/kernel/bar_emulation.c +++ b/kernel/bar_emulation.c @@ -279,6 +279,36 @@ int nv_vgpu_bar_emul_init(struct nv_vgpu_device *vgpu) */ *(u32 *)((u8 *)ctx->bar0_shadow + 0x100ce0) = 0x00000018; + /* + * NV_PCFG (BAR0+0x88000) - PCI config space mirror the driver reads + * via gpuReadBusConfigReg_HAL (GPU_BUS_CFG_RD32): + * 0x88084 NV_XVE_LINK_CAPABILITIES: MAX_LINK_SPEED 3:0 = 3 (8 GT/s, + * Gen3), MAX_LINK_WIDTH 9:4 = 0x10 (x16). + * 0x88088 NV_XVE_LINK_CONTROL_STATUS: negotiated speed 19:16 = 3, + * negotiated width 25:20 = 0x10 (x16). + * UVM's nvGpuOpsDeviceCreate -> getPCIELinkRateMBps -> + * kbifControlGetPCIEInfo -> kbifGetGpuLinkCapabilities reads 0x88084; + * zeros make calculatePCIELinkRateMBps log "Unknown PCIe speed" and + * return NV_ERR_INVALID_STATE, which fails cuInit + * (CUDA_ERROR_NOT_INITIALIZED in the guest). + * + * DEVICE_BASE(NV_PCFG) expands to 0 in this driver (nvmisc.h: + * "#define DEVICE_BASE(d) (0?d)"), so the read is actually + * gpuNvAddr + 0x84 - mirror the values at the low alias as well. + */ + *(u32 *)((u8 *)ctx->bar0_shadow + 0x88084) = 0x00000103; + *(u32 *)((u8 *)ctx->bar0_shadow + 0x88088) = 0x01030000; + *(u32 *)((u8 *)ctx->bar0_shadow + 0x00084) = 0x00000103; + *(u32 *)((u8 *)ctx->bar0_shadow + 0x00088) = 0x01030000; + /* Same values under the VF register window aliases, in case this + * driver reaches the config mirror through virtualRegPhysOffset. */ + *(u32 *)((u8 *)ctx->bar0_shadow + 0xB80084) = 0x00000103; + *(u32 *)((u8 *)ctx->bar0_shadow + 0xB80088) = 0x01030000; + *(u32 *)((u8 *)ctx->bar0_shadow + 0xB88084) = 0x00000103; + *(u32 *)((u8 *)ctx->bar0_shadow + 0xB88088) = 0x01030000; + *(u32 *)((u8 *)ctx->bar0_shadow + 0xC08084) = 0x00000103; + *(u32 *)((u8 *)ctx->bar0_shadow + 0xC08088) = 0x01030000; + /* * Serve a valid VBIOS at the PROM window (BAR0+0x300000). * diff --git a/kernel/gsp_emulation.c b/kernel/gsp_emulation.c index 0b6bba0..969d4fd 100644 --- a/kernel/gsp_emulation.c +++ b/kernel/gsp_emulation.c @@ -305,6 +305,18 @@ static void gsp_emu_poll_boot(struct gsp_emu_context *ctx) } } + /* Temporary: watch the PCFG link-caps mirror for guest writes */ + { + static u32 last_linkcap; + u32 v = gsp_emu_shadow_read32(ctx, 0x88084); + + if (v != last_linkcap) { + nv_vgpu_info(ctx->vgpu, "GSP-BOOT: PCFG[0x88084] = 0x%x (was 0x%x)", + v, last_linkcap); + last_linkcap = v; + } + } + /* GSP ENGINE reset asserted -> falcon rebooted, restart stage tracking */ if ((engine & 0x1) && ctx->boot_stage != GSP_BOOT_STAGE_IDLE) { nv_vgpu_info(ctx->vgpu, "GSP-BOOT: falcon reset, back to IDLE"); diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c index f18d17c..743a260 100644 --- a/kernel/gsp_rm_emulation.c +++ b/kernel/gsp_rm_emulation.c @@ -1269,6 +1269,193 @@ static void gsp_rm_handle_kgr_get_context_buffers_info( TU104_CTX_GPU_MAX_ENGINES, TU104_CTX_ENGINE_ID_COUNT); } +/* + * FB_GET_INFO_V2 (0x20801303) + * + * The client (kern_mem_sys_ctrl.c _fbGetFbInfos) sends a list of FB info + * indices to the physical RM and expects the same indices back with data + * populated. A zeroed reply trips "pFbInfos[i].index == ..." asserts and + * leaves all FB info zero - CUDA/UVM read total/usable memory, BAR1 size, + * L2/LTC topology from here. Echo the requested indices and fill in the + * emulated TU104 values. + */ +static u32 tu104_fb_info_data(struct gsp_emu_context *ctx, u32 index) +{ + struct nv_vgpu_device *vgpu = ctx->vgpu; + u64 fb = vgpu->fb_size ? vgpu->fb_size : NV_VGPU_BAR1_SIZE; + + switch (index) { + case TU104_FB_INFO_IDX_TILE_REGION_COUNT: + return 0; + case TU104_FB_INFO_IDX_COMPRESSION_SIZE: + return 0; + case TU104_FB_INFO_IDX_PARTITION_COUNT: + return 1; + case TU104_FB_INFO_IDX_BAR1_SIZE: + return (u32)fb; + case TU104_FB_INFO_IDX_RAM_SIZE: + case TU104_FB_INFO_IDX_TOTAL_RAM_SIZE: + case TU104_FB_INFO_IDX_USABLE_RAM_SIZE: + return (u32)fb; + case TU104_FB_INFO_IDX_HEAP_SIZE: + case TU104_FB_INFO_IDX_MAPPABLE_HEAP_SIZE: + return (u32)fb; + case TU104_FB_INFO_IDX_BUS_WIDTH: + return 256; + case TU104_FB_INFO_IDX_RAM_TYPE: + return TU104_RAM_TYPE_GDDR6; + case TU104_FB_INFO_IDX_BANK_COUNT: + return 8; + case TU104_FB_INFO_IDX_FB_TAX_SIZE_KB: + case TU104_FB_INFO_IDX_LARGEST_FREE_REGION_SIZE_KB: + return (u32)(fb >> 10); + case TU104_FB_INFO_IDX_PARTITION_MASK: + return 1; + case TU104_FB_INFO_IDX_HEAP_FREE: + return (u32)fb; + case TU104_FB_INFO_IDX_RAM_LOCATION: + return TU104_RAM_LOCATION_GPU_DEDICATED; + case TU104_FB_INFO_IDX_FBP_COUNT: + return 1; + case TU104_FB_INFO_IDX_FBP_MASK: + return 1; + case TU104_FB_INFO_IDX_L2CACHE_SIZE: + return TU104_L2CACHE_SIZE; + case TU104_FB_INFO_IDX_MEMORYINFO_VENDOR_ID: + return TU104_MEMORYINFO_VENDOR_ID_SAMSUNG; + case TU104_FB_INFO_IDX_BAR1_AVAIL_SIZE: + case TU104_FB_INFO_IDX_BAR1_MAX_CONTIG_AVAIL_SIZE: + return (u32)fb; + case TU104_FB_INFO_IDX_LTC_COUNT: + return TU104_LTC_COUNT; + case TU104_FB_INFO_IDX_LTS_COUNT: + return TU104_LTS_COUNT; + case TU104_FB_INFO_IDX_PSEUDO_CHANNEL_MODE: + return TU104_PSEUDO_CHANNEL_MODE_DISABLED; + case TU104_FB_INFO_IDX_ALLOW_PAGE_RETIREMENT: + return 0; + case TU104_FB_INFO_IDX_LTC_MASK: + return (1U << TU104_LTC_COUNT) - 1; + default: + return 0; + } +} + +static void gsp_rm_handle_fb_get_info_v2(struct gsp_emu_context *ctx, + const u8 *req_params, + u32 req_params_size, + u32 *out_status, + u8 *out_params, + u32 *out_params_size) +{ + struct tu104_fb_get_info_v2_params *reply = + (struct tu104_fb_get_info_v2_params *)out_params; + u32 count = 0; + u32 i; + + if (req_params_size >= sizeof(count)) + memcpy(&count, req_params, sizeof(count)); + if (count > TU104_FB_INFO_MAX_LIST_SIZE) + count = TU104_FB_INFO_MAX_LIST_SIZE; + + memset(out_params, 0, sizeof(*reply)); + reply->fbInfoListSize = count; + + for (i = 0; i < count; i++) { + const u8 *in = req_params + sizeof(count) + + i * sizeof(struct tu104_fb_info_entry); + u32 index = 0; + + if (sizeof(count) + (i + 1) * sizeof(struct tu104_fb_info_entry) <= + req_params_size) + memcpy(&index, in, sizeof(index)); + + reply->fbInfoList[i].index = index; + reply->fbInfoList[i].data = tu104_fb_info_data(ctx, index); + } + + *out_params_size = sizeof(*reply); + *out_status = 0; + + nv_vgpu_info(ctx->vgpu, "GSPRM: FB_GET_INFO_V2 -> %u entries populated (first idx=0x%x)", + count, count ? reply->fbInfoList[0].index : 0); +} + +/* + * BUS_GET_INFO_V2 (0x20801823) + * + * Same flat index/data list pattern as FB_GET_INFO_V2. UVM's + * gpuGetSysmemLinkInfo() asks for SYSMEM_CONNECTION_TYPE and then + * PCIE_GPU_LINK_CAPS to compute the sysmem link bandwidth; a zeroed reply + * makes getPCIELinkRateMBps() return NV_ERR_INVALID_STATE ("Unsupported + * sysmem connection type"). Report a PCIe Gen3 x16 link for the emulated + * vGPU and echo every requested index. + */ +static u32 tu104_bus_info_data(u32 index) +{ + switch (index) { + case TU104_BUS_INFO_IDX_TYPE: + return TU104_BUS_INFO_TYPE_PCI_EXPRESS; + case TU104_BUS_INFO_IDX_INTLINE: + return 0; + case TU104_BUS_INFO_IDX_PCIE_GPU_LINK_CAPS: + case TU104_BUS_INFO_IDX_PCIE_ROOT_LINK_CAPS: + case TU104_BUS_INFO_IDX_PCIE_UPSTREAM_LINK_CAPS: + case TU104_BUS_INFO_IDX_PCIE_DOWNSTREAM_LINK_CAPS: + case TU104_BUS_INFO_IDX_PCIE_GEN_INFO: + return TU104_PCIE_LINK_CAP_GEN3_X16; + case TU104_BUS_INFO_IDX_PCIE_GPU_LINK_CTRL_STATUS: + case TU104_BUS_INFO_IDX_PCIE_ROOT_LINK_CTRL_STATUS: + case TU104_BUS_INFO_IDX_PCIE_UPSTREAM_LINK_CTRL: + case TU104_BUS_INFO_IDX_PCIE_DOWNSTREAM_LINK_CTRL: + return TU104_PCIE_LINK_CTRL_STATUS_GEN3_X16; + case TU104_BUS_INFO_IDX_SYSMEM_CONNECTION_TYPE: + return TU104_BUS_INFO_SYSMEM_CONN_PCIE; + default: + return 0; + } +} + +static void gsp_rm_handle_bus_get_info_v2(struct gsp_emu_context *ctx, + const u8 *req_params, + u32 req_params_size, + u32 *out_status, + u8 *out_params, + u32 *out_params_size) +{ + struct tu104_bus_get_info_v2_params *reply = + (struct tu104_bus_get_info_v2_params *)out_params; + u32 count = 0; + u32 i; + + if (req_params_size >= sizeof(count)) + memcpy(&count, req_params, sizeof(count)); + if (count > TU104_BUS_INFO_MAX_LIST_SIZE) + count = TU104_BUS_INFO_MAX_LIST_SIZE; + + memset(out_params, 0, sizeof(*reply)); + reply->busInfoListSize = count; + + for (i = 0; i < count; i++) { + const u8 *in = req_params + sizeof(count) + + i * sizeof(struct tu104_bus_info_entry); + u32 index = 0; + + if (sizeof(count) + (i + 1) * sizeof(struct tu104_bus_info_entry) <= + req_params_size) + memcpy(&index, in, sizeof(index)); + + reply->busInfoList[i].index = index; + reply->busInfoList[i].data = tu104_bus_info_data(index); + } + + *out_params_size = sizeof(*reply); + *out_status = 0; + + nv_vgpu_info(ctx->vgpu, "GSPRM: BUS_GET_INFO_V2 -> %u entries populated (first idx=0x%x)", + count, count ? reply->busInfoList[0].index : 0); +} + static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx, const u8 *elem, u32 sequence) { @@ -1375,6 +1562,20 @@ static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx, reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size); break; + case TU104_CTRL_FB_GET_INFO_V2: + gsp_rm_handle_fb_get_info_v2(ctx, + req_data + GSP_RM_CTRL_HDR_SIZE, req.paramsSize, + &out_status, + reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size); + break; + + case TU104_CTRL_BUS_GET_INFO_V2: + gsp_rm_handle_bus_get_info_v2(ctx, + req_data + GSP_RM_CTRL_HDR_SIZE, req.paramsSize, + &out_status, + reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size); + break; + case TU104_CTRL_STATIC_KGR_GET_FLOORSWEEPING_MASKS: gsp_rm_handle_kgr_get_floorsweeping_masks(ctx, sequence, &out_status, diff --git a/kernel/gsp_rm_tu104.h b/kernel/gsp_rm_tu104.h index f40c77d..2edeeb4 100644 --- a/kernel/gsp_rm_tu104.h +++ b/kernel/gsp_rm_tu104.h @@ -780,6 +780,105 @@ struct tu104_gr_get_context_buffers_info_params { engineContextBuffersInfo[TU104_CTX_GPU_MAX_ENGINES]; }; +/* FB_GET_INFO_V2 (ctrl2080fb.h): the client sends a list of requested FB info + * indices; the physical RM must echo each index back with its data. + * _fbGetFbInfos() asserts pFbInfos[i].index == returned index, so a zeroed + * reply fires kern_mem_sys_ctrl.c:911 asserts and leaves all FB info zero + * (CUDA/UVMLite read total/usable memory, BAR1 size, ECC/LTC info from here). */ +#define TU104_CTRL_FB_GET_INFO_V2 0x20801303 +#define TU104_FB_INFO_MAX_LIST_SIZE 0x80 + +struct tu104_fb_info_entry { + u32 index; + u32 data; +}; + +struct tu104_fb_get_info_v2_params { + u32 fbInfoListSize; + struct tu104_fb_info_entry fbInfoList[TU104_FB_INFO_MAX_LIST_SIZE]; +}; + +/* NV2080_CTRL_FB_INFO_INDEX_* (subset we populate) */ +#define TU104_FB_INFO_IDX_TILE_REGION_COUNT 0x00 +#define TU104_FB_INFO_IDX_COMPRESSION_SIZE 0x01 +#define TU104_FB_INFO_IDX_PARTITION_COUNT 0x04 +#define TU104_FB_INFO_IDX_BAR1_SIZE 0x05 +#define TU104_FB_INFO_IDX_RAM_SIZE 0x07 +#define TU104_FB_INFO_IDX_TOTAL_RAM_SIZE 0x08 +#define TU104_FB_INFO_IDX_HEAP_SIZE 0x09 +#define TU104_FB_INFO_IDX_MAPPABLE_HEAP_SIZE 0x0a +#define TU104_FB_INFO_IDX_BUS_WIDTH 0x0b +#define TU104_FB_INFO_IDX_RAM_TYPE 0x0d +#define TU104_FB_INFO_IDX_BANK_COUNT 0x0e +#define TU104_FB_INFO_IDX_FB_TAX_SIZE_KB 0x10 +#define TU104_FB_INFO_IDX_LARGEST_FREE_REGION_SIZE_KB 0x12 +#define TU104_FB_INFO_IDX_PARTITION_MASK 0x14 +#define TU104_FB_INFO_IDX_HEAP_FREE 0x16 +#define TU104_FB_INFO_IDX_RAM_LOCATION 0x17 +#define TU104_FB_INFO_IDX_FBP_COUNT 0x19 +#define TU104_FB_INFO_IDX_FBP_MASK 0x1a +#define TU104_FB_INFO_IDX_L2CACHE_SIZE 0x1b +#define TU104_FB_INFO_IDX_MEMORYINFO_VENDOR_ID 0x1c +#define TU104_FB_INFO_IDX_BAR1_AVAIL_SIZE 0x1d +#define TU104_FB_INFO_IDX_BAR1_MAX_CONTIG_AVAIL_SIZE 0x1f +#define TU104_FB_INFO_IDX_USABLE_RAM_SIZE 0x20 +#define TU104_FB_INFO_IDX_LTC_COUNT 0x22 +#define TU104_FB_INFO_IDX_LTS_COUNT 0x23 +#define TU104_FB_INFO_IDX_PSEUDO_CHANNEL_MODE 0x25 +#define TU104_FB_INFO_IDX_ALLOW_PAGE_RETIREMENT 0x2a +#define TU104_FB_INFO_IDX_LTC_MASK 0x2b + +#define TU104_RAM_TYPE_GDDR6 0x11 +#define TU104_RAM_LOCATION_GPU_DEDICATED 0x00 +#define TU104_PSEUDO_CHANNEL_MODE_DISABLED 0x01 +#define TU104_MEMORYINFO_VENDOR_ID_SAMSUNG 0x01 +#define TU104_L2CACHE_SIZE 0x400000 /* TU104: 4MB */ +#define TU104_LTC_COUNT 8 +#define TU104_LTS_COUNT 16 + +/* BUS_GET_INFO_V2 (ctrl2080bus.h) - same flat index/data list pattern as FB. + * UVM's gpuGetSysmemLinkInfo() reads SYSMEM_CONNECTION_TYPE (PCIE) and then + * PCIE_GPU_LINK_CAPS for the link bandwidth; a zeroed reply makes + * getPCIELinkRateMBps() fail with NV_ERR_INVALID_STATE. */ +#define TU104_CTRL_BUS_GET_INFO_V2 0x20801823 +#define TU104_BUS_INFO_MAX_LIST_SIZE 0x34 + +struct tu104_bus_info_entry { + u32 index; + u32 data; +}; + +struct tu104_bus_get_info_v2_params { + u32 busInfoListSize; + struct tu104_bus_info_entry busInfoList[TU104_BUS_INFO_MAX_LIST_SIZE]; +}; + +/* NV2080_CTRL_BUS_INFO_INDEX_* (subset we populate) */ +#define TU104_BUS_INFO_IDX_TYPE 0x00 +#define TU104_BUS_INFO_IDX_INTLINE 0x01 +#define TU104_BUS_INFO_IDX_PCIE_GPU_LINK_CAPS 0x03 +#define TU104_BUS_INFO_IDX_PCIE_ROOT_LINK_CAPS 0x04 +#define TU104_BUS_INFO_IDX_PCIE_UPSTREAM_LINK_CAPS 0x05 +#define TU104_BUS_INFO_IDX_PCIE_DOWNSTREAM_LINK_CAPS 0x06 +#define TU104_BUS_INFO_IDX_PCIE_GPU_LINK_CTRL_STATUS 0x07 +#define TU104_BUS_INFO_IDX_PCIE_ROOT_LINK_CTRL_STATUS 0x08 +#define TU104_BUS_INFO_IDX_PCIE_UPSTREAM_LINK_CTRL 0x09 +#define TU104_BUS_INFO_IDX_PCIE_DOWNSTREAM_LINK_CTRL 0x0a +#define TU104_BUS_INFO_IDX_PCIE_GEN_INFO 0x2d +#define TU104_BUS_INFO_IDX_SYSMEM_CONNECTION_TYPE 0x33 + +#define TU104_BUS_INFO_TYPE_PCI_EXPRESS 0x03 +#define TU104_BUS_INFO_SYSMEM_CONN_PCIE 0x00 +/* PCIE link caps / GEN info layout: MAX_SPEED 3:0 (8000MBPS=3), MAX_WIDTH + * 9:4 (lanes), ASPM 11:10, GEN 15:12, CURR_LEVEL 19:16, GPU_GEN 23:20 + * (all GENx = 2 for Gen3), SPEED_CHANGES 24. */ +#define TU104_PCIE_LINK_CAP_GEN3_X16 (0x3u | (16u << 4) | \ + (2u << 12) | (2u << 16) | \ + (2u << 20)) +/* LINK_CTRL_STATUS: ASPM 1:0 (0=disabled), LINK_SPEED 19:16, + * LINK_WIDTH 25:20 (LINK_WIDTH_X16=0x10). */ +#define TU104_PCIE_LINK_CTRL_STATUS_GEN3_X16 ((0x3u << 16) | (0x10u << 20)) + /* NV0080_CTRL_GR_INFO entry + infoList indices (ctrl0080gr.h) */ struct tu104_gr_info_entry { diff --git a/kernel/main.c b/kernel/main.c index 0fea09e..209942b 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -1723,14 +1723,14 @@ static int nv_vgpu_config_space_init(struct nv_vgpu_device *vgpu, struct pci_dev cfg[0x89] = 0x00; cfg[0x8a] = 0x10; /* Device Status */ cfg[0x8b] = 0x00; - cfg[0x8c] = 0x00; /* Link Capabilities */ - cfg[0x8d] = 0x00; + cfg[0x8c] = 0x03; /* Link Capabilities: MAX_SPEED 3:0 = 3 (8 GT/s) */ + cfg[0x8d] = 0x01; /* ... MAX_WIDTH 9:4 = 0x10 (x16) -> 0x103 */ cfg[0x8e] = 0x00; cfg[0x8f] = 0x00; cfg[0x90] = 0x00; /* Link Control */ cfg[0x91] = 0x00; - cfg[0x92] = 0x00; /* Link Status */ - cfg[0x93] = 0x00; + cfg[0x92] = 0x03; /* Link Status: speed 3:0 = 3 (Gen3) */ + cfg[0x93] = 0x01; /* ... width 9:4 = 0x10 (x16) */ cfg[0x94] = 0x00; /* Slot Capabilities */ cfg[0x95] = 0x00; cfg[0x96] = 0x00; -- cgit v1.2.3