NPU (Neural Processing Unit)

Linux NPU 드라이버를 AI 추론 워크로드의 지연시간·전력·메모리 효율 관점에서 심층 정리합니다. DRM accel 계층과 커맨드 제출 모델, 사용자 공간 런타임과 커널 ioctl 경계, 텐서 버퍼 할당과 DMA-BUF 공유, IOMMU/PASID 기반 주소 공간 격리, 펌웨어 로딩과 에러 복구 시나리오, DVFS/thermal/runtime PM 연계 전력 최적화, CPU/GPU/NPU 협업 파이프라인 구성과 프로파일링까지 실전 NPU 스택 구축에 필요한 핵심 내용을 다룹니다.

전제 조건: 디바이스 드라이버DMA 문서를 먼저 읽으세요. 멀티미디어/가속기 경로는 대용량 버퍼 이동과 동기화가 성능의 핵심이므로, 메모리 경로와 큐 모델을 먼저 파악해야 합니다.
일상 비유: 이 주제는 영상 제작 파이프라인과 비슷합니다. 촬영·편집·인코딩 단계가 끊기지 않아야 결과가 나오듯이, 버퍼 큐와 하드웨어 스케줄링의 연속성이 중요합니다.

핵심 요약

  • 초기화 순서 — 탐색, 바인딩, 자원 등록 순서를 점검합니다.
  • 제어/데이터 분리 — 빠른 경로와 설정 경로를 분리 설계합니다.
  • IRQ/작업 분할 — 즉시 처리와 지연 처리를 구분합니다.
  • 안전 한계 — 전원/열/타이밍 임계값을 함께 관리합니다.
  • 운영 복구 — 오류 시 재초기화와 롤백 경로를 준비합니다.

단계별 이해

  1. 장치 수명주기 확인
    probe부터 remove까지 흐름을 점검합니다.
  2. 비동기 경로 설계
    IRQ, 워크큐, 타이머 역할을 분리합니다.
  3. 자원 정합성 검증
    DMA/클록/전원 참조를 교차 확인합니다.
  4. 현장 조건 테스트
    연결 끊김/복구/부하 상황을 재현합니다.
NPU vs GPU: NPU는 딥러닝 추론/학습에 특화된 하드웨어 가속기로, GPU와 달리 행렬 곱셈(GEMM)과 저정밀도 연산(INT8/FP16)에 최적화되어 있습니다. GPU는 범용 병렬 처리(CUDA/OpenCL)를 지원하는 반면, NPU는 컴파일러가 생성한 고정 함수 파이프라인으로 동작하여 특정 추론 워크로드에서 더 높은 전력 효율을 보이는 경우가 많습니다. 메인라인에서 도입된 DRM Accel 서브시스템(drivers/accel/)은 NPU와 GPU를 별도의 디바이스 노드(/dev/accel/accel* vs /dev/dri/renderD*)로 분리해 관리하며, 실제 지원 범위는 커널 브랜치/배포판 백포트에 따라 달라질 수 있습니다.

NPU (Neural Processing Unit) 개요

NPU(Neural Processing Unit)는 딥러닝 추론/학습 워크로드에 최적화된 전용 하드웨어 가속기입니다. 메인라인의 DRM Accel(drivers/accel/) 서브시스템은 GPU와 분리된 전용 디바이스 노드(/dev/accel/accel0)를 통해 NPU 및 AI 가속기를 관리하며, 커널 버전별 구체 기능은 릴리스/배포판 정책을 확인해야 합니다.

DRM Accel vs DRM GPU: DRM Accel은 DRM 인프라(GEM, DMA-BUF, drm_sched 등)를 재사용하지만, 렌더 노드(/dev/dri/renderD*)와 별도의 /dev/accel/accel* 디바이스 노드를 사용합니다. 이를 통해 GPU용 유저 공간 도구(Mesa, Vulkan)와 NPU용 ML 프레임워크가 충돌 없이 공존할 수 있습니다.

NPU vs GPU vs CPU 연산 특성

특성CPUGPUNPU
아키텍처범용 파이프라인, 소수의 고성능 코어대량의 SIMD/SIMT 코어MAC 어레이 + 전용 데이터 흐름 엔진
연산 강점분기 예측, 직렬 연산대규모 병렬 부동소수점INT8/FP16 행렬 곱셈 (GEMM)
전력 효율낮음 (범용)중간 (SIMD 활용)높음 (고정 함수 + 저정밀도)
메모리 접근캐시 계층 (L1/L2/L3)HBM/GDDR + 텍스처 캐시SRAM 스크래치패드 + DMA
프로그래밍 모델일반 코드CUDA/OpenCL/Vulkan Compute컴파일러가 생성한 명령 스트림
대표 TOPS/W~0.1~1–5~10–50+

NPU 하드웨어 아키텍처 개념

NPU의 핵심은 Systolic Array(맥동 배열)를 기반으로 한 행렬 연산 유닛과 전용 데이터 흐름 제어기입니다. 대부분의 NPU는 다음과 같은 공통 구조를 가집니다.

Host Interface PCIe / AXI Mailbox Command Queue IRQ Controller FW Loader MMU/IOMMU Compute Cluster (NCE / Tile) MAC Array (Systolic Array) INT8/FP16 GEMM Activation ReLU/Sigmoid/ SoftMax/Pool SRAM Scratchpad Memory DMA Engine Tile ↔ DDR/HBM Firmware / Microcontroller Task Scheduler Layer Dispatch Power Manager DVFS / Clock Gate External Memory DDR / LPDDR / HBM 모델 가중치 + 입출력 텐서 DMA-BUF 공유 가능 User Space Stack ML Framework (TFLite/ONNX) UMD (User Mode Driver) libdrm / ioctl /dev/accel/accel0

