USB 서브시스템 심화

USB 서브시스템을 프로토콜 계층, 컨트롤러 드라이버, 사용자 공간 인터페이스까지 통합 관점으로 심층 분석합니다. USB Core와 URB 흐름, EHCI/XHCI host controller 동작, enumeration과 descriptor 파싱, class driver 작성 패턴, Gadget/UDC 기반 디바이스 에뮬레이션, Type-C/PD 및 USB4/Thunderbolt 연동, autosuspend/runtime PM 정책, usbmon·tracepoint·wireshark를 활용한 패킷 디버깅까지 실전 제품 개발과 장애 분석에 필요한 내용을 폭넓게 다룹니다.

전제 조건: 디바이스 드라이버인터럽트 문서를 먼저 읽으세요. 버스/열거/프로브 경로는 초기화 순서와 자원 등록 규칙이 핵심이므로, 장치 발견부터 바인딩까지 흐름을 먼저 고정해야 합니다.
일상 비유: 이 주제는 터미널 입출고 게이트 운영과 비슷합니다. 차량(디바이스)이 들어오면 게이트 규칙(버스 규약)에 맞춰 배정하고 점검하듯이, 드라이버도 바인딩 규약을 정확히 따라야 합니다.

핵심 요약

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

단계별 이해

  1. 장치 수명주기 확인
    probe부터 remove까지 흐름을 점검합니다.
  2. 비동기 경로 설계
    IRQ, 워크큐, 타이머 역할을 분리합니다.
  3. 자원 정합성 검증
    DMA/클록/전원 참조를 교차 확인합니다.
  4. 현장 조건 테스트
    연결 끊김/복구/부하 상황을 재현합니다.
관련 표준: USB 2.0 Specification, USB 3.2 Specification, USB4 Specification, USB Type-C Specification, USB Power Delivery Specification — Linux USB 서브시스템이 구현하는 버스 프로토콜 규격입니다.

USB 개요

USB (Universal Serial Bus)는 1996년 Intel, Compaq, Microsoft 등이 공동으로 제안한 범용 직렬 버스 규격입니다. 키보드, 마우스부터 외장 스토리지, 네트워크 어댑터, 비디오 캡처 장치까지 거의 모든 주변기기의 사실상 표준 인터페이스로 자리 잡았습니다. Linux 커널은 USB 서브시스템을 통해 호스트 컨트롤러 관리, 디바이스 열거, 드라이버 바인딩, 전원 관리를 통합적으로 처리합니다.

USB Device Descriptor / Endpoint HCD (xHCI/EHCI) URB 스케줄링 USB Core / Driver Enumeration + Binding

USB 버전 발전

규격연도최대 속도인코딩커넥터
USB 1.019961.5 Mbps (Low Speed)NRZIType-A/B
USB 1.1199812 Mbps (Full Speed)NRZIType-A/B
USB 2.02000480 Mbps (High Speed)NRZIType-A/B, Mini, Micro
USB 3.020085 Gbps (SuperSpeed)8b/10bType-A (청색), Type-B SS, Micro-B SS
USB 3.1201310 Gbps (SuperSpeed+)128b/132bType-C
USB 3.2201720 Gbps (2x2 레인)128b/132bType-C 전용
USB4201940 Gbps (Gen 3x2)PAM3 (64b/66b)Type-C 전용
USB4 v2.0202280 Gbps (Gen 4)PAM3Type-C 전용
USB4와 Thunderbolt: USB4는 Thunderbolt 3 프로토콜을 기반으로 하며, PCIe 터널링과 DisplayPort Alt Mode를 지원합니다. Linux 커널의 Thunderbolt 드라이버(drivers/thunderbolt/)가 USB4 호스트 컨트롤러도 함께 관리합니다.

프로토콜 계층 구조

USB 통신은 다음과 같은 계층으로 구성됩니다:

계층역할주요 요소
Client Software클래스/벤더 드라이버, 유저스페이스 앱usb_driver, libusb
USB System SoftwareUSB Core, 디바이스 열거, 대역폭 관리usb_device, usb_bus
USB Host Controller하드웨어 트랜잭션 스케줄링, 데이터 전송xHCI, EHCI, OHCI, UHCI
USB Bus Interface전기/물리 시그널링, 패킷 인코딩차동 시그널링, NRZI/8b10b

USB 프로토콜 기초

디스크립터 계층

USB 디바이스는 자신의 기능을 디스크립터(Descriptor) 계층 구조로 기술합니다. 호스트는 열거(Enumeration) 과정에서 이 디스크립터를 읽어 적절한 드라이버를 바인딩합니다:

Device Descriptor (1개) Configuration Descriptor (1개 이상) Interface Descriptor (1개 이상) Endpoint (0개 이상) Class-Specific (선택) Interface Association (복합 디바이스) String Descriptor (선택) 포함 포함 연관 포함 확장 참조
디스크립터bDescriptorType핵심 필드설명
Device0x01idVendor, idProduct, bDeviceClass디바이스 전체 정보, VID/PID로 드라이버 매칭
Configuration0x02bNumInterfaces, bMaxPower전원 특성, 인터페이스 구성
Interface0x04bInterfaceClass/SubClass/Protocol기능 단위, 클래스 드라이버 매칭 기준
Endpoint0x05bEndpointAddress, bmAttributes, wMaxPacketSize데이터 파이프 정의, 전송 타입/방향/크기
/* 커널 내부: USB Device Descriptor 구조체 */
/* include/uapi/linux/usb/ch9.h */
struct usb_device_descriptor {
    __u8  bLength;             /* 18 */
    __u8  bDescriptorType;     /* USB_DT_DEVICE (0x01) */
    __le16 bcdUSB;             /* USB 규격 버전 (BCD: 0x0200 = USB 2.0) */
    __u8  bDeviceClass;        /* 디바이스 클래스 (0x00이면 인터페이스 레벨) */
    __u8  bDeviceSubClass;
    __u8  bDeviceProtocol;
    __u8  bMaxPacketSize0;     /* EP0 최대 패킷 크기 (8/16/32/64) */
    __le16 idVendor;           /* Vendor ID */
    __le16 idProduct;          /* Product ID */
    __le16 bcdDevice;          /* 디바이스 릴리즈 번호 */
    __u8  iManufacturer;       /* 제조사 문자열 인덱스 */
    __u8  iProduct;            /* 제품명 문자열 인덱스 */
    __u8  iSerialNumber;       /* 시리얼 번호 문자열 인덱스 */
    __u8  bNumConfigurations;  /* Configuration 수 */
} __attribute__ ((packed));

전송 타입

USB는 4가지 전송 타입을 정의하며, 각각 다른 특성과 용도를 가집니다:

전송 타입특성대역폭 보장오류 재전송용도
Control양방향, 셋업+데이터+상태 단계예약됨 (10~20%)디바이스 설정, 디스크립터 읽기, 벤더 요청
Bulk대용량, 잔여 대역폭 사용없음 (잔여 사용)Mass Storage, 프린터, 네트워크 데이터
Interrupt소량, 폴링 주기 보장예약됨키보드, 마우스, 조이스틱, HID
Isochronous실시간, 일정 대역폭예약됨없음오디오, 비디오, 웹캠
Endpoint 방향: Endpoint 주소의 비트 7이 방향을 나타냅니다. 0x81은 IN (디바이스 → 호스트) Endpoint 1, 0x02는 OUT (호스트 → 디바이스) Endpoint 2입니다. Endpoint 0(EP0)은 항상 양방향 Control 전송에 사용됩니다.

열거 (Enumeration) 과정

USB 디바이스가 연결되면 호스트는 다음 순서로 디바이스를 인식합니다:

  1. 연결 감지 — Hub가 포트 상태 변경을 인터럽트로 호스트에 통보
  2. 포트 리셋 — 호스트가 해당 포트에 USB Reset 시그널 전송 (SE0, 10~50ms)
  3. 속도 감지 — D+/D- 풀업 저항 위치로 Low/Full/High Speed 결정
  4. 기본 주소 할당 — 디바이스는 주소 0으로 응답, 호스트가 SET_ADDRESS(1~127) 전송
  5. 디스크립터 읽기 — GET_DESCRIPTOR로 Device, Configuration, Interface, Endpoint 정보 수집
  6. Configuration 선택 — SET_CONFIGURATION으로 활성 Configuration 설정
  7. 드라이버 바인딩 — 커널이 VID/PID 또는 클래스 코드 기반으로 적합한 드라이버를 probe

Linux USB Core

Linux USB Core(drivers/usb/core/)는 호스트 컨트롤러와 디바이스 드라이버 사이의 중간 계층으로, 디바이스 열거, URB 관리, 전원 관리, 드라이버 매칭을 담당합니다.

핵심 자료구조

구조체헤더역할
struct usb_bus<linux/usb.h>USB 버스 인스턴스, HCD와 1:1 대응
struct usb_device<linux/usb.h>USB 디바이스 인스턴스 (디스크립터, 상태, 파이프 정보)
struct usb_interface<linux/usb.h>인터페이스 단위 — 드라이버가 바인딩하는 대상
struct usb_host_config<linux/usb.h>Configuration Descriptor 파싱 결과
struct usb_host_interface<linux/usb.h>Interface Descriptor + Endpoint 배열
struct usb_host_endpoint<linux/usb.h>Endpoint Descriptor + URB 큐
/* struct usb_device 주요 필드 (simplified) */
/* include/linux/usb.h */
struct usb_device {
    int                     devnum;          /* 버스 내 디바이스 주소 (1~127) */
    char                    devpath[16];     /* sysfs 경로 문자열 */
    enum usb_device_state   state;           /* 연결 상태 */
    enum usb_device_speed   speed;           /* Low/Full/High/Super/Super+ */

    struct usb_device_descriptor descriptor;  /* Device Descriptor 사본 */
    struct usb_host_config  *config;         /* 모든 Configuration 배열 */
    struct usb_host_config  *actconfig;      /* 현재 활성 Configuration */

    struct usb_host_endpoint ep0;            /* Endpoint 0 (Control) */
    struct usb_host_endpoint *ep_in[16];     /* IN Endpoint 배열 */
    struct usb_host_endpoint *ep_out[16];    /* OUT Endpoint 배열 */

    struct usb_device       *parent;         /* 부모 Hub (Root Hub는 NULL) */
    struct usb_bus          *bus;            /* 소속 버스 */
    struct device           dev;             /* 범용 디바이스 모델 */

    int                     maxchild;        /* Hub인 경우 하위 포트 수 */
    unsigned                can_submit:1;    /* URB 제출 가능 여부 */
    /* ... */
};
/* struct usb_interface — 드라이버가 bind하는 단위 */
struct usb_interface {
    struct usb_host_interface *altsetting;    /* Alternate Setting 배열 */
    struct usb_host_interface *cur_altsetting; /* 현재 활성 설정 */
    unsigned                num_altsetting;  /* Alternate Setting 개수 */

    struct usb_interface_cache *intf_cache;
    struct device           dev;             /* 디바이스 모델 (드라이버 바인딩 대상) */
    int                     minor;           /* USB minor 번호 (-1 = 미사용) */
    /* ... */
};
Interface vs Device: USB 드라이버는 usb_device 전체가 아니라 usb_interface에 바인딩됩니다. 하나의 USB 디바이스가 여러 인터페이스를 가질 수 있고, 각 인터페이스에 서로 다른 드라이버가 바인딩될 수 있습니다 (예: CDC-ACM은 Control + Data 두 개의 인터페이스를 가집니다).

USB 스택 내부 구조

USB Core의 자료구조는 계층적으로 연결됩니다. usb_bus는 호스트 컨트롤러에 1:1 대응하고, 그 아래에 usb_device가 트리 형태로 구성됩니다. 각 usb_device는 하나 이상의 usb_interface를 가지며, 인터페이스에는 데이터 전송을 위한 usb_host_endpoint가 연결됩니다.

USB Core 자료구조 계층 struct usb_bus HCD 1:1 대응, 버스 번호, Root Hub 포인터 struct usb_device (Root Hub) devnum=1, parent=NULL, speed, state struct usb_device (Dev N) descriptor, actconfig, ep0, ep_in[], ep_out[] struct usb_device (Dev M) 같은 버스의 다른 디바이스 struct usb_interface [0] 드라이버 바인딩 대상, cur_altsetting struct usb_interface [1] 복합 디바이스의 두 번째 IF usb_host_endpoint EP 0x81 (Bulk IN) usb_host_endpoint EP 0x02 (Bulk OUT) 범례 usb_bus (HCD) usb_device (물리 장치) usb_interface (바인딩 단위) usb_host_endpoint (데이터 파이프)

디바이스 열거 내부 흐름

디바이스 연결 시 USB Core 내부에서 수행되는 열거(Enumeration) 과정의 핵심 함수 호출 순서입니다. Hub 드라이버의 hub_event()가 포트 변경 감지를 시작으로 전체 열거를 주도합니다:

/* drivers/usb/core/hub.c — 디바이스 열거 내부 흐름 */

/* 1. Hub 인터럽트 URB가 포트 상태 변경 감지 */
hub_irq()
  → kick_hub_wq()            /* Hub 이벤트 워크큐 스케줄 */

/* 2. 워크큐에서 hub_event() 실행 */
hub_event()
  → port_event()             /* 각 포트의 상태 변경 처리 */hub_port_connect_change()
      → hub_port_init()       /* 포트 리셋 + 속도 감지 */hub_set_address()    /* SET_ADDRESS(1~127) */usb_get_device_descriptor() /* 64바이트 Device Descriptor */usb_new_device()       /* 디바이스 등록 시작 */

