ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [리눅스 커널] 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 *);
Designed by Tistory.