NPU 데이터 흐름

NPU에서 추론을 수행하는 전체 데이터 흐름은 다음과 같습니다.

  1. 모델 컴파일: ONNX/TFLite 모델을 NPU 전용 바이너리(blob)로 오프라인 컴파일. 레이어별 타일링, 양자화, 메모리 할당 계획이 포함됨
  2. 버퍼 할당: GEM BO(Buffer Object)를 통해 입력/출력/가중치 버퍼를 커널 드라이버에 할당 요청
  3. 커맨드 버퍼 생성: UMD가 DMA 전송, 연산 커맨드 등을 커맨드 버퍼에 기록
  4. 잡 제출: ioctl을 통해 커맨드 버퍼를 커널에 제출 → drm_sched가 스케줄링
  5. HW 실행: 펌웨어가 레이어 단위로 Compute Cluster에 디스패치, SRAM ↔ DDR DMA 전송 관리
  6. 완료 통보: IRQ → dma_fence 시그널 → 유저 공간에 결과 전달

양자화(Quantization)와 데이터 타입

NPU는 전력 효율을 위해 낮은 정밀도의 데이터 타입을 사용합니다. MAC 어레이의 데이터 타입에 따라 연산 처리량(TOPS)이 크게 달라집니다.

데이터 타입비트 폭범위/정밀도용도상대 처리량
FP3232-bitIEEE 754 단정밀도학습 기준선1× (기준)
FP1616-bit±65504, 정밀도 ~3.3자리학습/추론 혼합
BF1616-bitFP32 동적 범위, 낮은 정밀도학습 (기울기 안정성)
INT88-bit-128~127 / 0~255추론 최적화 (PTQ/QAT)
INT44-bit-8~7 / 0~15LLM 가중치 압축
FP8 (E4M3/E5M2)8-bitE4M3: ±448 / E5M2: ±57344차세대 학습/추론
양자화 기법:
  • PTQ (Post-Training Quantization): 학습 완료 후 가중치/활성화를 INT8로 변환. 캘리브레이션 데이터셋으로 스케일 팩터 결정
  • QAT (Quantization-Aware Training): 학습 중에 양자화 시뮬레이션. PTQ보다 정확도 손실이 적음
  • Mixed Precision: 레이어별로 FP16/INT8을 혼합. 정확도에 민감한 레이어는 FP16, 나머지는 INT8 사용

DRM Accel 서브시스템

DRM Accel은 Linux 6.2에서 도입된 NPU/AI 가속기 전용 프레임워크입니다. DRM의 인프라를 재사용하면서도 GPU와 별개의 디바이스 노드 네임스페이스를 제공합니다.

디바이스 노드 구조

# GPU 디바이스 노드 (DRM)
/dev/dri/card0          # DRM master (KMS + 렌더)
/dev/dri/renderD128     # render-only (non-root GPU 접근)

# NPU/Accel 디바이스 노드 (DRM Accel)
/dev/accel/accel0       # AI 가속기 전용 노드
/dev/accel/accel1       # 두 번째 가속기 (있는 경우)

# sysfs 계층
/sys/class/accel/accel0/
    ├── device           # → PCI/platform 디바이스 심링크
    ├── dev              # major:minor 번호
    └── power/           # 전원 관리 속성

Accel 드라이버 등록

Accel 드라이버는 drm_dev_alloc() 대신 accel_minor_alloc()을 내부적으로 사용합니다. 드라이버는 drm_driverDRIVER_COMPUTE_ACCEL 플래그를 설정하여 Accel 모드를 활성화합니다.

#include <drm/drm_accel.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem.h>
#include <drm/drm_ioctl.h>

/* Accel 드라이버 플래그: DRIVER_COMPUTE_ACCEL을 설정하면
 * /dev/accel/accelN 노드가 생성됨 (GPU용 /dev/dri/* 대신)
 * 참고: DRIVER_RENDER와 동시에 사용 불가 */
static const struct drm_driver my_npu_driver = {
    .driver_features    = DRIVER_GEM | DRIVER_COMPUTE_ACCEL,
    .name               = "my_npu",
    .desc               = "My NPU Accelerator",
    .date               = "20250101",
    .major              = 1,
    .minor              = 0,

    /* GEM 오퍼레이션 */
    .gem_create_object  = my_npu_gem_create_object,

    /* ioctl 테이블 */
    .ioctls             = my_npu_ioctls,
    .num_ioctls         = ARRAY_SIZE(my_npu_ioctls),

    /* 파일 오퍼레이션 */
    .fops               = &my_npu_fops,
};

/* probe에서 등록 */
static int my_npu_probe(struct pci_dev *pdev,
                        const struct pci_device_id *ent)
{
    struct drm_device *drm;
    struct my_npu_device *ndev;
    int ret;

    ndev = devm_drm_dev_alloc(&pdev->dev, &my_npu_driver,
                              struct my_npu_device, drm);
    if (IS_ERR(ndev))
        return PTR_ERR(ndev);

    drm = &ndev->drm;
    pci_set_drvdata(pdev, ndev);

    /* HW 초기화: MMIO 매핑, IRQ 등록, 펌웨어 로딩 */
    ret = my_npu_hw_init(ndev);
    if (ret)
        return ret;

    /* drm_dev_register()가 내부적으로 accel_minor를 할당
     * → /dev/accel/accelN 생성 */
    ret = drm_dev_register(drm, 0);
    if (ret)
        goto err_hw;

    dev_info(&pdev->dev, "NPU registered as /dev/accel/accel%d\\n",
             drm->accel->index);
    return 0;

err_hw:
    my_npu_hw_fini(ndev);
    return ret;
}

GEM Buffer Object 관리

