IQ.Pilot Release Commit @ bec7652

This commit is contained in:
IQ.Lvbs history cleanup
2026-08-22 23:42:41 -05:00
commit 58039e647c
4603 changed files with 1236178 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
#!/usr/bin/env python3
import subprocess, json, sys, os
REMOTE_HOST = os.getenv("REMOTE_HOST", "192.168.52.154")
LOCAL_PCI = os.getenv("MLX_PCI", "0000:41:00.0")
REMOTE_PCI = os.getenv("REMOTE_PCI", "0000:41:00.0")
LOCAL_IP = os.getenv("LOCAL_IP", "10.0.0.1")
REMOTE_IP = os.getenv("REMOTE_IP", "10.0.0.2")
SSH = ["ssh", "-o", "StrictHostKeyChecking=no", REMOTE_HOST]
TINYGRAD = os.path.dirname(os.path.abspath(__file__)) + "/../.."
print("syncing code to remote")
subprocess.run(["rsync", "-az", "--exclude=.git", "--exclude=__pycache__", "--exclude=*.pyc",
TINYGRAD + "/", f"{REMOTE_HOST}:~/tinygrad/"], check=True)
print("booting remote")
remote = subprocess.Popen(
SSH + [f"cd ~/tinygrad && sudo PYTHONPATH=. MLX_DEBUG=1 MLX_PCI={REMOTE_PCI} MLX_IP={REMOTE_IP} python3 extra/mlx_driver/mlxdev.py --server"],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=sys.stderr, text=True)
remote_info = None
for line in iter(remote.stdout.readline, ''):
print(f" [remote] {line}", end='')
try: remote_info = json.loads(line.strip()); break
except json.JSONDecodeError: pass
assert remote_info, "failed to get remote connection info"
print("booting local")
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../.."))
from extra.mlx_driver.mlxdev import MLXDev, MLXQP
from tinygrad.runtime.support.system import PCIDevice
local_dev = MLXDev(PCIDevice("mlx5", LOCAL_PCI), ip=LOCAL_IP)
local_qp = MLXQP(local_dev)
local_info = {"qpn": local_qp.qpn, "mac": local_dev.mac.to_bytes(6,'big').hex(), "gid": local_dev.local_gid.hex()}
remote.stdin.write(json.dumps(local_info) + "\n")
remote.stdin.flush()
for line in iter(remote.stdout.readline, ''):
print(f" [remote] {line}", end='')
if "connected" in line: break
local_qp.connect(remote_info["qpn"], int(remote_info["mac"], 16), int(remote_info["gid"], 16))
print("both QPs in RTS")
remote_target = None
for line in iter(remote.stdout.readline, ''):
print(f" [remote] {line}", end='')
try: remote_target = json.loads(line.strip()); break
except json.JSONDecodeError: pass
assert remote_target
test_msg = b"Test message, rdma works!"
src_mem, src_paddrs = local_dev.pci_dev.alloc_sysmem(0x1000)
for i, b in enumerate(test_msg): src_mem[i] = b
print(f"RDMA WRITE {len(test_msg)}B to remote phys 0x{remote_target['target_addr']:x}")
local_qp.rdma_write(remote_target["target_addr"], remote_target["rkey"], src_paddrs[0], local_dev.mkey, len(test_msg))
remote.stdin.write("done\n")
remote.stdin.flush()
for line in iter(remote.stdout.readline, ''):
print(f" [remote] {line}", end='')
if "AS TEXT" in line: break
remote.stdin.close()
remote.wait()
print("RDMA WRITE test complete")

View File