/* 3. usb_new_device() 상세 */
usb_new_device(struct usb_device *udev)
{
    usb_enumerate_device(udev);
      → usb_get_configuration()    /* 모든 Configuration Descriptor 읽기 */usb_parse_configuration() /* Interface/Endpoint 파싱 */usb_get_string()           /* 제조사/제품명 문자열 */

    usb_choose_configuration(udev); /* 최적 Configuration 자동 선택 */
    usb_set_configuration(udev, config_num);

    device_add(&udev->dev);         /* 디바이스 모델 등록 → probe 트리거 */
}

디스크립터 파싱과 Configuration 선택

usb_parse_configuration()은 호스트가 GET_DESCRIPTOR로 수신한 원시 바이트 스트림을 파싱하여 커널 자료구조로 변환합니다. Configuration Descriptor를 기준으로 하위 Interface/Endpoint를 순차적으로 파싱합니다:

/* drivers/usb/core/config.c — Configuration 파싱 핵심 로직 */

/* usb_parse_configuration()이 처리하는 디스크립터 순서:
 *   Configuration Descriptor (bDescriptorType=0x02)
 *     └─ Interface Association Descriptor (IAD, 0x0B) — 복합 디바이스용
 *     └─ Interface Descriptor (0x04)
 *        └─ Class-Specific Descriptor (클래스별)
 *        └─ Endpoint Descriptor (0x05)
 *           └─ SS Endpoint Companion (0x30) — USB 3.x
 *           └─ SSP Isoc Endpoint Companion (0x31) — USB 3.1+
 */

/* Configuration 자동 선택 기준 (usb_choose_configuration) */
/*
 * 1. bNumInterfaces가 가장 많은 Configuration 우선
 * 2. 첫 Interface의 bInterfaceClass가 벤더 전용(0xFF)이 아닌 것 우선
 * 3. 위 조건이 같으면 첫 번째 Configuration 선택
 * 4. USB 허브는 항상 Configuration 1 선택
 *
 * 드라이버가 직접 선택하려면:
 *   usb_driver_set_configuration(udev, config_value);
 */
Alternate Setting: 하나의 인터페이스가 여러 Alternate Setting을 가질 수 있습니다. 예를 들어 USB 오디오 장치는 Alternate 0에서는 대역폭 0(유휴), Alternate 1에서 오디오 스트리밍용 Isochronous Endpoint를 활성화합니다. usb_set_interface(udev, ifnum, alt)로 전환합니다.

USB 드라이버 모델

드라이버 골격

#include <linux/module.h>
#include <linux/usb.h>

#define MY_VENDOR_ID   0x1234
#define MY_PRODUCT_ID  0x5678

struct my_usb_dev {
    struct usb_device    *udev;       /* USB 디바이스 */
    struct usb_interface  *intf;       /* 바인딩된 인터페이스 */
    unsigned char        *bulk_in_buf; /* Bulk IN 수신 버퍼 */
    size_t               bulk_in_size;
    __u8                 bulk_in_ep;  /* Bulk IN endpoint 주소 */
    __u8                 bulk_out_ep; /* Bulk OUT endpoint 주소 */
};

static int my_usb_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
{
    struct usb_device *udev = interface_to_usbdev(intf);
    struct usb_host_interface *iface_desc;
    struct usb_endpoint_descriptor *ep;
    struct my_usb_dev *dev;
    int i;

    iface_desc = intf->cur_altsetting;

    /* private 데이터 할당 */
    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    if (!dev)
        return -ENOMEM;

    dev->udev = usb_get_dev(udev);
    dev->intf = intf;

    /* Endpoint 탐색 */
    for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
        ep = &iface_desc->endpoint[i].desc;

        if (usb_endpoint_is_bulk_in(ep)) {
            dev->bulk_in_size = usb_endpoint_maxp(ep);
            dev->bulk_in_ep = ep->bEndpointAddress;
            dev->bulk_in_buf = kmalloc(dev->bulk_in_size,
                                       GFP_KERNEL);
        }
        if (usb_endpoint_is_bulk_out(ep))
            dev->bulk_out_ep = ep->bEndpointAddress;
    }

    usb_set_intfdata(intf, dev);

    dev_info(&intf->dev, "USB device probed: %04x:%04x\\n",
             le16_to_cpu(udev->descriptor.idVendor),
             le16_to_cpu(udev->descriptor.idProduct));
    return 0;
}

static void my_usb_disconnect(struct usb_interface *intf)
{
    struct my_usb_dev *dev = usb_get_intfdata(intf);

    usb_set_intfdata(intf, NULL);
    usb_put_dev(dev->udev);
    kfree(dev->bulk_in_buf);
    kfree(dev);

    dev_info(&intf->dev, "USB device disconnected\\n");
}

/* USB Device ID 테이블 — 드라이버가 지원하는 디바이스 목록 */
static const struct usb_device_id my_usb_ids[] = {
    { USB_DEVICE(MY_VENDOR_ID, MY_PRODUCT_ID) },
    { }  /* 종료 마커 */
};
MODULE_DEVICE_TABLE(usb, my_usb_ids);

static struct usb_driver my_usb_driver = {
    .name       = "my_usb",
    .id_table   = my_usb_ids,
    .probe      = my_usb_probe,
    .disconnect = my_usb_disconnect,
};
module_usb_driver(my_usb_driver);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Example USB driver");

USB ID 매칭 매크로

매크로매칭 기준
USB_DEVICE(vendor, product)Vendor + Product ID
USB_DEVICE_VER(vendor, product, lo, hi)+ bcdDevice 범위
USB_DEVICE_INTERFACE_CLASS(vend, prod, cl)+ Interface Class
USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr)+ Interface Protocol
USB_INTERFACE_INFO(cl, sc, pr)Interface Class/SubClass/Protocol
USB_DEVICE_INFO(cl, sc, pr)Device Class/SubClass/Protocol

드라이버 라이프사이클

USB 드라이버 라이프사이클 디바이스 연결 hub_event()/usb_new_device() 디스크립터 파싱 device_add() bus_probe_device() usb_device_match() usb_probe_interface() driver->probe() 정상 동작 분리 시: usb_disconnect()/device_del()

드라이버 매칭/바인딩 상세

USB Core의 usb_device_match()는 등록된 usb_driverid_table과 디바이스의 디스크립터 정보를 비교하여 적합한 드라이버를 찾습니다. 매칭이 성공하면 usb_probe_interface()를 거쳐 드라이버의 probe()가 호출됩니다.

USB 드라이버 매칭/바인딩 흐름 device_add(&intf->dev) bus_probe_device() usb_device_match() id_table 순회: VID/PID, Class/SubClass/Protocol 비교 Match Flags USB_DEVICE_ID_MATCH_VENDOR USB_DEVICE_ID_MATCH_PRODUCT USB_DEVICE_ID_MATCH_INT_CLASS USB_DEVICE_ID_MATCH_INT_PROTOCOL usb_probe_interface() driver->probe(intf, id) 분리 시 (Disconnect) 1. usb_unbind_interface() 2. driver->disconnect(intf) 3. usb_disable_interface() 4. device_del(&intf->dev) 5. usb_release_interface() 순서 중요: URB 취소 후 리소스 해제 수행 리셋 콜백 pre_reset(intf) post_reset(intf) 디바이스 리셋 전후 호출

매칭 플래그(match_flags)usb_device_id 구조체의 어떤 필드를 비교할지 결정합니다. USB_DEVICE() 매크로는 Vendor/Product ID만 비교하고, USB_INTERFACE_INFO()는 클래스/서브클래스/프로토콜을 비교합니다. 여러 플래그를 OR 조합하면 더 세밀한 매칭이 가능합니다.

분리(Disconnect) 처리 순서가 중요합니다. 드라이버의 disconnect() 콜백이 호출되기 전에 usb_unbind_interface()가 인터페이스를 비활성화하며, disconnect() 내에서 반드시 진행 중인 URB를 usb_kill_urb()로 취소하고, 할당된 리소스를 해제해야 합니다. pre_reset()/post_reset() 콜백은 usb_reset_device() 호출 시 디바이스 리셋 전후에 드라이버 상태를 저장/복원할 기회를 제공합니다.

/* disconnect 및 pre_reset/post_reset 콜백 패턴 */

static void my_usb_disconnect(struct usb_interface *intf)
{
    struct my_usb_dev *dev = usb_get_intfdata(intf);

    /* 1. 인터페이스 데이터 클리어 (재진입 방지) */
    usb_set_intfdata(intf, NULL);

    /* 2. 진행 중인 URB 모두 취소 (동기적으로 대기) */
    usb_kill_urb(dev->int_urb);
    usb_kill_urb(dev->bulk_urb);

    /* 3. 유저스페이스 인터페이스 해제 */
    usb_deregister_dev(intf, &my_class);

    /* 4. 리소스 해제 */
    usb_free_urb(dev->int_urb);
    usb_put_dev(dev->udev);
    kfree(dev);
}

/* pre_reset: 디바이스 리셋 직전 호출 */
static int my_pre_reset(struct usb_interface *intf)
{
    struct my_usb_dev *dev = usb_get_intfdata(intf);
    /* URB 중지, 상태 저장 */
    usb_kill_urb(dev->bulk_urb);
    return 0;
}

/* post_reset: 디바이스 리셋 완료 후 호출 */
static int my_post_reset(struct usb_interface *intf)
{
    struct my_usb_dev *dev = usb_get_intfdata(intf);
    /* 엔드포인트 재확인, URB 재제출 */
    usb_submit_urb(dev->bulk_urb, GFP_NOIO);
    return 0;
}

URB (USB Request Block)

URB (USB Request Block)은 USB 드라이버가 데이터를 전송하기 위해 USB Core에 제출하는 요청 단위입니다. 네트워크의 sk_buff, 블록 I/O의 bio에 해당하는 USB 서브시스템의 핵심 자료구조입니다.

struct urb 주요 필드

/* include/linux/usb.h */
struct urb {
    struct list_head       urb_list;        /* HCD 내부 리스트 */
    struct usb_device      *dev;            /* 대상 디바이스 */
    unsigned int           pipe;            /* 파이프 (endpoint + 방향 + 타입) */
    int                    status;          /* 완료 상태 (0=성공) */
    unsigned int           transfer_flags;  /* URB 플래그 */
    void                   *transfer_buffer; /* 데이터 버퍼 (kmalloc) */
    dma_addr_t             transfer_dma;    /* DMA 주소 (선택) */
    u32                    transfer_buffer_length; /* 버퍼 크기 */
    u32                    actual_length;   /* 실제 전송된 바이트 수 */
    unsigned char          *setup_packet;   /* Control 전송용 SETUP 패킷 */
    int                    interval;        /* Interrupt/Isoc 폴링 간격 */
    int                    number_of_packets; /* Isoc 패킷 수 */
    struct usb_iso_packet_descriptor iso_frame_desc[]; /* Isoc 프레임 */
    usb_complete_t         complete;        /* 완료 콜백 함수 */
    void                   *context;        /* 콜백 컨텍스트 */
    /* ... */
};

URB 라이프사이클

단계함수설명
1usb_alloc_urb()URB 할당
2usb_fill_*_urb()전송 타입별 필드 초기화
3usb_submit_urb()USB Core/HCD 큐에 제출
4HCD 처리하드웨어 전송 수행
5complete()완료 콜백 실행 (인터럽트 컨텍스트)
6usb_free_urb()참조 카운트 기반 해제

URB 초기화 헬퍼

/* Bulk 전송 URB 초기화 */
static void usb_fill_bulk_urb(
    struct urb *urb,
    struct usb_device *dev,
    unsigned int pipe,           /* usb_sndbulkpipe() / usb_rcvbulkpipe() */
    void *transfer_buffer,
    int buffer_length,
    usb_complete_t complete_fn,
    void *context);

/* Interrupt 전송 URB 초기화 */
static void usb_fill_int_urb(
    struct urb *urb,
    struct usb_device *dev,
    unsigned int pipe,
    void *transfer_buffer,
    int buffer_length,
    usb_complete_t complete_fn,
    void *context,
    int interval);              /* 폴링 간격 (ms 또는 microframes) */

/* Control 전송 URB 초기화 */
static void usb_fill_control_urb(
    struct urb *urb,
    struct usb_device *dev,
    unsigned int pipe,
    unsigned char *setup_packet,  /* 8바이트 SETUP 데이터 */
    void *transfer_buffer,
    int buffer_length,
    usb_complete_t complete_fn,
    void *context);

비동기 Bulk 전송 예제

static void my_bulk_complete(struct urb *urb)
{
    struct my_usb_dev *dev = urb->context;

    if (urb->status) {
        if (urb->status == -ENOENT ||
            urb->status == -ECONNRESET ||
            urb->status == -ESHUTDOWN) {
            /* URB 취소됨 — 정상적인 종료 */
            return;
        }
        dev_err(&dev->intf->dev,
                "bulk read failed: %d\\n", urb->status);
        return;
    }

    /* 수신 데이터 처리 */
    dev_info(&dev->intf->dev,
             "received %d bytes\\n", urb->actual_length);

    /* 연속 수신을 위해 URB 재제출 */
    usb_submit_urb(urb, GFP_ATOMIC);
}

