-
[리눅스 커널] Bus Types.Linux/kernel 2023. 8. 3. 02:32
글의 참고
- https://www.kernel.org/doc/html/next/driver-api/driver-model/bus.html
- http://www.makelinux.net/ldd3/chp-14-sect-4.shtml#chp-14-FNOTE-1
- https://www.cnblogs.com/schips/p/linux_device_model.html
글의 전제
- 내가 글을 쓰다가 궁금한 점은 파란색 볼드체로 표현했다. 나도 모르기 때문에 나중에 알아봐야 할 내용이라는 뜻이다.
- 밑줄로 작성된 글은 좀 더 긴 설명이 필요해서 친 것이다. 그러므로, 밑 줄 처친 글이 이해가 안간다면 링크를 따라서 관련 내용을 공부하자.
- `글의 참조`에서 빨간색 볼드체로 체크된 링크는 이 글을 작성하면 가장 많이 참조한 링크다.
- 이 글은 글의 참조에 있는 링크들을 내 마음대로 번역한 것이다. 심지어 필요없다고 생각된 부분은 생략했음을 알린다.
- 글의 참고의 번역본과 같다.
글의 내용
- Declaration
- 커널에서 각 버스(PCI, USB, etc)들은 변수로 선언이 가능하다. 예를 들어, PC안에 여러 개의 PCI 버스들이 존재할 수 있다. 그 PCI 버스들은 각각 `pci_bus_type`을 통해서 선언이 가능하다. 그렇면, SW 입장에서 여러 개의 PCI 버스들이 존재할 수 있는데, 어떻게 구별할까? `name` 필드로 구분한다.
struct bus_type pci_bus_type = { .name = "pci", .match = pci_bus_match, };
- name 필드 초기화는 필수다. `match` callback 초기화는 optional이다.
- 위의 변수는 export 되어야 한다. -> extern struct bus_type pci_bus_type;
- Registration
- 버스 드라이버가 초기화되면, 버스 드라이버 bus_register() 함수를 호출한다. 이 함수는 bus_type 구조체의 많은 필드들을 초기화해주고 global lis of bus types에 초기화한 버스를 추가시킨다. Once the bus object is registered, the fields in it are usable by the bus driver.
- match(): Attaching Drivers to Devices
- device ID 구조체의 멤버 변수들과 device ID를 비교하는 방식은 버스마다 모두 다르다. -> I2C, PLATFORM, USB, PCI 버스의 device ID 구조체의 멤버 변수는 실제 모두 다르다. 그리고 여기서 `device ID 비교` 라는 것은 버스마다 matching 메커니즘이 모두 다르다는 것을 해석될 거 같다.
- 일반적으로 드라이버는 버스별로 자기가 지원하는 디바이스들에 대한 ID 배열을 가지고 있다.
- 실제 driver와 device가 binding이 되는지를 판단하는 것은 앞에 driver와 device가 올라타고 있는 bus에 의해서 결정된다. bus들은 driver와 device 바인딩을 `match` callback function을 통해 처리한다. binding 과정은 driver가 지원하는 여러 device ID들과 특정 device의 device ID를 비교함으로써, device ID가 서로 동일하다면 binding 되는 식이다.
- driver가 특정 버스에 등록되면, bus`s list of devices를 순회한다. 그리고 driver와 matching되지 않은 각 devices의 match callback이 호출된다.
- Device and Driver Lists
- LDM(Linux Driver Model) core는 아래의 2개의 helper functions을 제공해서 각 리스트(디바이스, 드라이버)를 쉽게 순회할 수 있도록 해준다.
int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, int (*fn)(struct device *, void *)); int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, void * data, int (*fn)(struct device_driver *, void *));
- These helpers iterate over the respective list, and call the callback for each device or driver in the list. -> 여기서 말하는 callback은 각 함수의 4번째 파라미터를 의미한다.
- All list accesses are synchronized by taking the bus’s lock (read currently). The reference count on each object in the list is incremented before the callback is called; it is decremented after the next object has been obtained. The lock is not held when calling the callback.
- sysfs
- /sys/bus/ 폴더가 존재.
- 각 버스 폴더(pci, usb, platform 등)는 `/sys/bus/` 아래 만들어진다. 그리고 각 버스 폴더안에는 또 2개의 폴더(devices, drivers)가 기본적으로 만들어진다.
/sys/bus/pci/ |-- devices `-- drivers
- pci bus에 등록된 드라이버는 /sys/bus/pci/drivers/에 자신만의 폴더가 하나 더 생긴다. 그래서 아래를 보면, pci bus에 붙은 드라이버가 4개를 라는 것을 알 수 있고, 각 드라이버별 (Inter ICH, Interl ICH Joystick, agpgart, e100) 폴더가 있는것을 확인 할 수 있다.
/sys/bus/pci/ |-- devices `-- drivers |-- Intel ICH |-- Intel ICH Joystick |-- agpgart `-- e100
- 각 디바이스들도 마찬가지다. pci bus에 등록된 디바이스는 /sys/bus/pci/devices/에 자신만의 폴더가 하나 더 생긴다. 그런데 차이가 있다면, 각 디바이스 폴더들(/sys/bus/pci/devices/)은 /sys/devices/ 폴더로 symlink를 갖는다.
- Exporting Attributes
struct bus_attribute { struct attribute attr; ssize_t (*show)(struct bus_type *, char * buf); ssize_t (*store)(struct bus_type *, const char * buf, size_t count); };
- Devices들이 DEVIEC_ATTR_RW() 매크로를 사용해서 attributes를 만드는 것처럼, bus drivers 들도 BUS_ATTR_RW() 매크로를 통해서 attributes를 만들 수 있다.
static BUS_ATTR_RW(debug);
- 위의 라인은 아래 내용과 기능적으로 동일한 기능을 한다.
static bus_attribute bus_attr_debug;
- 위의 attributes 는 아래의 2개 함수를 통해 bus`s sysfs로 add 혹 romove 될 수 있다.
int bus_create_file(struct bus_type *, struct bus_attribute *); void bus_remove_file(struct bus_type *, struct bus_attribute *);
'Linux > kernel' 카테고리의 다른 글
[리눅스 커널] CPU topology (0) 2023.08.03 [리눅스 커널] CPU overview (0) 2023.08.03 [리눅스 커널] PM - System Power Management (0) 2023.08.03 [리눅스 커널] Symmetric Multi-Processing(SMP) (0) 2023.08.03 [리눅스] Linux kernel headers (0) 2023.08.03