NPU 드라이버는 GEM을 사용해 가중치, 텐서, 커맨드 버퍼 등의 메모리를 관리합니다. 일반적으로 drm_gem_shmem_object 헬퍼를 확장하거나, 독자적인 GEM 오브젝트를 구현합니다.

/* NPU 전용 GEM 버퍼 오브젝트 */
struct my_npu_bo {
    struct drm_gem_shmem_object base;
    u64  npu_addr;             /* NPU 가상 주소 (디바이스 MMU 매핑) */

    enum {
        NPU_BO_INPUT     = 0,   /* 입력 텐서 */
        NPU_BO_OUTPUT    = 1,   /* 출력 텐서 */
        NPU_BO_WEIGHTS   = 2,   /* 모델 가중치 (읽기 전용) */
        NPU_BO_CMDQ      = 3,   /* 커맨드 큐 */
    } usage;

    bool shared;               /* DMA-BUF로 다른 디바이스와 공유 가능 */
};

/* GEM 생성 ioctl 핸들러 */
static int my_npu_gem_create_ioctl(struct drm_device *dev,
                                    void *data,
                                    struct drm_file *file)
{
    struct my_npu_create_bo *args = data;
    struct my_npu_bo *bo;
    int ret;

    args->size = ALIGN(args->size, SZ_4K);

    bo = my_npu_bo_alloc(dev, args->size, args->flags);
    if (IS_ERR(bo))
        return PTR_ERR(bo);

    /* NPU MMU에 매핑 → npu_addr 할당 */
    ret = my_npu_mmu_map(bo);
    if (ret)
        goto err_free;

    ret = drm_gem_handle_create(file, &bo->base.base, &args->handle);
    drm_gem_object_put(&bo->base.base);
    args->npu_addr = bo->npu_addr;
    return ret;

err_free:
    drm_gem_object_put(&bo->base.base);
    return ret;
}

컴퓨트 잡 제출 (Job Submission)

NPU 드라이버는 drm_sched(GPU 스케줄러)를 재사용하여 컴퓨트 잡을 관리합니다.

/* NPU 잡 구조체 — drm_sched_job을 임베드 */
struct my_npu_job {
    struct drm_sched_job  base;
    struct my_npu_bo     *cmd_bo;      /* 커맨드 버퍼 */
    struct my_npu_bo    **bos;         /* 입출력 버퍼 참조 */
    u32                  bo_count;
    struct dma_fence     *done_fence;  /* 완료 fence */
};

/* drm_sched 백엔드 콜백 */
static struct dma_fence *
my_npu_run_job(struct drm_sched_job *sched_job)
{
    struct my_npu_job *job =
        container_of(sched_job, struct my_npu_job, base);
    struct my_npu_device *ndev = job_to_ndev(job);

    /* 1. 커맨드 버퍼의 NPU 가상 주소를 HW 레지스터에 기록 */
    writel(lower_32_bits(job->cmd_bo->npu_addr),
           ndev->mmio + NPU_REG_CMD_ADDR_LO);
    writel(upper_32_bits(job->cmd_bo->npu_addr),
           ndev->mmio + NPU_REG_CMD_ADDR_HI);

    /* 2. 실행 트리거 — 펌웨어가 처리 시작 */
    writel(NPU_CMD_EXECUTE, ndev->mmio + NPU_REG_DOORBELL);

    /* 3. HW fence 반환 — IRQ 핸들러에서 시그널됨 */
    return dma_fence_get(job->done_fence);
}

static enum drm_gpu_sched_stat
my_npu_timedout_job(struct drm_sched_job *sched_job)
{
    struct my_npu_job *job =
        container_of(sched_job, struct my_npu_job, base);

    dev_err(job->dev, "NPU job timeout — resetting engine\\n");
    my_npu_engine_reset(job_to_ndev(job));

    return DRM_GPU_SCHED_STAT_NOMINAL;
}

static const struct drm_sched_backend_ops my_npu_sched_ops = {
    .run_job      = my_npu_run_job,
    .timedout_job = my_npu_timedout_job,
};

펌웨어 로딩

대부분의 NPU는 부팅 시 펌웨어를 로딩해야 합니다. 커널의 request_firmware() API를 사용하여 /lib/firmware/에서 NPU 펌웨어 바이너리를 로드합니다.

static int my_npu_load_firmware(struct my_npu_device *ndev)
{
    const struct firmware *fw;
    int ret;

    ret = request_firmware(&fw, "my_npu/fw.bin", ndev->dev);
    if (ret) {
        dev_err(ndev->dev, "firmware load failed: %d\\n", ret);
        return ret;
    }

    /* 펌웨어를 NPU의 내부 SRAM 또는 전용 메모리 영역에 복사 */
    memcpy_toio(ndev->fw_region, fw->data, fw->size);

    /* 부트 레지스터 — 펌웨어 실행 시작 */
    writel(NPU_FW_BOOT, ndev->mmio + NPU_REG_FW_CTRL);

    /* 부팅 완료 대기 (mailbox 통신) */
    ret = my_npu_wait_fw_ready(ndev, 5000);
    release_firmware(fw);
    return ret;
}

NPU MMU (디바이스 가상 메모리)

NPU는 자체 MMU(또는 IOMMU 연동)를 통해 디바이스 가상 주소 공간을 관리합니다. 이를 통해 연속적이지 않은 물리 페이지를 NPU에서 연속 주소로 접근할 수 있습니다.

struct my_npu_mmu {
    struct my_npu_device  *ndev;
    dma_addr_t            pgd_dma;    /* L1 페이지 디렉토리 */
    u64                  *pgd_cpu;    /* CPU 매핑 */
    struct drm_mm         va_space;   /* VA 할당 관리 */
    struct mutex          lock;
};

