Commit 4157368e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'stable' of git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile

Pull arch/tile bug fixes from Chris Metcalf:
 "This includes Paul Gortmaker's change to fix the <asm/system.h>
  disintegration issues on tile, a fix to unbreak the tilepro ethernet
  driver, and a backlog of bugfix-only changes from internal Tilera
  development over the last few months.

  They have all been to LKML and on linux-next for the last few days.
  The EDAC change to MAINTAINERS is an oddity but discussion on the
  linux-edac list suggested I ask you to pull that change through my
  tree since they don't have a tree to pull edac changes from at the
  moment."

* 'stable' of git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile: (39 commits)
  drivers/net/ethernet/tile: fix netdev_alloc_skb() bombing
  MAINTAINERS: update EDAC information
  tilepro ethernet driver: fix a few minor issues
  tile-srom.c driver: minor code cleanup
  edac: say "TILEGx" not "TILEPro" for the tilegx edac driver
  arch/tile: avoid accidentally unmasking NMI-type interrupt accidentally
  arch/tile: remove bogus performance optimization
  arch/tile: return SIGBUS for addresses that are unaligned AND invalid
  arch/tile: fix finv_buffer_remote() for tilegx
  arch/tile: use atomic exchange in arch_write_unlock()
  arch/tile: stop mentioning the "kvm" subdirectory
  arch/tile: export the page_home() function.
  arch/tile: fix pointer cast in cacheflush.c
  arch/tile: fix single-stepping over swint1 instructions on tilegx
  arch/tile: implement panic_smp_self_stop()
  arch/tile: add "nop" after "nap" to help GX idle power draw
  arch/tile: use proper memparse() for "maxmem" options
  arch/tile: fix up locking in pgtable.c slightly
  arch/tile: don't leak kernel memory when we unload modules
  arch/tile: fix bug in delay_backoff()
  ...
