1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
|
/* 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
|