static int my_npu_mmu_map(struct my_npu_bo *bo)
{
    struct my_npu_mmu *mmu = &bo_to_ndev(bo)->mmu;
    struct drm_mm_node *node = &bo->mm_node;
    struct sg_table *sgt;
    int ret;

    mutex_lock(&mmu->lock);

    /* VA 공간에서 영역 할당 */
    ret = drm_mm_insert_node_generic(&mmu->va_space, node,
                                      bo->base.base.size,
                                      SZ_4K, 0, DRM_MM_INSERT_BEST);
    if (ret)
        goto out;

    bo->npu_addr = node->start;

    sgt = drm_gem_shmem_get_pages_sgt(&bo->base);
    if (IS_ERR(sgt)) {
        drm_mm_remove_node(node);
        ret = PTR_ERR(sgt);
        goto out;
    }

    my_npu_mmu_write_ptes(mmu, bo->npu_addr, sgt);
    my_npu_mmu_flush_tlb(mmu);

out:
    mutex_unlock(&mmu->lock);
    return ret;
}
NPU MMU와 시스템 IOMMU: NPU 자체 MMU와 시스템 IOMMU(예: ARM SMMU, Intel VT-d)는 별개입니다. 시스템 IOMMU는 NPU 디바이스의 DMA 접근을 물리 메모리 보호 관점에서 제한하고, NPU MMU는 디바이스 내부의 가상 주소 변환을 담당합니다. 두 단계 변환이 모두 적용됩니다.

주요 Linux NPU 드라이버

드라이버하드웨어커널 경로디바이스 노드도입 버전
intel_vpu (IVPU) Intel Meteor Lake / Arrow Lake / Lunar Lake NPU drivers/accel/ivpu/ /dev/accel/accel0 6.3
habanalabs Intel Gaudi / Gaudi2 / Gaudi3 (데이터센터 AI) drivers/accel/habanalabs/ /dev/accel/accel0 6.2 (이전)
amdxdna AMD Ryzen AI (XDNA / XDNA2 NPU) drivers/accel/amdxdna/ /dev/accel/accel0 6.11
qaic Qualcomm Cloud AI 100 drivers/accel/qaic/ /dev/accel/accel0 6.4
etnaviv (NPU 확장) Vivante VIP (i.MX 8M Plus 등) drivers/gpu/drm/etnaviv/ /dev/dri/renderD* 4.5+
samsung_npu Samsung Exynos NPU (모바일) Out-of-tree (vendor kernel) /dev/vertex*
mtk_apu MediaTek APU (Dimensity SoC) Out-of-tree (vendor kernel) /dev/apusys*

Intel NPU (IVPU) 드라이버 상세

Intel NPU(이전 명칭 VPU)는 Meteor Lake부터 Intel 클라이언트 프로세서에 통합된 AI 추론 가속기입니다. drivers/accel/ivpu/에 위치하며, DRM Accel 프레임워크를 사용하는 대표적인 드라이버입니다.

drivers/accel/ivpu/ 구성 ivpu_drv.c / ivpu_drv.h (드라이버 진입점, 디바이스 구조체) 실행/펌웨어 경로 ivpu_hw.c (IP별 HW 추상화) ivpu_ipc.c, ivpu_jsm_msg.c (IPC/JSM) ivpu_fw.c, ivpu_pm.c (부팅/전원) 잡/메모리 경로 ivpu_job.c (drm_sched 기반 잡 처리) ivpu_gem.c (GEM BO 관리) ivpu_mmu.c, ivpu_mmu_context.c 관측/디버깅 ivpu_debugfs.c 상태/펌웨어/큐 정보를 debugfs로 제공
Intel NPU 세대별 특성:
  • Meteor Lake (NPU 3720): 첫 통합 NPU, 최대 ~10 TOPS (INT8)
  • Arrow Lake (NPU 3720): 아키텍처 유사, 소프트웨어 최적화
  • Lunar Lake (NPU 4): 최대 ~48 TOPS, MCDM 아키텍처 대폭 개선

Intel NPU ioctl 인터페이스

ioctl방향설명
DRM_IOCTL_IVPU_GET_PARAMRHW 파라미터 조회 (플랫폼 타입, TOPS, 타일 수 등)
DRM_IOCTL_IVPU_SET_PARAMW런타임 파라미터 설정
DRM_IOCTL_IVPU_BO_CREATERWGEM BO 생성 (크기, 플래그 → 핸들, NPU VA)
DRM_IOCTL_IVPU_BO_INFORWBO 정보 조회 (mmap offset, VA, 크기)
DRM_IOCTL_IVPU_SUBMITW컴퓨트 잡 제출 (커맨드 버퍼 + BO 리스트)
DRM_IOCTL_IVPU_BO_WAITRWBO 사용 완료 대기 (타임아웃 지정)
DRM_IOCTL_IVPU_METRIC_STREAMER_*RW성능 메트릭 수집 (대역폭, 활용률)

AMD XDNA (Ryzen AI) 드라이버

AMD Ryzen AI 프로세서(Phoenix, Hawk Point, Strix Point)에 통합된 XDNA NPU입니다. FPGA 기반 AI Engine 타일로 구성되며, 각 타일은 VLIW 프로세서 + 벡터 유닛을 포함합니다.