static int my_start_bulk_read(struct my_usb_dev *dev)
{
    struct urb *urb;
    int ret;

    urb = usb_alloc_urb(0, GFP_KERNEL);
    if (!urb)
        return -ENOMEM;

    usb_fill_bulk_urb(urb, dev->udev,
        usb_rcvbulkpipe(dev->udev, dev->bulk_in_ep),
        dev->bulk_in_buf,
        dev->bulk_in_size,
        my_bulk_complete,
        dev);

    ret = usb_submit_urb(urb, GFP_KERNEL);
    if (ret) {
        dev_err(&dev->intf->dev,
                "failed to submit URB: %d\\n", ret);
        usb_free_urb(urb);
    }
    return ret;
}

동기 전송 래퍼

간단한 전송에는 URB를 직접 관리하지 않고 동기 래퍼를 사용할 수 있습니다:

/* 동기 Bulk 전송 */
int actual_len;
int ret = usb_bulk_msg(dev->udev,
    usb_rcvbulkpipe(dev->udev, dev->bulk_in_ep),
    dev->bulk_in_buf,
    dev->bulk_in_size,
    &actual_len,
    5000);  /* 타임아웃 (ms) */

/* 동기 Control 전송 */
ret = usb_control_msg(dev->udev,
    usb_sndctrlpipe(dev->udev, 0),
    0x09,                        /* bRequest: SET_CONFIGURATION */
    USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
    1,                           /* wValue */
    0,                           /* wIndex */
    NULL,                        /* data */
    0,                           /* size */
    5000);                       /* 타임아웃 (ms) */

/* 동기 Interrupt 전송 */
ret = usb_interrupt_msg(dev->udev,
    usb_rcvintpipe(dev->udev, dev->int_in_ep),
    dev->int_buf, dev->int_buf_size,
    &actual_len, 5000);
주의: usb_bulk_msg(), usb_control_msg() 같은 동기 API는 내부에서 wait_for_completion()을 호출하므로 인터럽트 컨텍스트나 URB 완료 콜백 내에서 사용하면 안 됩니다. 이런 경우에는 비동기 URB를 사용해야 합니다.

파이프(Pipe) 매크로

매크로용도
usb_sndctrlpipe(dev, ep)Control OUT 파이프
usb_rcvctrlpipe(dev, ep)Control IN 파이프
usb_sndbulkpipe(dev, ep)Bulk OUT 파이프
usb_rcvbulkpipe(dev, ep)Bulk IN 파이프
usb_sndintpipe(dev, ep)Interrupt OUT 파이프
usb_rcvintpipe(dev, ep)Interrupt IN 파이프
usb_sndisocpipe(dev, ep)Isochronous OUT 파이프
usb_rcvisocpipe(dev, ep)Isochronous IN 파이프

Host Controller Driver (HCD)

HCD(Host Controller Driver)는 USB 호스트 컨트롤러 하드웨어를 직접 제어하는 최하위 계층 드라이버입니다. USB Core가 제출한 URB를 하드웨어 트랜잭션으로 변환하여 실행합니다.

호스트 컨트롤러 종류

HCD규격USB 속도특징커널 드라이버
UHCIIntelUSB 1.x (LS/FS)소프트웨어 스케줄링, CPU 부하 높음uhci-hcd
OHCICompaq/Microsoft/NSCUSB 1.x (LS/FS)하드웨어 스케줄링, 임베디드 주력ohci-hcd
EHCIIntelUSB 2.0 (HS)Companion Controller(UHCI/OHCI)와 쌍ehci-hcd
xHCIIntelUSB 1.x ~ 3.x모든 속도 통합, 스트림 지원xhci-hcd
xHCI 통합: xHCI(eXtensible Host Controller Interface)는 USB 1.x/2.0/3.x 전 속도를 단일 컨트롤러로 지원합니다. EHCI와 달리 Companion Controller가 필요 없으며, 현대 시스템의 표준 HCD입니다.

struct hc_driver

/* include/linux/usb/hcd.h */
struct hc_driver {
    const char  *description;
    const char  *product_desc;
    size_t      hcd_priv_size;   /* HCD private 데이터 크기 */

    /* HCD 생명주기 */
    int  (*reset)(struct usb_hcd *hcd);
    int  (*start)(struct usb_hcd *hcd);
    void (*stop)(struct usb_hcd *hcd);
    void (*shutdown)(struct usb_hcd *hcd);

    /* URB 관리 */
    int  (*urb_enqueue)(struct usb_hcd *hcd,
                        struct urb *urb, gfp_t mem_flags);
    int  (*urb_dequeue)(struct usb_hcd *hcd,
                        struct urb *urb, int status);

    /* Root Hub 조작 */
    int  (*hub_status_data)(struct usb_hcd *hcd,
                            char *buf);
    int  (*hub_control)(struct usb_hcd *hcd,
                        u16 typeReq, u16 wValue,
                        u16 wIndex, char *buf,
                        u16 wLength);

    /* Endpoint 관리 */
    void (*endpoint_reset)(struct usb_hcd *hcd,
                           struct usb_host_endpoint *ep);
    void (*endpoint_disable)(struct usb_hcd *hcd,
                            struct usb_host_endpoint *ep);
    /* ... */
};

xHCI 내부 구조

xHCI는 링 버퍼(Ring) 기반의 명령/전송 메커니즘을 사용합니다:

링 타입방향용도
Command RingSW → HWSlot 활성화/비활성화, Endpoint 구성, 주소 할당
Event RingHW → SW명령 완료, 전송 완료, 포트 상태 변경 알림
Transfer RingSW → HW데이터 전송 요청 (Endpoint별 1개)
xHCI 메모리 구조 (DMA 메모리) Device Context Base Address Array [0] Scratchpad Buffer Pointer [1] → Slot 1 Device Context [2] → Slot 2 Device Context ... Device Context (Slot N) Slot Context (디바이스 상태, 주소) EP 0 Context (Control) + Transfer Ring EP 1 OUT Context + Transfer Ring EP 1 IN Context + Transfer Ring ... (최대 EP 30 OUT/IN) Command Ring 호스트→xHC 명령 (Enable Slot 등) Event Ring xHC→호스트 이벤트 (완료, 오류 등) Transfer Ring 동작 원리 • TRB(Transfer Request Block) 단위로 구성 — Normal/Setup/Status/Link TRB • Enqueue Pointer(SW 쓰기) / Dequeue Pointer(xHC 읽기) 로 링 관리 • Doorbell Register 쓰기로 xHC에 새 TRB 알림 • 완료 시 Event Ring에 Transfer Event TRB 생성 → 드라이버 인터럽트 처리

xHCI Transfer Ring / Event Ring 상세

xHCI의 Transfer Ring과 Event Ring은 호스트 메모리(DMA 가능 영역)에 TRB(Transfer Request Block) 배열로 구성됩니다. 각 TRB는 16바이트 크기이며, Enqueue Pointer(소프트웨어 쓰기 위치)와 Dequeue Pointer(하드웨어 읽기 위치)로 링을 관리합니다.

xHCI Transfer Ring / Event Ring 구조 Transfer Ring (Endpoint별 1개) Setup TRB Data TRB Status TRB Normal TRB Normal TRB Link TRB Link → 링 시작으로 순환 Enqueue Pointer (SW) 소프트웨어가 새 TRB를 쓰는 위치 Dequeue Pointer (xHC) 하드웨어가 다음 처리할 TRB 위치 Cycle Bit: Producer/Consumer 동기화 Doorbell Register 쓰기 → xHC 전송 시작 Event Ring (Interrupter별 1개) Transfer Event TRB Command Compl. TRB Port Status TRB 기타 Event TRB Event Ring Segment Table (ERST) Ring Base Address + Ring Size 엔트리 다중 세그먼트로 확장 가능 Dequeue Pointer (SW) 드라이버가 처리 완료한 위치 기록 Enqueue Pointer (xHC) 하드웨어가 새 이벤트를 쓰는 위치 MSI-X 인터럽트 → ISR에서 이벤트 폴링 주요 TRB 타입 (Type ID) Normal (1): Bulk/Interrupt 데이터 전송 | Setup (2): Control SETUP 단계 | Data (3): Control DATA 단계 Status (4): Control STATUS 단계 | Isoch (5): Isochronous 전송 | Link (6): 링 세그먼트 연결 No-Op (8): 빈 TRB | Enable Slot (9): 슬롯 활성화 | Disable Slot (10): 슬롯 비활성화 Address Device (11): 주소 할당 | Configure EP (12): 엔드포인트 구성 | Evaluate Context (13): 컨텍스트 갱신

xHCI 레지스터 맵

xHCI 호스트 컨트롤러는 PCI BAR0에 매핑된 MMIO 레지스터 공간을 4개 영역으로 구분합니다. 각 영역은 오프셋 기반으로 접근하며, Capability 레지스터에서 각 영역의 시작 오프셋을 읽습니다:

영역오프셋 결정주요 레지스터용도
CapabilityBAR0 + 0x00CAPLENGTH, HCSPARAMS1/2/3, HCCPARAMS1/2컨트롤러 성능/한계 정보 (읽기 전용)
OperationalBAR0 + CAPLENGTHUSBCMD, USBSTS, DNCTRL, CRCR, DCBAAP, CONFIG컨트롤러 제어, DCBAA/Command Ring 설정
RuntimeBAR0 + RTSOFFIMAN, IMOD, ERSTSZ, ERSTBA, ERDP (Interrupter별)인터럽트 관리, Event Ring 설정
DoorbellBAR0 + DBOFFDB[0] (Command), DB[1..MAX_SLOTS] (EP별)xHC에 새 작업 알림
/* drivers/usb/host/xhci.h — xHCI 레지스터 접근 (간략) */

/* Capability 레지스터에서 오프셋 추출 */
u32 cap_length = readl(&xhci->cap_regs->hc_capbase) & 0xFF;
u32 rts_offset = readl(&xhci->cap_regs->run_regs_off) & ~0x1F;
u32 db_offset  = readl(&xhci->cap_regs->db_off) & ~0x3;

/* Operational 레지스터 */
xhci->op_regs = (void *)xhci->cap_regs + cap_length;
writel(CMD_RUN, &xhci->op_regs->command);   /* 컨트롤러 시작 */

/* Doorbell 레지스터로 xHC에 새 TRB 알림 */
xhci->dba = (void *)xhci->cap_regs + db_offset;
writel(ep_index, &xhci->dba->doorbell[slot_id]); /* EP별 doorbell */
/* xHCI 대역폭 스케줄링 개요 */
/*
 * xHCI는 USB 2.0(Microframe 기반)과 USB 3.x(Service Interval 기반)
 * 의 대역폭을 각각 독립적으로 스케줄링합니다.
 *
 * Periodic (Interrupt/Isochronous) 엔드포인트 추가 시:
 * 1. Add Endpoint Command → xHC가 대역폭 계산
 * 2. 부족하면 Bandwidth Error (Completion Code 34) 반환
 * 3. 성공하면 Configure Endpoint Command로 확정
 *
 * USB 3.x Streams (Bulk 전용):
 * - 하나의 Bulk EP에 여러 Stream ID → 각각 독립 Transfer Ring
 * - UAS(USB Attached SCSI)에서 명령 큐잉에 활용
 * - xhci_alloc_streams() / xhci_free_streams() 로 관리
 */

USB Gadget Framework

USB Gadget Framework는 Linux 시스템을 USB 디바이스 (Function)로 동작하게 하는 프레임워크입니다. 임베디드 시스템, SBC(Single Board Computer), 스마트폰 등에서 호스트에 연결될 때 다양한 USB 기능(Mass Storage, Ethernet, Serial 등)을 제공합니다.

Gadget 아키텍처

계층역할예시
Gadget Function DriverUSB 클래스 기능 구현f_mass_storage, f_ecm, f_acm, f_hid
Composite Framework여러 Function을 하나의 Configuration으로 합성usb_composite_driver
UDC (USB Device Controller)디바이스 컨트롤러 하드웨어 제어dwc3, musb, cdns3, fotg210
USB Gadget 스택 구조 Gadget Function Drivers f_mass_storage f_ecm (NIC) f_acm (UART) f_hid / f_uvc 사용자 정의... Composite Framework usb_composite_driver — 여러 기능 합성, Config/Interface 관리 USB Gadget API usb_gadget_driver / usb_ep_ops — HAL 인터페이스 UDC Driver dwc3 / musb / cdns3 / chipidea — 플랫폼별 컨트롤러 드라이버 USB Device Controller Hardware

ConfigFS Gadget

ConfigFS를 통해 유저스페이스에서 USB Gadget을 동적으로 구성할 수 있습니다. 커널 모듈 재컴파일 없이 USB 디바이스 기능을 조합합니다:

# ConfigFS USB Gadget 생성 예제: CDC ECM (Ethernet) + ACM (Serial)

# 1. Gadget 디렉토리 생성
cd /sys/kernel/config/usb_gadget
mkdir my_gadget && cd my_gadget

# 2. 디바이스 디스크립터 설정
echo 0x1d6b > idVendor     # Linux Foundation
echo 0x0104 > idProduct    # Multifunction Composite Gadget
echo 0x0100 > bcdDevice
echo 0x0200 > bcdUSB

# 3. 영문 문자열 설정
mkdir strings/0x409
echo "0123456789" > strings/0x409/serialnumber
echo "Linux"      > strings/0x409/manufacturer
echo "My Gadget"  > strings/0x409/product

# 4. Configuration 생성
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "ECM + ACM" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower   # 500mA (USB 2.0 단위: 2mA)

# 5. Function 인스턴스 생성
mkdir functions/ecm.usb0           # CDC ECM (Ethernet)
mkdir functions/acm.GS0            # CDC ACM (Serial)

# 6. Function을 Configuration에 링크
ln -s functions/ecm.usb0 configs/c.1/
ln -s functions/acm.GS0  configs/c.1/

