diff -urN linux-2.4.32/arch/alpha/kernel/pci_iommu.c linux-2.4.33/arch/alpha/kernel/pci_iommu.c
--- linux-2.4.32/arch/alpha/kernel/pci_iommu.c 2003-06-13 14:51:29.000000000 +0000
+++ linux-2.4.33/arch/alpha/kernel/pci_iommu.c 2006-08-11 04:18:20.899189255 +0000
@@ -503,7 +503,7 @@
/* Given a scatterlist leader, choose an allocation method and fill
in the blanks. */
-static inline int
+static int
sg_fill(struct scatterlist *leader, struct scatterlist *end,
struct scatterlist *out, struct pci_iommu_arena *arena,
dma_addr_t max_dma, int dac_allowed)
diff -urN linux-2.4.32/arch/i386/config.in linux-2.4.33/arch/i386/config.in
--- linux-2.4.32/arch/i386/config.in 2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.33/arch/i386/config.in 2006-08-11 04:18:20.899189255 +0000
@@ -65,6 +65,7 @@
define_bool CONFIG_X86_POPAD_OK y
define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
+ define_bool CONFIG_X86_TSC n
fi
if [ "$CONFIG_M486" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 4
@@ -72,6 +73,7 @@
define_bool CONFIG_X86_ALIGNMENT_16 y
define_bool CONFIG_X86_PPRO_FENCE y
define_bool CONFIG_X86_F00F_WORKS_OK n
+ define_bool CONFIG_X86_TSC n
fi
if [ "$CONFIG_M586" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 5
diff -urN linux-2.4.32/arch/i386/kernel/dmi_scan.c linux-2.4.33/arch/i386/kernel/dmi_scan.c
--- linux-2.4.32/arch/i386/kernel/dmi_scan.c 2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.33/arch/i386/kernel/dmi_scan.c 2006-08-11 04:18:20.899189255 +0000
@@ -411,7 +411,7 @@
static __init int broken_ps2_resume(struct dmi_blacklist *d)
{
-#ifdef CONFIG_VT
+#if defined(CONFIG_VT) && !defined(CONFIG_DUMMY_KEYB)
if (pm_kbd_request_override == NULL)
{
pm_kbd_request_override = pckbd_pm_resume;
diff -urN linux-2.4.32/arch/i386/kernel/i387.c linux-2.4.33/arch/i386/kernel/i387.c
--- linux-2.4.32/arch/i386/kernel/i387.c 2005-04-04 01:42:19.000000000 +0000
+++ linux-2.4.33/arch/i386/kernel/i387.c 2006-08-11 04:18:20.899189255 +0000
@@ -11,6 +11,7 @@
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/init.h>
+#include <linux/kernel_stat.h>
#include <asm/processor.h>
#include <asm/i387.h>
#include <asm/math_emu.h>
@@ -70,8 +71,12 @@
static inline void __save_init_fpu( struct task_struct *tsk )
{
if ( cpu_has_fxsr ) {
- asm volatile( "fxsave %0 ; fnclex"
+ asm volatile( "fxsave %0"
: "=m" (tsk->thread.i387.fxsave) );
+ if (tsk->thread.i387.fxsave.swd & (1<<7))
+ asm volatile("fnclex");
+ /* AMD CPUs leak F?P. Clear it here */
+ asm volatile("ffree %%st(7) ; fildl %0" :: "m" (kstat.context_swtch));
} else {
asm volatile( "fnsave %0 ; fwait"
: "=m" (tsk->thread.i387.fsave) );
diff -urN linux-2.4.32/arch/i386/kernel/io_apic.c linux-2.4.33/arch/i386/kernel/io_apic.c
--- linux-2.4.32/arch/i386/kernel/io_apic.c 2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.33/arch/i386/kernel/io_apic.c 2006-08-11 04:18:20.899189255 +0000
@@ -1194,7 +1194,7 @@
* might have cached one ExtINT interrupt. Finally, at
* least one tick may be lost due to delays.
*/
- if (jiffies - t1 > 4)
+ if (jiffies - t1 > 4 && jiffies - t1 < 16)
return 1;
return 0;
diff -urN linux-2.4.32/arch/ia64/ia32/sys_ia32.c linux-2.4.33/arch/ia64/ia32/sys_ia32.c
--- linux-2.4.32/arch/ia64/ia32/sys_ia32.c 2005-11-16 19:12:54.000000000 +0000
+++ linux-2.4.33/arch/ia64/ia32/sys_ia32.c 2006-08-11 04:18:20.899189255 +0000
@@ -1442,6 +1442,7 @@
tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr)));
+ tmp = CMSG_ALIGN(tmp);
kcmlen += tmp;
ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
}
@@ -1478,7 +1479,7 @@
goto out_free_efault;
/* Advance. */
- kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
+ kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp);
ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
}
diff -urN linux-2.4.32/arch/parisc/kernel/ioctl32.c linux-2.4.33/arch/parisc/kernel/ioctl32.c
--- linux-2.4.32/arch/parisc/kernel/ioctl32.c 2005-01-19 14:09:34.000000000 +0000
+++ linux-2.4.33/arch/parisc/kernel/ioctl32.c 2006-08-11 04:18:20.903189689 +0000
@@ -35,6 +35,7 @@
#include <linux/cdrom.h>
#include <linux/loop.h>
#include <linux/auto_fs.h>
+#include <linux/auto_fs4.h>
#include <linux/devfs_fs.h>
#include <linux/tty.h>
#include <linux/vt_kern.h>
diff -urN linux-2.4.32/arch/parisc/kernel/sys_parisc32.c linux-2.4.33/arch/parisc/kernel/sys_parisc32.c
--- linux-2.4.32/arch/parisc/kernel/sys_parisc32.c 2005-04-04 01:42:19.000000000 +0000
+++ linux-2.4.33/arch/parisc/kernel/sys_parisc32.c 2006-08-11 04:18:20.903189689 +0000
@@ -1934,12 +1934,13 @@
struct cmsghdr *kcmsg, *kcmsg_base;
__kernel_size_t32 ucmlen;
__kernel_size_t kcmlen, tmp;
+ int err = -EFAULT;
kcmlen = 0;
kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
ucmsg = CMSG32_FIRSTHDR(kmsg);
while(ucmsg != NULL) {
- if(get_user(ucmlen, &ucmsg->cmsg_len))
+ if (get_user(ucmlen, &ucmsg->cmsg_len))
return -EFAULT;
/* Catch bogons. */
@@ -1948,6 +1949,7 @@
tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr)));
+ tmp = CMSG_ALIGN(tmp);
kcmlen += tmp;
ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
}
@@ -1968,21 +1970,23 @@
memset(kcmsg, 0, kcmlen);
ucmsg = CMSG32_FIRSTHDR(kmsg);
while(ucmsg != NULL) {
- __get_user(ucmlen, &ucmsg->cmsg_len);
+ if (__get_user(ucmlen, &ucmsg->cmsg_len))
+ goto Efault;
tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr)));
+ if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
+ goto Einval;
kcmsg->cmsg_len = tmp;
- __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
- __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
-
- /* Copy over the data. */
- if(copy_from_user(CMSG_DATA(kcmsg),
- CMSG32_DATA(ucmsg),
- (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
- goto out_free_efault;
+ tmp = CMSG_ALIGN(tmp);
+ if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) ||
+ __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) ||
+ copy_from_user(CMSG_DATA(kcmsg),
+ CMSG32_DATA(ucmsg),
+ (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
+ goto Efault;
/* Advance. */
- kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
+ kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp);
ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
}
@@ -1991,10 +1995,12 @@
kmsg->msg_controllen = kcmlen;
return 0;
-out_free_efault:
- if(kcmsg_base != (struct cmsghdr *)stackbuf)
+Einval:
+ err = -EINVAL;
+Efault:
+ if (kcmsg_base != (struct cmsghdr *)stackbuf)
kfree(kcmsg_base);
- return -EFAULT;
+ return err;
}
static void put_cmsg32(struct msghdr *kmsg, int level, int type,
diff -urN linux-2.4.32/arch/ppc64/kernel/ioctl32.c linux-2.4.33/arch/ppc64/kernel/ioctl32.c
--- linux-2.4.32/arch/ppc64/kernel/ioctl32.c 2005-11-16 19:12:54.000000000 +0000
+++ linux-2.4.33/arch/ppc64/kernel/ioctl32.c 2006-08-11 04:18:20.903189689 +0000
@@ -49,6 +49,7 @@
#include <linux/cdrom.h>
#include <linux/loop.h>
#include <linux/auto_fs.h>
+#include <linux/autofs_4.h>
#include <linux/devfs_fs.h>
#include <linux/tty.h>
#include <linux/vt_kern.h>
diff -urN linux-2.4.32/arch/ppc64/kernel/signal.c linux-2.4.33/arch/ppc64/kernel/signal.c
--- linux-2.4.32/arch/ppc64/kernel/signal.c 2005-01-19 14:09:36.000000000 +0000
+++ linux-2.4.33/arch/ppc64/kernel/signal.c 2006-08-11 04:18:20.903189689 +0000
@@ -332,7 +332,7 @@
}
-asmlinkage int
+asmlinkage long
sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7, unsigned long r8,
struct pt_regs *regs)
diff -urN linux-2.4.32/arch/ppc64/kernel/sys_ppc32.c linux-2.4.33/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.4.32/arch/ppc64/kernel/sys_ppc32.c 2005-04-04 01:42:19.000000000 +0000
+++ linux-2.4.33/arch/ppc64/kernel/sys_ppc32.c 2006-08-11 04:18:20.907190123 +0000
@@ -3442,12 +3442,13 @@
struct cmsghdr *kcmsg, *kcmsg_base;
__kernel_size_t32 ucmlen;
__kernel_size_t kcmlen, tmp;
+ int err = -EFAULT;
kcmlen = 0;
kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
ucmsg = CMSG32_FIRSTHDR(kmsg);
while(ucmsg != NULL) {
- if(get_user(ucmlen, &ucmsg->cmsg_len))
+ if (get_user(ucmlen, &ucmsg->cmsg_len))
return -EFAULT;
/* Catch bogons. */
@@ -3456,6 +3457,7 @@
tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr)));
+ tmp = CMSG_ALIGN(tmp);
kcmlen += tmp;
ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
}
@@ -3476,21 +3478,23 @@
memset(kcmsg, 0, kcmlen);
ucmsg = CMSG32_FIRSTHDR(kmsg);
while (ucmsg != NULL) {
- __get_user(ucmlen, &ucmsg->cmsg_len);
+ if (__get_user(ucmlen, &ucmsg->cmsg_len))
+ goto Efault;
tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr)));
+ if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
+ goto Einval;
kcmsg->cmsg_len = tmp;
- __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
- __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
-
- /* Copy over the data. */
- if(copy_from_user(CMSG_DATA(kcmsg),
- CMSG32_DATA(ucmsg),
- (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
- goto out_free_efault;
+ tmp = CMSG_ALIGN(tmp);
+ if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) ||
+ __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) ||
+ copy_from_user(CMSG_DATA(kcmsg),
+ CMSG32_DATA(ucmsg),
+ (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
+ goto Efault;
/* Advance. */
- kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
+ kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp);
ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
}
@@ -3499,10 +3503,12 @@
kmsg->msg_controllen = kcmlen;
return 0;
-out_free_efault:
- if(kcmsg_base != (struct cmsghdr *)stackbuf)
+Einval:
+ err = -EINVAL;
+Efault:
+ if (kcmsg_base != (struct cmsghdr *)stackbuf)
kfree(kcmsg_base);
- return -EFAULT;
+ return err;
}
asmlinkage long sys32_sendmsg(int fd, struct msghdr32* user_msg, unsigned int user_flags)
diff -urN linux-2.4.32/arch/s390x/kernel/linux32.c linux-2.4.33/arch/s390x/kernel/linux32.c
--- linux-2.4.32/arch/s390x/kernel/linux32.c 2005-04-04 01:42:19.000000000 +0000
+++ linux-2.4.33/arch/s390x/kernel/linux32.c 2006-08-11 04:18:20.907190123 +0000
@@ -2425,12 +2425,13 @@
struct cmsghdr *kcmsg, *kcmsg_base;
__kernel_size_t32 ucmlen;
__kernel_size_t kcmlen, tmp;
+ int err = -EFAULT;
kcmlen = 0;
kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
ucmsg = CMSG32_FIRSTHDR(kmsg);
while(ucmsg != NULL) {
- if(get_user(ucmlen, &ucmsg->cmsg_len))
+ if (get_user(ucmlen, &ucmsg->cmsg_len))
return -EFAULT;
/* Catch bogons. */
@@ -2439,6 +2440,7 @@
tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr)));
+ tmp = CMSG_ALIGN(tmp);
kcmlen += tmp;
ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
}
@@ -2459,21 +2461,23 @@
memset(kcmsg, 0, kcmlen);
ucmsg = CMSG32_FIRSTHDR(kmsg);
while(ucmsg != NULL) {
- __get_user(ucmlen, &ucmsg->cmsg_len);
+ if (__get_user(ucmlen, &ucmsg->cmsg_len))
+ goto Efault;
tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr)));
+ if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
+ goto Einval;
kcmsg->cmsg_len = tmp;
- __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
- __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
-
- /* Copy over the data. */
- if(copy_from_user(CMSG_DATA(kcmsg),
- CMSG32_DATA(ucmsg),
- (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
- goto out_free_efault;
+ tmp = CMSG_ALIGN(tmp);
+ if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) ||
+ __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) ||
+ copy_from_user(CMSG_DATA(kcmsg),
+ CMSG32_DATA(ucmsg),
+ (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
+ goto Efault;
/* Advance. */
- kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
+ kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp);
ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
}
@@ -2482,10 +2486,12 @@
kmsg->msg_controllen = kcmlen;
return 0;
-out_free_efault:
- if(kcmsg_base != (struct cmsghdr *)stackbuf)
+Einval:
+ err = -EINVAL;
+Efault:
+ if (kcmsg_base != (struct cmsghdr *)stackbuf)
kfree(kcmsg_base);
- return -EFAULT;
+ return err;
}
static void put_cmsg32(struct msghdr *kmsg, int level, int type,
diff -urN linux-2.4.32/arch/sparc/math-emu/math.c linux-2.4.33/arch/sparc/math-emu/math.c
--- linux-2.4.32/arch/sparc/math-emu/math.c 1999-12-02 23:28:54.000000000 +0000
+++ linux-2.4.33/arch/sparc/math-emu/math.c 2006-08-11 04:18:20.907190123 +0000
@@ -323,10 +323,6 @@
case FMOVS:
case FABSS:
case FNEGS: TYPE(2,1,0,1,0,0,0); break;
- default:
-#ifdef DEBUG_MATHEMU
- printk("unknown FPop1: %03lx\n",(insn>>5)&0x1ff);
-#endif
}
} else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ {
switch ((insn >> 5) & 0x1ff) {
@@ -336,10 +332,6 @@
case FCMPED: TYPE(3,0,0,2,1,2,1); break;
case FCMPQ: TYPE(3,0,0,3,1,3,1); break;
case FCMPEQ: TYPE(3,0,0,3,1,3,1); break;
- default:
-#ifdef DEBUG_MATHEMU
- printk("unknown FPop2: %03lx\n",(insn>>5)&0x1ff);
-#endif
}
}
diff -urN linux-2.4.32/arch/sparc64/kernel/entry.S linux-2.4.33/arch/sparc64/kernel/entry.S
--- linux-2.4.32/arch/sparc64/kernel/entry.S 2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.33/arch/sparc64/kernel/entry.S 2006-08-11 04:18:20.907190123 +0000
@@ -21,6 +21,7 @@
#include <asm/visasm.h>
#include <asm/estate.h>
#include <asm/auxio.h>
+#include <asm/sfafsr.h>
/* #define SYSCALL_TRACING 1 */
@@ -727,14 +728,159 @@
retl
nop
- /* These next few routines must be sure to clear the
- * SFSR FaultValid bit so that the fast tlb data protection
- * handler does not flush the wrong context and lock up the
- * box.
- */
- .globl __do_data_access_exception
- .globl __do_data_access_exception_tl1
-__do_data_access_exception_tl1:
+ /* We need to carefully read the error status, ACK
+ * the errors, prevent recursive traps, and pass the
+ * information on to C code for logging.
+ *
+ * We pass the AFAR in as-is, and we encode the status
+ * information as described in asm-sparc64/sfafsr.h
+ */
+ .globl __spitfire_access_error
+__spitfire_access_error:
+ /* Disable ESTATE error reporting so that we do not
+ * take recursive traps and RED state the processor.
+ */
+ stxa %g0, [%g0] ASI_ESTATE_ERROR_EN
+ membar #Sync
+
+ mov UDBE_UE, %g1
+ ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR
+
+ /* __spitfire_cee_trap branches here with AFSR in %g4 and
+ * UDBE_CE in %g1. It only clears ESTATE_ERR_CE in the
+ * ESTATE Error Enable register.
+ */
+__spitfire_cee_trap_continue:
+ ldxa [%g0] ASI_AFAR, %g5 ! Get AFAR
+
+ rdpr %tt, %g3
+ and %g3, 0x1ff, %g3 ! Paranoia
+ sllx %g3, SFSTAT_TRAP_TYPE_SHIFT, %g3
+ or %g4, %g3, %g4
+ rdpr %tl, %g3
+ cmp %g3, 1
+ mov 1, %g3
+ bleu %xcc, 1f
+ sllx %g3, SFSTAT_TL_GT_ONE_SHIFT, %g3
+
+ or %g4, %g3, %g4
+
+ /* Read in the UDB error register state, clearing the
+ * sticky error bits as-needed. We only clear them if
+ * the UE bit is set. Likewise, __spitfire_cee_trap
+ * below will only do so if the CE bit is set.
+ *
+ * NOTE: UltraSparc-I/II have high and low UDB error
+ * registers, corresponding to the two UDB units
+ * present on those chips. UltraSparc-IIi only
+ * has a single UDB, called "SDB" in the manual.
+ * For IIi the upper UDB register always reads
+ * as zero so for our purposes things will just
+ * work with the checks below.
+ */
+1: ldxa [%g0] ASI_UDBH_ERROR_R, %g3
+ and %g3, 0x3ff, %g7 ! Paranoia
+ sllx %g7, SFSTAT_UDBH_SHIFT, %g7
+ or %g4, %g7, %g4
+ andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE
+ be,pn %xcc, 1f
+ nop
+ stxa %g3, [%g0] ASI_UDB_ERROR_W
+ membar #Sync
+
+1: mov 0x18, %g3
+ ldxa [%g3] ASI_UDBL_ERROR_R, %g3
+ and %g3, 0x3ff, %g7 ! Paranoia
+ sllx %g7, SFSTAT_UDBL_SHIFT, %g7
+ or %g4, %g7, %g4
+ andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE
+ be,pn %xcc, 1f
+ nop
+ mov 0x18, %g7
+ stxa %g3, [%g7] ASI_UDB_ERROR_W
+ membar #Sync
+
+1: /* Ok, now that we've latched the error state,
+ * clear the sticky bits in the AFSR.
+ */
+ stxa %g4, [%g0] ASI_AFSR
+ membar #Sync
+
+ rdpr %tl, %g2
+ cmp %g2, 1
+ rdpr %pil, %g2
+ bleu,pt %xcc, 1f
+ wrpr %g0, 15, %pil
+
+ ba,pt %xcc, etraptl1
+ rd %pc, %g7
+
+ ba,pt %xcc, 2f
+ nop
+
+1: ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+
+2: mov %l4, %o1
+ mov %l5, %o2
+ call spitfire_access_error
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ clr %l6
+
+ /* This is the trap handler entry point for ECC correctable
+ * errors. They are corrected, but we listen for the trap
+ * so that the event can be logged.
+ *
+ * Disrupting errors are either:
+ * 1) single-bit ECC errors during UDB reads to system
+ * memory
+ * 2) data parity errors during write-back events
+ *
+ * As far as I can make out from the manual, the CEE trap
+ * is only for correctable errors during memory read
+ * accesses by the front-end of the processor.
+ *
+ * The code below is only for trap level 1 CEE events,
+ * as it is the only situation where we can safely record
+ * and log. For trap level >1 we just clear the CE bit
+ * in the AFSR and return.
+ *
+ * This is just like __spiftire_access_error above, but it
+ * specifically handles correctable errors. If an
+ * uncorrectable error is indicated in the AFSR we
+ * will branch directly above to __spitfire_access_error
+ * to handle it instead. Uncorrectable therefore takes
+ * priority over correctable, and the error logging
+ * C code will notice this case by inspecting the
+ * trap type.
+ */
+ .globl __spitfire_cee_trap
+__spitfire_cee_trap:
+ ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR
+ mov 1, %g3
+ sllx %g3, SFAFSR_UE_SHIFT, %g3
+ andcc %g4, %g3, %g0 ! Check for UE
+ bne,pn %xcc, __spitfire_access_error
+ nop
+
+ /* Ok, in this case we only have a correctable error.
+ * Indicate we only wish to capture that state in register
+ * %g1, and we only disable CE error reporting unlike UE
+ * handling which disables all errors.
+ */
+ ldxa [%g0] ASI_ESTATE_ERROR_EN, %g3
+ andn %g3, ESTATE_ERR_CE, %g3
+ stxa %g3, [%g0] ASI_ESTATE_ERROR_EN
+ membar #Sync
+
+ /* Preserve AFSR in %g4, indicate UDB state to capture in %g1 */
+ ba,pt %xcc, __spitfire_cee_trap_continue
+ mov UDBE_CE, %g1
+
+ .globl __spitfire_data_access_exception
+ .globl __spitfire_data_access_exception_tl1
+__spitfire_data_access_exception_tl1:
rdpr %pstate, %g4
wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
mov TLB_SFSR, %g3
@@ -743,9 +889,25 @@
ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR
stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit
membar #Sync
+ rdpr %tt, %g3
+ cmp %g3, 0x80 ! first win spill/fill trap
+ blu,pn %xcc, 1f
+ cmp %g3, 0xff ! last win spill/fill trap
+ bgu,pn %xcc, 1f
+ nop
ba,pt %xcc, winfix_dax
rdpr %tpc, %g3
-__do_data_access_exception:
+1: sethi %hi(109f), %g7
+ ba,pt %xcc, etraptl1
+109: or %g7, %lo(109b), %g7
+ mov %l4, %o1
+ mov %l5, %o2
+ call spitfire_data_access_exception_tl1
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ clr %l6
+
+__spitfire_data_access_exception:
rdpr %pstate, %g4
wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
mov TLB_SFSR, %g3
@@ -759,20 +921,19 @@
109: or %g7, %lo(109b), %g7
mov %l4, %o1
mov %l5, %o2
- call data_access_exception
+ call spitfire_data_access_exception
add %sp, PTREGS_OFF, %o0
ba,pt %xcc, rtrap
clr %l6
- .globl __do_instruction_access_exception
- .globl __do_instruction_access_exception_tl1
-__do_instruction_access_exception_tl1:
+ .globl __spitfire_insn_access_exception
+ .globl __spitfire_insn_access_exception_tl1
+__spitfire_insn_access_exception_tl1:
rdpr %pstate, %g4
wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
mov TLB_SFSR, %g3
- mov DMMU_SFAR, %g5
- ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR
- ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR
+ ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR
+ rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC
stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit
membar #Sync
sethi %hi(109f), %g7
@@ -780,18 +941,17 @@
109: or %g7, %lo(109b), %g7
mov %l4, %o1
mov %l5, %o2
- call instruction_access_exception_tl1
+ call spitfire_insn_access_exception_tl1
add %sp, PTREGS_OFF, %o0
ba,pt %xcc, rtrap
clr %l6
-__do_instruction_access_exception:
+__spitfire_insn_access_exception:
rdpr %pstate, %g4
wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
mov TLB_SFSR, %g3
- mov DMMU_SFAR, %g5
- ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR
- ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR
+ ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR
+ rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC
stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit
membar #Sync
sethi %hi(109f), %g7
@@ -799,102 +959,11 @@
109: or %g7, %lo(109b), %g7
mov %l4, %o1
mov %l5, %o2
- call instruction_access_exception
+ call spitfire_insn_access_exception
add %sp, PTREGS_OFF, %o0
ba,pt %xcc, rtrap
clr %l6
- /* This is the trap handler entry point for ECC correctable
- * errors. They are corrected, but we listen for the trap
- * so that the event can be logged.
- *
- * Disrupting errors are either:
- * 1) single-bit ECC errors during UDB reads to system
- * memory
- * 2) data parity errors during write-back events
- *
- * As far as I can make out from the manual, the CEE trap
- * is only for correctable errors during memory read
- * accesses by the front-end of the processor.
- *
- * The code below is only for trap level 1 CEE events,
- * as it is the only situation where we can safely record
- * and log. For trap level >1 we just clear the CE bit
- * in the AFSR and return.
- */
-
- /* Our trap handling infrastructure allows us to preserve
- * two 64-bit values during etrap for arguments to
- * subsequent C code. Therefore we encode the information
- * as follows:
- *
- * value 1) Full 64-bits of AFAR
- * value 2) Low 33-bits of AFSR, then bits 33-->42
- * are UDBL error status and bits 43-->52
- * are UDBH error status
- */
- .align 64
- .globl cee_trap
-cee_trap:
- ldxa [%g0] ASI_AFSR, %g1 ! Read AFSR
- ldxa [%g0] ASI_AFAR, %g2 ! Read AFAR
- sllx %g1, 31, %g1 ! Clear reserved bits
- srlx %g1, 31, %g1 ! in AFSR
-
- /* NOTE: UltraSparc-I/II have high and low UDB error
- * registers, corresponding to the two UDB units
- * present on those chips. UltraSparc-IIi only
- * has a single UDB, called "SDB" in the manual.
- * For IIi the upper UDB register always reads
- * as zero so for our purposes things will just
- * work with the checks below.
- */
- ldxa [%g0] ASI_UDBL_ERROR_R, %g3 ! Read UDB-Low error status
- andcc %g3, (1 << 8), %g4 ! Check CE bit
- sllx %g3, (64 - 10), %g3 ! Clear reserved bits
- srlx %g3, (64 - 10), %g3 ! in UDB-Low error status
-
- sllx %g3, (33 + 0), %g3 ! Shift up to encoding area
- or %g1, %g3, %g1 ! Or it in
- be,pn %xcc, 1f ! Branch if CE bit was clear
- nop
- stxa %g4, [%g0] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBL
- membar #Sync ! Synchronize ASI stores
-1: mov 0x18, %g5 ! Addr of UDB-High error status
- ldxa [%g5] ASI_UDBH_ERROR_R, %g3 ! Read it
-
- andcc %g3, (1 << 8), %g4 ! Check CE bit
- sllx %g3, (64 - 10), %g3 ! Clear reserved bits
- srlx %g3, (64 - 10), %g3 ! in UDB-High error status
- sllx %g3, (33 + 10), %g3 ! Shift up to encoding area
- or %g1, %g3, %g1 ! Or it in
- be,pn %xcc, 1f ! Branch if CE bit was clear
- nop
- nop
-
- stxa %g4, [%g5] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBH
- membar #Sync ! Synchronize ASI stores
-1: mov 1, %g5 ! AFSR CE bit is
- sllx %g5, 20, %g5 ! bit 20
- stxa %g5, [%g0] ASI_AFSR ! Clear CE sticky bit in AFSR
- membar #Sync ! Synchronize ASI stores
- sllx %g2, (64 - 41), %g2 ! Clear reserved bits
- srlx %g2, (64 - 41), %g2 ! in latched AFAR
-
- andn %g2, 0x0f, %g2 ! Finish resv bit clearing
- mov %g1, %g4 ! Move AFSR+UDB* into save reg
- mov %g2, %g5 ! Move AFAR into save reg
- rdpr %pil, %g2
- wrpr %g0, 15, %pil
- ba,pt %xcc, etrap_irq
- rd %pc, %g7
- mov %l4, %o0
-
- mov %l5, %o1
- call cee_log
- add %sp, PTREGS_OFF, %o2
- ba,a,pt %xcc, rtrap_clr_l6
-
/* Capture I/D/E-cache state into per-cpu error scoreboard.
*
* %g1: (TL>=0) ? 1 : 0
diff -urN linux-2.4.32/arch/sparc64/kernel/irq.c linux-2.4.33/arch/sparc64/kernel/irq.c
--- linux-2.4.32/arch/sparc64/kernel/irq.c 2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.33/arch/sparc64/kernel/irq.c 2006-08-11 04:18:20.907190123 +0000
@@ -599,7 +599,7 @@
#if 0
#define SYNC_OTHER_ULTRAS(x) udelay(x+1)
#else
-#define SYNC_OTHER_ULTRAS(x) membar("#Sync");
+#define SYNC_OTHER_ULTRAS(x) membar_safe("#Sync");
#endif
void synchronize_irq(void)
diff -urN linux-2.4.32/arch/sparc64/kernel/pci_iommu.c linux-2.4.33/arch/sparc64/kernel/pci_iommu.c
--- linux-2.4.32/arch/sparc64/kernel/pci_iommu.c 2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.33/arch/sparc64/kernel/pci_iommu.c 2006-08-11 04:18:20.907190123 +0000
@@ -436,7 +436,7 @@
pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
(void) pci_iommu_read(iommu->write_complete_reg);
while (!PCI_STC_FLUSHFLAG_SET(strbuf))
- membar("#LoadLoad");
+ rmb();
}
/* Step 2: Clear out first TSB entry. */
@@ -674,7 +674,7 @@
pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
(void) pci_iommu_read(iommu->write_complete_reg);
while (!PCI_STC_FLUSHFLAG_SET(strbuf))
- membar("#LoadLoad");
+ rmb();
}
/* Step 2: Clear out first TSB entry. */
@@ -742,7 +742,7 @@
pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
(void) pci_iommu_read(iommu->write_complete_reg);
while (!PCI_STC_FLUSHFLAG_SET(strbuf))
- membar("#LoadLoad");
+ rmb();
spin_unlock_irqrestore(&iommu->lock, flags);
}
@@ -807,7 +807,7 @@
pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
(void) pci_iommu_read(iommu->write_complete_reg);
while (!PCI_STC_FLUSHFLAG_SET(strbuf))
- membar("#LoadLoad");
+ rmb();
spin_unlock_irqrestore(&iommu->lock, flags);
}
diff -urN linux-2.4.32/arch/sparc64/kernel/process.c linux-2.4.33/arch/sparc64/kernel/process.c
--- linux-2.4.32/arch/sparc64/kernel/process.c 2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.33/arch/sparc64/kernel/process.c 2006-08-11 04:18:20.907190123 +0000
@@ -100,7 +100,7 @@
* other cpus see our increasing idleness for the buddy
* redistribution algorithm. -DaveM
*/
- membar("#StoreStore | #StoreLoad");
+ membar_safe("#StoreStore | #StoreLoad");
}
}
diff -urN linux-2.4.32/arch/sparc64/kernel/sbus.c linux-2.4.33/arch/sparc64/kernel/sbus.c
--- linux-2.4.32/arch/sparc64/kernel/sbus.c 2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.33/arch/sparc64/kernel/sbus.c 2006-08-11 04:18:20.907190123 +0000
@@ -128,7 +128,7 @@
iommu->strbuf_regs + STRBUF_FSYNC);
upa_readq(iommu->sbus_control_reg);
while (iommu->strbuf_flushflag == 0UL)
- membar("#LoadLoad");
+ rmb();
}
static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages)
diff -urN linux-2.4.32/arch/sparc64/kernel/smp.c linux-2.4.33/arch/sparc64/kernel/smp.c
--- linux-2.4.32/arch/sparc64/kernel/smp.c 2005-04-04 01:42:19.000000000 +0000
+++ linux-2.4.33/arch/sparc64/kernel/smp.c 2006-08-11 04:18:20.911190557 +0000
@@ -163,7 +163,7 @@
current->active_mm = &init_mm;
while (!smp_threads_ready)
- membar("#LoadLoad");
+ rmb();
}
extern int cpu_idle(void);
@@ -211,11 +211,11 @@
for (i = 0; i < NUM_ITERS; i++) {
t0 = tick_ops->get_tick();
go[MASTER] = 1;
- membar("#StoreLoad");
+ membar_safe("#StoreLoad");
while (!(tm = go[SLAVE]))
- membar("#LoadLoad");
+ rmb();
go[SLAVE] = 0;
- membar("#StoreStore");
+ membar_safe("#StoreStore");
t1 = tick_ops->get_tick();
if (t1 - t0 < best_t1 - best_t0)
@@ -248,7 +248,7 @@
go[MASTER] = 1;
while (go[MASTER])
- membar("#LoadLoad");
+ rmb();
local_irq_save(flags);
{
@@ -300,21 +300,21 @@
/* wait for client to be ready */
while (!go[MASTER])
- membar("#LoadLoad");
+ rmb();
/* now let the client proceed into his loop */
go[MASTER] = 0;
- membar("#StoreLoad");
+ membar_safe("#StoreLoad");
spin_lock_irqsave(&itc_sync_lock, flags);
{
for (i = 0; i < NUM_ROUNDS*NUM_ITERS; i++) {
while (!go[MASTER])
- membar("#LoadLoad");
+ rmb();
go[MASTER] = 0;
- membar("#StoreStore");
+ membar_safe("#StoreStore");
go[SLAVE] = tick_ops->get_tick();
- membar("#StoreLoad");
+ membar_safe("#StoreLoad");
}
}
spin_unlock_irqrestore(&itc_sync_lock, flags);
@@ -431,7 +431,7 @@
smp_num_cpus = cpucount + 1;
}
smp_processors_ready = 1;
- membar("#StoreStore | #StoreLoad");
+ membar_safe("#StoreStore | #StoreLoad");
smp_synchronize_tick();
}
@@ -1036,7 +1036,7 @@
if (smp_processors_ready) {
int result = atomic_add_ret(1, &smp_capture_depth);
- membar("#StoreStore | #LoadStore");
+ membar_safe("#StoreStore | #LoadStore");
if (result == 1) {
int ncpus = smp_num_cpus;
@@ -1045,11 +1045,11 @@
smp_processor_id());
#endif
penguins_are_doing_time = 1;
- membar("#StoreStore | #LoadStore");
+ membar_safe("#StoreStore | #LoadStore");
atomic_inc(&smp_capture_registry);
smp_cross_call(&xcall_capture, 0, 0, 0);
while (atomic_read(&smp_capture_registry) != ncpus)
- membar("#LoadLoad");
+ rmb();
#ifdef CAPTURE_DEBUG
printk("done\n");
#endif
@@ -1066,7 +1066,7 @@
smp_processor_id());
#endif
penguins_are_doing_time = 0;
- membar("#StoreStore | #StoreLoad");
+ membar_safe("#StoreStore | #StoreLoad");
atomic_dec(&smp_capture_registry);
}
}
@@ -1088,9 +1088,9 @@
save_alternate_globals(global_save);
prom_world(1);
atomic_inc(&smp_capture_registry);
- membar("#StoreLoad | #StoreStore");
+ membar_safe("#StoreLoad | #StoreStore");
while (penguins_are_doing_time)
- membar("#LoadLoad");
+ rmb();
restore_alternate_globals(global_save);
atomic_dec(&smp_capture_registry);
prom_world(0);
diff -urN linux-2.4.32/arch/sparc64/kernel/sys_sparc32.c linux-2.4.33/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.32/arch/sparc64/kernel/sys_sparc32.c 2005-11-16 19:12:54.000000000 +0000
+++ linux-2.4.33/arch/sparc64/kernel/sys_sparc32.c 2006-08-11 04:18:20.911190557 +0000
@@ -2497,12 +2497,13 @@
struct cmsghdr *kcmsg, *kcmsg_base;
__kernel_size_t32 ucmlen;
__kernel_size_t kcmlen, tmp;
+ int err = -EFAULT;
kcmlen = 0;
kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
ucmsg = CMSG32_FIRSTHDR(kmsg);
while(ucmsg != NULL) {
- if(get_user(ucmlen, &ucmsg->cmsg_len))
+ if (get_user(ucmlen, &ucmsg->cmsg_len))
return -EFAULT;
/* Catch bogons. */
@@ -2511,6 +2512,7 @@
tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr)));
+ tmp = CMSG_ALIGN(tmp);
kcmlen += tmp;
ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
}
@@ -2531,21 +2533,23 @@
memset(kcmsg, 0, kcmlen);
ucmsg = CMSG32_FIRSTHDR(kmsg);
while(ucmsg != NULL) {
- __get_user(ucmlen, &ucmsg->cmsg_len);
+ if (__get_user(ucmlen, &ucmsg->cmsg_len))
+ goto Efault;
tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr)));
+ if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
+ goto Einval;
kcmsg->cmsg_len = tmp;
- __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
- __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
-
- /* Copy over the data. */
- if(copy_from_user(CMSG_DATA(kcmsg),
- CMSG32_DATA(ucmsg),
- (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
- goto out_free_efault;
+ tmp = CMSG_ALIGN(tmp);
+ if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) ||
+ __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) ||
+ copy_from_user(CMSG_DATA(kcmsg),
+ CMSG32_DATA(ucmsg),
+ (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
+ goto Efault;
/* Advance. */
- kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
+ kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp);
ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
}
@@ -2554,10 +2558,12 @@
kmsg->msg_controllen = kcmlen;
return 0;
-out_free_efault:
- if(kcmsg_base != (struct cmsghdr *)stackbuf)
+Einval:
+ err = -EINVAL;
+Efault:
+ if (kcmsg_base != (struct cmsghdr *)stackbuf)
kfree(kcmsg_base);
- return -EFAULT;
+ return err;
}
static void put_cmsg32(struct msghdr *kmsg, int level, int type,
diff -urN linux-2.4.32/arch/sparc64/kernel/traps.c linux-2.4.33/arch/sparc64/kernel/traps.c
--- linux-2.4.32/arch/sparc64/kernel/traps.c 2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.33/arch/sparc64/kernel/traps.c 2006-08-11 04:18:20.911190557 +0000
@@ -30,6 +30,7 @@
#include <asm/dcu.h>
#include <asm/estate.h>
#include <asm/chafsr.h>
+#include <asm/sfafsr.h>
#include <asm/psrcompat.h>
#include <asm/processor.h>
#ifdef CONFIG_KMOD
@@ -112,14 +113,13 @@
}
#endif
-void instruction_access_exception(struct pt_regs *regs,
- unsigned long sfsr, unsigned long sfar)
+void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
{
siginfo_t info;
if (regs->tstate & TSTATE_PRIV) {
- printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n",
- sfsr, sfar);
+ printk("spitfire_insn_access_exception: SFSR[%016lx] "
+ "SFAR[%016lx], going.\n", sfsr, sfar);
die_if_kernel("Iax", regs);
}
if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
@@ -134,15 +134,13 @@
force_sig_info(SIGSEGV, &info, current);
}
-void instruction_access_exception_tl1(struct pt_regs *regs,
- unsigned long sfsr, unsigned long sfar)
+void spitfire_insn_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
{
dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
- instruction_access_exception(regs, sfsr, sfar);
+ spitfire_insn_access_exception(regs, sfsr, sfar);
}
-void data_access_exception (struct pt_regs *regs,
- unsigned long sfsr, unsigned long sfar)
+void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
{
siginfo_t info;
@@ -164,8 +162,8 @@
return;
}
/* Shit... */
- printk("data_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n",
- sfsr, sfar);
+ printk("spitfire_data_access_exception: SFSR[%016lx] "
+ "SFAR[%016lx], going.\n", sfsr, sfar);
die_if_kernel("Dax", regs);
}
@@ -177,6 +175,12 @@
force_sig_info(SIGSEGV, &info, current);
}
+void spitfire_data_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
+{
+ dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+ spitfire_data_access_exception(regs, sfsr, sfar);
+}
+
#ifdef CONFIG_PCI
/* This is really pathetic... */
extern volatile int pci_poke_in_progress;
@@ -210,37 +214,13 @@
: "memory");
}
-void do_iae(struct pt_regs *regs)
+static void spitfire_enable_estate_errors(void)
{
- siginfo_t info;
-
- spitfire_clean_and_reenable_l1_caches();
-
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_OBJERR;
- info.si_addr = (void *)0;
- info.si_trapno = 0;
- force_sig_info(SIGBUS, &info, current);
-}
-
-void do_dae(struct pt_regs *regs)
-{
-#ifdef CONFIG_PCI
- if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
- spitfire_clean_and_reenable_l1_caches();
-
- pci_poke_faulted = 1;
-
- /* Why the fuck did they have to change this? */
- if (tlb_type == cheetah || tlb_type == cheetah_plus)
- regs->tpc += 4;
-
- regs->tnpc = regs->tpc + 4;
- return;
- }
-#endif
- do_iae(regs);
+ __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (ESTATE_ERR_ALL),
+ "i" (ASI_ESTATE_ERROR_EN));
}
static char ecc_syndrome_table[] = {
@@ -278,65 +258,15 @@
0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a
};
-/* cee_trap in entry.S encodes AFSR/UDBH/UDBL error status
- * in the following format. The AFAR is left as is, with
- * reserved bits cleared, and is a raw 40-bit physical
- * address.
- */
-#define CE_STATUS_UDBH_UE (1UL << (43 + 9))
-#define CE_STATUS_UDBH_CE (1UL << (43 + 8))
-#define CE_STATUS_UDBH_ESYNDR (0xffUL << 43)
-#define CE_STATUS_UDBH_SHIFT 43
-#define CE_STATUS_UDBL_UE (1UL << (33 + 9))
-#define CE_STATUS_UDBL_CE (1UL << (33 + 8))
-#define CE_STATUS_UDBL_ESYNDR (0xffUL << 33)
-#define CE_STATUS_UDBL_SHIFT 33
-#define CE_STATUS_AFSR_MASK (0x1ffffffffUL)
-#define CE_STATUS_AFSR_ME (1UL << 32)
-#define CE_STATUS_AFSR_PRIV (1UL << 31)
-#define CE_STATUS_AFSR_ISAP (1UL << 30)
-#define CE_STATUS_AFSR_ETP (1UL << 29)
-#define CE_STATUS_AFSR_IVUE (1UL << 28)
-#define CE_STATUS_AFSR_TO (1UL << 27)
-#define CE_STATUS_AFSR_BERR (1UL << 26)
-#define CE_STATUS_AFSR_LDP (1UL << 25)
-#define CE_STATUS_AFSR_CP (1UL << 24)
-#define CE_STATUS_AFSR_WP (1UL << 23)
-#define CE_STATUS_AFSR_EDP (1UL << 22)
-#define CE_STATUS_AFSR_UE (1UL << 21)
-#define CE_STATUS_AFSR_CE (1UL << 20)
-#define CE_STATUS_AFSR_ETS (0xfUL << 16)
-#define CE_STATUS_AFSR_ETS_SHIFT 16
-#define CE_STATUS_AFSR_PSYND (0xffffUL << 0)
-#define CE_STATUS_AFSR_PSYND_SHIFT 0
-
-/* Layout of Ecache TAG Parity Syndrome of AFSR */
-#define AFSR_ETSYNDROME_7_0 0x1UL /* E$-tag bus bits <7:0> */
-#define AFSR_ETSYNDROME_15_8 0x2UL /* E$-tag bus bits <15:8> */
-#define AFSR_ETSYNDROME_21_16 0x4UL /* E$-tag bus bits <21:16> */
-#define AFSR_ETSYNDROME_24_22 0x8UL /* E$-tag bus bits <24:22> */
-
static char *syndrome_unknown = "<Unknown>";
-asmlinkage void cee_log(unsigned long ce_status,
- unsigned long afar,
- struct pt_regs *regs)
-{
- char memmod_str[64];
- char *p;
- unsigned short scode, udb_reg;
+static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long bit)
+{
+ unsigned short scode;
+ char memmod_str[64], *p;
- printk(KERN_WARNING "CPU[%d]: Correctable ECC Error "
- "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx]\n",
- smp_processor_id(),
- (ce_status & CE_STATUS_AFSR_MASK),
- afar,
- ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL),
- ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL));
-
- udb_reg = ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL);
- if (udb_reg & (1 << 8)) {
- scode = ecc_syndrome_table[udb_reg & 0xff];
+ if (udbl & bit) {
+ scode = ecc_syndrome_table[udbl & 0xff];
if (prom_getunumber(scode, afar,
memmod_str, sizeof(memmod_str)) == -1)
p = syndrome_unknown;
@@ -347,9 +277,8 @@
smp_processor_id(), scode, p);
}
- udb_reg = ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL);
- if (udb_reg & (1 << 8)) {
- scode = ecc_syndrome_table[udb_reg & 0xff];
+ if (udbh & bit) {
+ scode = ecc_syndrome_table[udbh & 0xff];
if (prom_getunumber(scode, afar,
memmod_str, sizeof(memmod_str)) == -1)
p = syndrome_unknown;
@@ -359,6 +288,115 @@
"Memory Module \"%s\"\n",
smp_processor_id(), scode, p);
}
+
+}
+
+static void spitfire_cee_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, int tl1, struct pt_regs *regs)
+{
+
+ printk(KERN_WARNING "CPU[%d]: Correctable ECC Error "
+ "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx] TL>1[%d]\n",
+ smp_processor_id(), afsr, afar, udbl, udbh, tl1);
+
+ spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_CE);
+
+ /* The Correctable ECC Error trap does not disable I/D caches. So
+ * we only have to restore the ESTATE Error Enable register.
+ */
+ spitfire_enable_estate_errors();
+}
+
+static void spitfire_ue_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long tt, int tl1, struct pt_regs *regs)
+{
+ siginfo_t info;
+
+ printk(KERN_WARNING "CPU[%d]: Uncorrectable Error AFSR[%lx] "
+ "AFAR[%lx] UDBL[%lx] UDBH[%ld] TT[%lx] TL>1[%d]\n",
+ smp_processor_id(), afsr, afar, udbl, udbh, tt, tl1);
+
+ /* XXX add more human friendly logging of the error status
+ * XXX as is implemented for cheetah
+ */
+
+ spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_UE);
+
+ if (regs->tstate & TSTATE_PRIV) {
+ if (tl1)
+ dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
+ die_if_kernel("UE", regs);
+ }
+
+ /* XXX need more intelligent processing here, such as is implemented
+ * XXX for cheetah errors, in fact if the E-cache still holds the
+ * XXX line with bad parity this will loop
+ */
+
+ spitfire_clean_and_reenable_l1_caches();
+ spitfire_enable_estate_errors();
+
+ if (current->thread.flags & SPARC_FLAG_32BIT) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_OBJERR;
+ info.si_addr = (void *)0;
+ info.si_trapno = 0;
+ force_sig_info(SIGBUS, &info, current);
+}
+
+void spitfire_access_error(struct pt_regs *regs, unsigned long status_encoded, unsigned long afar)
+{
+ unsigned long afsr, tt, udbh, udbl;
+ int tl1;
+
+ afsr = (status_encoded & SFSTAT_AFSR_MASK) >> SFSTAT_AFSR_SHIFT;
+ tt = (status_encoded & SFSTAT_TRAP_TYPE) >> SFSTAT_TRAP_TYPE_SHIFT;
+ tl1 = (status_encoded & SFSTAT_TL_GT_ONE) ? 1 : 0;
+ udbl = (status_encoded & SFSTAT_UDBL_MASK) >> SFSTAT_UDBL_SHIFT;
+ udbh = (status_encoded & SFSTAT_UDBH_MASK) >> SFSTAT_UDBH_SHIFT;
+
+#ifdef CONFIG_PCI
+ if (tt == TRAP_TYPE_DAE &&
+ pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
+ spitfire_clean_and_reenable_l1_caches();
+ spitfire_enable_estate_errors();
+
+ pci_poke_faulted = 1;
+ regs->tnpc = regs->tpc + 4;
+ return;
+ }
+#endif
+
+ if (afsr & SFAFSR_UE)
+ spitfire_ue_log(afsr, afar, udbh, udbl, tt, tl1, regs);
+
+ if (tt == TRAP_TYPE_CEE) {
+ /* Handle the case where we took a CEE trap, but ACK'd
+ * only the UE state in the UDB error registers.
+ */
+ if (afsr & SFAFSR_UE) {
+ if (udbh & UDBE_CE) {
+ __asm__ __volatile__(
+ "stxa %0, [%1] %2\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (udbh & UDBE_CE),
+ "r" (0x0), "i" (ASI_UDB_ERROR_W));
+ }
+ if (udbl & UDBE_CE) {
+ __asm__ __volatile__(
+ "stxa %0, [%1] %2\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (udbl & UDBE_CE),
+ "r" (0x18), "i" (ASI_UDB_ERROR_W));
+ }
+ }
+
+ spitfire_cee_log(afsr, afar, udbh, udbl, tl1, regs);
+ }
}
/* Cheetah error trap handling. */
diff -urN linux-2.4.32/arch/sparc64/kernel/ttable.S linux-2.4.33/arch/sparc64/kernel/ttable.S
--- linux-2.4.32/arch/sparc64/kernel/ttable.S 2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.33/arch/sparc64/kernel/ttable.S 2006-08-11 04:18:20.911190557 +0000
@@ -18,9 +18,10 @@
tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7)
tl0_iax: membar #Sync
- TRAP_NOSAVE_7INSNS(__do_instruction_access_exception)
+ TRAP_NOSAVE_7INSNS(__spitfire_insn_access_exception)
tl0_resv009: BTRAP(0x9)
-tl0_iae: TRAP(do_iae)
+tl0_iae: membar #Sync
+ TRAP_NOSAVE_7INSNS(__spitfire_access_error)
tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
tl0_ill: membar #Sync
TRAP_7INSNS(do_illegal_instruction)
@@ -36,9 +37,10 @@
tl0_div0: TRAP(do_div0)
tl0_resv029: BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e)
tl0_resv02f: BTRAP(0x2f)
-tl0_dax: TRAP_NOSAVE(__do_data_access_exception)
+tl0_dax: TRAP_NOSAVE(__spitfire_data_access_exception)
tl0_resv031: BTRAP(0x31)
-tl0_dae: TRAP(do_dae)
+tl0_dae: membar #Sync
+ TRAP_NOSAVE_7INSNS(__spitfire_access_error)
tl0_resv033: BTRAP(0x33)
tl0_mna: TRAP_NOSAVE(do_mna)
tl0_lddfmna: TRAP_NOSAVE(do_lddfmna)
@@ -73,7 +75,8 @@
tl0_ivec: TRAP_IVEC
tl0_paw: TRAP(do_paw)
tl0_vaw: TRAP(do_vaw)
-tl0_cee: TRAP_NOSAVE(cee_trap)
+tl0_cee: membar #Sync
+ TRAP_NOSAVE_7INSNS(__spitfire_cee_trap)
tl0_iamiss:
#include "itlb_base.S"
tl0_damiss:
@@ -175,9 +178,10 @@
sparc64_ttable_tl1:
tl1_resv000: BOOT_KERNEL BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3)
tl1_resv004: BTRAPTL1(0x4) BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7)
-tl1_iax: TRAP_NOSAVE(__do_instruction_access_exception_tl1)
+tl1_iax: TRAP_NOSAVE(__spitfire_insn_access_exception_tl1)
tl1_resv009: BTRAPTL1(0x9)
-tl1_iae: TRAPTL1(do_iae_tl1)
+tl1_iae: membar #Sync
+ TRAP_NOSAVE_7INSNS(__spitfire_access_error)
tl1_resv00b: BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf)
tl1_ill: TRAPTL1(do_ill_tl1)
tl1_privop: BTRAPTL1(0x11)
@@ -193,9 +197,10 @@
tl1_div0: TRAPTL1(do_div0_tl1)
tl1_resv029: BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c)
tl1_resv02d: BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f)
-tl1_dax: TRAP_NOSAVE(__do_data_access_exception_tl1)
+tl1_dax: TRAP_NOSAVE(__spitfire_data_access_exception_tl1)
tl1_resv031: BTRAPTL1(0x31)
-tl1_dae: TRAPTL1(do_dae_tl1)
+tl1_dae: membar #Sync
+ TRAP_NOSAVE_7INSNS(__spitfire_access_error)
tl1_resv033: BTRAPTL1(0x33)
tl1_mna: TRAP_NOSAVE(do_mna)
tl1_lddfmna: TRAPTL1(do_lddfmna_tl1)
@@ -218,11 +223,12 @@
tl1_paw: TRAPTL1(do_paw_tl1)
tl1_vaw: TRAPTL1(do_vaw_tl1)
- /* The grotty trick to save %g1 into current->thread.kernel_cntd0
- * is because when we take this trap we could be interrupting trap
- * code already using the trap alternate global registers. It is
- * better to corrupt a performance counter than corrupt trap register
- * state. We cross our fingers and pray that this store/load does
+ /* The grotty trick to save %g1 into
+ * current->thread.kernel_cntd0 is because when we take this
+ * trap we could be interrupting trap code already using the
+ * trap alternate global registers. It is better to corrupt
+ * a performance counter than corrupt trap register state.
+ * We cross our fingers and pray that this store/load does
* not cause yet another CEE trap.
*/
tl1_cee: membar #Sync
diff -urN linux-2.4.32/arch/sparc64/kernel/unaligned.c linux-2.4.33/arch/sparc64/kernel/unaligned.c
--- linux-2.4.32/arch/sparc64/kernel/unaligned.c 2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.33/arch/sparc64/kernel/unaligned.c 2006-08-11 04:18:20.911190557 +0000
@@ -479,9 +479,9 @@
extern void do_fpother(struct pt_regs *regs);
extern void do_privact(struct pt_regs *regs);
-extern void data_access_exception(struct pt_regs *regs,
- unsigned long sfsr,
- unsigned long sfar);
+extern void spitfire_data_access_exception(struct pt_regs *regs,
+ unsigned long sfsr,
+ unsigned long sfar);
int handle_ldf_stq(u32 insn, struct pt_regs *regs)
{
@@ -524,14 +524,14 @@
break;
}
default:
- data_access_exception(regs, 0, addr);
+ spitfire_data_access_exception(regs, 0, addr);
return 1;
}
if (put_user (first >> 32, (u32 *)addr) ||
__put_user ((u32)first, (u32 *)(addr + 4)) ||
__put_user (second >> 32, (u32 *)(addr + 8)) ||
__put_user ((u32)second, (u32 *)(addr + 12))) {
- data_access_exception(regs, 0, addr);
+ spitfire_data_access_exception(regs, 0, addr);
return 1;
}
} else {
@@ -544,7 +544,7 @@
do_privact(regs);
return 1;
} else if (asi > ASI_SNFL) {
- data_access_exception(regs, 0, addr);
+ spitfire_data_access_exception(regs, 0, addr);
return 1;
}
switch (insn & 0x180000) {
@@ -561,7 +561,7 @@
err |= __get_user (data[i], (u32 *)(addr + 4*i));
}
if (err && !(asi & 0x2 /* NF */)) {
- data_access_exception(regs, 0, addr);
+ spitfire_data_access_exception(regs, 0, addr);
return 1;
}
if (asi & 0x8) /* Little */ {
@@ -664,7 +664,7 @@
*(u64 *)(f->regs + freg) = value;
current->thread.fpsaved[0] |= flag;
} else {
-daex: data_access_exception(regs, sfsr, sfar);
+daex: spitfire_data_access_exception(regs, sfsr, sfar);
return;
}
advance(regs);
@@ -708,7 +708,7 @@
__put_user ((u32)value, (u32 *)(sfar + 4)))
goto daex;
} else {
-daex: data_access_exception(regs, sfsr, sfar);
+daex: spitfire_data_access_exception(regs, sfsr, sfar);
return;
}
advance(regs);
diff -urN linux-2.4.32/arch/sparc64/kernel/winfixup.S linux-2.4.33/arch/sparc64/kernel/winfixup.S
--- linux-2.4.32/arch/sparc64/kernel/winfixup.S 2003-06-13 14:51:32.000000000 +0000
+++ linux-2.4.33/arch/sparc64/kernel/winfixup.S 2006-08-11 04:18:20.911190557 +0000
@@ -296,7 +296,7 @@
flush %g6 ! Flush instruction buffers
rdpr %pstate, %l1 ! Prepare to change globals.
mov %g4, %o1 ! Setup args for
- mov %g5, %o2 ! final call to data_access_exception.
+ mov %g5, %o2 ! final call to spitfire_data_access_exception.
andn %l1, PSTATE_MM, %l1 ! We want to be in RMO
mov %g6, %o7 ! Stash away current.
@@ -305,7 +305,7 @@
sethi %uhi(PAGE_OFFSET), %g4 ! Set page_offset global reg.
mov %o7, %g6 ! Get current back.
sllx %g4, 32, %g4 ! Finish it.
- call data_access_exception
+ call spitfire_data_access_exception
add %sp, PTREGS_OFF, %o0
b,pt %xcc, rtrap
@@ -366,7 +366,7 @@
109: or %g7, %lo(109b), %g7
mov %l4, %o1
mov %l5, %o2
- call data_access_exception
+ call spitfire_data_access_exception
add %sp, PTREGS_OFF, %o0
ba,pt %xcc, rtrap
clr %l6
diff -urN linux-2.4.32/arch/sparc64/lib/debuglocks.c linux-2.4.33/arch/sparc64/lib/debuglocks.c
--- linux-2.4.32/arch/sparc64/lib/debuglocks.c 2005-04-04 01:42:19.000000000 +0000
+++ linux-2.4.33/arch/sparc64/lib/debuglocks.c 2006-08-11 04:18:20.911190557 +0000
@@ -61,7 +61,7 @@
: "=r" (val)
: "r" (&(lock->lock))
: "memory");
- membar("#StoreLoad | #StoreStore");
+ membar_safe("#StoreLoad | #StoreStore");
if (val) {
while (lock->lock) {
if (!--stuck) {
@@ -69,7 +69,7 @@
show(str, lock, caller);
stuck = INIT_STUCK;
}
- membar("#LoadLoad");
+ rmb();
}
goto again;
}
@@ -89,7 +89,7 @@
: "=r" (val)
: "r" (&(lock->lock))
: "memory");
- membar("#StoreLoad | #StoreStore");
+ membar_safe("#StoreLoad | #StoreStore");
if (!val) {
lock->owner_pc = ((unsigned int)caller);
lock->owner_cpu = cpu;
@@ -103,7 +103,7 @@
{
lock->owner_pc = 0;
lock->owner_cpu = NO_PROC_ID;
- membar("#StoreStore | #LoadStore");
+ membar_safe("#StoreStore | #LoadStore");
lock->lock = 0;
current->thread.smp_lock_count--;
}
@@ -126,7 +126,7 @@
show_read(str, rw, caller);
stuck = INIT_STUCK;
}
- membar("#LoadLoad");
+ rmb();
}
/* Try once to increment the counter. */
__asm__ __volatile__(
@@ -139,7 +139,7 @@
"2:" : "=r" (val)
: "0" (&(rw->lock))
: "g5", "g7", "memory");
- membar("#StoreLoad | #StoreStore");
+ membar_safe("#StoreLoad | #StoreStore");
if (val)
goto wlock_again;
rw->reader_pc[cpu] = ((unsigned int)caller);
@@ -197,7 +197,7 @@
show_write(str, rw, caller);
stuck = INIT_STUCK;
}
- membar("#LoadLoad");
+ rmb();
}
/* Try to acuire the write bit. */
@@ -251,7 +251,7 @@
show_write(str, rw, caller);
stuck = INIT_STUCK;
}
- membar("#LoadLoad");
+ rmb();
}
goto wlock_again;
}
diff -urN linux-2.4.32/arch/x86_64/ia32/socket32.c linux-2.4.33/arch/x86_64/ia32/socket32.c
--- linux-2.4.32/arch/x86_64/ia32/socket32.c 2005-04-04 01:42:19.000000000 +0000
+++ linux-2.4.33/arch/x86_64/ia32/socket32.c 2006-08-11 04:18:20.915190991 +0000
@@ -127,12 +127,13 @@
struct cmsghdr *kcmsg, *kcmsg_base;
__kernel_size_t32 ucmlen;
__kernel_size_t kcmlen, tmp;
+ int err = -EFAULT;
kcmlen = 0;
kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
ucmsg = CMSG32_FIRSTHDR(kmsg);
while(ucmsg != NULL) {
- if(get_user(ucmlen, &ucmsg->cmsg_len))
+ if (get_user(ucmlen, &ucmsg->cmsg_len))
return -EFAULT;
/* Catch bogons. */
@@ -164,18 +165,19 @@
memset(kcmsg, 0, kcmlen);
ucmsg = CMSG32_FIRSTHDR(kmsg);
while(ucmsg != NULL) {
- __get_user(ucmlen, &ucmsg->cmsg_len);
+ if (__get_user(ucmlen, &ucmsg->cmsg_len))
+ goto Efault;
tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr)));
+ if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
+ goto Einval;
kcmsg->cmsg_len = tmp;
- __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
- __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
-
- /* Copy over the data. */
- if(copy_from_user(CMSG_DATA(kcmsg),
- CMSG32_DATA(ucmsg),
- (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
- goto out_free_efault;
+ if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) ||
+ __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) ||
+ copy_from_user(CMSG_DATA(kcmsg),
+ CMSG32_DATA(ucmsg),
+ (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
+ goto Efault;
/* Advance. */
kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
@@ -187,10 +189,12 @@
kmsg->msg_controllen = kcmlen;
return 0;
-out_free_efault:
- if(kcmsg_base != (struct cmsghdr *)stackbuf)
+Einval:
+ err = -EINVAL;
+Efault:
+ if (kcmsg_base != (struct cmsghdr *)stackbuf)
kfree(kcmsg_base);
- return -EFAULT;
+ return err;
}
static void put_cmsg32(struct msghdr *kmsg, int level, int type,
diff -urN linux-2.4.32/arch/x86_64/kernel/process.c linux-2.4.33/arch/x86_64/kernel/process.c
--- linux-2.4.32/arch/x86_64/kernel/process.c 2005-11-16 19:12:54.000000000 +0000
+++ linux-2.4.33/arch/x86_64/kernel/process.c 2006-08-11 04:18:20.915190991 +0000
@@ -564,8 +564,6 @@
*next = &next_p->thread;
struct tss_struct *tss = init_tss + smp_processor_id();
- unlazy_fpu(prev_p);
-
/*
* Reload rsp0, LDT and the page table pointer:
*/
@@ -583,6 +581,11 @@
loadsegment(ds, next->ds);
/*
+ * Must be after DS reload for AMD workaround.
+ */
+ unlazy_fpu(prev_p);
+
+ /*
* Switch FS and GS.
*/
{
diff -urN linux-2.4.32/arch/x86_64/kernel/signal.c linux-2.4.33/arch/x86_64/kernel/signal.c
--- linux-2.4.32/arch/x86_64/kernel/signal.c 2005-01-19 14:09:40.000000000 +0000
+++ linux-2.4.33/arch/x86_64/kernel/signal.c 2006-08-11 04:18:20.915190991 +0000
@@ -137,15 +137,16 @@
#define COPY(x) err |= __get_user(regs->x, &sc->x)
-#define COPY_CANON(x) \
- COPY(x); \
- if ((regs->x >> 48) != 0 && (regs->x >> 48) != 0xffff) \
- regs->x = 0;
/* fs and gs are ignored because we cannot handle the 64bit base easily */
- COPY(rdi); COPY(rsi); COPY(rbp); COPY_CANON(rsp); COPY(rbx);
- COPY(rdx); COPY(rcx); COPY_CANON(rip);
+ COPY(rdi); COPY(rsi); COPY(rbp); COPY(rsp); COPY(rbx);
+ COPY(rdx); COPY(rcx);
+ COPY(rip);
+ if (regs->rip >= TASK_SIZE && regs->rip < VSYSCALL_START) {
+ regs->rip = 0;
+ return -EFAULT;
+ }
COPY(r8);
COPY(r9);
COPY(r10);
@@ -357,6 +358,11 @@
regs->rdx = (unsigned long)&frame->uc;
regs->rsp = (unsigned long) frame;
regs->rip = (unsigned long) ka->sa.sa_handler;
+ if (regs->rip >= TASK_SIZE) {
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ regs->rip = 0;
+ }
regs->cs = __USER_CS;
regs->ss = __USER_DS;
diff -urN linux-2.4.32/CREDITS linux-2.4.33/CREDITS
--- linux-2.4.32/CREDITS 2005-01-19 14:09:22.000000000 +0000
+++ linux-2.4.33/CREDITS 2006-08-11 04:18:20.915190991 +0000
@@ -2996,7 +2996,7 @@
S: USA
N: Marcelo W. Tosatti
-E: marcelo.tosatti@cyclades.com
+E: marcelo@kvack.org
D: Miscellaneous kernel hacker (mostly VM/MM work)
D: 2.4 maintainer
S: Av Cristovao Colombo, 462. Floresta.
diff -urN linux-2.4.32/Documentation/Changes linux-2.4.33/Documentation/Changes
--- linux-2.4.32/Documentation/Changes 2005-04-04 01:42:19.000000000 +0000
+++ linux-2.4.33/Documentation/Changes 2006-08-11 04:18:20.915190991 +0000
@@ -91,6 +91,8 @@
You should ensure you use gcc-2.96-74 or later. gcc-2.96-54 will not build
the kernel correctly.
+gcc 4 is not supported.
+
In addition, please pay attention to compiler optimization. Anything
greater than -O2 may not be wise. Similarly, if you choose to use gcc-2.95.x
or derivatives, be sure not to use -fstrict-aliasing (which, depending on
diff -urN linux-2.4.32/Documentation/Configure.help linux-2.4.33/Documentation/Configure.help
--- linux-2.4.32/Documentation/Configure.help 2005-11-16 19:12:54.000000000 +0000
+++ linux-2.4.33/Documentation/Configure.help 2006-08-11 04:18:20.927192293 +0000
@@ -8148,7 +8148,7 @@
Debug code enable mask (2048 for all debugging)
CONFIG_AIC7XXX_DEBUG_MASK
Bit mask of debug options that is only valid if the
- CONFIG_AIC7XXX_DEBUG_ENBLE option is enabled. The bits in this mask
+ CONFIG_AIC7XXX_DEBUG_ENABLE option is enabled. The bits in this mask
are defined in the drivers/scsi/aic7xxx/aic7xxx.h - search for the
variable ahc_debug in that file to find them.
@@ -8322,7 +8322,7 @@
CONFIG_AIC79XX_DEBUG_MASK
Bit mask of debug options that is only valid if the
- CONFIG_AIC79XX_DEBUG_ENBLE option is enabled. The bits in this mask
+ CONFIG_AIC79XX_DEBUG_ENABLE option is enabled. The bits in this mask
are defined in the drivers/scsi/aic7xxx/aic79xx.h - search for the
variable ahd_debug in that file to find them.
@@ -15240,6 +15240,24 @@
The module will be called joydev.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+Dummy keyboard driver
+CONFIG_DUMMY_KEYB
+ What is this for?
+
+ Not all systems have keyboards. Some don't even have a keyboard
+ port. However, some of those systems have video support and can
+ use the virtual terminal support for display. However, the virtual
+ terminal code expects a keyboard of some kind. This driver keeps
+ the virtual terminal code happy by providing it a "keyboard", albeit
+ a very quiet one.
+
+ If you want to use the virtual terminal support but your system
+ does not support a keyboard, define CONFIG_DUMMY_KEYB along with
+ CONFIG_VT.
+
+ This can also be selected lonesome without any VT support (i.e. no
+ monitor or keyboard attached) - just define CONFIG_DUMMY_KEYB.
+
Event interface support
CONFIG_INPUT_EVDEV
Say Y here if you want your USB or ADB HID device events be
diff -urN linux-2.4.32/drivers/acpi/system.c linux-2.4.33/drivers/acpi/system.c
--- linux-2.4.32/drivers/acpi/system.c 2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.33/drivers/acpi/system.c 2006-08-11 04:18:20.927192293 +0000
@@ -748,7 +748,7 @@
state = simple_strtoul(state_string, NULL, 0);
- if (!system->states[state])
+ if (state >= ACPI_S_STATE_COUNT || !system->states[state])
return_VALUE(-ENODEV);
/*
diff -urN linux-2.4.32/drivers/block/ll_rw_blk.c linux-2.4.33/drivers/block/ll_rw_blk.c
--- linux-2.4.32/drivers/block/ll_rw_blk.c 2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.33/drivers/block/ll_rw_blk.c 2006-08-11 04:18:20.927192293 +0000
@@ -285,21 +285,6 @@
void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr)
{
unsigned long bounce_pfn = dma_addr >> PAGE_SHIFT;
- unsigned long mb = dma_addr >> 20;
- static request_queue_t *old_q;
-
- /*
- * keep this for debugging for now...
- */
- if (dma_addr != BLK_BOUNCE_HIGH && q != old_q) {
- old_q = q;
- printk("blk: queue %p, ", q);
- if (dma_addr == BLK_BOUNCE_ANY)
- printk("no I/O memory limit\n");
- else
- printk("I/O limit %luMb (mask 0x%Lx)\n", mb,
- (long long) dma_addr);
- }
q->bounce_pfn = bounce_pfn;
}
diff -urN linux-2.4.32/drivers/cdrom/cdrom.c linux-2.4.33/drivers/cdrom/cdrom.c
--- linux-2.4.32/drivers/cdrom/cdrom.c 2005-01-19 14:09:43.000000000 +0000
+++ linux-2.4.33/drivers/cdrom/cdrom.c 2006-08-11 04:18:20.927192293 +0000
@@ -1259,7 +1259,7 @@
init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
cgc.cmd[7] = s->type;
- cgc.cmd[9] = cgc.buflen = 0xff;
+ cgc.cmd[9] = cgc.buflen & 0xff;
if ((ret = cdo->generic_packet(cdi, &cgc)))
return ret;
diff -urN linux-2.4.32/drivers/char/drm/drm_stub.h linux-2.4.33/drivers/char/drm/drm_stub.h
--- linux-2.4.32/drivers/char/drm/drm_stub.h 2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.33/drivers/char/drm/drm_stub.h 2006-08-11 04:18:20.927192293 +0000
@@ -52,6 +52,7 @@
int err = -ENODEV;
struct file_operations *old_fops;
+ if (minor < 0 || minor >=DRM_STUB_MAXCARDS) return -ENODEV;
if (!DRM(stub_list) || !DRM(stub_list)[minor].fops) return -ENODEV;
old_fops = filp->f_op;
filp->f_op = fops_get(DRM(stub_list)[minor].fops);
diff -urN linux-2.4.32/drivers/char/drm/radeon_mem.c linux-2.4.33/drivers/char/drm/radeon_mem.c
--- linux-2.4.32/drivers/char/drm/radeon_mem.c 2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.33/drivers/char/drm/radeon_mem.c 2006-08-11 04:18:20.927192293 +0000
@@ -131,6 +131,7 @@
}
}
+#if 0
static void print_heap( struct mem_block *heap )
{
struct mem_block *p;
@@ -140,6 +141,7 @@
p->start, p->start + p->size,
p->size, p->pid);
}
+#endif
/* Initialize. How to check for an uninitialized heap?
*/
diff -urN linux-2.4.32/drivers/char/dummy_keyb.c linux-2.4.33/drivers/char/dummy_keyb.c
--- linux-2.4.32/drivers/char/dummy_keyb.c 2003-08-25 11:44:41.000000000 +0000
+++ linux-2.4.33/drivers/char/dummy_keyb.c 2006-08-11 04:18:20.927192293 +0000
@@ -29,6 +29,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/input.h>
+#include <asm/keyboard.h>
void kbd_leds(unsigned char leds)
{
diff -urN linux-2.4.32/drivers/i2c/scx200_acb.c linux-2.4.33/drivers/i2c/scx200_acb.c
--- linux-2.4.32/drivers/i2c/scx200_acb.c 2003-06-13 14:51:33.000000000 +0000
+++ linux-2.4.33/drivers/i2c/scx200_acb.c 2006-08-11 04:18:20.927192293 +0000
@@ -467,7 +467,6 @@
struct scx200_acb_iface *iface;
struct i2c_adapter *adapter;
int rc = 0;
- char description[64];
iface = kmalloc(sizeof(*iface), GFP_KERNEL);
if (!iface) {
@@ -489,8 +488,7 @@
init_MUTEX(&iface->sem);
- sprintf(description, "NatSemi SCx200 ACCESS.bus [%s]", adapter->name);
- if (request_region(base, 8, description) == 0) {
+ if (request_region(base, 8, adapter->name) == 0) {
printk(KERN_ERR NAME ": %s, can't allocate io 0x%x-0x%x\n",
adapter->name, base, base + 8-1);
rc = -EBUSY;
diff -urN linux-2.4.32/drivers/ide/ide-dma.c linux-2.4.33/drivers/ide/ide-dma.c
--- linux-2.4.32/drivers/ide/ide-dma.c 2003-08-25 11:44:41.000000000 +0000
+++ linux-2.4.33/drivers/ide/ide-dma.c 2006-08-11 04:18:20.927192293 +0000
@@ -137,6 +137,7 @@
{ "CD-ROM Drive/F5A", "ALL" },
{ "RICOH CD-R/RW MP7083A", "ALL" },
{ "WPI CDD-820", "ALL" },
+ { "SAMSUNG CD-ROM SC-140", "ALL" },
{ "SAMSUNG CD-ROM SC-148C", "ALL" },
{ "SAMSUNG CD-ROM SC-148F", "ALL" },
{ "SAMSUNG CD-ROM SC", "ALL" },
@@ -566,6 +567,18 @@
}
/**
+ * __ide_dma_no_op - dummy DMA function.
+ *
+ * This empty function prevents non-DMA controllers from causing an oops.
+ */
+
+static int __ide_dma_no_op (ide_drive_t *ignored)
+{
+ return 0;
+}
+
+
+/**
* __ide_dma_host_off - Generic DMA kill
* @drive: drive to control
*
@@ -1214,3 +1227,20 @@
}
EXPORT_SYMBOL_GPL(ide_setup_dma);
+
+/*
+ * For IDE interfaces that do not support DMA, we still need to
+ * initialize some pointers to dummy functions.
+ */
+void ide_setup_no_dma (ide_hwif_t *hwif)
+{
+ if (!hwif->ide_dma_off_quietly)
+ hwif->ide_dma_off_quietly = &__ide_dma_no_op;
+ if (!hwif->ide_dma_host_off)
+ hwif->ide_dma_host_off = &__ide_dma_no_op;
+ if (!hwif->ide_dma_host_on)
+ hwif->ide_dma_host_on = &__ide_dma_no_op;
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_no_dma);
+
diff -urN linux-2.4.32/drivers/ide/ide-io.c linux-2.4.33/drivers/ide/ide-io.c
--- linux-2.4.32/drivers/ide/ide-io.c 2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.33/drivers/ide/ide-io.c 2006-08-11 04:18:20.931192727 +0000
@@ -899,11 +899,13 @@
rq = HWGROUP(drive)->rq;
HWGROUP(drive)->rq = NULL;
- rq->errors = 0;
- rq->sector = rq->bh->b_rsector;
- rq->current_nr_sectors = rq->bh->b_size >> 9;
- rq->hard_cur_sectors = rq->current_nr_sectors;
- rq->buffer = rq->bh->b_data;
+ if (rq) {
+ rq->errors = 0;
+ rq->sector = rq->bh->b_rsector;
+ rq->current_nr_sectors = rq->bh->b_size >> 9;
+ rq->hard_cur_sectors = rq->current_nr_sectors;
+ rq->buffer = rq->bh->b_data;
+ }
return ret;
}
diff -urN linux-2.4.32/drivers/ide/pci/atiixp.c linux-2.4.33/drivers/ide/pci/atiixp.c
--- linux-2.4.32/drivers/ide/pci/atiixp.c 2004-04-14 13:05:29.000000000 +0000
+++ linux-2.4.33/drivers/ide/pci/atiixp.c 2006-08-11 04:18:20.931192727 +0000
@@ -467,15 +467,35 @@
static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
{ /* 0 */
.vendor = PCI_VENDOR_ID_ATI,
- .device = PCI_DEVICE_ID_ATI_IXP_IDE,
- .name = "ATIIXP",
+ .device = PCI_DEVICE_ID_ATI_IXP200_IDE,
+ .name = "ATI-IXP200",
.init_chipset = init_chipset_atiixp,
.init_hwif = init_hwif_atiixp,
.channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
.bootable = ON_BOARD,
- }
+ },{ /* 1 */
+ .vendor = PCI_VENDOR_ID_ATI,
+ .device = PCI_DEVICE_ID_ATI_IXP300_IDE,
+ .name = "ATI-IXP300",
+ .init_chipset = init_chipset_atiixp,
+ .init_hwif = init_hwif_atiixp,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
+ .bootable = ON_BOARD,
+ },{ /* 2 */
+ .vendor = PCI_VENDOR_ID_ATI,
+ .device = PCI_DEVICE_ID_ATI_IXP400_IDE,
+ .name = "ATI-IXP400",
+ .init_chipset = init_chipset_atiixp,
+ .init_hwif = init_hwif_atiixp,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
+ .bootable = ON_BOARD,
+ }
};
/**
@@ -498,7 +518,9 @@
}
static struct pci_device_id atiixp_pci_tbl[] = {
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
{ 0, },
};
diff -urN linux-2.4.32/drivers/ide/setup-pci.c linux-2.4.33/drivers/ide/setup-pci.c
--- linux-2.4.32/drivers/ide/setup-pci.c 2003-08-25 11:44:41.000000000 +0000
+++ linux-2.4.33/drivers/ide/setup-pci.c 2006-08-11 04:18:20.931192727 +0000
@@ -507,6 +507,7 @@
} else {
printk(KERN_INFO "%s: %s Bus-Master DMA disabled "
"(BIOS)\n", hwif->name, d->name);
+ ide_setup_no_dma(hwif);
}
}
}
diff -urN linux-2.4.32/drivers/input/Config.in linux-2.4.33/drivers/input/Config.in
--- linux-2.4.32/drivers/input/Config.in 2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.33/drivers/input/Config.in 2006-08-11 04:18:20.931192727 +0000
@@ -7,6 +7,11 @@
tristate 'Input core support' CONFIG_INPUT
dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
+
+if [ "$CONFIG_INPUT_KEYBDEV" = "n" ]; then
+ bool ' Use dummy keyboard driver' CONFIG_DUMMY_KEYB $CONFIG_INPUT
+fi
+
dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
diff -urN linux-2.4.32/drivers/mtd/chips/amd_flash.c linux-2.4.33/drivers/mtd/chips/amd_flash.c
--- linux-2.4.32/drivers/mtd/chips/amd_flash.c 2003-06-13 14:51:34.000000000 +0000
+++ linux-2.4.33/drivers/mtd/chips/amd_flash.c 2006-08-11 04:18:20.931192727 +0000
@@ -1350,6 +1350,7 @@
default:
/* Not an idle state */
+ set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
spin_unlock_bh(chip->mutex);
diff -urN linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0001.c linux-2.4.33/drivers/mtd/chips/cfi_cmdset_0001.c
--- linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0001.c 2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.33/drivers/mtd/chips/cfi_cmdset_0001.c 2006-08-11 04:18:20.931192727 +0000
@@ -1687,6 +1687,7 @@
default:
/* Not an idle state */
+ set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
spin_unlock(chip->mutex);
diff -urN linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0002.c linux-2.4.33/drivers/mtd/chips/cfi_cmdset_0002.c
--- linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0002.c 2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.33/drivers/mtd/chips/cfi_cmdset_0002.c 2006-08-11 04:18:20.931192727 +0000
@@ -1172,6 +1172,7 @@
default:
/* Not an idle state */
+ set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
cfi_spin_unlock(chip->mutex);
diff -urN linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0020.c linux-2.4.33/drivers/mtd/chips/cfi_cmdset_0020.c
--- linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0020.c 2004-11-17 11:54:21.000000000 +0000
+++ linux-2.4.33/drivers/mtd/chips/cfi_cmdset_0020.c 2006-08-11 04:18:20.931192727 +0000
@@ -1036,6 +1036,7 @@
default:
/* Not an idle state */
+ set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
spin_unlock_bh(chip->mutex);
diff -urN linux-2.4.32/drivers/net/3c59x.c linux-2.4.33/drivers/net/3c59x.c
--- linux-2.4.32/drivers/net/3c59x.c 2005-01-19 14:09:56.000000000 +0000
+++ linux-2.4.33/drivers/net/3c59x.c 2006-08-11 04:18:20.931192727 +0000
@@ -413,7 +413,7 @@
HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100,
INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800,
EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000, WNO_XCVR_PWR=0x4000,
- EXTRA_PREAMBLE=0x8000, };
+ EXTRA_PREAMBLE=0x8000, EEPROM_RESET=0x10000, };
enum vortex_chips {
CH_3C590 = 0,
@@ -489,9 +489,9 @@
{"3c595 Vortex 100base-MII",
PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
{"3c900 Boomerang 10baseT",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
{"3c900 Boomerang 10Mbps Combo",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
{"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
{"3c900 Cyclone 10Mbps Combo",
@@ -502,9 +502,9 @@
{"3c900B-FL Cyclone 10base-FL",
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
{"3c905 Boomerang 100baseTx",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
{"3c905 Boomerang 100baseT4",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
{"3c905B Cyclone 100baseTx",
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
@@ -3094,7 +3094,8 @@
pci_restore_state(VORTEX_PCI(vp), vp->power_state);
}
/* Should really use issue_and_wait() here */
- outw(TotalReset|0x14, dev->base_addr + EL3_CMD);
+ outw(TotalReset | ((vp->drv_flags & EEPROM_RESET) ? 0x04 : 0x14),
+ dev->base_addr + EL3_CMD);
pci_free_consistent(pdev,
sizeof(struct boom_rx_desc) * RX_RING_SIZE
diff -urN linux-2.4.32/drivers/net/au1000_eth.c linux-2.4.33/drivers/net/au1000_eth.c
--- linux-2.4.32/drivers/net/au1000_eth.c 2005-01-19 14:09:56.000000000 +0000
+++ linux-2.4.33/drivers/net/au1000_eth.c 2006-08-11 04:18:20.935193161 +0000
@@ -83,8 +83,6 @@
static int au1000_set_config(struct net_device *dev, struct ifmap *map);
static void set_rx_mode(struct net_device *);
static struct net_device_stats *au1000_get_stats(struct net_device *);
-static inline void update_tx_stats(struct net_device *, u32, u32);
-static inline void update_rx_stats(struct net_device *, u32);
static void au1000_timer(unsigned long);
static int au1000_ioctl(struct net_device *, struct ifreq *, int);
static int mdio_read(struct net_device *, int, int);
@@ -1540,16 +1538,11 @@
}
}
-
-static inline void
-update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len)
+static void update_tx_stats(struct net_device *dev, u32 status)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
struct net_device_stats *ps = &aup->stats;
- ps->tx_packets++;
- ps->tx_bytes += pkt_len;
-
if (status & TX_FRAME_ABORTED) {
if (dev->if_port == IF_PORT_100BASEFX) {
if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) {
@@ -1582,7 +1575,7 @@
ptxd = aup->tx_dma_ring[aup->tx_tail];
while (ptxd->buff_stat & TX_T_DONE) {
- update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
+ update_tx_stats(dev, ptxd->status);
ptxd->buff_stat &= ~TX_T_DONE;
ptxd->len = 0;
au_sync();
@@ -1604,6 +1597,7 @@
static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
+ struct net_device_stats *ps = &aup->stats;
volatile tx_dma_t *ptxd;
u32 buff_stat;
db_dest_t *pDB;
@@ -1623,7 +1617,7 @@
return 1;
}
else if (buff_stat & TX_T_DONE) {
- update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff);
+ update_tx_stats(dev, ptxd->status);
ptxd->len = 0;
}
@@ -1643,6 +1637,9 @@
else
ptxd->len = skb->len;
+ ps->tx_packets++;
+ ps->tx_bytes += ptxd->len;
+
ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE;
au_sync();
dev_kfree_skb(skb);
@@ -1651,7 +1648,6 @@
return 0;
}
-
static inline void update_rx_stats(struct net_device *dev, u32 status)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
diff -urN linux-2.4.32/drivers/net/b44.c linux-2.4.33/drivers/net/b44.c
--- linux-2.4.32/drivers/net/b44.c 2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.33/drivers/net/b44.c 2006-08-11 04:18:20.935193161 +0000
@@ -1183,8 +1183,9 @@
b44_chip_reset(bp);
b44_phy_reset(bp);
b44_setup_phy(bp);
- val = br32(B44_MAC_CTRL);
- bw32(B44_MAC_CTRL, val | MAC_CTRL_CRC32_ENAB);
+
+ /* Enable CRC32, set proper LED modes and power on PHY */
+ bw32(B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL);
bw32(B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT));
/* This sets the MAC address too. */
@@ -1319,12 +1320,15 @@
hwstat->rx_symbol_errs);
nstat->tx_aborted_errors = hwstat->tx_underruns;
+#if 0
+ /* Carrier lost counter seems to be broken for some devices */
nstat->tx_carrier_errors = hwstat->tx_carrier_lost;
+#endif
return nstat;
}
-static void __b44_load_mcast(struct b44 *bp, struct net_device *dev)
+static int __b44_load_mcast(struct b44 *bp, struct net_device *dev)
{
struct dev_mc_list *mclist;
int i, num_ents;
@@ -1334,12 +1338,15 @@
for (i = 0; mclist && i < num_ents; i++, mclist = mclist->next) {
__b44_cam_write(bp, mclist->dmi_addr, i + 1);
}
+ return i+1;
}
static void __b44_set_rx_mode(struct net_device *dev)
{
struct b44 *bp = dev->priv;
u32 val;
+ int i=0;
+ unsigned char zero[6] = {0,0,0,0,0,0};
val = br32(B44_RXCONFIG);
val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
@@ -1352,8 +1359,11 @@
if (dev->flags & IFF_ALLMULTI)
val |= RXCONFIG_ALLMULTI;
else
- __b44_load_mcast(bp, dev);
-
+ i=__b44_load_mcast(bp, dev);
+
+ for(;i<64;i++) {
+ __b44_cam_write(bp, zero, i);
+ }
bw32(B44_RXCONFIG, val);
val = br32(B44_CAM_CTRL);
bw32(B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
diff -urN linux-2.4.32/drivers/net/bonding/bond_alb.c linux-2.4.33/drivers/net/bonding/bond_alb.c
--- linux-2.4.32/drivers/net/bonding/bond_alb.c 2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.33/drivers/net/bonding/bond_alb.c 2006-08-11 04:18:20.935193161 +0000
@@ -37,6 +37,9 @@
*
* 2004/01/14 - Shmulik Hen <shmulik.hen at intel dot com>
* - Add capability to tag self generated packets in ALB/TLB modes.
+ *
+ * 2005/12/02 - Michael O'Donnell <Michael.ODonnell at stratus dot com>
+ * - Stratus88746: tlb_clear_slave() must tlb_init_slave() while locked.
*/
//#define BONDING_DEBUG 1
@@ -187,9 +190,9 @@
index = next_index;
}
- _unlock_tx_hashtbl(bond);
+ tlb_init_slave(slave); /* Stratus88746: do this before unlocking */
- tlb_init_slave(slave);
+ _unlock_tx_hashtbl(bond);
}
/* Must be called before starting the monitor timer */
@@ -1275,7 +1278,7 @@
int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
- struct ethhdr *eth_data = (struct ethhdr *)skb->mac.raw = skb->data;
+ struct ethhdr *eth_data = (struct ethhdr *)(skb->mac.raw = skb->data);
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct slave *tx_slave = NULL;
static u32 ip_bcast = 0xffffffff;
diff -urN linux-2.4.32/drivers/net/e1000/e1000_hw.c linux-2.4.33/drivers/net/e1000/e1000_hw.c
--- linux-2.4.32/drivers/net/e1000/e1000_hw.c 2005-04-04 01:42:19.000000000 +0000
+++ linux-2.4.33/drivers/net/e1000/e1000_hw.c 2006-08-11 04:18:20.935193161 +0000
@@ -5049,7 +5049,7 @@
if(ret_val)
return ret_val;
- msec_delay(20);
+ msec_delay_irq(20);
ret_val = e1000_write_phy_reg(hw, 0x0000,
IGP01E1000_IEEE_FORCE_GIGA);
@@ -5073,7 +5073,7 @@
if(ret_val)
return ret_val;
- msec_delay(20);
+ msec_delay_irq(20);
/* Now enable the transmitter */
ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
@@ -5098,7 +5098,7 @@
if(ret_val)
return ret_val;
- msec_delay(20);
+ msec_delay_irq(20);
ret_val = e1000_write_phy_reg(hw, 0x0000,
IGP01E1000_IEEE_FORCE_GIGA);
@@ -5114,7 +5114,7 @@
if(ret_val)
return ret_val;
- msec_delay(20);
+ msec_delay_irq(20);
/* Now enable the transmitter */
ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
diff -urN linux-2.4.32/drivers/net/e1000/e1000_main.c linux-2.4.33/drivers/net/e1000/e1000_main.c
--- linux-2.4.32/drivers/net/e1000/e1000_main.c 2005-04-04 01:42:19.000000000 +0000
+++ linux-2.4.33/drivers/net/e1000/e1000_main.c 2006-08-11 04:18:20.939193595 +0000
@@ -2755,7 +2755,7 @@
if (e1000_write_phy_reg(&adapter->hw, data->reg_num,
mii_reg))
return -EIO;
- if (adapter->hw.phy_type == e1000_phy_m88) {
+ if (adapter->hw.media_type == e1000_media_type_copper) {
switch (data->reg_num) {
case PHY_CTRL:
if(mii_reg & MII_CR_POWER_DOWN)
@@ -2771,8 +2771,8 @@
else
spddplx = SPEED_10;
spddplx += (mii_reg & 0x100)
- ? FULL_DUPLEX :
- HALF_DUPLEX;
+ ? DUPLEX_FULL :
+ DUPLEX_HALF;
retval = e1000_set_spd_dplx(adapter,
spddplx);
if(retval)
diff -urN linux-2.4.32/drivers/net/forcedeth.c linux-2.4.33/drivers/net/forcedeth.c
--- linux-2.4.32/drivers/net/forcedeth.c 2005-01-19 14:09:56.000000000 +0000
+++ linux-2.4.33/drivers/net/forcedeth.c 2006-08-11 04:18:20.939193595 +0000
@@ -10,7 +10,7 @@
* trademarks of NVIDIA Corporation in the United States and other
* countries.
*
- * Copyright (C) 2003,4 Manfred Spraul
+ * Copyright (C) 2003,4,5 Manfred Spraul
* Copyright (C) 2004 Andrew de Quincey (wol support)
* Copyright (C) 2004 Carl-Daniel Hailfinger (invalid MAC handling, insane
* IRQ rate fixes, bigendian fixes, cleanups, verification)
@@ -79,6 +79,30 @@
* 0.30: 25 Sep 2004: rx checksum support for nf 250 Gb. Add rx reset
* into nv_close, otherwise reenabling for wol can
* cause DMA to kfree'd memory.
+ * 0.31: 14 Nov 2004: ethtool support for getting/setting link
+ * capabilities.
+ * 0.32: 16 Apr 2005: RX_ERROR4 handling added.
+ * 0.33: 16 May 2005: Support for MCP51 added.
+ * 0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics.
+ * 0.35: 26 Jun 2005: Support for MCP55 added.
+ * 0.36: 28 Jun 2005: Add jumbo frame support.
+ * 0.37: 10 Jul 2005: Additional ethtool support, cleanup of pci id list
+ * 0.38: 16 Jul 2005: tx irq rewrite: Use global flags instead of
+ * per-packet flags.
+ * 0.39: 18 Jul 2005: Add 64bit descriptor support.
+ * 0.40: 19 Jul 2005: Add support for mac address change.
+ * 0.41: 30 Jul 2005: Write back original MAC in nv_close instead
+ * of nv_remove
+ * 0.42: 06 Aug 2005: Fix lack of link speed initialization
+ * in the second (and later) nv_open call
+ * 0.43: 10 Aug 2005: Add support for tx checksum.
+ * 0.44: 20 Aug 2005: Add support for scatter gather and segmentation.
+ * 0.45: 18 Sep 2005: Remove nv_stop/start_rx from every link check
+ * 0.46: 20 Oct 2005: Add irq optimization modes.
+ * 0.47: 26 Oct 2005: Add phyaddr 0 in phy scan.
+ * 0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single
+ * 0.49: 10 Dec 2005: Fix tso for large buffers.
+ * 0.50: 20 Jan 2006: Add 8021pq tagging support.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -90,7 +114,7 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
-#define FORCEDETH_VERSION "0.30"
+#define FORCEDETH_VERSION "0.50"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -108,6 +132,7 @@
#include <linux/mii.h>
#include <linux/random.h>
#include <linux/init.h>
+#include <linux/if_vlan.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -120,16 +145,22 @@
#define dprintk(x...) do { } while (0)
#endif
+/* not present in 2.4 */
+#ifndef NETDEV_TX_OK
+#define NETDEV_TX_OK 0
+#define NETDEV_TX_BUSY 1
+#endif
/*
* Hardware access:
*/
-#define DEV_NEED_LASTPACKET1 0x0001 /* set LASTPACKET1 in tx flags */
-#define DEV_IRQMASK_1 0x0002 /* use NVREG_IRQMASK_WANTED_1 for irq mask */
-#define DEV_IRQMASK_2 0x0004 /* use NVREG_IRQMASK_WANTED_2 for irq mask */
-#define DEV_NEED_TIMERIRQ 0x0008 /* set the timer irq flag in the irq mask */
-#define DEV_NEED_LINKTIMER 0x0010 /* poll link settings. Relies on the timer irq */
+#define DEV_NEED_TIMERIRQ 0x0001 /* set the timer irq flag in the irq mask */
+#define DEV_NEED_LINKTIMER 0x0002 /* poll link settings. Relies on the timer irq */
+#define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */
+#define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */
+#define DEV_HAS_CHECKSUM 0x0010 /* device supports tx and rx checksum offloads */
+#define DEV_HAS_VLAN 0x0020 /* device supports vlan tagging and striping */
enum {
NvRegIrqStatus = 0x000,
@@ -140,13 +171,17 @@
#define NVREG_IRQ_RX 0x0002
#define NVREG_IRQ_RX_NOBUF 0x0004
#define NVREG_IRQ_TX_ERR 0x0008
-#define NVREG_IRQ_TX2 0x0010
+#define NVREG_IRQ_TX_OK 0x0010
#define NVREG_IRQ_TIMER 0x0020
#define NVREG_IRQ_LINK 0x0040
+#define NVREG_IRQ_TX_ERROR 0x0080
#define NVREG_IRQ_TX1 0x0100
-#define NVREG_IRQMASK_WANTED_1 0x005f
-#define NVREG_IRQMASK_WANTED_2 0x0147
-#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1))
+#define NVREG_IRQMASK_THROUGHPUT 0x00df
+#define NVREG_IRQMASK_CPU 0x0040
+
+#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \
+ NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX_ERROR| \
+ NVREG_IRQ_TX1))
NvRegUnknownSetupReg6 = 0x008,
#define NVREG_UNKSETUP6_VAL 3
@@ -156,7 +191,8 @@
* NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
*/
NvRegPollingInterval = 0x00c,
-#define NVREG_POLL_DEFAULT 970
+#define NVREG_POLL_DEFAULT_THROUGHPUT 970
+#define NVREG_POLL_DEFAULT_CPU 13
NvRegMisc1 = 0x080,
#define NVREG_MISC1_HD 0x02
#define NVREG_MISC1_FORCE 0x3b0f3c
@@ -211,6 +247,7 @@
#define NVREG_LINKSPEED_10 1000
#define NVREG_LINKSPEED_100 100
#define NVREG_LINKSPEED_1000 50
+#define NVREG_LINKSPEED_MASK (0xFFF)
NvRegUnknownSetupReg5 = 0x130,
#define NVREG_UNKSETUP5_BIT31 (1<<31)
NvRegUnknownSetupReg3 = 0x13c,
@@ -222,6 +259,11 @@
#define NVREG_TXRXCTL_IDLE 0x0008
#define NVREG_TXRXCTL_RESET 0x0010
#define NVREG_TXRXCTL_RXCHECK 0x0400
+#define NVREG_TXRXCTL_DESC_1 0
+#define NVREG_TXRXCTL_DESC_2 0x02100
+#define NVREG_TXRXCTL_DESC_3 0x02200
+#define NVREG_TXRXCTL_VLANSTRIP 0x00040
+#define NVREG_TXRXCTL_VLANINS 0x00080
NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008
@@ -271,6 +313,8 @@
#define NVREG_POWERSTATE_D1 0x0001
#define NVREG_POWERSTATE_D2 0x0002
#define NVREG_POWERSTATE_D3 0x0003
+ NvRegVlanControl = 0x300,
+#define NVREG_VLANCONTROL_ENABLE 0x2000
};
/* Big endian: should work, but is untested */
@@ -279,6 +323,18 @@
u32 FlagLen;
};
+struct ring_desc_ex {
+ u32 PacketBufferHigh;
+ u32 PacketBufferLow;
+ u32 TxVlan;
+ u32 FlagLen;
+};
+
+typedef union _ring_type {
+ struct ring_desc* orig;
+ struct ring_desc_ex* ex;
+} ring_type;
+
#define FLAG_MASK_V1 0xffff0000
#define FLAG_MASK_V2 0xffffc000
#define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1)
@@ -286,7 +342,7 @@
#define NV_TX_LASTPACKET (1<<16)
#define NV_TX_RETRYERROR (1<<19)
-#define NV_TX_LASTPACKET1 (1<<24)
+#define NV_TX_FORCED_INTERRUPT (1<<24)
#define NV_TX_DEFERRED (1<<26)
#define NV_TX_CARRIERLOST (1<<27)
#define NV_TX_LATECOLLISION (1<<28)
@@ -296,7 +352,7 @@
#define NV_TX2_LASTPACKET (1<<29)
#define NV_TX2_RETRYERROR (1<<18)
-#define NV_TX2_LASTPACKET1 (1<<23)
+#define NV_TX2_FORCED_INTERRUPT (1<<30)
#define NV_TX2_DEFERRED (1<<25)
#define NV_TX2_CARRIERLOST (1<<26)
#define NV_TX2_LATECOLLISION (1<<27)
@@ -304,6 +360,14 @@
/* error and valid are the same for both */
#define NV_TX2_ERROR (1<<30)
#define NV_TX2_VALID (1<<31)
+#define NV_TX2_TSO (1<<28)
+#define NV_TX2_TSO_SHIFT 14
+#define NV_TX2_TSO_MAX_SHIFT 14
+#define NV_TX2_TSO_MAX_SIZE (1<<NV_TX2_TSO_MAX_SHIFT)
+#define NV_TX2_CHECKSUM_L3 (1<<27)
+#define NV_TX2_CHECKSUM_L4 (1<<26)
+
+#define NV_TX3_VLAN_TAG_PRESENT (1<<18)
#define NV_RX_DESCRIPTORVALID (1<<16)
#define NV_RX_MISSEDFRAME (1<<17)
@@ -335,6 +399,9 @@
#define NV_RX2_ERROR (1<<30)
#define NV_RX2_AVAIL (1<<31)
+#define NV_RX3_VLAN_TAG_PRESENT (1<<16)
+#define NV_RX3_VLAN_TAG_MASK (0x0000FFFF)
+
/* Miscelaneous hardware related defines: */
#define NV_PCI_REGSZ 0x270
@@ -361,34 +428,39 @@
#define NV_WATCHDOG_TIMEO (5*HZ)
#define RX_RING 128
-#define TX_RING 64
-/*
+#define TX_RING 256
+/*
* If your nic mysteriously hangs then try to reduce the limits
* to 1/0: It might be required to set NV_TX_LASTPACKET in the
* last valid ring entry. But this would be impossible to
* implement - probably a disassembly error.
*/
-#define TX_LIMIT_STOP 63
-#define TX_LIMIT_START 62
+#define TX_LIMIT_STOP 255
+#define TX_LIMIT_START 254
/* rx/tx mac addr + type + vlan + align + slack*/
-#define RX_NIC_BUFSIZE (ETH_DATA_LEN + 64)
-/* even more slack */
-#define RX_ALLOC_BUFSIZE (ETH_DATA_LEN + 128)
+#define NV_RX_HEADERS (64)
+/* even more slack. */
+#define NV_RX_ALLOC_PAD (64)
+
+/* maximum mtu size */
+#define NV_PKTLIMIT_1 ETH_DATA_LEN /* hard limit not known */
+#define NV_PKTLIMIT_2 9100 /* Actual limit according to NVidia: 9202 */
#define OOM_REFILL (1+HZ/20)
#define POLL_WAIT (1+HZ/100)
#define LINK_TIMEOUT (3*HZ)
-/*
+/*
* desc_ver values:
- * This field has two purposes:
- * - Newer nics uses a different ring layout. The layout is selected by
- * comparing np->desc_ver with DESC_VER_xy.
- * - It contains bits that are forced on when writing to NvRegTxRxControl.
+ * The nic supports three different descriptor types:
+ * - DESC_VER_1: Original
+ * - DESC_VER_2: support for jumbo frames.
+ * - DESC_VER_3: 64-bit format.
*/
-#define DESC_VER_1 0x0
-#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK)
+#define DESC_VER_1 1
+#define DESC_VER_2 2
+#define DESC_VER_3 3
/* PHY defines */
#define PHY_OUI_MARVELL 0x5043
@@ -442,6 +514,8 @@
int in_shutdown;
u32 linkspeed;
int duplex;
+ int autoneg;
+ int fixed_mode;
int phyaddr;
int wolenabled;
unsigned int phy_oui;
@@ -453,15 +527,20 @@
u32 orig_mac[2];
u32 irqmask;
u32 desc_ver;
+ u32 txrxctl_bits;
+ u32 vlanctl_bits;
+
+ void __iomem *base;
/* rx specific fields.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
*/
- struct ring_desc *rx_ring;
+ ring_type rx_ring;
unsigned int cur_rx, refill_rx;
struct sk_buff *rx_skbuff[RX_RING];
dma_addr_t rx_dma[RX_RING];
unsigned int rx_buf_sz;
+ unsigned int pkt_limit;
struct timer_list oom_kick;
struct timer_list nic_poll;
@@ -473,11 +552,15 @@
/*
* tx specific fields.
*/
- struct ring_desc *tx_ring;
+ ring_type tx_ring;
unsigned int next_tx, nic_tx;
struct sk_buff *tx_skbuff[TX_RING];
dma_addr_t tx_dma[TX_RING];
+ unsigned int tx_dma_len[TX_RING];
u32 tx_flags;
+
+ /* vlan fields */
+ struct vlan_group *vlangrp;
};
/*
@@ -486,17 +569,36 @@
*/
static int max_interrupt_work = 5;
+/*
+ * Optimization can be either throuput mode or cpu mode
+ *
+ * Throughput Mode: Every tx and rx packet will generate an interrupt.
+ * CPU Mode: Interrupts are controlled by a timer.
+ */
+#define NV_OPTIMIZATION_MODE_THROUGHPUT 0
+#define NV_OPTIMIZATION_MODE_CPU 1
+static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT;
+
+/*
+ * Poll interval for timer irq
+ *
+ * This interval determines how frequent an interrupt is generated.
+ * The is value is determined by [(time_in_micro_secs * 100) / (2^10)]
+ * Min = 0, and Max = 65535
+ */
+static int poll_interval = -1;
+
static inline struct fe_priv *get_nvpriv(struct net_device *dev)
{
- return (struct fe_priv *) dev->priv;
+ return netdev_priv(dev);
}
-static inline u8 *get_hwbase(struct net_device *dev)
+static inline u8 __iomem *get_hwbase(struct net_device *dev)
{
- return (u8 *) dev->base_addr;
+ return ((struct fe_priv *)netdev_priv(dev))->base;
}
-static inline void pci_push(u8 * base)
+static inline void pci_push(u8 __iomem *base)
{
/* force out pending posted writes */
readl(base);
@@ -508,10 +610,15 @@
& ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
}
+static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v)
+{
+ return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2;
+}
+
static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
int delay, int delaymax, const char *msg)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
pci_push(base);
do {
@@ -533,7 +640,7 @@
*/
static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
u32 reg;
int retval;
@@ -577,7 +684,7 @@
static int phy_reset(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u32 miicontrol;
unsigned int tries = 0;
@@ -604,7 +711,7 @@
static int phy_init(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg;
/* set advertise register */
@@ -680,8 +787,8 @@
static void nv_start_rx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name);
/* Already running? Stop it. */
@@ -699,7 +806,7 @@
static void nv_stop_rx(struct net_device *dev)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name);
writel(0, base + NvRegReceiverControl);
@@ -713,7 +820,7 @@
static void nv_start_tx(struct net_device *dev)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name);
writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl);
@@ -722,7 +829,7 @@
static void nv_stop_tx(struct net_device *dev)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name);
writel(0, base + NvRegTransmitterControl);
@@ -736,14 +843,14 @@
static void nv_txrx_reset(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name);
- writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl);
pci_push(base);
udelay(NV_TXRX_RESET_DELAY);
- writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl);
pci_push(base);
}
@@ -755,7 +862,7 @@
*/
static struct net_device_stats *nv_get_stats(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
/* It seems that the nic always generates interrupts and doesn't
* accumulate errors internally. Thus the current values in np->stats
@@ -764,50 +871,6 @@
return &np->stats;
}
-static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
- struct fe_priv *np = get_nvpriv(dev);
- strcpy(info->driver, "forcedeth");
- strcpy(info->version, FORCEDETH_VERSION);
- strcpy(info->bus_info, pci_name(np->pci_dev));
-}
-
-static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
-{
- struct fe_priv *np = get_nvpriv(dev);
- wolinfo->supported = WAKE_MAGIC;
-
- spin_lock_irq(&np->lock);
- if (np->wolenabled)
- wolinfo->wolopts = WAKE_MAGIC;
- spin_unlock_irq(&np->lock);
-}
-
-static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
-{
- struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
-
- spin_lock_irq(&np->lock);
- if (wolinfo->wolopts == 0) {
- writel(0, base + NvRegWakeUpFlags);
- np->wolenabled = 0;
- }
- if (wolinfo->wolopts & WAKE_MAGIC) {
- writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags);
- np->wolenabled = 1;
- }
- spin_unlock_irq(&np->lock);
- return 0;
-}
-
-static struct ethtool_ops ops = {
- .get_drvinfo = nv_get_drvinfo,
- .get_link = ethtool_op_get_link,
- .get_wol = nv_get_wol,
- .set_wol = nv_set_wol,
-};
-
/*
* nv_alloc_rx: fill rx ring entries.
* Return 1 if the allocations for the skbs failed and the
@@ -815,7 +878,7 @@
*/
static int nv_alloc_rx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
unsigned int refill_rx = np->refill_rx;
int nr;
@@ -825,7 +888,7 @@
nr = refill_rx % RX_RING;
if (np->rx_skbuff[nr] == NULL) {
- skb = dev_alloc_skb(RX_ALLOC_BUFSIZE);
+ skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
if (!skb)
break;
@@ -834,11 +897,18 @@
} else {
skb = np->rx_skbuff[nr];
}
- np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len,
- PCI_DMA_FROMDEVICE);
- np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
- wmb();
- np->rx_ring[nr].FlagLen = cpu_to_le32(RX_NIC_BUFSIZE | NV_RX_AVAIL);
+ np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data,
+ skb->end-skb->data, PCI_DMA_FROMDEVICE);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
+ wmb();
+ np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+ } else {
+ np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
+ np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
+ wmb();
+ np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+ }
dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
dev->name, refill_rx);
refill_rx++;
@@ -852,7 +922,7 @@
static void nv_do_rx_refill(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
disable_irq(dev->irq);
if (nv_alloc_rx(dev)) {
@@ -864,49 +934,94 @@
enable_irq(dev->irq);
}
-static int nv_init_ring(struct net_device *dev)
+static void nv_init_rx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
int i;
- np->next_tx = np->nic_tx = 0;
- for (i = 0; i < TX_RING; i++)
- np->tx_ring[i].FlagLen = 0;
-
np->cur_rx = RX_RING;
np->refill_rx = 0;
for (i = 0; i < RX_RING; i++)
- np->rx_ring[i].FlagLen = 0;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ np->rx_ring.orig[i].FlagLen = 0;
+ else
+ np->rx_ring.ex[i].FlagLen = 0;
+}
+
+static void nv_init_tx(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ int i;
+
+ np->next_tx = np->nic_tx = 0;
+ for (i = 0; i < TX_RING; i++) {
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ np->tx_ring.orig[i].FlagLen = 0;
+ else
+ np->tx_ring.ex[i].FlagLen = 0;
+ np->tx_skbuff[i] = NULL;
+ np->tx_dma[i] = 0;
+ }
+}
+
+static int nv_init_ring(struct net_device *dev)
+{
+ nv_init_tx(dev);
+ nv_init_rx(dev);
return nv_alloc_rx(dev);
}
+static int nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+{
+ struct fe_priv *np = netdev_priv(dev);
+
+ dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n",
+ dev->name, skbnr);
+
+ if (np->tx_dma[skbnr]) {
+ pci_unmap_page(np->pci_dev, np->tx_dma[skbnr],
+ np->tx_dma_len[skbnr],
+ PCI_DMA_TODEVICE);
+ np->tx_dma[skbnr] = 0;
+ }
+
+ if (np->tx_skbuff[skbnr]) {
+ dev_kfree_skb_irq(np->tx_skbuff[skbnr]);
+ np->tx_skbuff[skbnr] = NULL;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
static void nv_drain_tx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
- int i;
+ struct fe_priv *np = netdev_priv(dev);
+ unsigned int i;
+
for (i = 0; i < TX_RING; i++) {
- np->tx_ring[i].FlagLen = 0;
- if (np->tx_skbuff[i]) {
- pci_unmap_single(np->pci_dev, np->tx_dma[i],
- np->tx_skbuff[i]->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb(np->tx_skbuff[i]);
- np->tx_skbuff[i] = NULL;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ np->tx_ring.orig[i].FlagLen = 0;
+ else
+ np->tx_ring.ex[i].FlagLen = 0;
+ if (nv_release_txskb(dev, i))
np->stats.tx_dropped++;
- }
}
}
static void nv_drain_rx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
int i;
for (i = 0; i < RX_RING; i++) {
- np->rx_ring[i].FlagLen = 0;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ np->rx_ring.orig[i].FlagLen = 0;
+ else
+ np->rx_ring.ex[i].FlagLen = 0;
wmb();
if (np->rx_skbuff[i]) {
pci_unmap_single(np->pci_dev, np->rx_dma[i],
- np->rx_skbuff[i]->len,
+ np->rx_skbuff[i]->end-np->rx_skbuff[i]->data,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(np->rx_skbuff[i]);
np->rx_skbuff[i] = NULL;
@@ -926,20 +1041,113 @@
*/
static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
- int nr = np->next_tx % TX_RING;
+ struct fe_priv *np = netdev_priv(dev);
+ u32 tx_flags = 0;
+ u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
+ unsigned int fragments = skb_shinfo(skb)->nr_frags;
+ unsigned int nr = (np->next_tx - 1) % TX_RING;
+ unsigned int start_nr = np->next_tx % TX_RING;
+ unsigned int i;
+ u32 offset = 0;
+ u32 bcnt;
+ u32 size = skb->len-skb->data_len;
+ u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+ u32 tx_flags_vlan = 0;
+
+ /* add fragments to entries count */
+ for (i = 0; i < fragments; i++) {
+ entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) +
+ ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+ }
+
+ spin_lock_irq(&np->lock);
+
+ if ((np->next_tx - np->nic_tx + entries - 1) > TX_LIMIT_STOP) {
+ spin_unlock_irq(&np->lock);
+ netif_stop_queue(dev);
+ return NETDEV_TX_BUSY;
+ }
+
+ /* setup the header buffer */
+ do {
+ bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+ nr = (nr + 1) % TX_RING;
+
+ np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->tx_dma_len[nr] = bcnt;
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+ np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ } else {
+ np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+ np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+ np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ }
+ tx_flags = np->tx_flags;
+ offset += bcnt;
+ size -= bcnt;
+ } while(size);
+
+ /* setup the fragments */
+ for (i = 0; i < fragments; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ u32 size = frag->size;
+ offset = 0;
+
+ do {
+ bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+ nr = (nr + 1) % TX_RING;
+
+ np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->tx_dma_len[nr] = bcnt;
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+ np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ } else {
+ np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+ np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+ np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ }
+ offset += bcnt;
+ size -= bcnt;
+ } while (size);
+ }
+
+ /* set last fragment flag */
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+ } else {
+ np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+ }
np->tx_skbuff[nr] = skb;
- np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len,
- PCI_DMA_TODEVICE);
- np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+#ifdef NETIF_F_TSO
+ if (skb_shinfo(skb)->tso_size)
+ tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
+ else
+#endif
+ tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
- spin_lock_irq(&np->lock);
- wmb();
- np->tx_ring[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
- dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n",
- dev->name, np->next_tx);
+ /* vlan tag */
+ if (np->vlangrp && vlan_tx_tag_present(skb)) {
+ tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb);
+ }
+
+ /* set tx flags */
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ } else {
+ np->tx_ring.ex[start_nr].TxVlan = cpu_to_le32(tx_flags_vlan);
+ np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ }
+
+ dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
+ dev->name, np->next_tx, entries, tx_flags_extra);
{
int j;
for (j=0; j<64; j++) {
@@ -950,15 +1158,13 @@
dprintk("\n");
}
- np->next_tx++;
+ np->next_tx += entries;
dev->trans_start = jiffies;
- if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP)
- netif_stop_queue(dev);
spin_unlock_irq(&np->lock);
- writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
pci_push(get_hwbase(dev));
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -968,49 +1174,55 @@
*/
static void nv_tx_done(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u32 Flags;
- int i;
+ unsigned int i;
+ struct sk_buff *skb;
while (np->nic_tx != np->next_tx) {
i = np->nic_tx % TX_RING;
- Flags = le32_to_cpu(np->tx_ring[i].FlagLen);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen);
+ else
+ Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen);
dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
dev->name, np->nic_tx, Flags);
if (Flags & NV_TX_VALID)
break;
if (np->desc_ver == DESC_VER_1) {
- if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
- NV_TX_UNDERFLOW|NV_TX_ERROR)) {
- if (Flags & NV_TX_UNDERFLOW)
- np->stats.tx_fifo_errors++;
- if (Flags & NV_TX_CARRIERLOST)
- np->stats.tx_carrier_errors++;
- np->stats.tx_errors++;
- } else {
- np->stats.tx_packets++;
- np->stats.tx_bytes += np->tx_skbuff[i]->len;
+ if (Flags & NV_TX_LASTPACKET) {
+ skb = np->tx_skbuff[i];
+ if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
+ NV_TX_UNDERFLOW|NV_TX_ERROR)) {
+ if (Flags & NV_TX_UNDERFLOW)
+ np->stats.tx_fifo_errors++;
+ if (Flags & NV_TX_CARRIERLOST)
+ np->stats.tx_carrier_errors++;
+ np->stats.tx_errors++;
+ } else {
+ np->stats.tx_packets++;
+ np->stats.tx_bytes += skb->len;
+ }
}
} else {
- if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
- NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
- if (Flags & NV_TX2_UNDERFLOW)
- np->stats.tx_fifo_errors++;
- if (Flags & NV_TX2_CARRIERLOST)
- np->stats.tx_carrier_errors++;
- np->stats.tx_errors++;
- } else {
- np->stats.tx_packets++;
- np->stats.tx_bytes += np->tx_skbuff[i]->len;
+ if (Flags & NV_TX2_LASTPACKET) {
+ skb = np->tx_skbuff[i];
+ if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
+ NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
+ if (Flags & NV_TX2_UNDERFLOW)
+ np->stats.tx_fifo_errors++;
+ if (Flags & NV_TX2_CARRIERLOST)
+ np->stats.tx_carrier_errors++;
+ np->stats.tx_errors++;
+ } else {
+ np->stats.tx_packets++;
+ np->stats.tx_bytes += skb->len;
+ }
}
}
- pci_unmap_single(np->pci_dev, np->tx_dma[i],
- np->tx_skbuff[i]->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(np->tx_skbuff[i]);
- np->tx_skbuff[i] = NULL;
+ nv_release_txskb(dev, i);
np->nic_tx++;
}
if (np->next_tx - np->nic_tx < TX_LIMIT_START)
@@ -1023,12 +1235,59 @@
*/
static void nv_tx_timeout(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
- dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name,
+ printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name,
readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK);
+ {
+ int i;
+
+ printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n",
+ dev->name, (unsigned long)np->ring_addr,
+ np->next_tx, np->nic_tx);
+ printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
+ for (i=0;i<0x400;i+= 32) {
+ printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ i,
+ readl(base + i + 0), readl(base + i + 4),
+ readl(base + i + 8), readl(base + i + 12),
+ readl(base + i + 16), readl(base + i + 20),
+ readl(base + i + 24), readl(base + i + 28));
+ }
+ printk(KERN_INFO "%s: Dumping tx ring\n", dev->name);
+ for (i=0;i<TX_RING;i+= 4) {
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
+ i,
+ le32_to_cpu(np->tx_ring.orig[i].PacketBuffer),
+ le32_to_cpu(np->tx_ring.orig[i].FlagLen),
+ le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer),
+ le32_to_cpu(np->tx_ring.orig[i+1].FlagLen),
+ le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer),
+ le32_to_cpu(np->tx_ring.orig[i+2].FlagLen),
+ le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer),
+ le32_to_cpu(np->tx_ring.orig[i+3].FlagLen));
+ } else {
+ printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
+ i,
+ le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh),
+ le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow),
+ le32_to_cpu(np->tx_ring.ex[i].FlagLen),
+ le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh),
+ le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow),
+ le32_to_cpu(np->tx_ring.ex[i+1].FlagLen),
+ le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh),
+ le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow),
+ le32_to_cpu(np->tx_ring.ex[i+2].FlagLen),
+ le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh),
+ le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow),
+ le32_to_cpu(np->tx_ring.ex[i+3].FlagLen));
+ }
+ }
+ }
+
spin_lock_irq(&np->lock);
/* 1) stop tx engine */
@@ -1042,7 +1301,10 @@
printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
nv_drain_tx(dev);
np->next_tx = np->nic_tx = 0;
- writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+ else
+ writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
netif_wake_queue(dev);
}
@@ -1051,10 +1313,65 @@
spin_unlock_irq(&np->lock);
}
+/*
+ * Called when the nic notices a mismatch between the actual data len on the
+ * wire and the len indicated in the 802 header
+ */
+static int nv_getlen(struct net_device *dev, void *packet, int datalen)
+{
+ int hdrlen; /* length of the 802 header */
+ int protolen; /* length as stored in the proto field */
+
+ /* 1) calculate len according to header */
+ if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) {
+ protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto );
+ hdrlen = VLAN_HLEN;
+ } else {
+ protolen = ntohs( ((struct ethhdr *)packet)->h_proto);
+ hdrlen = ETH_HLEN;
+ }
+ dprintk(KERN_DEBUG "%s: nv_getlen: datalen %d, protolen %d, hdrlen %d\n",
+ dev->name, datalen, protolen, hdrlen);
+ if (protolen > ETH_DATA_LEN)
+ return datalen; /* Value in proto field not a len, no checks possible */
+
+ protolen += hdrlen;
+ /* consistency checks: */
+ if (datalen > ETH_ZLEN) {
+ if (datalen >= protolen) {
+ /* more data on wire than in 802 header, trim of
+ * additional data.
+ */
+ dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
+ dev->name, protolen);
+ return protolen;
+ } else {
+ /* less data on wire than mentioned in header.
+ * Discard the packet.
+ */
+ dprintk(KERN_DEBUG "%s: nv_getlen: discarding long packet.\n",
+ dev->name);
+ return -1;
+ }
+ } else {
+ /* short packet. Accept only if 802 values are also short */
+ if (protolen > ETH_ZLEN) {
+ dprintk(KERN_DEBUG "%s: nv_getlen: discarding short packet.\n",
+ dev->name);
+ return -1;
+ }
+ dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
+ dev->name, datalen);
+ return datalen;
+ }
+}
+
static void nv_rx_process(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u32 Flags;
+ u32 vlanflags = 0;
+
for (;;) {
struct sk_buff *skb;
@@ -1064,8 +1381,14 @@
break; /* we scanned the whole ring - do not continue */
i = np->cur_rx % RX_RING;
- Flags = le32_to_cpu(np->rx_ring[i].FlagLen);
- len = nv_descr_getlength(&np->rx_ring[i], np->desc_ver);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen);
+ len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
+ } else {
+ Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen);
+ len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
+ vlanflags = le32_to_cpu(np->rx_ring.ex[i].PacketBufferLow);
+ }
dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n",
dev->name, np->cur_rx, Flags);
@@ -1079,7 +1402,7 @@
* the performance.
*/
pci_unmap_single(np->pci_dev, np->rx_dma[i],
- np->rx_skbuff[i]->len,
+ np->rx_skbuff[i]->end-np->rx_skbuff[i]->data,
PCI_DMA_FROMDEVICE);
{
@@ -1097,63 +1420,71 @@
if (!(Flags & NV_RX_DESCRIPTORVALID))
goto next_pkt;
- if (Flags & NV_RX_MISSEDFRAME) {
- np->stats.rx_missed_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) {
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (Flags & NV_RX_CRCERR) {
- np->stats.rx_crc_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (Flags & NV_RX_OVERFLOW) {
- np->stats.rx_over_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
if (Flags & NV_RX_ERROR) {
- /* framing errors are soft errors, the rest is fatal. */
+ if (Flags & NV_RX_MISSEDFRAME) {
+ np->stats.rx_missed_errors++;
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+ if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+ if (Flags & NV_RX_CRCERR) {
+ np->stats.rx_crc_errors++;
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+ if (Flags & NV_RX_OVERFLOW) {
+ np->stats.rx_over_errors++;
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+ if (Flags & NV_RX_ERROR4) {
+ len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
+ if (len < 0) {
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+ }
+ /* framing errors are soft errors. */
if (Flags & NV_RX_FRAMINGERR) {
if (Flags & NV_RX_SUBSTRACT1) {
len--;
}
- } else {
- np->stats.rx_errors++;
- goto next_pkt;
}
}
} else {
if (!(Flags & NV_RX2_DESCRIPTORVALID))
goto next_pkt;
- if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3|NV_RX2_ERROR4)) {
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (Flags & NV_RX2_CRCERR) {
- np->stats.rx_crc_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (Flags & NV_RX2_OVERFLOW) {
- np->stats.rx_over_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
if (Flags & NV_RX2_ERROR) {
- /* framing errors are soft errors, the rest is fatal. */
+ if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+ if (Flags & NV_RX2_CRCERR) {
+ np->stats.rx_crc_errors++;
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+ if (Flags & NV_RX2_OVERFLOW) {
+ np->stats.rx_over_errors++;
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+ if (Flags & NV_RX2_ERROR4) {
+ len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
+ if (len < 0) {
+ np->stats.rx_errors++;
+ goto next_pkt;
+ }
+ }
+ /* framing errors are soft errors */
if (Flags & NV_RX2_FRAMINGERR) {
if (Flags & NV_RX2_SUBSTRACT1) {
len--;
}
- } else {
- np->stats.rx_errors++;
- goto next_pkt;
}
}
Flags &= NV_RX2_CHECKSUMMASK;
@@ -1174,7 +1505,11 @@
skb->protocol = eth_type_trans(skb, dev);
dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
dev->name, np->cur_rx, len, skb->protocol);
- netif_rx(skb);
+ if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) {
+ vlan_hwaccel_rx(skb, np->vlangrp, vlanflags & NV_RX3_VLAN_TAG_MASK);
+ } else {
+ netif_rx(skb);
+ }
dev->last_rx = jiffies;
np->stats.rx_packets++;
np->stats.rx_bytes += len;
@@ -1183,15 +1518,133 @@
}
}
+static void set_bufsize(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+
+ if (dev->mtu <= ETH_DATA_LEN)
+ np->rx_buf_sz = ETH_DATA_LEN + NV_RX_HEADERS;
+ else
+ np->rx_buf_sz = dev->mtu + NV_RX_HEADERS;
+}
+
/*
* nv_change_mtu: dev->change_mtu function
* Called with dev_base_lock held for read.
*/
static int nv_change_mtu(struct net_device *dev, int new_mtu)
{
- if (new_mtu > ETH_DATA_LEN)
+ struct fe_priv *np = netdev_priv(dev);
+ int old_mtu;
+
+ if (new_mtu < 64 || new_mtu > np->pkt_limit)
return -EINVAL;
+
+ old_mtu = dev->mtu;
dev->mtu = new_mtu;
+
+ /* return early if the buffer sizes will not change */
+ if (old_mtu <= ETH_DATA_LEN && new_mtu <= ETH_DATA_LEN)
+ return 0;
+ if (old_mtu == new_mtu)
+ return 0;
+
+ /* synchronized against open : rtnl_lock() held by caller */
+ if (netif_running(dev)) {
+ u8 __iomem *base = get_hwbase(dev);
+ /*
+ * It seems that the nic preloads valid ring entries into an
+ * internal buffer. The procedure for flushing everything is
+ * guessed, there is probably a simpler approach.
+ * Changing the MTU is a rare event, it shouldn't matter.
+ */
+ disable_irq(dev->irq);
+ spin_lock_bh(&dev->xmit_lock);
+ spin_lock(&np->lock);
+ /* stop engines */
+ nv_stop_rx(dev);
+ nv_stop_tx(dev);
+ nv_txrx_reset(dev);
+ /* drain rx queue */
+ nv_drain_rx(dev);
+ nv_drain_tx(dev);
+ /* reinit driver view of the rx queue */
+ nv_init_rx(dev);
+ nv_init_tx(dev);
+ /* alloc new rx buffers */
+ set_bufsize(dev);
+ if (nv_alloc_rx(dev)) {
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ }
+ /* reinit nic view of the rx queue */
+ writel(np->rx_buf_sz, base + NvRegOffloadConfig);
+ writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+ else
+ writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
+ writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
+ base + NvRegRingSizes);
+ pci_push(base);
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+ pci_push(base);
+
+ /* restart rx engine */
+ nv_start_rx(dev);
+ nv_start_tx(dev);
+ spin_unlock(&np->lock);
+ spin_unlock_bh(&dev->xmit_lock);
+ enable_irq(dev->irq);
+ }
+ return 0;
+}
+
+static void nv_copy_mac_to_hw(struct net_device *dev)
+{
+ u8 __iomem *base = get_hwbase(dev);
+ u32 mac[2];
+
+ mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
+ (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
+ mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
+
+ writel(mac[0], base + NvRegMacAddrA);
+ writel(mac[1], base + NvRegMacAddrB);
+}
+
+/*
+ * nv_set_mac_address: dev->set_mac_address function
+ * Called with rtnl_lock() held.
+ */
+static int nv_set_mac_address(struct net_device *dev, void *addr)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ struct sockaddr *macaddr = (struct sockaddr*)addr;
+
+ if(!is_valid_ether_addr(macaddr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ /* synchronized against open : rtnl_lock() held by caller */
+ memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
+
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ spin_lock_irq(&np->lock);
+
+ /* stop rx engine */
+ nv_stop_rx(dev);
+
+ /* set mac address */
+ nv_copy_mac_to_hw(dev);
+
+ /* restart rx engine */
+ nv_start_rx(dev);
+ spin_unlock_irq(&np->lock);
+ spin_unlock_bh(&dev->xmit_lock);
+ } else {
+ nv_copy_mac_to_hw(dev);
+ }
return 0;
}
@@ -1201,8 +1654,8 @@
*/
static void nv_set_multicast(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
u32 addr[2];
u32 mask[2];
u32 pff;
@@ -1259,10 +1712,21 @@
spin_unlock_irq(&np->lock);
}
+/**
+ * nv_update_linkspeed: Setup the MAC according to the link partner
+ * @dev: Network device to be configured
+ *
+ * The function queries the PHY and checks if there is a link partner.
+ * If yes, then it sets up the MAC accordingly. Otherwise, the MAC is
+ * set to 10 MBit HD.
+ *
+ * The function returns 0 if there is no link partner and 1 if there is
+ * a good link partner.
+ */
static int nv_update_linkspeed(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
int adv, lpa;
int newls = np->linkspeed;
int newdup = np->duplex;
@@ -1285,6 +1749,25 @@
goto set_speed;
}
+ if (np->autoneg == 0) {
+ dprintk(KERN_DEBUG "%s: nv_update_linkspeed: autoneg off, PHY set to 0x%04x.\n",
+ dev->name, np->fixed_mode);
+ if (np->fixed_mode & LPA_100FULL) {
+ newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100;
+ newdup = 1;
+ } else if (np->fixed_mode & LPA_100HALF) {
+ newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100;
+ newdup = 0;
+ } else if (np->fixed_mode & LPA_10FULL) {
+ newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
+ newdup = 1;
+ } else {
+ newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
+ newdup = 0;
+ }
+ retval = 1;
+ goto set_speed;
+ }
/* check auto negotiation is complete */
if (!(mii_status & BMSR_ANEGCOMPLETE)) {
/* still in autonegotiation - configure nic for 10 MBit HD and wait. */
@@ -1302,7 +1785,7 @@
if ((control_1000 & ADVERTISE_1000FULL) &&
(status_1000 & LPA_1000FULL)) {
- dprintk(KERN_DEBUG "%s: nv_update_linkspeed: GBit ethernet detected.\n",
+ dprintk(KERN_DEBUG "%s: nv_update_linkspeed: GBit ethernet detected.\n",
dev->name);
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_1000;
newdup = 1;
@@ -1361,9 +1844,9 @@
phyreg &= ~(PHY_HALF|PHY_100|PHY_1000);
if (np->duplex == 0)
phyreg |= PHY_HALF;
- if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
+ if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_100)
phyreg |= PHY_100;
- else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
+ else if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_1000)
phyreg |= PHY_1000;
writel(phyreg, base + NvRegPhyInterface);
@@ -1379,13 +1862,11 @@
static void nv_linkchange(struct net_device *dev)
{
if (nv_update_linkspeed(dev)) {
- if (netif_carrier_ok(dev)) {
- nv_stop_rx(dev);
- } else {
+ if (!netif_carrier_ok(dev)) {
netif_carrier_on(dev);
printk(KERN_INFO "%s: link up.\n", dev->name);
+ nv_start_rx(dev);
}
- nv_start_rx(dev);
} else {
if (netif_carrier_ok(dev)) {
netif_carrier_off(dev);
@@ -1397,7 +1878,7 @@
static void nv_link_irq(struct net_device *dev)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
u32 miistat;
miistat = readl(base + NvRegMIIStatus);
@@ -1412,8 +1893,8 @@
static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) data;
- struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
u32 events;
int i;
@@ -1427,22 +1908,18 @@
if (!(events & np->irqmask))
break;
- if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) {
+ spin_lock(&np->lock);
+ nv_tx_done(dev);
+ spin_unlock(&np->lock);
+
+ nv_rx_process(dev);
+ if (nv_alloc_rx(dev)) {
spin_lock(&np->lock);
- nv_tx_done(dev);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
spin_unlock(&np->lock);
}
-
- if (events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) {
- nv_rx_process(dev);
- if (nv_alloc_rx(dev)) {
- spin_lock(&np->lock);
- if (!np->in_shutdown)
- mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
- spin_unlock(&np->lock);
- }
- }
-
+
if (events & NVREG_IRQ_LINK) {
spin_lock(&np->lock);
nv_link_irq(dev);
@@ -1484,8 +1961,8 @@
static void nv_do_nic_poll(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
- struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
disable_irq(dev->irq);
/* FIXME: Do we need synchronize_irq(dev->irq) here? */
@@ -1499,10 +1976,313 @@
enable_irq(dev->irq);
}
-static int nv_open(struct net_device *dev)
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void nv_poll_controller(struct net_device *dev)
+{
+ nv_do_nic_poll((unsigned long) dev);
+}
+#endif
+
+static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ strcpy(info->driver, "forcedeth");
+ strcpy(info->version, FORCEDETH_VERSION);