linux下inb函数的有效反胃,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.youkuaiyun.com/adaptiver/article/details/6874271

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

http://blog.youkuaiyun.com/do2jiang/article/details/5450839

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值