# 7. UDC에 바인딩 (활성화)
ls /sys/class/udc                  # 사용 가능한 UDC 확인
echo "fe980000.usb" > UDC          # UDC 이름 기록 → 호스트에 연결됨

# 비활성화
echo "" > UDC

FunctionFS

FunctionFS는 USB Gadget Function의 로직을 유저스페이스에서 구현할 수 있게 하는 파일시스템입니다. 커널 드라이버 없이 사용자 정의 USB 프로토콜을 구현할 수 있습니다:

/* 유저스페이스 FunctionFS 사용 예제 (간략) */
#include <linux/usb/functionfs.h>

/* 1. FunctionFS 마운트 */
/* mount -t functionfs my_func /dev/ffs-my_func */

/* 2. ep0에 디스크립터 기록 */
int ep0_fd = open("/dev/ffs-my_func/ep0", O_RDWR);
write(ep0_fd, &descriptors, sizeof(descriptors));
write(ep0_fd, &strings, sizeof(strings));

/* 3. Endpoint 파일 열기 */
int ep1_fd = open("/dev/ffs-my_func/ep1", O_RDWR);  /* Bulk IN */
int ep2_fd = open("/dev/ffs-my_func/ep2", O_RDWR);  /* Bulk OUT */

/* 4. 데이터 송수신 */
read(ep2_fd, buf, sizeof(buf));   /* Bulk OUT에서 수신 */
write(ep1_fd, buf, len);           /* Bulk IN으로 송신 */

USB 클래스 드라이버

USB 클래스 드라이버는 USB-IF가 정의한 표준 디바이스 클래스를 구현합니다. VID/PID에 무관하게 클래스 코드만으로 드라이버가 매칭됩니다.

HID (Human Interface Device)

속성
Interface Class0x03
전송 타입Interrupt (IN/OUT)
커널 드라이버usbhid (drivers/hid/usbhid/)
디바이스 예시키보드, 마우스, 게임패드, 터치스크린
/* HID Report Descriptor 파싱 흐름 */
/* drivers/hid/usbhid/hid-core.c */
usbhid_probe()
  → hid_parse()            /* HID Report Descriptor 파싱 */hid_hw_start()         /* Input 디바이스 등록 */usb_fill_int_urb()     /* Interrupt IN URB 설정 */usb_submit_urb()       /* 입력 이벤트 수신 시작 */

Mass Storage

속성
Interface Class0x08
SubClass0x06 (SCSI transparent)
Protocol0x50 (Bulk-Only Transport, BOT)
전송 타입Bulk (IN + OUT)
커널 드라이버usb-storage, uas (UASP)
USB Mass Storage BOT 전송 순서 Host Device 1) CBW (31B) 전송 2) Data 단계 (IN 또는 OUT, 선택) 3) CSW (13B) 수신 CBW 필드: Signature(0x43425355), Tag, DataLength, Flags(IN/OUT), LUN, CDB Length, CDB(16B)
UAS (USB Attached SCSI): USB 3.0부터 지원되는 UAS(UASP) 프로토콜은 BOT 대비 명령 큐잉, 스트림 지원, 낮은 레이턴시로 성능이 크게 향상됩니다. 커널의 uas 드라이버(drivers/usb/storage/uas.c)가 담당합니다.

CDC (Communications Device Class)

서브클래스용도커널 드라이버호스트측 인터페이스
ACM (Abstract Control Model)가상 시리얼 포트cdc-acm/dev/ttyACM*
ECM (Ethernet Control Model)Ethernet 어댑터cdc_ethereth* / usb*
NCM (Network Control Model)고성능 Ethernet (USB 3.0+)cdc_ncmeth* / usb*
EEM (Ethernet Emulation Model)가상 Ethernet (Control IF 없음)cdc_eemusb*
MBIM모바일 광대역 (LTE/5G)cdc_mbimwwan*

Audio Class

속성
Interface Class0x01
전송 타입Isochronous (오디오 스트림), Interrupt (MIDI)
커널 드라이버snd-usb-audio (sound/usb/)
디바이스 예시USB 헤드셋, DAC, 마이크, MIDI 컨트롤러
USB 오디오 오프로드 (v6.16+): 커널 6.16에서 USB 오디오에 오프로드 모드가 추가되었습니다. 오디오 DSP/코프로세서가 USB 오디오 스트림을 직접 처리하여, 메인 CPU가 오디오 데이터 전송에 관여하지 않습니다. 이를 통해 모바일 기기에서 USB DAC 사용 시 전력 소모를 줄이고, CPU를 절전 상태로 유지할 수 있습니다. Qualcomm SoC의 ADSP(Audio DSP)와 연동하는 구현이 포함되어 있습니다.

주요 USB 클래스 코드

Class이름예시
0x01AudioUSB 사운드 카드, 마이크
0x02CDC (Communications)모뎀, Ethernet, 시리얼
0x03HID키보드, 마우스, 게임패드
0x06Still Image디지털 카메라 (PTP)
0x07PrinterUSB 프린터
0x08Mass StorageUSB 메모리, 외장 하드
0x09HubUSB 허브
0x0ACDC-DataCDC 데이터 인터페이스
0x0EVideo웹캠, 비디오 캡처
0xE0Wireless ControllerBluetooth 어댑터
0xEFMiscellaneousIAD(Interface Association)
0xFEApplication SpecificDFU (Device Firmware Upgrade)
0xFFVendor Specific벤더 전용 프로토콜

HID Report Descriptor 파싱 흐름

HID(Human Interface Device) 드라이버는 디바이스가 제공하는 Report Descriptor를 파싱하여 입력/출력 필드를 자동으로 매핑합니다. Report Descriptor는 바이트 스트림으로 인코딩된 계층적 구조이며, Global/Local/Main 아이템으로 구성됩니다.

HID Report Descriptor 파싱 흐름 GET_DESCRIPTOR (HID Report, Type=0x22) 바이트 스트림 수신 0x05 0x01 0x09 0x06 ... hid_parse_report() 아이템 단위 파싱 HID Item 타입 Global Items Usage Page, Logical Min/Max, Report Size/Count Local Items Usage, Usage Min/Max, Designator Main Items Input, Output, Feature, Collection, End Collection 파싱 결과: struct hid_device report_enum[HID_INPUT_REPORT]: Input 리포트 목록 report_enum[HID_OUTPUT_REPORT]: Output 리포트 목록 각 Report → hid_field[] → hid_usage[] Usage → input_dev 이벤트 매핑 (EV_KEY, EV_REL 등) hid_input_report() → input_event() → 유저스페이스 전달 Input 서브시스템 연동 hid_hw_start() → hid_connect() → hidinput_connect(): input_dev 등록 → hidraw_connect(): /dev/hidraw* 생성 Interrupt IN URB 수신 → hid_input_report() → extract_field() → input_event() 전달
/* HID Report Descriptor 바이트 예제: USB 키보드 (간략) */
/*
 * 0x05, 0x01,       // Usage Page (Generic Desktop)
 * 0x09, 0x06,       // Usage (Keyboard)
 * 0xA1, 0x01,       // Collection (Application)
 *   0x05, 0x07,     //   Usage Page (Key Codes)
 *   0x19, 0xE0,     //   Usage Minimum (Left Control)
 *   0x29, 0xE7,     //   Usage Maximum (Right GUI)
 *   0x15, 0x00,     //   Logical Minimum (0)
 *   0x25, 0x01,     //   Logical Maximum (1)
 *   0x75, 0x01,     //   Report Size (1 bit)
 *   0x95, 0x08,     //   Report Count (8 modifiers)
 *   0x81, 0x02,     //   Input (Data, Variable, Absolute) → 8 modifier bits
 *   0x95, 0x06,     //   Report Count (6 keys)
 *   0x75, 0x08,     //   Report Size (8 bits each)
 *   0x19, 0x00,     //   Usage Minimum (0)
 *   0x29, 0xFF,     //   Usage Maximum (255)
 *   0x81, 0x00,     //   Input (Data, Array) → 6 key codes
 * 0xC0              // End Collection
 *
 * → 총 8바이트 Report: [Modifiers(1B)] [Reserved(1B)] [Key1..Key6(6B)]
 * → usbhid-dump으로 실제 디바이스의 Report Descriptor 확인 가능
 */

UAS (USB Attached SCSI) 프로토콜

UAS는 USB 3.0 이상에서 Mass Storage의 BOT(Bulk-Only Transport)를 대체하는 고성능 프로토콜입니다. xHCI의 Streams 기능을 활용하여 하나의 Bulk Endpoint에 여러 독립 스트림을 할당하고, 명령 큐잉과 비순차 완료를 지원합니다:

특성BOT (Bulk-Only Transport)UAS (USB Attached SCSI)
명령 큐잉불가 (한 번에 1개 명령)가능 (최대 32+ 큐 깊이)
완료 순서순차 (FIFO)비순차 (Out-of-Order)
Endpoint 수2개 (Bulk IN + OUT)4개 (Command/Status/Data IN/OUT)
xHCI Streams미사용활용 (Stream ID = Tag)
오버헤드CBW/CSW 31+13 바이트IU 헤더 8~16 바이트
성능 향상기준~20~40% IOPS 향상 (랜덤 I/O 기준)

CDC 변형 비교: ACM/ECM/NCM/MBIM

CDC(Communications Device Class)는 다양한 하위 모델을 정의합니다. 각 변형은 다른 프레이밍과 집적(aggregation) 방식을 사용하여 네트워크 성능과 호환성에 큰 차이가 있습니다:

CDC 변형SubClass데이터 프레이밍패킷 집적최대 성능주요 용도
ACM0x02시리얼 스트림없음~10 MbpsAT 모뎀, 디버그 콘솔
ECM0x06Ethernet 프레임 (1:1)없음~200 MbpsUSB 2.0 Ethernet 어댑터
NCM0x0DNTB (Network Transfer Block)다중 프레임 집적~900 MbpsUSB 3.0+ 고성능 NIC
MBIM0x0ENCM 기반 + 제어 채널다중 프레임 집적~1 GbpsLTE/5G 모뎀
EEM0x0CEEM 패킷 캡슐화가능~200 MbpsControl IF 불필요 장치
/* NCM vs ECM 성능 차이의 핵심: NTB (Network Transfer Block) */
/*
 * ECM: USB 전송 1회 = Ethernet 프레임 1개
 *   → USB 전송 오버헤드가 패킷마다 발생
 *
 * NCM: USB 전송 1회 = NTB 1개 = 다수의 Ethernet 프레임 포함
 *   NTB 구조:
 *   ┌─────────────┬──────────────┬──────────────┬────────┐
 *   │ NTH (12B)   │ NDP (가변)   │ Datagram 1   │ Dgram 2│
 *   │ dwSignature │ wNdpIndex    │ (Eth Frame)  │ ...    │
 *   │ wBlockLen   │ Pointer Tbl  │              │        │
 *   └─────────────┴──────────────┴──────────────┴────────┘
 *   NTH: NTB Header, NDP: NTB Datagram Pointer
 *   최대 NTB 크기: 16KB (USB 2.0) ~ 65535B (USB 3.x)
 *
 * 결과: NCM은 USB 전송 1회로 수십 개 패킷을 보내
 *       프로토콜 오버헤드를 크게 줄입니다.
 */

USB Type-C와 Power Delivery

USB Type-C는 단순한 커넥터 규격을 넘어 전원 공급(PD), 대체 모드(Alt Mode), 역할 전환(DRP) 등 복잡한 기능을 제공합니다. Linux 커널은 Type-C 서브시스템을 통해 이를 관리합니다.

Type-C 서브시스템

구성 요소역할커널 경로
typec coreType-C 포트/파트너/케이블 모델링drivers/usb/typec/
UCSIUSB Type-C Connector System Software Interfacedrivers/usb/typec/ucsi/
TCPMType-C Port Manager (PD 상태 머신)drivers/usb/typec/tcpm/
tcpciType-C Port Controller Interface 드라이버drivers/usb/typec/tcpm/tcpci.c
Alt Mode driversDisplayPort, TBT3 등 대체 모드drivers/usb/typec/altmodes/

PD (Power Delivery) 협상

USB PD는 Type-C CC(Configuration Channel) 라인을 통해 전원 협상을 수행합니다:

PD 버전최대 전력전압 범위
USB 2.0/3.0 기본4.5W (5V/900mA)5V 고정
USB Type-C 기본15W (5V/3A)5V 고정
PD 2.0/3.0100W (20V/5A)5V, 9V, 15V, 20V
PD 3.1 (EPR)240W (48V/5A)최대 48V (Extended Power Range)
USB PD 협상 흐름 Source (전원 공급) Sink (전원 수신) Source_Capabilities (PDO 목록) Request (원하는 PDO 선택) Accept PS_RDY (전압/전류 전환 완료) 전원 계약 체결 완료 PDO 타입: Fixed, Variable, Battery, PPS, AVS(PD 3.1 EPR)
# sysfs에서 Type-C 정보 확인
ls /sys/class/typec/

# 포트 정보
cat /sys/class/typec/port0/data_role         # [host] device
cat /sys/class/typec/port0/power_role        # [source] sink
cat /sys/class/typec/port0/preferred_role    # sink / source / none
cat /sys/class/typec/port0/port_type         # dual / source / sink

# 연결된 파트너 정보
cat /sys/class/typec/port0-partner/type      # UFP / DFP
cat /sys/class/typec/port0-partner/usb_power_delivery/
ls /sys/class/typec/port0-partner/identity/  # VDM ID 정보

