aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/align.c36
-rw-r--r--arch/powerpc/kernel/ftrace.c5
-rw-r--r--arch/powerpc/kernel/head_32.S15
-rw-r--r--arch/powerpc/kernel/pci-common.c17
4 files changed, 49 insertions, 24 deletions
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index 5af4e9b2dbe..73cb6a3229a 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -367,27 +367,24 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
unsigned int flags)
{
- char *ptr = (char *) &current->thread.TS_FPR(reg);
- int i, ret;
+ char *ptr0 = (char *) &current->thread.TS_FPR(reg);
+ char *ptr1 = (char *) &current->thread.TS_FPR(reg+1);
+ int i, ret, sw = 0;
if (!(flags & F))
return 0;
if (reg & 1)
return 0; /* invalid form: FRS/FRT must be even */
- if (!(flags & SW)) {
- /* not byte-swapped - easy */
- if (!(flags & ST))
- ret = __copy_from_user(ptr, addr, 16);
- else
- ret = __copy_to_user(addr, ptr, 16);
- } else {
- /* each FPR value is byte-swapped separately */
- ret = 0;
- for (i = 0; i < 16; ++i) {
- if (!(flags & ST))
- ret |= __get_user(ptr[i^7], addr + i);
- else
- ret |= __put_user(ptr[i^7], addr + i);
+ if (flags & SW)
+ sw = 7;
+ ret = 0;
+ for (i = 0; i < 8; ++i) {
+ if (!(flags & ST)) {
+ ret |= __get_user(ptr0[i^sw], addr + i);
+ ret |= __get_user(ptr1[i^sw], addr + i + 8);
+ } else {
+ ret |= __put_user(ptr0[i^sw], addr + i);
+ ret |= __put_user(ptr1[i^sw], addr + i + 8);
}
}
if (ret)
@@ -646,11 +643,16 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg,
unsigned int areg, struct pt_regs *regs,
unsigned int flags, unsigned int length)
{
- char *ptr = (char *) &current->thread.TS_FPR(reg);
+ char *ptr;
int ret = 0;
flush_vsx_to_thread(current);
+ if (reg < 32)
+ ptr = (char *) &current->thread.TS_FPR(reg);
+ else
+ ptr = (char *) &current->thread.vr[reg - 32];
+
if (flags & ST)
ret = __copy_to_user(addr, ptr, length);
else {
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index 5355244c99f..60c60ccf5e3 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -195,8 +195,9 @@ __ftrace_make_nop(struct module *mod,
return -EINVAL;
}
- offset = (unsigned)((unsigned short)jmp[0]) << 16 |
- (unsigned)((unsigned short)jmp[1]);
+ /* The bottom half is signed extended */
+ offset = ((unsigned)((unsigned short)jmp[0]) << 16) +
+ (int)((short)jmp[1]);
DEBUGP(" %x ", offset);
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index a1c4cfd25de..d794a637e42 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -511,8 +511,11 @@ InstructionTLBMiss:
and r1,r1,r2 /* writable if _RW and _DIRTY */
rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */
rlwimi r3,r3,32-1,31,31 /* _PAGE_USER -> PP lsb */
- ori r1,r1,0xe14 /* clear out reserved bits and M */
+ ori r1,r1,0xe04 /* clear out reserved bits */
andc r1,r3,r1 /* PP = user? (rw&dirty? 2: 3): 0 */
+BEGIN_FTR_SECTION
+ rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
+END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
mtspr SPRN_RPA,r1
mfspr r3,SPRN_IMISS
tlbli r3
@@ -585,8 +588,11 @@ DataLoadTLBMiss:
and r1,r1,r2 /* writable if _RW and _DIRTY */
rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */
rlwimi r3,r3,32-1,31,31 /* _PAGE_USER -> PP lsb */
- ori r1,r1,0xe14 /* clear out reserved bits and M */
+ ori r1,r1,0xe04 /* clear out reserved bits */
andc r1,r3,r1 /* PP = user? (rw&dirty? 2: 3): 0 */
+BEGIN_FTR_SECTION
+ rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
+END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
mtspr SPRN_RPA,r1
mfspr r3,SPRN_DMISS
tlbld r3
@@ -653,8 +659,11 @@ DataStoreTLBMiss:
stw r3,0(r2) /* update PTE (accessed/dirty bits) */
/* Convert linux-style PTE to low word of PPC-style PTE */
rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */
- li r1,0xe15 /* clear out reserved bits and M */
+ li r1,0xe05 /* clear out reserved bits & PP lsb */
andc r1,r3,r1 /* PP = user? 2: 0 */
+BEGIN_FTR_SECTION
+ rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
+END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
mtspr SPRN_RPA,r1
mfspr r3,SPRN_DMISS
tlbld r3
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 19b12d2cbb4..0f418127231 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -561,8 +561,21 @@ int pci_mmap_legacy_page_range(struct pci_bus *bus,
(unsigned long long)(offset + size - 1));
if (mmap_state == pci_mmap_mem) {
- if ((offset + size) > hose->isa_mem_size)
- return -ENXIO;
+ /* Hack alert !
+ *
+ * Because X is lame and can fail starting if it gets an error trying
+ * to mmap legacy_mem (instead of just moving on without legacy memory
+ * access) we fake it here by giving it anonymous memory, effectively
+ * behaving just like /dev/zero
+ */
+ if ((offset + size) > hose->isa_mem_size) {
+ printk(KERN_DEBUG
+ "Process %s (pid:%d) mapped non-existing PCI legacy memory for 0%04x:%02x\n",
+ current->comm, current->pid, pci_domain_nr(bus), bus->number);
+ if (vma->vm_flags & VM_SHARED)
+ return shmem_zero_setup(vma);
+ return 0;
+ }
offset += hose->isa_mem_phys;
} else {
unsigned long io_offset = (unsigned long)hose->io_base_virt - _IO_BASE;