drivers/accel/amdxdna/ 구성 aie2_pci.c + aie2_pm.c (PCIe 초기화/전원 관리) 런타임 실행 경로 aie2_ctx.c / amdxdna_ctx.c aie2_solver.c (리소스 파티션) amdxdna_gem.c (BO 관리) amdxdna_mailbox.c (호스트↔FW 통신) 제어/관측 경로 aie2_message.c (ERT 메시지 프로토콜) amdxdna_sysfs.c (sysfs 디버그 속성) 드라이버 상태, 성능, 오류 관찰 지점
AMD XDNA 아키텍처 특징:
  • AI Engine 타일: 각 타일에 VLIW 스칼라 프로세서 + 512-bit 벡터 유닛 + 로컬 데이터 메모리(DM)
  • 컬럼 기반 할당: 복수의 타일을 컬럼 단위로 묶어 워크로드에 할당 (리소스 파티셔닝)
  • 데이터 흐름: 타일 간 스트림 인터커넥트로 파이프라인 구성 (ISA는 Xilinx Versal에서 유래)
  • XDNA2 (Strix Point): Block FP (BFLOAT16 블록), 최대 ~50 TOPS

Intel Gaudi (habanalabs) 드라이버

데이터센터급 AI 학습/추론 가속기인 Intel Gaudi 시리즈를 지원합니다. DRM Accel 프레임워크 도입 이전부터 존재하며, 6.2에서 drivers/accel/로 이동했습니다.

특성GaudiGaudi2Gaudi3
TPC (Tensor Processing Core)8개24개64개
MME (Matrix Math Engine)2개2개8개
HBM32GB HBM296GB HBM2E128GB HBM2E
네트워크10× 100GbE RoCE24× 100GbE RoCE24× 200GbE RoCE
BF16 성능~370 TFLOPS~865 TFLOPS~1835 TFLOPS
FP8 성능~1730 TFLOPS~3670 TFLOPS
/* habanalabs 드라이버 핵심 구조 (간략화) */
struct hl_device {
    struct drm_device      drm;
    const struct hl_asic_funcs *asic_funcs;  /* ASIC별 함수 포인터 */
    struct hl_cs_counters_atomic  cs_cnt;    /* 커맨드 서브미션 */
    struct hl_vm            vm;              /* 메모리 관리 */
    struct hl_nic          *nic;             /* 멀티 디바이스 통신 */
    struct hwmon_ops       *hwmon;           /* 전원/열 관리 */
};

/* hl_asic_funcs: ASIC 추상화 인터페이스 */
struct hl_asic_funcs {
    int  (*hw_init)(struct hl_device *hdev);
    void (*hw_fini)(struct hl_device *hdev, bool hard);
    int  (*suspend)(struct hl_device *hdev);
    int  (*resume)(struct hl_device *hdev);
    int  (*cb_mmap)(struct hl_device *hdev,
                    struct vm_area_struct *vma);
    void (*ring_doorbell)(struct hl_device *hdev,
                          u32 hw_queue_id, u32 pi);
    /* ... 50+ 함수 포인터 ... */
};

Qualcomm QNN / HTP (Hexagon Tensor Processor)

Qualcomm은 Snapdragon SoC에 DSP 기반 AI 가속기를 통합해 왔습니다. 초기 Hexagon DSP에서 시작해, 현재는 HTP(Hexagon Tensor Processor)라는 독립적인 AI 코어로 진화했습니다. Snapdragon 8 Gen 3, Snapdragon X Elite 등 최신 칩에는 전용 NPU 클러스터가 탑재됩니다.

HTP 아키텍처와 진화

Qualcomm AI Engine 계층 구조 애플리케이션 / ONNX 모델 TensorFlow Lite / PyTorch Mobile / ONNX Runtime QNN SDK (Qualcomm Neural Network SDK) 모델 변환 · INT4/INT8 양자화 · 백엔드 선택 (HTP / GPU / CPU) FastRPC drivers/misc/fastrpc.c SMEM · RPM · rpmsg 버스 remoteproc qcom_q6v5_mss.c DSP 펌웨어 로딩 · 생명주기 HTP (Hexagon Tensor Processor) Hardware Vector 유닛 · Tensor 슬라이스 · Scalar Core · VTCM(Vector TCM) Hexagon DSP → Hexagon v65 HVX → HTP v73 (Snapdragon 8 Gen 2) → HTP v75 (Snapdragon 8 Gen 3, X Elite) 성능: 10 TOPS (8 Gen 1) → 45 TOPS (8 Gen 3) → 75 TOPS (Snapdragon X Elite)

FastRPC 커널 드라이버

Qualcomm DSP/HTP는 FastRPC 메커니즘으로 유저 공간과 통신합니다. FastRPC는 CPU↔DSP 간 함수 호출을 원격 프로시저 콜(RPC) 형태로 처리하며, 커널 드라이버 drivers/misc/fastrpc.c가 이를 중재합니다.

# FastRPC 관련 디바이스 노드
ls /dev/fastrpc-*
# /dev/fastrpc-cdsp   → Compute DSP (AI 추론)
# /dev/fastrpc-adsp   → Audio DSP
# /dev/fastrpc-mdsp   → Modem DSP

# remoteproc를 통한 DSP 펌웨어 상태 확인
cat /sys/bus/platform/drivers/qcom-q6v5-pas/*/state
/* FastRPC 커널 핵심 구조 (drivers/misc/fastrpc.c) */
struct fastrpc_channel_ctx {
    char                  *name;       /* "cdsp", "adsp" 등 */
    struct rpmsg_device   *rpdev;      /* rpmsg 채널 */
    struct fastrpc_apps   *apps;
    spinlock_t             lock;
    struct idr             ctx_idr;    /* 컨텍스트 ID 관리 */
    u32                    dsp_cap_idx;
};

struct fastrpc_invoke_ctx {
    int                    nscalars;   /* 인자 수 */
    struct fastrpc_map   **maps;       /* DMA buf 매핑 */
    dma_addr_t             buf;        /* 인자 버퍼 */
    struct completion      work;       /* 완료 대기 */
    int                    retval;     /* DSP 반환값 */
};