# 역할 전환 (DRP 포트)
echo "device" > /sys/class/typec/port0/data_role
echo "sink"   > /sys/class/typec/port0/power_role

Type-C CC 라인 감지와 방향 결정

USB Type-C 커넥터는 CC1/CC2(Configuration Channel) 핀을 통해 연결 감지, 방향 결정, 역할 협상을 수행합니다. Source 측은 Rp(풀업), Sink 측은 Rd(풀다운) 저항을 연결하며, CC 라인의 전압 레벨로 연결 상태와 전류 공급 능력을 판단합니다.

Type-C CC 라인 감지 및 방향 결정 Source (DFP / 전원 공급) CC1 ──── Rp (풀업 → VCONN 또는 VBUS) CC2 ──── Rp (풀업 → VCONN 또는 VBUS) Rp 전류 광고 (CC 전압 레벨) Default USB (500/900mA): Rp = 56kΩ → ~0.4V 1.5A: Rp = 22kΩ → ~0.66V 3.0A: Rp = 10kΩ → ~1.23V PD 사용 시: CC 라인으로 PD 메시지 통신 Sink (UFP / 전원 수신) CC1 ──── Rd (풀다운, 5.1kΩ → GND) CC2 ──── Rd (풀다운, 5.1kΩ → GND) CC 라인으로 결정되는 정보 1. 연결 감지: Rp-Rd 분압 전압 변화 2. 방향(Orientation): CC1 또는 CC2 활성 3. 전류 능력: Rp 값으로 판단 4. 케이블 타입: Ra(1kΩ)=전자마크 케이블 CC 라인 플러그 방향(Orientation) 감지 정방향 삽입 (Normal) CC1 활성 (Rp-Rd 연결) → 데이터 TX/RX 핀 매핑 CC2: VCONN (전자마크 케이블 전원) 또는 미연결 SBU1/SBU2: Alt Mode 신호 (DP AUX 등) 역방향 삽입 (Flipped) CC2 활성 (Rp-Rd 연결) → 핀 크로스 매핑 MUX가 SS 데이터 라인 방향 전환 Type-C PHY가 자동으로 처리

PD 협상 상태 머신

USB PD(Power Delivery)의 전원 협상은 CC 라인을 통한 메시지 교환으로 이루어집니다. TCPM(Type-C Port Manager)이 PD 상태 머신을 구현하며, Source와 Sink 간 PDO(Power Data Object) 교환을 통해 최적의 전원 계약을 체결합니다.

PD 협상 상태 머신 (Source → Sink) SRC_STARTUP VBUS 5V 공급 시작 SRC_DISCOVERY Source_Capabilities 전송 SRC_NEGOTIATE Request 수신 + 평가 SRC_TRANSITION 전압 전환 중 SRC_READY 전원 계약 완료 (PS_RDY) PDO (Power Data Object) 형식 — 32비트 Fixed Supply Type[31:30]=00 전압(50mV단위), 전류(10mA) 5V/9V/15V/20V 고정 Variable Supply Type[31:30]=10 최소/최대 전압 범위 가변 전원 공급 PPS (APDO) Type[31:30]=11, Sub=0 20mV 단위 전압 조절 50mA 단위 전류 제한 AVS (APDO) Type[31:30]=11, Sub=1 PD 3.1 EPR 전용 15~48V, 최대 5A (240W) EPR (PD 3.1) Extended Power Range 28V/36V/48V 고정 추가 EPR_Source/Sink_Cap 별도 TCPM (Type-C Port Manager) drivers/usb/typec/tcpm/tcpm.c PD 상태 머신 전체 구현 (~4000줄) TCPC(Port Controller) 하드웨어 추상화 VDM(Vendor Defined Message) 처리 Alt Mode 진입/탈출 관리 UCSI (Connector System SW Interface) drivers/usb/typec/ucsi/ucsi.c 펌웨어 기반 Type-C 관리 인터페이스 ACPI/PCI 백엔드 (플랫폼 의존) Command/Notification 모델 PPM(Platform Policy Manager) 위임

UCSI 명령/알림 모델

UCSI(USB Type-C Connector System Software Interface)는 인텔이 표준화한 펌웨어 기반 Type-C 관리 인터페이스입니다. 운영체제(OPM)가 플랫폼 정책 관리자(PPM)에게 명령을 보내고, PPM이 CC 감지와 PD 협상을 자체 처리한 뒤 알림으로 결과를 보고합니다:

/* drivers/usb/typec/ucsi/ucsi.c — UCSI 명령 인터페이스 */

/* UCSI 주요 명령 (Command) */
enum ucsi_command {
    UCSI_PPM_RESET          = 0x01,  /* PPM 초기화 */
    UCSI_CANCEL             = 0x02,  /* 진행 중인 명령 취소 */
    UCSI_CONNECTOR_RESET    = 0x03,  /* 특정 커넥터 리셋 */
    UCSI_ACK_CC_CI          = 0x04,  /* 알림 확인 응답 */
    UCSI_SET_NOTIFICATION_ENABLE = 0x05, /* 알림 활성화 */
    UCSI_GET_CAPABILITY     = 0x06,  /* PPM 성능 조회 */
    UCSI_GET_CONNECTOR_CAPABILITY = 0x07,
    UCSI_SET_UOM            = 0x08,  /* USB Operation Mode 설정 */
    UCSI_SET_PDR            = 0x0B,  /* Power Direction Role 설정 */
    UCSI_GET_PDOS           = 0x10,  /* PDO 목록 조회 */
    UCSI_GET_CONNECTOR_STATUS = 0x12, /* 커넥터 상태 조회 */
};

typec connector class API

커널의 typec 클래스는 Type-C 포트, 파트너, 케이블을 sysfs에 등록하고 유저스페이스에 노출합니다. TCPM이나 UCSI 드라이버가 이 API를 호출하여 상태를 업데이트합니다:

/* drivers/usb/typec/class.c — Connector Class API (간략) */

/* 1. 포트 등록 */
struct typec_port *port = typec_register_port(dev, &cap);
/* cap: typec_capability 구조체 — 역할, 전압, Alt Mode 등 */

/* 2. 파트너 연결 시 */
struct typec_partner *partner = typec_register_partner(port, &desc);
/* desc: 파트너 정보 — UFP/DFP, USB PD 버전, Identity */

/* 3. 상태 업데이트 */
typec_set_data_role(port, TYPEC_HOST);     /* DFP */
typec_set_pwr_role(port, TYPEC_SOURCE);    /* Source */
typec_set_orientation(port, TYPEC_ORIENTATION_NORMAL);

/* 4. PD 계약 등록 */
struct usb_power_delivery *pd;
pd = usb_power_delivery_register(dev, &pd_desc);
typec_port_set_usb_power_delivery(port, pd);

/* 5. 분리 시 */
typec_unregister_partner(partner);
typec_unregister_port(port);
PD 3.1 EPR(Extended Power Range): PD 3.1은 기존 20V/5A(100W) 한계를 넘어 28V, 36V, 48V 고정 전압과 AVS(Adjustable Voltage Supply)를 추가하여 최대 240W까지 지원합니다. EPR 진입에는 Source와 Sink 모두 EPR 지원을 선언하고, 전자마크(E-Marked) 케이블이 EPR 레이팅을 보고해야 합니다. 커널의 TCPM은 SRC_EPR_KEEP_ALIVE 상태를 통해 EPR 세션을 유지합니다.

Thunderbolt / USB4

Thunderbolt은 Intel이 개발한 고속 인터커넥트 기술로, PCIe와 DisplayPort를 단일 케이블로 터널링합니다. USB4는 Thunderbolt 3 프로토콜을 USB-IF가 공개 표준으로 채택한 것이며, Linux 커널에서는 동일한 drivers/thunderbolt/ 드라이버가 Thunderbolt 1~4와 USB4를 모두 관리합니다.

용어 정리: Intel은 Thunderbolt 3 프로토콜 사양을 USB-IF에 기증했고, 이것이 USB4 1.0이 되었습니다. Thunderbolt 4는 USB4의 인증 프로그램이며, Thunderbolt 5(2024)는 USB4 v2.0 기반에 Intel 독자 확장(120 Gbps 대역폭 공유)을 추가한 버전입니다.

세대별 비교

세대연도최대 대역폭프로토콜커넥터PCIe 터널링데이지 체인
Thunderbolt 120112×10 GbpsPCIe 2.0 + DPMini DisplayPortPCIe 2.0 ×4최대 6대
Thunderbolt 2201320 Gbps (채널 결합)PCIe 2.0 + DP 1.2Mini DisplayPortPCIe 2.0 ×4최대 6대
Thunderbolt 3201540 GbpsPCIe 3.0 + DP 1.2/1.4USB Type-CPCIe 3.0 ×4최대 6대
USB4 1.0201940 Gbps (Gen 3×2)PCIe + DP 터널링USB Type-C선택적트리 토폴로지
Thunderbolt 4202040 GbpsUSB4 + Intel 인증USB Type-CPCIe 3.0 ×4 (32 Gbps 필수)허브를 통한 트리
USB4 v2.0202280 Gbps (Gen 4)PCIe + DP 2.1 터널링USB Type-C선택적트리 토폴로지
Thunderbolt 5202480/120 Gbps (PAM-3)USB4 v2.0 + 대역폭 공유USB Type-CPCIe 4.0 ×4 (64 Gbps)트리 토폴로지

아키텍처: 터널링과 어댑터

Thunderbolt/USB4의 핵심 개념은 터널링입니다. 단일 물리 링크 위에 여러 프로토콜을 동시에 멀티플렉싱합니다:

Thunderbolt / USB4 링크 아키텍처 Physical Layer (USB Type-C) 40 Gbps (Gen 3x2) / 80 Gbps (Gen 4), lane bonding Transport Layer (터널링) PCIe Tunnel DP Tunnel USB3 Tunnel DMA/Host Adapter Layer (Router 내부) Lane / DP / USB3 / PCIe / Protocol(DMA) Adapter 각 어댑터가 터널 endpoint로 동작 대역폭 분배 예 (40 Gbps 링크) DP 17.28 Gbps + PCIe 약 22 Gbps + USB3 10 Gbps 유휴 터널 대역폭은 동적으로 재할당(QoS 기반)

라우터(Router)는 Thunderbolt/USB4 토폴로지의 핵심 구성 요소입니다. 각 장치(호스트, 허브, 도크)에 하나 이상의 라우터가 있으며, 라우터에는 여러 어댑터(Adapter)가 연결됩니다:

어댑터 유형역할커널 표현
Lane Adapter물리 링크 관리, 레인 본딩struct tb_port (type=1)
PCIe Down/Up AdapterPCIe 터널의 송/수신 엔드포인트struct tb_port (type=PCIe)
DP IN/OUT AdapterDisplayPort 터널 엔드포인트struct tb_port (type=DP)
USB3 Down/Up AdapterUSB 3.x 터널 엔드포인트struct tb_port (type=USB3)
Protocol Adapter (DMA)호스트 메모리 DMA, 네트워킹struct tb_port (type=DMA)

토폴로지와 라우팅

Thunderbolt/USB4 토폴로지와 라우팅 Host Router Router A (Dock) PCIe → NVMe SSD DP → Monitor Router B (eGPU) PCIe Adapter → GPU 고대역폭 compute/render Router C (Hub) USB3 Adapter → USB Hub 다중 다운스트림 분기 Route String 라우팅 64-bit route string 사용 각 홉마다 포트 번호 인코딩 최대 7홉 깊이 TBT3/USB4 공통 개념 경로 계산 후 tunnel/path 구성 USB4 트리 토폴로지 데이지 체인보다 허브 중심 분기 한 포트당 하나의 직접 연결 터널별 독립 대역폭 정책 CM이 전체 토폴로지 관리 hotplug 시 경로 재계산

Linux 커널 Thunderbolt 드라이버

커널의 Thunderbolt 드라이버(drivers/thunderbolt/)는 Thunderbolt 1~4와 USB4를 통합 관리합니다:

파일역할
tb.c코어 로직, 연결 관리자(Connection Manager) 구현
switch.c라우터(스위치) 초기화, 열거(enumeration)
tunnel.cPCIe/DP/USB3/DMA 터널 생성 및 관리
path.c터널 경로(path) 설정, 홉 구성
nhi.cNative Host Interface — 호스트 컨트롤러 PCIe 드라이버
ctl.c컨트롤 채널 (라우터 간 통신, 설정 공간 읽기/쓰기)
icm.cIntel Connection Manager (펌웨어 기반 CM)
usb4.cUSB4 전용 레지스터/오퍼레이션
usb4_port.cUSB4 포트 관리, 링크 재훈련
xdomain.c크로스 도메인(peer-to-peer) 디스커버리, 서비스 프로토콜
eeprom.c디바이스 ROM (DROM) 파싱 — 장치 ID 정보
dma_port.cDMA 포트 기반 NVM(Non-Volatile Memory) 펌웨어 업데이트
retimer.cUSB4 리타이머 펌웨어 업데이트
clx.cCL0s/CL1/CL2 링크 절전 상태 관리

연결 관리자 (Connection Manager)

Thunderbolt/USB4에서 연결 관리자(CM)는 터널 생성, 대역폭 할당, 보안 정책을 결정하는 핵심 컴포넌트입니다. Linux에는 두 가지 CM이 있습니다:

