mips中的read、write、ioremap、out、in函数

一、我们在驱动里面一般是这样访问寄存器的(以龙芯1b-linux-3.1内核为例):

__raw_writel(__raw_readl(LS1X_INTC_INTCLR(n)) | (1 << bit), LS1X_INTC_INTCLR(n));  --->

#define LS1X_INTC_INTCLR(n)        LS1X_INTC_REG(n, 0xc)  ---->

#define LS1X_INTC_REG(n, x)  (ioremap(LS1X_INTC_BASE + (n * 0x18) + (x), 4)) ---->

#define LS1X_INTC_BASE            0x1fd01040

也就是先通过ioremap(),再用__raw_read()/__raw_write()来访问寄存器。下面我们分别来看一下这两个步骤是怎么实现的:

1、ioremap()

在/arch/mips/include/asm/io.h里定义:

#define ioremap(offset, size)                                           \
         __ioremap_mode((offset), (size), _CACHE_UNCACHED)

static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size,
172         unsigned long flags)
173 {
174         void __iomem *addr = plat_ioremap(offset, size, flags);
175 
176         if (addr)
177                 return addr;
178 
179 #define __IS_LOW512(addr) (!((phys_t)(addr) & (phys_t) ~0x1fffffffULL))
180 
181         if (cpu_has_64bit_addresses) {
182                 u64 base = UNCAC_BASE;
183 
184                 /*
185  * R10000 supports a 2 bit uncached attribute therefore
186  * UNCAC_BASE may not equal IO_BASE.
187  */
188                 if (flags == _CACHE_UNCACHED)
189                         base = (u64) IO_BASE;
190                 return (void __iomem *) (unsigned long) (base + offset);
191         } else if (__builtin_constant_p(offset) &&
192                    __builtin_constant_p(size) && __builtin_constant_p(flags)) {
193                 phys_t phys_addr, last_addr;
194 
195                 phys_addr = fixup_bigphys_addr(offset, size);
196 
197                 /* Don't allow wraparound or zero size. */
198                 last_addr = phys_addr + size - 1;
199                 if (!size || last_addr < phys_addr)
200                         return NULL;
201 
202                 /*
203  * Map uncached objects in the low 512MB of address
204  * space using KSEG1.
205  */
206                 if (__IS_LOW512(phys_addr) && __IS_LOW512(last_addr) &&
207                     flags == _CACHE_UNCACHED)
208                         return (void __iomem *)
209                                 (unsigned long)CKSEG1ADDR(phys_addr);
210         }
211 
212         return __ioremap(offset, size, flags);
213 
214 #undef __IS_LOW512
215 }

其中plat_ioremap定义为空,同时也不是64位的地址,而__builtin_constant_p(x)作用是用来确定一个值在编译时是否为常量
(use to determine whether a value is a constant at compile-time)。
如果x在编译的时候就能获得常值,则为TRUE;如果是变量则为FALSE,所以最终会执行__ioremap()。

2、__ioremap()
在/arch/mips/mm/ioremap.c里
void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
{
    ......
    
     if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
                vunmap(addr);
                return NULL;
     }

     return (void __iomem *) (offset + (char *)addr);
} 
作用就是将一个IO地址空间映射到内核的虚拟地址空间上去,返回一个虚拟地址。


3、__raw_read()/__raw_write()
现在先看一下/arch/mips/include/asm/io.h里的宏定义:
#define BUILDIO_MEM(bwlq, type)                                         \
414                                                                         \
415 __BUILD_MEMORY_PFX(__raw_, bwlq, type)                                  \
416 __BUILD_MEMORY_PFX(, bwlq, type)                                        \
417 __BUILD_MEMORY_PFX(__mem_, bwlq, type)                                  \

#define __BUILD_MEMORY_PFX(bus, bwlq, type)            __BUILD_MEMORY_SINGLE(bus, bwlq, type, 1) ------>

#define __BUILD_MEMORY_SINGLE(pfx, bwlq, type, irq)                     \
305                                                                         \
306 static inline void pfx##write##bwlq(type val,                           \
307                                     volatile void __iomem *mem)         \
308 {                                                                       \
309         volatile type *__mem;                                           \
310         type __val;                                                     \
311                                                                         \
312         war_octeon_io_reorder_wmb();                                    \
313                                                                         \
314         __mem = (void *)__swizzle_addr_##bwlq((unsigned long)(mem));    \
315                                                                         \
316         __val = pfx##ioswab##bwlq(__mem, val);                          \
317                                                                         \
318         if (sizeof(type) != sizeof(u64) || sizeof(u64) == sizeof(long)) \
319                 *__mem = __val;                                         \
320         else if (cpu_has_64bits) {                                      \
321                 unsigned long __flags;                                  \
322                 type __tmp;                                             \
323                                                                         \
324                 if (irq)                                                \
325                         local_irq_save(__flags);                        \
326                 __asm__ __volatile__(                                   \
327                         ".set   mips3"          "\t\t# __writeq""\n\t"  \
328                         "dsll32 %L0, %L0, 0"                    "\n\t"  \
329                         "dsrl32 %L0, %L0, 0"                    "\n\t"  \
330                         "dsll32 %M0, %M0, 0"                    "\n\t"  \
331                         "or     %L0, %L0, %M0"                  "\n\t"  \
332                         "sd     %L0, %2"                        "\n\t"  \
333                         ".set   mips0"                          "\n"    \
334                         : "=r" (__tmp)                                  \
335                         : "" (__val), "m" (*__mem));                   \
336                 if (irq)                                                \
337                         local_irq_restore(__flags);                     \
338         } else                                                          \
339                 BUG();                                                  \
340 }  

所以调用__raw_read/__raw_write()时,会把__raw当作参数传给pfx,
所以pfx##write##bwlq相当于pfx##=__raw,##bwlq=空。
也就是说,__raw_write()最终只会执行:*__mem = __val;只是对ioremap返回的虚拟地址进行赋值。
同时在/arch/mips/include/asm/mach-generic/mangle-port.h这个文件里我们可以看到__swizzle_addr_b和ioswabb的定义
#define __swizzle_addr_b(port)  (port)
# define ioswabb(a, x)          (x)

4、inb/outb
在文件/arch/mips/include/asm/io.h里,跟上面的方法类似也定义了以下宏:
432 BUILDIO_IOPORT(b, u8)
433 BUILDIO_IOPORT(w, u16)
434 BUILDIO_IOPORT(l, u32)
展开宏的方式也是类似的,最终展开的结果是:
static inline void pfx##out##bwlq##p(type val, unsigned long port)      \
377 {                                                                       \
            .....
382                                                                         \
383         __addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \
384                                                                         \
385         __val = pfx##ioswab##bwlq(__addr, val);                         \
386                                                                         \
387         /* Really, we want this to be atomic */                         \
388         BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));             \
389                                                                         \
390         *__addr = __val;                                                \
391         slow;                                                           \
392 }         
相当于对(mips_io_port_base + port)的虚拟地址进行读写。

参考文章:

http://blog.csdn.net/adaptiver/article/details/6874271

http://blog.chinaunix.net/space.php?uid=15724196&do=blog&id=128138

http://blog.csdn.net/do2jiang/article/details/5450839

你可能感兴趣的:(IO,cache,null,Build,64bit)