/* RPC 흐름:
 * 1. 유저 공간 → ioctl(FASTRPC_IOCTL_INVOKE)
 * 2. 커널: DMA 버퍼 고정(pin) + IOMMU 매핑
 * 3. rpmsg로 DSP에 invoke 메시지 전송
 * 4. DSP가 HTP에서 연산 실행
 * 5. 완료 인터럽트 → completion 시그널
 * 6. 유저 공간 복귀
 */

QNN SDK와 양자화

QNN(Qualcomm Neural Network) SDK는 ONNX/TFLite 모델을 HTP에서 실행 가능한 형태로 변환하고, INT4/INT8 양자화를 통해 추론 속도를 극대화합니다.

# ONNX 모델 → QNN 변환 (오프라인 컴파일)
qnn-onnx-converter \
  --input_network mobilenet_v3.onnx \
  --output_path   mobilenet_v3.cpp \
  --input_dim     input "1,3,224,224"

# QNN 모델 → HTP 바이너리 (.serialized)
qnn-model-lib-generator \
  -m mobilenet_v3.cpp \
  -b libQnnHtp.so \
  --output_dir ./output/

# 추론 성능 측정 (TOPS, 지연 시간)
qnn-net-run \
  --model        output/mobilenet_v3.serialized \
  --backend      libQnnHtp.so \
  --input_list   input_list.txt \
  --duration     10
오픈소스 현황 (2024~2025):
  • drivers/misc/fastrpc.c — mainline 포함 (Linux 5.4+)
  • drivers/remoteproc/qcom_q6v5_pas.c — mainline 포함
  • QNN SDK 자체 — 비공개 바이너리 (Qualcomm 개발자 사이트 배포)
  • HTP 펌웨어 — 바이너리 전용 (/lib/firmware/qcom/)
  • ONNX Runtime QNN EP — 오픈소스 (Microsoft/Qualcomm 협력)

Huawei Ascend / CANN AI 플랫폼

Huawei Ascend는 대규모 AI 훈련(910 시리즈)과 에지 추론(310 시리즈)을 위해 설계된 자체 AI 칩 시리즈입니다. 핵심 연산 유닛인 DaVinci Core는 행렬 곱셈을 3D 큐브 방식으로 처리하여 고효율 AI 연산을 구현합니다.

Ascend 아키텍처: DaVinci Core

Ascend DaVinci Core 구조 3D Cube (행렬 연산 유닛) 16×16×16 FP16 MAC Array 단일 클럭: 4096 FP16 연산 INT8 모드: 8192 연산/클럭 GEMM·Conv·Pooling 하드웨어 가속 Ascend 910B: 4096 TFLOPS (FP16) Vector Unit 활성화 함수 (ReLU, GELU, Softmax) 원소별 연산, 배치 정규화 Scalar Unit 흐름 제어 · 인덱스 계산 · 동기화 L0/L1 온칩 SRAM 버퍼 L0A (행렬 A) / L0B (행렬 B) / L0C (출력) / L1 (입력 스테이징) HBM2e (Ascend 910B: 64GB, 2 TB/s) 가중치 · 활성화 · 중간 텐서 저장 HCCS (Huawei Cache Coherence System) 칩간 통신 (Atlas 서버: 최대 8 Ascend 910B, NVLink 유사)
Ascend 시리즈 비교
모델용도성능메모리TDP
Ascend 910B 대형 모델 훈련 (LLM) 4096 TFLOPS (FP16) HBM2e 64GB 400W
Ascend 910 훈련 / 대규모 추론 1456 TFLOPS (FP16) HBM2e 32GB 310W
Ascend 310P 에지 추론 (서버/엣지) 256 TOPS (INT8) LPDDR4X 8GB 75W
Ascend 310 경량 추론 22 TOPS (INT8) LPDDR4 8GB 8W

CANN 런타임 구조

CANN(Compute Architecture for Neural Networks)은 Ascend 칩을 위한 소프트웨어 스택입니다. PyTorch/TensorFlow와 Ascend 하드웨어 사이를 중재하며, 커널 드라이버와 런타임 라이브러리로 구성됩니다.

PyTorch (torch_npu) / TensorFlow-NPU 프레임워크 플러그인 ← User Space AscendCL (Ascend Computing Language) 유저 공간 API Graph Engine (GE) + TBE 커널 라이브러리 그래프 컴파일러 Kernel Space ↓ Ascend 커널 드라이버 (ascend_drv.ko) 커널 모듈 (비공개) Ascend 910B / 310P 하드웨어
# Atlas 800T A2 서버에서의 디바이스 확인
npu-smi info                          # NPU 상태 (nvidia-smi 유사)
npu-smi info -t usages -i 0          # 칩 0번 사용률
ls /dev/davinci*                      # DaVinci 디바이스 노드
# /dev/davinci0 ~ /dev/davinci7
# /dev/davinci_manager
# PyTorch + torch_npu 사용 예제
import torch
import torch_npu                        # Ascend 백엔드 플러그인

# NPU 디바이스 지정
device = torch.device("npu:0")          # Ascend 910B 0번 칩
model  = MyModel().to(device)
x      = torch.randn(1, 3, 224, 224).to(device)

# AscendCL 내부 처리:
# 1. PyTorch Op → GE 그래프로 변환
# 2. 그래프 컴파일 → DaVinci ISA
# 3. /dev/davinci0 ioctl로 커널 드라이버 전달
# 4. DaVinci Core에서 3D Cube 연산 실행
output = model(x)

커널 드라이버 현황

드라이버 공개 범위 (2025 기준):
  • 비공개: Ascend 메인 드라이버 (ascend_drv.ko, davinci_manager.ko) — Huawei 배포 바이너리
  • 부분 공개: drivers/char/hisi_acc_qm.c, drivers/crypto/hisilicon/ — 암호화 가속기는 mainline
  • 오픈소스: torch_npu (GitHub), MindSpore (오픈소스 AI 프레임워크)
  • 제약 요인: 미국 수출 규제로 인한 독립 개발 경로 → mainline 기여 일부 차단