CM 유형설명사용 조건
ICM (Intel CM)인텔 펌웨어 기반 CM. 커널은 펌웨어에 메시지를 보내 터널 생성을 요청Thunderbolt 1~3 (Alpine/Titan Ridge)
Software CM커널이 직접 라우터 설정 공간을 제어하여 터널 생성USB4 호스트, Ice Lake+, Apple Silicon
/* drivers/thunderbolt/tb.c — Software CM의 핵심 구조 */
static const struct tb_cm_ops tb_cm_ops = {
    .start             = tb_start,
    .stop              = tb_stop,
    .suspend_noirq     = tb_suspend_noirq,
    .resume_noirq      = tb_resume_noirq,
    .handle_event      = tb_handle_event,
    .disapprove_switch = tb_disconnect_and_release_dp,
    .approve_switch    = tb_tunnel_pci,
    .approve_xdomain_paths = tb_approve_xdomain_paths,
    .runtime_suspend   = tb_runtime_suspend,
    .runtime_resume    = tb_runtime_resume,
};

/* Software CM 디바이스 연결 시 터널 생성 흐름 */
/*
 * 1. NHI가 Hotplug 이벤트 수신 (인터럽트)
 * 2. tb_handle_event() 호출 → TB_CFG_PKG_EVENT
 * 3. 새 라우터(switch) 열거: tb_scan_port()
 * 4. 보안 레벨 확인 후 승인
 * 5. 터널 생성: tb_tunnel_pci(), tb_tunnel_dp(), tb_tunnel_usb3()
 * 6. 대역폭 분배: tb_reclaim_usb3_bandwidth()
 * 7. PCIe 핫플러그로 downstream 디바이스 열거
 */

핵심 자료구조

/* include/linux/thunderbolt.h */

/* struct tb — Thunderbolt 도메인(버스) */
struct tb {
    struct device dev;
    struct mutex lock;          /* 도메인 잠금 */
    struct tb_nhi *nhi;         /* Native Host Interface */
    struct tb_ctl *ctl;         /* 컨트롤 채널 */
    struct tb_switch *root_switch; /* 호스트 라우터 */
    const struct tb_cm_ops *cm_ops; /* CM 콜백 */
    int index;                  /* 도메인 번호 */
    enum tb_security_level security_level;
};

/* struct tb_switch — 라우터(스위치) */
struct tb_switch {
    struct device dev;
    struct tb *tb;              /* 소속 도메인 */
    u64 route;                  /* route string */
    u16 vendor;                 /* 벤더 ID */
    u16 device;                 /* 디바이스 ID */
    struct tb_port *ports;      /* 어댑터(포트) 배열 */
    unsigned int config_space_len; /* 설정 공간 크기 */
    bool is_unplugged;          /* 제거됨 플래그 */
    u8 link_speed;              /* Gbps */
    u8 link_width;              /* 1 또는 2 (레인 수) */
    enum tb_clx clx;            /* CL 절전 상태 */
    unsigned int generation;     /* TBT 세대 */
};

/* struct tb_port — 어댑터(포트) */
struct tb_port {
    struct tb_switch *sw;       /* 소속 라우터 */
    u8 port;                    /* 포트 번호 */
    enum tb_port_type type;     /* Lane/PCIe/DP/USB3/DMA */
    struct tb_port *remote;     /* 연결된 원격 포트 */
    struct tb_port *dual_link_port; /* 듀얼 레인 파트너 */
    unsigned int total_credits; /* 대역폭 크레딧 */
};

/* struct tb_tunnel — 터널 (PCIe, DP, USB3, DMA) */
struct tb_tunnel {
    struct tb *tb;
    struct tb_port *src_port;   /* 소스 어댑터 */
    struct tb_port *dst_port;   /* 목적지 어댑터 */
    struct tb_path **paths;     /* 경로 배열 */
    unsigned int npaths;
    enum tb_tunnel_type type;   /* PCIe/DP/USB3/DMA */
    int allocated_up;            /* 할당된 업스트림 Mbps */
    int allocated_down;          /* 할당된 다운스트림 Mbps */
};

터널 생성 과정

/* drivers/thunderbolt/tunnel.c — PCIe 터널 생성 */
struct tb_tunnel *tb_tunnel_alloc_pci(
    struct tb *tb,
    struct tb_port *up,      /* PCIe Up Adapter (디바이스 측) */
    struct tb_port *down     /* PCIe Down Adapter (호스트 측) */
)
{
    struct tb_tunnel *tunnel;
    struct tb_path *path;

    tunnel = tb_tunnel_alloc(tb, 2, TB_TUNNEL_PCI);
    /* path[0]: downstream (호스트→디바이스) */
    path = tb_path_alloc(tb, down, TB_PCI_HOPID, up, TB_PCI_HOPID);
    tunnel->paths[0] = path;
    /* path[1]: upstream (디바이스→호스트) */
    path = tb_path_alloc(tb, up, TB_PCI_HOPID, down, TB_PCI_HOPID);
    tunnel->paths[1] = path;

    return tunnel;
}

/* 터널 활성화 시 각 홉의 라우터 설정 공간에 path를 기록 */
int tb_tunnel_activate(struct tb_tunnel *tunnel)
{
    for (int i = 0; i < tunnel->npaths; i++) {
        tb_path_activate(tunnel->paths[i]);
        /* 각 홉의 라우터에 in_port, in_hop, out_port, out_hop 설정 */
    }
    return 0;
}

대역폭 관리

USB4/Thunderbolt 4 이상에서는 터널 간 대역폭을 동적으로 분배합니다. DP 터널이 필요로 하는 대역폭에 따라 PCIe와 USB3 터널의 할당량이 조정됩니다:

/* drivers/thunderbolt/tunnel.c — 대역폭 재분배 */

/* USB3 터널의 대역폭을 DP 터널을 위해 양보 */
static int tb_reclaim_usb3_bandwidth(struct tb *tb,
    struct tb_port *port)
{
    /* 1. 현재 USB3 터널의 실제 사용량 확인 */
    /* 2. 미사용 대역폭을 DP 터널에 재할당 */
    /* 3. USB3 터널의 보장 최소 대역폭(1 Gbps) 유지 */
}

/*
 * 대역폭 그룹 (Bandwidth Group):
 * - USB4 v2.0에서 도입된 QoS 메커니즘
 * - 같은 그룹의 터널은 대역폭을 공유
 * - DP 터널은 높은 우선순위, PCIe는 Best-Effort
 *
 * 40 Gbps 링크 대역폭 분배 예시:
 *   DP (4K@60):  ~17 Gbps (보장)
 *   USB3:        ~5 Gbps  (보장 최소, 최대 10 Gbps)
 *   PCIe:        나머지    (Best-Effort, 최대 ~32 Gbps)
 */

보안 레벨

Thunderbolt의 PCIe 터널링은 DMA를 통한 직접 메모리 접근을 허용하므로, 보안이 중요합니다:

보안 레벨설명sysfs 값
none모든 디바이스 자동 연결 (보안 없음)none
user사용자 승인 후 연결 (기본값)user
secure디바이스 키 기반 인증 후 연결secure
dponlyDisplayPort 터널만 허용 (PCIe 차단)dponly
usbonlyUSB 터널만 허용 (PCIe/DP 차단)usbonly
nopcieUSB4: PCIe 터널 없음 (USB3 + DP만)nopcie
# 도메인 보안 레벨 확인
cat /sys/bus/thunderbolt/devices/domain0/security

# 디바이스 승인 (user 모드)
echo 1 > /sys/bus/thunderbolt/devices/0-1/authorized

# 디바이스 키 기반 인증 (secure 모드)
# 1. 처음 연결 시 challenge 키 저장
cat /sys/bus/thunderbolt/devices/0-1/key
# 2. 재연결 시 저장된 키로 인증
echo "<saved-key>" > /sys/bus/thunderbolt/devices/0-1/key
echo 2 > /sys/bus/thunderbolt/devices/0-1/authorized
DMA 공격 방어: IOMMU(Intel VT-d / AMD-Vi)를 활성화하여 Thunderbolt 디바이스의 DMA 접근 범위를 제한하세요. 보안 목적이라면 패스스루 성향의 iommu=pt 대신 strict 모드(CONFIG_IOMMU_DEFAULT_DMA_STRICT=y 또는 iommu.strict=1)를 우선 검토하고, 플랫폼 정책에 맞게 조합을 선택해야 합니다. 최신 커널은 CONFIG_THUNDERBOLT_DMA_PROTECTION 지원 여부도 함께 확인하세요.

보안 레벨 상세 및 인증 흐름

Thunderbolt의 보안 레벨은 PCIe DMA 터널링으로 인한 메모리 직접 접근 위험을 관리합니다. 각 레벨은 디바이스 연결 시 요구하는 인증 수준이 다르며, IOMMU 보호와 함께 다층 방어를 구성합니다.

Thunderbolt 보안 레벨과 IOMMU 보호 SL0: none 자동 연결 (인증 없음) 모든 터널 즉시 생성 보안 취약 — 개발용 BIOS에서 설정 또는 thunderbolt.host_reset=1 SL1: user 사용자 승인 필요 (기본값) authorized=0 → 승인 대기 echo 1 > authorized bolt 데몬이 UI로 확인 ACL로 자동 승인 가능 SL2: secure 키 기반 챌린지 인증 첫 연결: 디바이스 키 저장 재연결: 챌린지-응답 검증 HMAC-SHA256 기반 authorized=2 (키 인증) SL3: dponly / nopcie PCIe 터널 완전 차단 DP + USB3만 허용 DMA 공격 원천 차단 eGPU/NVMe 사용 불가 보안 최우선 환경용 SL2 (secure) 인증 흐름 디바이스 연결 키 확인 (key 읽기) 챌린지 전송/검증 authorized=2 설정 터널 생성 인증 실패 시: authorized=0 유지, PCIe 터널 생성 거부, dmesg에 경고 기록 Boot ACL: 부팅 시 자동 승인할 디바이스 UUID 목록 (BIOS/EFI 변수 저장, /sys/.../boot_acl) IOMMU 기반 DMA 보호 계층 1. IOMMU Strict 모드: 모든 DMA 매핑을 페이지 단위로 검증, 접근 범위 제한 2. Pre-boot DMA Protection: BIOS가 부팅 전 IOMMU로 Thunderbolt DMA 차단 (DMAR ACPI 테이블) 3. CONFIG_THUNDERBOLT_DMA_PROTECTION=y: 커널이 IOMMU DMA 보호 상태 확인 및 보고 4. 보안 레벨 + IOMMU 조합이 최선: SL1(user) + IOMMU Strict = 실용성과 보안의 균형 5. ACS(Access Control Services): PCIe 레벨에서 피어-투-피어 DMA 방지, Thunderbolt 브리지에 적용 6. sysfs 확인: cat /sys/bus/thunderbolt/devices/domain0/iommu_dma_protection → 1(보호 활성)

NHI 드라이버와 CM 상태 전환

NHI(Native Host Interface)는 Thunderbolt 호스트 컨트롤러의 PCI 디바이스 드라이버입니다. PCI BAR0에 매핑된 레지스터를 통해 송수신 링 버퍼를 관리하고, MSI-X 인터럽트로 이벤트를 수신합니다:

/* drivers/thunderbolt/nhi.c — NHI PCI 드라이버 구조 */

struct tb_nhi {
    struct pci_dev *pdev;
    void __iomem *iobase;         /* PCI BAR0 매핑 */
    struct tb_ring **tx_rings;     /* 송신 링 배열 */
    struct tb_ring **rx_rings;     /* 수신 링 배열 */
    int hop_count;                /* 사용 가능한 HopID 수 */
    int msix_ida;                 /* MSI-X 벡터 관리 */
};

/* NHI 링 구조: DMA 기반 송수신 버퍼 */
struct tb_ring {
    struct tb_ring_desc *descriptors;  /* DMA 디스크립터 배열 */
    dma_addr_t descriptors_dma;
    unsigned int head;                /* SW 쓰기 포인터 */
    unsigned int tail;                /* HW 읽기 포인터 */
    unsigned int size;                /* 링 크기 */
    int hop;                          /* HopID */
    void (*callback)(struct tb_ring *, struct ring_frame *, bool);
};

Connection Manager(CM) 상태 전환은 디바이스의 핫플러그, 절전, 에러 복구를 관리합니다. Software CM의 주요 상태 전환은 다음과 같습니다:

/* Software CM 상태 전환 흐름 */
/*
 * [IDLE] ──hotplug──→ [SCANNING]
 *   │                    │
 *   │                    ├── tb_scan_port()
 *   │                    ├── tb_switch_alloc() → tb_switch_add()
 *   │                    ├── 보안 레벨 확인
 *   │                    └── tb_tunnel_pci() / tb_tunnel_dp() / tb_tunnel_usb3()
 *   │                         │
 *   │                         ↓
 *   │                    [ACTIVE] ──unplug──→ [REMOVING]
 *   │                         │                   │
 *   │                         │                   ├── tb_tunnel_deactivate()
 *   │                         │                   ├── tb_switch_remove()
 *   │                         │                   └── 대역폭 재계산
 *   │                         │                        │
 *   ←──────────────────────────←────────────────────────┘
 *
 * Suspend 시: tb_suspend_noirq() → 터널 상태 저장
 * Resume 시: tb_resume_noirq() → 라우터 재열거 + 터널 복원
 *
 * 터널 대역폭 QoS:
 * - DP 터널: 해상도/주사율 기반 보장 대역폭 계산
 * - USB3 터널: 최소 1 Gbps 보장, 유휴 시 DP/PCIe에 양보
 * - PCIe 터널: Best-Effort, 잔여 대역폭 사용
 * - tb_reclaim_usb3_bandwidth()로 동적 재분배
 */

sysfs 인터페이스

