1644a699eSMichał Winiarski // SPDX-License-Identifier: MIT 2644a699eSMichał Winiarski /* 3644a699eSMichał Winiarski * Copyright © 2025 Intel Corporation 4644a699eSMichał Winiarski */ 5644a699eSMichał Winiarski 6644a699eSMichał Winiarski #include "xe_bo.h" 7644a699eSMichał Winiarski #include "xe_device.h" 8*70e2fa91SMichał Winiarski #include "xe_guc_klv_helpers.h" 9644a699eSMichał Winiarski #include "xe_printk.h" 10644a699eSMichał Winiarski #include "xe_sriov_packet.h" 11644a699eSMichał Winiarski #include "xe_sriov_packet_types.h" 121ed30397SMichał Winiarski #include "xe_sriov_pf_helpers.h" 131ed30397SMichał Winiarski #include "xe_sriov_pf_migration.h" 141ed30397SMichał Winiarski #include "xe_sriov_printk.h" 151ed30397SMichał Winiarski 161ed30397SMichał Winiarski static struct mutex *pf_migration_mutex(struct xe_device *xe, unsigned int vfid) 171ed30397SMichał Winiarski { 181ed30397SMichał Winiarski xe_assert(xe, IS_SRIOV_PF(xe)); 191ed30397SMichał Winiarski xe_assert(xe, vfid <= xe_sriov_pf_get_totalvfs(xe)); 201ed30397SMichał Winiarski 211ed30397SMichał Winiarski return &xe->sriov.pf.vfs[vfid].migration.lock; 221ed30397SMichał Winiarski } 231ed30397SMichał Winiarski 241ed30397SMichał Winiarski static struct xe_sriov_packet **pf_pick_pending(struct xe_device *xe, unsigned int vfid) 251ed30397SMichał Winiarski { 261ed30397SMichał Winiarski xe_assert(xe, IS_SRIOV_PF(xe)); 271ed30397SMichał Winiarski xe_assert(xe, vfid <= xe_sriov_pf_get_totalvfs(xe)); 281ed30397SMichał Winiarski lockdep_assert_held(pf_migration_mutex(xe, vfid)); 291ed30397SMichał Winiarski 301ed30397SMichał Winiarski return &xe->sriov.pf.vfs[vfid].migration.pending; 311ed30397SMichał Winiarski } 321ed30397SMichał Winiarski 331ed30397SMichał Winiarski static struct xe_sriov_packet ** 341ed30397SMichał Winiarski pf_pick_descriptor(struct xe_device *xe, unsigned int vfid) 351ed30397SMichał Winiarski { 361ed30397SMichał Winiarski xe_assert(xe, IS_SRIOV_PF(xe)); 371ed30397SMichał Winiarski xe_assert(xe, vfid <= xe_sriov_pf_get_totalvfs(xe)); 381ed30397SMichał Winiarski lockdep_assert_held(pf_migration_mutex(xe, vfid)); 391ed30397SMichał Winiarski 401ed30397SMichał Winiarski return &xe->sriov.pf.vfs[vfid].migration.descriptor; 411ed30397SMichał Winiarski } 421ed30397SMichał Winiarski 431ed30397SMichał Winiarski static struct xe_sriov_packet **pf_pick_trailer(struct xe_device *xe, unsigned int vfid) 441ed30397SMichał Winiarski { 451ed30397SMichał Winiarski xe_assert(xe, IS_SRIOV_PF(xe)); 461ed30397SMichał Winiarski xe_assert(xe, vfid <= xe_sriov_pf_get_totalvfs(xe)); 471ed30397SMichał Winiarski lockdep_assert_held(pf_migration_mutex(xe, vfid)); 481ed30397SMichał Winiarski 491ed30397SMichał Winiarski return &xe->sriov.pf.vfs[vfid].migration.trailer; 501ed30397SMichał Winiarski } 511ed30397SMichał Winiarski 521ed30397SMichał Winiarski static struct xe_sriov_packet **pf_pick_read_packet(struct xe_device *xe, 531ed30397SMichał Winiarski unsigned int vfid) 541ed30397SMichał Winiarski { 551ed30397SMichał Winiarski struct xe_sriov_packet **data; 561ed30397SMichał Winiarski 571ed30397SMichał Winiarski data = pf_pick_descriptor(xe, vfid); 581ed30397SMichał Winiarski if (*data) 591ed30397SMichał Winiarski return data; 601ed30397SMichał Winiarski 611ed30397SMichał Winiarski data = pf_pick_pending(xe, vfid); 621ed30397SMichał Winiarski if (!*data) 631ed30397SMichał Winiarski *data = xe_sriov_pf_migration_save_consume(xe, vfid); 641ed30397SMichał Winiarski if (*data) 651ed30397SMichał Winiarski return data; 661ed30397SMichał Winiarski 671ed30397SMichał Winiarski data = pf_pick_trailer(xe, vfid); 681ed30397SMichał Winiarski if (*data) 691ed30397SMichał Winiarski return data; 701ed30397SMichał Winiarski 711ed30397SMichał Winiarski return NULL; 721ed30397SMichał Winiarski } 73644a699eSMichał Winiarski 74644a699eSMichał Winiarski static bool pkt_needs_bo(struct xe_sriov_packet *data) 75644a699eSMichał Winiarski { 76644a699eSMichał Winiarski return data->hdr.type == XE_SRIOV_PACKET_TYPE_VRAM; 77644a699eSMichał Winiarski } 78644a699eSMichał Winiarski 79644a699eSMichał Winiarski /** 80644a699eSMichał Winiarski * xe_sriov_packet_alloc() - Allocate migration data packet 81644a699eSMichał Winiarski * @xe: the &xe_device 82644a699eSMichał Winiarski * 83644a699eSMichał Winiarski * Only allocates the "outer" structure, without initializing the migration 84644a699eSMichał Winiarski * data backing storage. 85644a699eSMichał Winiarski * 86644a699eSMichał Winiarski * Return: Pointer to &xe_sriov_packet on success, 87644a699eSMichał Winiarski * NULL in case of error. 88644a699eSMichał Winiarski */ 89644a699eSMichał Winiarski struct xe_sriov_packet *xe_sriov_packet_alloc(struct xe_device *xe) 90644a699eSMichał Winiarski { 91644a699eSMichał Winiarski struct xe_sriov_packet *data; 92644a699eSMichał Winiarski 93644a699eSMichał Winiarski data = kzalloc(sizeof(*data), GFP_KERNEL); 94644a699eSMichał Winiarski if (!data) 95644a699eSMichał Winiarski return NULL; 96644a699eSMichał Winiarski 97644a699eSMichał Winiarski data->xe = xe; 98644a699eSMichał Winiarski data->hdr_remaining = sizeof(data->hdr); 99644a699eSMichał Winiarski 100644a699eSMichał Winiarski return data; 101644a699eSMichał Winiarski } 102644a699eSMichał Winiarski 103644a699eSMichał Winiarski /** 104644a699eSMichał Winiarski * xe_sriov_packet_free() - Free migration data packet. 105644a699eSMichał Winiarski * @data: the &xe_sriov_packet 106644a699eSMichał Winiarski */ 107644a699eSMichał Winiarski void xe_sriov_packet_free(struct xe_sriov_packet *data) 108644a699eSMichał Winiarski { 109644a699eSMichał Winiarski if (IS_ERR_OR_NULL(data)) 110644a699eSMichał Winiarski return; 111644a699eSMichał Winiarski 112644a699eSMichał Winiarski if (pkt_needs_bo(data)) 113644a699eSMichał Winiarski xe_bo_unpin_map_no_vm(data->bo); 114644a699eSMichał Winiarski else 115644a699eSMichał Winiarski kvfree(data->buff); 116644a699eSMichał Winiarski 117644a699eSMichał Winiarski kfree(data); 118644a699eSMichał Winiarski } 119644a699eSMichał Winiarski 120644a699eSMichał Winiarski static int pkt_init(struct xe_sriov_packet *data) 121644a699eSMichał Winiarski { 122644a699eSMichał Winiarski struct xe_gt *gt = xe_device_get_gt(data->xe, data->hdr.gt_id); 123644a699eSMichał Winiarski 124644a699eSMichał Winiarski if (!gt) 125644a699eSMichał Winiarski return -EINVAL; 126644a699eSMichał Winiarski 127644a699eSMichał Winiarski if (data->hdr.size == 0) 128644a699eSMichał Winiarski return 0; 129644a699eSMichał Winiarski 130644a699eSMichał Winiarski if (pkt_needs_bo(data)) { 131644a699eSMichał Winiarski struct xe_bo *bo; 132644a699eSMichał Winiarski 133644a699eSMichał Winiarski bo = xe_bo_create_pin_map_novm(data->xe, gt->tile, PAGE_ALIGN(data->hdr.size), 134644a699eSMichał Winiarski ttm_bo_type_kernel, 135644a699eSMichał Winiarski XE_BO_FLAG_SYSTEM | XE_BO_FLAG_PINNED, false); 136644a699eSMichał Winiarski if (IS_ERR(bo)) 137644a699eSMichał Winiarski return PTR_ERR(bo); 138644a699eSMichał Winiarski 139644a699eSMichał Winiarski data->bo = bo; 140644a699eSMichał Winiarski data->vaddr = bo->vmap.vaddr; 141644a699eSMichał Winiarski } else { 142644a699eSMichał Winiarski void *buff = kvzalloc(data->hdr.size, GFP_KERNEL); 143644a699eSMichał Winiarski 144644a699eSMichał Winiarski if (!buff) 145644a699eSMichał Winiarski return -ENOMEM; 146644a699eSMichał Winiarski 147644a699eSMichał Winiarski data->buff = buff; 148644a699eSMichał Winiarski data->vaddr = buff; 149644a699eSMichał Winiarski } 150644a699eSMichał Winiarski 151644a699eSMichał Winiarski return 0; 152644a699eSMichał Winiarski } 153644a699eSMichał Winiarski 154644a699eSMichał Winiarski #define XE_SRIOV_PACKET_SUPPORTED_VERSION 1 155644a699eSMichał Winiarski 156644a699eSMichał Winiarski /** 157644a699eSMichał Winiarski * xe_sriov_packet_init() - Initialize migration packet header and backing storage. 158644a699eSMichał Winiarski * @data: the &xe_sriov_packet 159644a699eSMichał Winiarski * @tile_id: tile identifier 160644a699eSMichał Winiarski * @gt_id: GT identifier 161644a699eSMichał Winiarski * @type: &xe_sriov_packet_type 162644a699eSMichał Winiarski * @offset: offset of data packet payload (within wider resource) 163644a699eSMichał Winiarski * @size: size of data packet payload 164644a699eSMichał Winiarski * 165644a699eSMichał Winiarski * Return: 0 on success or a negative error code on failure. 166644a699eSMichał Winiarski */ 167644a699eSMichał Winiarski int xe_sriov_packet_init(struct xe_sriov_packet *data, u8 tile_id, u8 gt_id, 168644a699eSMichał Winiarski enum xe_sriov_packet_type type, loff_t offset, size_t size) 169644a699eSMichał Winiarski { 170644a699eSMichał Winiarski data->hdr.version = XE_SRIOV_PACKET_SUPPORTED_VERSION; 171644a699eSMichał Winiarski data->hdr.type = type; 172644a699eSMichał Winiarski data->hdr.tile_id = tile_id; 173644a699eSMichał Winiarski data->hdr.gt_id = gt_id; 174644a699eSMichał Winiarski data->hdr.offset = offset; 175644a699eSMichał Winiarski data->hdr.size = size; 176644a699eSMichał Winiarski data->remaining = size; 177644a699eSMichał Winiarski 178644a699eSMichał Winiarski return pkt_init(data); 179644a699eSMichał Winiarski } 180644a699eSMichał Winiarski 181644a699eSMichał Winiarski /** 182644a699eSMichał Winiarski * xe_sriov_packet_init_from_hdr() - Initialize migration packet backing storage based on header. 183644a699eSMichał Winiarski * @data: the &xe_sriov_packet 184644a699eSMichał Winiarski * 185644a699eSMichał Winiarski * Header data is expected to be filled prior to calling this function. 186644a699eSMichał Winiarski * 187644a699eSMichał Winiarski * Return: 0 on success or a negative error code on failure. 188644a699eSMichał Winiarski */ 189644a699eSMichał Winiarski int xe_sriov_packet_init_from_hdr(struct xe_sriov_packet *data) 190644a699eSMichał Winiarski { 191644a699eSMichał Winiarski xe_assert(data->xe, !data->hdr_remaining); 192644a699eSMichał Winiarski 193644a699eSMichał Winiarski if (data->hdr.version != XE_SRIOV_PACKET_SUPPORTED_VERSION) 194644a699eSMichał Winiarski return -EINVAL; 195644a699eSMichał Winiarski 196644a699eSMichał Winiarski data->remaining = data->hdr.size; 197644a699eSMichał Winiarski 198644a699eSMichał Winiarski return pkt_init(data); 199644a699eSMichał Winiarski } 2001ed30397SMichał Winiarski 2011ed30397SMichał Winiarski static ssize_t pkt_hdr_read(struct xe_sriov_packet *data, 2021ed30397SMichał Winiarski char __user *buf, size_t len) 2031ed30397SMichał Winiarski { 2041ed30397SMichał Winiarski loff_t offset = sizeof(data->hdr) - data->hdr_remaining; 2051ed30397SMichał Winiarski 2061ed30397SMichał Winiarski if (!data->hdr_remaining) 2071ed30397SMichał Winiarski return -EINVAL; 2081ed30397SMichał Winiarski 2091ed30397SMichał Winiarski if (len > data->hdr_remaining) 2101ed30397SMichał Winiarski len = data->hdr_remaining; 2111ed30397SMichał Winiarski 2121ed30397SMichał Winiarski if (copy_to_user(buf, (void *)&data->hdr + offset, len)) 2131ed30397SMichał Winiarski return -EFAULT; 2141ed30397SMichał Winiarski 2151ed30397SMichał Winiarski data->hdr_remaining -= len; 2161ed30397SMichał Winiarski 2171ed30397SMichał Winiarski return len; 2181ed30397SMichał Winiarski } 2191ed30397SMichał Winiarski 2201ed30397SMichał Winiarski static ssize_t pkt_data_read(struct xe_sriov_packet *data, 2211ed30397SMichał Winiarski char __user *buf, size_t len) 2221ed30397SMichał Winiarski { 2231ed30397SMichał Winiarski if (len > data->remaining) 2241ed30397SMichał Winiarski len = data->remaining; 2251ed30397SMichał Winiarski 2261ed30397SMichał Winiarski if (copy_to_user(buf, data->vaddr + (data->hdr.size - data->remaining), len)) 2271ed30397SMichał Winiarski return -EFAULT; 2281ed30397SMichał Winiarski 2291ed30397SMichał Winiarski data->remaining -= len; 2301ed30397SMichał Winiarski 2311ed30397SMichał Winiarski return len; 2321ed30397SMichał Winiarski } 2331ed30397SMichał Winiarski 2341ed30397SMichał Winiarski static ssize_t pkt_read_single(struct xe_sriov_packet **data, 2351ed30397SMichał Winiarski unsigned int vfid, char __user *buf, size_t len) 2361ed30397SMichał Winiarski { 2371ed30397SMichał Winiarski ssize_t copied = 0; 2381ed30397SMichał Winiarski 2391ed30397SMichał Winiarski if ((*data)->hdr_remaining) 2401ed30397SMichał Winiarski copied = pkt_hdr_read(*data, buf, len); 2411ed30397SMichał Winiarski else 2421ed30397SMichał Winiarski copied = pkt_data_read(*data, buf, len); 2431ed30397SMichał Winiarski 2441ed30397SMichał Winiarski if ((*data)->remaining == 0 && (*data)->hdr_remaining == 0) { 2451ed30397SMichał Winiarski xe_sriov_packet_free(*data); 2461ed30397SMichał Winiarski *data = NULL; 2471ed30397SMichał Winiarski } 2481ed30397SMichał Winiarski 2491ed30397SMichał Winiarski return copied; 2501ed30397SMichał Winiarski } 2511ed30397SMichał Winiarski 2521ed30397SMichał Winiarski /** 2531ed30397SMichał Winiarski * xe_sriov_packet_read_single() - Read migration data from a single packet. 2541ed30397SMichał Winiarski * @xe: the &xe_device 2551ed30397SMichał Winiarski * @vfid: the VF identifier 2561ed30397SMichał Winiarski * @buf: start address of userspace buffer 2571ed30397SMichał Winiarski * @len: requested read size from userspace 2581ed30397SMichał Winiarski * 2591ed30397SMichał Winiarski * Return: number of bytes that has been successfully read, 2601ed30397SMichał Winiarski * 0 if no more migration data is available, 2611ed30397SMichał Winiarski * -errno on failure. 2621ed30397SMichał Winiarski */ 2631ed30397SMichał Winiarski ssize_t xe_sriov_packet_read_single(struct xe_device *xe, unsigned int vfid, 2641ed30397SMichał Winiarski char __user *buf, size_t len) 2651ed30397SMichał Winiarski { 2661ed30397SMichał Winiarski struct xe_sriov_packet **data = pf_pick_read_packet(xe, vfid); 2671ed30397SMichał Winiarski 2681ed30397SMichał Winiarski if (!data) 2691ed30397SMichał Winiarski return -ENODATA; 2701ed30397SMichał Winiarski if (IS_ERR(*data)) 2711ed30397SMichał Winiarski return PTR_ERR(*data); 2721ed30397SMichał Winiarski 2731ed30397SMichał Winiarski return pkt_read_single(data, vfid, buf, len); 2741ed30397SMichał Winiarski } 2751ed30397SMichał Winiarski 2761ed30397SMichał Winiarski static ssize_t pkt_hdr_write(struct xe_sriov_packet *data, 2771ed30397SMichał Winiarski const char __user *buf, size_t len) 2781ed30397SMichał Winiarski { 2791ed30397SMichał Winiarski loff_t offset = sizeof(data->hdr) - data->hdr_remaining; 2801ed30397SMichał Winiarski int ret; 2811ed30397SMichał Winiarski 2821ed30397SMichał Winiarski if (len > data->hdr_remaining) 2831ed30397SMichał Winiarski len = data->hdr_remaining; 2841ed30397SMichał Winiarski 2851ed30397SMichał Winiarski if (copy_from_user((void *)&data->hdr + offset, buf, len)) 2861ed30397SMichał Winiarski return -EFAULT; 2871ed30397SMichał Winiarski 2881ed30397SMichał Winiarski data->hdr_remaining -= len; 2891ed30397SMichał Winiarski 2901ed30397SMichał Winiarski if (!data->hdr_remaining) { 2911ed30397SMichał Winiarski ret = xe_sriov_packet_init_from_hdr(data); 2921ed30397SMichał Winiarski if (ret) 2931ed30397SMichał Winiarski return ret; 2941ed30397SMichał Winiarski } 2951ed30397SMichał Winiarski 2961ed30397SMichał Winiarski return len; 2971ed30397SMichał Winiarski } 2981ed30397SMichał Winiarski 2991ed30397SMichał Winiarski static ssize_t pkt_data_write(struct xe_sriov_packet *data, 3001ed30397SMichał Winiarski const char __user *buf, size_t len) 3011ed30397SMichał Winiarski { 3021ed30397SMichał Winiarski if (len > data->remaining) 3031ed30397SMichał Winiarski len = data->remaining; 3041ed30397SMichał Winiarski 3051ed30397SMichał Winiarski if (copy_from_user(data->vaddr + (data->hdr.size - data->remaining), buf, len)) 3061ed30397SMichał Winiarski return -EFAULT; 3071ed30397SMichał Winiarski 3081ed30397SMichał Winiarski data->remaining -= len; 3091ed30397SMichał Winiarski 3101ed30397SMichał Winiarski return len; 3111ed30397SMichał Winiarski } 3121ed30397SMichał Winiarski 3131ed30397SMichał Winiarski /** 3141ed30397SMichał Winiarski * xe_sriov_packet_write_single() - Write migration data to a single packet. 3151ed30397SMichał Winiarski * @xe: the &xe_device 3161ed30397SMichał Winiarski * @vfid: the VF identifier 3171ed30397SMichał Winiarski * @buf: start address of userspace buffer 3181ed30397SMichał Winiarski * @len: requested write size from userspace 3191ed30397SMichał Winiarski * 3201ed30397SMichał Winiarski * Return: number of bytes that has been successfully written, 3211ed30397SMichał Winiarski * -errno on failure. 3221ed30397SMichał Winiarski */ 3231ed30397SMichał Winiarski ssize_t xe_sriov_packet_write_single(struct xe_device *xe, unsigned int vfid, 3241ed30397SMichał Winiarski const char __user *buf, size_t len) 3251ed30397SMichał Winiarski { 3261ed30397SMichał Winiarski struct xe_sriov_packet **data = pf_pick_pending(xe, vfid); 3271ed30397SMichał Winiarski int ret; 3281ed30397SMichał Winiarski ssize_t copied; 3291ed30397SMichał Winiarski 3301ed30397SMichał Winiarski if (IS_ERR_OR_NULL(*data)) { 3311ed30397SMichał Winiarski *data = xe_sriov_packet_alloc(xe); 3321ed30397SMichał Winiarski if (!*data) 3331ed30397SMichał Winiarski return -ENOMEM; 3341ed30397SMichał Winiarski } 3351ed30397SMichał Winiarski 3361ed30397SMichał Winiarski if ((*data)->hdr_remaining) 3371ed30397SMichał Winiarski copied = pkt_hdr_write(*data, buf, len); 3381ed30397SMichał Winiarski else 3391ed30397SMichał Winiarski copied = pkt_data_write(*data, buf, len); 3401ed30397SMichał Winiarski 3411ed30397SMichał Winiarski if ((*data)->hdr_remaining == 0 && (*data)->remaining == 0) { 3421ed30397SMichał Winiarski ret = xe_sriov_pf_migration_restore_produce(xe, vfid, *data); 3431ed30397SMichał Winiarski if (ret) { 3441ed30397SMichał Winiarski xe_sriov_packet_free(*data); 3451ed30397SMichał Winiarski return ret; 3461ed30397SMichał Winiarski } 3471ed30397SMichał Winiarski 3481ed30397SMichał Winiarski *data = NULL; 3491ed30397SMichał Winiarski } 3501ed30397SMichał Winiarski 3511ed30397SMichał Winiarski return copied; 3521ed30397SMichał Winiarski } 3531ed30397SMichał Winiarski 354*70e2fa91SMichał Winiarski #define MIGRATION_KLV_DEVICE_DEVID_KEY 0xf001u 355*70e2fa91SMichał Winiarski #define MIGRATION_KLV_DEVICE_DEVID_LEN 1u 356*70e2fa91SMichał Winiarski #define MIGRATION_KLV_DEVICE_REVID_KEY 0xf002u 357*70e2fa91SMichał Winiarski #define MIGRATION_KLV_DEVICE_REVID_LEN 1u 358*70e2fa91SMichał Winiarski 359*70e2fa91SMichał Winiarski #define MIGRATION_DESCRIPTOR_DWORDS (GUC_KLV_LEN_MIN + MIGRATION_KLV_DEVICE_DEVID_LEN + \ 360*70e2fa91SMichał Winiarski GUC_KLV_LEN_MIN + MIGRATION_KLV_DEVICE_REVID_LEN) 3611ed30397SMichał Winiarski static size_t pf_descriptor_init(struct xe_device *xe, unsigned int vfid) 3621ed30397SMichał Winiarski { 3631ed30397SMichał Winiarski struct xe_sriov_packet **desc = pf_pick_descriptor(xe, vfid); 3641ed30397SMichał Winiarski struct xe_sriov_packet *data; 365*70e2fa91SMichał Winiarski unsigned int len = 0; 366*70e2fa91SMichał Winiarski u32 *klvs; 3671ed30397SMichał Winiarski int ret; 3681ed30397SMichał Winiarski 3691ed30397SMichał Winiarski data = xe_sriov_packet_alloc(xe); 3701ed30397SMichał Winiarski if (!data) 3711ed30397SMichał Winiarski return -ENOMEM; 3721ed30397SMichał Winiarski 3731ed30397SMichał Winiarski ret = xe_sriov_packet_init(data, 0, 0, XE_SRIOV_PACKET_TYPE_DESCRIPTOR, 3741ed30397SMichał Winiarski 0, MIGRATION_DESCRIPTOR_DWORDS * sizeof(u32)); 3751ed30397SMichał Winiarski if (ret) { 3761ed30397SMichał Winiarski xe_sriov_packet_free(data); 3771ed30397SMichał Winiarski return ret; 3781ed30397SMichał Winiarski } 3791ed30397SMichał Winiarski 380*70e2fa91SMichał Winiarski klvs = data->vaddr; 381*70e2fa91SMichał Winiarski klvs[len++] = PREP_GUC_KLV_CONST(MIGRATION_KLV_DEVICE_DEVID_KEY, 382*70e2fa91SMichał Winiarski MIGRATION_KLV_DEVICE_DEVID_LEN); 383*70e2fa91SMichał Winiarski klvs[len++] = xe->info.devid; 384*70e2fa91SMichał Winiarski klvs[len++] = PREP_GUC_KLV_CONST(MIGRATION_KLV_DEVICE_REVID_KEY, 385*70e2fa91SMichał Winiarski MIGRATION_KLV_DEVICE_REVID_LEN); 386*70e2fa91SMichał Winiarski klvs[len++] = xe->info.revid; 387*70e2fa91SMichał Winiarski 388*70e2fa91SMichał Winiarski xe_assert(xe, len == MIGRATION_DESCRIPTOR_DWORDS); 389*70e2fa91SMichał Winiarski 3901ed30397SMichał Winiarski *desc = data; 3911ed30397SMichał Winiarski 3921ed30397SMichał Winiarski return 0; 3931ed30397SMichał Winiarski } 3941ed30397SMichał Winiarski 395*70e2fa91SMichał Winiarski /** 396*70e2fa91SMichał Winiarski * xe_sriov_packet_process_descriptor() - Process migration data descriptor packet. 397*70e2fa91SMichał Winiarski * @xe: the &xe_device 398*70e2fa91SMichał Winiarski * @vfid: the VF identifier 399*70e2fa91SMichał Winiarski * @data: the &xe_sriov_packet containing the descriptor 400*70e2fa91SMichał Winiarski * 401*70e2fa91SMichał Winiarski * The descriptor uses the same KLV format as GuC, and contains metadata used for 402*70e2fa91SMichał Winiarski * checking migration data compatibility. 403*70e2fa91SMichał Winiarski * 404*70e2fa91SMichał Winiarski * Return: 0 on success, -errno on failure. 405*70e2fa91SMichał Winiarski */ 406*70e2fa91SMichał Winiarski int xe_sriov_packet_process_descriptor(struct xe_device *xe, unsigned int vfid, 407*70e2fa91SMichał Winiarski struct xe_sriov_packet *data) 408*70e2fa91SMichał Winiarski { 409*70e2fa91SMichał Winiarski u32 num_dwords = data->hdr.size / sizeof(u32); 410*70e2fa91SMichał Winiarski u32 *klvs = data->vaddr; 411*70e2fa91SMichał Winiarski 412*70e2fa91SMichał Winiarski xe_assert(xe, data->hdr.type == XE_SRIOV_PACKET_TYPE_DESCRIPTOR); 413*70e2fa91SMichał Winiarski 414*70e2fa91SMichał Winiarski if (data->hdr.size % sizeof(u32)) { 415*70e2fa91SMichał Winiarski xe_sriov_warn(xe, "Aborting migration, descriptor not in KLV format (size=%llu)\n", 416*70e2fa91SMichał Winiarski data->hdr.size); 417*70e2fa91SMichał Winiarski return -EINVAL; 418*70e2fa91SMichał Winiarski } 419*70e2fa91SMichał Winiarski 420*70e2fa91SMichał Winiarski while (num_dwords >= GUC_KLV_LEN_MIN) { 421*70e2fa91SMichał Winiarski u32 key = FIELD_GET(GUC_KLV_0_KEY, klvs[0]); 422*70e2fa91SMichał Winiarski u32 len = FIELD_GET(GUC_KLV_0_LEN, klvs[0]); 423*70e2fa91SMichał Winiarski 424*70e2fa91SMichał Winiarski klvs += GUC_KLV_LEN_MIN; 425*70e2fa91SMichał Winiarski num_dwords -= GUC_KLV_LEN_MIN; 426*70e2fa91SMichał Winiarski 427*70e2fa91SMichał Winiarski if (len > num_dwords) { 428*70e2fa91SMichał Winiarski xe_sriov_warn(xe, "Aborting migration, truncated KLV %#x, len %u\n", 429*70e2fa91SMichał Winiarski key, len); 430*70e2fa91SMichał Winiarski return -EINVAL; 431*70e2fa91SMichał Winiarski } 432*70e2fa91SMichał Winiarski 433*70e2fa91SMichał Winiarski switch (key) { 434*70e2fa91SMichał Winiarski case MIGRATION_KLV_DEVICE_DEVID_KEY: 435*70e2fa91SMichał Winiarski if (*klvs != xe->info.devid) { 436*70e2fa91SMichał Winiarski xe_sriov_warn(xe, 437*70e2fa91SMichał Winiarski "Aborting migration, devid mismatch %#06x!=%#06x\n", 438*70e2fa91SMichał Winiarski *klvs, xe->info.devid); 439*70e2fa91SMichał Winiarski return -ENODEV; 440*70e2fa91SMichał Winiarski } 441*70e2fa91SMichał Winiarski break; 442*70e2fa91SMichał Winiarski case MIGRATION_KLV_DEVICE_REVID_KEY: 443*70e2fa91SMichał Winiarski if (*klvs != xe->info.revid) { 444*70e2fa91SMichał Winiarski xe_sriov_warn(xe, 445*70e2fa91SMichał Winiarski "Aborting migration, revid mismatch %#06x!=%#06x\n", 446*70e2fa91SMichał Winiarski *klvs, xe->info.revid); 447*70e2fa91SMichał Winiarski return -ENODEV; 448*70e2fa91SMichał Winiarski } 449*70e2fa91SMichał Winiarski break; 450*70e2fa91SMichał Winiarski default: 451*70e2fa91SMichał Winiarski xe_sriov_dbg(xe, 452*70e2fa91SMichał Winiarski "Skipping unknown migration KLV %#x, len=%u\n", 453*70e2fa91SMichał Winiarski key, len); 454*70e2fa91SMichał Winiarski print_hex_dump_bytes("desc: ", DUMP_PREFIX_OFFSET, klvs, 455*70e2fa91SMichał Winiarski min(SZ_64, len * sizeof(u32))); 456*70e2fa91SMichał Winiarski break; 457*70e2fa91SMichał Winiarski } 458*70e2fa91SMichał Winiarski 459*70e2fa91SMichał Winiarski klvs += len; 460*70e2fa91SMichał Winiarski num_dwords -= len; 461*70e2fa91SMichał Winiarski } 462*70e2fa91SMichał Winiarski 463*70e2fa91SMichał Winiarski return 0; 464*70e2fa91SMichał Winiarski } 465*70e2fa91SMichał Winiarski 4661ed30397SMichał Winiarski static void pf_pending_init(struct xe_device *xe, unsigned int vfid) 4671ed30397SMichał Winiarski { 4681ed30397SMichał Winiarski struct xe_sriov_packet **data = pf_pick_pending(xe, vfid); 4691ed30397SMichał Winiarski 4701ed30397SMichał Winiarski *data = NULL; 4711ed30397SMichał Winiarski } 4721ed30397SMichał Winiarski 4731ed30397SMichał Winiarski #define MIGRATION_TRAILER_SIZE 0 4741ed30397SMichał Winiarski static int pf_trailer_init(struct xe_device *xe, unsigned int vfid) 4751ed30397SMichał Winiarski { 4761ed30397SMichał Winiarski struct xe_sriov_packet **trailer = pf_pick_trailer(xe, vfid); 4771ed30397SMichał Winiarski struct xe_sriov_packet *data; 4781ed30397SMichał Winiarski int ret; 4791ed30397SMichał Winiarski 4801ed30397SMichał Winiarski data = xe_sriov_packet_alloc(xe); 4811ed30397SMichał Winiarski if (!data) 4821ed30397SMichał Winiarski return -ENOMEM; 4831ed30397SMichał Winiarski 4841ed30397SMichał Winiarski ret = xe_sriov_packet_init(data, 0, 0, XE_SRIOV_PACKET_TYPE_TRAILER, 4851ed30397SMichał Winiarski 0, MIGRATION_TRAILER_SIZE); 4861ed30397SMichał Winiarski if (ret) { 4871ed30397SMichał Winiarski xe_sriov_packet_free(data); 4881ed30397SMichał Winiarski return ret; 4891ed30397SMichał Winiarski } 4901ed30397SMichał Winiarski 4911ed30397SMichał Winiarski *trailer = data; 4921ed30397SMichał Winiarski 4931ed30397SMichał Winiarski return 0; 4941ed30397SMichał Winiarski } 4951ed30397SMichał Winiarski 4961ed30397SMichał Winiarski /** 4971ed30397SMichał Winiarski * xe_sriov_packet_save_init() - Initialize the pending save migration packets. 4981ed30397SMichał Winiarski * @xe: the &xe_device 4991ed30397SMichał Winiarski * @vfid: the VF identifier 5001ed30397SMichał Winiarski * 5011ed30397SMichał Winiarski * Return: 0 on success, -errno on failure. 5021ed30397SMichał Winiarski */ 5031ed30397SMichał Winiarski int xe_sriov_packet_save_init(struct xe_device *xe, unsigned int vfid) 5041ed30397SMichał Winiarski { 5051ed30397SMichał Winiarski int ret; 5061ed30397SMichał Winiarski 5071ed30397SMichał Winiarski scoped_cond_guard(mutex_intr, return -EINTR, pf_migration_mutex(xe, vfid)) { 5081ed30397SMichał Winiarski ret = pf_descriptor_init(xe, vfid); 5091ed30397SMichał Winiarski if (ret) 5101ed30397SMichał Winiarski return ret; 5111ed30397SMichał Winiarski 5121ed30397SMichał Winiarski ret = pf_trailer_init(xe, vfid); 5131ed30397SMichał Winiarski if (ret) 5141ed30397SMichał Winiarski return ret; 5151ed30397SMichał Winiarski 5161ed30397SMichał Winiarski pf_pending_init(xe, vfid); 5171ed30397SMichał Winiarski } 5181ed30397SMichał Winiarski 5191ed30397SMichał Winiarski return 0; 5201ed30397SMichał Winiarski } 521