# Atlas 200I DK (개발 키트)에서의 추론 예제
# .om 파일 = Ascend 오프라인 모델 (atc 컴파일러 출력)

# 1. ONNX → Ascend .om 변환
atc --model=resnet50.onnx \
    --framework=5 \
    --output=resnet50 \
    --input_shape="input:1,3,224,224" \
    --soc_version=Ascend310P3

# 2. .om 모델 추론 실행
python3 acl_run.py --model resnet50.om

# 커널 DMA 흐름:
# CPU 메모리 → DMA → HBM2e (가중치/입력)
# DaVinci Core 연산 → HBM2e (출력)
# DMA → CPU 메모리 (결과 수집)

NPU 전원 관리

NPU는 항상 활성 상태일 필요가 없으므로, Runtime PM을 통한 공격적인 전원 관리가 중요합니다. 특히 노트북/모바일 SoC에서는 추론이 없을 때 NPU를 완전히 꺼서 전력을 절약합니다.

static int my_npu_runtime_suspend(struct device *dev)
{
    struct my_npu_device *ndev = dev_get_drvdata(dev);

    my_npu_wait_idle(ndev);               /* 잡 완료 대기 */
    my_npu_mmu_save_state(ndev);           /* MMU 컨텍스트 저장 */
    clk_disable_unprepare(ndev->clk);     /* 클럭 게이팅 */
    my_npu_power_off(ndev);                /* 전원 도메인 OFF */
    return 0;
}

static int my_npu_runtime_resume(struct device *dev)
{
    struct my_npu_device *ndev = dev_get_drvdata(dev);
    int ret;

    my_npu_power_on(ndev);                 /* 전원 ON */
    clk_prepare_enable(ndev->clk);         /* 클럭 활성화 */

    ret = my_npu_load_firmware(ndev);       /* FW 재로딩 */
    if (ret)
        return ret;

    my_npu_mmu_restore_state(ndev);        /* MMU 복원 */
    return 0;
}

static const struct dev_pm_ops my_npu_pm_ops = {
    SET_RUNTIME_PM_OPS(my_npu_runtime_suspend,
                       my_npu_runtime_resume, NULL)
    SET_SYSTEM_SLEEP_PM_OPS(my_npu_system_suspend,
                            my_npu_system_resume)
};
DVFS (Dynamic Voltage and Frequency Scaling): NPU 워크로드 강도에 따라 동적으로 클럭 주파수와 전압을 조절합니다. 가벼운 추론(이미지 분류)은 낮은 OPP(Operating Performance Point)로, 대규모 LLM 추론은 최고 OPP로 실행하여 전력 효율을 극대화합니다.

NPU와 DMA-BUF: 디바이스 간 버퍼 공유

DMA-BUF를 통해 NPU, GPU, 카메라(ISP), 비디오 디코더 간에 제로카피 버퍼 공유가 가능합니다. 이는 카메라 → NPU → GPU → 디스플레이 같은 ML 파이프라인에서 중요한 역할을 합니다.

Camera ISP 프레임 캡처 DMA-BUF NPU 객체 검출 추론 DMA-BUF GPU 바운딩 박스 오버레이 DMA-BUF Display (KMS) 화면 출력 공유 물리 메모리 (DMA-BUF) CPU 복사 없이 디바이스 간 직접 접근 (제로카피)
/* NPU에서 DMA-BUF 익스포트 (exporter 역할) */
static struct dma_buf *
my_npu_gem_prime_export(struct drm_gem_object *obj, int flags)
{
    struct dma_buf_export_info exp_info = {
        .exp_name  = "my_npu",
        .owner     = obj->dev->driver->fops->owner,
        .ops       = &my_npu_dmabuf_ops,
        .size      = obj->size,
        .flags     = flags,
        .priv      = obj,
    };
    return drm_gem_dmabuf_export(obj->dev, &exp_info);
}

/* GPU에서 NPU의 DMA-BUF를 임포트 (importer 역할) */
struct drm_gem_object *
gpu_gem_prime_import(struct drm_device *dev,
                     struct dma_buf *dma_buf)
{
    struct dma_buf_attachment *attach;
    struct sg_table *sgt;

    attach = dma_buf_attach(dma_buf, dev->dev);
    if (IS_ERR(attach))
        return ERR_CAST(attach);

    sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
    if (IS_ERR(sgt)) {
        dma_buf_detach(dma_buf, attach);
        return ERR_CAST(sgt);
    }

    /* sg_table을 GPU 페이지 테이블에 매핑
     * → NPU가 쓴 결과를 GPU가 직접 읽기 가능 */
    return gpu_create_gem_from_sgt(dev, sgt, dma_buf->size);
}
심화 학습: CPU-GPU-NPU 간 메모리를 동일한 가상 주소로 공유하고 자동 마이그레이션하는 HMM(Heterogeneous Memory Management)은 HMM (이기종 메모리 관리) 페이지에서 자세히 다룹니다.

NPU 커널 설정 (Kconfig)

# DRM Accel 기본 지원
CONFIG_DRM=m                       # DRM 코어 (필수)
CONFIG_DRM_ACCEL=y                 # Accel 서브시스템 활성화

# Intel NPU (IVPU)
CONFIG_DRM_ACCEL_IVPU=m            # Intel VPU/NPU 드라이버

# Intel Gaudi (habanalabs)
CONFIG_DRM_ACCEL_HABANALABS=m      # Gaudi/Gaudi2/Gaudi3

