/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /* * Copyright 2026 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * */ #ifndef AMDGPU_UALINK_H #define AMDGPU_UALINK_H #include #include #include struct amdgpu_device; struct amdgpu_xcp; #define AMDGPU_UALINK_ACCEL_MAX 256 #define AMDGPU_UALINK_LOCAL_ACCELS_MAX 8 #define AMDGPU_UALINK_STATIONS_MAX 64 /* A vpod_id of 0 is reserved and treated as invalid/no vPod */ #define AMDGPU_UALINK_VPOD_ID_INVALID 0 /* nHT firmware status */ #define AMDGPU_NHT_FW_ST_PREINIT 0xA0 #define AMDGPU_NHT_FW_ST_READY 0xA1 #define AMDGPU_NHT_FW_ST_HALT 0xA2 #define AMDGPU_NHT_FW_ST_ERROR 0xA3 #define AMDGPU_NHT_FW_ST_FATAL 0xF0 #define AMDGPU_UALINK_RESP_TIMEOUT 5000 /* 5s timeout */ #define AMDGPU_UALINK_HANDLE_ACCID_MASK GENMASK_ULL(9, 0) #define AMDGPU_UALINK_MESSAGE_HEADER_MASK GENMASK_ULL(9, 0) #define AMDGPU_UALINK_HELLO_MSG_ACCID_MASK GENMASK_U32(9, 0) #define AMDGPU_UALINK_HELLO_MSG_RECV_ACCID_SHIFT 10 #define AMDGPU_UALINK_HELLO_MSG_SENDER_ACCID_SHIFT 20 #define AMDGPU_UALINK_NPA_FAIL_MSG_FAIL_REASON_MASK GENMASK_U32(7, 0) /* GPU-ID is stored in bits 41-50 of the NPA address. However, we * store NPA address is GPU PAGE aligned so bottom 12 bits are not used. * As a result, we need the GPU-ID shift to be 41 - 12 = 29. */ #define AMDGPU_UALINK_NPA_ADDR_GPUID_SHIFT 29 #define AMDGPU_UALINK_NPA_ADDR_GPUID_MASK GENMASK_ULL(38, 29) /* Reserve 2M in each 2TB range for ring buffer allocations for * remote interrupts. In terms of GPU pages, this is 2M / 4K = 512 pages. * So we reserve 512 pages in each 2TB range. */ #define AMDGPU_UALINK_NPA_ADDR_RANGE_RESERVED (1U << 9) #define AMDGPU_UALINK_NPA_ADDR_RANGE_MASK GENMASK_ULL(28, 0) enum AMDGPU_UALINK_NPA_FAIL_REASON { AMDGPU_UALINK_NPA_FAIL_NOSPACE = 1, AMDGPU_UALINK_NPA_FAIL_INVALID_HANDLE = 2, AMDGPU_UALINK_NPA_FAIL_DUPLICATE = 3, AMDGPU_UALINK_NPA_FAIL_ERROR = 4, }; enum AMDGPU_UALINK_NODE_STATE { AMDGPU_UALINK_NODE_NOT_READY = 0, AMDGPU_UALINK_NODE_PENDING = 1, AMDGPU_UALINK_NODE_READY = 2, AMDGPU_UALINK_NODE_TEARDOWN = 3 }; enum AMDGPU_UALINK_PROTOCOL_MESSAGES { AMDGPU_UALINK_HELLO_MSG = 1, AMDGPU_UALINK_HELLO_ACK_MSG = 2, AMDGPU_UALINK_NPA_REQ_MSG = 3, AMDGPU_UALINK_NPA_RSP_MSG = 4, AMDGPU_UALINK_NPA_FAIL_MSG = 5, AMDGPU_UALINK_NPA_REVOKE_MSG = 6, AMDGPU_UALINK_NPA_RELEASE_MSG = 7, AMDGPU_UALINK_MAX_PROTOCOL_MSG }; #define AMDGPU_UALINK_LIGHTWEIGHT_TLB_SHOOTDOWN 0x1 #define AMDGPU_UALINK_HEAVYWEIGHT_TLB_SHOOTDOWN 0x2 enum amdgpu_ualink_conn_state { AMDGPU_UALINK_CONN_NOT_READY = 0, AMDGPU_UALINK_CONN_IN_PROGRESS = 1, AMDGPU_UALINK_CONN_PENDING = 2, AMDGPU_UALINK_CONN_ESTABLISHED = 3 }; enum amdgpu_ualink_type { AMDGPU_UALINK_TYPE_UALOE = 0, AMDGPU_UALINK_TYPE_UALINK = 1, AMDGPU_UALINK_TYPE_MAX }; enum amdgpu_ualink_accel_state { AMDGPU_UALINK_ACCEL_STATE_UNCONFIGURED = 0, AMDGPU_UALINK_ACCEL_STATE_PPOD_CONFIGURED, AMDGPU_UALINK_ACCEL_STATE_VPOD_CONFIGURED, AMDGPU_UALINK_ACCEL_STATE_READY, AMDGPU_UALINK_ACCEL_STATE_ACTIVE, AMDGPU_UALINK_ACCEL_STATE_ERROR, AMDGPU_UALINK_ACCEL_STATE_MAX }; enum amdgpu_ualink_addr_mode { AMDGPU_UALINK_ADDR_MODE_SOURCE_ALIAS = 0, AMDGPU_UALINK_ADDR_MODE_SOURCE_IDENT = 1, AMDGPU_UALINK_ADDR_MODE_MAX }; enum amdgpu_ualink_mgr_state { AMDGPU_UALINK_INIT_NONE = 0, AMDGPU_UALINK_INIT_HW, AMDGPU_UALINK_INIT_COMPLETE, AMDGPU_UALINK_INIT_ERROR }; /* Physical pod info shared between query and setup API */ struct amdgpu_ualink_ppod_info { u32 accel_id; u32 bandwidth; u32 latency; u32 size; uuid_t id; }; /* Virtual pod info shared between query and config API */ struct amdgpu_ualink_vpod_info { u32 id; u32 size; u32 addr_mode; DECLARE_BITMAP(active_accel_bits, AMDGPU_UALINK_ACCEL_MAX); }; /* Query current UALink physical and virtual pod info */ struct amdgpu_ualink_info { struct kobject kobj; enum amdgpu_ualink_type link_type; enum amdgpu_ualink_accel_state accel_state; struct amdgpu_ualink_ppod_info ppod; struct amdgpu_ualink_vpod_info vpod; /* Local accelerator array in the vpod derived from * vpod.active_accel_bits, in arbitrary order */ u32 n_local_accels; u32 local_accels[AMDGPU_UALINK_LOCAL_ACCELS_MAX]; }; #define to_ualink_info(ko) container_of(ko, struct amdgpu_ualink_info, kobj) /* UALink physical pod setup */ struct amdgpu_ualink_ppod_setup { struct kobject kobj; struct amdgpu_ualink_ppod_info ppod; /* Local accelerator array indexed by socket ID */ u32 n_local_accels; u32 local_accels[AMDGPU_UALINK_LOCAL_ACCELS_MAX]; }; #define to_ualink_ppod_setup(ko) container_of(ko, struct amdgpu_ualink_ppod_setup, kobj) /* UAlink virtual pod config */ struct amdgpu_ualink_vpod_config { struct kobject kobj; struct amdgpu_ualink_vpod_info vpod; }; #define to_ualink_vpod_config(ko) container_of(ko, struct amdgpu_ualink_vpod_config, kobj) /* UALink station configuration */ struct amdgpu_ualink_station_config { struct kobject kobj; /* Station configuration flags * bits [3:0]: PortPerStation (PPS) - 1, 2, or 4 * bits [7:4]: Reserved */ u8 flags; u8 n_stations; /* bitmap or enabled lanes for each station in logical station order */ u8 lane_en_bitmap[AMDGPU_UALINK_STATIONS_MAX]; }; #define to_ualink_station_config(ko) container_of(ko, struct amdgpu_ualink_station_config, kobj) struct amdgpu_ualink_handle { union { struct { u64 handle_lo; u64 handle_hi; }; u64 handle[2]; }; }; struct amdgpu_ualink_imp_xa_node { struct amdgpu_device *adev; /* 128-bit handle for the BO */ struct amdgpu_ualink_handle handle; /* Use to signal NPA-RSP arrival */ struct completion npa_done; /* NPA address received in the NPA-RSP message */ u64 npa_addr; u64 size; /* GEM handle for the NPA BO */ u32 gem_handle; /* Fail reason received in NPA-FAIL message */ int fail_reason; /* Node state to signal if node setup is in progress * or is already completed. Node state goes back to * in progress if a HELLO message is received in * response to NPA-REQ message. */ enum AMDGPU_UALINK_NODE_STATE node_state; /* Used to connect all importer XA nodes from a particular * exporter. */ struct list_head list; /* Dmabuf corresponding to the NPA BO */ struct dma_buf *dmabuf; /* Refcount to track lifetime of this node */ struct kref refcount; }; struct amdgpu_ualink_npa_mm { struct drm_mm mm; u64 va_start; u64 va_size; struct mutex mm_lock; }; struct amdgpu_ualink_importer_entry { struct drm_mm_node *mm_node; u64 npa_addr; /* Keep track of if the connection got reset */ u32 generation_count; /* Used to connect all handles exported to a particular importer */ struct list_head list; /* Pointer to the parent XA node. */ struct amdgpu_ualink_exp_xa_node *parent; }; struct amdgpu_ualink_exp_xa_node { /* 128-bit handle for the BO */ struct amdgpu_ualink_handle handle; /* Pointer to the BO thats exported.*/ struct amdgpu_bo *bo; /* Dmabuf corresponding to the BO */ struct dma_buf *dmabuf; /* Mutex to protect the node from concurrent access */ struct mutex node_lock; /* Used for storing importer info in source identification mode */ struct amdgpu_ualink_importer_entry importer_entries[AMDGPU_UALINK_ACCEL_MAX]; /* Used to track all importers of this BO. This is set when the * exporter sends back the NPA-RSP message. */ DECLARE_BITMAP(importers_bitmap, AMDGPU_UALINK_ACCEL_MAX); /* This bitmap is used to send NPA-REVOKE messages to all the importers. * And to track the NPA-RELEASE response for each NPA-REVOKE message sent. * A bit is cleared in this bitmap when the NPA RELEASE message is * received in response to the NPA-REVOKE message. */ DECLARE_BITMAP(npa_release_bitmap, AMDGPU_UALINK_ACCEL_MAX); /* Use to signal responses received from all importers */ struct completion npa_done; /* Refcount to track lifetime of this node */ struct kref refcount; /* Work to cleanup the node. */ struct work_struct cleanup_work; }; struct amdgpu_ualink_connection { struct completion hello_done; struct mutex lock; u32 generation_count; enum amdgpu_ualink_conn_state state; }; struct amdgpu_ualink_remote; struct amdgpu_ualink_msg_ctl { u32 (*check_status)(struct amdgpu_device *adev); int (*send_metadata)(struct amdgpu_device *adev, u64 metadata_gpu_addr, u32 accel_data); int (*send_halt)(struct amdgpu_device *adev); }; struct amdgpu_ualink_mgr { u64 npa_size; u32 psp_if_ver; const struct amdgpu_ualink_msg_ctl *msg_ctl; struct amdgpu_ualink_info *info; struct amdgpu_ualink_ppod_setup *setup; struct amdgpu_ualink_vpod_config *config; struct amdgpu_ualink_station_config *stations; bool sysfs_init; enum amdgpu_ualink_mgr_state mgr_state; /* For remote interrupt and shootdown */ struct amdgpu_ualink_remote *remote; /* handle irq from ualink client of remote GPUs */ struct amdgpu_irq_src irq; /* Xarray to store info about exported BOs */ struct xarray exp_xa; /* Xarray to store info about imported ualink handles */ struct xarray imp_xa; /* Xarray to store handles to be deleted */ struct xarray handle_invalid_xa; /* Array to store connection state per remote GPU */ struct amdgpu_ualink_connection conn_state[AMDGPU_UALINK_ACCEL_MAX]; /* List of exported ualink handles per GPU. Used to quickly traverse * the list of all handles exported to a remote GPU. */ struct list_head exp_handles_list[AMDGPU_UALINK_ACCEL_MAX]; /* List of imported ualink handles per GPU. Used to quickly traverse * the list of all handles imported from a remote GPU. */ struct list_head imp_handles_list[AMDGPU_UALINK_ACCEL_MAX]; /* WQ to manage revocation of exported memory. */ struct workqueue_struct *npa_wq; /* Memory-manager for managing NPA address space. */ struct amdgpu_ualink_npa_mm npa_mm; /* NPA-VM used on the exporter.*/ struct amdgpu_vm npa_vm; /* DRM client for UALink to manage GEM handles for NPA BOs */ struct drm_client_dev client; /* Sequence number to track the need for TLB flushes */ atomic64_t last_flushed_tlb_seq; /* Debug-only: bitmap of incoming UALink protocol messages to drop. * * Each bit position corresponds to a value from * enum AMDGPU_UALINK_PROTOCOL_MESSAGES: * BIT(AMDGPU_UALINK_NPA_REQ_MSG) drops one incoming NPA-REQ. * BIT(AMDGPU_UALINK_NPA_RSP_MSG) drops one incoming NPA-RSP. * * On reception of a message whose corresponding bit is set, the bit * is atomically cleared and the message is silently dropped. This * means at most one packet per set bit is dropped; any further * incoming packets of the same type are processed normally. This is * intended to exercise the connection reset / recovery paths from a * debugfs handle. */ unsigned long drop_msg_bitmap; }; int amdgpu_ualink_init_interrupt(struct amdgpu_device *adev, unsigned int client_id, unsigned int src_id); int amdgpu_ualink_sw_init(struct amdgpu_device *adev); void amdgpu_ualink_sw_fini(struct amdgpu_device *adev); int ualink_send_hello(struct amdgpu_device *adev, u32 remote_accel_id); int amdgpu_ualink_config_update_handler(struct amdgpu_device *adev); int amdgpu_ualink_pause_handler(struct amdgpu_device *adev); int amdgpu_ualink_resume_handler(struct amdgpu_device *adev); int amdgpu_ualink_sysfs_init(struct amdgpu_device *adev); void amdgpu_ualink_sysfs_fini(struct amdgpu_device *adev); void amdgpu_ualink_xcp_sysfs_update(struct amdgpu_xcp *xcp); int amdgpu_ualink_manager_start(struct amdgpu_device *adev); void amdgpu_ualink_manager_stop(struct amdgpu_device *adev); int amdgpu_ualink_export_handle(struct drm_device *dev, struct drm_file *filp, u32 gem_handle, struct amdgpu_ualink_handle *handle_out); int amdgpu_ualink_import_handle(struct drm_device *dev, const struct amdgpu_ualink_handle *ualink_handle, int *fd_out); int amdgpu_gem_ualink_handle_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); void amdgpu_ualink_revoke_exported_memory(struct amdgpu_bo *bo); int ualink_ip_hw_init(struct amdgpu_ip_block *ip_block); int ualink_ip_hw_fini(struct amdgpu_ip_block *ip_block); int ualink_ip_late_init(struct amdgpu_ip_block *ip_block); int ualink_ip_sw_init(struct amdgpu_ip_block *ip_block); int ualink_ip_sw_fini(struct amdgpu_ip_block *ip_block); extern const struct amdgpu_ip_block_version ualink_v1_0_ip_block; #endif