# Thunderbolt/USB4 도메인 정보
ls /sys/bus/thunderbolt/devices/
# domain0       — 도메인 (버스)
# 0-0           — 호스트 라우터 (route 0)
# 0-1           — 첫 번째 연결 디바이스 (route 1)
# 0-301         — 두 번째 홉 디바이스 (route 0x301)

# 라우터(스위치) 속성
cat /sys/bus/thunderbolt/devices/0-1/device_name  # 디바이스 이름
cat /sys/bus/thunderbolt/devices/0-1/vendor_name  # 벤더 이름
cat /sys/bus/thunderbolt/devices/0-1/generation   # TBT 세대 (1-4) 또는 USB4
cat /sys/bus/thunderbolt/devices/0-1/authorized   # 승인 상태
cat /sys/bus/thunderbolt/devices/0-1/link_speed   # 링크 속도 (Gbps)
cat /sys/bus/thunderbolt/devices/0-1/link_width   # 레인 수 (1 또는 2)
cat /sys/bus/thunderbolt/devices/0-1/rx_speed     # USB4: 수신 속도
cat /sys/bus/thunderbolt/devices/0-1/rx_lanes     # USB4: 수신 레인 수
cat /sys/bus/thunderbolt/devices/0-1/tx_speed     # USB4: 송신 속도
cat /sys/bus/thunderbolt/devices/0-1/tx_lanes     # USB4: 송신 레인 수
cat /sys/bus/thunderbolt/devices/0-1/nvm_version  # 펌웨어 버전

# NVM(펌웨어) 업데이트
# 1. 펌웨어 이미지를 nvm_non_active_store에 기록
dd if=firmware.bin of=/sys/bus/thunderbolt/devices/0-1/nvm_non_active_store
# 2. 인증(플래시) 시작
echo 1 > /sys/bus/thunderbolt/devices/0-1/nvm_authenticate
# 3. 상태 확인 (0 = 성공)
cat /sys/bus/thunderbolt/devices/0-1/nvm_authenticate

Thunderbolt 네트워킹

Thunderbolt은 두 호스트 간 고속 IP 네트워킹을 지원합니다. 커널의 thunderbolt-net 드라이버가 DMA 터널을 통해 가상 이더넷 인터페이스를 생성합니다:

# thunderbolt-net 커널 모듈 로드
modprobe thunderbolt_net

# Thunderbolt 케이블로 두 호스트 연결 시 자동으로 네트워크 인터페이스 생성
ip link show thunderbolt0   # 또는 thunderbolt1, ...

# IP 주소 설정 (양쪽 호스트)
# Host A:
ip addr add 172.16.0.1/24 dev thunderbolt0
ip link set thunderbolt0 up
# Host B:
ip addr add 172.16.0.2/24 dev thunderbolt0
ip link set thunderbolt0 up

# 대역폭 테스트 (Thunderbolt 3: ~22 Gbps 실측)
iperf3 -s                        # Host A: 서버
iperf3 -c 172.16.0.1 -t 30      # Host B: 클라이언트
XDomain 프로토콜: Thunderbolt 네트워킹은 XDomain(크로스 도메인) 디스커버리 프로토콜을 사용합니다. 두 호스트가 연결되면 UUID 교환 → 프로퍼티 디렉터리 교환 → DMA 터널 설정 → 네트워크 인터페이스 생성 순서로 자동 설정됩니다. drivers/thunderbolt/xdomain.cdrivers/net/thunderbolt/에 구현되어 있습니다.

PCIe 터널링과 eGPU

Thunderbolt PCIe 터널을 통해 외부 GPU(eGPU), NVMe 스토리지, 네트워크 카드 등을 연결할 수 있습니다:

# Thunderbolt을 통해 연결된 PCIe 디바이스 확인
lspci -vt | grep -A2 "Thunderbolt"
# -[0000:00]-+-00.0  Intel ... Host Bridge
#            +-0d.2  Intel ... Thunderbolt 4 NHI
#            \-0d.0-[01-04]--+-00.0  Intel ... USB4 Root Port
#                            \-[02-04]--+-00.0  eGPU (NVIDIA/AMD)

# eGPU PCIe 대역폭 확인
lspci -vvs 02:00.0 | grep -i "lnksta"
# LnkSta: Speed 8GT/s (ok), Width x4 (ok)
# → PCIe 3.0 x4 = ~32 Gbps (Thunderbolt 3/4 최대)

# eGPU 핫플러그 이벤트 모니터링
udevadm monitor --subsystem-match=thunderbolt
udevadm monitor --subsystem-match=pci

# 안전한 eGPU 제거
# 1. GPU를 사용하는 프로세스 종료
# 2. PCIe 디바이스 제거
echo 1 > /sys/bus/pci/devices/0000:02:00.0/remove
# 3. Thunderbolt 디바이스 분리
eGPU 대역폭 제한: Thunderbolt 3/4의 PCIe 터널은 최대 PCIe 3.0 ×4 (약 32 Gbps)를 제공합니다. 이는 데스크톱 PCIe 4.0 ×16 (약 256 Gbps)의 1/8 수준이므로, GPU 성능이 약 10~25% 하락할 수 있습니다. Thunderbolt 5에서는 PCIe 4.0 ×4 (약 64 Gbps)로 개선됩니다.

DisplayPort 터널링

Thunderbolt/USB4는 DisplayPort 신호를 터널링하여 외부 모니터를 연결합니다:

연결 방식설명대역폭
DP Alt ModeType-C 핀을 DP 신호로 직접 사용 (터널링 아님)DP 1.4: 32.4 Gbps
DP Tunnel (TBT3/USB4)Thunderbolt 링크 위에 DP 패킷 터널링링크 대역폭에서 동적 할당
DP 2.1 Tunnel (USB4 v2)UHBR 레이트 터널링최대 80 Gbps
# 연결된 DP 터널 확인 (debugfs)
cat /sys/kernel/debug/thunderbolt/0-0/tunnels
# DP IN:  port 3 → port 12 (0-1), allocated_bw: 17280 Mbps
# PCIe:   port 1 → port 9 (0-1), allocated_bw: 22000 Mbps
# USB3:   port 2 → port 10 (0-1), allocated_bw: 10000 Mbps

# DRM/KMS에서 Thunderbolt 연결 모니터 확인
cat /sys/class/drm/card0-DP-*/status    # connected
cat /sys/class/drm/card0-DP-*/edid | edid-decode

전원 관리

절전 상태설명복구 시간
CL0s링크 유휴 시 저전력 (PCIe L0s와 유사)~수 μs
CL1더 깊은 링크 절전 (PCIe L1과 유사)~수십 μs
CL2USB4: 가장 깊은 절전, PHY 전원 차단~수 ms
RTD3Runtime D3 — 컨트롤러 전원 완전 차단~수백 ms
# Thunderbolt 런타임 PM 상태 확인
cat /sys/bus/thunderbolt/devices/0-0/power/runtime_status
# active / suspended

# RTD3 활성화 확인 (기본 활성화)
cat /sys/bus/thunderbolt/devices/domain0/boot_acl

# CLx 상태 확인
cat /sys/bus/thunderbolt/devices/0-1/clx    # cl0s, cl1, cl2 또는 disabled

# 전원 관리 관련 커널 메시지
dmesg | grep -i "thunderbolt.*power\|thunderbolt.*CLx\|thunderbolt.*RTD3"

디버깅

# 커널 로그에서 Thunderbolt/USB4 메시지 확인
dmesg | grep -i thunderbolt
# thunderbolt 0-1: new device found, vendor=0x8086 device=0x1234
# thunderbolt 0-1: Thunderbolt 4 device

# 동적 디버그 활성화 (상세 로깅)
echo "module thunderbolt +p" > /sys/kernel/debug/dynamic_debug/control

# debugfs 정보
ls /sys/kernel/debug/thunderbolt/
# 0-0/  — 호스트 라우터 디버그 정보
# 0-1/  — 연결 디바이스 디버그 정보

# 라우터 설정 공간 덤프
cat /sys/kernel/debug/thunderbolt/0-1/regs

# 트레이스포인트
echo 1 > /sys/kernel/debug/tracing/events/thunderbolt/enable
cat /sys/kernel/debug/tracing/trace_pipe
# tb_cfg_read/write: 라우터 설정 공간 접근 추적
# tb_tx/rx: 컨트롤 패킷 송수신 추적

# boltctl — 유저스페이스 관리 도구 (bolt 프로젝트)
boltctl list                  # 연결된 디바이스 목록
boltctl info 0-1             # 디바이스 상세 정보
boltctl authorize 0-1        # 디바이스 승인
boltctl enroll 0-1           # 디바이스 등록 (자동 승인)
boltctl forget 0-1           # 등록 해제
boltctl monitor              # 실시간 이벤트 모니터링

Thunderbolt/USB4 Kconfig 옵션

옵션설명
CONFIG_USB4Thunderbolt/USB4 서브시스템 활성화 (이전명: CONFIG_THUNDERBOLT)
CONFIG_USB4_DEBUGFS_WRITEdebugfs를 통한 라우터 설정 공간 쓰기 허용 (디버깅용)
CONFIG_USB4_DMA_TESTDMA 트래픽 테스트 드라이버 (개발/테스트용)
CONFIG_USB4_KUNIT_TESTThunderbolt KUnit 테스트
CONFIG_THUNDERBOLT_NETThunderbolt 네트워킹 (호스트 간 IP)
CONFIG_THUNDERBOLT_DMA_PROTECTION부팅 시 IOMMU 기반 DMA 보호 자동 적용
CONFIG_HOTPLUG_PCI_PCIEPCIe 핫플러그 (Thunderbolt PCIe 터널에 필요)
CONFIG_ACPI_HOTPLUG_MEMORYACPI 기반 Thunderbolt 독 메모리 핫플러그

usbfs와 libusb

usbfs는 유저스페이스에서 USB 디바이스에 직접 접근할 수 있게 하는 파일시스템입니다. 커널 드라이버 없이도 /dev/bus/usb/를 통해 Control, Bulk, Interrupt, Isochronous 전송을 수행할 수 있습니다.

usbfs 접근 구조

경로의미
/dev/bus/usb/001/001Bus 1의 Root Hub (Device 1)
/dev/bus/usb/001/002Bus 1의 연결 디바이스
/dev/bus/usb/002/001Bus 2의 Root Hub 또는 디바이스

각 디바이스 파일은 캐릭터 디바이스이며, ioctl()로 다음 트랜잭션을 수행합니다: USBDEVFS_CONTROL, USBDEVFS_BULK, USBDEVFS_SUBMITURB, USBDEVFS_REAPURB, USBDEVFS_CLAIMINTERFACE, USBDEVFS_RELEASEINTERFACE, USBDEVFS_RESETEP, USBDEVFS_RESET.

libusb 사용 예제

libusb는 usbfs 위에 구축된 크로스 플랫폼 유저스페이스 USB 라이브러리입니다:

#include <libusb-1.0/libusb.h>
#include <stdio.h>

#define VENDOR_ID   0x1234
#define PRODUCT_ID  0x5678
#define EP_BULK_IN  0x81
#define EP_BULK_OUT 0x02

int main(void)
{
    libusb_device_handle *handle;
    int ret, transferred;
    unsigned char buf[64];

    /* 1. 라이브러리 초기화 */
    libusb_init(NULL);

    /* 2. 디바이스 열기 */
    handle = libusb_open_device_with_vid_pid(
        NULL, VENDOR_ID, PRODUCT_ID);
    if (!handle) {
        fprintf(stderr, "Device not found\\n");
        return 1;
    }

    /* 3. 커널 드라이버 분리 (필요 시) */
    if (libusb_kernel_driver_active(handle, 0) == 1)
        libusb_detach_kernel_driver(handle, 0);

    /* 4. 인터페이스 점유 */
    libusb_claim_interface(handle, 0);

    /* 5. Bulk OUT 전송 (호스트 → 디바이스) */
    unsigned char tx_data[] = {0x01, 0x02, 0x03};
    ret = libusb_bulk_transfer(handle, EP_BULK_OUT,
        tx_data, sizeof(tx_data), &transferred, 5000);
    printf("Sent %d bytes\\n", transferred);

    /* 6. Bulk IN 전송 (디바이스 → 호스트) */
    ret = libusb_bulk_transfer(handle, EP_BULK_IN,
        buf, sizeof(buf), &transferred, 5000);
    printf("Received %d bytes\\n", transferred);

    /* 7. 정리 */
    libusb_release_interface(handle, 0);
    libusb_close(handle);
    libusb_exit(NULL);
    return 0;
}
권한 설정: usbfs 접근에는 root 권한이 필요합니다. udev 규칙으로 특정 VID/PID에 대해 일반 사용자 접근을 허용할 수 있습니다:
SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", MODE="0666"

USB 전원 관리

USB 전원 관리는 사용하지 않는 디바이스를 저전력 상태(Suspend)로 전환하여 전력 소모를 줄입니다. Linux 커널은 USB 디바이스 레벨과 인터페이스 레벨 모두에서 전원 관리를 지원합니다.

Autosuspend

Autosuspend는 디바이스가 일정 시간 유휴 상태이면 자동으로 Suspend하는 메커니즘입니다:

# autosuspend 설정 (sysfs)
# 디바이스별 경로: /sys/bus/usb/devices/<busnum>-<port>/power/

# autosuspend 활성화
echo "auto" > /sys/bus/usb/devices/1-2/power/control

# autosuspend 비활성화 (항상 활성)
echo "on" > /sys/bus/usb/devices/1-2/power/control

