Driver / Device · Linux v6.6 · source + diagram note

device tree

live device tree의 경로 조회, platform device population, driver probe의 경계를 v6.6 소스로 구분합니다.

FDT, live node, 장치 등록의 경계

이 글의 두 대표 함수는 이미 만들어진 live device tree를 사용한다. flat FDT에서 device_node tree를 만드는 unflatten_device_tree()는 drivers/of/fdt.c의 앞 단계다. of_platform_populate()는 그 live tree를 순회하여 장치 생성 경로에 들어가고, of_find_node_by_path()는 경로 조회만 한다.

그림 1. 네 층을 분리해서 읽는 device-tree 경로
flat FDT blobfirmware가 제공한 바이너리 표현
live device_node treeunflatten_device_tree()가 생성. 아래 두 함수의 입력 기반
platform/AMBA deviceof_platform_populate()→of_platform_bus_create()가 조건에 따라 생성·건너뜀
driver match·probe별도 driver core 경계. DT 기재나 populate 호출만으로 완료되지 않음
경로 조회 가지of_find_node_by_path(path) → live node 참조 또는 NULL. compatible match를 수행하지 않음.
검증할 실제 보드 상태FDT 내용, Kconfig, 생성된 device, driver binding·deferred probe를 각각 확인.

고정 원문: fdt.c unflatten · platform.c populate · of.h path wrapper

소스 코드 위치

먼저 확인할 Linux v6.6 소스 파일

원본 코드:
Linux v6.6: drivers/of/base.c
Linux v6.6: drivers/of/platform.c
Linux v6.6: drivers/of/fdt.c
Linux v6.6: include/linux/of.h

설명: 진입 함수가 있는 파일과 구조체 정의, 아키텍처별 연결 코드, 콜백 구현을 함께 확인한다. 여러 파일을 대조해야 호출 관계와 각 코드의 역할을 알 수 있다.

대표 코드

of_platform_populate

원본 코드: drivers/of/platform.c:494-523 · v6.6 · 로컬 원문
int of_platform_populate(struct device_node *root,
			const struct of_device_id *matches,
			const struct of_dev_auxdata *lookup,
			struct device *parent)
{
	struct device_node *child;
	int rc = 0;

	root = root ? of_node_get(root) : of_find_node_by_path("/");
	if (!root)
		return -EINVAL;

	pr_debug("%s()\n", __func__);
	pr_debug(" starting at: %pOF\n", root);

	device_links_supplier_sync_state_pause();
	for_each_child_of_node(root, child) {
		rc = of_platform_bus_create(child, matches, lookup, parent, true);
		if (rc) {
			of_node_put(child);
			break;
		}
	}
	device_links_supplier_sync_state_resume();

	of_node_set_flag(root, OF_POPULATED_BUS);

	of_node_put(root);
	return rc;
}

확인 사항: root 참조 획득 실패는 -EINVAL이다. 반복문에는 rc != 0이면 중단하는 분기가 있지만, 장치 생성 실패가 모두 음수 오류로 전달되지는 않는다. sync-state resume와 root의 OF_POPULATED_BUS 설정·of_node_put(root)은 이후에도 실행된다. 이 flag를 모든 child/probe 성공으로 읽지 않는다.

of_find_node_by_path

원본 코드: include/linux/of.h:285-288 · v6.6 · 로컬 원문
static inline struct device_node *of_find_node_by_path(const char *path)
{
	return of_find_node_opts_by_path(path, NULL);
}

CONFIG_OF가 켜진 이 wrapper는 경로를 of_find_node_opts_by_path(path, NULL)에 전달한다. CONFIG_OF가 꺼진 별도 stub은 NULL을 반환한다. machine compatible 검사와는 관계가 없다. 성공 시 반환된 device_node 참조는 사용 후 of_node_put()으로 해제해야 한다.

두 대표 함수가 하는 일과 하지 않는 일

of_platform_populate()와 of_find_node_by_path()는 순차 호출 체인이 아니다. populate가 root 인자로 NULL을 받았을 때 경로 "/"를 조회할 수 있지만, 호출자가 다른 path를 찾는 wrapper는 독립적으로 쓸 수 있다.

