Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb3e5cce authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge master.kernel.org:/home/rmk/linux-2.6-arm

* master.kernel.org:/home/rmk/linux-2.6-arm:
  ARM: 5974/1: arm/mach-at91 Makefile: remove two blanks.
  ARM: 6052/1: kdump: make kexec work in interrupt context
  ARM: 6051/1: VFP: preserve the HW context when calling signal handlers
  ARM: 6050/1: VFP: fix the SMP versions of vfp_{sync,flush}_hwstate
  ARM: 6007/1: fix highmem with VIPT cache and DMA
  ARM: 5975/1: AT91 slow-clock suspend: don't wait when turning PLLs off
parents 13bd8e46 b1cdbb5f
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -11,7 +11,11 @@

#define kmap_prot		PAGE_KERNEL

#define flush_cache_kmaps()	flush_cache_all()
#define flush_cache_kmaps() \
	do { \
		if (cache_is_vivt()) \
			flush_cache_all(); \
	} while (0)

extern pte_t *pkmap_page_table;

@@ -21,11 +25,20 @@ extern void *kmap_high(struct page *page);
extern void *kmap_high_get(struct page *page);
extern void kunmap_high(struct page *page);

extern void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte);
extern void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte);

/*
 * The following functions are already defined by <linux/highmem.h>
 * when CONFIG_HIGHMEM is not set.
 */
#ifdef CONFIG_HIGHMEM
extern void *kmap(struct page *page);
extern void kunmap(struct page *page);
extern void *kmap_atomic(struct page *page, enum km_type type);
extern void kunmap_atomic(void *kvaddr, enum km_type type);
extern void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
extern struct page *kmap_atomic_to_page(const void *ptr);
#endif

#endif
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ enum km_type {
	KM_IRQ1,
	KM_SOFTIRQ0,
	KM_SOFTIRQ1,
	KM_L1_CACHE,
	KM_L2_CACHE,
	KM_TYPE_NR
};
+11 −12
Original line number Diff line number Diff line
@@ -59,23 +59,22 @@ struct iwmmxt_sigframe {
#endif /* CONFIG_IWMMXT */

#ifdef CONFIG_VFP
#if __LINUX_ARM_ARCH__ < 6
/* For ARM pre-v6, we use fstmiax and fldmiax.  This adds one extra
 * word after the registers, and a word of padding at the end for
 * alignment.  */
#define VFP_MAGIC		0x56465001
#define VFP_STORAGE_SIZE	152
#else
#define VFP_MAGIC		0x56465002
#define VFP_STORAGE_SIZE	144
#endif

struct vfp_sigframe
{
	unsigned long		magic;
	unsigned long		size;
	union vfp_state		storage;
};
	struct user_vfp		ufp;
	struct user_vfp_exc	ufp_exc;
} __attribute__((__aligned__(8)));

/*
 *  8 byte for magic and size, 264 byte for ufp, 12 bytes for ufp_exc,
 *  4 bytes padding.
 */
#define VFP_STORAGE_SIZE	sizeof(struct vfp_sigframe)

#endif /* CONFIG_VFP */

/*
@@ -91,7 +90,7 @@ struct aux_sigframe {
#ifdef CONFIG_IWMMXT
	struct iwmmxt_sigframe	iwmmxt;
#endif
#if 0 && defined CONFIG_VFP /* Not yet saved.  */
#ifdef CONFIG_VFP
	struct vfp_sigframe	vfp;
#endif
	/* Something that isn't a valid magic number for any coprocessor.  */