parents 9479f0f8 00a62d4b
...@@ -2450,17 +2450,17 @@ F: fs/ecryptfs/ ...@@ -2450,17 +2450,17 @@ F: fs/ecryptfs/
EDAC-CORE EDAC-CORE
M: Doug Thompson <dougthompson@xmission.com> M: Doug Thompson <dougthompson@xmission.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net W: bluesmoke.sourceforge.net
S: Supported S: Supported
F: Documentation/edac.txt F: Documentation/edac.txt
F: drivers/edac/edac_* F: drivers/edac/
F: include/linux/edac.h F: include/linux/edac.h
EDAC-AMD64 EDAC-AMD64
M: Doug Thompson <dougthompson@xmission.com> M: Doug Thompson <dougthompson@xmission.com>
M: Borislav Petkov <borislav.petkov@amd.com> M: Borislav Petkov <borislav.petkov@amd.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net W: bluesmoke.sourceforge.net
S: Supported S: Supported
F: drivers/edac/amd64_edac* F: drivers/edac/amd64_edac*
...@@ -2468,35 +2468,35 @@ F: drivers/edac/amd64_edac* ...@@ -2468,35 +2468,35 @@ F: drivers/edac/amd64_edac*
EDAC-E752X EDAC-E752X
M: Mark Gross <mark.gross@intel.com> M: Mark Gross <mark.gross@intel.com>
M: Doug Thompson <dougthompson@xmission.com> M: Doug Thompson <dougthompson@xmission.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/e752x_edac.c F: drivers/edac/e752x_edac.c
EDAC-E7XXX EDAC-E7XXX
M: Doug Thompson <dougthompson@xmission.com> M: Doug Thompson <dougthompson@xmission.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/e7xxx_edac.c F: drivers/edac/e7xxx_edac.c
EDAC-I82443BXGX EDAC-I82443BXGX
M: Tim Small <tim@buttersideup.com> M: Tim Small <tim@buttersideup.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/i82443bxgx_edac.c F: drivers/edac/i82443bxgx_edac.c
EDAC-I3000 EDAC-I3000
M: Jason Uhlenkott <juhlenko@akamai.com> M: Jason Uhlenkott <juhlenko@akamai.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/i3000_edac.c F: drivers/edac/i3000_edac.c
EDAC-I5000 EDAC-I5000
M: Doug Thompson <dougthompson@xmission.com> M: Doug Thompson <dougthompson@xmission.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/i5000_edac.c F: drivers/edac/i5000_edac.c
...@@ -2525,21 +2525,21 @@ F: drivers/edac/i7core_edac.c ...@@ -2525,21 +2525,21 @@ F: drivers/edac/i7core_edac.c
EDAC-I82975X EDAC-I82975X
M: Ranganathan Desikan <ravi@jetztechnologies.com> M: Ranganathan Desikan <ravi@jetztechnologies.com>
M: "Arvind R." <arvino55@gmail.com> M: "Arvind R." <arvino55@gmail.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/i82975x_edac.c F: drivers/edac/i82975x_edac.c
EDAC-PASEMI EDAC-PASEMI
M: Egor Martovetsky <egor@pasemi.com> M: Egor Martovetsky <egor@pasemi.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/pasemi_edac.c F: drivers/edac/pasemi_edac.c
EDAC-R82600 EDAC-R82600
M: Tim Small <tim@buttersideup.com> M: Tim Small <tim@buttersideup.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/r82600_edac.c F: drivers/edac/r82600_edac.c
......
...@@ -12,7 +12,7 @@ config TILE ...@@ -12,7 +12,7 @@ config TILE
select GENERIC_PENDING_IRQ if SMP select GENERIC_PENDING_IRQ if SMP
select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW
select SYS_HYPERVISOR select SYS_HYPERVISOR
select ARCH_HAVE_NMI_SAFE_CMPXCHG if !M386 select ARCH_HAVE_NMI_SAFE_CMPXCHG
# FIXME: investigate whether we need/want these options. # FIXME: investigate whether we need/want these options.
# select HAVE_IOREMAP_PROT # select HAVE_IOREMAP_PROT
...@@ -69,6 +69,9 @@ config ARCH_PHYS_ADDR_T_64BIT ...@@ -69,6 +69,9 @@ config ARCH_PHYS_ADDR_T_64BIT
config ARCH_DMA_ADDR_T_64BIT config ARCH_DMA_ADDR_T_64BIT
def_bool y def_bool y
config NEED_DMA_MAP_STATE
def_bool y
config LOCKDEP_SUPPORT config LOCKDEP_SUPPORT
def_bool y def_bool y
...@@ -118,7 +121,7 @@ config 64BIT ...@@ -118,7 +121,7 @@ config 64BIT
config ARCH_DEFCONFIG config ARCH_DEFCONFIG
string string
default "arch/tile/configs/tile_defconfig" if !TILEGX default "arch/tile/configs/tilepro_defconfig" if !TILEGX
default "arch/tile/configs/tilegx_defconfig" if TILEGX default "arch/tile/configs/tilegx_defconfig" if TILEGX
source "init/Kconfig" source "init/Kconfig"
...@@ -240,6 +243,7 @@ endchoice ...@@ -240,6 +243,7 @@ endchoice
config PAGE_OFFSET config PAGE_OFFSET
hex hex
depends on !64BIT
default 0xF0000000 if VMSPLIT_3_75G default 0xF0000000 if VMSPLIT_3_75G
default 0xE0000000 if VMSPLIT_3_5G default 0xE0000000 if VMSPLIT_3_5G
default 0xB0000000 if VMSPLIT_2_75G default 0xB0000000 if VMSPLIT_2_75G
......
...@@ -30,7 +30,8 @@ ifneq ($(CONFIG_DEBUG_EXTRA_FLAGS),"") ...@@ -30,7 +30,8 @@ ifneq ($(CONFIG_DEBUG_EXTRA_FLAGS),"")
KBUILD_CFLAGS += $(CONFIG_DEBUG_EXTRA_FLAGS) KBUILD_CFLAGS += $(CONFIG_DEBUG_EXTRA_FLAGS)
endif endif
LIBGCC_PATH := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) LIBGCC_PATH := \
$(shell $(CC) $(KBUILD_CFLAGS) $(KCFLAGS) -print-libgcc-file-name)
# Provide the path to use for "make defconfig". # Provide the path to use for "make defconfig".
KBUILD_DEFCONFIG := $(ARCH)_defconfig KBUILD_DEFCONFIG := $(ARCH)_defconfig
...@@ -53,8 +54,6 @@ libs-y += $(LIBGCC_PATH) ...@@ -53,8 +54,6 @@ libs-y += $(LIBGCC_PATH)
# See arch/tile/Kbuild for content of core part of the kernel # See arch/tile/Kbuild for content of core part of the kernel
core-y += arch/tile/ core-y += arch/tile/
core-$(CONFIG_KVM) += arch/tile/kvm/
ifdef TILERA_ROOT ifdef TILERA_ROOT
INSTALL_PATH ?= $(TILERA_ROOT)/tile/boot INSTALL_PATH ?= $(TILERA_ROOT)/tile/boot
endif endif
......
...@@ -60,8 +60,8 @@ ...@@ -60,8 +60,8 @@
_concat4(SPR_IPI_EVENT_, CONFIG_KERNEL_PL,,) _concat4(SPR_IPI_EVENT_, CONFIG_KERNEL_PL,,)
#define SPR_IPI_EVENT_RESET_K \ #define SPR_IPI_EVENT_RESET_K \
_concat4(SPR_IPI_EVENT_RESET_, CONFIG_KERNEL_PL,,) _concat4(SPR_IPI_EVENT_RESET_, CONFIG_KERNEL_PL,,)
#define SPR_IPI_MASK_SET_K \ #define SPR_IPI_EVENT_SET_K \
_concat4(SPR_IPI_MASK_SET_, CONFIG_KERNEL_PL,,) _concat4(SPR_IPI_EVENT_SET_, CONFIG_KERNEL_PL,,)
#define INT_IPI_K \ #define INT_IPI_K \
_concat4(INT_IPI_, CONFIG_KERNEL_PL,,) _concat4(INT_IPI_, CONFIG_KERNEL_PL,,)
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#ifndef _ASM_TILE_ATOMIC_H #ifndef _ASM_TILE_ATOMIC_H
#define _ASM_TILE_ATOMIC_H #define _ASM_TILE_ATOMIC_H
#include <asm/cmpxchg.h>
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <linux/compiler.h> #include <linux/compiler.h>
...@@ -121,54 +123,6 @@ static inline int atomic_read(const atomic_t *v) ...@@ -121,54 +123,6 @@ static inline int atomic_read(const atomic_t *v)
*/ */
#define atomic_add_negative(i, v) (atomic_add_return((i), (v)) < 0) #define atomic_add_negative(i, v) (atomic_add_return((i), (v)) < 0)
/* Nonexistent functions intended to cause link errors. */
extern unsigned long __xchg_called_with_bad_pointer(void);
extern unsigned long __cmpxchg_called_with_bad_pointer(void);
#define xchg(ptr, x) \
({ \
typeof(*(ptr)) __x; \
switch (sizeof(*(ptr))) { \
case 4: \
__x = (typeof(__x))(typeof(__x-__x))atomic_xchg( \
(atomic_t *)(ptr), \
(u32)(typeof((x)-(x)))(x)); \
break; \
case 8: \
__x = (typeof(__x))(typeof(__x-__x))atomic64_xchg( \
(atomic64_t *)(ptr), \
(u64)(typeof((x)-(x)))(x)); \
break; \
default: \
__xchg_called_with_bad_pointer(); \
} \
__x; \
})
#define cmpxchg(ptr, o, n) \
({ \
typeof(*(ptr)) __x; \
switch (sizeof(*(ptr))) { \
case 4: \
__x = (typeof(__x))(typeof(__x-__x))atomic_cmpxchg( \
(atomic_t *)(ptr), \
(u32)(typeof((o)-(o)))(o), \
(u32)(typeof((n)-(n)))(n)); \
break; \
case 8: \
__x = (typeof(__x))(typeof(__x-__x))atomic64_cmpxchg( \
(atomic64_t *)(ptr), \
(u64)(typeof((o)-(o)))(o), \
(u64)(typeof((n)-(n)))(n)); \
break; \
default: \
__cmpxchg_called_with_bad_pointer(); \
} \
__x; \
})
#define tas(ptr) (xchg((ptr), 1))
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#ifndef __tilegx__ #ifndef __tilegx__
......
...@@ -200,7 +200,7 @@ static inline u64 atomic64_add_return(u64 i, atomic64_t *v) ...@@ -200,7 +200,7 @@ static inline u64 atomic64_add_return(u64 i, atomic64_t *v)
* @u: ...unless v is equal to u. * @u: ...unless v is equal to u.
* *
* Atomically adds @a to @v, so long as @v was not already @u. * Atomically adds @a to @v, so long as @v was not already @u.
* Returns the old value of @v. * Returns non-zero if @v was not @u, and zero otherwise.
*/ */
static inline u64 atomic64_add_unless(atomic64_t *v, u64 a, u64 u) static inline u64 atomic64_add_unless(atomic64_t *v, u64 a, u64 u)
{ {
......
...@@ -38,10 +38,10 @@ static inline void clear_bit(unsigned nr, volatile unsigned long *addr) ...@@ -38,10 +38,10 @@ static inline void clear_bit(unsigned nr, volatile unsigned long *addr)
static inline void change_bit(unsigned nr, volatile unsigned long *addr) static inline void change_bit(unsigned nr, volatile unsigned long *addr)
{ {
unsigned long old, mask = (1UL << (nr % BITS_PER_LONG)); unsigned long mask = (1UL << (nr % BITS_PER_LONG));
long guess, oldval; unsigned long guess, oldval;
addr += nr / BITS_PER_LONG; addr += nr / BITS_PER_LONG;
old = *addr; oldval = *addr;
do { do {
guess = oldval; guess = oldval;
oldval = atomic64_cmpxchg((atomic64_t *)addr, oldval = atomic64_cmpxchg((atomic64_t *)addr,
...@@ -85,7 +85,7 @@ static inline int test_and_change_bit(unsigned nr, ...@@ -85,7 +85,7 @@ static inline int test_and_change_bit(unsigned nr,
volatile unsigned long *addr) volatile unsigned long *addr)
{ {
unsigned long mask = (1UL << (nr % BITS_PER_LONG)); unsigned long mask = (1UL << (nr % BITS_PER_LONG));
long guess, oldval = *addr; unsigned long guess, oldval;
addr += nr / BITS_PER_LONG; addr += nr / BITS_PER_LONG;
oldval = *addr; oldval = *addr;
do { do {
......
/*
* cmpxchg.h -- forked from asm/atomic.h with this copyright:
*
* Copyright 2010 Tilera Corporation. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for
* more details.
*
*/
#ifndef _ASM_TILE_CMPXCHG_H
#define _ASM_TILE_CMPXCHG_H
#ifndef __ASSEMBLY__
/* Nonexistent functions intended to cause link errors. */
extern unsigned long __xchg_called_with_bad_pointer(void);
extern unsigned long __cmpxchg_called_with_bad_pointer(void);
#define xchg(ptr, x) \
({ \
typeof(*(ptr)) __x; \
switch (sizeof(*(ptr))) { \
case 4: \
__x = (typeof(__x))(typeof(__x-__x))atomic_xchg( \
(atomic_t *)(ptr), \
(u32)(typeof((x)-(x)))(x)); \
break; \
case 8: \
__x = (typeof(__x))(typeof(__x-__x))atomic64_xchg( \
(atomic64_t *)(ptr), \
(u64)(typeof((x)-(x)))(x)); \
break; \
default: \
__xchg_called_with_bad_pointer(); \
} \
__x; \
})
#define cmpxchg(ptr, o, n) \
({ \
typeof(*(ptr)) __x; \
switch (sizeof(*(ptr))) { \
case 4: \
__x = (typeof(__x))(typeof(__x-__x))atomic_cmpxchg( \
(atomic_t *)(ptr), \
(u32)(typeof((o)-(o)))(o), \
(u32)(typeof((n)-(n)))(n)); \
break; \
case 8: \
__x = (typeof(__x))(typeof(__x-__x))atomic64_cmpxchg( \
(atomic64_t *)(ptr), \
(u64)(typeof((o)-(o)))(o), \
(u64)(typeof((n)-(n)))(n)); \
break; \
default: \
__cmpxchg_called_with_bad_pointer(); \
} \
__x; \
})
#define tas(ptr) (xchg((ptr), 1))
#endif /* __ASSEMBLY__ */
#endif /* _ASM_TILE_CMPXCHG_H */
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#define NR_IRQS 32 #define NR_IRQS 32
/* IRQ numbers used for linux IPIs. */ /* IRQ numbers used for linux IPIs. */
#define IRQ_RESCHEDULE 1 #define IRQ_RESCHEDULE 0
#define irq_canonicalize(irq) (irq) #define irq_canonicalize(irq) (irq)
......
...@@ -137,7 +137,7 @@ static inline void arch_read_unlock(arch_rwlock_t *rw) ...@@ -137,7 +137,7 @@ static inline void arch_read_unlock(arch_rwlock_t *rw)
static inline void arch_write_unlock(arch_rwlock_t *rw) static inline void arch_write_unlock(arch_rwlock_t *rw)
{ {
__insn_mf(); __insn_mf();
rw->lock = 0; __insn_exch4(&rw->lock, 0); /* Avoid waiting in the write buffer. */
} }
static inline int arch_read_trylock(arch_rwlock_t *rw) static inline int arch_read_trylock(arch_rwlock_t *rw)
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
struct KBacktraceIterator { struct KBacktraceIterator {
BacktraceIterator it; BacktraceIterator it;
struct task_struct *task; /* task we are backtracing */ struct task_struct *task; /* task we are backtracing */
pte_t *pgtable; /* page table for user space access */
int end; /* iteration complete. */ int end; /* iteration complete. */
int new_context; /* new context is starting */ int new_context; /* new context is starting */
int profile; /* profiling, so stop on async intrpt */ int profile; /* profiling, so stop on async intrpt */
......
...@@ -64,7 +64,11 @@ void do_breakpoint(struct pt_regs *, int fault_num); ...@@ -64,7 +64,11 @@ void do_breakpoint(struct pt_regs *, int fault_num);
#ifdef __tilegx__ #ifdef __tilegx__
/* kernel/single_step.c */
void gx_singlestep_handle(struct pt_regs *, int fault_num); void gx_singlestep_handle(struct pt_regs *, int fault_num);
/* kernel/intvec_64.S */
void fill_ra_stack(void);
#endif #endif
#endif /* _ASM_TILE_SYSCALLS_H */ #endif /* _ASM_TILE_TRAPS_H */
...@@ -85,6 +85,7 @@ STD_ENTRY(cpu_idle_on_new_stack) ...@@ -85,6 +85,7 @@ STD_ENTRY(cpu_idle_on_new_stack)
/* Loop forever on a nap during SMP boot. */ /* Loop forever on a nap during SMP boot. */
STD_ENTRY(smp_nap) STD_ENTRY(smp_nap)
nap nap
nop /* avoid provoking the icache prefetch with a jump */
j smp_nap /* we are not architecturally guaranteed not to exit nap */ j smp_nap /* we are not architecturally guaranteed not to exit nap */
jrp lr /* clue in the backtracer */ jrp lr /* clue in the backtracer */
STD_ENDPROC(smp_nap) STD_ENDPROC(smp_nap)
...@@ -105,5 +106,6 @@ STD_ENTRY(_cpu_idle) ...@@ -105,5 +106,6 @@ STD_ENTRY(_cpu_idle)
.global _cpu_idle_nap .global _cpu_idle_nap
_cpu_idle_nap: _cpu_idle_nap:
nap nap
nop /* avoid provoking the icache prefetch with a jump */
jrp lr jrp lr
STD_ENDPROC(_cpu_idle) STD_ENDPROC(_cpu_idle)
...@@ -799,6 +799,10 @@ handle_interrupt: ...@@ -799,6 +799,10 @@ handle_interrupt:
* This routine takes a boolean in r30 indicating if this is an NMI. * This routine takes a boolean in r30 indicating if this is an NMI.
* If so, we also expect a boolean in r31 indicating whether to * If so, we also expect a boolean in r31 indicating whether to
* re-enable the oprofile interrupts. * re-enable the oprofile interrupts.
*
* Note that .Lresume_userspace is jumped to directly in several
* places, and we need to make sure r30 is set correctly in those
* callers as well.
*/ */
STD_ENTRY(interrupt_return) STD_ENTRY(interrupt_return)
/* If we're resuming to kernel space, don't check thread flags. */ /* If we're resuming to kernel space, don't check thread flags. */
...@@ -1237,7 +1241,10 @@ handle_syscall: ...@@ -1237,7 +1241,10 @@ handle_syscall:
bzt r30, 1f bzt r30, 1f
jal do_syscall_trace jal do_syscall_trace
FEEDBACK_REENTER(handle_syscall) FEEDBACK_REENTER(handle_syscall)
1: j .Lresume_userspace /* jump into middle of interrupt_return */ 1: {
movei r30, 0 /* not an NMI */
j .Lresume_userspace /* jump into middle of interrupt_return */
}
.Linvalid_syscall: .Linvalid_syscall:
/* Report an invalid syscall back to the user program */ /* Report an invalid syscall back to the user program */
...@@ -1246,7 +1253,10 @@ handle_syscall: ...@@ -1246,7 +1253,10 @@ handle_syscall:
movei r28, -ENOSYS movei r28, -ENOSYS
} }
sw r29, r28 sw r29, r28
{
movei r30, 0 /* not an NMI */
j .Lresume_userspace /* jump into middle of interrupt_return */ j .Lresume_userspace /* jump into middle of interrupt_return */
}
STD_ENDPROC(handle_syscall) STD_ENDPROC(handle_syscall)
/* Return the address for oprofile to suppress in backtraces. */ /* Return the address for oprofile to suppress in backtraces. */
...@@ -1262,7 +1272,10 @@ STD_ENTRY(ret_from_fork) ...@@ -1262,7 +1272,10 @@ STD_ENTRY(ret_from_fork)
jal sim_notify_fork jal sim_notify_fork
jal schedule_tail jal schedule_tail
FEEDBACK_REENTER(ret_from_fork) FEEDBACK_REENTER(ret_from_fork)
{
movei r30, 0 /* not an NMI */
j .Lresume_userspace /* jump into middle of interrupt_return */ j .Lresume_userspace /* jump into middle of interrupt_return */
}
STD_ENDPROC(ret_from_fork) STD_ENDPROC(ret_from_fork)
/* /*
...@@ -1376,7 +1389,10 @@ handle_ill: ...@@ -1376,7 +1389,10 @@ handle_ill:
jal send_sigtrap /* issue a SIGTRAP */ jal send_sigtrap /* issue a SIGTRAP */
FEEDBACK_REENTER(handle_ill) FEEDBACK_REENTER(handle_ill)
{
movei r30, 0 /* not an NMI */
j .Lresume_userspace /* jump into middle of interrupt_return */ j .Lresume_userspace /* jump into middle of interrupt_return */
}
.Ldispatch_normal_ill: .Ldispatch_normal_ill:
{ {
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <asm/irqflags.h> #include <asm/irqflags.h>
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
#include <asm/types.h> #include <asm/types.h>
#include <asm/signal.h>
#include <hv/hypervisor.h> #include <hv/hypervisor.h>
#include <arch/abi.h> #include <arch/abi.h>
#include <arch/interrupts.h> #include <arch/interrupts.h>
...@@ -605,6 +606,10 @@ handle_interrupt: ...@@ -605,6 +606,10 @@ handle_interrupt:
* This routine takes a boolean in r30 indicating if this is an NMI. * This routine takes a boolean in r30 indicating if this is an NMI.
* If so, we also expect a boolean in r31 indicating whether to * If so, we also expect a boolean in r31 indicating whether to
* re-enable the oprofile interrupts. * re-enable the oprofile interrupts.
*
* Note that .Lresume_userspace is jumped to directly in several
* places, and we need to make sure r30 is set correctly in those
* callers as well.
*/ */
STD_ENTRY(interrupt_return) STD_ENTRY(interrupt_return)
/* If we're resuming to kernel space, don't check thread flags. */ /* If we're resuming to kernel space, don't check thread flags. */
...@@ -1039,11 +1044,28 @@ handle_syscall: ...@@ -1039,11 +1044,28 @@ handle_syscall:
/* Do syscall trace again, if requested. */ /* Do syscall trace again, if requested. */
ld r30, r31 ld r30, r31
andi r30, r30, _TIF_SYSCALL_TRACE andi r0, r30, _TIF_SYSCALL_TRACE
beqzt r30, 1f {
andi r0, r30, _TIF_SINGLESTEP
beqzt r0, 1f
}
jal do_syscall_trace jal do_syscall_trace
FEEDBACK_REENTER(handle_syscall) FEEDBACK_REENTER(handle_syscall)
1: j .Lresume_userspace /* jump into middle of interrupt_return */ andi r0, r30, _TIF_SINGLESTEP
1: beqzt r0, 2f
/* Single stepping -- notify ptrace. */
{
movei r0, SIGTRAP
jal ptrace_notify
}
FEEDBACK_REENTER(handle_syscall)
2: {
movei r30, 0 /* not an NMI */
j .Lresume_userspace /* jump into middle of interrupt_return */
}
.Lcompat_syscall: .Lcompat_syscall:
/* /*
...@@ -1077,7 +1099,10 @@ handle_syscall: ...@@ -1077,7 +1099,10 @@ handle_syscall:
movei r28, -ENOSYS movei r28, -ENOSYS
} }
st r29, r28 st r29, r28
{
movei r30, 0 /* not an NMI */
j .Lresume_userspace /* jump into middle of interrupt_return */ j .Lresume_userspace /* jump into middle of interrupt_return */
}
STD_ENDPROC(handle_syscall) STD_ENDPROC(handle_syscall)
/* Return the address for oprofile to suppress in backtraces. */ /* Return the address for oprofile to suppress in backtraces. */
...@@ -1093,7 +1118,10 @@ STD_ENTRY(ret_from_fork) ...@@ -1093,7 +1118,10 @@ STD_ENTRY(ret_from_fork)
jal sim_notify_fork jal sim_notify_fork
jal schedule_tail jal schedule_tail
FEEDBACK_REENTER(ret_from_fork) FEEDBACK_REENTER(ret_from_fork)
j .Lresume_userspace {
movei r30, 0 /* not an NMI */
j .Lresume_userspace /* jump into middle of interrupt_return */
}
STD_ENDPROC(ret_from_fork) STD_ENDPROC(ret_from_fork)
/* Various stub interrupt handlers and syscall handlers */ /* Various stub interrupt handlers and syscall handlers */
...@@ -1156,6 +1184,18 @@ int_unalign: ...@@ -1156,6 +1184,18 @@ int_unalign:
push_extra_callee_saves r0 push_extra_callee_saves r0
j do_trap j do_trap
/* Fill the return address stack with nonzero entries. */
STD_ENTRY(fill_ra_stack)
{
move r0, lr
jal 1f
}
1: jal 2f
2: jal 3f
3: jal 4f
4: jrp r0
STD_ENDPROC(fill_ra_stack)
/* Include .intrpt1 array of interrupt vectors */ /* Include .intrpt1 array of interrupt vectors */
.section ".intrpt1", "ax" .section ".intrpt1", "ax"
...@@ -1166,7 +1206,7 @@ int_unalign: ...@@ -1166,7 +1206,7 @@ int_unalign:
#define do_hardwall_trap bad_intr #define do_hardwall_trap bad_intr
#endif #endif
int_hand INT_MEM_ERROR, MEM_ERROR, bad_intr int_hand INT_MEM_ERROR, MEM_ERROR, do_trap
int_hand INT_SINGLE_STEP_3, SINGLE_STEP_3, bad_intr int_hand INT_SINGLE_STEP_3, SINGLE_STEP_3, bad_intr
#if CONFIG_KERNEL_PL == 2 #if CONFIG_KERNEL_PL == 2
int_hand INT_SINGLE_STEP_2, SINGLE_STEP_2, gx_singlestep_handle int_hand INT_SINGLE_STEP_2, SINGLE_STEP_2, gx_singlestep_handle
......
...@@ -67,6 +67,8 @@ void *module_alloc(unsigned long size) ...@@ -67,6 +67,8 @@ void *module_alloc(unsigned long size)
area = __get_vm_area(size, VM_ALLOC, MEM_MODULE_START, MEM_MODULE_END); area = __get_vm_area(size, VM_ALLOC, MEM_MODULE_START, MEM_MODULE_END);
if (!area) if (!area)
goto error; goto error;
area->nr_pages = npages;
area->pages = pages;
if (map_vm_area(area, prot_rwx, &pages)) { if (map_vm_area(area, prot_rwx, &pages)) {
vunmap(area->addr); vunmap(area->addr);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/tracehook.h> #include <linux/tracehook.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <asm/stack.h> #include <asm/stack.h>
#include <asm/switch_to.h>
#include <asm/homecache.h> #include <asm/homecache.h>
#include <asm/syscalls.h> #include <asm/syscalls.h>
#include <asm/traps.h> #include <asm/traps.h>
...@@ -285,7 +286,7 @@ struct task_struct *validate_current(void) ...@@ -285,7 +286,7 @@ struct task_struct *validate_current(void)
static struct task_struct corrupt = { .comm = "<corrupt>" }; static struct task_struct corrupt = { .comm = "<corrupt>" };
struct task_struct *tsk = current; struct task_struct *tsk = current;
if (unlikely((unsigned long)tsk < PAGE_OFFSET || if (unlikely((unsigned long)tsk < PAGE_OFFSET ||
(void *)tsk > high_memory || (high_memory && (void *)tsk > high_memory) ||
((unsigned long)tsk & (__alignof__(*tsk) - 1)) != 0)) { ((unsigned long)tsk & (__alignof__(*tsk) - 1)) != 0)) {
pr_err("Corrupt 'current' %p (sp %#lx)\n", tsk, stack_pointer); pr_err("Corrupt 'current' %p (sp %#lx)\n", tsk, stack_pointer);
tsk = &corrupt; tsk = &corrupt;
......
...@@ -103,13 +103,11 @@ unsigned long __initdata pci_reserve_end_pfn = -1U; ...@@ -103,13 +103,11 @@ unsigned long __initdata pci_reserve_end_pfn = -1U;
static int __init setup_maxmem(char *str) static int __init setup_maxmem(char *str)
{ {
long maxmem_mb; unsigned long long maxmem;
if (str == NULL || strict_strtol(str, 0, &maxmem_mb) != 0 || if (str == NULL || (maxmem = memparse(str, NULL)) == 0)
maxmem_mb == 0)
return -EINVAL; return -EINVAL;
maxmem_pfn = (maxmem_mb >> (HPAGE_SHIFT - 20)) << maxmem_pfn = (maxmem >> HPAGE_SHIFT) << (HPAGE_SHIFT - PAGE_SHIFT);
(HPAGE_SHIFT - PAGE_SHIFT);
pr_info("Forcing RAM used to no more than %dMB\n", pr_info("Forcing RAM used to no more than %dMB\n",
maxmem_pfn >> (20 - PAGE_SHIFT)); maxmem_pfn >> (20 - PAGE_SHIFT));
return 0; return 0;
...@@ -119,14 +117,15 @@ early_param("maxmem", setup_maxmem); ...@@ -119,14 +117,15 @@ early_param("maxmem", setup_maxmem);
static int __init setup_maxnodemem(char *str) static int __init setup_maxnodemem(char *str)
{ {
char *endp; char *endp;
long maxnodemem_mb, node; unsigned long long maxnodemem;
long node;
node = str ? simple_strtoul(str, &endp, 0) : INT_MAX; node = str ? simple_strtoul(str, &endp, 0) : INT_MAX;
if (node >= MAX_NUMNODES || *endp != ':' || if (node >= MAX_NUMNODES || *endp != ':')
strict_strtol(endp+1, 0, &maxnodemem_mb) != 0)
return -EINVAL; return -EINVAL;
maxnodemem_pfn[node] = (maxnodemem_mb >> (HPAGE_SHIFT - 20)) << maxnodemem = memparse(endp+1, NULL);
maxnodemem_pfn[node] = (maxnodemem >> HPAGE_SHIFT) <<
(HPAGE_SHIFT - PAGE_SHIFT); (HPAGE_SHIFT - PAGE_SHIFT);
pr_info("Forcing RAM used on node %ld to no more than %dMB\n", pr_info("Forcing RAM used on node %ld to no more than %dMB\n",
node, maxnodemem_pfn[node] >> (20 - PAGE_SHIFT)); node, maxnodemem_pfn[node] >> (20 - PAGE_SHIFT));
...@@ -913,6 +912,13 @@ void __cpuinit setup_cpu(int boot) ...@@ -913,6 +912,13 @@ void __cpuinit setup_cpu(int boot)
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
/*
* Note that the kernel can potentially support other compression
* techniques than gz, though we don't do so by default. If we ever
* decide to do so we can either look for other filename extensions,
* or just allow a file with this name to be compressed with an
* arbitrary compressor (somewhat counterintuitively).
*/
static int __initdata set_initramfs_file; static int __initdata set_initramfs_file;
static char __initdata initramfs_file[128] = "initramfs.cpio.gz"; static char __initdata initramfs_file[128] = "initramfs.cpio.gz";
...@@ -928,9 +934,9 @@ static int __init setup_initramfs_file(char *str) ...@@ -928,9 +934,9 @@ static int __init setup_initramfs_file(char *str)
early_param("initramfs_file", setup_initramfs_file); early_param("initramfs_file", setup_initramfs_file);
/* /*
* We look for an additional "initramfs.cpio.gz" file in the hvfs. * We look for an "initramfs.cpio.gz" file in the hvfs.
* If there is one, we allocate some memory for it and it will be * If there is one, we allocate some memory for it and it will be
* unpacked to the initramfs after any built-in initramfs_data. * unpacked to the initramfs.
*/ */
static void __init load_hv_initrd(void) static void __init load_hv_initrd(void)
{ {
......
...@@ -153,6 +153,25 @@ static tile_bundle_bits rewrite_load_store_unaligned( ...@@ -153,6 +153,25 @@ static tile_bundle_bits rewrite_load_store_unaligned(
if (((unsigned long)addr % size) == 0) if (((unsigned long)addr % size) == 0)
return bundle; return bundle;
/*
* Return SIGBUS with the unaligned address, if requested.
* Note that we return SIGBUS even for completely invalid addresses
* as long as they are in fact unaligned; this matches what the
* tilepro hardware would be doing, if it could provide us with the
* actual bad address in an SPR, which it doesn't.
*/
if (unaligned_fixup == 0) {
siginfo_t info = {
.si_signo = SIGBUS,
.si_code = BUS_ADRALN,
.si_addr = addr
};
trace_unhandled_signal("unaligned trap", regs,
(unsigned long)addr, SIGBUS);
force_sig_info(info.si_signo, &info, current);
return (tilepro_bundle_bits) 0;
}
#ifndef __LITTLE_ENDIAN #ifndef __LITTLE_ENDIAN
# error We assume little-endian representation with copy_xx_user size 2 here # error We assume little-endian representation with copy_xx_user size 2 here
#endif #endif
...@@ -192,18 +211,6 @@ static tile_bundle_bits rewrite_load_store_unaligned( ...@@ -192,18 +211,6 @@ static tile_bundle_bits rewrite_load_store_unaligned(
return (tile_bundle_bits) 0; return (tile_bundle_bits) 0;
} }
if (unaligned_fixup == 0) {
siginfo_t info = {
.si_signo = SIGBUS,
.si_code = BUS_ADRALN,
.si_addr = addr
};
trace_unhandled_signal("unaligned trap", regs,
(unsigned long)addr, SIGBUS);
force_sig_info(info.si_signo, &info, current);
return (tile_bundle_bits) 0;
}
if (unaligned_printk || unaligned_fixup_count == 0) { if (unaligned_printk || unaligned_fixup_count == 0) {
pr_info("Process %d/%s: PC %#lx: Fixup of" pr_info("Process %d/%s: PC %#lx: Fixup of"
" unaligned %s at %#lx.\n", " unaligned %s at %#lx.\n",
......
...@@ -103,7 +103,7 @@ static void smp_stop_cpu_interrupt(void) ...@@ -103,7 +103,7 @@ static void smp_stop_cpu_interrupt(void)
set_cpu_online(smp_processor_id(), 0); set_cpu_online(smp_processor_id(), 0);
arch_local_irq_disable_all(); arch_local_irq_disable_all();
for (;;) for (;;)
asm("nap"); asm("nap; nop");
} }
/* This function calls the 'stop' function on all other CPUs in the system. */ /* This function calls the 'stop' function on all other CPUs in the system. */
...@@ -113,6 +113,12 @@ void smp_send_stop(void) ...@@ -113,6 +113,12 @@ void smp_send_stop(void)
send_IPI_allbutself(MSG_TAG_STOP_CPU); send_IPI_allbutself(MSG_TAG_STOP_CPU);
} }
/* On panic, just wait; we may get an smp_send_stop() later on. */
void panic_smp_self_stop(void)
{
while (1)
asm("nap; nop");
}
/* /*
* Dispatch code called from hv_message_intr() for HV_MSG_TILE hv messages. * Dispatch code called from hv_message_intr() for HV_MSG_TILE hv messages.
......
This diff is collapsed.
...@@ -200,7 +200,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, ...@@ -200,7 +200,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
{ {
siginfo_t info = { 0 }; siginfo_t info = { 0 };
int signo, code; int signo, code;
unsigned long address; unsigned long address = 0;
bundle_bits instr; bundle_bits instr;
/* Re-enable interrupts. */ /* Re-enable interrupts. */
...@@ -223,6 +223,10 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, ...@@ -223,6 +223,10 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
} }
switch (fault_num) { switch (fault_num) {
case INT_MEM_ERROR:
signo = SIGBUS;
code = BUS_OBJERR;
break;
case INT_ILL: case INT_ILL:
if (copy_from_user(&instr, (void __user *)regs->pc, if (copy_from_user(&instr, (void __user *)regs->pc,
sizeof(instr))) { sizeof(instr))) {
...@@ -289,7 +293,10 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, ...@@ -289,7 +293,10 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
address = regs->pc; address = regs->pc;
break; break;
#ifdef __tilegx__ #ifdef __tilegx__
case INT_ILL_TRANS: case INT_ILL_TRANS: {
/* Avoid a hardware erratum with the return address stack. */
fill_ra_stack();
signo = SIGSEGV; signo = SIGSEGV;
code = SEGV_MAPERR; code = SEGV_MAPERR;
if (reason & SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK) if (reason & SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK)
...@@ -297,6 +304,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, ...@@ -297,6 +304,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
else else
address = 0; /* FIXME: GX: single-step for address */ address = 0; /* FIXME: GX: single-step for address */
break; break;
}
#endif #endif
default: default:
panic("Unexpected do_trap interrupt number %d", fault_num); panic("Unexpected do_trap interrupt number %d", fault_num);
...@@ -308,6 +316,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, ...@@ -308,6 +316,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
info.si_addr = (void __user *)address; info.si_addr = (void __user *)address;
if (signo == SIGILL) if (signo == SIGILL)
info.si_trapno = fault_num; info.si_trapno = fault_num;
if (signo != SIGTRAP)
trace_unhandled_signal("trap", regs, address, signo); trace_unhandled_signal("trap", regs, address, signo);
force_sig_info(signo, &info, current); force_sig_info(signo, &info, current);
} }
......
...@@ -7,6 +7,7 @@ lib-y = cacheflush.o checksum.o cpumask.o delay.o uaccess.o \ ...@@ -7,6 +7,7 @@ lib-y = cacheflush.o checksum.o cpumask.o delay.o uaccess.o \
strchr_$(BITS).o strlen_$(BITS).o strchr_$(BITS).o strlen_$(BITS).o
ifeq ($(CONFIG_TILEGX),y) ifeq ($(CONFIG_TILEGX),y)
CFLAGS_REMOVE_memcpy_user_64.o = -fno-omit-frame-pointer
lib-y += memcpy_user_64.o lib-y += memcpy_user_64.o
else else
lib-y += atomic_32.o atomic_asm_32.o memcpy_tile64.o lib-y += atomic_32.o atomic_asm_32.o memcpy_tile64.o
......
...@@ -39,7 +39,21 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh) ...@@ -39,7 +39,21 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
{ {
char *p, *base; char *p, *base;
size_t step_size, load_count; size_t step_size, load_count;
/*
* On TILEPro the striping granularity is a fixed 8KB; on
* TILE-Gx it is configurable, and we rely on the fact that
* the hypervisor always configures maximum striping, so that
* bits 9 and 10 of the PA are part of the stripe function, so
* every 512 bytes we hit a striping boundary.
*
*/
#ifdef __tilegx__
const unsigned long STRIPE_WIDTH = 512;
#else
const unsigned long STRIPE_WIDTH = 8192; const unsigned long STRIPE_WIDTH = 8192;
#endif
#ifdef __tilegx__ #ifdef __tilegx__
/* /*
* On TILE-Gx, we must disable the dstream prefetcher before doing * On TILE-Gx, we must disable the dstream prefetcher before doing
...@@ -74,7 +88,7 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh) ...@@ -74,7 +88,7 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
* memory, that one load would be sufficient, but since we may * memory, that one load would be sufficient, but since we may
* be, we also need to back up to the last load issued to * be, we also need to back up to the last load issued to
* another memory controller, which would be the point where * another memory controller, which would be the point where
* we crossed an 8KB boundary (the granularity of striping * we crossed a "striping" boundary (the granularity of striping
* across memory controllers). Keep backing up and doing this * across memory controllers). Keep backing up and doing this
* until we are before the beginning of the buffer, or have * until we are before the beginning of the buffer, or have
* hit all the controllers. * hit all the controllers.
...@@ -88,12 +102,22 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh) ...@@ -88,12 +102,22 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
* every cache line on a full memory stripe on each * every cache line on a full memory stripe on each
* controller" that we simply do that, to simplify the logic. * controller" that we simply do that, to simplify the logic.
* *
* FIXME: See bug 9535 for some issues with this code. * On TILE-Gx the hash-for-home function is much more complex,
* with the upshot being we can't readily guarantee we have
* hit both entries in the 128-entry AMT that were hit by any
* load in the entire range, so we just re-load them all.
* With larger buffers, we may want to consider using a hypervisor
* trap to issue loads directly to each hash-for-home tile for
* each controller (doing it from Linux would trash the TLB).
*/ */
if (hfh) { if (hfh) {
step_size = L2_CACHE_BYTES; step_size = L2_CACHE_BYTES;
#ifdef __tilegx__
load_count = (size + L2_CACHE_BYTES - 1) / L2_CACHE_BYTES;
#else
load_count = (STRIPE_WIDTH / L2_CACHE_BYTES) * load_count = (STRIPE_WIDTH / L2_CACHE_BYTES) *
(1 << CHIP_LOG_NUM_MSHIMS()); (1 << CHIP_LOG_NUM_MSHIMS());
#endif
} else { } else {
step_size = STRIPE_WIDTH; step_size = STRIPE_WIDTH;
load_count = (1 << CHIP_LOG_NUM_MSHIMS()); load_count = (1 << CHIP_LOG_NUM_MSHIMS());
...@@ -109,7 +133,7 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh) ...@@ -109,7 +133,7 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
/* Figure out how far back we need to go. */ /* Figure out how far back we need to go. */
base = p - (step_size * (load_count - 2)); base = p - (step_size * (load_count - 2));
if ((long)base < (long)buffer) if ((unsigned long)base < (unsigned long)buffer)
base = buffer; base = buffer;
/* /*
......
...@@ -14,7 +14,13 @@ ...@@ -14,7 +14,13 @@
* Do memcpy(), but trap and return "n" when a load or store faults. * Do memcpy(), but trap and return "n" when a load or store faults.
* *
* Note: this idiom only works when memcpy() compiles to a leaf function. * Note: this idiom only works when memcpy() compiles to a leaf function.
* If "sp" is updated during memcpy, the "jrp lr" will be incorrect. * Here leaf function not only means it does not have calls, but also
* requires no stack operations (sp, stack frame pointer) and no
* use of callee-saved registers, else "jrp lr" will be incorrect since
* unwinding stack frame is bypassed. Since memcpy() is not complex so
* these conditions are satisfied here, but we need to be careful when
* modifying this file. This is not a clean solution but is the best
* one so far.
* *
* Also note that we are capturing "n" from the containing scope here. * Also note that we are capturing "n" from the containing scope here.
*/ */
......
...@@ -60,5 +60,5 @@ static void delay_backoff(int iterations) ...@@ -60,5 +60,5 @@ static void delay_backoff(int iterations)
loops += __insn_crc32_32(stack_pointer, get_cycles_low()) & loops += __insn_crc32_32(stack_pointer, get_cycles_low()) &
(loops - 1); (loops - 1);
relax(1 << exponent); relax(loops);
} }
...@@ -130,7 +130,7 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) ...@@ -130,7 +130,7 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
} }
/* /*
* Handle a fault on the vmalloc or module mapping area * Handle a fault on the vmalloc area.
*/ */
static inline int vmalloc_fault(pgd_t *pgd, unsigned long address) static inline int vmalloc_fault(pgd_t *pgd, unsigned long address)
{ {
...@@ -203,9 +203,14 @@ static pgd_t *get_current_pgd(void) ...@@ -203,9 +203,14 @@ static pgd_t *get_current_pgd(void)
* interrupt or a critical region, and must do as little as possible. * interrupt or a critical region, and must do as little as possible.
* Similarly, we can't use atomic ops here, since we may be handling a * Similarly, we can't use atomic ops here, since we may be handling a
* fault caused by an atomic op access. * fault caused by an atomic op access.
*
* If we find a migrating PTE while we're in an NMI context, and we're
* at a PC that has a registered exception handler, we don't wait,
* since this thread may (e.g.) have been interrupted while migrating
* its own stack, which would then cause us to self-deadlock.
*/ */
static int handle_migrating_pte(pgd_t *pgd, int fault_num, static int handle_migrating_pte(pgd_t *pgd, int fault_num,
unsigned long address, unsigned long address, unsigned long pc,
int is_kernel_mode, int write) int is_kernel_mode, int write)
{ {
pud_t *pud; pud_t *pud;
...@@ -227,6 +232,8 @@ static int handle_migrating_pte(pgd_t *pgd, int fault_num, ...@@ -227,6 +232,8 @@ static int handle_migrating_pte(pgd_t *pgd, int fault_num,
pte_offset_kernel(pmd, address); pte_offset_kernel(pmd, address);
pteval = *pte; pteval = *pte;
if (pte_migrating(pteval)) { if (pte_migrating(pteval)) {
if (in_nmi() && search_exception_tables(pc))
return 0;
wait_for_migration(pte); wait_for_migration(pte);
return 1; return 1;
} }
...@@ -300,7 +307,7 @@ static int handle_page_fault(struct pt_regs *regs, ...@@ -300,7 +307,7 @@ static int handle_page_fault(struct pt_regs *regs,
* rather than trying to patch up the existing PTE. * rather than trying to patch up the existing PTE.
*/ */
pgd = get_current_pgd(); pgd = get_current_pgd();
if (handle_migrating_pte(pgd, fault_num, address, if (handle_migrating_pte(pgd, fault_num, address, regs->pc,
is_kernel_mode, write)) is_kernel_mode, write))
return 1; return 1;
...@@ -335,8 +342,11 @@ static int handle_page_fault(struct pt_regs *regs, ...@@ -335,8 +342,11 @@ static int handle_page_fault(struct pt_regs *regs,
/* /*
* If we're trying to touch user-space addresses, we must * If we're trying to touch user-space addresses, we must
* be either at PL0, or else with interrupts enabled in the * be either at PL0, or else with interrupts enabled in the
* kernel, so either way we can re-enable interrupts here. * kernel, so either way we can re-enable interrupts here
* unless we are doing atomic access to user space with
* interrupts disabled.
*/ */
if (!(regs->flags & PT_FLAGS_DISABLE_IRQ))
local_irq_enable(); local_irq_enable();
mm = tsk->mm; mm = tsk->mm;
...@@ -665,7 +675,7 @@ struct intvec_state do_page_fault_ics(struct pt_regs *regs, int fault_num, ...@@ -665,7 +675,7 @@ struct intvec_state do_page_fault_ics(struct pt_regs *regs, int fault_num,
*/ */
if (fault_num == INT_DTLB_ACCESS) if (fault_num == INT_DTLB_ACCESS)
write = 1; write = 1;
if (handle_migrating_pte(pgd, fault_num, address, 1, write)) if (handle_migrating_pte(pgd, fault_num, address, pc, 1, write))
return state; return state;
/* Return zero so that we continue on with normal fault handling. */ /* Return zero so that we continue on with normal fault handling. */
......
...@@ -394,6 +394,7 @@ int page_home(struct page *page) ...@@ -394,6 +394,7 @@ int page_home(struct page *page)
return pte_to_home(*virt_to_pte(NULL, kva)); return pte_to_home(*virt_to_pte(NULL, kva));
} }
} }
EXPORT_SYMBOL(page_home);
void homecache_change_page_home(struct page *page, int order, int home) void homecache_change_page_home(struct page *page, int order, int home)
{ {
......
...@@ -254,11 +254,6 @@ static pgprot_t __init init_pgprot(ulong address) ...@@ -254,11 +254,6 @@ static pgprot_t __init init_pgprot(ulong address)
return construct_pgprot(PAGE_KERNEL_RO, PAGE_HOME_IMMUTABLE); return construct_pgprot(PAGE_KERNEL_RO, PAGE_HOME_IMMUTABLE);
} }
/* As a performance optimization, keep the boot init stack here. */
if (address >= (ulong)&init_thread_union &&
address < (ulong)&init_thread_union + THREAD_SIZE)
return construct_pgprot(PAGE_KERNEL, smp_processor_id());
#ifndef __tilegx__ #ifndef __tilegx__
#if !ATOMIC_LOCKS_FOUND_VIA_TABLE() #if !ATOMIC_LOCKS_FOUND_VIA_TABLE()
/* Force the atomic_locks[] array page to be hash-for-home. */ /* Force the atomic_locks[] array page to be hash-for-home. */
...@@ -557,6 +552,7 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) ...@@ -557,6 +552,7 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
address = MEM_SV_INTRPT; address = MEM_SV_INTRPT;
pmd = get_pmd(pgtables, address); pmd = get_pmd(pgtables, address);
pfn = 0; /* code starts at PA 0 */
if (ktext_small) { if (ktext_small) {
/* Allocate an L2 PTE for the kernel text */ /* Allocate an L2 PTE for the kernel text */
int cpu = 0; int cpu = 0;
...@@ -579,10 +575,15 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) ...@@ -579,10 +575,15 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
} }
BUG_ON(address != (unsigned long)_stext); BUG_ON(address != (unsigned long)_stext);
pfn = 0; /* code starts at PA 0 */ pte = NULL;
for (; address < (unsigned long)_einittext;
pfn++, address += PAGE_SIZE) {
pte_ofs = pte_index(address);
if (pte_ofs == 0) {
if (pte)
assign_pte(pmd++, pte);
pte = alloc_pte(); pte = alloc_pte();
for (pte_ofs = 0; address < (unsigned long)_einittext; }
pfn++, pte_ofs++, address += PAGE_SIZE) {
if (!ktext_local) { if (!ktext_local) {
prot = set_remote_cache_cpu(prot, cpu); prot = set_remote_cache_cpu(prot, cpu);
cpu = cpumask_next(cpu, &ktext_mask); cpu = cpumask_next(cpu, &ktext_mask);
...@@ -591,6 +592,7 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) ...@@ -591,6 +592,7 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
} }
pte[pte_ofs] = pfn_pte(pfn, prot); pte[pte_ofs] = pfn_pte(pfn, prot);
} }
if (pte)
assign_pte(pmd, pte); assign_pte(pmd, pte);
} else { } else {
pte_t pteval = pfn_pte(0, PAGE_KERNEL_EXEC); pte_t pteval = pfn_pte(0, PAGE_KERNEL_EXEC);
...@@ -614,7 +616,9 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) ...@@ -614,7 +616,9 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
else else
pteval = hv_pte_set_mode(pteval, pteval = hv_pte_set_mode(pteval,
HV_PTE_MODE_CACHE_NO_L3); HV_PTE_MODE_CACHE_NO_L3);
*(pte_t *)pmd = pteval; for (; address < (unsigned long)_einittext;
pfn += PFN_DOWN(HPAGE_SIZE), address += HPAGE_SIZE)
*(pte_t *)(pmd++) = pfn_pte(pfn, pteval);
} }
/* Set swapper_pgprot here so it is flushed to memory right away. */ /* Set swapper_pgprot here so it is flushed to memory right away. */
......
...@@ -177,14 +177,10 @@ void shatter_huge_page(unsigned long addr) ...@@ -177,14 +177,10 @@ void shatter_huge_page(unsigned long addr)
if (!pmd_huge_page(*pmd)) if (!pmd_huge_page(*pmd))
return; return;
/* spin_lock_irqsave(&init_mm.page_table_lock, flags);
* Grab the pgd_lock, since we may need it to walk the pgd_list,
* and since we need some kind of lock here to avoid races.
*/
spin_lock_irqsave(&pgd_lock, flags);
if (!pmd_huge_page(*pmd)) { if (!pmd_huge_page(*pmd)) {
/* Lost the race to convert the huge page. */ /* Lost the race to convert the huge page. */
spin_unlock_irqrestore(&pgd_lock, flags); spin_unlock_irqrestore(&init_mm.page_table_lock, flags);
return; return;
} }
...@@ -194,6 +190,7 @@ void shatter_huge_page(unsigned long addr) ...@@ -194,6 +190,7 @@ void shatter_huge_page(unsigned long addr)
#ifdef __PAGETABLE_PMD_FOLDED #ifdef __PAGETABLE_PMD_FOLDED
/* Walk every pgd on the system and update the pmd there. */ /* Walk every pgd on the system and update the pmd there. */
spin_lock(&pgd_lock);
list_for_each(pos, &pgd_list) { list_for_each(pos, &pgd_list) {
pmd_t *copy_pmd; pmd_t *copy_pmd;
pgd = list_to_pgd(pos) + pgd_index(addr); pgd = list_to_pgd(pos) + pgd_index(addr);
...@@ -201,6 +198,7 @@ void shatter_huge_page(unsigned long addr) ...@@ -201,6 +198,7 @@ void shatter_huge_page(unsigned long addr)
copy_pmd = pmd_offset(pud, addr); copy_pmd = pmd_offset(pud, addr);
__set_pmd(copy_pmd, *pmd); __set_pmd(copy_pmd, *pmd);
} }
spin_unlock(&pgd_lock);
#endif #endif
/* Tell every cpu to notice the change. */ /* Tell every cpu to notice the change. */
...@@ -208,7 +206,7 @@ void shatter_huge_page(unsigned long addr) ...@@ -208,7 +206,7 @@ void shatter_huge_page(unsigned long addr)
cpu_possible_mask, NULL, 0); cpu_possible_mask, NULL, 0);
/* Hold the lock until the TLB flush is finished to avoid races. */ /* Hold the lock until the TLB flush is finished to avoid races. */
spin_unlock_irqrestore(&pgd_lock, flags); spin_unlock_irqrestore(&init_mm.page_table_lock, flags);
} }
/* /*
...@@ -217,9 +215,13 @@ void shatter_huge_page(unsigned long addr) ...@@ -217,9 +215,13 @@ void shatter_huge_page(unsigned long addr)
* against pageattr.c; it is the unique case in which a valid change * against pageattr.c; it is the unique case in which a valid change
* of kernel pagetables can't be lazily synchronized by vmalloc faults. * of kernel pagetables can't be lazily synchronized by vmalloc faults.
* vmalloc faults work because attached pagetables are never freed. * vmalloc faults work because attached pagetables are never freed.
* The locking scheme was chosen on the basis of manfred's *
* recommendations and having no core impact whatsoever. * The lock is always taken with interrupts disabled, unlike on x86
* -- wli * and other platforms, because we need to take the lock in
* shatter_huge_page(), which may be called from an interrupt context.
* We are not at risk from the tlbflush IPI deadlock that was seen on
* x86, since we use the flush_remote() API to have the hypervisor do
* the TLB flushes regardless of irq disabling.
*/ */
DEFINE_SPINLOCK(pgd_lock); DEFINE_SPINLOCK(pgd_lock);
LIST_HEAD(pgd_list); LIST_HEAD(pgd_list);
...@@ -469,10 +471,18 @@ void __set_pte(pte_t *ptep, pte_t pte) ...@@ -469,10 +471,18 @@ void __set_pte(pte_t *ptep, pte_t pte)
void set_pte(pte_t *ptep, pte_t pte) void set_pte(pte_t *ptep, pte_t pte)
{ {
struct page *page = pfn_to_page(pte_pfn(pte)); if (pte_present(pte) &&
(!CHIP_HAS_MMIO() || hv_pte_get_mode(pte) != HV_PTE_MODE_MMIO)) {
/* Update the home of a PTE if necessary */ /* The PTE actually references physical memory. */
pte = pte_set_home(pte, page_home(page)); unsigned long pfn = pte_pfn(pte);
if (pfn_valid(pfn)) {
/* Update the home of the PTE from the struct page. */
pte = pte_set_home(pte, page_home(pfn_to_page(pfn)));
} else if (hv_pte_get_mode(pte) == 0) {
/* remap_pfn_range(), etc, must supply PTE mode. */
panic("set_pte(): out-of-range PFN and mode 0\n");
}
}
__set_pte(ptep, pte); __set_pte(ptep, pte);
} }
......
...@@ -194,17 +194,17 @@ static ssize_t srom_read(struct file *filp, char __user *buf, ...@@ -194,17 +194,17 @@ static ssize_t srom_read(struct file *filp, char __user *buf,
hv_retval = _srom_read(srom->hv_devhdl, kernbuf, hv_retval = _srom_read(srom->hv_devhdl, kernbuf,
*f_pos, bytes_this_pass); *f_pos, bytes_this_pass);
if (hv_retval > 0) { if (hv_retval <= 0) {
if (copy_to_user(buf, kernbuf, hv_retval) != 0) {
retval = -EFAULT;
break;
}
} else if (hv_retval <= 0) {
if (retval == 0) if (retval == 0)
retval = hv_retval; retval = hv_retval;
break; break;
} }
if (copy_to_user(buf, kernbuf, hv_retval) != 0) {
retval = -EFAULT;
break;
}
retval += hv_retval; retval += hv_retval;
*f_pos += hv_retval; *f_pos += hv_retval;
buf += hv_retval; buf += hv_retval;
......
...@@ -145,7 +145,11 @@ static int __devinit tile_edac_mc_probe(struct platform_device *pdev) ...@@ -145,7 +145,11 @@ static int __devinit tile_edac_mc_probe(struct platform_device *pdev)
mci->edac_ctl_cap = EDAC_FLAG_SECDED; mci->edac_ctl_cap = EDAC_FLAG_SECDED;
mci->mod_name = DRV_NAME; mci->mod_name = DRV_NAME;
#ifdef __tilegx__
mci->ctl_name = "TILEGx_Memory_Controller";
#else
mci->ctl_name = "TILEPro_Memory_Controller"; mci->ctl_name = "TILEPro_Memory_Controller";
#endif
mci->dev_name = dev_name(&pdev->dev); mci->dev_name = dev_name(&pdev->dev);
mci->edac_check = tile_edac_check; mci->edac_check = tile_edac_check;
......
...@@ -342,6 +342,21 @@ inline int __netio_fastio1(u32 fastio_index, u32 arg0) ...@@ -342,6 +342,21 @@ inline int __netio_fastio1(u32 fastio_index, u32 arg0)
} }
static void tile_net_return_credit(struct tile_net_cpu *info)
{
struct tile_netio_queue *queue = &info->queue;
netio_queue_user_impl_t *qup = &queue->__user_part;
/* Return four credits after every fourth packet. */
if (--qup->__receive_credit_remaining == 0) {
u32 interval = qup->__receive_credit_interval;
qup->__receive_credit_remaining = interval;
__netio_fastio_return_credits(qup->__fastio_index, interval);
}
}
/* /*
* Provide a linux buffer to LIPP. * Provide a linux buffer to LIPP.
*/ */
...@@ -433,7 +448,7 @@ static bool tile_net_provide_needed_buffer(struct tile_net_cpu *info, ...@@ -433,7 +448,7 @@ static bool tile_net_provide_needed_buffer(struct tile_net_cpu *info,
struct sk_buff **skb_ptr; struct sk_buff **skb_ptr;
/* Request 96 extra bytes for alignment purposes. */ /* Request 96 extra bytes for alignment purposes. */
skb = netdev_alloc_skb(info->napi->dev, len + padding); skb = netdev_alloc_skb(info->napi.dev, len + padding);
if (skb == NULL) if (skb == NULL)
return false; return false;
...@@ -864,19 +879,11 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index) ...@@ -864,19 +879,11 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += len; stats->rx_bytes += len;
if (small)
info->num_needed_small_buffers++;
else
info->num_needed_large_buffers++;
} }
/* Return four credits after every fourth packet. */ /* ISSUE: It would be nice to defer this until the packet has */
if (--qup->__receive_credit_remaining == 0) { /* actually been processed. */
u32 interval = qup->__receive_credit_interval; tile_net_return_credit(info);
qup->__receive_credit_remaining = interval;
__netio_fastio_return_credits(qup->__fastio_index, interval);
}
/* Consume this packet. */ /* Consume this packet. */
qup->__packet_receive_read = index2; qup->__packet_receive_read = index2;
...@@ -1543,7 +1550,7 @@ static int tile_net_drain_lipp_buffers(struct tile_net_priv *priv) ...@@ -1543,7 +1550,7 @@ static int tile_net_drain_lipp_buffers(struct tile_net_priv *priv)
/* Drain all the LIPP buffers. */ /* Drain all the LIPP buffers. */
while (true) { while (true) {
int buffer; unsigned int buffer;
/* NOTE: This should never fail. */ /* NOTE: This should never fail. */
if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&buffer, if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&buffer,
...@@ -1707,7 +1714,7 @@ static unsigned int tile_net_tx_frags(lepp_frag_t *frags, ...@@ -1707,7 +1714,7 @@ static unsigned int tile_net_tx_frags(lepp_frag_t *frags,
if (!hash_default) { if (!hash_default) {
void *va = pfn_to_kaddr(pfn) + f->page_offset; void *va = pfn_to_kaddr(pfn) + f->page_offset;
BUG_ON(PageHighMem(skb_frag_page(f))); BUG_ON(PageHighMem(skb_frag_page(f)));
finv_buffer_remote(va, f->size, 0); finv_buffer_remote(va, skb_frag_size(f), 0);
} }
cpa = ((phys_addr_t)pfn << PAGE_SHIFT) + f->page_offset; cpa = ((phys_addr_t)pfn << PAGE_SHIFT) + f->page_offset;
...@@ -1735,8 +1742,8 @@ static unsigned int tile_net_tx_frags(lepp_frag_t *frags, ...@@ -1735,8 +1742,8 @@ static unsigned int tile_net_tx_frags(lepp_frag_t *frags,
* Sometimes, if "sendfile()" requires copying, we will be called with * Sometimes, if "sendfile()" requires copying, we will be called with
* "data" containing the header and payload, with "frags" being empty. * "data" containing the header and payload, with "frags" being empty.
* *
* In theory, "sh->nr_frags" could be 3, but in practice, it seems * Sometimes, for example when using NFS over TCP, a single segment can
* that this will never actually happen. * span 3 fragments, which must be handled carefully in LEPP.
* *
* See "emulate_large_send_offload()" for some reference code, which * See "emulate_large_send_offload()" for some reference code, which
* does not handle checksumming. * does not handle checksumming.
...@@ -1844,10 +1851,8 @@ static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev) ...@@ -1844,10 +1851,8 @@ static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&priv->eq_lock, irqflags); spin_lock_irqsave(&priv->eq_lock, irqflags);
/* /* Handle completions if needed to make room. */
* Handle completions if needed to make room. /* NOTE: Return NETDEV_TX_BUSY if there is still no room. */
* HACK: Spin until there is sufficient room.
*/
if (lepp_num_free_comp_slots(eq) == 0) { if (lepp_num_free_comp_slots(eq) == 0) {
nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 0); nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 0);
if (nolds == 0) { if (nolds == 0) {
...@@ -1861,6 +1866,7 @@ static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev) ...@@ -1861,6 +1866,7 @@ static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev)
cmd_tail = eq->cmd_tail; cmd_tail = eq->cmd_tail;
/* Prepare to advance, detecting full queue. */ /* Prepare to advance, detecting full queue. */
/* NOTE: Return NETDEV_TX_BUSY if the queue is full. */
cmd_next = cmd_tail + cmd_size; cmd_next = cmd_tail + cmd_size;
if (cmd_tail < cmd_head && cmd_next >= cmd_head) if (cmd_tail < cmd_head && cmd_next >= cmd_head)
goto busy; goto busy;
...@@ -2023,10 +2029,8 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -2023,10 +2029,8 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&priv->eq_lock, irqflags); spin_lock_irqsave(&priv->eq_lock, irqflags);
/* /* Handle completions if needed to make room. */
* Handle completions if needed to make room. /* NOTE: Return NETDEV_TX_BUSY if there is still no room. */
* HACK: Spin until there is sufficient room.
*/
if (lepp_num_free_comp_slots(eq) == 0) { if (lepp_num_free_comp_slots(eq) == 0) {
nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 0); nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 0);
if (nolds == 0) { if (nolds == 0) {
...@@ -2040,6 +2044,7 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -2040,6 +2044,7 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
cmd_tail = eq->cmd_tail; cmd_tail = eq->cmd_tail;
/* Copy the commands, or fail. */ /* Copy the commands, or fail. */
/* NOTE: Return NETDEV_TX_BUSY if the queue is full. */
for (i = 0; i < num_frags; i++) { for (i = 0; i < num_frags; i++) {
/* Prepare to advance, detecting full queue. */ /* Prepare to advance, detecting full queue. */
...@@ -2261,6 +2266,23 @@ static int tile_net_get_mac(struct net_device *dev) ...@@ -2261,6 +2266,23 @@ static int tile_net_get_mac(struct net_device *dev)
return 0; return 0;
} }
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
* Polling 'interrupt' - used by things like netconsole to send skbs
* without having to re-enable interrupts. It's not called while
* the interrupt routine is executing.
*/
static void tile_net_netpoll(struct net_device *dev)
{
struct tile_net_priv *priv = netdev_priv(dev);
disable_percpu_irq(priv->intr_id);
tile_net_handle_ingress_interrupt(priv->intr_id, dev);
enable_percpu_irq(priv->intr_id, 0);
}
#endif
static const struct net_device_ops tile_net_ops = { static const struct net_device_ops tile_net_ops = {
.ndo_open = tile_net_open, .ndo_open = tile_net_open,
.ndo_stop = tile_net_stop, .ndo_stop = tile_net_stop,
...@@ -2269,7 +2291,10 @@ static const struct net_device_ops tile_net_ops = { ...@@ -2269,7 +2291,10 @@ static const struct net_device_ops tile_net_ops = {
.ndo_get_stats = tile_net_get_stats, .ndo_get_stats = tile_net_get_stats,
.ndo_change_mtu = tile_net_change_mtu, .ndo_change_mtu = tile_net_change_mtu,
.ndo_tx_timeout = tile_net_tx_timeout, .ndo_tx_timeout = tile_net_tx_timeout,
.ndo_set_mac_address = tile_net_set_mac_address .ndo_set_mac_address = tile_net_set_mac_address,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = tile_net_netpoll,
#endif
}; };
...@@ -2409,7 +2434,7 @@ static void tile_net_cleanup(void) ...@@ -2409,7 +2434,7 @@ static void tile_net_cleanup(void)
*/ */
static int tile_net_init_module(void) static int tile_net_init_module(void)
{ {
pr_info("Tilera IPP Net Driver\n"); pr_info("Tilera Network Driver\n");
tile_net_devs[0] = tile_net_dev_init("xgbe0"); tile_net_devs[0] = tile_net_dev_init("xgbe0");
tile_net_devs[1] = tile_net_dev_init("xgbe1"); tile_net_devs[1] = tile_net_dev_init("xgbe1");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment