Chinaunix首页 | 论坛 | 博客
  • 博客访问: 493019
  • 博文数量: 154
  • 博客积分: 746
  • 博客等级: 入伍新兵
  • 技术积分: 1129
  • 用 户 组: 普通用户
  • 注册时间: 2011-05-20 09:20
个人简介

此生既入苦寒山,何妨再攀险峰!

文章分类

全部博文(154)

文章存档

2017年(1)

2016年(2)

2015年(25)

2014年(24)

2013年(8)

2012年(15)

2011年(79)

分类:

2011-09-20 10:43:14

申明:本文章是对Linux对I/O端口资源的管理”该文章进行总结,从2.4内核I/O端口资源管理经过少量的更改成2.6内核I/O资源管理

三、管理I/O Region资源
  Linux将基于I/O映射方式的I/O端口和基于内存映射方式的I/O端口资源统称为“I/O区域”(I/O Region)。I/O Region仍然是一种I/O资源,因此它仍然可以用resource结构类型来描述。下面我们就来看看Linux是如何管理I/O Region的。
  3.1 I/O Region的分配
  Linux实现了用于分配I/O区域的函数__request_region(),如下:



struct resource * __request_region(struct resource *parent,
                                   resource_size_t start, resource_size_t n,
                                   const char *name)
{
        struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);

        if (res) {
                res->name = name;
                res->start = start;
                res->end = start + n - 1;
                res->flags = IORESOURCE_BUSY;

                write_lock(&resource_lock);

                for (;;) {
                        struct resource *conflict;

                        conflict = __request_resource(parent, res);
                        if (!conflict)
                                break;
                        if (conflict != parent) {
                                parent = conflict;
                                if (!(conflict->flags & IORESOURCE_BUSY))
                                        continue;
                        }

                        /* Uhhuh, that didn't work out.. */
                        kfree(res);
                        res = NULL;
                        break;
                }
                write_unlock(&resource_lock);
        }
        return res;
}

  ①首先,调用kmalloc()函数在SLAB分配器缓存中分配一个resource结构。
  ②然后,相应的根据参数值初始化所分配的resource结构。注意!flags成员被初始化为IORESOURCE_BUSY。
  ③接下来,用一个for循环开始进行资源分配,循环体的步骤如下:
  1> 首先,调用__request_resource()函数进行资源分配。如果返回NULL,说明分配成功,因此就执行break语句推出for循环,返回所分配的resource结构的指针,函数成功地结束。
  2> 如果__request_resource()函数分配不成功,则进一步判断所返回的冲突资源节点是否就是父资源节点parent。如果不是,则将分配行 为下降一个层次,即试图在当前冲突的资源节点中进行分配(只有在冲突的资源节点没有设置IORESOURCE_BUSY的情况下才可以),于是让 parent指针等于conflict,并在conflict->flags&IORESOURCE_BUSY为0的情况下执行 continue语句继续for循环。
  3> 否则如果相冲突的资源节点就是父节点parent,或者相冲突资源节点设置了IORESOURCE_BUSY标志位,则宣告分配失败。于是调用 kfree()函数释放所分配的resource结构,并将res指针置为NULL,最后用break语句推出for循环。
  ④最后,返回所分配的resource结构的指针。


3.2 I/O Region释放
  函数__release_region()实现在一个父资源节点parent中释放给定范围的I/O Region。实际上该函数的实现思想与__release_resource()相类似。

void __release_region(struct resource *parent, resource_size_t start,
                        resource_size_t n)
{
        struct resource **p;
        resource_size_t end;

        p = &parent->child;
        end = start + n - 1;

        write_lock(&resource_lock);

        for (;;) {
                struct resource *res = *p;

                if (!res)
                        break;
                if (res->start <= start && res->end >= end) {
                        if (!(res->flags & IORESOURCE_BUSY)) {
                                p = &res->child;
                                continue;
                        }
                        if (res->start != start || res->end != end)
                                break;
                        *p = res->sibling;
                        write_unlock(&resource_lock);
                        kfree(res);
                        return;
                }
                p = &res->sibling;
        }

        write_unlock(&resource_lock);

        printk(KERN_WARNING "Trying to free nonexistent resource "
                "<%016llx-%016llx>\n", (unsigned long long)start,
                (unsigned long long)end);
}
  ①让res指针指向当前被扫描的子资源节点(res=*p)。
  ②如果res指针为NULL,说明已经扫描完整个child链表,所以退出for循环。
  ③如果res指针不为NULL,则继续看看所指定的I/O区域范围是否完全包含在当前资源节点中,也即看看[start,start+n-1]是否包 含在res->[start,end]中。如果不属于,则让p指向当前资源节点的sibling成员,然后继续for循环。如果属于,则执行下列步 骤:
  1> 先看看当前资源节点是否设置了IORESOURCE_BUSY标志位。如果没有设置该标志位,则说明该资源节点下面可能还会有子节点,因此将扫描过程下降 一个层次,于是修改p指针,使它指向res->child,然后执行continue语句继续for循环。
  2> 如果设置了IORESOURCE_BUSY标志位。则一定要确保当前资源节点就是所指定的I/O区域,然后将当前资源节点从其父资源的child链表中去 除。这可以通过让前一个兄弟资源节点的sibling指针指向当前资源节点的下一个兄弟资源节点来实现(即让*p=res->sibling),最 后调用kfree()函数释放当前资源节点的resource结构。然后函数就可以成功返回了。


四、管理I/O端口资源
  Linux是基于“I/O Region”这一概念来实现对I/O端口资源(I/O-mapped 或 Memory-mapped)的管理的。
  4.1 资源根节点的定义
  Linux在kernel/Resource.c文件中定义了全局变量ioport_resource和iomem_resource,来分别描述基 于I/O映射方式的整个I/O端口空间和基于内存映射方式的I/O内存资源空间(包括I/O端口和外设内存)。其定义如下:

struct resource ioport_resource = {
        .name = "PCI IO",
        .start = 0,
        .end = IO_SPACE_LIMIT,
        .flags = IORESOURCE_IO,
};

struct resource iomem_resource = {
        .name = "PCI mem",
        .start = 0,
        .end = -1,
        .flags = IORESOURCE_MEM,
};


阅读(462) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~