# AMD XDNA (Ryzen AI)
CONFIG_DRM_ACCEL_AMDXDNA=m         # AMD XDNA NPU

# Qualcomm Cloud AI
CONFIG_DRM_ACCEL_QAIC=m            # Qualcomm AIC100

# 공통 의존성
CONFIG_DRM_GEM_SHMEM_HELPER=m      # GEM shmem 헬퍼
CONFIG_DRM_SCHED=m                 # GPU/NPU 스케줄러
CONFIG_DMA_SHARED_BUFFER=y         # DMA-BUF (디바이스 간 공유)
CONFIG_FW_LOADER=y                 # 펌웨어 로더 (필수)
CONFIG_IOMMU_API=y                 # IOMMU 지원

NPU 디버깅

sysfs / debugfs 인터페이스

# Accel 디바이스 확인
ls -la /dev/accel/
ls -la /sys/class/accel/

# Intel NPU debugfs
cat /sys/kernel/debug/accel/0/info
cat /sys/kernel/debug/accel/0/fw_version
cat /sys/kernel/debug/accel/0/busy_time_us
cat /sys/kernel/debug/accel/0/freq

# Runtime PM 상태 확인
cat /sys/class/accel/accel0/device/power/runtime_status

# HW 센서 (hwmon)
cat /sys/class/accel/accel0/device/hwmon/*/temp1_input
cat /sys/class/accel/accel0/device/hwmon/*/power1_input

# AMD XDNA sysfs
cat /sys/class/accel/accel0/device/npu_clk_freq
cat /sys/class/accel/accel0/device/npu_power_state

NPU 디버깅 도구

도구용도사용법
dmesgNPU 드라이버 로그dmesg | grep -i "ivpu\|npu\|accel\|xdna"
lspci -vvvNPU PCI 디바이스 정보lspci -d ::0x1200 -vvv (Processing Accel class)
ftraceDRM/Accel 내부 추적echo drm:* > /sys/kernel/debug/tracing/set_event
perf드라이버 성능 분석perf record -a -g -e drm:* -- sleep 5
Intel NPU PluginOpenVINO 통합 프로파일링OpenVINO benchmark_app + NPU 플러그인
xrt-smiAMD XDNA 모니터링Xilinx Runtime CLI (xrt-smi examine)

NPU 유저 공간 소프트웨어 스택

NPU 드라이버는 커널에서 HW 접근과 메모리 관리만 담당하고, 실제 ML 모델 컴파일/실행은 유저 공간 스택이 처리합니다.

계층Intel NPUAMD XDNAQualcomm Cloud AI
ML 프레임워크 OpenVINO, ONNX Runtime ONNX Runtime, PyTorch Qualcomm AI Engine Direct
컴파일러 NPU Compiler (VPUX) Vitis AI / XDNA Compiler QNN SDK
UMD (런타임) intel-npu-acceleration-library XRT (Xilinx Runtime) libqaic
KMD (커널) ivpu (drivers/accel/ivpu/) amdxdna (drivers/accel/amdxdna/) qaic (drivers/accel/qaic/)
NPU 추론 실행 예시 (OpenVINO + Intel NPU):
# 1. 모델 벤치마크
benchmark_app -m model.onnx -d NPU -hint latency

# 2. Python API로 추론
import openvino as ov

core = ov.Core()
model = core.compile_model("model.onnx", "NPU")
result = model.infer_new_request({"input": input_data})

참고 사항

커널 소스 참고 경로:
  • drivers/gpu/drm/ — DRM 코어 + 모든 GPU 드라이버
  • drivers/accel/ — DRM Accel (NPU/AI 가속기 드라이버)
  • drivers/accel/ivpu/ — Intel NPU (IVPU) 드라이버
  • drivers/accel/habanalabs/ — Intel Gaudi 드라이버
  • drivers/accel/amdxdna/ — AMD XDNA NPU 드라이버
  • drivers/accel/qaic/ — Qualcomm Cloud AI 100 드라이버
  • include/drm/ — DRM 헤더 파일
  • include/drm/drm_accel.h — Accel 서브시스템 API
  • include/uapi/drm/ — 유저 공간 API (ioctl, 구조체)
  • include/uapi/drm/ivpu_accel.h — Intel NPU ioctl 정의
  • drivers/dma-buf/ — DMA-BUF 프레임워크
  • Documentation/gpu/ — 커널 공식 GPU 문서
  • Documentation/accel/ — Accel 서브시스템 문서
NPU 드라이버 개발 시 주의사항:
  • Fence 시그널링 규칙dma_fence는 반드시 유한 시간 내에 시그널되어야 합니다. 무한 대기 fence는 시스템 전체를 교착시킬 수 있습니다
  • 메모리 매핑 주의 — NPU 메모리를 WC(Write-Combining)로 매핑할 때 캐시 일관성에 주의. ioremap_wc() 사용
  • NPU 전원 관리 — NPU는 유휴 시 Runtime PM으로 완전 전원 차단을 권장. 펌웨어 재로딩 비용과 절전 효과의 트레이드오프 고려
  • 펌웨어 로딩 — 최신 NPU는 대부분 request_firmware()로 마이크로코드를 로딩합니다. initramfs에 펌웨어 포함 필요 (CONFIG_EXTRA_FIRMWARE)
  • DMA-BUF 공유 — NPU ↔ GPU ↔ ISP 간 제로카피 버퍼 공유 시 디바이스 간 캐시 일관성 보장 필요 (CPU 캐시 플러시)
  • NPU MMU와 IOMMU — NPU 자체 MMU와 시스템 IOMMU는 별개. 두 단계 변환이 모두 적용되므로 디버깅 시 주소 변환 경로 추적 필수

이 주제와 관련된 다른 문서를 더 깊이 이해하고 싶다면 다음을 참고하세요.