그림 2. populate의 반복과 독립적인 path lookup
  1. 1
    root 참조 확보전달된 root면 of_node_get(root), NULL이면 of_find_node_by_path("/"). 둘 다 root가 없으면 -EINVAL.
  2. 2
    device-link sync pause → 자식 순회for_each_child_of_node(root, child)에서 of_platform_bus_create(..., true) 호출. strict mode에서는 compatible이 없는 노드를 건너뛸 수 있다.
  3. 3
    오류 시 break·child 참조 정리for_each_child_of_node의 break에서 of_node_put(child)을 명시적으로 호출한다. 이미 처리한 장치의 포괄적 rollback은 이 함수에 없다.
  4. 4
    resume → root flag → root put → rcOF_POPULATED_BUS는 이 위치에서 rc가 0이 아니어도 설정된다. 모든 자식 생성·driver probe 성공 표시가 아니다.
별도 API: path lookupof_find_node_by_path(path)는 of_find_node_opts_by_path(path, NULL)를 부른다. 성공 시 caller가 of_node_put().
probe 경계장치 생성 이후 driver match/probe는 장치·드라이버와 의존성 조건에 따른다. deferred probe도 가능하다.
함수입력소스가 보장하는 처리보장하지 않는 것
of_platform_populatelive root 또는 NULL, bus matches, auxdata, parentroot 참조를 확보·반납하고 child 생성 경로를 순회; rc 반환 (생성 실패가 0으로 처리될 수 있음)FDT unflatten, 모든 노드의 장치화, 모든 driver probe 완료
of_find_node_by_path경로 문자열node 참조 또는 NULL; CONFIG_OF off stub은 NULLcompatible 검사, platform device 생성, driver binding

base.c path lookup 구현 · platform.c:494–523

device_node 참조와 장치 객체의 소유권

경로 조회가 돌려준 node 참조, populate 내부가 임시 확보한 root 참조, 자식 순회 중의 참조는 서로 다른 소유권이다.

그림 3. 어떤 참조를 누가 반납하는가
populate의 root인자로 받으면 of_node_get, 없으면 "/" 조회 → 내부에서 of_node_put(root). 호출자가 원래 보유한 참조는 별개.
순회 중 childfor_each_child_of_node의 break에서 of_node_put(child)을 명시적으로 호출한다. of_platform_bus_create의 반환에 따라 다음 자식 또는 break.
독립 path 조회 결과of_find_node_by_path(path)를 직접 호출한 쪽이 성공한 node를 사용한 뒤 of_node_put().
생성된 devicenode와 연관된 platform/AMBA device는 별도 device model 객체. node 조회 참조를 내려놓는 것과 device 해제는 같은 작업이 아님.
참조·객체획득/생성반납/수명흔한 오해
populate root refof_node_get 또는 root path lookup함수 말미 of_node_put(root)호출자가 넘긴 원래 참조까지 소비한다고 착각
child iterator reffor_each_child_of_nodebreak 시 child를 명시적으로 putbreak 뒤 참조 누락/중복 put
직접 path lookup ref성공한 of_find_node_by_path호출자 of_node_put함수 자체가 driver를 probe한다고 착각
platform/AMBA deviceof_platform_bus_create의 조건별 분기device model 수명·해제 경로node ref 하나의 put이 device를 제거한다고 착각

참조 계약: of.h node ref API · populate 반복

이 고정 버전의 of_platform_device_create_pdata()는 비활성/이미 populated 노드뿐 아니라 할당·등록 실패에도 NULL을 반환한다. 이를 호출한 of_platform_bus_create()의 !dev 분기는 0을 반환한다. 따라서 모든 장치 생성 실패가 음수 rc로 전파된다고 해석하면 안 된다. 반환 0과 OF_POPULATED_BUS만으로 장치 생성 완료를 판단하지 않고 실제 객체와 로그를 확인한다. 생성 helper · bus 생성의 NULL 처리

성공·건너뜀·오류를 구별하는 상태표

한 함수가 0을 반환해도 모든 DT node가 장치로 바뀌거나 probe가 끝난 것은 아니다. 먼저 live node 존재와 장치 등록 여부를 분리한다.

