Proposed changes to io.h
John Whitney
johnw at sands-edge.com
Thu Apr 1 01:44:25 EST 2004
I've made few changes to include/asm-ppc/io.h that might want to be
incorporated into the mainline tree. These changes include:
1. Modifications to virt_to_bus, bus_to_virt, virt_to_phys, and
phys_to_virt. With the use of fully virtual addresses for
cache-coherent allocations (consistent_alloc(), etc.), just subracting
KERNELBASE from the virtual address is no longer sufficient. Because
of this, I have modified virt_to_phys and phys_to_virt to look like:
extern inline unsigned long virt_to_phys(volatile void * address)
{
unsigned long phys_addr;
unsigned long virt_addr = (unsigned long) address;
#ifndef CONFIG_APUS
if ((virt_addr >= KERNELBASE) && (virt_addr < (unsigned long)
high_memory))
phys_addr = (virt_addr - KERNELBASE);
else
phys_addr = iopa (virt_addr);
#else
phys_addr = iopa (virt_addr);
#endif
return phys_addr;
}
extern inline void * phys_to_virt(unsigned long address)
{
#ifndef CONFIG_APUS
return (void *) (address + KERNELBASE);
#else
return (void*) mm_ptov (address);
#endif
}
And I have modified virt_to_bus and bus_to_virt to use those inlined
functions:
extern inline unsigned long virt_to_bus(volatile void * address)
{
if (address == (void *) 0)
return 0;
return virt_to_phys (address) + PCI_DRAM_OFFSET;
}
extern inline void * bus_to_virt(unsigned long address)
{
if (address == 0)
return 0;
return phys_to_virt (address - PCI_DRAM_OFFSET);
}
This simplifies the "bus" routines, and makes sure that they use the
standard virtual/physical translations.
2. I'd like to add 64-bit __raw_readll and __raw_writell routines to
io.h, done using floating-point registers. Currently, modules such as
MTD (when writing to 64-bit buses) perform two 32-bit, non-atomic
writes, which can cause problems. Using a floating-point register to
guarantee a 64-bit write is ugly, but it works. Code for these inlined
routines is as follows:
/*
* For reading and writing 64-bit values, we need to use the floating
point
* registers. The code will enable MSR_FP in the MSR register, use
FPR1 to
* read from and write to memory, and then restore everything to the
* previous values.
*/
#define __raw_readll __raw_readll
static inline unsigned long long __raw_readll (int addr)
{
unsigned long flags;
unsigned long msr;
unsigned long msr_save;
unsigned long long result;
unsigned long long fp_save;
local_irq_save (flags);
asm volatile ("sync\n"
"mfmsr %0\n"
"ori %1,%0,0x2000\n"
"mtmsr %1\n"
"isync\n"
"stfdx 1,0,%2\n"
"lfdx 1,0,%4\n"
"stfdx 1,0,%3\n"
"sync\n"
"lfdx 1,0,%2\n"
"mtmsr %0\n"
"sync\n"
"isync\n"
: "=&r" (msr_save), "=&r" (msr)
: "r" (&fp_save), "r" (&result), "r" (addr)
: "memory" );
local_irq_restore (flags);
return result;
}
#define __raw_writell __raw_writell
static inline void __raw_writell (unsigned long long value, int addr)
{
unsigned long flags;
unsigned long msr;
unsigned long msr_save;
unsigned long long fp_save;
local_irq_save (flags);
asm volatile ("sync\n"
"mfmsr %0\n"
"ori %1,%0,0x2000\n"
"mtmsr %1\n"
"isync\n"
"stfdx 1,0,%2\n"
"lfdx 1,0,%3\n"
"stfdx 1,0,%4\n"
"sync\n"
"lfdx 1,0,%2\n"
"mtmsr %0\n"
"sync\n"
"isync\n"
: "=&r" (msr_save), "=&r" (msr)
: "r" (&fp_save), "r" (&value), "r" (addr)
: "memory" );
local_irq_restore (flags);
return;
}
Questions, comments, or flames?
John Whitney
-------------- next part --------------
A non-text attachment was scrubbed...
Name: io.h.patch
Type: application/octet-stream
Size: 4949 bytes
Desc: not available
URL: <http://lists.ozlabs.org/pipermail/linuxppc-dev/attachments/20040331/4e07aec6/attachment.obj>
More information about the Linuxppc-dev
mailing list