@@ -0,0 +1,99 @@
#!/usr/bin/env python3
# GMMU=0 MLX_PCI=0000:41:00.0 PYTHONPATH=. python3 extra/mlx_driver/loopback.py
import struct
from tinygrad.helpers import getenv, round_up
from tinygrad.device import Device, BufferSpec
from tinygrad.runtime.support.system import PCIDevice
from tinygrad.runtime.support.memory import AddrSpace
from tinygrad.runtime.ops_amd import AMDComputeQueue
from tinygrad.helpers import to_be32, to_be64
from extra.mlx_driver.mlxdev import MLXDev, MLXQP
BUF_SIZE = 0x1000
MLX_PCI = getenv("MLX_PCI", "0000:41:00.0")
MLX_IP = getenv("MLX_IP", "10.0.0.1")
def map_phys_to_gpu(gpu, paddr, size):
size = round_up(size, 0x1000)
va = gpu.iface.dev_impl.mm.alloc_vaddr(size, align=0x1000)
gpu.iface.dev_impl.mm.map_range(va, size, [(paddr, size)], aspace=AddrSpace.SYS, snooped=True, uncached=True)
return va
print("[init] AMD GPU...")
gpu = Device["AMD"]
print(f"[init] MLX5 at {MLX_PCI}")
dev = MLXDev(PCIDevice("mlx5", MLX_PCI), ip=MLX_IP)
qp = MLXQP(dev)
print(f"[init] loopback connect QP 0x{qp.qp_info['qpn']:x}")
qp.connect(qp.qp_info['qpn'], dev.mac, int.from_bytes(dev.local_gid, 'big'))
# allocate src/dst via AMD GPU allocator
buf_src = gpu.allocator.alloc(BUF_SIZE, BufferSpec(nolru=True))
buf_dst = gpu.allocator.alloc(BUF_SIZE, BufferSpec(nolru=True))
bar_base = gpu.iface.pci_dev.bar_info(gpu.iface.vram_bar)[0]
src_paddr = buf_src.meta.mapping.paddrs[0][0] + bar_base
dst_paddr = buf_dst.meta.mapping.paddrs[0][0] + bar_base
print(f"src paddr=0x{src_paddr:x} dst paddr=0x{dst_paddr:x}")
# fill src, zero dst
test_msg = b"Hello from loopback send/recv!"
gpu.allocator._copyin(buf_src, memoryview(bytearray(test_msg.ljust(BUF_SIZE, b'\x00'))))
gpu.allocator._copyin(buf_dst, memoryview(bytearray(BUF_SIZE)))
gpu.synchronize()
# post recv WQE on RQ from CPU (scatter entry: byte_count, lkey, addr)
rq_mask = (1 << 4) - 1 # log_rq_size=4
rq_wqe = qp.qp_buf.view((qp.rq_head & rq_mask) * 16, 16)
rq_wqe[:] = struct.pack('>IIQ', len(test_msg), dev.mkey, dst_paddr)
qp.rq_head += 1
# ring recv doorbell from CPU (DBR offset 0 = recv counter)
dev.dbr[qp.qp_dbr // 4] = to_be32(qp.rq_head)
# build send WQE in SQ from CPU (opcode 0x0a = SEND, ds_count=2)
sq_head = qp.sq_head
sq_mask = (1 << qp.log_sq_size) - 1
wqe = qp.qp_buf.view(qp.sq_offset + (sq_head & sq_mask) * 64, 64)
wqe[:] = bytes(64)
wqe[0:8] = struct.pack('>II', (sq_head << 8) | 0x0a, (qp.qp_info['qpn'] << 8) | 2)
wqe[11] = 0x08 # CE: signal completion
wqe[16:32] = struct.pack('>IIQ', len(test_msg), dev.mkey, src_paddr)
qp.sq_head += 1
doorbell_val = to_be64(int.from_bytes(bytes(wqe[0:8]), 'big'))
# map MLX5 UAR and DBR into GPU VA
uar_paddr = dev.pci_dev.bar_info(0)[0] + dev.uar * 0x1000
uar_gpu_va = map_phys_to_gpu(gpu, uar_paddr, 0x1000)
dbr_gpu_va = map_phys_to_gpu(gpu, dev.dbr_paddrs[0], 0x1000)
print(f"UAR gpu_va=0x{uar_gpu_va:x} DBR gpu_va=0x{dbr_gpu_va:x}")
# GPU rings send doorbell via compute queue release_mem
q = AMDComputeQueue(gpu)
q.wait(gpu.timeline_signal, gpu.timeline_value - 1)
# write DBR (32-bit sq_head) - send doorbell at qp_dbr + 4
q.release_mem(dbr_gpu_va + qp.qp_dbr + 4, to_be32(qp.sq_head), q.pm4.data_sel__mec_release_mem__send_32_bit_low,
q.pm4.int_sel__mec_release_mem__none)
# write UAR doorbell (64-bit)
q.release_mem(uar_gpu_va + 0x800, doorbell_val, q.pm4.data_sel__mec_release_mem__send_64_bit_data,
q.pm4.int_sel__mec_release_mem__none)
q.signal(gpu.timeline_signal, gpu.next_timeline())
q.submit(gpu)
print("GPU kicked doorbell, waiting...")
gpu.synchronize()
# poll CQ from CPU (send + recv completions)
qp.poll_cq()
qp.poll_cq()
# read back
result = bytearray(BUF_SIZE)
gpu.allocator._copyout(memoryview(result), buf_dst)
gpu.synchronize()
got = bytes(result[:len(test_msg)])
print(f"result: {got}")
assert got == test_msg, f"MISMATCH: {got} != {test_msg}"
print("RDMA loopback send/recv test passed (GPU-kicked)")

View File

@@ -0,0 +1,144 @@
// MLX5 autogen header — kernel struct layouts and constants
typedef unsigned char __u8;
typedef unsigned short __be16;
typedef unsigned int __be32;
typedef unsigned long long __be64;
// --- device.h structs ---
struct mlx5_cmd_layout {
__u8 type;
__u8 rsvd0[3];
__be32 inlen;
__be64 in_ptr;
__be32 in[4];
__be32 out[4];
__be64 out_ptr;
__be32 outlen;
__u8 token;
__u8 sig;
__u8 rsvd1;
__u8 status_own;
};
struct mlx5_cmd_prot_block {
__u8 data[512];
__u8 rsvd0[48];
__be64 next;
__be32 block_num;
__u8 rsvd1;
__u8 token;
__u8 ctrl_sig;
__u8 sig;
};
struct mlx5_init_seg {
__be32 fw_rev;
__be32 cmdif_rev_fw_sub;
__be32 rsvd0[2];
__be32 cmdq_addr_h;
__be32 cmdq_addr_l_sz;
__be32 cmd_dbell;
__be32 rsvd1[120];
__be32 initializing;
};
// --- Command opcodes (mlx5_ifc.h) ---
#define MLX5_CMD_OP_QUERY_HCA_CAP 0x100
#define MLX5_CMD_OP_QUERY_ADAPTER 0x101
#define MLX5_CMD_OP_INIT_HCA 0x102
#define MLX5_CMD_OP_TEARDOWN_HCA 0x103
#define MLX5_CMD_OP_ENABLE_HCA 0x104
#define MLX5_CMD_OP_DISABLE_HCA 0x105
#define MLX5_CMD_OP_QUERY_PAGES 0x107
#define MLX5_CMD_OP_MANAGE_PAGES 0x108
#define MLX5_CMD_OP_SET_HCA_CAP 0x109
#define MLX5_CMD_OP_QUERY_ISSI 0x10a
#define MLX5_CMD_OP_SET_ISSI 0x10b
#define MLX5_CMD_OP_SET_DRIVER_VERSION 0x10d
#define MLX5_CMD_OP_CREATE_MKEY 0x200
#define MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS 0x203
#define MLX5_CMD_OP_CREATE_EQ 0x301
#define MLX5_CMD_OP_DESTROY_EQ 0x302
#define MLX5_CMD_OP_CREATE_CQ 0x400
#define MLX5_CMD_OP_DESTROY_CQ 0x401
#define MLX5_CMD_OP_CREATE_QP 0x500
#define MLX5_CMD_OP_DESTROY_QP 0x501
#define MLX5_CMD_OP_RST2INIT_QP 0x502
#define MLX5_CMD_OP_INIT2RTR_QP 0x503
#define MLX5_CMD_OP_RTR2RTS_QP 0x504
#define MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT 0x754
#define MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT 0x755
#define MLX5_CMD_OP_SET_ROCE_ADDRESS 0x761
#define MLX5_CMD_OP_ALLOC_PD 0x800
#define MLX5_CMD_OP_ALLOC_UAR 0x802
#define MLX5_CMD_OP_ACCESS_REG 0x805
#define MLX5_CMD_OP_ALLOC_TRANSPORT_DOMAIN 0x816
// --- Command status (device.h) ---
#define MLX5_CMD_STAT_OK 0x0
#define MLX5_CMD_STAT_INT_ERR 0x1
#define MLX5_CMD_STAT_BAD_OP_ERR 0x2
#define MLX5_CMD_STAT_BAD_PARAM_ERR 0x3
#define MLX5_CMD_STAT_BAD_SYS_STATE_ERR 0x4
#define MLX5_CMD_STAT_BAD_RES_ERR 0x5
#define MLX5_CMD_STAT_RES_BUSY 0x6
#define MLX5_CMD_STAT_LIM_ERR 0x8
#define MLX5_CMD_STAT_BAD_RES_STATE_ERR 0x9
#define MLX5_CMD_STAT_NO_RES_ERR 0xf
#define MLX5_CMD_STAT_BAD_INP_LEN_ERR 0x50
#define MLX5_CMD_STAT_BAD_OUTP_LEN_ERR 0x51
// --- HCA cap types ---
#define MLX5_CAP_GENERAL 0x0
#define MLX5_CAP_ODP 0x2
#define MLX5_CAP_ATOMIC 0x3
#define MLX5_CAP_ROCE 0x4
#define HCA_CAP_OPMOD_GET_MAX 0
#define HCA_CAP_OPMOD_GET_CUR 1
// --- Pages ---
#define MLX5_PAGES_GIVE 1
#define MLX5_PAGES_TAKE 2
#define MLX5_BOOT_PAGES 1
#define MLX5_INIT_PAGES 2
// --- Registers ---
#define MLX5_REG_HOST_ENDIANNESS 0x7004
#define MLX5_REG_DTOR 0xC00E
// --- Misc ---
#define MLX5_PCI_CMD_XPORT 0x07
#define MLX5_CMD_DATA_BLOCK_SIZE 512
#define CMD_OWNER_HW 0x01
// --- IFC cmd_hca_cap bit offsets ---
#define CAP_GEN_ABS_NATIVE_PORT_NUM 0x007
#define CAP_GEN_HCA_CAP_2 0x020
#define CAP_GEN_EVENT_ON_VHCA_STATE_ALLOCATED 0x023
#define CAP_GEN_EVENT_ON_VHCA_STATE_ACTIVE 0x024
#define CAP_GEN_EVENT_ON_VHCA_STATE_IN_USE 0x025
#define CAP_GEN_EVENT_ON_VHCA_STATE_TEARDOWN_REQUEST 0x026
#define CAP_GEN_LOG_MAX_QP 0x09B
#define CAP_GEN_LOG_MAX_CQ 0x0DB
#define CAP_GEN_RELEASE_ALL_PAGES 0x145
#define CAP_GEN_CACHE_LINE_128BYTE 0x164
#define CAP_GEN_NUM_PORTS 0x1B8
#define CAP_GEN_PKEY_TABLE_SIZE 0x190
#define CAP_GEN_PCI_SYNC_FOR_FW_UPDATE_EVENT 0x1F1
#define CAP_GEN_CMDIF_CHECKSUM 0x210
#define CAP_GEN_DCT 0x21A
#define CAP_GEN_ROCE 0x21D
#define CAP_GEN_ATOMIC 0x21E
#define CAP_GEN_ODP 0x227
#define CAP_GEN_MKEY_BY_NAME 0x266
#define CAP_GEN_LOG_MAX_PD 0x32B
#define CAP_GEN_PCIE_RESET_USING_HOTRESET 0x335
#define CAP_GEN_PCI_SYNC_FOR_FW_UPDATE_WITH_DRIVER_UNLOAD 0x336
#define CAP_GEN_VHCA_STATE 0x3EA
#define CAP_GEN_ROCE_RW_SUPPORTED 0x3A1
#define CAP_GEN_LOG_MAX_CURRENT_UC_LIST 0x3FB
#define CAP_GEN_LOG_UAR_PAGE_SZ 0x490
#define CAP_GEN_NUM_VHCA_PORTS 0x610
#define CAP_GEN_SW_OWNER_ID 0x61E
#define CAP_GEN_NUM_TOTAL_DYNAMIC_VF_MSIX 0x708