그림 4. populate 결과를 네 가지 관찰 지점으로 나누기
live root 없음root == NULL → -EINVAL. child 순회·flag 설정 전 종료.
child 건너뜀compatible 없음, skip table, 이미 populated 등의 조건이면 장치가 생성되지 않을 수 있다. 반환 0과 양립한다.
비0 rc의 제어 흐름rc != 0이면 반복 중단. pause는 resume되고 root flag가 설정된 뒤 root ref를 놓고 rc 반환.
장치 생성 후device가 보여도 driver match/probe는 별도 경계. 의존성 미충족이면 deferred 상태일 수 있다.

OF_POPULATED_BUS는 이 함수의 최종 성공 비트가 아니다. 코드상 오류 반환 전에 root에도 설정된다.

관찰소스 단계직접 확인할 것단정할 수 없는 것
live nodeFDT unflatten 또는 동적 OF tree/sys/firmware/devicetree/base의 해당 경로device 등록
population 시도of_platform_populate → child helperreturn code, skip 조건, root flag모든 child 성공
device 객체platform/AMBA device 생성 분기device의 of_node 연결driver binding
driver 상태match·probe 또는 deferred probedriver link·deferred 목록·관련 로그DT 기재만으로 probe 완료

두 API에서 지켜야 할 경계

입력 tree

of_platform_populate()가 flat blob을 unflatten하지 않는다. root가 없으면 -EINVAL이며, 노드가 있어도 skip 조건을 통과해야 device 생성에 이른다.

참조 수명

populate 내부 root 참조와 외부 path 조회 참조를 각각 한 번씩 반납한다. 이 버전의 child 반복에서는 break 시 child를 명시적으로 put.

오류 뒤 상태

장치 생성 실패가 0으로 처리되어도 앞서 만든 device를 여기서 일괄 되돌리지 않는다. root의 OF_POPULATED_BUS도 설정된다. 반환값과 실제 객체를 함께 검사한다.

probe는 별도

compatible은 device/driver 매칭의 한 재료다. path lookup 성공이나 population 반환 0만으로 driver probe 성공을 주장하지 않는다.

근거: populate · path wrapper · path lookup 구현

읽기 전용으로 단계별 확인

아래 경로는 해당 기능이 켜진 보드에서만 나타난다. 실제 DT 내용과 Kconfig·driver 로그를 함께 기록해야 원인 단계가 구분된다. 전역 tracefs tracer/filter를 바꾸지 않는다.

가설읽기 전용 관찰해석 한계
live node가 있나?ls /sys/firmware/devicetree/base와 대상 경로 확인device 생성이나 probe를 보장하지 않음
platform device가 생겼나?ls /sys/bus/platform/devices, 대상 device의 of_node symlinkAMBA 등 별도 bus 경로도 가능
driver가 붙었나?대상 device의 driver symlink와 관련 dmesg없는 경우 no match·probe 오류·defer를 분리해야 함
defer 상태인가?존재할 때 cat /sys/kernel/debug/devices_deferreddebugfs/설정 조건부, 목록에 없다는 것만으로 probe 성공 아님

동적 추적이 필요하면 테스트 환경에서 사용 가능한 event/function을 먼저 확인하고 범위를 협의한다. 시스템 전체 current_tracer·set_ftrace_filter를 예제로 덮어쓰지 않는다.

보드에서 추가로 확인할 질문

  • 사용한 FDT와 Kconfig에서 어떤 node가 live tree에 존재하며 status와 compatible은 무엇인가?
  • 선택한 root 아래 각 child가 strict compatible·skip table·already-populated 조건 중 어디에서 걸리는가?
  • root 부재의 -EINVAL과, 반환 0인데도 일부 장치가 없는 경우를 구분했는가? 생성 helper의 NULL 반환과 root flag를 각각 확인했는가?
  • 찾은 node의 참조는 어느 호출자가 of_node_put()하며, 같은 node에 대응하는 device와 driver link는 별도로 존재하는가?
  • device는 있는데 driver가 없다면 match 부재, probe 실패, deferred probe 중 어느 로그가 근거인가?