요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
================
EISA bus support
================
:Author: Marc Zyngier <[email protected]>
This document groups random notes about porting EISA drivers to the
new EISA/sysfs API.
Starting from version 2.5.59, the EISA bus is almost given the same
status as other much more mainstream buses such as PCI or USB. This
has been possible through sysfs, which defines a nice enough set of
abstractions to manage buses, devices and drivers.
Although the new API is quite simple to use, converting existing
drivers to the new infrastructure is not an easy task (mostly because
detection code is generally also used to probe ISA cards). Moreover,
most EISA drivers are among the oldest Linux drivers so, as you can
imagine, some dust has settled here over the years.
The EISA infrastructure is made up of three parts:
- The bus code implements most of the generic code. It is shared
among all the architectures that the EISA code runs on. It
implements bus probing (detecting EISA cards available on the bus),
allocates I/O resources, allows fancy naming through sysfs, and
offers interfaces for driver to register.
- The bus root driver implements the glue between the bus hardware
and the generic bus code. It is responsible for discovering the
device implementing the bus, and setting it up to be latter probed
by the bus code. This can go from something as simple as reserving
an I/O region on x86, to the rather more complex, like the hppa
EISA code. This is the part to implement in order to have EISA
running on an "new" platform.
- The driver offers the bus a list of devices that it manages, and
implements the necessary callbacks to probe and release devices
whenever told to.
Every function/structure below lives in <linux/eisa.h>, which depends
heavily on <linux/device.h>.
Bus root driver
===============
::
int eisa_root_register (struct eisa_root_device *root);
The eisa_root_register function is used to declare a device as the
root of an EISA bus. The eisa_root_device structure holds a reference
to this device, as well as some parameters for probing purposes::
struct eisa_root_device {
struct device *dev; /* Pointer to bridge device */
struct resource *res;
unsigned long bus_base_addr;
int slots; /* Max slot number */
int force_probe; /* Probe even when no slot 0 */
u64 dma_mask; /* from bridge device */
int bus_nr; /* Set by eisa_root_register */
struct resource eisa_root_res; /* ditto */
};
============= ======================================================
node used for eisa_root_register internal purpose
dev pointer to the root device
res root device I/O resource
bus_base_addr slot 0 address on this bus
slots max slot number to probe
force_probe Probe even when slot 0 is empty (no EISA mainboard)
dma_mask Default DMA mask. Usually the bridge device dma_mask.
bus_nr unique bus id, set by eisa_root_register
============= ======================================================
Driver
======
::
int eisa_driver_register (struct eisa_driver *edrv);
void eisa_driver_unregister (struct eisa_driver *edrv);
Clear enough ?
::
struct eisa_device_id {
char sig[EISA_SIG_LEN];
unsigned long driver_data;
};
struct eisa_driver {
const struct eisa_device_id *id_table;
struct device_driver driver;
};
=============== ====================================================
id_table an array of NULL terminated EISA id strings,
followed by an empty string. Each string can
optionally be paired with a driver-dependent value
(driver_data).
driver a generic driver, such as described in
Documentation/driver-api/driver-model/driver.rst. Only .name,
.probe and .remove members are mandatory.
=============== ====================================================
An example is the 3c59x driver::
static struct eisa_device_id vortex_eisa_ids[] = {
{ "TCM5920", EISA_3C592_OFFSET },
{ "TCM5970", EISA_3C597_OFFSET },
{ "" }
};
static struct eisa_driver vortex_eisa_driver = {
.id_table = vortex_eisa_ids,
.driver = {
.name = "3c59x",
.probe = vortex_eisa_probe,
.remove = vortex_eisa_remove
}
};
Device
======
The sysfs framework calls .probe and .remove functions upon device
discovery and removal (note that the .remove function is only called
when driver is built as a module).
Both functions are passed a pointer to a 'struct device', which is
encapsulated in a 'struct eisa_device' described as follows::
struct eisa_device {
struct eisa_device_id id;
int slot;
int state;
unsigned long base_addr;
struct resource res[EISA_MAX_RESOURCES];
u64 dma_mask;
struct device dev; /* generic device */
};
======== ============================================================
id EISA id, as read from device. id.driver_data is set from the
matching driver EISA id.
slot slot number which the device was detected on
state set of flags indicating the state of the device. Current
flags are EISA_CONFIG_ENABLED and EISA_CONFIG_FORCED.
res set of four 256 bytes I/O regions allocated to this device
dma_mask DMA mask set from the parent device.
dev generic device (see Documentation/driver-api/driver-model/device.rst)
======== ============================================================
You can get the 'struct eisa_device' from 'struct device' using the
'to_eisa_device' macro.
Misc stuff
==========
::
void eisa_set_drvdata (struct eisa_device *edev, void *data);
Stores data into the device's driver_data area.
::
void *eisa_get_drvdata (struct eisa_device *edev):
Gets the pointer previously stored into the device's driver_data area.
::
int eisa_get_region_index (void *addr);
Returns the region number (0 <= x < EISA_MAX_RESOURCES) of a given
address.
Kernel parameters
=================
eisa_bus.enable_dev
A comma-separated list of slots to be enabled, even if the firmware
set the card as disabled. The driver must be able to properly
initialize the device in such conditions.
eisa_bus.disable_dev
A comma-separated list of slots to be disabled, even if the firmware
set the card as enabled. The driver won't be called to handle this
device.
virtual_root.force_probe
Force the probing code to probe EISA slots even when it cannot find an
EISA compliant mainboard (nothing appears on slot 0). Defaults to 0
(don't force), and set to 1 (force probing) when
CONFIG_EISA_VLB_PRIMING is set.
Random notes
============
Converting an EISA driver to the new API mostly involves *deleting*
code (since probing is now in the core EISA code). Unfortunately, most
drivers share their probing routine between ISA, and EISA. Special
care must be taken when ripping out the EISA code, so other buses
won't suffer from these surgical strikes...
You *must not* expect any EISA device to be detected when returning
from eisa_driver_register, since the chances are that the bus has not
yet been probed. In fact, that's what happens most of the time (the
bus root driver usually kicks in rather late in the boot process).
Unfortunately, most drivers are doing the probing by themselves, and
expect to have explored the whole machine when they exit their probe
routine.
For example, switching your favorite EISA SCSI card to the "hotplug"
model is "the right thing"(tm).
Thanks
======
I'd like to thank the following people for their help:
- Xavier Benigni for lending me a wonderful Alpha Jensen,
- James Bottomley, Jeff Garzik for getting this stuff into the kernel,
- Andries Brouwer for contributing numerous EISA ids,
- Catrin Jones for coping with far too many machines at home.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
EISA/sysfs API 개요
1-43문서 제목은 `EISA bus support`이며 저자는 Marc Zyngier `<[email protected]>`입니다. 기존 EISA driver를 새 EISA/sysfs API로 porting할 때 필요한 여러 note를 모았습니다.
kernel 2.5.59부터 EISA bus는 PCI나 USB 같은 mainstream bus와 거의 같은 지위를 갖게 되었습니다. sysfs가 bus, device, driver를 관리하는 충분한 abstraction을 정의한 덕분입니다.
새 API 자체는 단순하지만 기존 driver 전환은 쉽지 않습니다. detection code를 ISA card probing에도 함께 사용하는 경우가 많고, EISA driver 대부분이 오래된 Linux driver라 누적된 legacy code가 많기 때문입니다.
EISA infrastructure는 세 부분으로 구성됩니다.
- `bus code`: EISA가 동작하는 모든 architecture가 공유하는 generic code입니다. bus probing으로 사용 가능한 EISA card를 검출하고, I/O resource를 할당하며, sysfs를 통한 이름 지정과 driver registration interface를 제공합니다.
- `bus root driver`: bus hardware와 generic bus code를 잇는 glue입니다. bus를 구현하는 device를 찾고 generic bus code가 나중에 probe할 수 있도록 setup합니다. x86의 단순한 I/O region reserve부터 hppa EISA의 복잡한 처리까지 platform마다 다르며, 새 platform에서 EISA를 지원하려면 이 부분을 구현합니다.
- `driver`: 자신이 관리하는 device 목록을 bus에 제공하고, 요청받을 때 device를 probe하고 release하는 callback을 구현합니다.
아래 모든 function과 structure는 `<linux/eisa.h>`에 있으며 이 header는 `<linux/device.h>`에 크게 의존합니다.
generic bus, platform glue와 device driver의 책임을 구분했습니다.
Bus root driver
44-76`eisa_root_register()`는 device를 EISA bus의 root로 선언합니다.
int eisa_root_register (struct eisa_root_device *root);
`struct eisa_root_device`는 bridge/root device reference와 probing에 필요한 parameter를 보관합니다.
struct eisa_root_device {
struct device *dev; /* Pointer to bridge device */
struct resource *res;
unsigned long bus_base_addr;
int slots; /* Max slot number */
int force_probe; /* Probe even when no slot 0 */
u64 dma_mask; /* from bridge device */
int bus_nr; /* Set by eisa_root_register */
struct resource eisa_root_res; /* ditto */
};
원문의 field 설명 표는 다음과 같습니다. `node`는 `eisa_root_register` 내부 용도이고, `dev`는 root device pointer, `res`는 root I/O resource, `bus_base_addr`는 해당 bus의 slot 0 address입니다. `slots`는 probe할 최대 slot number, `force_probe`는 slot 0이 비어 있어 EISA mainboard가 보이지 않아도 probe할지 여부입니다. `dma_mask`는 보통 bridge device에서 가져온 기본 DMA mask이고 `bus_nr`는 register 함수가 설정하는 unique bus ID입니다.
============= ======================================================
node used for eisa_root_register internal purpose
dev pointer to the root device
res root device I/O resource
bus_base_addr slot 0 address on this bus
slots max slot number to probe
force_probe Probe even when slot 0 is empty (no EISA mainboard)
dma_mask Default DMA mask. Usually the bridge device dma_mask.
bus_nr unique bus id, set by eisa_root_register
============= ======================================================
structure의 `eisa_root_res` 역시 `eisa_root_register()`가 설정하는 root resource입니다.
bridge reference, probing 범위와 register 결과를 구분했습니다.
EISA driver 등록과 ID table
77-126EISA driver는 다음 API로 등록하고 unregister합니다.
int eisa_driver_register (struct eisa_driver *edrv);
void eisa_driver_unregister (struct eisa_driver *edrv);
`struct eisa_device_id`는 길이 `EISA_SIG_LEN`인 signature와 driver-specific `driver_data`를 가집니다. `struct eisa_driver`는 ID table과 generic `struct device_driver`를 포함합니다.
struct eisa_device_id {
char sig[EISA_SIG_LEN];
unsigned long driver_data;
};
struct eisa_driver {
const struct eisa_device_id *id_table;
struct device_driver driver;
};
`id_table`은 NULL-terminated EISA ID string array이며 마지막에는 empty string entry가 옵니다. 각 string에는 선택적으로 driver-dependent value인 `driver_data`를 짝지을 수 있습니다.
`driver`는 `Documentation/driver-api/driver-model/driver.rst`가 설명하는 generic driver입니다. `.name`, `.probe`, `.remove` member만 필수입니다.
=============== ====================================================
id_table an array of NULL terminated EISA id strings,
followed by an empty string. Each string can
optionally be paired with a driver-dependent value
(driver_data).
driver a generic driver, such as described in
Documentation/driver-api/driver-model/driver.rst. Only .name,
.probe and .remove members are mandatory.
=============== ====================================================
3c59x driver 예제는 `TCM5920`, `TCM5970` ID를 offset 값과 연결하고 empty entry로 table을 끝낸 뒤 `3c59x`라는 generic driver name과 probe/remove callback을 설정합니다.
static struct eisa_device_id vortex_eisa_ids[] = {
{ "TCM5920", EISA_3C592_OFFSET },
{ "TCM5970", EISA_3C597_OFFSET },
{ "" }
};
static struct eisa_driver vortex_eisa_driver = {
.id_table = vortex_eisa_ids,
.driver = {
.name = "3c59x",
.probe = vortex_eisa_probe,
.remove = vortex_eisa_remove
}
};
ID table 등록에서 generic callback 호출까지의 흐름입니다.
EISA device 표현
127-160sysfs framework는 device를 발견하거나 제거할 때 `.probe`와 `.remove`를 호출합니다. `.remove`는 driver를 module로 build한 경우에만 호출된다는 점에 유의해야 합니다.
두 callback은 `struct device` pointer를 받으며, 이 generic device는 다음 `struct eisa_device` 안에 포함됩니다.
struct eisa_device {
struct eisa_device_id id;
int slot;
int state;
unsigned long base_addr;
struct resource res[EISA_MAX_RESOURCES];
u64 dma_mask;
struct device dev; /* generic device */
};
`id`는 device에서 읽은 EISA ID이고 `id.driver_data`는 matching driver의 EISA ID entry에서 설정됩니다. `slot`은 device를 발견한 slot number입니다. `state`는 device 상태 flag 집합이며 현재 `EISA_CONFIG_ENABLED`와 `EISA_CONFIG_FORCED`가 있습니다.
`res`는 device에 할당된 256byte I/O region 네 개의 집합이고 `dma_mask`는 parent device에서 가져옵니다. `dev`는 `Documentation/driver-api/driver-model/device.rst`가 설명하는 generic device입니다.
======== ============================================================
id EISA id, as read from device. id.driver_data is set from the
matching driver EISA id.
slot slot number which the device was detected on
state set of flags indicating the state of the device. Current
flags are EISA_CONFIG_ENABLED and EISA_CONFIG_FORCED.
res set of four 256 bytes I/O regions allocated to this device
dma_mask DMA mask set from the parent device.
dev generic device (see Documentation/driver-api/driver-model/device.rst)
======== ============================================================
generic `struct device`에서 enclosing `struct eisa_device`를 얻을 때는 `to_eisa_device` macro를 사용합니다.
bus에서 검출한 identity, resource와 generic device 연결입니다.
Driver data와 region helper
161-182`eisa_set_drvdata()`는 device의 `driver_data` area에 caller data를 저장합니다.
void eisa_set_drvdata (struct eisa_device *edev, void *data);
`eisa_get_drvdata()`는 앞서 device의 `driver_data` area에 저장한 pointer를 반환합니다. 원문의 declaration 끝에 있는 colon 표기를 그대로 보존했습니다.
void *eisa_get_drvdata (struct eisa_device *edev):
`eisa_get_region_index()`는 주어진 address가 속한 region number를 반환하며 범위는 `0 <= x < EISA_MAX_RESOURCES`입니다.
int eisa_get_region_index (void *addr);
driver-private data와 resource index 접근 API입니다.
Kernel parameter
183-201`eisa_bus.enable_dev`는 firmware가 disabled로 표시했어도 강제로 enable할 slot의 comma-separated list입니다. 이 조건에서도 driver가 device를 올바르게 initialize할 수 있어야 합니다.
`eisa_bus.disable_dev`는 firmware가 enabled로 표시했어도 disable할 slot의 comma-separated list입니다. 해당 device를 처리하도록 driver를 호출하지 않습니다.
`virtual_root.force_probe`는 EISA-compliant mainboard를 찾지 못해 slot 0에 아무것도 나타나지 않아도 EISA slot을 probe하도록 강제합니다. 기본값은 0으로 강제하지 않으며 `CONFIG_EISA_VLB_PRIMING`을 설정하면 1, 즉 force probing이 됩니다.
firmware 상태 override와 virtual root probing을 정리했습니다.
Driver porting과 probe 시점 주의
202-221EISA driver를 새 API로 바꾸는 작업은 probing이 core EISA code로 이동했으므로 대체로 code를 삭제하는 일입니다. 하지만 대부분 driver가 ISA와 EISA 사이에 probing routine을 공유하므로 EISA code를 제거할 때 다른 bus 경로를 손상하지 않도록 특별히 주의해야 합니다.
`eisa_driver_register()`가 반환할 때 EISA device가 이미 검출되었을 것이라고 절대 기대하면 안 됩니다. bus가 아직 probe되지 않았을 가능성이 크고, bus root driver는 보통 boot process의 상당히 늦은 시점에 동작합니다.
기존 driver 대부분은 직접 probing하며 probe routine을 빠져나올 때 machine 전체를 탐색했다고 가정합니다. 이러한 전제를 버리고 EISA SCSI card 같은 device를 hotplug model로 전환하는 것이 올바른 방향입니다.
driver 등록 반환과 실제 device discovery가 분리될 수 있음을 보여줍니다.
감사
222-230저자는 도움을 준 다음 사람들에게 감사를 표합니다.
- 멋진 Alpha Jensen을 빌려준 Xavier Benigni
- 이 code를 kernel에 넣는 데 기여한 James Bottomley와 Jeff Garzik
- 많은 EISA ID를 제공한 Andries Brouwer
- 집의 너무 많은 machine을 감당한 Catrin Jones
요약과 해설
eisa.rst:1-230새 EISA API는 card detection과 I/O resource 할당을 generic bus core로 옮기고, platform별 root driver가 hardware bridge를 등록하며 개별 driver는 ID table과 probe/remove callback에 집중하게 합니다.
전환의 핵심은 ISA와 공유하던 legacy probing code를 조심스럽게 분리하고, `eisa_driver_register()` 반환과 실제 device discovery가 동기화되어 있다고 가정하지 않는 것입니다. device는 boot 후반의 root bus probing 뒤 hotplug model로 bind될 수 있습니다.