요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
============================
Platform Devices and Drivers
============================
See <linux/platform_device.h> for the driver model interface to the
platform bus: platform_device, and platform_driver. This pseudo-bus
is used to connect devices on buses with minimal infrastructure,
like those used to integrate peripherals on many system-on-chip
processors, or some "legacy" PC interconnects; as opposed to large
formally specified ones like PCI or USB.
Platform devices
~~~~~~~~~~~~~~~~
Platform devices are devices that typically appear as autonomous
entities in the system. This includes legacy port-based devices and
host bridges to peripheral buses, and most controllers integrated
into system-on-chip platforms. What they usually have in common
is direct addressing from a CPU bus. Rarely, a platform_device will
be connected through a segment of some other kind of bus; but its
registers will still be directly addressable.
Platform devices are given a name, used in driver binding, and a
list of resources such as addresses and IRQs::
struct platform_device {
const char *name;
u32 id;
struct device dev;
u32 num_resources;
struct resource *resource;
};
Platform drivers
~~~~~~~~~~~~~~~~
Platform drivers follow the standard driver model convention, where
discovery/enumeration is handled outside the drivers, and drivers
provide probe() and remove() methods. They support power management
and shutdown notifications using the standard conventions::
struct platform_driver {
int (*probe)(struct platform_device *);
void (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
bool driver_managed_dma;
};
Note that probe() should in general verify that the specified device hardware
actually exists; sometimes platform setup code can't be sure. The probing
can use device resources, including clocks, and device platform_data.
Platform drivers register themselves the normal way::
int platform_driver_register(struct platform_driver *drv);
Or, in common situations where the device is known not to be hot-pluggable,
the probe() routine can live in an init section to reduce the driver's
runtime memory footprint::
int platform_driver_probe(struct platform_driver *drv,
int (*probe)(struct platform_device *))
Kernel modules can be composed of several platform drivers. The platform core
provides helpers to register and unregister an array of drivers::
int __platform_register_drivers(struct platform_driver * const *drivers,
unsigned int count, struct module *owner);
void platform_unregister_drivers(struct platform_driver * const *drivers,
unsigned int count);
If one of the drivers fails to register, all drivers registered up to that
point will be unregistered in reverse order. Note that there is a convenience
macro that passes THIS_MODULE as owner parameter::
#define platform_register_drivers(drivers, count)
Device Enumeration
~~~~~~~~~~~~~~~~~~
As a rule, platform specific (and often board-specific) setup code will
register platform devices::
int platform_device_register(struct platform_device *pdev);
int platform_add_devices(struct platform_device **pdevs, int ndev);
The general rule is to register only those devices that actually exist,
but in some cases extra devices might be registered. For example, a kernel
might be configured to work with an external network adapter that might not
be populated on all boards, or likewise to work with an integrated controller
that some boards might not hook up to any peripherals.
In some cases, boot firmware will export tables describing the devices
that are populated on a given board. Without such tables, often the
only way for system setup code to set up the correct devices is to build
a kernel for a specific target board. Such board-specific kernels are
common with embedded and custom systems development.
In many cases, the memory and IRQ resources associated with the platform
device are not enough to let the device's driver work. Board setup code
will often provide additional information using the device's platform_data
field to hold additional information.
Embedded systems frequently need one or more clocks for platform devices,
which are normally kept off until they're actively needed (to save power).
System setup also associates those clocks with the device, so that
calls to clk_get(&pdev->dev, clock_name) return them as needed.
Legacy Drivers: Device Probing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Some drivers are not fully converted to the driver model, because they take
on a non-driver role: the driver registers its platform device, rather than
leaving that for system infrastructure. Such drivers can't be hotplugged
or coldplugged, since those mechanisms require device creation to be in a
different system component than the driver.
The only "good" reason for this is to handle older system designs which, like
original IBM PCs, rely on error-prone "probe-the-hardware" models for hardware
configuration. Newer systems have largely abandoned that model, in favor of
bus-level support for dynamic configuration (PCI, USB), or device tables
provided by the boot firmware (e.g. PNPACPI on x86). There are too many
conflicting options about what might be where, and even educated guesses by
an operating system will be wrong often enough to make trouble.
This style of driver is discouraged. If you're updating such a driver,
please try to move the device enumeration to a more appropriate location,
outside the driver. This will usually be cleanup, since such drivers
tend to already have "normal" modes, such as ones using device nodes that
were created by PNP or by platform device setup.
None the less, there are some APIs to support such legacy drivers. Avoid
using these calls except with such hotplug-deficient drivers::
struct platform_device *platform_device_alloc(
const char *name, int id);
You can use platform_device_alloc() to dynamically allocate a device, which
you will then initialize with resources and platform_device_register().
A better solution is usually::
struct platform_device *platform_device_register_simple(
const char *name, int id,
struct resource *res, unsigned int nres);
You can use platform_device_register_simple() as a one-step call to allocate
and register a device.
Device Naming and Driver Binding
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The platform_device.dev.bus_id is the canonical name for the devices.
It's built from two components:
* platform_device.name ... which is also used to for driver matching.
* platform_device.id ... the device instance number, or else "-1"
to indicate there's only one.
These are concatenated, so name/id "serial"/0 indicates bus_id "serial.0", and
"serial/3" indicates bus_id "serial.3"; both would use the platform_driver
named "serial". While "my_rtc"/-1 would be bus_id "my_rtc" (no instance id)
and use the platform_driver called "my_rtc".
Driver binding is performed automatically by the driver core, invoking
driver probe() after finding a match between device and driver. If the
probe() succeeds, the driver and device are bound as usual. There are
three different ways to find such a match:
- Whenever a device is registered, the drivers for that bus are
checked for matches. Platform devices should be registered very
early during system boot.
- When a driver is registered using platform_driver_register(), all
unbound devices on that bus are checked for matches. Drivers
usually register later during booting, or by module loading.
- Registering a driver using platform_driver_probe() works just like
using platform_driver_register(), except that the driver won't
be probed later if another device registers. (Which is OK, since
this interface is only for use with non-hotpluggable devices.)
Early Platform Devices and Drivers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The early platform interfaces provide platform data to platform device
drivers early on during the system boot. The code is built on top of the
early_param() command line parsing and can be executed very early on.
Example: "earlyprintk" class early serial console in 6 steps
1. Registering early platform device data
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The architecture code registers platform device data using the function
early_platform_add_devices(). In the case of early serial console this
should be hardware configuration for the serial port. Devices registered
at this point will later on be matched against early platform drivers.
2. Parsing kernel command line
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The architecture code calls parse_early_param() to parse the kernel
command line. This will execute all matching early_param() callbacks.
User specified early platform devices will be registered at this point.
For the early serial console case the user can specify port on the
kernel command line as "earlyprintk=serial.0" where "earlyprintk" is
the class string, "serial" is the name of the platform driver and
0 is the platform device id. If the id is -1 then the dot and the
id can be omitted.
3. Installing early platform drivers belonging to a certain class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The architecture code may optionally force registration of all early
platform drivers belonging to a certain class using the function
early_platform_driver_register_all(). User specified devices from
step 2 have priority over these. This step is omitted by the serial
driver example since the early serial driver code should be disabled
unless the user has specified port on the kernel command line.
4. Early platform driver registration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compiled-in platform drivers making use of early_platform_init() are
automatically registered during step 2 or 3. The serial driver example
should use early_platform_init("earlyprintk", &platform_driver).
5. Probing of early platform drivers belonging to a certain class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The architecture code calls early_platform_driver_probe() to match
registered early platform devices associated with a certain class with
registered early platform drivers. Matched devices will get probed().
This step can be executed at any point during the early boot. As soon
as possible may be good for the serial port case.
6. Inside the early platform driver probe()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The driver code needs to take special care during early boot, especially
when it comes to memory allocation and interrupt registration. The code
in the probe() function can use is_early_platform_device() to check if
it is called at early platform device or at the regular platform device
time. The early serial driver performs register_console() at this point.
For further information, see <linux/platform_device.h>.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Platform bus 소개
1-12platform bus의 driver model interface인 `platform_device`와 `platform_driver`는 `<linux/platform_device.h>`에 있습니다. 이 pseudo-bus는 PCI·USB처럼 큰 정식 specification이 있는 bus와 달리, 많은 SoC peripheral이나 일부 legacy PC interconnect처럼 infrastructure가 최소인 bus의 device를 연결합니다.
Platform device
13-34platform device는 보통 system에서 autonomous entity로 나타납니다. legacy port-based device, peripheral bus host bridge, 대부분의 SoC integrated controller가 포함됩니다. 공통점은 CPU bus에서 직접 address할 수 있다는 것입니다. 드물게 다른 bus segment를 거쳐도 register는 여전히 직접 address할 수 있습니다.
driver binding에 사용하는 name과 address·IRQ 같은 resource 목록을 가집니다.
struct platform_device {
const char *name;
u32 id;
struct device dev;
u32 num_resources;
struct resource *resource;
};
identity, generic core object와 resource를 구분했습니다.
Platform driver와 등록 helper
35-83platform driver는 discovery/enumeration을 driver 밖에서 처리하고 driver가 `probe()`와 `remove()`를 제공하는 standard driver model convention을 따릅니다. standard convention으로 power management와 shutdown notification도 지원합니다.
struct platform_driver {
int (*probe)(struct platform_device *);
void (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
bool driver_managed_dma;
};
`probe()`는 지정 hardware가 실제로 존재하는지 보통 확인해야 합니다. platform setup code가 확신하지 못할 수 있기 때문입니다. probing에는 clock을 포함한 device resource와 `platform_data`를 사용할 수 있습니다.
일반 등록 함수는 다음과 같습니다.
int platform_driver_register(struct platform_driver *drv);
hot-plug되지 않는 것이 확실한 흔한 경우에는 `probe()`를 init section에 두어 runtime memory footprint를 줄일 수 있습니다.
int platform_driver_probe(struct platform_driver *drv,
int (*probe)(struct platform_device *))
kernel module 하나가 여러 platform driver로 구성될 수 있어 core는 driver array 등록·해제 helper를 제공합니다.
int __platform_register_drivers(struct platform_driver * const *drivers,
unsigned int count, struct module *owner);
void platform_unregister_drivers(struct platform_driver * const *drivers,
unsigned int count);
driver 하나의 등록이 실패하면 앞서 등록된 모든 driver를 reverse order로 unregister합니다. owner로 `THIS_MODULE`을 넘기는 convenience macro도 있습니다.
#define platform_register_drivers(drivers, count)
부분 실패 시 rollback 순서를 나타냅니다.
Device enumeration과 board data
84-115일반적으로 platform-specific, 흔히 board-specific setup code가 platform device를 등록합니다.
int platform_device_register(struct platform_device *pdev);
int platform_add_devices(struct platform_device **pdevs, int ndev);
실제로 존재하는 device만 등록하는 것이 원칙이지만, 모든 board에 장착되지 않은 external network adapter나 peripheral에 연결되지 않은 integrated controller를 지원하려고 extra device를 등록할 수도 있습니다.
boot firmware가 board에 장착된 device table을 export하기도 합니다. table이 없으면 target board 전용 kernel을 build하는 것이 올바른 setup의 유일한 방법일 수 있으며 embedded·custom system에서 흔합니다.
memory와 IRQ resource만으로 부족하면 board setup code가 `platform_data` field에 추가 정보를 제공합니다. embedded system의 platform device는 power 절약을 위해 필요할 때만 켜는 clock이 흔하며 system setup이 clock을 device와 연결해 `clk_get(&pdev->dev, clock_name)`으로 얻도록 합니다.
Legacy probe-the-hardware driver
116-155일부 driver는 system infrastructure 대신 자신이 platform device를 등록하는 non-driver role까지 맡아 driver model로 완전히 전환되지 않았습니다. device creation과 driver가 분리되지 않으므로 hotplug·coldplug할 수 없습니다.
정당한 이유는 original IBM PC처럼 오류가 잦은 `probe-the-hardware` model에 의존하는 오래된 system을 처리하는 경우뿐입니다. 새 system은 PCI·USB dynamic configuration이나 PNPACPI 같은 boot firmware device table을 사용합니다. 가능한 위치 조합이 너무 많아 OS의 educated guess도 문제를 일으킬 만큼 자주 틀립니다.
이 style은 권장하지 않습니다. 수정할 때 device enumeration을 driver 밖의 적절한 위치로 옮겨야 합니다. PNP나 platform setup이 만든 device node를 쓰는 normal mode가 이미 있는 경우가 많아 보통 cleanup이 됩니다. 그래도 legacy 지원 API는 존재하며 hotplug가 불가능한 driver 외에는 피해야 합니다.
struct platform_device *platform_device_alloc(
const char *name, int id);
`platform_device_alloc()`으로 device를 동적 할당한 뒤 resource를 초기화하고 `platform_device_register()`로 등록할 수 있지만 보통 다음 one-step call이 더 낫습니다.
struct platform_device *platform_device_register_simple(
const char *name, int id,
struct resource *res, unsigned int nres);
`platform_device_register_simple()`은 device allocation과 registration을 한 번에 수행합니다.
Device naming과 automatic binding
156-189`platform_device.dev.bus_id`는 canonical device name이며 driver matching에도 쓰는 `platform_device.name`과 instance number인 `platform_device.id`를 결합합니다. instance가 하나뿐이면 id `-1`을 사용합니다.
name/id `serial`/0과 `serial`/3은 각각 `serial.0`, `serial.3`이 되고 둘 다 `serial` platform_driver를 사용합니다. `my_rtc`/-1은 instance suffix 없이 `my_rtc`가 되고 같은 이름의 driver를 사용합니다.
driver core는 device와 driver match를 찾은 뒤 `probe()`를 호출해 자동 binding합니다. device 등록 시 bus driver를 검사하므로 platform device는 boot 초기에 등록해야 합니다. `platform_driver_register()` 시 bus의 unbound device를 모두 검사하며 driver는 보통 boot 후반이나 module load 때 등록됩니다. `platform_driver_probe()`도 비슷하지만 이후 새 device가 등록되어도 다시 probe하지 않으므로 non-hotpluggable device에만 적합합니다.
세 binding 시점과 hotplug 특성을 비교했습니다.
Early platform interface 개요
190-197early platform interface는 boot 초기에 platform device driver에 platform data를 제공합니다. `early_param()` command-line parsing 위에 구현되어 매우 이르게 실행할 수 있습니다. 문서는 `earlyprintk` class early serial console을 6단계로 설명합니다.
data 등록에서 early probe까지의 전체 순서입니다.
1. Early device data 등록
198-204architecture code는 `early_platform_add_devices()`로 platform device data를 등록합니다. early serial console이라면 serial port hardware configuration입니다. 이때 등록한 device는 나중에 early platform driver와 match됩니다.
2. Kernel command line parsing
205-215architecture code가 `parse_early_param()`을 호출해 command line을 parse하고 일치하는 모든 `early_param()` callback을 실행합니다. user가 지정한 early platform device도 여기서 등록됩니다. serial console은 `earlyprintk=serial.0`처럼 class string, platform driver name, device id를 지정하며 id가 -1이면 dot과 id를 생략할 수 있습니다.
3. Class driver 강제 등록
216-224architecture code는 선택적으로 `early_platform_driver_register_all()`로 특정 class의 early platform driver를 모두 강제 등록할 수 있습니다. 2단계의 user-specified device가 우선합니다. early serial driver는 user가 command line에서 port를 지정하지 않으면 disable되어야 하므로 이 단계를 생략합니다.
4. Early driver registration
225-230`early_platform_init()`을 사용하는 built-in platform driver는 2단계나 3단계 중 자동 등록됩니다. serial 예제는 `early_platform_init("earlyprintk", &platform_driver)`를 사용해야 합니다.
5. Early driver probing
231-238architecture code가 `early_platform_driver_probe()`를 호출해 특정 class의 등록 device와 driver를 match하고 일치한 device를 `probe()`합니다. early boot 중 어느 때든 실행할 수 있으며 serial port는 가능한 한 이른 시점이 좋습니다.
6. Early probe 내부 주의점
239-247driver code는 early boot에서 memory allocation과 interrupt registration에 특별히 주의해야 합니다. `probe()`는 `is_early_platform_device()`로 early device 시점인지 regular platform device 시점인지 확인할 수 있습니다. early serial driver는 여기서 `register_console()`을 수행합니다. 자세한 내용은 `<linux/platform_device.h>`를 참고합니다.
요약과 해설
platform.rst:1-247platform bus는 SoC와 legacy device를 name/id·resource로 표현하고 enumeration과 driver를 분리합니다. 일반 등록·array rollback·legacy 제한·automatic binding을 제공하며 early platform interface로 command line parsing 전후의 매우 이른 console 같은 device도 안전하게 probe합니다.