天天看點

IORESOURCE_IO和IORESOURCE_MEM

核心中有很多資源,但屬于IO資源的有:

#define IORESOURCE_IO        0x00000100   

#define IORESOURCE_MEM        0x00000200

#define IORESOURCE_IRQ        0x00000400

#define IORESOURCE_DMA        0x00000800

本文我主要研究IORESOURCE_IO IORESOURCE_MEM,及位址空間的管理,涉及的檔案隻有kernel/resource.c.

這兩種資源本質上都是一段位址空間. 隻是類型不一樣

IORESOURCE_IO 指的是IO位址空間,這個空間從kernel程式設計上來看,隻能通過專門的接口函數才能通路.硬體層面上,cpu需要用特殊指令才能通路或需要用特殊通路方式才能通路,不能直接用指針來尋址.在PC機上,其指的就是PCI/CPU IO address space.在嵌入式中,基本上沒有io address space. 

IORESOURCE_MEM 指的是屬于外設或者用于和裝置通訊的支援直接尋址的位址空間.PC機上,主機闆上北橋上連的記憶體都是交給kernel直接管理,或者都是用于軟體執行,是以這部分記憶體不屬于IORESOURCE_MEM, IORESOURCE_MEM主要是指PCI裝置的 memory address space. 但在嵌入式上, 主機闆上的sdram一般是裝置與cpu共享的. 故交給kernel直接管理的記憶體隻是一部分.餘下的記憶體以及寄存器空間都作為IORESOURCE_MEM來管理.

隻是以需要管理,是因為像PCI總路線裝置的這些位址空間是裝置向系統申請的,故是可配置的,并且裝置并身可能熱插撥或更換,故其變成一種可配置設定的資源. 故核心用算法來管理配置設定與釋放操作,防止沖突和便于查詢維護.但實際PC中,BIOS一般會做配置設定操作,核心需要是把配置設定結果添加進來,故提供了注冊(或者叫做添加)接口. 在嵌入式系統中,外設的位址也通常是固定的,隻需要添加即可.

這兩種資源,核心采用同樣的管理算法--二叉樹.相當于核心維護兩個獨立的二叉樹. 按位址基位址與位址長度範圍作為管理資料.可以添加,配置設定,釋放節點.配置設定過程中可以避

免空間沖突,添加時可以識别空間沖突.根節點在kernel/resource.c中以全局變量方式定義.根節點用于限制位址空間的範圍.

主要接口:

int insert_resource(struct resource *parent, struct resource *new)

int adjust_resource(struct resource *res, unsigned long start, unsigned long size)

int allocate_resource(struct resource *root, struct resource *new,

              unsigned long size,

              unsigned long min, unsigned long max,

              unsigned long align,

              void (*alignf)(void *, struct resource *,

                     unsigned long, unsigned long),

              void *alignf_data)

int release_resource(struct resource *old)

int request_resource(struct resource *root, struct resource *new)

上面的接口對上述4種資源類型都有效,對于IORESOURCE_IO 和 IORESOURCE_MEM這兩種資源,使用這兩個接口更為友善

request_region(start,n,name)

release_region(start,n)

        io space

request_mem_region(start,n,name)

release_mem_region(start,n)

        mem space

在 /proc 檔案系統中,ioports和iomem分别顯示系統目前這兩種資源.

嵌入式裝置的外設一般先作為platform device添加到platform bus上,其主要目的就是向系統注冊資源,在platform_add_devices時做,

如:

static struct resource wdt_resource[] = {

    [0] = {

        .start = 0xFFC00008,

        .end = 0xFFC00010,

        .flags = IORESOURCE_MEM,

    }

};

struct platform_device wdt_device = {

    .name = "wdt",

    .id = -1,

    .num_resources = ARRAY_SIZE(wdt_resource),

    .resource = wdt_resource,

};

platform_add_devices(wdt_device,1);

故如已知裝置的實體位址,并不一定需要request_mem_region,因為這個操作并沒有涉及到任何硬體,與軟體通路也沒有任何關系..但一般還是推薦做.

I/O port 通路流程( 不用mem模拟方式):

request_region()   #在裝置驅動子產品加載或opn() 函數中進行,實體i/o port位址由pci bios子產品配置設定

inb(),outb()等     #在裝置驅動初始化,write(),red(),ioctl() 等函數中進行

relase_region      #在裝置驅動子產品解除安裝或release() 函數中進行

I/O port 通路流程( 用mem模拟方式):

request_region() 

ioport_map         #在裝置驅動子產品加載或opn() 函數中進行,實體i/o port位址由pci bios子產品配置設定

ioread8,iowrite8等 #在裝置驅動初始化,write(),red(),ioctl() 等函數中進行

ioport_unmap()

relase_region      #在裝置驅動子產品解除安裝或release() 函數中進行

request_mem_region

ioremap         #在裝置驅動子產品加載或opn() 函數中進行,實體i/o port位址由pci bios子產品配置設定

ioread8,iowrite8等 #在裝置驅動初始化,write(),red(),ioctl() 等函數中進行

iounmap()

relase_region      #在裝置驅動子產品解除安裝或release() 函數中進行