+11 −1
Original line number Diff line number Diff line
@@ -83,11 +83,21 @@ struct user{

/*
 * User specific VFP registers. If only VFPv2 is present, registers 16 to 31
 * are ignored by the ptrace system call.
 * are ignored by the ptrace system call and the signal handler.
 */
struct user_vfp {
	unsigned long long fpregs[32];
	unsigned long fpscr;
};

/*
 * VFP exception registers exposed to user space during signal delivery.
 * Fields not relavant to the current VFP architecture are ignored.
 */
struct user_vfp_exc {
	unsigned long	fpexc;
	unsigned long	fpinst;
	unsigned long	fpinst2;
};

#endif /* _ARM_USER_H */
+89 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <asm/cacheflush.h>
#include <asm/ucontext.h>
#include <asm/unistd.h>
#include <asm/vfp.h>

#include "ptrace.h"
#include "signal.h"
@@ -175,6 +176,90 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)

#endif

#ifdef CONFIG_VFP

static int preserve_vfp_context(struct vfp_sigframe __user *frame)
{
	struct thread_info *thread = current_thread_info();
	struct vfp_hard_struct *h = &thread->vfpstate.hard;
	const unsigned long magic = VFP_MAGIC;
	const unsigned long size = VFP_STORAGE_SIZE;
	int err = 0;

	vfp_sync_hwstate(thread);
	__put_user_error(magic, &frame->magic, err);
	__put_user_error(size, &frame->size, err);

	/*
	 * Copy the floating point registers. There can be unused
	 * registers see asm/hwcap.h for details.
	 */
	err |= __copy_to_user(&frame->ufp.fpregs, &h->fpregs,
			      sizeof(h->fpregs));
	/*
	 * Copy the status and control register.
	 */
	__put_user_error(h->fpscr, &frame->ufp.fpscr, err);

	/*
	 * Copy the exception registers.
	 */
	__put_user_error(h->fpexc, &frame->ufp_exc.fpexc, err);
	__put_user_error(h->fpinst, &frame->ufp_exc.fpinst, err);
	__put_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err);

	return err ? -EFAULT : 0;
}

static int restore_vfp_context(struct vfp_sigframe __user *frame)
{
	struct thread_info *thread = current_thread_info();
	struct vfp_hard_struct *h = &thread->vfpstate.hard;
	unsigned long magic;
	unsigned long size;
	unsigned long fpexc;
	int err = 0;

	__get_user_error(magic, &frame->magic, err);
	__get_user_error(size, &frame->size, err);

	if (err)
		return -EFAULT;
	if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE)
		return -EINVAL;

	/*
	 * Copy the floating point registers. There can be unused
	 * registers see asm/hwcap.h for details.
	 */
	err |= __copy_from_user(&h->fpregs, &frame->ufp.fpregs,
				sizeof(h->fpregs));
	/*
	 * Copy the status and control register.
	 */
	__get_user_error(h->fpscr, &frame->ufp.fpscr, err);

	/*
	 * Sanitise and restore the exception registers.
	 */
	__get_user_error(fpexc, &frame->ufp_exc.fpexc, err);
	/* Ensure the VFP is enabled. */
	fpexc |= FPEXC_EN;
	/* Ensure FPINST2 is invalid and the exception flag is cleared. */
	fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
	h->fpexc = fpexc;

	__get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err);
	__get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err);

	if (!err)
		vfp_flush_hwstate(thread);

	return err ? -EFAULT : 0;
}

#endif

/*
 * Do a signal return; undo the signal stack.  These are aligned to 64-bit.
 */
@@ -233,8 +318,8 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
		err |= restore_iwmmxt_context(&aux->iwmmxt);
#endif
#ifdef CONFIG_VFP
//	if (err == 0)
//		err |= vfp_restore_state(&sf->aux.vfp);
	if (err == 0)
		err |= restore_vfp_context(&aux->vfp);
#endif

	return err;
@@ -348,8 +433,8 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
		err |= preserve_iwmmxt_context(&aux->iwmmxt);
#endif
#ifdef CONFIG_VFP
//	if (err == 0)
//		err |= vfp_save_state(&sf->aux.vfp);
	if (err == 0)
		err |= preserve_vfp_context(&aux->vfp);
#endif
	__put_user_error(0, &aux->end_magic, err);

Loading