전체 흐름
드라이버 등록 때 플랫폼 버스를 지정하고(861–868행), 플랫폼 버스는 platform_match와 platform_probe를 각각 match·probe 콜백으로 둡니다(1482–1493행). 매칭 후 platform_probe()가 드라이버의 probe를 호출할 수 있습니다(1379–1416행). platform_get_resource()는 그 구현이 필요할 때 호출하는 자원 조회 함수이며 매칭 함수가 아닙니다(55–67행).
override, OF, ACPI, ID 테이블, 이름 비교의 순서를 확인합니다. ID 테이블이 있으면 불일치에서 이름 비교로 떨어지지 않습니다(1335–1358행).
일회성 __platform_driver_probe()는 동기 실행·deferred probe 제한·bound 장치 확인을 추가합니다(913–958행). 일반 드라이버의 probe 본문과 구분합니다.
실선은 버스 콜백의 순서와 분기, 점선은 드라이버 구현에서 선택적으로 일어나는 자원 조회입니다. platform_get_resource()가 매칭을 하거나 레지스터를 쓰는 화살표는 없습니다.
소스 코드 위치
먼저 확인할 Linux v6.6 소스 파일
Linux v6.6: drivers/base/platform.c
Linux v6.6: drivers/base/dd.c
Linux v6.6: include/linux/platform_device.h
설명: 이 글의 함수 역할·행 번호·그림은 고정된 v6.6 drivers/base/platform.c에서 확인했습니다. dd.c와 platform_device.h는 driver core 동작과 구조체 정의를 더 읽기 위한 원본 링크입니다.
대표 코드
아래 세 발췌는 v6.6 drivers/base/platform.c의 정확한 함수 범위다. 기존 상자의 앞뒤 무관한 코드와 잘린 일회성 등록 함수를 바로잡았다. 버스 platform_probe()는 별도 원문에서 확인한다.
platform_match(): 버스 매칭
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* When driver_override is set, only bind to the matching driver */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}읽는 법: pdev->driver_override가 설정되면 그 드라이버 이름과의 비교로 바로 끝난다. 그다음 OF·ACPI·ID·이름을 순서대로 확인하며 ID 테이블이 있으면 불일치에도 이름 fallback을 하지 않는다.
__platform_driver_probe(): 일회성 등록
int __init_or_module __platform_driver_probe(struct platform_driver *drv,
int (*probe)(struct platform_device *), struct module *module)
{
int retval;
if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) {
pr_err("%s: drivers registered with %s can not be probed asynchronously\n",
drv->driver.name, __func__);
return -EINVAL;
}
/*
* We have to run our probes synchronously because we check if
* we find any devices to bind to and exit with error if there
* are any.
*/
drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS;
/*
* Prevent driver from requesting probe deferral to avoid further
* futile probe attempts.
*/
drv->prevent_deferred_probe = true;
/* make sure driver won't have bind/unbind attributes */
drv->driver.suppress_bind_attrs = true;
/* temporary section violation during probe() */
drv->probe = probe;
retval = __platform_driver_register(drv, module);
if (retval)
return retval;
/* Force all new probes of this driver to fail */
drv->probe = platform_probe_fail;
/* Walk all platform devices and see if any actually bound to this driver.
* If not, return an error as the device should have done so by now.
*/
if (!bus_for_each_dev(&platform_bus_type, NULL, &drv->driver, is_bound_to_driver)) {
retval = -ENODEV;
platform_driver_unregister(drv);
}
return retval;
}읽는 법: 동기 probe·deferred probe 금지를 설정하고 등록 뒤 drv->probe를 실패 함수로 바꾼다. bound 장치가 없다면 -ENODEV로 등록 해제한다. 레지스터 설정 함수가 아니다.
platform_get_resource(): 자원 배열 조회
struct resource *platform_get_resource(struct platform_device *dev,
unsigned int type, unsigned int num)
{
u32 i;
for (i = 0; i < dev->num_resources; i++) {
struct resource *r = &dev->resource[i];
if (type == resource_type(r) && num-- == 0)
return r;
}
return NULL;
}읽는 법: 장치의 resource[]에서 요청 타입의 num번째 항목을 반환한다. 없으면 NULL; 장치·드라이버 매칭이나 mapping을 하지 않는다.
함수별 분석
원문의 “platform_driver_probe가 자원을 얻고 레지스터를 설정한 뒤 platform_get_resource가 compatible/name을 매칭한다”는 순서는 실제 함수의 역할과 반대입니다. 아래 표는 버스 콜백, 일회성 도우미, 드라이버별 조회를 분리합니다.
| 함수 | 입력·역할 | 결정하는 결과 | 원본 행 |
|---|---|---|---|
platform_match | 장치와 드라이버를 override·OF·ACPI·ID·이름 순으로 비교 | 매칭 여부; 자원 조회와 무관 | 1335–1358 |
platform_probe | 버스 probe 콜백; clock 기본값·PM domain을 준비한 뒤 드라이버 probe 호출 | probe 결과, 일회성 재호출 차단·deferred probe 처리 | 1379–1416 |
__platform_driver_probe | 비핫플러그 장치용 일회성 등록 도우미 | 동기 등록, bound 장치 없음 -ENODEV, 재probe 방지 | 913–958 |
platform_get_resource | 장치 자원 배열을 타입·순번으로 조회 | struct resource * 또는 NULL | 55–67 |
일반적인 매칭과 probe
__platform_driver_register()는 드라이버의 버스를 platform_bus_type으로 지정하고 등록합니다(861–868행). 그 버스의 .match와 .probe는 각각 platform_match, platform_probe입니다(1482–1493행). 장치와 드라이버가 매칭된 경우, 버스 probe 함수는 드라이버별 probe가 존재하면 호출합니다(1403–1407행).
자원 조회는 드라이버의 선택
드라이버 callback 안에서 필요한 resource를 찾을 수 있지만 platform_get_resource()는 그 callback을 자동으로 실행하지 않습니다. 내부 루프는 resource_type(r)과 요청 타입, 순번을 비교할 뿐입니다(55–67행).
구조체와 필드
platform_driver와 platform_device는 매칭의 양쪽 입력입니다. 자원 배열은 장치 쪽에 있고, 드라이버 callback이 필요할 때 이를 조회합니다. devm이나 regmap의 동작은 이 파일의 세 함수만으로 설명할 수 없어 이번 도식의 단계로 넣지 않았습니다.
| 대상 | 이 코드에서 맡는 역할 | 원본 행 |
|---|---|---|
platform_driver | 매칭 시 ID 테이블 참조, 버스 probe에서 드라이버의 probe callback 사용 | 1337–1354, 1379–1407 |
platform_device | 매칭에 쓰는 장치 이름 및 자원 배열을 보유 | 55–66, 1337–1357 |
dev->resource[] | 타입과 순번으로 조회할 기존 자원 항목 | 55–67 |
drv->probe | 버스 probe에서 호출하는 드라이버 callback; 일회성 도우미는 등록 후 실패 함수로 변경 | 940–947, 1403–1407 |
실행 단계와 상태 변화
일반 probe와 일회성 등록 도우미의 실패 경로가 다릅니다. 자원 조회 실패도 매칭 실패와 별개이므로, 어느 분기에서 멈췄는지 행 번호로 분리합니다.
| 조건 | 코드의 결과 | 해석 | 원본 행 |
|---|---|---|---|
| override 설정 | pdev->driver_override를 즉시 비교 | OF·ACPI·ID·이름 비교보다 우선 | 1340–1342 |
| ID 테이블 존재 | platform_match_id() 결과를 즉시 반환 | 불일치해도 이름 fallback을 수행하지 않음 | 1352–1357 |
| 일회성 등록에 비동기 선호 설정 | -EINVAL | 이 도우미는 동기 probe를 요구 | 918–929 |
| 일회성 등록 후 bound 장치 없음 | -ENODEV로 바꾸고 등록 해제 | 드라이버 probe가 성공했다고 가정하지 않음 | 949–955 |
| 요청 타입·순번의 자원 없음 | NULL | 매칭 실패가 아니라 자원 조회 결과 | 55–67 |
v6.6과 v6.18.37의 구현 차이
두 버전 모두 override → OF → ACPI → ID table → 이름 순서를 사용한다. 다만 이를 검사하는 API와 probe 실패 시 PM domain 처리 코드는 같지 않다.
| 경계 | Linux v6.6 | Linux v6.18.37 |
|---|---|---|
| override | pdev->driver_override를 직접 비교 (platform.c 1335–1358). | device_match_driver_override(dev, drv)의 음수가 아닌 결과를 반환 (platform.c 1305–1330). |
| driver probe 실패 | dev_pm_domain_attach(_dev, true) 뒤 드라이버 callback이 실패하면 dev_pm_domain_detach(_dev, true)를 여기서 호출 (platform.c 1379–1416). | PD_FLAG_ATTACH_POWER_ON | PD_FLAG_DETACH_POWER_OFF로 attach하며 이 함수 본문에는 callback 실패 직후 명시적 detach 호출이 없음 (platform.c 1351–1386). |
위 표는 두 platform_probe() 본문의 차이를 기술한다. 이것만으로 전체 driver core의 PM 정리 시점까지 단정하지 않는다.
불변 조건과 실패 사례
platform_match()는 override가 결론을 내리면 바로 반환하고, 그 뒤 OF·ACPI·ID·이름 순서입니다(1340–1357행). ID 테이블이 있을 때 이름 fallback을 기대하면 원인을 잘못 찾습니다.
__platform_driver_probe()는 deferred probe를 막고 등록 직후 drv->probe를 실패 함수로 바꿉니다(929–947행). 이 동작을 일반 등록의 성질로 확대하지 않습니다.
버스의 platform_probe()가 조건을 확인한 뒤 드라이버의 probe callback을 호출합니다(1379–1416행). 일회성 도우미 이름과 실제 하드웨어 초기화 callback을 구분합니다.
platform_get_resource()는 기존 resource[]에서 항목을 찾거나 NULL을 돌려줍니다(55–67행). 여기서 mapping, IRQ 요청, 레지스터 쓰기까지 완료됐다고 결론 내리지 않습니다.
계측과 검증
probe가 호출되지 않는다면 드라이버 본문보다 앞선 조건을 먼저 나눕니다. 버스의 .match와 .probe 연결(1482–1493행), 매칭 우선순위(1335–1358행), 일회성 등록의 동기·재probe 제한(913–958행), 자원 배열 조회(55–67행)는 서로 다른 확인 지점입니다.
| 증상 | 먼저 볼 조건 | 원본 행 |
|---|---|---|
| 매칭되지 않음 | override 결정값, OF·ACPI 결과, ID 테이블 존재 시 결과, 이름 fallback 여부 | 1335–1358 |
| 일회성 등록이 실패 | 비동기 선호는 -EINVAL; bound 장치가 없으면 -ENODEV와 등록 해제 | 918–921, 949–955 |
| 일회성 등록 후 다시 probe 불가 | drv->probe를 platform_probe_fail로 바꾼 시점 | 940–947, 1385–1393 |
| 자원을 못 찾음 | dev->resource[]에서 요청한 타입·순번이 존재하는지 | 55–67 |
추가 확인 사항
- 드라이버에 ID 테이블이 있을 때 그 ID가 실패하면 이름 fallback이 실행된다고 가정하고 있지 않은가(1352–1357행)?
- 일반
platform_driver_register()경로와 일회성platform_driver_probe()경로를 구분했는가(861–868, 893–958행)? platform_probe()에 도달하기 전인지, 도달한 뒤 드라이버의probe또는 deferred probe 조건에서 실패했는가(1379–1416행)?- 필요한 자원이 없는 것과 장치·드라이버가 매칭되지 않은 것을 별도 원인으로 기록했는가(55–67, 1335–1358행)?