blob: 85c9a9634a4b0679065e1f0c902cd33bc1e14c94 [file] [edit]
/* 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 <linux/uuid.h>
#include <linux/bitmap.h>
#include <linux/kobject.h>
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