# autosuspend 대기 시간 (초) — 0이면 즉시 suspend
echo 2 > /sys/bus/usb/devices/1-2/power/autosuspend_delay_ms

# 현재 전원 상태 확인
cat /sys/bus/usb/devices/1-2/power/runtime_status
# active / suspended / suspending

# USB autosuspend 전역 기본값 (커널 파라미터)
# usbcore.autosuspend=2  (2초 후 자동 suspend)
# usbcore.autosuspend=-1 (autosuspend 비활성화)

Remote Wakeup

Remote Wakeup은 Suspend된 디바이스가 이벤트 발생 시 호스트를 깨울 수 있는 기능입니다 (예: 마우스 움직임, 키보드 입력):

/* 드라이버에서 autosuspend / remote wakeup 지원 */
static int my_usb_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
{
    struct usb_device *udev = interface_to_usbdev(intf);

    /* ... 드라이버 초기화 ... */

    /* Remote Wakeup 허용 */
    device_set_wakeup_enable(&udev->dev, 1);

    /* autosuspend 활성화 */
    usb_enable_autosuspend(udev);

    return 0;
}

/* Suspend 콜백 */
static int my_usb_suspend(struct usb_interface *intf,
                          pm_message_t message)
{
    struct my_usb_dev *dev = usb_get_intfdata(intf);

    /* 진행 중인 URB 취소 */
    usb_kill_urb(dev->bulk_urb);

    return 0;
}

/* Resume 콜백 */
static int my_usb_resume(struct usb_interface *intf)
{
    struct my_usb_dev *dev = usb_get_intfdata(intf);

    /* URB 재제출 */
    usb_submit_urb(dev->bulk_urb, GFP_NOIO);

    return 0;
}

static struct usb_driver my_usb_driver = {
    .name       = "my_usb",
    .id_table   = my_usb_ids,
    .probe      = my_usb_probe,
    .disconnect = my_usb_disconnect,
    .suspend    = my_usb_suspend,
    .resume     = my_usb_resume,
    .supports_autosuspend = 1,  /* autosuspend 지원 선언 */
};

Selective Suspend

용어설명
Global Suspend전체 USB 버스 Suspend (시스템 Sleep 시)
Selective Suspend개별 디바이스만 Suspend (런타임 PM)
L1 (LPM)USB 2.0 Link Power Management — 빠른 진입/탈출
U1/U2/U3USB 3.x Link States — U1/U2(저전력), U3(Suspend)
Autosuspend 주의: 모든 USB 디바이스가 Suspend/Resume을 올바르게 구현하는 것은 아닙니다. 일부 디바이스는 Suspend 후 응답하지 않거나 데이터를 잃을 수 있습니다. 문제가 있는 디바이스는 echo "on" > power/control로 autosuspend를 비활성화하거나, 커널의 USB quirks 테이블에 등록합니다.

USB 3.x는 링크 레벨에서 4가지 전력 상태(U0~U3)를 정의합니다. U1/U2는 LPM(Link Power Management)을 통해 유휴 시 자동 전환되며, U3는 전통적인 Suspend 상태입니다. 상태 전환은 링크 양쪽이 LPM 토큰(LGO_U1/LGO_U2)을 교환하여 합의합니다.

USB 3.x Link Power State 전환 U0 (Active) 정상 동작 상태, 데이터 전송 가능 U1 (Standby) 내부 클록 유지, ~수 μs 복구 U2 (Sleep) 클록 정지, ~수십 μs~ms 복구 U3 (Suspend) PHY 전원 차단, ~수 ms 복구 LGO_U1 LFPS wakeup LGO_U2 LFPS wakeup 타이머 만료 시 깊은 절전 전환 SET_FEATURE SET_FEATURE Remote Wakeup / Resume LPM 토큰 (Link Management Packet) LGO_U1/LGO_U2: 상대방에게 상태 전환 요청 LAU/LXU: 승인(Accept) / 거부(Reject) 응답

Selective Suspend 메커니즘 상세

USB의 Selective Suspend는 시스템이 활성(S0) 상태에서 개별 디바이스만 Suspend하는 런타임 PM 메커니즘입니다. USB 2.0 LPM(L1 상태)과 USB 3.x U1/U2는 하드웨어가 자동으로 전환하는 반면, Selective Suspend(U3/L2)는 소프트웨어가 명시적으로 제어합니다:

메커니즘적용 버전진입 방법복구 시간절전 효과
USB 2.0 LPM (L1)USB 2.0 AddendumHW 자동 (Extended Token)~50~300 μs중간 (PHY 유지)
USB 3.x U1USB 3.0+HW 자동 (LGO_U1 토큰)~수 μs낮음 (클록 유지)
USB 3.x U2USB 3.0+HW 자동 (LGO_U2 토큰)~수십 μs~ms중간 (클록 정지)
Selective Suspend (U3/L2)USB 1.1+SW 명시적 (SET_FEATURE)~수 ms~20ms높음 (PHY 전원 차단)

BESL(Best Effort Service Latency)은 USB 2.0 LPM에서 디바이스가 L1 상태에서 복구하는 데 필요한 시간을 호스트에 알리는 메커니즘입니다. BESL 값이 클수록 깊은 절전이 가능하지만 복구 시간이 길어집니다. xHCI 드라이버는 Endpoint의 BESL 값을 확인하여 LPM 정책을 조정합니다.

Remote Wakeup은 Suspend 상태의 디바이스가 호스트를 깨울 수 있는 기능입니다. USB 2.0에서는 D+/D- 라인에 Resume 신호를 보내고, USB 3.x에서는 LFPS(Low Frequency Periodic Signaling)를 사용합니다. 드라이버는 device_set_wakeup_enable()으로 Remote Wakeup을 허용하고, 호스트는 SET_FEATURE(DEVICE_REMOTE_WAKEUP)로 디바이스에 통보합니다. Suspend 중 디바이스 이벤트(키보드 입력, 마우스 이동 등) 발생 시 디바이스가 스스로 Resume 신호를 생성하여 호스트를 깨웁니다.

디버깅

lsusb

# 연결된 USB 디바이스 목록
lsusb

# 트리 구조 (토폴로지)
lsusb -t

# 특정 디바이스 상세 정보 (모든 디스크립터 덤프)
lsusb -v -d 1234:5678

# 특정 버스/디바이스
lsusb -v -s 001:003

# 출력 예시 (lsusb -t)
# /:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 10000M
#     |__ Port 1: Dev 2, If 0, Class=Mass Storage, Driver=uas, 5000M
# /:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/12p, 480M
#     |__ Port 3: Dev 5, If 0, Class=HID, Driver=usbhid, 12M
#     |__ Port 3: Dev 5, If 1, Class=HID, Driver=usbhid, 12M
#     |__ Port 9: Dev 3, If 0, Class=Wireless, Driver=btusb, 12M

usbmon

usbmon은 USB 트래픽을 모니터링하는 커널 기능입니다. /sys/kernel/debug/usb/usbmon/을 통해 접근합니다:

# usbmon 모듈 로드
modprobe usbmon

# debugfs 마운트 확인
mount -t debugfs none /sys/kernel/debug 2>/dev/null

# 텍스트 형식 모니터링 (Bus 1)
cat /sys/kernel/debug/usb/usbmon/1t

# 모든 버스 모니터링
cat /sys/kernel/debug/usb/usbmon/0t

# 바이너리 형식 (Wireshark용)
cat /sys/kernel/debug/usb/usbmon/1u > capture.bin

# usbmon 텍스트 출력 형식:
# URB_TAG TIMESTAMP EVENT_TYPE ADDRESS:EP STATUS LENGTH DATA
# d5ea8c00 3575914555 S Bi:1:003:1 -115 31 = 55534253 ...
#   S = Submit, C = Complete
#   Bi = Bulk IN, Bo = Bulk OUT, Ci = Control IN

Wireshark를 이용한 USB 분석

# Wireshark에서 USB 캡처 (usbmon 인터페이스 선택)
# 또는 tcpdump로 캡처 파일 생성
tcpdump -i usbmon1 -w usb_capture.pcap

# Wireshark에서 열기
wireshark usb_capture.pcap

# Wireshark 필터 예시:
# usb.transfer_type == URB_BULK
# usb.device_address == 3
# usb.endpoint_address == 0x81
# usb.idVendor == 0x1234

sysfs USB 정보

sysfs USB 디바이스 정보 구조 `/sys/bus/usb/devices/1-2/` 장치 루트 디렉터리 기본 식별자 idVendor / idProduct manufacturer / product serial / bcdDevice bDeviceClass/SubClass bDeviceProtocol version / speed 구성/전송 특성 bNumConfigurations bNumInterfaces bMaxPacketSize0 bMaxPower configuration urbnum 상태/정책 authorized / removable avoid_reset_quirk maxchild (hub) connected_duration runtime PM 상태 wakeup 정책 `power/` 디렉터리 control (auto/on) autosuspend_delay_ms runtime_status wakeup (enabled/disabled) connected_duration 인터페이스/엔드포인트 `1-2:1.0/`, `1-2:1.1/` bInterfaceClass/SubClass bInterfaceProtocol bNumEndpoints driver/ (바인딩 드라이버) ep_81/ → type / direction wMaxPacketSize / interval

커널 디버깅

# USB 관련 커널 메시지
dmesg | grep -i usb

# Dynamic Debug 활성화
echo 'module usbcore +p' > /sys/kernel/debug/dynamic_debug/control
echo 'module xhci_hcd +p' > /sys/kernel/debug/dynamic_debug/control
echo 'module usbhid +p' > /sys/kernel/debug/dynamic_debug/control

# USB 디바이스 수동 리셋
echo 0 > /sys/bus/usb/devices/1-2/authorized
echo 1 > /sys/bus/usb/devices/1-2/authorized

# USB 바인딩/언바인딩
echo "1-2:1.0" > /sys/bus/usb/drivers/usbhid/unbind
echo "1-2:1.0" > /sys/bus/usb/drivers/usbhid/bind

# quirks 설정 (모듈 파라미터)
# usbcore.quirks=VID:PID:flags
# 예: usbcore.quirks=0x1234:0x5678:gn  (RESET_RESUME + NO_SET_INTF)

디버깅 도구 요약

도구용도설치
lsusbUSB 디바이스 목록 및 디스크립터 덤프usbutils
usbmon커널 레벨 USB 트래픽 모니터링커널 내장 (CONFIG_USB_MON)
WiresharkGUI USB 프로토콜 분석wireshark
usbhid-dumpHID Report Descriptor 덤프usbutils
usb-devices텍스트 기반 디바이스 정보usbutils
usbipUSB over IP (원격 디바이스 공유)usbip

커널 소스 구조

경로설명
drivers/usb/core/USB Core (열거, URB, Hub, 드라이버 매칭)
drivers/usb/host/HCD 드라이버 (xhci, ehci, ohci, uhci)
drivers/usb/gadget/USB Gadget Framework (UDC, composite, function)
drivers/usb/storage/USB Mass Storage 드라이버 (usb-storage, uas)
drivers/usb/class/USB 클래스 드라이버 (cdc-acm, usblp)
drivers/usb/serial/USB-Serial 어댑터 드라이버
drivers/usb/typec/Type-C 서브시스템 (TCPM, UCSI, Alt Mode)
drivers/hid/usbhid/USB HID 드라이버
sound/usb/USB Audio 드라이버
drivers/net/usb/USB 네트워크 드라이버 (cdc_ether, cdc_ncm, rndis)
drivers/media/usb/USB 미디어 드라이버 (UVC 웹캠 등)
include/linux/usb.hUSB Core API 헤더
include/linux/usb/hcd.hHCD API 헤더
include/linux/usb/gadget.hGadget API 헤더
include/linux/usb/ch9.hUSB Chapter 9 상수/구조체 (uapi)
drivers/thunderbolt/Thunderbolt/USB4 코어 (CM, 터널, 라우터, NHI)
drivers/net/thunderbolt/Thunderbolt 네트워킹 드라이버
include/linux/thunderbolt.hThunderbolt/USB4 API 헤더

주요 Kconfig 옵션

옵션설명
CONFIG_USBUSB 서브시스템 활성화
CONFIG_USB_XHCI_HCDxHCI 호스트 컨트롤러 드라이버
CONFIG_USB_EHCI_HCDEHCI 호스트 컨트롤러 드라이버
CONFIG_USB_OHCI_HCDOHCI 호스트 컨트롤러 드라이버
CONFIG_USB_STORAGEUSB Mass Storage 드라이버
CONFIG_USB_UASUSB Attached SCSI (UASP) 드라이버
CONFIG_USB_HIDUSB HID 드라이버
CONFIG_USB_ACMCDC ACM (가상 시리얼) 드라이버
CONFIG_USB_NET_CDCETHERCDC Ethernet 드라이버
CONFIG_USB_NET_CDC_NCMCDC NCM 네트워크 드라이버
CONFIG_SND_USB_AUDIOUSB Audio 드라이버
CONFIG_USB_GADGETUSB Gadget Framework
CONFIG_USB_CONFIGFSConfigFS 기반 USB Gadget 구성
CONFIG_USB_FUNCTIONFSFunctionFS (유저스페이스 Gadget)
CONFIG_TYPECUSB Type-C 서브시스템
CONFIG_TYPEC_TCPMType-C Port Manager
CONFIG_TYPEC_UCSIUCSI Type-C 인터페이스
CONFIG_USB4Thunderbolt/USB4 서브시스템
CONFIG_THUNDERBOLT_NETThunderbolt 네트워킹 (호스트 간 IP)
CONFIG_USB_MONusbmon (USB 트래픽 모니터링)

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