Linux의 mmc 드라이버 개요

Linux Kernel의 mmc 드라이버를 조사할 기회가 있었으므로, 메모 대신에 개요를 정리해 보고 싶습니다.
(Kernel 버전은 4.1을 기반으로 작성되었습니다)

소개



mmc 드라이버는 Linux의 저장 장치 드라이버 중 하나입니다.
eMMC나 SD카드등의 디바이스를 Linux로 취급하기 위한 드라이버가 되고 있습니다.

다음과 같은 처리를 담당하고 있습니다.
  • 하드 초기화 처리
  • 연결된 장치의 인식 및 속도 모드 설정
  • SD 카드, eMMC 또는
  • SD 호스트 컨트롤러 인식

  • 파일 시스템 및 상위 계층에서 데이터 전송 요청 처리

  • mmc 드라이버의 구조



    mmc 드라이버의 소스는 아래에 저장됩니다.
    (Kernelソースディレクトリ)
      └ drivers
       └ mmc
        ├ card
        ├ core
        └ host
    

    mmc 드라이버는 아래 그림과 같이 구성되어 있습니다.



    mmc 블록 큐 드라이버



    이 부분에서는, 상위의 블록 I/O 처리부로부터 받은 요구를, 큐 드라이버가 큐로 관리합니다.
    그리고, 블록 드라이버는 큐로부터 픽업 된 요구의 타입 (read,write,erase 등)을 해석해, 한층 더 아래의 mmc 코어부에 건네줍니다.

    mmc 코어, SD 카드/eMMC 처리부



    mmc 코어부는 상위로부터 받은 요구의 대상이, SD 카드인지 eMMC인지를 판별하고, SD 카드/eMMC 처리부에 요구를 건네줍니다.

    SD 카드와 eMMC에서는 카드의 인식이나 스피드 모드의 설정 등, 세세한 부분에서 처리가 다르기 때문에, SD 카드/eMMC 처리부에서, 상위로부터의 요구를 각각에 대응한 처리로 바꾸어, 하위의 SD 호스트 컨트롤러 공통 처리부나 모델 종속부의 구현을 호출하여 호스트 컨트롤러를 제어합니다.

    SD 호스트 컨트롤러 공통 처리부/기종 의존부



    SD 호스트 컨트롤러의 레지스터를 두드려 조작하고 있는 부분이 여기가 됩니다.
    SD 호스트 컨트롤러는 규격화되어 ​​있어 레지스터 구조 등은 기본적으로 동일하게 되어 있으므로, 규격에 따른 기종을 사용하고 있는 경우는 거의 공통 처리부에서 처리할 수 있습니다.
    기종 의존부는, 하드의 초기화나, 그 이름대로 기종에 의해 공통 처리부에서는 대응할 수 없는 처리를 담당합니다.

    mmc 드라이버에서는, 기종 의존의 처리를 공통부에 건네주기 위해서, 이하의 2개의 구조체가 준비되어 있습니다. 각 멤버에는 공통 처리부에서 구현되는 함수를 사용할지, 모델 종속부에서 구현하는 함수를 사용할지를 선택할 수 있습니다.

    include/linux/mmc/host.h
    struct mmc_host_ops {
        /*
         * It is optional for the host to implement pre_req and post_req in
         * order to support double buffering of requests (prepare one
         * request while another request is active).
         * pre_req() must always be followed by a post_req().
         * To undo a call made to pre_req(), call post_req() with
         * a nonzero err condition.
         */
        void    (*post_req)(struct mmc_host *host, struct mmc_request *req,
                    int err);
        void    (*pre_req)(struct mmc_host *host, struct mmc_request *req,
                   bool is_first_req);
        void    (*request)(struct mmc_host *host, struct mmc_request *req);
        /*
         * Avoid calling these three functions too often or in a "fast path",
         * since underlaying controller might implement them in an expensive
         * and/or slow way.
         *
         * Also note that these functions might sleep, so don't call them
         * in the atomic contexts!
         *
         * Return values for the get_ro callback should be:
         *   0 for a read/write card
         *   1 for a read-only card
         *   -ENOSYS when not supported (equal to NULL callback)
         *   or a negative errno value when something bad happened
         *
         * Return values for the get_cd callback should be:
         *   0 for a absent card
         *   1 for a present card
         *   -ENOSYS when not supported (equal to NULL callback)
         *   or a negative errno value when something bad happened
         */
        void    (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
        int (*get_ro)(struct mmc_host *host);
        int (*get_cd)(struct mmc_host *host);
    
        void    (*enable_sdio_irq)(struct mmc_host *host, int enable);
    
        /* optional callback for HC quirks */
        void    (*init_card)(struct mmc_host *host, struct mmc_card *card);
    
        int (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
    
        /* Check if the card is pulling dat[0:3] low */
        int (*card_busy)(struct mmc_host *host);
    
        /* The tuning command opcode value is different for SD and eMMC cards */
        int (*execute_tuning)(struct mmc_host *host, u32 opcode);
    
        /* Prepare HS400 target operating frequency depending host driver */
        int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
        int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
        void    (*hw_reset)(struct mmc_host *host);
        void    (*card_event)(struct mmc_host *host);
    
        /*
         * Optional callback to support controllers with HW issues for multiple
         * I/O. Returns the number of supported blocks for the request.
         */
        int (*multi_io_quirk)(struct mmc_card *card,
                      unsigned int direction, int blk_size);
    };
    

    drivers/mmc/host/sdhci.h
    struct sdhci_ops {
    #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
        u32     (*read_l)(struct sdhci_host *host, int reg);
        u16     (*read_w)(struct sdhci_host *host, int reg);
        u8      (*read_b)(struct sdhci_host *host, int reg);
        void        (*write_l)(struct sdhci_host *host, u32 val, int reg);
        void        (*write_w)(struct sdhci_host *host, u16 val, int reg);
        void        (*write_b)(struct sdhci_host *host, u8 val, int reg);
    #endif
    
        void    (*set_clock)(struct sdhci_host *host, unsigned int clock);
    
        int     (*enable_dma)(struct sdhci_host *host);
        unsigned int    (*get_max_clock)(struct sdhci_host *host);
        unsigned int    (*get_min_clock)(struct sdhci_host *host);
        unsigned int    (*get_timeout_clock)(struct sdhci_host *host);
        unsigned int    (*get_max_timeout_count)(struct sdhci_host *host);
        void        (*set_timeout)(struct sdhci_host *host,
                           struct mmc_command *cmd);
        void        (*set_bus_width)(struct sdhci_host *host, int width);
        void (*platform_send_init_74_clocks)(struct sdhci_host *host,
                             u8 power_mode);
        unsigned int    (*get_ro)(struct sdhci_host *host);
        void        (*reset)(struct sdhci_host *host, u8 mask);
        int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
        void    (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
        void    (*hw_reset)(struct sdhci_host *host);
        void    (*adma_workaround)(struct sdhci_host *host, u32 intmask);
        void    (*platform_init)(struct sdhci_host *host);
        void    (*card_event)(struct sdhci_host *host);
        void    (*voltage_switch)(struct sdhci_host *host);
    };
    

    이러한 구조로 되어 있기 때문에, 드라이버 개발자는 공통부에 손을 넣지 않고, 기종 ​​의존부만을 기술하는 것으로 드라이버의 실장을 할 수 있게 되어 있습니다.

    참고 자료



    Linux Kernel MMC Storage driver Overview
    htps //w w. s에서 멋지다. 네 t / 라 m ぃ 라 j / ぃ ん x 케 r 네 루 m ㎝ s 라 게 d ゔ ぇ r ゔ ぇ r ゔ ぃ

    좋은 웹페이지 즐겨찾기