From nobody@FreeBSD.org  Wed Mar 24 05:22:03 2004
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 7F8C316A4CE
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 24 Mar 2004 05:22:03 -0800 (PST)
Received: from www.freebsd.org (www.freebsd.org [216.136.204.117])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 74F2643D49
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 24 Mar 2004 05:22:03 -0800 (PST)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.12.10/8.12.10) with ESMTP id i2ODM372054003
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 24 Mar 2004 05:22:03 -0800 (PST)
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.12.10/8.12.10/Submit) id i2ODM3uv054002;
	Wed, 24 Mar 2004 05:22:03 -0800 (PST)
	(envelope-from nobody)
Message-Id: <200403241322.i2ODM3uv054002@www.freebsd.org>
Date: Wed, 24 Mar 2004 05:22:03 -0800 (PST)
From: Jianqin Qu <jqu@its.brooklyn.cuny.edu>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Bugs with Ethernet driver "bfe"
X-Send-Pr-Version: www-2.3

>Number:         64656
>Category:       i386
>Synopsis:       Bugs with Ethernet driver "bfe"
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-i386
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Mar 24 05:30:21 PST 2004
>Closed-Date:    Sun May 23 01:42:18 PDT 2004
>Last-Modified:  Sun May 23 01:42:18 PDT 2004
>Originator:     Jianqin Qu
>Release:        5.2.1
>Organization:
>Environment:
FreeBSD faculty51 5.2.1-RELEASE FreeBSD 5.2.1-RELEASE #0: Mon Feb 23 20:45:55 GMT 2004     root@wv1u.btc.adaptec.com:/usr/obj/usr/src/sys/GENERIC  i386

>Description:
Below is the ouput from "dmesg", whose bottom lines state the bug in bfe drivers in a very clear way by itself.


Copyright (c) 1992-2004 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
	The Regents of the University of California. All rights reserved.
FreeBSD 5.2.1-RELEASE #0: Mon Feb 23 20:45:55 GMT 2004
    root@wv1u.btc.adaptec.com:/usr/obj/usr/src/sys/GENERIC
Preloaded elf kernel "/boot/kernel/kernel" at 0xc0a35000.
Preloaded elf module "/boot/kernel/acpi.ko" at 0xc0a35244.
ACPI APIC Table: <DELL   160L   >
Timecounter "i8254" frequency 1193182 Hz quality 0
CPU: Intel(R) Pentium(R) 4 CPU 2.40GHz (2392.29-MHz 686-class CPU)
  Origin = "GenuineIntel"  Id = 0xf27  Stepping = 7
  Features=0xbfebfbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CLFLUSH,DTS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE>
real memory  = 259473408 (247 MB)
avail memory = 242401280 (231 MB)
ioapic0: Changing APIC ID to 1
ioapic0 <Version 2.0> irqs 0-23 on motherboard
Pentium Pro MTRR support enabled
npx0: [FAST]
npx0: <math processor> on motherboard
npx0: INT 16 interface
acpi0: <DELL   160L   > on motherboard
pcibios: BIOS version 2.10
Using $PIR table, 7 entries at 0xc00feae0
acpi0: Power Button (fixed)
Timecounter "ACPI-fast" frequency 3579545 Hz quality 1000
acpi_timer0: <24-bit timer at 3.579545MHz> port 0x808-0x80b on acpi0
acpi_cpu0: <CPU> on acpi0
acpi_cpu1: <CPU> on acpi0
device_probe_and_attach: acpi_cpu1 attach returned 6
acpi_button0: <Power Button> on acpi0
pcib0: <ACPI Host-PCI bridge> port 0xcf8-0xcff on acpi0
pci0: <ACPI PCI bus> on pcib0
agp0: <Intel 82845G (845G GMCH) SVGA controller> mem 0xfeb80000-0xfebfffff,0xe8000000-0xefffffff irq 16 at device 2.0 on pci0
agp0: detected 8060k stolen memory
agp0: aperture size is 128M
uhci0: <Intel 82801DB (ICH4) USB controller USB-A> port 0xff80-0xff9f irq 16 at device 29.0 on pci0
usb0: <Intel 82801DB (ICH4) USB controller USB-A> on uhci0
usb0: USB revision 1.0
uhub0: Intel UHCI root hub, class 9/0, rev 1.00/1.00, addr 1
uhub0: 2 ports with 2 removable, self powered
uhci1: <Intel 82801DB (ICH4) USB controller USB-B> port 0xff60-0xff7f irq 19 at device 29.1 on pci0
usb1: <Intel 82801DB (ICH4) USB controller USB-B> on uhci1
usb1: USB revision 1.0
uhub1: Intel UHCI root hub, class 9/0, rev 1.00/1.00, addr 1
uhub1: 2 ports with 2 removable, self powered
uhci2: <Intel 82801DB (ICH4) USB controller USB-C> port 0xff40-0xff5f irq 18 at device 29.2 on pci0
usb2: <Intel 82801DB (ICH4) USB controller USB-C> on uhci2
usb2: USB revision 1.0
uhub2: Intel UHCI root hub, class 9/0, rev 1.00/1.00, addr 1
uhub2: 2 ports with 2 removable, self powered
pci0: <serial bus, USB> at device 29.7 (no driver attached)
pcib1: <ACPI PCI-PCI bridge> at device 30.0 on pci0
pci1: <ACPI PCI bus> on pcib1
bfe0: <Broadcom BCM4401 Fast Ethernet> mem 0xfe9fe000-0xfe9fffff irq 17 at device 9.0 on pci1
bfe0: Ethernet address: 00:0b:db:b6:6f:5e
miibus0: <MII bus> on bfe0
bmtphy0: <BCM4401 10/100baseTX PHY> on miibus0
bmtphy0:  10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto
isab0: <PCI-ISA bridge> at device 31.0 on pci0
isa0: <ISA bus> on isab0
atapci0: <Intel ICH4 UDMA100 controller> port 0xffa0-0xffaf,0xed8c-0xed8f,0xed98-0xed9f,0xed88-0xed8b,0xed90-0xed97 mem 0xfeb7fc00-0xfeb7ffff irq 18 at device 31.1 on pci0
ata0: at 0x1f0 irq 14 on atapci0
ata0: [MPSAFE]
ata1: at 0x170 irq 15 on atapci0
ata1: [MPSAFE]
pci0: <serial bus, SMBus> at device 31.3 (no driver attached)
pci0: <multimedia, audio> at device 31.5 (no driver attached)
fdc0: <Enhanced floppy controller (i82077, NE72065 or clone)> port 0x3f7,0x3f0-0x3f5 irq 6 drq 2 on acpi0
fdc0: FIFO enabled, 8 bytes threshold
fd0: <1440-KB 3.5" drive> on fdc0 drive 0
atkbdc0: <Keyboard controller (i8042)> port 0x64,0x60 irq 1 on acpi0
atkbd0: <AT Keyboard> flags 0x1 irq 1 on atkbdc0
kbd0 at atkbd0
psm0: <PS/2 Mouse> irq 12 on atkbdc0
psm0: model IntelliMouse, device ID 3
sio0 port 0x3f8-0x3ff irq 4 on acpi0
sio0: type 16550A
ppc0 port 0x778-0x77f,0x378-0x37f irq 7 on acpi0
ppc0: SMC-like chipset (ECP/EPP/PS2/NIBBLE) in COMPATIBLE mode
ppc0: FIFO with 16/16/8 bytes threshold
ppbus0: <Parallel port bus> on ppc0
plip0: <PLIP network interface> on ppbus0
lpt0: <Printer> on ppbus0
lpt0: Interrupt-driven port
ppi0: <Parallel I/O> on ppbus0
acpi_cpu1: <CPU> on acpi0
device_probe_and_attach: acpi_cpu1 attach returned 6
orm0: <Option ROMs> at iomem 0xcd000-0xcffff,0xcb800-0xccfff,0xc0000-0xcb7ff on isa0
pmtimer0 on isa0
sc0: <System console> at flags 0x100 on isa0
sc0: VGA <16 virtual consoles, flags=0x300>
sio1: configured irq 3 not in bitmap of probed irqs 0
sio1: port may not be enabled
vga0: <Generic ISA VGA> at port 0x3c0-0x3df iomem 0xa0000-0xbffff on isa0
Timecounter "TSC" frequency 2392290076 Hz quality 800
Timecounters tick every 10.000 msec
GEOM: create disk ad0 dp=0xc2d0de60
ad0: 76293MB <ST380011A> [155009/16/63] at ata0-master UDMA100
acd0: CDROM <GCR-8481B> at ata1-master PIO4
Mounting root from ufs:/dev/ad0s4a
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
bfe0: BUG!  Timeout waiting for bit 80000000 of register 428 to clear.
 
>How-To-Repeat:
Install FreeBSD 5.2.1 (i386) to any machine with a Broadcom 4401 Ethernet card  and the problem arises when you boot FreeBSD
>Fix:
Bug-fix with "bfe" driver
>Release-Note:
>Audit-Trail:

From: Jianqin Qu <jqu@its.brooklyn.cuny.edu>
To: freebsd-gnats-submit@freebsd.org, jqu@its.brooklyn.cuny.edu
Cc:  
Subject: Re: i386/64656: Bugs with Ethernet driver "bfe"[patch] (fwd)
Date: Mon, 10 May 2004 09:50:48 -0400 (EDT)

   This message is in MIME format.  The first part should be readable text,
   while the remaining parts are likely unreadable without MIME-aware tools.
   Send mail to mime@docserver.cac.washington.edu for more info.
 
 --------------090505010100030000050608
 Content-Type: TEXT/PLAIN; CHARSET=US-ASCII; FORMAT=flowed
 Content-ID: <Pine.GSO.4.58.0405100938532.27550@atrium69.its.brooklyn.cuny.edu>
 
 
 More tests showed that this problem does not appear every time at boot
 on my Dell Optiplex 160L.
 
 I found a tempory workaround for that.  When the problem occurs, simply
 shut down your computer completely (not just switch off the power button
 on your computer, but also detach your power cable!!! )   and  wait for
 sufficiently long time  and  then restart your computer to boot into
 FreeBSD 5.2.1 directly.   Here sufficiently long time varies, but 30
 minutes seems sufficient for my case most of time.
 
 If  you switch off your computer power button without unplugging the
 power cable and the LED light on the system board is on, then after some
 time (several hours) when you boot your computer into FreeBSD 5.2.1,
 this problem almost certainly occur.
 
 Rebooting into FreeBSD 5.2.1 release from another operating system
 installed on the same box  may reproduce the problem too.  Particularly
 rebooting into FreeBSD from a Linux system with a NIC driver of version
 3.0.7 from BroadCom  always results in the occurence of this problem.
 When the problem occurs, the link and activity indicator of the NIC are
 both off.   So it seems the bfe driver fails to reset the NIC card to a
 correct state in some cases.
 
 A patch with the bfe driver  is attached, which fixes the bug.  The
 patch is against 5.2.1 Release and had been tested with it.   The
 patched file "if_bfe.c" is also attached for reference.
 
 Jianqin
 --------------090505010100030000050608
 Content-Type: TEXT/PLAIN; NAME="tcp52.patch"
 Content-ID: <Pine.GSO.4.58.0405100938533.27550@atrium69.its.brooklyn.cuny.edu>
 Content-Description: 
 Content-Disposition: INLINE; FILENAME="tcp52.patch"
 
 ? tcp_reass-5.2.1-20040301.patch
 Index: tcp_input.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v
 retrieving revision 1.217.2.1
 diff -u -p -r1.217.2.1 tcp_input.c
 --- sys/netinet/tcp_input.c	9 Jan 2004 12:32:36 -0000	1.217.2.1
 +++ sys/netinet/tcp_input.c	1 Mar 2004 15:18:54 -0000
 @@ -57,6 +57,8 @@
  
  #include <machine/cpu.h>	/* before tcp_seq.h, for tcp_random18() */
  
 +#include <vm/uma.h>
 +
  #include <net/if.h>
  #include <net/route.h>
  
 @@ -97,8 +99,6 @@
  
  #include <machine/in_cksum.h>
  
 -MALLOC_DEFINE(M_TSEGQ, "tseg_qent", "TCP segment queue entry");
 -
  static const int tcprexmtthresh = 3;
  tcp_cc	tcp_ccgen;
  
 @@ -134,6 +134,24 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, rfc3
      &tcp_do_rfc3390, 0,
      "Enable RFC 3390 (Increasing TCP's Initial Congestion Window)");
  
 +SYSCTL_NODE(_net_inet_tcp, OID_AUTO, reass, CTLFLAG_RW, 0,
 +    "TCP Segment Reassembly Queue");
 +
 +static int tcp_reass_maxseg = 0;
 +SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, maxsegments, CTLFLAG_RDTUN,
 +    &tcp_reass_maxseg, 0,
 +    "Global maximum number of TCP Segments in Reassembly Queue");
 +
 +int tcp_reass_qsize = 0;
 +SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, cursegments, CTLFLAG_RD,
 +    &tcp_reass_qsize, 0,
 +    "Global number of TCP Segments currently in Reassembly Queue");
 +
 +static int tcp_reass_overflows = 0;
 +SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, overflows, CTLFLAG_RD,
 +    &tcp_reass_overflows, 0,
 +    "Global number of TCP Segment Reassembly Queue Overflows");
 +
  struct inpcbhead tcb;
  #define	tcb6	tcb  /* for KAME src sync over BSD*'s */
  struct inpcbinfo tcbinfo;
 @@ -174,6 +192,19 @@ do { \
  	    (tp->t_flags & TF_RXWIN0SENT) == 0) &&			\
  	    (tcp_delack_enabled || (tp->t_flags & TF_NEEDSYN)))
  
 +/* Initialize TCP reassembly queue */
 +uma_zone_t	tcp_reass_zone;
 +void
 +tcp_reass_init()
 +{
 +	tcp_reass_maxseg = nmbclusters / 16;
 +	TUNABLE_INT_FETCH("net.inet.tcp.reass.maxsegments",
 +	    &tcp_reass_maxseg);
 +	tcp_reass_zone = uma_zcreate("tcpreass", sizeof (struct tseg_qent),
 +	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
 +	uma_zone_set_max(tcp_reass_zone, tcp_reass_maxseg);
 +}
 +
  static int
  tcp_reass(tp, th, tlenp, m)
  	register struct tcpcb *tp;
 @@ -184,7 +215,7 @@ tcp_reass(tp, th, tlenp, m)
  	struct tseg_qent *q;
  	struct tseg_qent *p = NULL;
  	struct tseg_qent *nq;
 -	struct tseg_qent *te;
 +	struct tseg_qent *te = NULL;
  	struct socket *so = tp->t_inpcb->inp_socket;
  	int flags;
  
 @@ -195,9 +226,27 @@ tcp_reass(tp, th, tlenp, m)
  	if (th == 0)
  		goto present;
  
 -	/* Allocate a new queue entry. If we can't, just drop the pkt. XXX */
 -	MALLOC(te, struct tseg_qent *, sizeof (struct tseg_qent), M_TSEGQ,
 -	       M_NOWAIT);
 +	/*
 +	 * Limit the number of segments in the reassembly queue to prevent
 +	 * holding on to too many segments (and thus running out of mbufs).
 +	 * Make sure to let the missing segment through which caused this
 +	 * queue.  Always keep one global queue entry spare to be able to
 +	 * process the missing segment.
 +	 */
 +	if (th->th_seq != tp->rcv_nxt &&
 +	    tcp_reass_qsize + 1 >= tcp_reass_maxseg) {
 +		tcp_reass_overflows++;
 +		tcpstat.tcps_rcvmemdrop++;
 +		m_freem(m);
 +		return (0);
 +	}
 +	tcp_reass_qsize++;
 +
 +	/*
 +	 * Allocate a new queue entry. If we can't, or hit the zone limit
 +	 * just drop the pkt.
 +	 */
 +	te = uma_zalloc(tcp_reass_zone, M_NOWAIT);
  	if (te == NULL) {
  		tcpstat.tcps_rcvmemdrop++;
  		m_freem(m);
 @@ -227,7 +276,8 @@ tcp_reass(tp, th, tlenp, m)
  				tcpstat.tcps_rcvduppack++;
  				tcpstat.tcps_rcvdupbyte += *tlenp;
  				m_freem(m);
 -				FREE(te, M_TSEGQ);
 +				uma_zfree(tcp_reass_zone, te);
 +				tcp_reass_qsize--;
  				/*
  				 * Try to present any queued data
  				 * at the left window edge to the user.
 @@ -262,7 +312,8 @@ tcp_reass(tp, th, tlenp, m)
  		nq = LIST_NEXT(q, tqe_q);
  		LIST_REMOVE(q, tqe_q);
  		m_freem(q->tqe_m);
 -		FREE(q, M_TSEGQ);
 +		uma_zfree(tcp_reass_zone, q);
 +		tcp_reass_qsize--;
  		q = nq;
  	}
  
 @@ -296,7 +347,8 @@ present:
  			m_freem(q->tqe_m);
  		else
  			sbappendstream(&so->so_rcv, q->tqe_m);
 -		FREE(q, M_TSEGQ);
 +		uma_zfree(tcp_reass_zone, q);
 +		tcp_reass_qsize--;
  		q = nq;
  	} while (q && q->tqe_th->th_seq == tp->rcv_nxt);
  	ND6_HINT(tp);
 Index: tcp_subr.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/tcp_subr.c,v
 retrieving revision 1.169.2.3
 diff -u -p -r1.169.2.3 tcp_subr.c
 --- sys/netinet/tcp_subr.c	23 Feb 2004 15:32:55 -0000	1.169.2.3
 +++ sys/netinet/tcp_subr.c	1 Mar 2004 15:18:54 -0000
 @@ -286,6 +286,7 @@ tcp_init()
  	tcp_timer_init();
  	syncache_init();
  	tcp_hc_init();
 +	tcp_reass_init();
  }
  
  /*
 @@ -708,7 +709,8 @@ tcp_discardcb(tp)
  	while ((q = LIST_FIRST(&tp->t_segq)) != NULL) {
  		LIST_REMOVE(q, tqe_q);
  		m_freem(q->tqe_m);
 -		FREE(q, M_TSEGQ);
 +		uma_zfree(tcp_reass_zone, q);
 +		tcp_reass_qsize--;
  	}
  	inp->inp_ppcb = NULL;
  	tp->t_inpcb = NULL;
 @@ -769,7 +771,8 @@ tcp_drain()
  			            != NULL) {
  					LIST_REMOVE(te, tqe_q);
  					m_freem(te->tqe_m);
 -					FREE(te, M_TSEGQ);
 +					uma_zfree(tcp_reass_zone, te);
 +					tcp_reass_qsize--;
  				}
  			}
  			INP_UNLOCK(inpb);
 Index: tcp_var.h
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/tcp_var.h,v
 retrieving revision 1.93.2.1
 diff -u -p -r1.93.2.1 tcp_var.h
 --- sys/netinet/tcp_var.h	9 Jan 2004 12:32:36 -0000	1.93.2.1
 +++ sys/netinet/tcp_var.h	1 Mar 2004 15:18:55 -0000
 @@ -54,9 +54,8 @@ struct tseg_qent {
  	struct	mbuf	*tqe_m;		/* mbuf contains packet */
  };
  LIST_HEAD(tsegqe_head, tseg_qent);
 -#ifdef MALLOC_DECLARE
 -MALLOC_DECLARE(M_TSEGQ);
 -#endif
 +extern int	tcp_reass_qsize;
 +extern struct uma_zone	*tcp_reass_zone;
  
  struct tcptemp {
  	u_char	tt_ipgen[40]; /* the size must be of max ip header, now IPv6 */
 @@ -514,6 +513,7 @@ struct tcpcb *
  int	 tcp_output(struct tcpcb *);
  struct inpcb *
  	 tcp_quench(struct inpcb *, int);
 +void	 tcp_reass_init(void);
  void	 tcp_respond(struct tcpcb *, void *,
  	    struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int);
  int	 tcp_twrespond(struct tcptw *, struct socket *, struct mbuf *, int);
 
 --------------090505010100030000050608
 Content-Type: TEXT/PLAIN; NAME="if_bfe.c"
 Content-ID: <Pine.GSO.4.58.0405100938534.27550@atrium69.its.brooklyn.cuny.edu>
 Content-Description: 
 Content-Disposition: INLINE; FILENAME="if_bfe.c"
 
 /*
  * Copyright (c) 2003 Stuart Walsh<stu@ipng.org.uk>
  * and Duncan Barclay<dmlb@dmlb.org>
  */
 
 /*
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 'AS IS' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sys/dev/bfe/if_bfe.c,v 1.4 2003/11/14 19:00:30 sam Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/sockio.h>
 #include <sys/mbuf.h>
 #include <sys/malloc.h>
 #include <sys/kernel.h>
 #include <sys/socket.h>
 #include <sys/queue.h>
 
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <net/ethernet.h>
 #include <net/if_dl.h>
 #include <net/if_media.h>
 
 #include <net/bpf.h>
 
 #include <net/if_types.h>
 #include <net/if_vlan_var.h>
 
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
 
 #include <machine/clock.h>      /* for DELAY */
 #include <machine/bus_memio.h>
 #include <machine/bus.h>
 #include <machine/resource.h>
 #include <sys/bus.h>
 #include <sys/rman.h>
 
 #include <dev/mii/mii.h>
 #include <dev/mii/miivar.h>
 #include "miidevs.h"
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 
 #include <dev/bfe/if_bfereg.h>
 
 MODULE_DEPEND(bfe, pci, 1, 1, 1);
 MODULE_DEPEND(bfe, ether, 1, 1, 1);
 MODULE_DEPEND(bfe, miibus, 1, 1, 1);
 
 /* "controller miibus0" required.  See GENERIC if you get errors here. */
 #include "miibus_if.h"
 
 #define BFE_DEVDESC_MAX		64	/* Maximum device description length */
 
 static struct bfe_type bfe_devs[] = {
 	{ BCOM_VENDORID, BCOM_DEVICEID_BCM4401,
 		"Broadcom BCM4401 Fast Ethernet" },
 		{ 0, 0, NULL }
 };
 
 static int  bfe_probe				(device_t);
 static int  bfe_attach				(device_t);
 static int  bfe_detach				(device_t);
 static void bfe_release_resources	(struct bfe_softc *);
 static void bfe_intr				(void *);
 static void bfe_start				(struct ifnet *);
 static int  bfe_ioctl				(struct ifnet *, u_long, caddr_t);
 static void bfe_init				(void *);
 static void bfe_stop				(struct bfe_softc *);
 static void bfe_watchdog			(struct ifnet *);
 static void bfe_shutdown			(device_t);
 static void bfe_tick				(void *);
 static void bfe_txeof				(struct bfe_softc *);
 static void bfe_rxeof				(struct bfe_softc *);
 static void bfe_set_rx_mode			(struct bfe_softc *);
 static int  bfe_list_rx_init		(struct bfe_softc *);
 static int  bfe_list_newbuf			(struct bfe_softc *, int, struct mbuf*);
 static void bfe_rx_ring_free		(struct bfe_softc *);
 
 static void bfe_pci_setup			(struct bfe_softc *, u_int32_t);
 static int  bfe_ifmedia_upd			(struct ifnet *);
 static void bfe_ifmedia_sts			(struct ifnet *, struct ifmediareq *);
 static int  bfe_miibus_readreg		(device_t, int, int);
 static int  bfe_miibus_writereg		(device_t, int, int, int);
 static void bfe_miibus_statchg		(device_t);
 static int  bfe_wait_bit			(struct bfe_softc *, u_int32_t, u_int32_t, 
 		u_long, const int);
 static void bfe_get_config			(struct bfe_softc *sc);
 static void bfe_read_eeprom			(struct bfe_softc *, u_int8_t *);
 static void bfe_stats_update		(struct bfe_softc *);
 static void bfe_clear_stats			(struct bfe_softc *);
 static int  bfe_readphy				(struct bfe_softc *, u_int32_t, u_int32_t*);
 static int  bfe_writephy			(struct bfe_softc *, u_int32_t, u_int32_t);
 static int  bfe_resetphy			(struct bfe_softc *);
 static int  bfe_setupphy			(struct bfe_softc *);
 static void bfe_chip_reset			(struct bfe_softc *);
 static void bfe_chip_halt			(struct bfe_softc *);
 static void bfe_core_reset			(struct bfe_softc *);
 static void bfe_core_disable		(struct bfe_softc *);
 static int  bfe_dma_alloc			(device_t);
 static void bfe_dma_map_desc		(void *, bus_dma_segment_t *, int, int);
 static void bfe_dma_map				(void *, bus_dma_segment_t *, int, int);
 static void bfe_cam_write			(struct bfe_softc *, u_char *, int);
 
 static device_method_t bfe_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		bfe_probe),
 	DEVMETHOD(device_attach,	bfe_attach),
 	DEVMETHOD(device_detach,	bfe_detach),
 	DEVMETHOD(device_shutdown,	bfe_shutdown),
 
 	/* bus interface */
 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
 	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
 
 	/* MII interface */
 	DEVMETHOD(miibus_readreg,	bfe_miibus_readreg),
 	DEVMETHOD(miibus_writereg,	bfe_miibus_writereg),
 	DEVMETHOD(miibus_statchg,	bfe_miibus_statchg),
 
 	{ 0, 0 }
 };
 
 static driver_t bfe_driver = {
 	"bfe",
 	bfe_methods,
 	sizeof(struct bfe_softc)
 };
 
 static devclass_t bfe_devclass;
 
 DRIVER_MODULE(bfe, pci, bfe_driver, bfe_devclass, 0, 0);
 DRIVER_MODULE(miibus, bfe, miibus_driver, miibus_devclass, 0, 0);
 
 /*
  * Probe for a Broadcom 4401 chip. 
  */
 static int
 bfe_probe(device_t dev)
 {
 	struct bfe_type *t;
 	struct bfe_softc *sc;
 
 	t = bfe_devs;
 
 	sc = device_get_softc(dev);
 	bzero(sc, sizeof(struct bfe_softc));
 	sc->bfe_unit = device_get_unit(dev);
 	sc->bfe_dev = dev;
 
 	while(t->bfe_name != NULL) {
 		if ((pci_get_vendor(dev) == t->bfe_vid) &&
 				(pci_get_device(dev) == t->bfe_did)) {
 			device_set_desc_copy(dev, t->bfe_name);
 			return(0);
 		}
 		t++;
 	}
 
 	return(ENXIO);
 }
 
 static int
 bfe_dma_alloc(device_t dev)
 {
 	struct bfe_softc *sc;
 	int error, i;
 
 	sc = device_get_softc(dev);
 
 	/* parent tag */
 	error = bus_dma_tag_create(NULL,  /* parent */
 			PAGE_SIZE, 0,             /* alignment, boundary */
 			BUS_SPACE_MAXADDR,        /* lowaddr */      
 			BUS_SPACE_MAXADDR_32BIT,  /* highaddr */
 			NULL, NULL,               /* filter, filterarg */
 			MAXBSIZE,                 /* maxsize */
 			BUS_SPACE_UNRESTRICTED,   /* num of segments */
 			BUS_SPACE_MAXSIZE_32BIT,  /* max segment size */
 			BUS_DMA_ALLOCNOW,         /* flags */
 			NULL, NULL,               /* lockfunc, lockarg */
 			&sc->bfe_parent_tag);
 
 	/* tag for TX ring */
 	error = bus_dma_tag_create(sc->bfe_parent_tag, BFE_TX_LIST_SIZE, 
 			BFE_TX_LIST_SIZE, BUS_SPACE_MAXADDR,  BUS_SPACE_MAXADDR, 
 			NULL, NULL, BFE_TX_LIST_SIZE, 1,  BUS_SPACE_MAXSIZE_32BIT,
 			0, NULL, NULL, &sc->bfe_tx_tag);
 
 	if (error) {
 		device_printf(dev, "could not allocate dma tag\n");
 		return(ENOMEM);
 	}
 
 	/* tag for RX ring */
 	error = bus_dma_tag_create(sc->bfe_parent_tag, BFE_RX_LIST_SIZE, 
 			BFE_RX_LIST_SIZE, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 
 			NULL, NULL, BFE_RX_LIST_SIZE, 1, BUS_SPACE_MAXSIZE_32BIT, 
 			0, NULL, NULL, &sc->bfe_rx_tag);
 
 	if (error) {
 		device_printf(dev, "could not allocate dma tag\n");
 		return(ENOMEM);
 	}
 
 	/* tag for mbufs */
 	error = bus_dma_tag_create(sc->bfe_parent_tag, ETHER_ALIGN, 0,
 			BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 
 			1, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, &sc->bfe_tag);
 
 	if (error) {
 		device_printf(dev, "could not allocate dma tag\n");
 		return(ENOMEM);
 	}
 
 	/* pre allocate dmamaps for RX list */
 	for (i = 0; i < BFE_RX_LIST_CNT; i++) {
 		error = bus_dmamap_create(sc->bfe_tag, 0, &sc->bfe_rx_ring[i].bfe_map);
 		if (error) {
 			device_printf(dev, "cannot create DMA map for RX\n");
 			return(ENOMEM);
 		}
 	}
 
 	/* pre allocate dmamaps for TX list */
 	for (i = 0; i < BFE_TX_LIST_CNT; i++) {
 		error = bus_dmamap_create(sc->bfe_tag, 0, &sc->bfe_tx_ring[i].bfe_map);
 		if (error) {
 			device_printf(dev, "cannot create DMA map for TX\n");
 			return(ENOMEM);
 		}
 	}
 
 	/* Alloc dma for rx ring */
 	error = bus_dmamem_alloc(sc->bfe_rx_tag, (void *)&sc->bfe_rx_list,
 			BUS_DMA_NOWAIT, &sc->bfe_rx_map);
 
 	if(error)
 		return(ENOMEM);
 
 	bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE);
 	error = bus_dmamap_load(sc->bfe_rx_tag, sc->bfe_rx_map,
 			sc->bfe_rx_list, sizeof(struct bfe_desc),
 			bfe_dma_map, &sc->bfe_rx_dma, 0);
 
 	if(error)
 		return(ENOMEM);
 
 	bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, BUS_DMASYNC_PREREAD);
 
 	error = bus_dmamem_alloc(sc->bfe_tx_tag, (void *)&sc->bfe_tx_list, 
 			BUS_DMA_NOWAIT, &sc->bfe_tx_map);
 	if (error) 
 		return(ENOMEM);
 
 
 	error = bus_dmamap_load(sc->bfe_tx_tag, sc->bfe_tx_map, 
 			sc->bfe_tx_list, sizeof(struct bfe_desc), 
 			bfe_dma_map, &sc->bfe_tx_dma, 0);
 	if(error)
 		return(ENOMEM);
 
 	bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE);
 	bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, BUS_DMASYNC_PREREAD);
 
 	return(0);
 }
 
 static int
 bfe_attach(device_t dev)
 {
 	struct ifnet *ifp;
 	struct bfe_softc *sc;
 	int unit, error = 0, rid;
 
 	sc = device_get_softc(dev);
 	mtx_init(&sc->bfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
 			MTX_DEF | MTX_RECURSE);
 
 	unit = device_get_unit(dev);
 	sc->bfe_dev = dev;
 	sc->bfe_unit = unit;
 
 	/*
 	 * Handle power management nonsense.
 	 */
 	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
 		u_int32_t membase, irq;
 
 		/* Save important PCI config data. */
 		membase = pci_read_config(dev, BFE_PCI_MEMLO, 4);
 		irq = pci_read_config(dev, BFE_PCI_INTLINE, 4);
 
 		/* Reset the power state. */
 		printf("bfe%d: chip is is in D%d power mode -- setting to D0\n", 
 				sc->bfe_unit, pci_get_powerstate(dev));
 
 		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
 
 		/* Restore PCI config data. */
 		pci_write_config(dev, BFE_PCI_MEMLO, membase, 4);
 		pci_write_config(dev, BFE_PCI_INTLINE, irq, 4);
 	}
 
 	/*
 	 * Map control/status registers.
 	 */
 	pci_enable_busmaster(dev);
 
 	rid = BFE_PCI_MEMLO;
 	sc->bfe_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, 
 			RF_ACTIVE);
 	if (sc->bfe_res == NULL) {
 		printf ("bfe%d: couldn't map memory\n", unit);
 		error = ENXIO;
 		goto fail;
 	}
 
 	sc->bfe_btag = rman_get_bustag(sc->bfe_res);
 	sc->bfe_bhandle = rman_get_bushandle(sc->bfe_res);
 	sc->bfe_vhandle = (vm_offset_t)rman_get_virtual(sc->bfe_res);
 
 	/* Allocate interrupt */
 	rid = 0;
 
 	sc->bfe_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
 			RF_SHAREABLE | RF_ACTIVE);
 	if (sc->bfe_irq == NULL) {
 		printf("bfe%d: couldn't map interrupt\n", unit);
 		error = ENXIO;
 		goto fail;
 	}
 
 	if (bfe_dma_alloc(dev)) {
 		printf("bfe%d: failed to allocate DMA resources\n", sc->bfe_unit);
 		bfe_release_resources(sc);
 		error = ENXIO;
 		goto fail;
 	}
 
 	/* Set up ifnet structure */
 	ifp = &sc->arpcom.ac_if;
 	ifp->if_softc = sc;
 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_ioctl = bfe_ioctl;
 	ifp->if_output = ether_output;
 	ifp->if_start = bfe_start;
 	ifp->if_watchdog = bfe_watchdog;
 	ifp->if_init = bfe_init;
 	ifp->if_mtu = ETHERMTU;
 	ifp->if_baudrate = 10000000;
 	ifp->if_snd.ifq_maxlen = BFE_TX_QLEN;
 
 	bfe_get_config(sc);
 
 	printf("bfe%d: Ethernet address: %6D\n", unit, sc->arpcom.ac_enaddr, ":");
 
 	/* Reset the chip and turn on the PHY */
 	bfe_chip_reset(sc);
 
 	if (mii_phy_probe(dev, &sc->bfe_miibus,
 				bfe_ifmedia_upd, bfe_ifmedia_sts)) {
 		printf("bfe%d: MII without any PHY!\n", sc->bfe_unit);
 		error = ENXIO;
 		goto fail;
 	}
 
 	ether_ifattach(ifp, sc->arpcom.ac_enaddr);
 	callout_handle_init(&sc->bfe_stat_ch);
 
 	/*
 	 * Hook interrupt last to avoid having to lock softc
 	 */
 	error = bus_setup_intr(dev, sc->bfe_irq, INTR_TYPE_NET,
 			bfe_intr, sc, &sc->bfe_intrhand);
 
 	if (error) {
 		bfe_release_resources(sc);
 		printf("bfe%d: couldn't set up irq\n", unit);
 		goto fail;
 	}
 fail:
 	if(error)
 		bfe_release_resources(sc);
 	return(error);
 }
 
 static int
 bfe_detach(device_t dev)
 {
 	struct bfe_softc *sc;
 	struct ifnet *ifp;
 
 	sc = device_get_softc(dev);
 
 	KASSERT(mtx_initialized(&sc->bfe_mtx), ("bfe mutex not initialized"));
 	BFE_LOCK(scp);
 
 	ifp = &sc->arpcom.ac_if;
 
 	if (device_is_attached(dev)) {
 		bfe_stop(sc);
 		ether_ifdetach(ifp);
 	}
 
 	bfe_chip_reset(sc);
 
 	bus_generic_detach(dev);
 	if(sc->bfe_miibus != NULL)
 		device_delete_child(dev, sc->bfe_miibus);
 
 	bfe_release_resources(sc);
 	BFE_UNLOCK(sc);
 	mtx_destroy(&sc->bfe_mtx);
 
 	return(0);
 }
 
 /*
  * Stop all chip I/O so that the kernel's probe routines don't
  * get confused by errant DMAs when rebooting.
  */
 static void
 bfe_shutdown(device_t dev)
 {
 	struct bfe_softc *sc;
 
 	sc = device_get_softc(dev);
 	BFE_LOCK(sc);
 	bfe_stop(sc); 
 
 	BFE_UNLOCK(sc);
 	return;
 }
 
 static int
 bfe_miibus_readreg(device_t dev, int phy, int reg)
 {
 	struct bfe_softc *sc;
 	u_int32_t ret;
 
 	sc = device_get_softc(dev);
 	if(phy != sc->bfe_phyaddr)
 		return(0);
 	bfe_readphy(sc, reg, &ret);
 
 	return(ret);
 }
 
 static int
 bfe_miibus_writereg(device_t dev, int phy, int reg, int val)
 {
 	struct bfe_softc *sc;
 
 	sc = device_get_softc(dev);
 	if(phy != sc->bfe_phyaddr)
 		return(0);
 	bfe_writephy(sc, reg, val); 
 
 	return(0);
 }
 
 static void
 bfe_miibus_statchg(device_t dev)
 {
 	return;
 }
 
 static void
 bfe_tx_ring_free(struct bfe_softc *sc)
 {
     int i;
     
     for(i = 0; i < BFE_TX_LIST_CNT; i++) {
         if(sc->bfe_tx_ring[i].bfe_mbuf != NULL) {
             m_freem(sc->bfe_tx_ring[i].bfe_mbuf);
             sc->bfe_tx_ring[i].bfe_mbuf = NULL;
             bus_dmamap_unload(sc->bfe_tag,
                     sc->bfe_tx_ring[i].bfe_map);
             bus_dmamap_destroy(sc->bfe_tag,
                     sc->bfe_tx_ring[i].bfe_map);
         }
     }
     bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE);
     bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, BUS_DMASYNC_PREREAD);
 }
 
 static void
 bfe_rx_ring_free(struct bfe_softc *sc)
 {
 	int i;
 
 	for (i = 0; i < BFE_RX_LIST_CNT; i++) {
 		if (sc->bfe_rx_ring[i].bfe_mbuf != NULL) {
 			m_freem(sc->bfe_rx_ring[i].bfe_mbuf);
 			sc->bfe_rx_ring[i].bfe_mbuf = NULL;
 			bus_dmamap_unload(sc->bfe_tag,
 					sc->bfe_rx_ring[i].bfe_map);
 			bus_dmamap_destroy(sc->bfe_tag,
 					sc->bfe_rx_ring[i].bfe_map);
 		}
 	}
 	bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE);
 	bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, BUS_DMASYNC_PREREAD);
 }
 
 
 static int 
 bfe_list_rx_init(struct bfe_softc *sc)
 {
 	int i;
 
 	for(i = 0; i < BFE_RX_LIST_CNT; i++) {
 		if(bfe_list_newbuf(sc, i, NULL) == ENOBUFS) 
 			return ENOBUFS;
 	}
 
 	bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, BUS_DMASYNC_PREREAD);
 	CSR_WRITE_4(sc, BFE_DMARX_PTR, (i * sizeof(struct bfe_desc)));
 
 	sc->bfe_rx_cons = 0;
 
 	return(0);
 }
 
 static int
 bfe_list_newbuf(struct bfe_softc *sc, int c, struct mbuf *m)
 {
 	struct bfe_rxheader *rx_header;
 	struct bfe_desc *d;
 	struct bfe_data *r;
 	u_int32_t ctrl;
 
 	if ((c < 0) || (c >= BFE_RX_LIST_CNT))
 		return(EINVAL);
 
 	if(m == NULL) {
 		m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
 		if(m == NULL)
 			return(ENOBUFS);
 		m->m_len = m->m_pkthdr.len = MCLBYTES;
 	}
 	else
 		m->m_data = m->m_ext.ext_buf;
 
 	rx_header = mtod(m, struct bfe_rxheader *);
 	rx_header->len = 0;
 	rx_header->flags = 0;
 
 	/* Map the mbuf into DMA */
 	sc->bfe_rx_cnt = c;
 	d = &sc->bfe_rx_list[c];
 	r = &sc->bfe_rx_ring[c];
 	bus_dmamap_load(sc->bfe_tag, r->bfe_map, mtod(m, void *), 
 			MCLBYTES, bfe_dma_map_desc, d, 0);
 	bus_dmamap_sync(sc->bfe_tag, r->bfe_map, BUS_DMASYNC_PREWRITE);
 
 	ctrl = ETHER_MAX_LEN + 32;
 
 	if(c == BFE_RX_LIST_CNT - 1)
 		ctrl |= BFE_DESC_EOT;
 
 	d->bfe_ctrl = ctrl;
 	r->bfe_mbuf = m;
 	bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, BUS_DMASYNC_PREREAD);
 	return(0);
 }
 
 static void
 bfe_get_config(struct bfe_softc *sc)
 {
 	u_int8_t eeprom[128];
 
 	bfe_read_eeprom(sc, eeprom);
 
 	sc->arpcom.ac_enaddr[0] = eeprom[79];
 	sc->arpcom.ac_enaddr[1] = eeprom[78];
 	sc->arpcom.ac_enaddr[2] = eeprom[81];
 	sc->arpcom.ac_enaddr[3] = eeprom[80];
 	sc->arpcom.ac_enaddr[4] = eeprom[83];
 	sc->arpcom.ac_enaddr[5] = eeprom[82];
 
 	sc->bfe_phyaddr = eeprom[90] & 0x1f;
 	sc->bfe_mdc_port = (eeprom[90] >> 14) & 0x1;
 
 	sc->bfe_core_unit = 0; 
 	sc->bfe_dma_offset = BFE_PCI_DMA;
 }
 
 static void
 bfe_pci_setup(struct bfe_softc *sc, u_int32_t cores)
 {
 	u_int32_t bar_orig, pci_rev, val;
 
 	bar_orig = pci_read_config(sc->bfe_dev, BFE_BAR0_WIN, 4);
 	pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, BFE_REG_PCI, 4);
 	pci_rev = CSR_READ_4(sc, BFE_SBIDHIGH) & BFE_RC_MASK;
 
 	val = CSR_READ_4(sc, BFE_SBINTVEC);
 	val |= cores;
 	CSR_WRITE_4(sc, BFE_SBINTVEC, val);
 
 	val = CSR_READ_4(sc, BFE_SSB_PCI_TRANS_2);
 	val |= BFE_SSB_PCI_PREF | BFE_SSB_PCI_BURST;
 	CSR_WRITE_4(sc, BFE_SSB_PCI_TRANS_2, val);
 
 	pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, bar_orig, 4);
 }
 
 static void 
 bfe_clear_stats(struct bfe_softc *sc)
 {
 	u_long reg;
 
 	BFE_LOCK(sc);
 
 	CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ);
 	for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4)
 		CSR_READ_4(sc, reg);
 	for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4)
 		CSR_READ_4(sc, reg);
 
 	BFE_UNLOCK(sc);
 }
 
 static int 
 bfe_resetphy(struct bfe_softc *sc)
 {
 	u_int32_t val;
 
 	BFE_LOCK(sc);
 	bfe_writephy(sc, 0, BMCR_RESET);
 	DELAY(100);
 	bfe_readphy(sc, 0, &val);
 	if (val & BMCR_RESET) {
 		printf("bfe%d: PHY Reset would not complete.\n", sc->bfe_unit);
 		BFE_UNLOCK(sc);
 		return ENXIO;
 	}
 	BFE_UNLOCK(sc);
 	return 0;
 }
 
 static void
 bfe_chip_halt(struct bfe_softc *sc)
 {
 	BFE_LOCK(sc);
 	/* disable interrupts - not that it actually does..*/
 	CSR_WRITE_4(sc, BFE_IMASK, 0);
 	CSR_READ_4(sc, BFE_IMASK);
 
 	CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE);
 	bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 200, 1);
 
 	CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0);
 	CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0);
 	DELAY(10);
 
 	BFE_UNLOCK(sc);
 }
 
 static void
 bfe_chip_reset(struct bfe_softc *sc)
 {
 	u_int32_t val;    
 
 	BFE_LOCK(sc);
 
 	/* Set the interrupt vector for the enet core */
 	bfe_pci_setup(sc, BFE_INTVEC_ENET0);
 
 	/* is core up? */
 	val = CSR_READ_4(sc, BFE_SBTMSLOW) & (BFE_RESET | BFE_REJECT | BFE_CLOCK);
 	if (val == BFE_CLOCK) {
 		/* It is, so shut it down */
 		CSR_WRITE_4(sc, BFE_RCV_LAZY, 0);
 		CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE);
 		bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 100, 1);
 		CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0);
 		sc->bfe_tx_cnt = sc->bfe_tx_prod = sc->bfe_tx_cons = 0;
 		if (CSR_READ_4(sc, BFE_DMARX_STAT) & BFE_STAT_EMASK) 
 			bfe_wait_bit(sc, BFE_DMARX_STAT, BFE_STAT_SIDLE, 100, 0);
 		CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0);
 		sc->bfe_rx_prod = sc->bfe_rx_cons = 0;
 	}
 
 	bfe_core_reset(sc);
 	bfe_clear_stats(sc);
 
 	/*
 	 * We want the phy registers to be accessible even when
 	 * the driver is "downed" so initialize MDC preamble, frequency,
 	 * and whether internal or external phy here.
 	 */
 
 	/* 4402 has 62.5Mhz SB clock and internal phy */
 	CSR_WRITE_4(sc, BFE_MDIO_CTRL, 0x8d);
 
 	/* Internal or external PHY? */
 	val = CSR_READ_4(sc, BFE_DEVCTRL);
 	if(!(val & BFE_IPP)) 
 		CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_EPSEL);
 	else if(CSR_READ_4(sc, BFE_DEVCTRL) & BFE_EPR) {
 		BFE_AND(sc, BFE_DEVCTRL, ~BFE_EPR);
 		DELAY(100);
 	}
 
 	//BFE_OR(sc, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB);
 	BFE_OR(sc, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB | 7 << 5);
 	CSR_WRITE_4(sc, BFE_RCV_LAZY, ((1 << BFE_LAZY_FC_SHIFT) & 
 				BFE_LAZY_FC_MASK));
 
 	/* 
 	 * We don't want lazy interrupts, so just send them at the end of a frame,
 	 * please 
 	 */
 	BFE_OR(sc, BFE_RCV_LAZY, 0);
 
 	/* Set max lengths, accounting for VLAN tags */
 	CSR_WRITE_4(sc, BFE_RXMAXLEN, ETHER_MAX_LEN+32);
 	CSR_WRITE_4(sc, BFE_TXMAXLEN, ETHER_MAX_LEN+32);
 
 	/* Set watermark XXX - magic */
 	CSR_WRITE_4(sc, BFE_TX_WMARK, 56);
 
 	/* 
 	 * Initialise DMA channels - not forgetting dma addresses need to be added
 	 * to BFE_PCI_DMA 
 	 */
 	CSR_WRITE_4(sc, BFE_DMATX_CTRL, BFE_TX_CTRL_ENABLE);
 	CSR_WRITE_4(sc, BFE_DMATX_ADDR, sc->bfe_tx_dma + BFE_PCI_DMA);
 
 	CSR_WRITE_4(sc, BFE_DMARX_CTRL, (BFE_RX_OFFSET << BFE_RX_CTRL_ROSHIFT) | 
 			BFE_RX_CTRL_ENABLE);
 	CSR_WRITE_4(sc, BFE_DMARX_ADDR, sc->bfe_rx_dma + BFE_PCI_DMA);
 
 	bfe_resetphy(sc);
 	bfe_setupphy(sc);
 
 	BFE_UNLOCK(sc);
 }
 
 static void
 bfe_core_disable(struct bfe_softc *sc)
 {
 	if((CSR_READ_4(sc, BFE_SBTMSLOW)) & BFE_RESET)
 		return;
 
 	/* 
 	 * Set reject, wait for it set, then wait for the core to stop being busy
 	 * Then set reset and reject and enable the clocks
 	 */
 	CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_CLOCK));
 	bfe_wait_bit(sc, BFE_SBTMSLOW, BFE_REJECT, 1000, 0);
 	bfe_wait_bit(sc, BFE_SBTMSHIGH, BFE_BUSY, 1000, 1);
 	CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_FGC | BFE_CLOCK | BFE_REJECT |
 				BFE_RESET));
 	CSR_READ_4(sc, BFE_SBTMSLOW);
 	DELAY(10);
 	/* Leave reset and reject set */
 	CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_RESET));
 	DELAY(10);
 }
 
 static void
 bfe_core_reset(struct bfe_softc *sc)
 {
 	u_int32_t val;
 
 	/* Disable the core */
 	bfe_core_disable(sc);
 
 	/* and bring it back up */
 	CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC));
 	CSR_READ_4(sc, BFE_SBTMSLOW);
 	DELAY(10);
 
 	/* Chip bug, clear SERR, IB and TO if they are set. */
 	if (CSR_READ_4(sc, BFE_SBTMSHIGH) & BFE_SERR)
 		CSR_WRITE_4(sc, BFE_SBTMSHIGH, 0);
 	val = CSR_READ_4(sc, BFE_SBIMSTATE);
 	if (val & (BFE_IBE | BFE_TO))
 		CSR_WRITE_4(sc, BFE_SBIMSTATE, val & ~(BFE_IBE | BFE_TO));
 
 	/* Clear reset and allow it to move through the core */
 	CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC));
 	CSR_READ_4(sc, BFE_SBTMSLOW);
 	DELAY(10);
 
 	/* Leave the clock set */
 	CSR_WRITE_4(sc, BFE_SBTMSLOW, BFE_CLOCK);
 	CSR_READ_4(sc, BFE_SBTMSLOW);
 	DELAY(10);
 }
 
 static void 
 bfe_cam_write(struct bfe_softc *sc, u_char *data, int index)
 {
 	u_int32_t val;
 
 	val  = ((u_int32_t) data[2]) << 24;
 	val |= ((u_int32_t) data[3]) << 16;
 	val |= ((u_int32_t) data[4]) <<  8;
 	val |= ((u_int32_t) data[5]);
 	CSR_WRITE_4(sc, BFE_CAM_DATA_LO, val);
 	val = (BFE_CAM_HI_VALID |
 			(((u_int32_t) data[0]) << 8) |
 			(((u_int32_t) data[1])));
 	CSR_WRITE_4(sc, BFE_CAM_DATA_HI, val);
 	CSR_WRITE_4(sc, BFE_CAM_CTRL, (BFE_CAM_WRITE |
 				(index << BFE_CAM_INDEX_SHIFT)));
 	bfe_wait_bit(sc, BFE_CAM_CTRL, BFE_CAM_BUSY, 10000, 1);
 }
 
 static void 
 bfe_set_rx_mode(struct bfe_softc *sc)
 {
 	struct ifnet *ifp = &sc->arpcom.ac_if;
 	struct ifmultiaddr  *ifma;
 	u_int32_t val;
 	int i = 0;
 
 	val = CSR_READ_4(sc, BFE_RXCONF);
 
 	if (ifp->if_flags & IFF_PROMISC)
 		val |= BFE_RXCONF_PROMISC;
 	else
 		val &= ~BFE_RXCONF_PROMISC;
 
 	if (ifp->if_flags & IFF_BROADCAST)
 		val &= ~BFE_RXCONF_DBCAST;
 	else
 		val |= BFE_RXCONF_DBCAST;
 
 
 	CSR_WRITE_4(sc, BFE_CAM_CTRL, 0);
 	bfe_cam_write(sc, sc->arpcom.ac_enaddr, i++);
 
 	if (ifp->if_flags & IFF_ALLMULTI)
 		val |= BFE_RXCONF_ALLMULTI;
 	else {
 		val &= ~BFE_RXCONF_ALLMULTI;
 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
 			if (ifma->ifma_addr->sa_family != AF_LINK)
 				continue;
 			bfe_cam_write(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
 					i++);
 		}
 	}
 
 	CSR_WRITE_4(sc, BFE_RXCONF, val);
 	BFE_OR(sc, BFE_CAM_CTRL, BFE_CAM_ENABLE);
 }
 
 static void
 bfe_dma_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 {
 	u_int32_t *ptr;
 
 	ptr = arg;
 	*ptr = segs->ds_addr;
 }
 
 static void
 bfe_dma_map_desc(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 {
 	struct bfe_desc *d;
 
 	d = arg;
 	/* The chip needs all addresses to be added to BFE_PCI_DMA */
 	d->bfe_addr = segs->ds_addr + BFE_PCI_DMA;
 }
 
 static void
 bfe_release_resources(struct bfe_softc *sc)
 {
 	device_t dev;
 	int i;
 
 	dev = sc->bfe_dev;
 
 	if (sc->bfe_vpd_prodname != NULL)
 		free(sc->bfe_vpd_prodname, M_DEVBUF);
 
 	if (sc->bfe_vpd_readonly != NULL)
 		free(sc->bfe_vpd_readonly, M_DEVBUF);
 
 	if (sc->bfe_intrhand != NULL)
 		bus_teardown_intr(dev, sc->bfe_irq, sc->bfe_intrhand);
 
 	if (sc->bfe_irq != NULL)
 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->bfe_irq);
 
 	if (sc->bfe_res != NULL)
 		bus_release_resource(dev, SYS_RES_MEMORY, 0x10, sc->bfe_res);
 
 	if(sc->bfe_tx_tag != NULL) {
 		bus_dmamap_unload(sc->bfe_tx_tag, sc->bfe_tx_map);
 		bus_dmamem_free(sc->bfe_tx_tag, sc->bfe_tx_list, sc->bfe_tx_map);
 		bus_dma_tag_destroy(sc->bfe_tx_tag);
 		sc->bfe_tx_tag = NULL;
 	}
 
 	if(sc->bfe_rx_tag != NULL) {
 		bus_dmamap_unload(sc->bfe_rx_tag, sc->bfe_rx_map);
 		bus_dmamem_free(sc->bfe_rx_tag, sc->bfe_rx_list, sc->bfe_rx_map);
 		bus_dma_tag_destroy(sc->bfe_rx_tag);
 		sc->bfe_rx_tag = NULL;
 	}
 
 	if(sc->bfe_tag != NULL) {
 		for(i = 0; i < BFE_TX_LIST_CNT; i++) {
 			bus_dmamap_destroy(sc->bfe_tag, sc->bfe_tx_ring[i].bfe_map);
 		}
 		bus_dma_tag_destroy(sc->bfe_tag);
         sc->bfe_tag = NULL;
 	}
 
 	if(sc->bfe_parent_tag != NULL)
 		bus_dma_tag_destroy(sc->bfe_parent_tag);
 
 	return;
 }
 
 static void
 bfe_read_eeprom(struct bfe_softc *sc, u_int8_t *data)
 {
 	long i;
 	u_int16_t *ptr = (u_int16_t *)data;
 
 	for(i = 0; i < 128; i += 2)
 		ptr[i/2] = CSR_READ_4(sc, 4096 + i);
 }
 
 static int
 bfe_wait_bit(struct bfe_softc *sc, u_int32_t reg, u_int32_t bit, 
 		u_long timeout, const int clear)
 {
 	u_long i;
 
 	for (i = 0; i < timeout; i++) {
 		u_int32_t val = CSR_READ_4(sc, reg);
 
 		if (clear && !(val & bit))
 			break;
 		if (!clear && (val & bit))
 			break;
 		DELAY(10);
 	}
 	if (i == timeout) {
 		printf("bfe%d: BUG!  Timeout waiting for bit %08x of register "
 				"%x to %s.\n", sc->bfe_unit, bit, reg, 
 				(clear ? "clear" : "set"));
 		return -1;
 	}
 	return 0;
 }
 
 static int
 bfe_readphy(struct bfe_softc *sc, u_int32_t reg, u_int32_t *val)
 {
 	int err; 
 
 	BFE_LOCK(sc);
 	/* Clear MII ISR */
 	CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII);
 	CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START |
 				(BFE_MDIO_OP_READ << BFE_MDIO_OP_SHIFT) |
 				(sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) |
 				(reg << BFE_MDIO_RA_SHIFT) |
 				(BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT)));
 	err = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0);
 	*val = CSR_READ_4(sc, BFE_MDIO_DATA) & BFE_MDIO_DATA_DATA;
 
 	BFE_UNLOCK(sc);
 	return err;
 }
 
 static int
 bfe_writephy(struct bfe_softc *sc, u_int32_t reg, u_int32_t val)
 {
 	int status;
 
 	BFE_LOCK(sc);
 	CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII);
 	CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START |
 				(BFE_MDIO_OP_WRITE << BFE_MDIO_OP_SHIFT) |
 				(sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) |
 				(reg << BFE_MDIO_RA_SHIFT) |
 				(BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT) |
 				(val & BFE_MDIO_DATA_DATA)));
 	status = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0);
 	BFE_UNLOCK(sc);
 
 	return status;
 }
 
 /* 
  * XXX - I think this is handled by the PHY driver, but it can't hurt to do it
  * twice
  */
 static int
 bfe_setupphy(struct bfe_softc *sc)
 {
 	u_int32_t val;
 	BFE_LOCK(sc);
 
 	/* Enable activity LED */
 	bfe_readphy(sc, 26, &val);
 	bfe_writephy(sc, 26, val & 0x7fff); 
 	bfe_readphy(sc, 26, &val);
 
 	/* Enable traffic meter LED mode */
 	bfe_readphy(sc, 27, &val);
 	bfe_writephy(sc, 27, val | (1 << 6));
 
 	BFE_UNLOCK(sc);
 	return 0;
 }
 
 static void 
 bfe_stats_update(struct bfe_softc *sc)
 {
 	u_long reg;
 	u_int32_t *val;
 
 	val = &sc->bfe_hwstats.tx_good_octets;
 	for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4) {
 		*val++ += CSR_READ_4(sc, reg);
 	}
 	val = &sc->bfe_hwstats.rx_good_octets;
 	for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4) {
 		*val++ += CSR_READ_4(sc, reg);
 	}
 }
 
 static void
 bfe_txeof(struct bfe_softc *sc)
 {
 	struct ifnet *ifp;
 	int i, chipidx;
 
 	BFE_LOCK(sc);
 
 	ifp = &sc->arpcom.ac_if;
 
 	chipidx = CSR_READ_4(sc, BFE_DMATX_STAT) & BFE_STAT_CDMASK;
 	chipidx /= sizeof(struct bfe_desc);
 
     i = sc->bfe_tx_cons;
 	/* Go through the mbufs and free those that have been transmitted */
     while(i != chipidx) {
 		struct bfe_data *r = &sc->bfe_tx_ring[i];
 		if(r->bfe_mbuf != NULL) {
 			ifp->if_opackets++;
 			m_freem(r->bfe_mbuf);
 			r->bfe_mbuf = NULL;
 			bus_dmamap_unload(sc->bfe_tag, r->bfe_map);
 		}
         sc->bfe_tx_cnt--;
         BFE_INC(i, BFE_TX_LIST_CNT);
 	}
 
 	if(i != sc->bfe_tx_cons) {
 		/* we freed up some mbufs */
 		sc->bfe_tx_cons = i;
 		ifp->if_flags &= ~IFF_OACTIVE;
 	}
 	if(sc->bfe_tx_cnt == 0)
 		ifp->if_timer = 0;
 	else
 		ifp->if_timer = 5;
 
 	BFE_UNLOCK(sc);
 }
 
 /* Pass a received packet up the stack */
 static void
 bfe_rxeof(struct bfe_softc *sc)
 {
 	struct mbuf *m;
 	struct ifnet *ifp;
 	struct bfe_rxheader *rxheader;
 	struct bfe_data *r;
 	int cons;
 	u_int32_t status, current, len, flags;
 
 	BFE_LOCK(sc);
 	cons = sc->bfe_rx_cons;
 	status = CSR_READ_4(sc, BFE_DMARX_STAT);
 	current = (status & BFE_STAT_CDMASK) / sizeof(struct bfe_desc);
 
 	ifp = &sc->arpcom.ac_if;
 
 	while(current != cons) {
 		r = &sc->bfe_rx_ring[cons];
 		m = r->bfe_mbuf;
 		rxheader = mtod(m, struct bfe_rxheader*);
 		bus_dmamap_sync(sc->bfe_tag, r->bfe_map, BUS_DMASYNC_POSTWRITE);
 		len = rxheader->len;
 		r->bfe_mbuf = NULL;
 
 		bus_dmamap_unload(sc->bfe_tag, r->bfe_map);
 		flags = rxheader->flags;
 
 		len -= ETHER_CRC_LEN;
 
 		/* flag an error and try again */
 		if ((len > ETHER_MAX_LEN+32) || (flags & BFE_RX_FLAG_ERRORS)) {
 			ifp->if_ierrors++;
 			if (flags & BFE_RX_FLAG_SERR)
 				ifp->if_collisions++;
 			bfe_list_newbuf(sc, cons, m);
 			continue;
 		}
 
 		/* Go past the rx header */
 		if (bfe_list_newbuf(sc, cons, NULL) == 0) {
 			m_adj(m, BFE_RX_OFFSET);
 			m->m_len = m->m_pkthdr.len = len;
 		} else {
 			bfe_list_newbuf(sc, cons, m);
 			ifp->if_ierrors++;
 			continue;
 		}
 
 		ifp->if_ipackets++;
 		m->m_pkthdr.rcvif = ifp;
 		BFE_UNLOCK(sc);
 		(*ifp->if_input)(ifp, m);
 		BFE_LOCK(sc);
 
         BFE_INC(cons, BFE_RX_LIST_CNT);
 	}
 	sc->bfe_rx_cons = cons;
 	BFE_UNLOCK(sc);
 }
 
 static void
 bfe_intr(void *xsc)
 {
 	struct bfe_softc *sc = xsc;
 	struct ifnet *ifp;
 	u_int32_t istat, imask, flag;
 
 	ifp = &sc->arpcom.ac_if;
 
 	BFE_LOCK(sc);
 
 	istat = CSR_READ_4(sc, BFE_ISTAT);
 	imask = CSR_READ_4(sc, BFE_IMASK);
 
 	/* 
 	 * Defer unsolicited interrupts - This is necessary because setting the
 	 * chips interrupt mask register to 0 doesn't actually stop the
 	 * interrupts
 	 */
 	istat &= imask;
 	CSR_WRITE_4(sc, BFE_ISTAT, istat);
 	CSR_READ_4(sc, BFE_ISTAT);
 
 	/* not expecting this interrupt, disregard it */
 	if(istat == 0) {
 		BFE_UNLOCK(sc);
 		return;
 	}
 
 	if(istat & BFE_ISTAT_ERRORS) {
 		flag = CSR_READ_4(sc, BFE_DMATX_STAT);
 		if(flag & BFE_STAT_EMASK)
 			ifp->if_oerrors++;
 
 		flag = CSR_READ_4(sc, BFE_DMARX_STAT);
 		if(flag & BFE_RX_FLAG_ERRORS)
 			ifp->if_ierrors++;
 
 		ifp->if_flags &= ~IFF_RUNNING;
 		bfe_init(sc);
 	}
 
 	/* A packet was received */
 	if(istat & BFE_ISTAT_RX)
 		bfe_rxeof(sc);
 
 	/* A packet was sent */
 	if(istat & BFE_ISTAT_TX)
 		bfe_txeof(sc);
 
 	/* We have packets pending, fire them out */ 
 	if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
 		bfe_start(ifp);
 
 	BFE_UNLOCK(sc);
 }
 
 static int
 bfe_encap(struct bfe_softc *sc, struct mbuf *m_head, u_int32_t *txidx)
 {
 	struct bfe_desc *d = NULL;
 	struct bfe_data *r = NULL;
 	struct mbuf     *m;
 	u_int32_t       frag, cur, cnt = 0;
 	int chainlen = 0;
 
 	if(BFE_TX_LIST_CNT - sc->bfe_tx_cnt < 2)
 		return(ENOBUFS);
 
 	/*
 	 * Count the number of frags in this chain to see if
 	 * we need to m_defrag.  Since the descriptor list is shared
 	 * by all packets, we'll m_defrag long chains so that they
 	 * do not use up the entire list, even if they would fit.
 	 */
 	for(m = m_head; m != NULL; m = m->m_next) 
 		chainlen++;
 
 
 	if ((chainlen > BFE_TX_LIST_CNT / 4) || 
 			((BFE_TX_LIST_CNT - (chainlen + sc->bfe_tx_cnt)) < 2)) {
 		m = m_defrag(m_head, M_DONTWAIT);
 		if (m == NULL) 
 			return(ENOBUFS);
 		m_head = m;
 	}
 
 	/*
 	 * Start packing the mbufs in this chain into
 	 * the fragment pointers. Stop when we run out
 	 * of fragments or hit the end of the mbuf chain.
 	 */
 	m = m_head;
 	cur = frag = *txidx;
 	cnt = 0;
 
 	for(m = m_head; m != NULL; m = m->m_next) {
 		if(m->m_len != 0) {
 			if((BFE_TX_LIST_CNT - (sc->bfe_tx_cnt + cnt)) < 2)
 				return(ENOBUFS);
 
 			d = &sc->bfe_tx_list[cur];
 			r = &sc->bfe_tx_ring[cur];
 			d->bfe_ctrl = BFE_DESC_LEN & m->m_len;
 			/* always intterupt on completion */
 			d->bfe_ctrl |= BFE_DESC_IOC;
 			if(cnt == 0)
 				/* Set start of frame */
 				d->bfe_ctrl |= BFE_DESC_SOF;
 			if(cur == BFE_TX_LIST_CNT - 1)
 				/* Tell the chip to wrap to the start of the descriptor list */
 				d->bfe_ctrl |= BFE_DESC_EOT;
 
 			bus_dmamap_load(sc->bfe_tag, r->bfe_map, mtod(m, void*), m->m_len, 
 					bfe_dma_map_desc, d, 0);
 			bus_dmamap_sync(sc->bfe_tag, r->bfe_map, BUS_DMASYNC_PREREAD);
 
 			frag = cur;
             BFE_INC(cur, BFE_TX_LIST_CNT);
 			cnt++;
 		}
 	}
 
 	if (m != NULL)
 		return(ENOBUFS);
 
 	sc->bfe_tx_list[frag].bfe_ctrl |= BFE_DESC_EOF;
 	sc->bfe_tx_ring[frag].bfe_mbuf = m_head;
 	bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, BUS_DMASYNC_PREREAD);
 
 	*txidx = cur;
 	sc->bfe_tx_cnt += cnt;
 	return (0);
 }
 
 /*
  * Set up to transmit a packet
  */
 static void
 bfe_start(struct ifnet *ifp)
 {
 	struct bfe_softc *sc;
 	struct mbuf *m_head = NULL;
 	int idx;
 
 	sc = ifp->if_softc;
 	idx = sc->bfe_tx_prod;
 
 	BFE_LOCK(sc);
 
 	/* 
 	 * not much point trying to send if the link is down or we have nothing to
 	 * send
 	 */
 	if (!sc->bfe_link && ifp->if_snd.ifq_len < 10) {
 		BFE_UNLOCK(sc);
 		return;
 	}
 
 	if (ifp->if_flags & IFF_OACTIVE) {
 		BFE_UNLOCK(sc);
 		return;
 	}
 
 	while(sc->bfe_tx_ring[idx].bfe_mbuf == NULL) {
 		IF_DEQUEUE(&ifp->if_snd, m_head);
 		if(m_head == NULL)
 			break;
 
 		/* 
 		 * Pack the data into the tx ring.  If we dont have enough room, let
 		 * the chip drain the ring
 		 */
 		if(bfe_encap(sc, m_head, &idx)) {
 			IF_PREPEND(&ifp->if_snd, m_head);
 			ifp->if_flags |= IFF_OACTIVE;
 			break;
 		}
 
 		/*
 		 * If there's a BPF listener, bounce a copy of this frame
 		 * to him.
 		 */
 		BPF_MTAP(ifp, m_head);
 	}
 
 	sc->bfe_tx_prod = idx;
 	/* Transmit - twice due to apparent hardware bug */
 	CSR_WRITE_4(sc, BFE_DMATX_PTR, idx * sizeof(struct bfe_desc));
 	CSR_WRITE_4(sc, BFE_DMATX_PTR, idx * sizeof(struct bfe_desc));
 
 	/*
 	 * Set a timeout in case the chip goes out to lunch.
 	 */
 	ifp->if_timer = 5;
 	BFE_UNLOCK(sc);
 }
 
 static void
 bfe_init(void *xsc)
 {
 
     uint32_t val1, val2, val3;
 
 	struct bfe_softc *sc = (struct bfe_softc*)xsc;
 	struct ifnet *ifp = &sc->arpcom.ac_if;
 
 	BFE_LOCK(sc);
 
 	if (ifp->if_flags & IFF_RUNNING) {
 		BFE_UNLOCK(sc);
 		return;
 	}
 
 /* for test only */ 
 	val1 = CSR_READ_4(sc, BFE_CAM_CTRL);
     val2 = CSR_READ_4(sc, BFE_MAC_CTRL); 
 	val3 = CSR_READ_4(sc, BFE_ENET_CTRL);
 	printf("At entry: CAM_CTRL =%08x, MAC_CTRL =%08x, ENET_CTRL=%08x\n",
             val1, val2, val3);
 /* for test end */
 
 	bfe_stop(sc);
 	bfe_chip_reset(sc);
 
 /* for test only */ 
 	val1 = CSR_READ_4(sc, BFE_CAM_CTRL);
     val2 = CSR_READ_4(sc, BFE_MAC_CTRL); 
 	val3 = CSR_READ_4(sc, BFE_ENET_CTRL);
 	printf("After reset: CAM_CTRL =%08x, MAC_CTRL =%08x, ENET_CTRL=%08x\n",
             val1, val2, val3);
 /* for test end */
 
 	if (bfe_list_rx_init(sc) == ENOBUFS) {
 		printf("bfe%d: bfe_init failed. Not enough memory for list buffers\n",
 				sc->bfe_unit);
 		bfe_stop(sc);
 		return;
 	}
 
 	bfe_set_rx_mode(sc);
 
 	/* Enable the chip and core */
 	BFE_OR(sc, BFE_ENET_CTRL, BFE_ENET_ENABLE);
 	/* Enable interrupts */
 	CSR_WRITE_4(sc, BFE_IMASK, BFE_IMASK_DEF);
 
 	bfe_ifmedia_upd(ifp);
 	ifp->if_flags |= IFF_RUNNING;
 	ifp->if_flags &= ~IFF_OACTIVE;
 
 	sc->bfe_stat_ch = timeout(bfe_tick, sc, hz);
 	BFE_UNLOCK(sc);
 
 /* for test only */ 
 	val1 = CSR_READ_4(sc, BFE_CAM_CTRL);
     val2 = CSR_READ_4(sc, BFE_MAC_CTRL); 
 	val3 = CSR_READ_4(sc, BFE_ENET_CTRL);
 	printf("At exit: CAM_CTRL =%08x, MAC_CTRL =%08x, ENET_CTRL=%08x\n",
             val1, val2, val3);
 /* for test end */
 
 }
 
 /*
  * Set media options.
  */
 static int
 bfe_ifmedia_upd(struct ifnet *ifp)
 {
 	struct bfe_softc *sc;
 	struct mii_data *mii;
 
 	sc = ifp->if_softc;
 
 	BFE_LOCK(sc);
 
 	mii = device_get_softc(sc->bfe_miibus);
 	sc->bfe_link = 0;
 	if (mii->mii_instance) {
 		struct mii_softc *miisc;
 		for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
 				miisc = LIST_NEXT(miisc, mii_list))
 			mii_phy_reset(miisc);
 	}
 	mii_mediachg(mii);
 
 	BFE_UNLOCK(sc);
 	return(0);
 }
 
 /*
  * Report current media status.
  */
 static void
 bfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
 {
 	struct bfe_softc *sc = ifp->if_softc;
 	struct mii_data *mii;
 
 	BFE_LOCK(sc);
 
 	mii = device_get_softc(sc->bfe_miibus);
 	mii_pollstat(mii);
 	ifmr->ifm_active = mii->mii_media_active;
 	ifmr->ifm_status = mii->mii_media_status;
 
 	BFE_UNLOCK(sc);
 }
 
 static int
 bfe_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
 {
 	struct bfe_softc *sc = ifp->if_softc;
 	struct ifreq *ifr = (struct ifreq *) data;
 	struct mii_data *mii;
 	int error = 0;
 
 	BFE_LOCK(sc);
 
 	switch(command) {
 		case SIOCSIFFLAGS:
 			if(ifp->if_flags & IFF_UP)
 				if(ifp->if_flags & IFF_RUNNING)
 					bfe_set_rx_mode(sc);
 				else
 					bfe_init(sc);
 			else if(ifp->if_flags & IFF_RUNNING)
 				bfe_stop(sc);
 			break;
 		case SIOCADDMULTI:
 		case SIOCDELMULTI:
 			if(ifp->if_flags & IFF_RUNNING)
 				bfe_set_rx_mode(sc);
 			break;
 		case SIOCGIFMEDIA:
 		case SIOCSIFMEDIA:
 			mii = device_get_softc(sc->bfe_miibus);
 			error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
 			break;
 		default:
 			error = ether_ioctl(ifp, command, data); 
 			break;
 	}
 
 	BFE_UNLOCK(sc);
 	return error;
 }
 
 static void
 bfe_watchdog(struct ifnet *ifp)
 {
 	struct bfe_softc *sc;
 
 	sc = ifp->if_softc;
 
 	BFE_LOCK(sc);
 
 	printf("bfe%d: watchdog timeout -- resetting\n", sc->bfe_unit);
 
 	ifp->if_flags &= ~IFF_RUNNING;
 	bfe_init(sc);
 
 	ifp->if_oerrors++;
 
 	BFE_UNLOCK(sc);
 }
 
 static void
 bfe_tick(void *xsc)
 {
 	struct bfe_softc *sc = xsc;
 	struct mii_data *mii;
 
 	if (sc == NULL)
 		return;
 
 	BFE_LOCK(sc);
 
 	mii = device_get_softc(sc->bfe_miibus);
 
 	bfe_stats_update(sc);
 	sc->bfe_stat_ch = timeout(bfe_tick, sc, hz);
 
 	if(sc->bfe_link) {
 		BFE_UNLOCK(sc);
 		return;
 	}
 
 	mii_tick(mii);
 	if (!sc->bfe_link && mii->mii_media_status & IFM_ACTIVE &&
 			IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) 
 		sc->bfe_link++;
 
 	BFE_UNLOCK(sc);
 }
 
 /*
  * Stop the adapter and free any mbufs allocated to the
  * RX and TX lists.
  */
 static void
 bfe_stop(struct bfe_softc *sc)
 {
 	struct ifnet *ifp;
 
 	BFE_LOCK(sc);
 
 	untimeout(bfe_tick, sc, sc->bfe_stat_ch);
 
 	ifp = &sc->arpcom.ac_if;
 
 	bfe_chip_halt(sc);
     bfe_tx_ring_free(sc);
 	bfe_rx_ring_free(sc);
 
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 
 	BFE_UNLOCK(sc);
 }
 
 --------------090505010100030000050608--

From: Jianqin Qu <jqu@its.brooklyn.cuny.edu>
To: freebsd-gnats-submit@freebsd.org
Cc:  
Subject: Re: i386/64656: Bugs with Ethernet driver "bfe"[patch] 
Date: Mon, 10 May 2004 10:44:16 -0400 (EDT)

   This message is in MIME format.  The first part should be readable text,
   while the remaining parts are likely unreadable without MIME-aware tools.
   Send mail to mime@docserver.cac.washington.edu for more info.
 
 ---559023410-851401618-1084200166=:27340
 Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
 Content-ID: <Pine.GSO.4.58.0405101043181.27383@atrium67.its.brooklyn.cuny.edu>
 
 Sorry, the wrong files were ataached to last message. The correct
 files for patches are attached to this message.
 
 Jianqin
 ---559023410-851401618-1084200166=:27340
 Content-Type: TEXT/PLAIN; CHARSET=US-ASCII; NAME="bfe521.patch"
 Content-Transfer-Encoding: BASE64
 Content-ID: <Pine.GSO.4.58.0405101042460.27340@atrium67.its.brooklyn.cuny.edu>
 Content-Description: 
 Content-Disposition: ATTACHMENT; FILENAME="bfe521.patch"
 
 LS0tIC91c3Ivc3JjL3N5cy9kZXYvYmZlL2lmX2JmZS5jCVNhdCBOb3YgMTUg
 MDM6MDA6MzAgMjAwMw0KKysrIGlmX2JmZS5jCVR1ZSBNYXkgIDYgMTU6Mjc6
 MjcgMjAwMw0KQEAgLTczMyw3ICs3MzMsMTIgQEANCiAJCURFTEFZKDEwMCk7
 DQogCX0NCiANCi0JQkZFX09SKHNjLCBCRkVfTUFDX0NUUkwsIEJGRV9DVFJM
 X0NSQzMyX0VOQUIpOw0KKwkvKiBFbmFibGUgQ1JDMzIgZ2VuZXJhdGlvbiBh
 bmQgc2V0IHByb3BlciBMRUQgbW9kZXMgKi8NCisJQkZFX09SKHNjLCBCRkVf
 TUFDX0NUUkwsIEJGRV9DVFJMX0NSQzMyX0VOQUIgfCBCRkVfQ1RSTF9MRUQp
 Ow0KKw0KKwkvKiBSZXNldC9DbGVhciBwb3dlcmRvd24gYml0ICAqLw0KKwlC
 RkVfQU5EKHNjLCBCRkVfTUFDX0NUUkwsIH5CRkVfQ1RSTF9QRE9XTik7DQor
 DQogCUNTUl9XUklURV80KHNjLCBCRkVfUkNWX0xBWlksICgoMSA8PCBCRkVf
 TEFaWV9GQ19TSElGVCkgJiANCiAJCQkJQkZFX0xBWllfRkNfTUFTSykpOw0K
 IA0KQEAgLTgzNSw3ICs4NDAsNyBAQA0KIAkJCSgoKHVfaW50MzJfdCkgZGF0
 YVsxXSkpKTsNCiAJQ1NSX1dSSVRFXzQoc2MsIEJGRV9DQU1fREFUQV9ISSwg
 dmFsKTsNCiAJQ1NSX1dSSVRFXzQoc2MsIEJGRV9DQU1fQ1RSTCwgKEJGRV9D
 QU1fV1JJVEUgfA0KLQkJCQkoaW5kZXggPDwgQkZFX0NBTV9JTkRFWF9TSElG
 VCkpKTsNCisJCQkJKCh1X2ludDMyX3QpIGluZGV4IDw8IEJGRV9DQU1fSU5E
 RVhfU0hJRlQpKSk7DQogCWJmZV93YWl0X2JpdChzYywgQkZFX0NBTV9DVFJM
 LCBCRkVfQ0FNX0JVU1ksIDEwMDAwLCAxKTsNCiB9DQogDQo=
 
 ---559023410-851401618-1084200166=:27340
 Content-Type: TEXT/PLAIN; CHARSET=US-ASCII; NAME="if_bfe.c"
 Content-Transfer-Encoding: BASE64
 Content-ID: <Pine.GSO.4.58.0405101042461.27340@atrium67.its.brooklyn.cuny.edu>
 Content-Description: 
 Content-Disposition: ATTACHMENT; FILENAME="if_bfe.c"
 
 LyoNCiAqIENvcHlyaWdodCAoYykgMjAwMyBTdHVhcnQgV2Fsc2g8c3R1QGlw
 bmcub3JnLnVrPg0KICogYW5kIER1bmNhbiBCYXJjbGF5PGRtbGJAZG1sYi5v
 cmc+DQogKi8NCg0KLyoNCiAqIFJlZGlzdHJpYnV0aW9uIGFuZCB1c2UgaW4g
 c291cmNlIGFuZCBiaW5hcnkgZm9ybXMsIHdpdGggb3Igd2l0aG91dA0KICog
 bW9kaWZpY2F0aW9uLCBhcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhl
 IGZvbGxvd2luZyBjb25kaXRpb25zDQogKiBhcmUgbWV0Og0KICogMS4gUmVk
 aXN0cmlidXRpb25zIG9mIHNvdXJjZSBjb2RlIG11c3QgcmV0YWluIHRoZSBh
 Ym92ZSBjb3B5cmlnaHQNCiAqICAgIG5vdGljZSwgdGhpcyBsaXN0IG9mIGNv
 bmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lci4NCiAqIDIu
 IFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVj
 ZSB0aGUgYWJvdmUgY29weXJpZ2h0DQogKiAgICBub3RpY2UsIHRoaXMgbGlz
 dCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIg
 aW4gdGhlDQogKiAgICBkb2N1bWVudGF0aW9uIGFuZC9vciBvdGhlciBtYXRl
 cmlhbHMgcHJvdmlkZWQgd2l0aCB0aGUgZGlzdHJpYnV0aW9uLg0KICoNCiAq
 IFRISVMgU09GVFdBUkUgSVMgUFJPVklERUQgQlkgVEhFIEFVVEhPUiBBTkQg
 Q09OVFJJQlVUT1JTICdBUyBJUycgQU5EDQogKiBBTlkgRVhQUkVTUyBPUiBJ
 TVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVE
 IFRPLCBUSEUNCiAqIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFC
 SUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFDQog
 KiBBUkUgRElTQ0xBSU1FRC4gIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRI
 T1IgT1IgQ09OVFJJQlVUT1JTIEJFIExJQUJMRQ0KICogRk9SIEFOWSBESVJF
 Q1QsIElORElSRUNULCBJTkNJREVOVEFMLCBTUEVDSUFMLCBFWEVNUExBUlks
 IE9SIENPTlNFUVVFTlRJQUwNCiAqIERBTUFHRVMgKElOQ0xVRElORywgQlVU
 IE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdP
 T0RTDQogKiBPUiBTRVJWSUNFUzsgTE9TUyBPRiBVU0UsIERBVEEsIE9SIFBS
 T0ZJVFM7IE9SIEJVU0lORVNTIElOVEVSUlVQVElPTikNCiAqIEhPV0VWRVIg
 Q0FVU0VEIEFORCBPTiBBTlkgVEhFT1JZIE9GIExJQUJJTElUWSwgV0hFVEhF
 UiBJTiBDT05UUkFDVCwgU1RSSUNUDQogKiBMSUFCSUxJVFksIE9SIFRPUlQg
 KElOQ0xVRElORyBORUdMSUdFTkNFIE9SIE9USEVSV0lTRSkgQVJJU0lORyBJ
 TiBBTlkgV0FZDQogKiBPVVQgT0YgVEhFIFVTRSBPRiBUSElTIFNPRlRXQVJF
 LCBFVkVOIElGIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GDQogKiBT
 VUNIIERBTUFHRS4NCiAqLw0KDQoNCiNpbmNsdWRlIDxzeXMvY2RlZnMuaD4N
 Cl9fRkJTRElEKCIkRnJlZUJTRDogc3JjL3N5cy9kZXYvYmZlL2lmX2JmZS5j
 LHYgMS40IDIwMDMvMTEvMTQgMTk6MDA6MzAgc2FtIEV4cCAkIik7DQoNCiNp
 bmNsdWRlIDxzeXMvcGFyYW0uaD4NCiNpbmNsdWRlIDxzeXMvc3lzdG0uaD4N
 CiNpbmNsdWRlIDxzeXMvc29ja2lvLmg+DQojaW5jbHVkZSA8c3lzL21idWYu
 aD4NCiNpbmNsdWRlIDxzeXMvbWFsbG9jLmg+DQojaW5jbHVkZSA8c3lzL2tl
 cm5lbC5oPg0KI2luY2x1ZGUgPHN5cy9zb2NrZXQuaD4NCiNpbmNsdWRlIDxz
 eXMvcXVldWUuaD4NCg0KI2luY2x1ZGUgPG5ldC9pZi5oPg0KI2luY2x1ZGUg
 PG5ldC9pZl9hcnAuaD4NCiNpbmNsdWRlIDxuZXQvZXRoZXJuZXQuaD4NCiNp
 bmNsdWRlIDxuZXQvaWZfZGwuaD4NCiNpbmNsdWRlIDxuZXQvaWZfbWVkaWEu
 aD4NCg0KI2luY2x1ZGUgPG5ldC9icGYuaD4NCg0KI2luY2x1ZGUgPG5ldC9p
 Zl90eXBlcy5oPg0KI2luY2x1ZGUgPG5ldC9pZl92bGFuX3Zhci5oPg0KDQoj
 aW5jbHVkZSA8bmV0aW5ldC9pbl9zeXN0bS5oPg0KI2luY2x1ZGUgPG5ldGlu
 ZXQvaW4uaD4NCiNpbmNsdWRlIDxuZXRpbmV0L2lwLmg+DQoNCiNpbmNsdWRl
 IDxtYWNoaW5lL2Nsb2NrLmg+ICAgICAgLyogZm9yIERFTEFZICovDQojaW5j
 bHVkZSA8bWFjaGluZS9idXNfbWVtaW8uaD4NCiNpbmNsdWRlIDxtYWNoaW5l
 L2J1cy5oPg0KI2luY2x1ZGUgPG1hY2hpbmUvcmVzb3VyY2UuaD4NCiNpbmNs
 dWRlIDxzeXMvYnVzLmg+DQojaW5jbHVkZSA8c3lzL3JtYW4uaD4NCg0KI2lu
 Y2x1ZGUgPGRldi9taWkvbWlpLmg+DQojaW5jbHVkZSA8ZGV2L21paS9taWl2
 YXIuaD4NCiNpbmNsdWRlICJtaWlkZXZzLmgiDQoNCiNpbmNsdWRlIDxkZXYv
 cGNpL3BjaXJlZy5oPg0KI2luY2x1ZGUgPGRldi9wY2kvcGNpdmFyLmg+DQoN
 CiNpbmNsdWRlIDxkZXYvYmZlL2lmX2JmZXJlZy5oPg0KDQpNT0RVTEVfREVQ
 RU5EKGJmZSwgcGNpLCAxLCAxLCAxKTsNCk1PRFVMRV9ERVBFTkQoYmZlLCBl
 dGhlciwgMSwgMSwgMSk7DQpNT0RVTEVfREVQRU5EKGJmZSwgbWlpYnVzLCAx
 LCAxLCAxKTsNCg0KLyogImNvbnRyb2xsZXIgbWlpYnVzMCIgcmVxdWlyZWQu
 ICBTZWUgR0VORVJJQyBpZiB5b3UgZ2V0IGVycm9ycyBoZXJlLiAqLw0KI2lu
 Y2x1ZGUgIm1paWJ1c19pZi5oIg0KDQojZGVmaW5lIEJGRV9ERVZERVNDX01B
 WAkJNjQJLyogTWF4aW11bSBkZXZpY2UgZGVzY3JpcHRpb24gbGVuZ3RoICov
 DQoNCnN0YXRpYyBzdHJ1Y3QgYmZlX3R5cGUgYmZlX2RldnNbXSA9IHsNCgl7
 IEJDT01fVkVORE9SSUQsIEJDT01fREVWSUNFSURfQkNNNDQwMSwNCgkJIkJy
 b2FkY29tIEJDTTQ0MDEgRmFzdCBFdGhlcm5ldCIgfSwNCgkJeyAwLCAwLCBO
 VUxMIH0NCn07DQoNCnN0YXRpYyBpbnQgIGJmZV9wcm9iZQkJCQkoZGV2aWNl
 X3QpOw0Kc3RhdGljIGludCAgYmZlX2F0dGFjaAkJCQkoZGV2aWNlX3QpOw0K
 c3RhdGljIGludCAgYmZlX2RldGFjaAkJCQkoZGV2aWNlX3QpOw0Kc3RhdGlj
 IHZvaWQgYmZlX3JlbGVhc2VfcmVzb3VyY2VzCShzdHJ1Y3QgYmZlX3NvZnRj
 ICopOw0Kc3RhdGljIHZvaWQgYmZlX2ludHIJCQkJKHZvaWQgKik7DQpzdGF0
 aWMgdm9pZCBiZmVfc3RhcnQJCQkJKHN0cnVjdCBpZm5ldCAqKTsNCnN0YXRp
 YyBpbnQgIGJmZV9pb2N0bAkJCQkoc3RydWN0IGlmbmV0ICosIHVfbG9uZywg
 Y2FkZHJfdCk7DQpzdGF0aWMgdm9pZCBiZmVfaW5pdAkJCQkodm9pZCAqKTsN
 CnN0YXRpYyB2b2lkIGJmZV9zdG9wCQkJCShzdHJ1Y3QgYmZlX3NvZnRjICop
 Ow0Kc3RhdGljIHZvaWQgYmZlX3dhdGNoZG9nCQkJKHN0cnVjdCBpZm5ldCAq
 KTsNCnN0YXRpYyB2b2lkIGJmZV9zaHV0ZG93bgkJCShkZXZpY2VfdCk7DQpz
 dGF0aWMgdm9pZCBiZmVfdGljawkJCQkodm9pZCAqKTsNCnN0YXRpYyB2b2lk
 IGJmZV90eGVvZgkJCQkoc3RydWN0IGJmZV9zb2Z0YyAqKTsNCnN0YXRpYyB2
 b2lkIGJmZV9yeGVvZgkJCQkoc3RydWN0IGJmZV9zb2Z0YyAqKTsNCnN0YXRp
 YyB2b2lkIGJmZV9zZXRfcnhfbW9kZQkJCShzdHJ1Y3QgYmZlX3NvZnRjICop
 Ow0Kc3RhdGljIGludCAgYmZlX2xpc3RfcnhfaW5pdAkJKHN0cnVjdCBiZmVf
 c29mdGMgKik7DQpzdGF0aWMgaW50ICBiZmVfbGlzdF9uZXdidWYJCQkoc3Ry
 dWN0IGJmZV9zb2Z0YyAqLCBpbnQsIHN0cnVjdCBtYnVmKik7DQpzdGF0aWMg
 dm9pZCBiZmVfcnhfcmluZ19mcmVlCQkoc3RydWN0IGJmZV9zb2Z0YyAqKTsN
 Cg0Kc3RhdGljIHZvaWQgYmZlX3BjaV9zZXR1cAkJCShzdHJ1Y3QgYmZlX3Nv
 ZnRjICosIHVfaW50MzJfdCk7DQpzdGF0aWMgaW50ICBiZmVfaWZtZWRpYV91
 cGQJCQkoc3RydWN0IGlmbmV0ICopOw0Kc3RhdGljIHZvaWQgYmZlX2lmbWVk
 aWFfc3RzCQkJKHN0cnVjdCBpZm5ldCAqLCBzdHJ1Y3QgaWZtZWRpYXJlcSAq
 KTsNCnN0YXRpYyBpbnQgIGJmZV9taWlidXNfcmVhZHJlZwkJKGRldmljZV90
 LCBpbnQsIGludCk7DQpzdGF0aWMgaW50ICBiZmVfbWlpYnVzX3dyaXRlcmVn
 CQkoZGV2aWNlX3QsIGludCwgaW50LCBpbnQpOw0Kc3RhdGljIHZvaWQgYmZl
 X21paWJ1c19zdGF0Y2hnCQkoZGV2aWNlX3QpOw0Kc3RhdGljIGludCAgYmZl
 X3dhaXRfYml0CQkJKHN0cnVjdCBiZmVfc29mdGMgKiwgdV9pbnQzMl90LCB1
 X2ludDMyX3QsIA0KCQl1X2xvbmcsIGNvbnN0IGludCk7DQpzdGF0aWMgdm9p
 ZCBiZmVfZ2V0X2NvbmZpZwkJCShzdHJ1Y3QgYmZlX3NvZnRjICpzYyk7DQpz
 dGF0aWMgdm9pZCBiZmVfcmVhZF9lZXByb20JCQkoc3RydWN0IGJmZV9zb2Z0
 YyAqLCB1X2ludDhfdCAqKTsNCnN0YXRpYyB2b2lkIGJmZV9zdGF0c191cGRh
 dGUJCShzdHJ1Y3QgYmZlX3NvZnRjICopOw0Kc3RhdGljIHZvaWQgYmZlX2Ns
 ZWFyX3N0YXRzCQkJKHN0cnVjdCBiZmVfc29mdGMgKik7DQpzdGF0aWMgaW50
 ICBiZmVfcmVhZHBoeQkJCQkoc3RydWN0IGJmZV9zb2Z0YyAqLCB1X2ludDMy
 X3QsIHVfaW50MzJfdCopOw0Kc3RhdGljIGludCAgYmZlX3dyaXRlcGh5CQkJ
 KHN0cnVjdCBiZmVfc29mdGMgKiwgdV9pbnQzMl90LCB1X2ludDMyX3QpOw0K
 c3RhdGljIGludCAgYmZlX3Jlc2V0cGh5CQkJKHN0cnVjdCBiZmVfc29mdGMg
 Kik7DQpzdGF0aWMgaW50ICBiZmVfc2V0dXBwaHkJCQkoc3RydWN0IGJmZV9z
 b2Z0YyAqKTsNCnN0YXRpYyB2b2lkIGJmZV9jaGlwX3Jlc2V0CQkJKHN0cnVj
 dCBiZmVfc29mdGMgKik7DQpzdGF0aWMgdm9pZCBiZmVfY2hpcF9oYWx0CQkJ
 KHN0cnVjdCBiZmVfc29mdGMgKik7DQpzdGF0aWMgdm9pZCBiZmVfY29yZV9y
 ZXNldAkJCShzdHJ1Y3QgYmZlX3NvZnRjICopOw0Kc3RhdGljIHZvaWQgYmZl
 X2NvcmVfZGlzYWJsZQkJKHN0cnVjdCBiZmVfc29mdGMgKik7DQpzdGF0aWMg
 aW50ICBiZmVfZG1hX2FsbG9jCQkJKGRldmljZV90KTsNCnN0YXRpYyB2b2lk
 IGJmZV9kbWFfbWFwX2Rlc2MJCSh2b2lkICosIGJ1c19kbWFfc2VnbWVudF90
 ICosIGludCwgaW50KTsNCnN0YXRpYyB2b2lkIGJmZV9kbWFfbWFwCQkJCSh2
 b2lkICosIGJ1c19kbWFfc2VnbWVudF90ICosIGludCwgaW50KTsNCnN0YXRp
 YyB2b2lkIGJmZV9jYW1fd3JpdGUJCQkoc3RydWN0IGJmZV9zb2Z0YyAqLCB1
 X2NoYXIgKiwgaW50KTsNCg0Kc3RhdGljIGRldmljZV9tZXRob2RfdCBiZmVf
 bWV0aG9kc1tdID0gew0KCS8qIERldmljZSBpbnRlcmZhY2UgKi8NCglERVZN
 RVRIT0QoZGV2aWNlX3Byb2JlLAkJYmZlX3Byb2JlKSwNCglERVZNRVRIT0Qo
 ZGV2aWNlX2F0dGFjaCwJYmZlX2F0dGFjaCksDQoJREVWTUVUSE9EKGRldmlj
 ZV9kZXRhY2gsCWJmZV9kZXRhY2gpLA0KCURFVk1FVEhPRChkZXZpY2Vfc2h1
 dGRvd24sCWJmZV9zaHV0ZG93biksDQoNCgkvKiBidXMgaW50ZXJmYWNlICov
 DQoJREVWTUVUSE9EKGJ1c19wcmludF9jaGlsZCwJYnVzX2dlbmVyaWNfcHJp
 bnRfY2hpbGQpLA0KCURFVk1FVEhPRChidXNfZHJpdmVyX2FkZGVkLAlidXNf
 Z2VuZXJpY19kcml2ZXJfYWRkZWQpLA0KDQoJLyogTUlJIGludGVyZmFjZSAq
 Lw0KCURFVk1FVEhPRChtaWlidXNfcmVhZHJlZywJYmZlX21paWJ1c19yZWFk
 cmVnKSwNCglERVZNRVRIT0QobWlpYnVzX3dyaXRlcmVnLAliZmVfbWlpYnVz
 X3dyaXRlcmVnKSwNCglERVZNRVRIT0QobWlpYnVzX3N0YXRjaGcsCWJmZV9t
 aWlidXNfc3RhdGNoZyksDQoNCgl7IDAsIDAgfQ0KfTsNCg0Kc3RhdGljIGRy
 aXZlcl90IGJmZV9kcml2ZXIgPSB7DQoJImJmZSIsDQoJYmZlX21ldGhvZHMs
 DQoJc2l6ZW9mKHN0cnVjdCBiZmVfc29mdGMpDQp9Ow0KDQpzdGF0aWMgZGV2
 Y2xhc3NfdCBiZmVfZGV2Y2xhc3M7DQoNCkRSSVZFUl9NT0RVTEUoYmZlLCBw
 Y2ksIGJmZV9kcml2ZXIsIGJmZV9kZXZjbGFzcywgMCwgMCk7DQpEUklWRVJf
 TU9EVUxFKG1paWJ1cywgYmZlLCBtaWlidXNfZHJpdmVyLCBtaWlidXNfZGV2
 Y2xhc3MsIDAsIDApOw0KDQovKg0KICogUHJvYmUgZm9yIGEgQnJvYWRjb20g
 NDQwMSBjaGlwLiANCiAqLw0Kc3RhdGljIGludA0KYmZlX3Byb2JlKGRldmlj
 ZV90IGRldikNCnsNCglzdHJ1Y3QgYmZlX3R5cGUgKnQ7DQoJc3RydWN0IGJm
 ZV9zb2Z0YyAqc2M7DQoNCgl0ID0gYmZlX2RldnM7DQoNCglzYyA9IGRldmlj
 ZV9nZXRfc29mdGMoZGV2KTsNCgliemVybyhzYywgc2l6ZW9mKHN0cnVjdCBi
 ZmVfc29mdGMpKTsNCglzYy0+YmZlX3VuaXQgPSBkZXZpY2VfZ2V0X3VuaXQo
 ZGV2KTsNCglzYy0+YmZlX2RldiA9IGRldjsNCg0KCXdoaWxlKHQtPmJmZV9u
 YW1lICE9IE5VTEwpIHsNCgkJaWYgKChwY2lfZ2V0X3ZlbmRvcihkZXYpID09
 IHQtPmJmZV92aWQpICYmDQoJCQkJKHBjaV9nZXRfZGV2aWNlKGRldikgPT0g
 dC0+YmZlX2RpZCkpIHsNCgkJCWRldmljZV9zZXRfZGVzY19jb3B5KGRldiwg
 dC0+YmZlX25hbWUpOw0KCQkJcmV0dXJuKDApOw0KCQl9DQoJCXQrKzsNCgl9
 DQoNCglyZXR1cm4oRU5YSU8pOw0KfQ0KDQpzdGF0aWMgaW50DQpiZmVfZG1h
 X2FsbG9jKGRldmljZV90IGRldikNCnsNCglzdHJ1Y3QgYmZlX3NvZnRjICpz
 YzsNCglpbnQgZXJyb3IsIGk7DQoNCglzYyA9IGRldmljZV9nZXRfc29mdGMo
 ZGV2KTsNCg0KCS8qIHBhcmVudCB0YWcgKi8NCgllcnJvciA9IGJ1c19kbWFf
 dGFnX2NyZWF0ZShOVUxMLCAgLyogcGFyZW50ICovDQoJCQlQQUdFX1NJWkUs
 IDAsICAgICAgICAgICAgIC8qIGFsaWdubWVudCwgYm91bmRhcnkgKi8NCgkJ
 CUJVU19TUEFDRV9NQVhBRERSLCAgICAgICAgLyogbG93YWRkciAqLyAgICAg
 IA0KCQkJQlVTX1NQQUNFX01BWEFERFJfMzJCSVQsICAvKiBoaWdoYWRkciAq
 Lw0KCQkJTlVMTCwgTlVMTCwgICAgICAgICAgICAgICAvKiBmaWx0ZXIsIGZp
 bHRlcmFyZyAqLw0KCQkJTUFYQlNJWkUsICAgICAgICAgICAgICAgICAvKiBt
 YXhzaXplICovDQoJCQlCVVNfU1BBQ0VfVU5SRVNUUklDVEVELCAgIC8qIG51
 bSBvZiBzZWdtZW50cyAqLw0KCQkJQlVTX1NQQUNFX01BWFNJWkVfMzJCSVQs
 ICAvKiBtYXggc2VnbWVudCBzaXplICovDQoJCQlCVVNfRE1BX0FMTE9DTk9X
 LCAgICAgICAgIC8qIGZsYWdzICovDQoJCQlOVUxMLCBOVUxMLCAgICAgICAg
 ICAgICAgIC8qIGxvY2tmdW5jLCBsb2NrYXJnICovDQoJCQkmc2MtPmJmZV9w
 YXJlbnRfdGFnKTsNCg0KCS8qIHRhZyBmb3IgVFggcmluZyAqLw0KCWVycm9y
 ID0gYnVzX2RtYV90YWdfY3JlYXRlKHNjLT5iZmVfcGFyZW50X3RhZywgQkZF
 X1RYX0xJU1RfU0laRSwgDQoJCQlCRkVfVFhfTElTVF9TSVpFLCBCVVNfU1BB
 Q0VfTUFYQUREUiwgIEJVU19TUEFDRV9NQVhBRERSLCANCgkJCU5VTEwsIE5V
 TEwsIEJGRV9UWF9MSVNUX1NJWkUsIDEsICBCVVNfU1BBQ0VfTUFYU0laRV8z
 MkJJVCwNCgkJCTAsIE5VTEwsIE5VTEwsICZzYy0+YmZlX3R4X3RhZyk7DQoN
 CglpZiAoZXJyb3IpIHsNCgkJZGV2aWNlX3ByaW50ZihkZXYsICJjb3VsZCBu
 b3QgYWxsb2NhdGUgZG1hIHRhZ1xuIik7DQoJCXJldHVybihFTk9NRU0pOw0K
 CX0NCg0KCS8qIHRhZyBmb3IgUlggcmluZyAqLw0KCWVycm9yID0gYnVzX2Rt
 YV90YWdfY3JlYXRlKHNjLT5iZmVfcGFyZW50X3RhZywgQkZFX1JYX0xJU1Rf
 U0laRSwgDQoJCQlCRkVfUlhfTElTVF9TSVpFLCBCVVNfU1BBQ0VfTUFYQURE
 UiwgQlVTX1NQQUNFX01BWEFERFIsIA0KCQkJTlVMTCwgTlVMTCwgQkZFX1JY
 X0xJU1RfU0laRSwgMSwgQlVTX1NQQUNFX01BWFNJWkVfMzJCSVQsIA0KCQkJ
 MCwgTlVMTCwgTlVMTCwgJnNjLT5iZmVfcnhfdGFnKTsNCg0KCWlmIChlcnJv
 cikgew0KCQlkZXZpY2VfcHJpbnRmKGRldiwgImNvdWxkIG5vdCBhbGxvY2F0
 ZSBkbWEgdGFnXG4iKTsNCgkJcmV0dXJuKEVOT01FTSk7DQoJfQ0KDQoJLyog
 dGFnIGZvciBtYnVmcyAqLw0KCWVycm9yID0gYnVzX2RtYV90YWdfY3JlYXRl
 KHNjLT5iZmVfcGFyZW50X3RhZywgRVRIRVJfQUxJR04sIDAsDQoJCQlCVVNf
 U1BBQ0VfTUFYQUREUiwgQlVTX1NQQUNFX01BWEFERFIsIE5VTEwsIE5VTEws
 IE1DTEJZVEVTLCANCgkJCTEsIEJVU19TUEFDRV9NQVhTSVpFXzMyQklULCAw
 LCBOVUxMLCBOVUxMLCAmc2MtPmJmZV90YWcpOw0KDQoJaWYgKGVycm9yKSB7
 DQoJCWRldmljZV9wcmludGYoZGV2LCAiY291bGQgbm90IGFsbG9jYXRlIGRt
 YSB0YWdcbiIpOw0KCQlyZXR1cm4oRU5PTUVNKTsNCgl9DQoNCgkvKiBwcmUg
 YWxsb2NhdGUgZG1hbWFwcyBmb3IgUlggbGlzdCAqLw0KCWZvciAoaSA9IDA7
 IGkgPCBCRkVfUlhfTElTVF9DTlQ7IGkrKykgew0KCQllcnJvciA9IGJ1c19k
 bWFtYXBfY3JlYXRlKHNjLT5iZmVfdGFnLCAwLCAmc2MtPmJmZV9yeF9yaW5n
 W2ldLmJmZV9tYXApOw0KCQlpZiAoZXJyb3IpIHsNCgkJCWRldmljZV9wcmlu
 dGYoZGV2LCAiY2Fubm90IGNyZWF0ZSBETUEgbWFwIGZvciBSWFxuIik7DQoJ
 CQlyZXR1cm4oRU5PTUVNKTsNCgkJfQ0KCX0NCg0KCS8qIHByZSBhbGxvY2F0
 ZSBkbWFtYXBzIGZvciBUWCBsaXN0ICovDQoJZm9yIChpID0gMDsgaSA8IEJG
 RV9UWF9MSVNUX0NOVDsgaSsrKSB7DQoJCWVycm9yID0gYnVzX2RtYW1hcF9j
 cmVhdGUoc2MtPmJmZV90YWcsIDAsICZzYy0+YmZlX3R4X3JpbmdbaV0uYmZl
 X21hcCk7DQoJCWlmIChlcnJvcikgew0KCQkJZGV2aWNlX3ByaW50ZihkZXYs
 ICJjYW5ub3QgY3JlYXRlIERNQSBtYXAgZm9yIFRYXG4iKTsNCgkJCXJldHVy
 bihFTk9NRU0pOw0KCQl9DQoJfQ0KDQoJLyogQWxsb2MgZG1hIGZvciByeCBy
 aW5nICovDQoJZXJyb3IgPSBidXNfZG1hbWVtX2FsbG9jKHNjLT5iZmVfcnhf
 dGFnLCAodm9pZCAqKSZzYy0+YmZlX3J4X2xpc3QsDQoJCQlCVVNfRE1BX05P
 V0FJVCwgJnNjLT5iZmVfcnhfbWFwKTsNCg0KCWlmKGVycm9yKQ0KCQlyZXR1
 cm4oRU5PTUVNKTsNCg0KCWJ6ZXJvKHNjLT5iZmVfcnhfbGlzdCwgQkZFX1JY
 X0xJU1RfU0laRSk7DQoJZXJyb3IgPSBidXNfZG1hbWFwX2xvYWQoc2MtPmJm
 ZV9yeF90YWcsIHNjLT5iZmVfcnhfbWFwLA0KCQkJc2MtPmJmZV9yeF9saXN0
 LCBzaXplb2Yoc3RydWN0IGJmZV9kZXNjKSwNCgkJCWJmZV9kbWFfbWFwLCAm
 c2MtPmJmZV9yeF9kbWEsIDApOw0KDQoJaWYoZXJyb3IpDQoJCXJldHVybihF
 Tk9NRU0pOw0KDQoJYnVzX2RtYW1hcF9zeW5jKHNjLT5iZmVfcnhfdGFnLCBz
 Yy0+YmZlX3J4X21hcCwgQlVTX0RNQVNZTkNfUFJFUkVBRCk7DQoNCgllcnJv
 ciA9IGJ1c19kbWFtZW1fYWxsb2Moc2MtPmJmZV90eF90YWcsICh2b2lkICop
 JnNjLT5iZmVfdHhfbGlzdCwgDQoJCQlCVVNfRE1BX05PV0FJVCwgJnNjLT5i
 ZmVfdHhfbWFwKTsNCglpZiAoZXJyb3IpIA0KCQlyZXR1cm4oRU5PTUVNKTsN
 Cg0KDQoJZXJyb3IgPSBidXNfZG1hbWFwX2xvYWQoc2MtPmJmZV90eF90YWcs
 IHNjLT5iZmVfdHhfbWFwLCANCgkJCXNjLT5iZmVfdHhfbGlzdCwgc2l6ZW9m
 KHN0cnVjdCBiZmVfZGVzYyksIA0KCQkJYmZlX2RtYV9tYXAsICZzYy0+YmZl
 X3R4X2RtYSwgMCk7DQoJaWYoZXJyb3IpDQoJCXJldHVybihFTk9NRU0pOw0K
 DQoJYnplcm8oc2MtPmJmZV90eF9saXN0LCBCRkVfVFhfTElTVF9TSVpFKTsN
 CglidXNfZG1hbWFwX3N5bmMoc2MtPmJmZV90eF90YWcsIHNjLT5iZmVfdHhf
 bWFwLCBCVVNfRE1BU1lOQ19QUkVSRUFEKTsNCg0KCXJldHVybigwKTsNCn0N
 Cg0Kc3RhdGljIGludA0KYmZlX2F0dGFjaChkZXZpY2VfdCBkZXYpDQp7DQoJ
 c3RydWN0IGlmbmV0ICppZnA7DQoJc3RydWN0IGJmZV9zb2Z0YyAqc2M7DQoJ
 aW50IHVuaXQsIGVycm9yID0gMCwgcmlkOw0KDQoJc2MgPSBkZXZpY2VfZ2V0
 X3NvZnRjKGRldik7DQoJbXR4X2luaXQoJnNjLT5iZmVfbXR4LCBkZXZpY2Vf
 Z2V0X25hbWV1bml0KGRldiksIE1UWF9ORVRXT1JLX0xPQ0ssDQoJCQlNVFhf
 REVGIHwgTVRYX1JFQ1VSU0UpOw0KDQoJdW5pdCA9IGRldmljZV9nZXRfdW5p
 dChkZXYpOw0KCXNjLT5iZmVfZGV2ID0gZGV2Ow0KCXNjLT5iZmVfdW5pdCA9
 IHVuaXQ7DQoNCgkvKg0KCSAqIEhhbmRsZSBwb3dlciBtYW5hZ2VtZW50IG5v
 bnNlbnNlLg0KCSAqLw0KCWlmIChwY2lfZ2V0X3Bvd2Vyc3RhdGUoZGV2KSAh
 PSBQQ0lfUE9XRVJTVEFURV9EMCkgew0KCQl1X2ludDMyX3QgbWVtYmFzZSwg
 aXJxOw0KDQoJCS8qIFNhdmUgaW1wb3J0YW50IFBDSSBjb25maWcgZGF0YS4g
 Ki8NCgkJbWVtYmFzZSA9IHBjaV9yZWFkX2NvbmZpZyhkZXYsIEJGRV9QQ0lf
 TUVNTE8sIDQpOw0KCQlpcnEgPSBwY2lfcmVhZF9jb25maWcoZGV2LCBCRkVf
 UENJX0lOVExJTkUsIDQpOw0KDQoJCS8qIFJlc2V0IHRoZSBwb3dlciBzdGF0
 ZS4gKi8NCgkJcHJpbnRmKCJiZmUlZDogY2hpcCBpcyBpcyBpbiBEJWQgcG93
 ZXIgbW9kZSAtLSBzZXR0aW5nIHRvIEQwXG4iLCANCgkJCQlzYy0+YmZlX3Vu
 aXQsIHBjaV9nZXRfcG93ZXJzdGF0ZShkZXYpKTsNCg0KCQlwY2lfc2V0X3Bv
 d2Vyc3RhdGUoZGV2LCBQQ0lfUE9XRVJTVEFURV9EMCk7DQoNCgkJLyogUmVz
 dG9yZSBQQ0kgY29uZmlnIGRhdGEuICovDQoJCXBjaV93cml0ZV9jb25maWco
 ZGV2LCBCRkVfUENJX01FTUxPLCBtZW1iYXNlLCA0KTsNCgkJcGNpX3dyaXRl
 X2NvbmZpZyhkZXYsIEJGRV9QQ0lfSU5UTElORSwgaXJxLCA0KTsNCgl9DQoN
 CgkvKg0KCSAqIE1hcCBjb250cm9sL3N0YXR1cyByZWdpc3RlcnMuDQoJICov
 DQoJcGNpX2VuYWJsZV9idXNtYXN0ZXIoZGV2KTsNCg0KCXJpZCA9IEJGRV9Q
 Q0lfTUVNTE87DQoJc2MtPmJmZV9yZXMgPSBidXNfYWxsb2NfcmVzb3VyY2Uo
 ZGV2LCBTWVNfUkVTX01FTU9SWSwgJnJpZCwgMCwgfjAsIDEsIA0KCQkJUkZf
 QUNUSVZFKTsNCglpZiAoc2MtPmJmZV9yZXMgPT0gTlVMTCkgew0KCQlwcmlu
 dGYgKCJiZmUlZDogY291bGRuJ3QgbWFwIG1lbW9yeVxuIiwgdW5pdCk7DQoJ
 CWVycm9yID0gRU5YSU87DQoJCWdvdG8gZmFpbDsNCgl9DQoNCglzYy0+YmZl
 X2J0YWcgPSBybWFuX2dldF9idXN0YWcoc2MtPmJmZV9yZXMpOw0KCXNjLT5i
 ZmVfYmhhbmRsZSA9IHJtYW5fZ2V0X2J1c2hhbmRsZShzYy0+YmZlX3Jlcyk7
 DQoJc2MtPmJmZV92aGFuZGxlID0gKHZtX29mZnNldF90KXJtYW5fZ2V0X3Zp
 cnR1YWwoc2MtPmJmZV9yZXMpOw0KDQoJLyogQWxsb2NhdGUgaW50ZXJydXB0
 ICovDQoJcmlkID0gMDsNCg0KCXNjLT5iZmVfaXJxID0gYnVzX2FsbG9jX3Jl
 c291cmNlKGRldiwgU1lTX1JFU19JUlEsICZyaWQsIDAsIH4wLCAxLA0KCQkJ
 UkZfU0hBUkVBQkxFIHwgUkZfQUNUSVZFKTsNCglpZiAoc2MtPmJmZV9pcnEg
 PT0gTlVMTCkgew0KCQlwcmludGYoImJmZSVkOiBjb3VsZG4ndCBtYXAgaW50
 ZXJydXB0XG4iLCB1bml0KTsNCgkJZXJyb3IgPSBFTlhJTzsNCgkJZ290byBm
 YWlsOw0KCX0NCg0KCWlmIChiZmVfZG1hX2FsbG9jKGRldikpIHsNCgkJcHJp
 bnRmKCJiZmUlZDogZmFpbGVkIHRvIGFsbG9jYXRlIERNQSByZXNvdXJjZXNc
 biIsIHNjLT5iZmVfdW5pdCk7DQoJCWJmZV9yZWxlYXNlX3Jlc291cmNlcyhz
 Yyk7DQoJCWVycm9yID0gRU5YSU87DQoJCWdvdG8gZmFpbDsNCgl9DQoNCgkv
 KiBTZXQgdXAgaWZuZXQgc3RydWN0dXJlICovDQoJaWZwID0gJnNjLT5hcnBj
 b20uYWNfaWY7DQoJaWZwLT5pZl9zb2Z0YyA9IHNjOw0KCWlmX2luaXRuYW1l
 KGlmcCwgZGV2aWNlX2dldF9uYW1lKGRldiksIGRldmljZV9nZXRfdW5pdChk
 ZXYpKTsNCglpZnAtPmlmX2ZsYWdzID0gSUZGX0JST0FEQ0FTVCB8IElGRl9T
 SU1QTEVYIHwgSUZGX01VTFRJQ0FTVDsNCglpZnAtPmlmX2lvY3RsID0gYmZl
 X2lvY3RsOw0KCWlmcC0+aWZfb3V0cHV0ID0gZXRoZXJfb3V0cHV0Ow0KCWlm
 cC0+aWZfc3RhcnQgPSBiZmVfc3RhcnQ7DQoJaWZwLT5pZl93YXRjaGRvZyA9
 IGJmZV93YXRjaGRvZzsNCglpZnAtPmlmX2luaXQgPSBiZmVfaW5pdDsNCglp
 ZnAtPmlmX210dSA9IEVUSEVSTVRVOw0KCWlmcC0+aWZfYmF1ZHJhdGUgPSAx
 MDAwMDAwMDsNCglpZnAtPmlmX3NuZC5pZnFfbWF4bGVuID0gQkZFX1RYX1FM
 RU47DQoNCgliZmVfZ2V0X2NvbmZpZyhzYyk7DQoNCglwcmludGYoImJmZSVk
 OiBFdGhlcm5ldCBhZGRyZXNzOiAlNkRcbiIsIHVuaXQsIHNjLT5hcnBjb20u
 YWNfZW5hZGRyLCAiOiIpOw0KDQoJLyogUmVzZXQgdGhlIGNoaXAgYW5kIHR1
 cm4gb24gdGhlIFBIWSAqLw0KCWJmZV9jaGlwX3Jlc2V0KHNjKTsNCg0KCWlm
 IChtaWlfcGh5X3Byb2JlKGRldiwgJnNjLT5iZmVfbWlpYnVzLA0KCQkJCWJm
 ZV9pZm1lZGlhX3VwZCwgYmZlX2lmbWVkaWFfc3RzKSkgew0KCQlwcmludGYo
 ImJmZSVkOiBNSUkgd2l0aG91dCBhbnkgUEhZIVxuIiwgc2MtPmJmZV91bml0
 KTsNCgkJZXJyb3IgPSBFTlhJTzsNCgkJZ290byBmYWlsOw0KCX0NCg0KCWV0
 aGVyX2lmYXR0YWNoKGlmcCwgc2MtPmFycGNvbS5hY19lbmFkZHIpOw0KCWNh
 bGxvdXRfaGFuZGxlX2luaXQoJnNjLT5iZmVfc3RhdF9jaCk7DQoNCgkvKg0K
 CSAqIEhvb2sgaW50ZXJydXB0IGxhc3QgdG8gYXZvaWQgaGF2aW5nIHRvIGxv
 Y2sgc29mdGMNCgkgKi8NCgllcnJvciA9IGJ1c19zZXR1cF9pbnRyKGRldiwg
 c2MtPmJmZV9pcnEsIElOVFJfVFlQRV9ORVQsDQoJCQliZmVfaW50ciwgc2Ms
 ICZzYy0+YmZlX2ludHJoYW5kKTsNCg0KCWlmIChlcnJvcikgew0KCQliZmVf
 cmVsZWFzZV9yZXNvdXJjZXMoc2MpOw0KCQlwcmludGYoImJmZSVkOiBjb3Vs
 ZG4ndCBzZXQgdXAgaXJxXG4iLCB1bml0KTsNCgkJZ290byBmYWlsOw0KCX0N
 CmZhaWw6DQoJaWYoZXJyb3IpDQoJCWJmZV9yZWxlYXNlX3Jlc291cmNlcyhz
 Yyk7DQoJcmV0dXJuKGVycm9yKTsNCn0NCg0Kc3RhdGljIGludA0KYmZlX2Rl
 dGFjaChkZXZpY2VfdCBkZXYpDQp7DQoJc3RydWN0IGJmZV9zb2Z0YyAqc2M7
 DQoJc3RydWN0IGlmbmV0ICppZnA7DQoNCglzYyA9IGRldmljZV9nZXRfc29m
 dGMoZGV2KTsNCg0KCUtBU1NFUlQobXR4X2luaXRpYWxpemVkKCZzYy0+YmZl
 X210eCksICgiYmZlIG11dGV4IG5vdCBpbml0aWFsaXplZCIpKTsNCglCRkVf
 TE9DSyhzY3ApOw0KDQoJaWZwID0gJnNjLT5hcnBjb20uYWNfaWY7DQoNCglp
 ZiAoZGV2aWNlX2lzX2F0dGFjaGVkKGRldikpIHsNCgkJYmZlX3N0b3Aoc2Mp
 Ow0KCQlldGhlcl9pZmRldGFjaChpZnApOw0KCX0NCg0KCWJmZV9jaGlwX3Jl
 c2V0KHNjKTsNCg0KCWJ1c19nZW5lcmljX2RldGFjaChkZXYpOw0KCWlmKHNj
 LT5iZmVfbWlpYnVzICE9IE5VTEwpDQoJCWRldmljZV9kZWxldGVfY2hpbGQo
 ZGV2LCBzYy0+YmZlX21paWJ1cyk7DQoNCgliZmVfcmVsZWFzZV9yZXNvdXJj
 ZXMoc2MpOw0KCUJGRV9VTkxPQ0soc2MpOw0KCW10eF9kZXN0cm95KCZzYy0+
 YmZlX210eCk7DQoNCglyZXR1cm4oMCk7DQp9DQoNCi8qDQogKiBTdG9wIGFs
 bCBjaGlwIEkvTyBzbyB0aGF0IHRoZSBrZXJuZWwncyBwcm9iZSByb3V0aW5l
 cyBkb24ndA0KICogZ2V0IGNvbmZ1c2VkIGJ5IGVycmFudCBETUFzIHdoZW4g
 cmVib290aW5nLg0KICovDQpzdGF0aWMgdm9pZA0KYmZlX3NodXRkb3duKGRl
 dmljZV90IGRldikNCnsNCglzdHJ1Y3QgYmZlX3NvZnRjICpzYzsNCg0KCXNj
 ID0gZGV2aWNlX2dldF9zb2Z0YyhkZXYpOw0KCUJGRV9MT0NLKHNjKTsNCgli
 ZmVfc3RvcChzYyk7IA0KDQoJQkZFX1VOTE9DSyhzYyk7DQoJcmV0dXJuOw0K
 fQ0KDQpzdGF0aWMgaW50DQpiZmVfbWlpYnVzX3JlYWRyZWcoZGV2aWNlX3Qg
 ZGV2LCBpbnQgcGh5LCBpbnQgcmVnKQ0Kew0KCXN0cnVjdCBiZmVfc29mdGMg
 KnNjOw0KCXVfaW50MzJfdCByZXQ7DQoNCglzYyA9IGRldmljZV9nZXRfc29m
 dGMoZGV2KTsNCglpZihwaHkgIT0gc2MtPmJmZV9waHlhZGRyKQ0KCQlyZXR1
 cm4oMCk7DQoJYmZlX3JlYWRwaHkoc2MsIHJlZywgJnJldCk7DQoNCglyZXR1
 cm4ocmV0KTsNCn0NCg0Kc3RhdGljIGludA0KYmZlX21paWJ1c193cml0ZXJl
 ZyhkZXZpY2VfdCBkZXYsIGludCBwaHksIGludCByZWcsIGludCB2YWwpDQp7
 DQoJc3RydWN0IGJmZV9zb2Z0YyAqc2M7DQoNCglzYyA9IGRldmljZV9nZXRf
 c29mdGMoZGV2KTsNCglpZihwaHkgIT0gc2MtPmJmZV9waHlhZGRyKQ0KCQly
 ZXR1cm4oMCk7DQoJYmZlX3dyaXRlcGh5KHNjLCByZWcsIHZhbCk7IA0KDQoJ
 cmV0dXJuKDApOw0KfQ0KDQpzdGF0aWMgdm9pZA0KYmZlX21paWJ1c19zdGF0
 Y2hnKGRldmljZV90IGRldikNCnsNCglyZXR1cm47DQp9DQoNCnN0YXRpYyB2
 b2lkDQpiZmVfdHhfcmluZ19mcmVlKHN0cnVjdCBiZmVfc29mdGMgKnNjKQ0K
 ew0KICAgIGludCBpOw0KICAgIA0KICAgIGZvcihpID0gMDsgaSA8IEJGRV9U
 WF9MSVNUX0NOVDsgaSsrKSB7DQogICAgICAgIGlmKHNjLT5iZmVfdHhfcmlu
 Z1tpXS5iZmVfbWJ1ZiAhPSBOVUxMKSB7DQogICAgICAgICAgICBtX2ZyZWVt
 KHNjLT5iZmVfdHhfcmluZ1tpXS5iZmVfbWJ1Zik7DQogICAgICAgICAgICBz
 Yy0+YmZlX3R4X3JpbmdbaV0uYmZlX21idWYgPSBOVUxMOw0KICAgICAgICAg
 ICAgYnVzX2RtYW1hcF91bmxvYWQoc2MtPmJmZV90YWcsDQogICAgICAgICAg
 ICAgICAgICAgIHNjLT5iZmVfdHhfcmluZ1tpXS5iZmVfbWFwKTsNCiAgICAg
 ICAgICAgIGJ1c19kbWFtYXBfZGVzdHJveShzYy0+YmZlX3RhZywNCiAgICAg
 ICAgICAgICAgICAgICAgc2MtPmJmZV90eF9yaW5nW2ldLmJmZV9tYXApOw0K
 ICAgICAgICB9DQogICAgfQ0KICAgIGJ6ZXJvKHNjLT5iZmVfdHhfbGlzdCwg
 QkZFX1RYX0xJU1RfU0laRSk7DQogICAgYnVzX2RtYW1hcF9zeW5jKHNjLT5i
 ZmVfdHhfdGFnLCBzYy0+YmZlX3R4X21hcCwgQlVTX0RNQVNZTkNfUFJFUkVB
 RCk7DQp9DQoNCnN0YXRpYyB2b2lkDQpiZmVfcnhfcmluZ19mcmVlKHN0cnVj
 dCBiZmVfc29mdGMgKnNjKQ0Kew0KCWludCBpOw0KDQoJZm9yIChpID0gMDsg
 aSA8IEJGRV9SWF9MSVNUX0NOVDsgaSsrKSB7DQoJCWlmIChzYy0+YmZlX3J4
 X3JpbmdbaV0uYmZlX21idWYgIT0gTlVMTCkgew0KCQkJbV9mcmVlbShzYy0+
 YmZlX3J4X3JpbmdbaV0uYmZlX21idWYpOw0KCQkJc2MtPmJmZV9yeF9yaW5n
 W2ldLmJmZV9tYnVmID0gTlVMTDsNCgkJCWJ1c19kbWFtYXBfdW5sb2FkKHNj
 LT5iZmVfdGFnLA0KCQkJCQlzYy0+YmZlX3J4X3JpbmdbaV0uYmZlX21hcCk7
 DQoJCQlidXNfZG1hbWFwX2Rlc3Ryb3koc2MtPmJmZV90YWcsDQoJCQkJCXNj
 LT5iZmVfcnhfcmluZ1tpXS5iZmVfbWFwKTsNCgkJfQ0KCX0NCgliemVybyhz
 Yy0+YmZlX3J4X2xpc3QsIEJGRV9SWF9MSVNUX1NJWkUpOw0KCWJ1c19kbWFt
 YXBfc3luYyhzYy0+YmZlX3J4X3RhZywgc2MtPmJmZV9yeF9tYXAsIEJVU19E
 TUFTWU5DX1BSRVJFQUQpOw0KfQ0KDQoNCnN0YXRpYyBpbnQgDQpiZmVfbGlz
 dF9yeF9pbml0KHN0cnVjdCBiZmVfc29mdGMgKnNjKQ0Kew0KCWludCBpOw0K
 DQoJZm9yKGkgPSAwOyBpIDwgQkZFX1JYX0xJU1RfQ05UOyBpKyspIHsNCgkJ
 aWYoYmZlX2xpc3RfbmV3YnVmKHNjLCBpLCBOVUxMKSA9PSBFTk9CVUZTKSAN
 CgkJCXJldHVybiBFTk9CVUZTOw0KCX0NCg0KCWJ1c19kbWFtYXBfc3luYyhz
 Yy0+YmZlX3J4X3RhZywgc2MtPmJmZV9yeF9tYXAsIEJVU19ETUFTWU5DX1BS
 RVJFQUQpOw0KCUNTUl9XUklURV80KHNjLCBCRkVfRE1BUlhfUFRSLCAoaSAq
 IHNpemVvZihzdHJ1Y3QgYmZlX2Rlc2MpKSk7DQoNCglzYy0+YmZlX3J4X2Nv
 bnMgPSAwOw0KDQoJcmV0dXJuKDApOw0KfQ0KDQpzdGF0aWMgaW50DQpiZmVf
 bGlzdF9uZXdidWYoc3RydWN0IGJmZV9zb2Z0YyAqc2MsIGludCBjLCBzdHJ1
 Y3QgbWJ1ZiAqbSkNCnsNCglzdHJ1Y3QgYmZlX3J4aGVhZGVyICpyeF9oZWFk
 ZXI7DQoJc3RydWN0IGJmZV9kZXNjICpkOw0KCXN0cnVjdCBiZmVfZGF0YSAq
 cjsNCgl1X2ludDMyX3QgY3RybDsNCg0KCWlmICgoYyA8IDApIHx8IChjID49
 IEJGRV9SWF9MSVNUX0NOVCkpDQoJCXJldHVybihFSU5WQUwpOw0KDQoJaWYo
 bSA9PSBOVUxMKSB7DQoJCW0gPSBtX2dldGNsKE1fRE9OVFdBSVQsIE1UX0RB
 VEEsIE1fUEtUSERSKTsNCgkJaWYobSA9PSBOVUxMKQ0KCQkJcmV0dXJuKEVO
 T0JVRlMpOw0KCQltLT5tX2xlbiA9IG0tPm1fcGt0aGRyLmxlbiA9IE1DTEJZ
 VEVTOw0KCX0NCgllbHNlDQoJCW0tPm1fZGF0YSA9IG0tPm1fZXh0LmV4dF9i
 dWY7DQoNCglyeF9oZWFkZXIgPSBtdG9kKG0sIHN0cnVjdCBiZmVfcnhoZWFk
 ZXIgKik7DQoJcnhfaGVhZGVyLT5sZW4gPSAwOw0KCXJ4X2hlYWRlci0+Zmxh
 Z3MgPSAwOw0KDQoJLyogTWFwIHRoZSBtYnVmIGludG8gRE1BICovDQoJc2Mt
 PmJmZV9yeF9jbnQgPSBjOw0KCWQgPSAmc2MtPmJmZV9yeF9saXN0W2NdOw0K
 CXIgPSAmc2MtPmJmZV9yeF9yaW5nW2NdOw0KCWJ1c19kbWFtYXBfbG9hZChz
 Yy0+YmZlX3RhZywgci0+YmZlX21hcCwgbXRvZChtLCB2b2lkICopLCANCgkJ
 CU1DTEJZVEVTLCBiZmVfZG1hX21hcF9kZXNjLCBkLCAwKTsNCglidXNfZG1h
 bWFwX3N5bmMoc2MtPmJmZV90YWcsIHItPmJmZV9tYXAsIEJVU19ETUFTWU5D
 X1BSRVdSSVRFKTsNCg0KCWN0cmwgPSBFVEhFUl9NQVhfTEVOICsgMzI7DQoN
 CglpZihjID09IEJGRV9SWF9MSVNUX0NOVCAtIDEpDQoJCWN0cmwgfD0gQkZF
 X0RFU0NfRU9UOw0KDQoJZC0+YmZlX2N0cmwgPSBjdHJsOw0KCXItPmJmZV9t
 YnVmID0gbTsNCglidXNfZG1hbWFwX3N5bmMoc2MtPmJmZV9yeF90YWcsIHNj
 LT5iZmVfcnhfbWFwLCBCVVNfRE1BU1lOQ19QUkVSRUFEKTsNCglyZXR1cm4o
 MCk7DQp9DQoNCnN0YXRpYyB2b2lkDQpiZmVfZ2V0X2NvbmZpZyhzdHJ1Y3Qg
 YmZlX3NvZnRjICpzYykNCnsNCgl1X2ludDhfdCBlZXByb21bMTI4XTsNCg0K
 CWJmZV9yZWFkX2VlcHJvbShzYywgZWVwcm9tKTsNCg0KCXNjLT5hcnBjb20u
 YWNfZW5hZGRyWzBdID0gZWVwcm9tWzc5XTsNCglzYy0+YXJwY29tLmFjX2Vu
 YWRkclsxXSA9IGVlcHJvbVs3OF07DQoJc2MtPmFycGNvbS5hY19lbmFkZHJb
 Ml0gPSBlZXByb21bODFdOw0KCXNjLT5hcnBjb20uYWNfZW5hZGRyWzNdID0g
 ZWVwcm9tWzgwXTsNCglzYy0+YXJwY29tLmFjX2VuYWRkcls0XSA9IGVlcHJv
 bVs4M107DQoJc2MtPmFycGNvbS5hY19lbmFkZHJbNV0gPSBlZXByb21bODJd
 Ow0KDQoJc2MtPmJmZV9waHlhZGRyID0gZWVwcm9tWzkwXSAmIDB4MWY7DQoJ
 c2MtPmJmZV9tZGNfcG9ydCA9IChlZXByb21bOTBdID4+IDE0KSAmIDB4MTsN
 Cg0KCXNjLT5iZmVfY29yZV91bml0ID0gMDsgDQoJc2MtPmJmZV9kbWFfb2Zm
 c2V0ID0gQkZFX1BDSV9ETUE7DQp9DQoNCnN0YXRpYyB2b2lkDQpiZmVfcGNp
 X3NldHVwKHN0cnVjdCBiZmVfc29mdGMgKnNjLCB1X2ludDMyX3QgY29yZXMp
 DQp7DQoJdV9pbnQzMl90IGJhcl9vcmlnLCBwY2lfcmV2LCB2YWw7DQoNCgli
 YXJfb3JpZyA9IHBjaV9yZWFkX2NvbmZpZyhzYy0+YmZlX2RldiwgQkZFX0JB
 UjBfV0lOLCA0KTsNCglwY2lfd3JpdGVfY29uZmlnKHNjLT5iZmVfZGV2LCBC
 RkVfQkFSMF9XSU4sIEJGRV9SRUdfUENJLCA0KTsNCglwY2lfcmV2ID0gQ1NS
 X1JFQURfNChzYywgQkZFX1NCSURISUdIKSAmIEJGRV9SQ19NQVNLOw0KDQoJ
 dmFsID0gQ1NSX1JFQURfNChzYywgQkZFX1NCSU5UVkVDKTsNCgl2YWwgfD0g
 Y29yZXM7DQoJQ1NSX1dSSVRFXzQoc2MsIEJGRV9TQklOVFZFQywgdmFsKTsN
 Cg0KCXZhbCA9IENTUl9SRUFEXzQoc2MsIEJGRV9TU0JfUENJX1RSQU5TXzIp
 Ow0KCXZhbCB8PSBCRkVfU1NCX1BDSV9QUkVGIHwgQkZFX1NTQl9QQ0lfQlVS
 U1Q7DQoJQ1NSX1dSSVRFXzQoc2MsIEJGRV9TU0JfUENJX1RSQU5TXzIsIHZh
 bCk7DQoNCglwY2lfd3JpdGVfY29uZmlnKHNjLT5iZmVfZGV2LCBCRkVfQkFS
 MF9XSU4sIGJhcl9vcmlnLCA0KTsNCn0NCg0Kc3RhdGljIHZvaWQgDQpiZmVf
 Y2xlYXJfc3RhdHMoc3RydWN0IGJmZV9zb2Z0YyAqc2MpDQp7DQoJdV9sb25n
 IHJlZzsNCg0KCUJGRV9MT0NLKHNjKTsNCg0KCUNTUl9XUklURV80KHNjLCBC
 RkVfTUlCX0NUUkwsIEJGRV9NSUJfQ0xSX09OX1JFQUQpOw0KCWZvciAocmVn
 ID0gQkZFX1RYX0dPT0RfTzsgcmVnIDw9IEJGRV9UWF9QQVVTRTsgcmVnICs9
 IDQpDQoJCUNTUl9SRUFEXzQoc2MsIHJlZyk7DQoJZm9yIChyZWcgPSBCRkVf
 UlhfR09PRF9POyByZWcgPD0gQkZFX1JYX05QQVVTRTsgcmVnICs9IDQpDQoJ
 CUNTUl9SRUFEXzQoc2MsIHJlZyk7DQoNCglCRkVfVU5MT0NLKHNjKTsNCn0N
 Cg0Kc3RhdGljIGludCANCmJmZV9yZXNldHBoeShzdHJ1Y3QgYmZlX3NvZnRj
 ICpzYykNCnsNCgl1X2ludDMyX3QgdmFsOw0KDQoJQkZFX0xPQ0soc2MpOw0K
 CWJmZV93cml0ZXBoeShzYywgMCwgQk1DUl9SRVNFVCk7DQoJREVMQVkoMTAw
 KTsNCgliZmVfcmVhZHBoeShzYywgMCwgJnZhbCk7DQoJaWYgKHZhbCAmIEJN
 Q1JfUkVTRVQpIHsNCgkJcHJpbnRmKCJiZmUlZDogUEhZIFJlc2V0IHdvdWxk
 IG5vdCBjb21wbGV0ZS5cbiIsIHNjLT5iZmVfdW5pdCk7DQoJCUJGRV9VTkxP
 Q0soc2MpOw0KCQlyZXR1cm4gRU5YSU87DQoJfQ0KCUJGRV9VTkxPQ0soc2Mp
 Ow0KCXJldHVybiAwOw0KfQ0KDQpzdGF0aWMgdm9pZA0KYmZlX2NoaXBfaGFs
 dChzdHJ1Y3QgYmZlX3NvZnRjICpzYykNCnsNCglCRkVfTE9DSyhzYyk7DQoJ
 LyogZGlzYWJsZSBpbnRlcnJ1cHRzIC0gbm90IHRoYXQgaXQgYWN0dWFsbHkg
 ZG9lcy4uKi8NCglDU1JfV1JJVEVfNChzYywgQkZFX0lNQVNLLCAwKTsNCglD
 U1JfUkVBRF80KHNjLCBCRkVfSU1BU0spOw0KDQoJQ1NSX1dSSVRFXzQoc2Ms
 IEJGRV9FTkVUX0NUUkwsIEJGRV9FTkVUX0RJU0FCTEUpOw0KCWJmZV93YWl0
 X2JpdChzYywgQkZFX0VORVRfQ1RSTCwgQkZFX0VORVRfRElTQUJMRSwgMjAw
 LCAxKTsNCg0KCUNTUl9XUklURV80KHNjLCBCRkVfRE1BUlhfQ1RSTCwgMCk7
 DQoJQ1NSX1dSSVRFXzQoc2MsIEJGRV9ETUFUWF9DVFJMLCAwKTsNCglERUxB
 WSgxMCk7DQoNCglCRkVfVU5MT0NLKHNjKTsNCn0NCg0Kc3RhdGljIHZvaWQN
 CmJmZV9jaGlwX3Jlc2V0KHN0cnVjdCBiZmVfc29mdGMgKnNjKQ0Kew0KCXVf
 aW50MzJfdCB2YWw7ICAgIA0KDQoJQkZFX0xPQ0soc2MpOw0KDQoJLyogU2V0
 IHRoZSBpbnRlcnJ1cHQgdmVjdG9yIGZvciB0aGUgZW5ldCBjb3JlICovDQoJ
 YmZlX3BjaV9zZXR1cChzYywgQkZFX0lOVFZFQ19FTkVUMCk7DQoNCgkvKiBp
 cyBjb3JlIHVwPyAqLw0KCXZhbCA9IENTUl9SRUFEXzQoc2MsIEJGRV9TQlRN
 U0xPVykgJiAoQkZFX1JFU0VUIHwgQkZFX1JFSkVDVCB8IEJGRV9DTE9DSyk7
 DQoJaWYgKHZhbCA9PSBCRkVfQ0xPQ0spIHsNCgkJLyogSXQgaXMsIHNvIHNo
 dXQgaXQgZG93biAqLw0KCQlDU1JfV1JJVEVfNChzYywgQkZFX1JDVl9MQVpZ
 LCAwKTsNCgkJQ1NSX1dSSVRFXzQoc2MsIEJGRV9FTkVUX0NUUkwsIEJGRV9F
 TkVUX0RJU0FCTEUpOw0KCQliZmVfd2FpdF9iaXQoc2MsIEJGRV9FTkVUX0NU
 UkwsIEJGRV9FTkVUX0RJU0FCTEUsIDEwMCwgMSk7DQoJCUNTUl9XUklURV80
 KHNjLCBCRkVfRE1BVFhfQ1RSTCwgMCk7DQoJCXNjLT5iZmVfdHhfY250ID0g
 c2MtPmJmZV90eF9wcm9kID0gc2MtPmJmZV90eF9jb25zID0gMDsNCgkJaWYg
 KENTUl9SRUFEXzQoc2MsIEJGRV9ETUFSWF9TVEFUKSAmIEJGRV9TVEFUX0VN
 QVNLKSANCgkJCWJmZV93YWl0X2JpdChzYywgQkZFX0RNQVJYX1NUQVQsIEJG
 RV9TVEFUX1NJRExFLCAxMDAsIDApOw0KCQlDU1JfV1JJVEVfNChzYywgQkZF
 X0RNQVJYX0NUUkwsIDApOw0KCQlzYy0+YmZlX3J4X3Byb2QgPSBzYy0+YmZl
 X3J4X2NvbnMgPSAwOw0KCX0NCg0KCWJmZV9jb3JlX3Jlc2V0KHNjKTsNCgli
 ZmVfY2xlYXJfc3RhdHMoc2MpOw0KDQoJLyoNCgkgKiBXZSB3YW50IHRoZSBw
 aHkgcmVnaXN0ZXJzIHRvIGJlIGFjY2Vzc2libGUgZXZlbiB3aGVuDQoJICog
 dGhlIGRyaXZlciBpcyAiZG93bmVkIiBzbyBpbml0aWFsaXplIE1EQyBwcmVh
 bWJsZSwgZnJlcXVlbmN5LA0KCSAqIGFuZCB3aGV0aGVyIGludGVybmFsIG9y
 IGV4dGVybmFsIHBoeSBoZXJlLg0KCSAqLw0KDQoJLyogNDQwMiBoYXMgNjIu
 NU1oeiBTQiBjbG9jayBhbmQgaW50ZXJuYWwgcGh5ICovDQoJQ1NSX1dSSVRF
 XzQoc2MsIEJGRV9NRElPX0NUUkwsIDB4OGQpOw0KDQoJLyogSW50ZXJuYWwg
 b3IgZXh0ZXJuYWwgUEhZPyAqLw0KCXZhbCA9IENTUl9SRUFEXzQoc2MsIEJG
 RV9ERVZDVFJMKTsNCglpZighKHZhbCAmIEJGRV9JUFApKSANCgkJQ1NSX1dS
 SVRFXzQoc2MsIEJGRV9FTkVUX0NUUkwsIEJGRV9FTkVUX0VQU0VMKTsNCgll
 bHNlIGlmKENTUl9SRUFEXzQoc2MsIEJGRV9ERVZDVFJMKSAmIEJGRV9FUFIp
 IHsNCgkJQkZFX0FORChzYywgQkZFX0RFVkNUUkwsIH5CRkVfRVBSKTsNCgkJ
 REVMQVkoMTAwKTsNCgl9DQoNCgkvKiBFbmFibGUgQ1JDMzIgZ2VuZXJhdGlv
 biBhbmQgc2V0IHByb3BlciBMRUQgbW9kZXMgKi8NCglCRkVfT1Ioc2MsIEJG
 RV9NQUNfQ1RSTCwgQkZFX0NUUkxfQ1JDMzJfRU5BQiB8IEJGRV9DVFJMX0xF
 RCk7DQoNCgkvKiBSZXNldC9DbGVhciBwb3dlcmRvd24gYml0ICAqLw0KCUJG
 RV9BTkQoc2MsIEJGRV9NQUNfQ1RSTCwgfkJGRV9DVFJMX1BET1dOKTsNCg0K
 CUNTUl9XUklURV80KHNjLCBCRkVfUkNWX0xBWlksICgoMSA8PCBCRkVfTEFa
 WV9GQ19TSElGVCkgJiANCgkJCQlCRkVfTEFaWV9GQ19NQVNLKSk7DQoNCgkv
 KiANCgkgKiBXZSBkb24ndCB3YW50IGxhenkgaW50ZXJydXB0cywgc28ganVz
 dCBzZW5kIHRoZW0gYXQgdGhlIGVuZCBvZiBhIGZyYW1lLA0KCSAqIHBsZWFz
 ZSANCgkgKi8NCglCRkVfT1Ioc2MsIEJGRV9SQ1ZfTEFaWSwgMCk7DQoNCgkv
 KiBTZXQgbWF4IGxlbmd0aHMsIGFjY291bnRpbmcgZm9yIFZMQU4gdGFncyAq
 Lw0KCUNTUl9XUklURV80KHNjLCBCRkVfUlhNQVhMRU4sIEVUSEVSX01BWF9M
 RU4rMzIpOw0KCUNTUl9XUklURV80KHNjLCBCRkVfVFhNQVhMRU4sIEVUSEVS
 X01BWF9MRU4rMzIpOw0KDQoJLyogU2V0IHdhdGVybWFyayBYWFggLSBtYWdp
 YyAqLw0KCUNTUl9XUklURV80KHNjLCBCRkVfVFhfV01BUkssIDU2KTsNCg0K
 CS8qIA0KCSAqIEluaXRpYWxpc2UgRE1BIGNoYW5uZWxzIC0gbm90IGZvcmdl
 dHRpbmcgZG1hIGFkZHJlc3NlcyBuZWVkIHRvIGJlIGFkZGVkDQoJICogdG8g
 QkZFX1BDSV9ETUEgDQoJICovDQoJQ1NSX1dSSVRFXzQoc2MsIEJGRV9ETUFU
 WF9DVFJMLCBCRkVfVFhfQ1RSTF9FTkFCTEUpOw0KCUNTUl9XUklURV80KHNj
 LCBCRkVfRE1BVFhfQUREUiwgc2MtPmJmZV90eF9kbWEgKyBCRkVfUENJX0RN
 QSk7DQoNCglDU1JfV1JJVEVfNChzYywgQkZFX0RNQVJYX0NUUkwsIChCRkVf
 UlhfT0ZGU0VUIDw8IEJGRV9SWF9DVFJMX1JPU0hJRlQpIHwgDQoJCQlCRkVf
 UlhfQ1RSTF9FTkFCTEUpOw0KCUNTUl9XUklURV80KHNjLCBCRkVfRE1BUlhf
 QUREUiwgc2MtPmJmZV9yeF9kbWEgKyBCRkVfUENJX0RNQSk7DQoNCgliZmVf
 cmVzZXRwaHkoc2MpOw0KCWJmZV9zZXR1cHBoeShzYyk7DQoNCglCRkVfVU5M
 T0NLKHNjKTsNCn0NCg0Kc3RhdGljIHZvaWQNCmJmZV9jb3JlX2Rpc2FibGUo
 c3RydWN0IGJmZV9zb2Z0YyAqc2MpDQp7DQoJaWYoKENTUl9SRUFEXzQoc2Ms
 IEJGRV9TQlRNU0xPVykpICYgQkZFX1JFU0VUKQ0KCQlyZXR1cm47DQoNCgkv
 KiANCgkgKiBTZXQgcmVqZWN0LCB3YWl0IGZvciBpdCBzZXQsIHRoZW4gd2Fp
 dCBmb3IgdGhlIGNvcmUgdG8gc3RvcCBiZWluZyBidXN5DQoJICogVGhlbiBz
 ZXQgcmVzZXQgYW5kIHJlamVjdCBhbmQgZW5hYmxlIHRoZSBjbG9ja3MNCgkg
 Ki8NCglDU1JfV1JJVEVfNChzYywgQkZFX1NCVE1TTE9XLCAoQkZFX1JFSkVD
 VCB8IEJGRV9DTE9DSykpOw0KCWJmZV93YWl0X2JpdChzYywgQkZFX1NCVE1T
 TE9XLCBCRkVfUkVKRUNULCAxMDAwLCAwKTsNCgliZmVfd2FpdF9iaXQoc2Ms
 IEJGRV9TQlRNU0hJR0gsIEJGRV9CVVNZLCAxMDAwLCAxKTsNCglDU1JfV1JJ
 VEVfNChzYywgQkZFX1NCVE1TTE9XLCAoQkZFX0ZHQyB8IEJGRV9DTE9DSyB8
 IEJGRV9SRUpFQ1QgfA0KCQkJCUJGRV9SRVNFVCkpOw0KCUNTUl9SRUFEXzQo
 c2MsIEJGRV9TQlRNU0xPVyk7DQoJREVMQVkoMTApOw0KCS8qIExlYXZlIHJl
 c2V0IGFuZCByZWplY3Qgc2V0ICovDQoJQ1NSX1dSSVRFXzQoc2MsIEJGRV9T
 QlRNU0xPVywgKEJGRV9SRUpFQ1QgfCBCRkVfUkVTRVQpKTsNCglERUxBWSgx
 MCk7DQp9DQoNCnN0YXRpYyB2b2lkDQpiZmVfY29yZV9yZXNldChzdHJ1Y3Qg
 YmZlX3NvZnRjICpzYykNCnsNCgl1X2ludDMyX3QgdmFsOw0KDQoJLyogRGlz
 YWJsZSB0aGUgY29yZSAqLw0KCWJmZV9jb3JlX2Rpc2FibGUoc2MpOw0KDQoJ
 LyogYW5kIGJyaW5nIGl0IGJhY2sgdXAgKi8NCglDU1JfV1JJVEVfNChzYywg
 QkZFX1NCVE1TTE9XLCAoQkZFX1JFU0VUIHwgQkZFX0NMT0NLIHwgQkZFX0ZH
 QykpOw0KCUNTUl9SRUFEXzQoc2MsIEJGRV9TQlRNU0xPVyk7DQoJREVMQVko
 MTApOw0KDQoJLyogQ2hpcCBidWcsIGNsZWFyIFNFUlIsIElCIGFuZCBUTyBp
 ZiB0aGV5IGFyZSBzZXQuICovDQoJaWYgKENTUl9SRUFEXzQoc2MsIEJGRV9T
 QlRNU0hJR0gpICYgQkZFX1NFUlIpDQoJCUNTUl9XUklURV80KHNjLCBCRkVf
 U0JUTVNISUdILCAwKTsNCgl2YWwgPSBDU1JfUkVBRF80KHNjLCBCRkVfU0JJ
 TVNUQVRFKTsNCglpZiAodmFsICYgKEJGRV9JQkUgfCBCRkVfVE8pKQ0KCQlD
 U1JfV1JJVEVfNChzYywgQkZFX1NCSU1TVEFURSwgdmFsICYgfihCRkVfSUJF
 IHwgQkZFX1RPKSk7DQoNCgkvKiBDbGVhciByZXNldCBhbmQgYWxsb3cgaXQg
 dG8gbW92ZSB0aHJvdWdoIHRoZSBjb3JlICovDQoJQ1NSX1dSSVRFXzQoc2Ms
 IEJGRV9TQlRNU0xPVywgKEJGRV9DTE9DSyB8IEJGRV9GR0MpKTsNCglDU1Jf
 UkVBRF80KHNjLCBCRkVfU0JUTVNMT1cpOw0KCURFTEFZKDEwKTsNCg0KCS8q
 IExlYXZlIHRoZSBjbG9jayBzZXQgKi8NCglDU1JfV1JJVEVfNChzYywgQkZF
 X1NCVE1TTE9XLCBCRkVfQ0xPQ0spOw0KCUNTUl9SRUFEXzQoc2MsIEJGRV9T
 QlRNU0xPVyk7DQoJREVMQVkoMTApOw0KfQ0KDQpzdGF0aWMgdm9pZCANCmJm
 ZV9jYW1fd3JpdGUoc3RydWN0IGJmZV9zb2Z0YyAqc2MsIHVfY2hhciAqZGF0
 YSwgaW50IGluZGV4KQ0Kew0KCXVfaW50MzJfdCB2YWw7DQoNCgl2YWwgID0g
 KCh1X2ludDMyX3QpIGRhdGFbMl0pIDw8IDI0Ow0KCXZhbCB8PSAoKHVfaW50
 MzJfdCkgZGF0YVszXSkgPDwgMTY7DQoJdmFsIHw9ICgodV9pbnQzMl90KSBk
 YXRhWzRdKSA8PCAgODsNCgl2YWwgfD0gKCh1X2ludDMyX3QpIGRhdGFbNV0p
 Ow0KCUNTUl9XUklURV80KHNjLCBCRkVfQ0FNX0RBVEFfTE8sIHZhbCk7DQoJ
 dmFsID0gKEJGRV9DQU1fSElfVkFMSUQgfA0KCQkJKCgodV9pbnQzMl90KSBk
 YXRhWzBdKSA8PCA4KSB8DQoJCQkoKCh1X2ludDMyX3QpIGRhdGFbMV0pKSk7
 DQoJQ1NSX1dSSVRFXzQoc2MsIEJGRV9DQU1fREFUQV9ISSwgdmFsKTsNCglD
 U1JfV1JJVEVfNChzYywgQkZFX0NBTV9DVFJMLCAoQkZFX0NBTV9XUklURSB8
 DQoJCQkJKCh1X2ludDMyX3QpIGluZGV4IDw8IEJGRV9DQU1fSU5ERVhfU0hJ
 RlQpKSk7DQoJYmZlX3dhaXRfYml0KHNjLCBCRkVfQ0FNX0NUUkwsIEJGRV9D
 QU1fQlVTWSwgMTAwMDAsIDEpOw0KfQ0KDQpzdGF0aWMgdm9pZCANCmJmZV9z
 ZXRfcnhfbW9kZShzdHJ1Y3QgYmZlX3NvZnRjICpzYykNCnsNCglzdHJ1Y3Qg
 aWZuZXQgKmlmcCA9ICZzYy0+YXJwY29tLmFjX2lmOw0KCXN0cnVjdCBpZm11
 bHRpYWRkciAgKmlmbWE7DQoJdV9pbnQzMl90IHZhbDsNCglpbnQgaSA9IDA7
 DQoNCgl2YWwgPSBDU1JfUkVBRF80KHNjLCBCRkVfUlhDT05GKTsNCg0KCWlm
 IChpZnAtPmlmX2ZsYWdzICYgSUZGX1BST01JU0MpDQoJCXZhbCB8PSBCRkVf
 UlhDT05GX1BST01JU0M7DQoJZWxzZQ0KCQl2YWwgJj0gfkJGRV9SWENPTkZf
 UFJPTUlTQzsNCg0KCWlmIChpZnAtPmlmX2ZsYWdzICYgSUZGX0JST0FEQ0FT
 VCkNCgkJdmFsICY9IH5CRkVfUlhDT05GX0RCQ0FTVDsNCgllbHNlDQoJCXZh
 bCB8PSBCRkVfUlhDT05GX0RCQ0FTVDsNCg0KDQoJQ1NSX1dSSVRFXzQoc2Ms
 IEJGRV9DQU1fQ1RSTCwgMCk7DQoJYmZlX2NhbV93cml0ZShzYywgc2MtPmFy
 cGNvbS5hY19lbmFkZHIsIGkrKyk7DQoNCglpZiAoaWZwLT5pZl9mbGFncyAm
 IElGRl9BTExNVUxUSSkNCgkJdmFsIHw9IEJGRV9SWENPTkZfQUxMTVVMVEk7
 DQoJZWxzZSB7DQoJCXZhbCAmPSB+QkZFX1JYQ09ORl9BTExNVUxUSTsNCgkJ
 VEFJTFFfRk9SRUFDSChpZm1hLCAmaWZwLT5pZl9tdWx0aWFkZHJzLCBpZm1h
 X2xpbmspIHsNCgkJCWlmIChpZm1hLT5pZm1hX2FkZHItPnNhX2ZhbWlseSAh
 PSBBRl9MSU5LKQ0KCQkJCWNvbnRpbnVlOw0KCQkJYmZlX2NhbV93cml0ZShz
 YywgTExBRERSKChzdHJ1Y3Qgc29ja2FkZHJfZGwgKilpZm1hLT5pZm1hX2Fk
 ZHIpLA0KCQkJCQlpKyspOw0KCQl9DQoJfQ0KDQoJQ1NSX1dSSVRFXzQoc2Ms
 IEJGRV9SWENPTkYsIHZhbCk7DQoJQkZFX09SKHNjLCBCRkVfQ0FNX0NUUkws
 IEJGRV9DQU1fRU5BQkxFKTsNCn0NCg0Kc3RhdGljIHZvaWQNCmJmZV9kbWFf
 bWFwKHZvaWQgKmFyZywgYnVzX2RtYV9zZWdtZW50X3QgKnNlZ3MsIGludCBu
 c2VnLCBpbnQgZXJyb3IpDQp7DQoJdV9pbnQzMl90ICpwdHI7DQoNCglwdHIg
 PSBhcmc7DQoJKnB0ciA9IHNlZ3MtPmRzX2FkZHI7DQp9DQoNCnN0YXRpYyB2
 b2lkDQpiZmVfZG1hX21hcF9kZXNjKHZvaWQgKmFyZywgYnVzX2RtYV9zZWdt
 ZW50X3QgKnNlZ3MsIGludCBuc2VnLCBpbnQgZXJyb3IpDQp7DQoJc3RydWN0
 IGJmZV9kZXNjICpkOw0KDQoJZCA9IGFyZzsNCgkvKiBUaGUgY2hpcCBuZWVk
 cyBhbGwgYWRkcmVzc2VzIHRvIGJlIGFkZGVkIHRvIEJGRV9QQ0lfRE1BICov
 DQoJZC0+YmZlX2FkZHIgPSBzZWdzLT5kc19hZGRyICsgQkZFX1BDSV9ETUE7
 DQp9DQoNCnN0YXRpYyB2b2lkDQpiZmVfcmVsZWFzZV9yZXNvdXJjZXMoc3Ry
 dWN0IGJmZV9zb2Z0YyAqc2MpDQp7DQoJZGV2aWNlX3QgZGV2Ow0KCWludCBp
 Ow0KDQoJZGV2ID0gc2MtPmJmZV9kZXY7DQoNCglpZiAoc2MtPmJmZV92cGRf
 cHJvZG5hbWUgIT0gTlVMTCkNCgkJZnJlZShzYy0+YmZlX3ZwZF9wcm9kbmFt
 ZSwgTV9ERVZCVUYpOw0KDQoJaWYgKHNjLT5iZmVfdnBkX3JlYWRvbmx5ICE9
 IE5VTEwpDQoJCWZyZWUoc2MtPmJmZV92cGRfcmVhZG9ubHksIE1fREVWQlVG
 KTsNCg0KCWlmIChzYy0+YmZlX2ludHJoYW5kICE9IE5VTEwpDQoJCWJ1c190
 ZWFyZG93bl9pbnRyKGRldiwgc2MtPmJmZV9pcnEsIHNjLT5iZmVfaW50cmhh
 bmQpOw0KDQoJaWYgKHNjLT5iZmVfaXJxICE9IE5VTEwpDQoJCWJ1c19yZWxl
 YXNlX3Jlc291cmNlKGRldiwgU1lTX1JFU19JUlEsIDAsIHNjLT5iZmVfaXJx
 KTsNCg0KCWlmIChzYy0+YmZlX3JlcyAhPSBOVUxMKQ0KCQlidXNfcmVsZWFz
 ZV9yZXNvdXJjZShkZXYsIFNZU19SRVNfTUVNT1JZLCAweDEwLCBzYy0+YmZl
 X3Jlcyk7DQoNCglpZihzYy0+YmZlX3R4X3RhZyAhPSBOVUxMKSB7DQoJCWJ1
 c19kbWFtYXBfdW5sb2FkKHNjLT5iZmVfdHhfdGFnLCBzYy0+YmZlX3R4X21h
 cCk7DQoJCWJ1c19kbWFtZW1fZnJlZShzYy0+YmZlX3R4X3RhZywgc2MtPmJm
 ZV90eF9saXN0LCBzYy0+YmZlX3R4X21hcCk7DQoJCWJ1c19kbWFfdGFnX2Rl
 c3Ryb3koc2MtPmJmZV90eF90YWcpOw0KCQlzYy0+YmZlX3R4X3RhZyA9IE5V
 TEw7DQoJfQ0KDQoJaWYoc2MtPmJmZV9yeF90YWcgIT0gTlVMTCkgew0KCQli
 dXNfZG1hbWFwX3VubG9hZChzYy0+YmZlX3J4X3RhZywgc2MtPmJmZV9yeF9t
 YXApOw0KCQlidXNfZG1hbWVtX2ZyZWUoc2MtPmJmZV9yeF90YWcsIHNjLT5i
 ZmVfcnhfbGlzdCwgc2MtPmJmZV9yeF9tYXApOw0KCQlidXNfZG1hX3RhZ19k
 ZXN0cm95KHNjLT5iZmVfcnhfdGFnKTsNCgkJc2MtPmJmZV9yeF90YWcgPSBO
 VUxMOw0KCX0NCg0KCWlmKHNjLT5iZmVfdGFnICE9IE5VTEwpIHsNCgkJZm9y
 KGkgPSAwOyBpIDwgQkZFX1RYX0xJU1RfQ05UOyBpKyspIHsNCgkJCWJ1c19k
 bWFtYXBfZGVzdHJveShzYy0+YmZlX3RhZywgc2MtPmJmZV90eF9yaW5nW2ld
 LmJmZV9tYXApOw0KCQl9DQoJCWJ1c19kbWFfdGFnX2Rlc3Ryb3koc2MtPmJm
 ZV90YWcpOw0KICAgICAgICBzYy0+YmZlX3RhZyA9IE5VTEw7DQoJfQ0KDQoJ
 aWYoc2MtPmJmZV9wYXJlbnRfdGFnICE9IE5VTEwpDQoJCWJ1c19kbWFfdGFn
 X2Rlc3Ryb3koc2MtPmJmZV9wYXJlbnRfdGFnKTsNCg0KCXJldHVybjsNCn0N
 Cg0Kc3RhdGljIHZvaWQNCmJmZV9yZWFkX2VlcHJvbShzdHJ1Y3QgYmZlX3Nv
 ZnRjICpzYywgdV9pbnQ4X3QgKmRhdGEpDQp7DQoJbG9uZyBpOw0KCXVfaW50
 MTZfdCAqcHRyID0gKHVfaW50MTZfdCAqKWRhdGE7DQoNCglmb3IoaSA9IDA7
 IGkgPCAxMjg7IGkgKz0gMikNCgkJcHRyW2kvMl0gPSBDU1JfUkVBRF80KHNj
 LCA0MDk2ICsgaSk7DQp9DQoNCnN0YXRpYyBpbnQNCmJmZV93YWl0X2JpdChz
 dHJ1Y3QgYmZlX3NvZnRjICpzYywgdV9pbnQzMl90IHJlZywgdV9pbnQzMl90
 IGJpdCwgDQoJCXVfbG9uZyB0aW1lb3V0LCBjb25zdCBpbnQgY2xlYXIpDQp7
 DQoJdV9sb25nIGk7DQoNCglmb3IgKGkgPSAwOyBpIDwgdGltZW91dDsgaSsr
 KSB7DQoJCXVfaW50MzJfdCB2YWwgPSBDU1JfUkVBRF80KHNjLCByZWcpOw0K
 DQoJCWlmIChjbGVhciAmJiAhKHZhbCAmIGJpdCkpDQoJCQlicmVhazsNCgkJ
 aWYgKCFjbGVhciAmJiAodmFsICYgYml0KSkNCgkJCWJyZWFrOw0KCQlERUxB
 WSgxMCk7DQoJfQ0KCWlmIChpID09IHRpbWVvdXQpIHsNCgkJcHJpbnRmKCJi
 ZmUlZDogQlVHISAgVGltZW91dCB3YWl0aW5nIGZvciBiaXQgJTA4eCBvZiBy
 ZWdpc3RlciAiDQoJCQkJIiV4IHRvICVzLlxuIiwgc2MtPmJmZV91bml0LCBi
 aXQsIHJlZywgDQoJCQkJKGNsZWFyID8gImNsZWFyIiA6ICJzZXQiKSk7DQoJ
 CXJldHVybiAtMTsNCgl9DQoJcmV0dXJuIDA7DQp9DQoNCnN0YXRpYyBpbnQN
 CmJmZV9yZWFkcGh5KHN0cnVjdCBiZmVfc29mdGMgKnNjLCB1X2ludDMyX3Qg
 cmVnLCB1X2ludDMyX3QgKnZhbCkNCnsNCglpbnQgZXJyOyANCg0KCUJGRV9M
 T0NLKHNjKTsNCgkvKiBDbGVhciBNSUkgSVNSICovDQoJQ1NSX1dSSVRFXzQo
 c2MsIEJGRV9FTUFDX0lTVEFULCBCRkVfRU1BQ19JTlRfTUlJKTsNCglDU1Jf
 V1JJVEVfNChzYywgQkZFX01ESU9fREFUQSwgKEJGRV9NRElPX1NCX1NUQVJU
 IHwNCgkJCQkoQkZFX01ESU9fT1BfUkVBRCA8PCBCRkVfTURJT19PUF9TSElG
 VCkgfA0KCQkJCShzYy0+YmZlX3BoeWFkZHIgPDwgQkZFX01ESU9fUE1EX1NI
 SUZUKSB8DQoJCQkJKHJlZyA8PCBCRkVfTURJT19SQV9TSElGVCkgfA0KCQkJ
 CShCRkVfTURJT19UQV9WQUxJRCA8PCBCRkVfTURJT19UQV9TSElGVCkpKTsN
 CgllcnIgPSBiZmVfd2FpdF9iaXQoc2MsIEJGRV9FTUFDX0lTVEFULCBCRkVf
 RU1BQ19JTlRfTUlJLCAxMDAsIDApOw0KCSp2YWwgPSBDU1JfUkVBRF80KHNj
 LCBCRkVfTURJT19EQVRBKSAmIEJGRV9NRElPX0RBVEFfREFUQTsNCg0KCUJG
 RV9VTkxPQ0soc2MpOw0KCXJldHVybiBlcnI7DQp9DQoNCnN0YXRpYyBpbnQN
 CmJmZV93cml0ZXBoeShzdHJ1Y3QgYmZlX3NvZnRjICpzYywgdV9pbnQzMl90
 IHJlZywgdV9pbnQzMl90IHZhbCkNCnsNCglpbnQgc3RhdHVzOw0KDQoJQkZF
 X0xPQ0soc2MpOw0KCUNTUl9XUklURV80KHNjLCBCRkVfRU1BQ19JU1RBVCwg
 QkZFX0VNQUNfSU5UX01JSSk7DQoJQ1NSX1dSSVRFXzQoc2MsIEJGRV9NRElP
 X0RBVEEsIChCRkVfTURJT19TQl9TVEFSVCB8DQoJCQkJKEJGRV9NRElPX09Q
 X1dSSVRFIDw8IEJGRV9NRElPX09QX1NISUZUKSB8DQoJCQkJKHNjLT5iZmVf
 cGh5YWRkciA8PCBCRkVfTURJT19QTURfU0hJRlQpIHwNCgkJCQkocmVnIDw8
 IEJGRV9NRElPX1JBX1NISUZUKSB8DQoJCQkJKEJGRV9NRElPX1RBX1ZBTElE
 IDw8IEJGRV9NRElPX1RBX1NISUZUKSB8DQoJCQkJKHZhbCAmIEJGRV9NRElP
 X0RBVEFfREFUQSkpKTsNCglzdGF0dXMgPSBiZmVfd2FpdF9iaXQoc2MsIEJG
 RV9FTUFDX0lTVEFULCBCRkVfRU1BQ19JTlRfTUlJLCAxMDAsIDApOw0KCUJG
 RV9VTkxPQ0soc2MpOw0KDQoJcmV0dXJuIHN0YXR1czsNCn0NCg0KLyogDQog
 KiBYWFggLSBJIHRoaW5rIHRoaXMgaXMgaGFuZGxlZCBieSB0aGUgUEhZIGRy
 aXZlciwgYnV0IGl0IGNhbid0IGh1cnQgdG8gZG8gaXQNCiAqIHR3aWNlDQog
 Ki8NCnN0YXRpYyBpbnQNCmJmZV9zZXR1cHBoeShzdHJ1Y3QgYmZlX3NvZnRj
 ICpzYykNCnsNCgl1X2ludDMyX3QgdmFsOw0KCUJGRV9MT0NLKHNjKTsNCg0K
 CS8qIEVuYWJsZSBhY3Rpdml0eSBMRUQgKi8NCgliZmVfcmVhZHBoeShzYywg
 MjYsICZ2YWwpOw0KCWJmZV93cml0ZXBoeShzYywgMjYsIHZhbCAmIDB4N2Zm
 Zik7IA0KCWJmZV9yZWFkcGh5KHNjLCAyNiwgJnZhbCk7DQoNCgkvKiBFbmFi
 bGUgdHJhZmZpYyBtZXRlciBMRUQgbW9kZSAqLw0KCWJmZV9yZWFkcGh5KHNj
 LCAyNywgJnZhbCk7DQoJYmZlX3dyaXRlcGh5KHNjLCAyNywgdmFsIHwgKDEg
 PDwgNikpOw0KDQoJQkZFX1VOTE9DSyhzYyk7DQoJcmV0dXJuIDA7DQp9DQoN
 CnN0YXRpYyB2b2lkIA0KYmZlX3N0YXRzX3VwZGF0ZShzdHJ1Y3QgYmZlX3Nv
 ZnRjICpzYykNCnsNCgl1X2xvbmcgcmVnOw0KCXVfaW50MzJfdCAqdmFsOw0K
 DQoJdmFsID0gJnNjLT5iZmVfaHdzdGF0cy50eF9nb29kX29jdGV0czsNCglm
 b3IgKHJlZyA9IEJGRV9UWF9HT09EX087IHJlZyA8PSBCRkVfVFhfUEFVU0U7
 IHJlZyArPSA0KSB7DQoJCSp2YWwrKyArPSBDU1JfUkVBRF80KHNjLCByZWcp
 Ow0KCX0NCgl2YWwgPSAmc2MtPmJmZV9od3N0YXRzLnJ4X2dvb2Rfb2N0ZXRz
 Ow0KCWZvciAocmVnID0gQkZFX1JYX0dPT0RfTzsgcmVnIDw9IEJGRV9SWF9O
 UEFVU0U7IHJlZyArPSA0KSB7DQoJCSp2YWwrKyArPSBDU1JfUkVBRF80KHNj
 LCByZWcpOw0KCX0NCn0NCg0Kc3RhdGljIHZvaWQNCmJmZV90eGVvZihzdHJ1
 Y3QgYmZlX3NvZnRjICpzYykNCnsNCglzdHJ1Y3QgaWZuZXQgKmlmcDsNCglp
 bnQgaSwgY2hpcGlkeDsNCg0KCUJGRV9MT0NLKHNjKTsNCg0KCWlmcCA9ICZz
 Yy0+YXJwY29tLmFjX2lmOw0KDQoJY2hpcGlkeCA9IENTUl9SRUFEXzQoc2Ms
 IEJGRV9ETUFUWF9TVEFUKSAmIEJGRV9TVEFUX0NETUFTSzsNCgljaGlwaWR4
 IC89IHNpemVvZihzdHJ1Y3QgYmZlX2Rlc2MpOw0KDQogICAgaSA9IHNjLT5i
 ZmVfdHhfY29uczsNCgkvKiBHbyB0aHJvdWdoIHRoZSBtYnVmcyBhbmQgZnJl
 ZSB0aG9zZSB0aGF0IGhhdmUgYmVlbiB0cmFuc21pdHRlZCAqLw0KICAgIHdo
 aWxlKGkgIT0gY2hpcGlkeCkgew0KCQlzdHJ1Y3QgYmZlX2RhdGEgKnIgPSAm
 c2MtPmJmZV90eF9yaW5nW2ldOw0KCQlpZihyLT5iZmVfbWJ1ZiAhPSBOVUxM
 KSB7DQoJCQlpZnAtPmlmX29wYWNrZXRzKys7DQoJCQltX2ZyZWVtKHItPmJm
 ZV9tYnVmKTsNCgkJCXItPmJmZV9tYnVmID0gTlVMTDsNCgkJCWJ1c19kbWFt
 YXBfdW5sb2FkKHNjLT5iZmVfdGFnLCByLT5iZmVfbWFwKTsNCgkJfQ0KICAg
 ICAgICBzYy0+YmZlX3R4X2NudC0tOw0KICAgICAgICBCRkVfSU5DKGksIEJG
 RV9UWF9MSVNUX0NOVCk7DQoJfQ0KDQoJaWYoaSAhPSBzYy0+YmZlX3R4X2Nv
 bnMpIHsNCgkJLyogd2UgZnJlZWQgdXAgc29tZSBtYnVmcyAqLw0KCQlzYy0+
 YmZlX3R4X2NvbnMgPSBpOw0KCQlpZnAtPmlmX2ZsYWdzICY9IH5JRkZfT0FD
 VElWRTsNCgl9DQoJaWYoc2MtPmJmZV90eF9jbnQgPT0gMCkNCgkJaWZwLT5p
 Zl90aW1lciA9IDA7DQoJZWxzZQ0KCQlpZnAtPmlmX3RpbWVyID0gNTsNCg0K
 CUJGRV9VTkxPQ0soc2MpOw0KfQ0KDQovKiBQYXNzIGEgcmVjZWl2ZWQgcGFj
 a2V0IHVwIHRoZSBzdGFjayAqLw0Kc3RhdGljIHZvaWQNCmJmZV9yeGVvZihz
 dHJ1Y3QgYmZlX3NvZnRjICpzYykNCnsNCglzdHJ1Y3QgbWJ1ZiAqbTsNCglz
 dHJ1Y3QgaWZuZXQgKmlmcDsNCglzdHJ1Y3QgYmZlX3J4aGVhZGVyICpyeGhl
 YWRlcjsNCglzdHJ1Y3QgYmZlX2RhdGEgKnI7DQoJaW50IGNvbnM7DQoJdV9p
 bnQzMl90IHN0YXR1cywgY3VycmVudCwgbGVuLCBmbGFnczsNCg0KCUJGRV9M
 T0NLKHNjKTsNCgljb25zID0gc2MtPmJmZV9yeF9jb25zOw0KCXN0YXR1cyA9
 IENTUl9SRUFEXzQoc2MsIEJGRV9ETUFSWF9TVEFUKTsNCgljdXJyZW50ID0g
 KHN0YXR1cyAmIEJGRV9TVEFUX0NETUFTSykgLyBzaXplb2Yoc3RydWN0IGJm
 ZV9kZXNjKTsNCg0KCWlmcCA9ICZzYy0+YXJwY29tLmFjX2lmOw0KDQoJd2hp
 bGUoY3VycmVudCAhPSBjb25zKSB7DQoJCXIgPSAmc2MtPmJmZV9yeF9yaW5n
 W2NvbnNdOw0KCQltID0gci0+YmZlX21idWY7DQoJCXJ4aGVhZGVyID0gbXRv
 ZChtLCBzdHJ1Y3QgYmZlX3J4aGVhZGVyKik7DQoJCWJ1c19kbWFtYXBfc3lu
 YyhzYy0+YmZlX3RhZywgci0+YmZlX21hcCwgQlVTX0RNQVNZTkNfUE9TVFdS
 SVRFKTsNCgkJbGVuID0gcnhoZWFkZXItPmxlbjsNCgkJci0+YmZlX21idWYg
 PSBOVUxMOw0KDQoJCWJ1c19kbWFtYXBfdW5sb2FkKHNjLT5iZmVfdGFnLCBy
 LT5iZmVfbWFwKTsNCgkJZmxhZ3MgPSByeGhlYWRlci0+ZmxhZ3M7DQoNCgkJ
 bGVuIC09IEVUSEVSX0NSQ19MRU47DQoNCgkJLyogZmxhZyBhbiBlcnJvciBh
 bmQgdHJ5IGFnYWluICovDQoJCWlmICgobGVuID4gRVRIRVJfTUFYX0xFTisz
 MikgfHwgKGZsYWdzICYgQkZFX1JYX0ZMQUdfRVJST1JTKSkgew0KCQkJaWZw
 LT5pZl9pZXJyb3JzKys7DQoJCQlpZiAoZmxhZ3MgJiBCRkVfUlhfRkxBR19T
 RVJSKQ0KCQkJCWlmcC0+aWZfY29sbGlzaW9ucysrOw0KCQkJYmZlX2xpc3Rf
 bmV3YnVmKHNjLCBjb25zLCBtKTsNCgkJCWNvbnRpbnVlOw0KCQl9DQoNCgkJ
 LyogR28gcGFzdCB0aGUgcnggaGVhZGVyICovDQoJCWlmIChiZmVfbGlzdF9u
 ZXdidWYoc2MsIGNvbnMsIE5VTEwpID09IDApIHsNCgkJCW1fYWRqKG0sIEJG
 RV9SWF9PRkZTRVQpOw0KCQkJbS0+bV9sZW4gPSBtLT5tX3BrdGhkci5sZW4g
 PSBsZW47DQoJCX0gZWxzZSB7DQoJCQliZmVfbGlzdF9uZXdidWYoc2MsIGNv
 bnMsIG0pOw0KCQkJaWZwLT5pZl9pZXJyb3JzKys7DQoJCQljb250aW51ZTsN
 CgkJfQ0KDQoJCWlmcC0+aWZfaXBhY2tldHMrKzsNCgkJbS0+bV9wa3RoZHIu
 cmN2aWYgPSBpZnA7DQoJCUJGRV9VTkxPQ0soc2MpOw0KCQkoKmlmcC0+aWZf
 aW5wdXQpKGlmcCwgbSk7DQoJCUJGRV9MT0NLKHNjKTsNCg0KICAgICAgICBC
 RkVfSU5DKGNvbnMsIEJGRV9SWF9MSVNUX0NOVCk7DQoJfQ0KCXNjLT5iZmVf
 cnhfY29ucyA9IGNvbnM7DQoJQkZFX1VOTE9DSyhzYyk7DQp9DQoNCnN0YXRp
 YyB2b2lkDQpiZmVfaW50cih2b2lkICp4c2MpDQp7DQoJc3RydWN0IGJmZV9z
 b2Z0YyAqc2MgPSB4c2M7DQoJc3RydWN0IGlmbmV0ICppZnA7DQoJdV9pbnQz
 Ml90IGlzdGF0LCBpbWFzaywgZmxhZzsNCg0KCWlmcCA9ICZzYy0+YXJwY29t
 LmFjX2lmOw0KDQoJQkZFX0xPQ0soc2MpOw0KDQoJaXN0YXQgPSBDU1JfUkVB
 RF80KHNjLCBCRkVfSVNUQVQpOw0KCWltYXNrID0gQ1NSX1JFQURfNChzYywg
 QkZFX0lNQVNLKTsNCg0KCS8qIA0KCSAqIERlZmVyIHVuc29saWNpdGVkIGlu
 dGVycnVwdHMgLSBUaGlzIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIHNldHRpbmcg
 dGhlDQoJICogY2hpcHMgaW50ZXJydXB0IG1hc2sgcmVnaXN0ZXIgdG8gMCBk
 b2Vzbid0IGFjdHVhbGx5IHN0b3AgdGhlDQoJICogaW50ZXJydXB0cw0KCSAq
 Lw0KCWlzdGF0ICY9IGltYXNrOw0KCUNTUl9XUklURV80KHNjLCBCRkVfSVNU
 QVQsIGlzdGF0KTsNCglDU1JfUkVBRF80KHNjLCBCRkVfSVNUQVQpOw0KDQoJ
 Lyogbm90IGV4cGVjdGluZyB0aGlzIGludGVycnVwdCwgZGlzcmVnYXJkIGl0
 ICovDQoJaWYoaXN0YXQgPT0gMCkgew0KCQlCRkVfVU5MT0NLKHNjKTsNCgkJ
 cmV0dXJuOw0KCX0NCg0KCWlmKGlzdGF0ICYgQkZFX0lTVEFUX0VSUk9SUykg
 ew0KCQlmbGFnID0gQ1NSX1JFQURfNChzYywgQkZFX0RNQVRYX1NUQVQpOw0K
 CQlpZihmbGFnICYgQkZFX1NUQVRfRU1BU0spDQoJCQlpZnAtPmlmX29lcnJv
 cnMrKzsNCg0KCQlmbGFnID0gQ1NSX1JFQURfNChzYywgQkZFX0RNQVJYX1NU
 QVQpOw0KCQlpZihmbGFnICYgQkZFX1JYX0ZMQUdfRVJST1JTKQ0KCQkJaWZw
 LT5pZl9pZXJyb3JzKys7DQoNCgkJaWZwLT5pZl9mbGFncyAmPSB+SUZGX1JV
 Tk5JTkc7DQoJCWJmZV9pbml0KHNjKTsNCgl9DQoNCgkvKiBBIHBhY2tldCB3
 YXMgcmVjZWl2ZWQgKi8NCglpZihpc3RhdCAmIEJGRV9JU1RBVF9SWCkNCgkJ
 YmZlX3J4ZW9mKHNjKTsNCg0KCS8qIEEgcGFja2V0IHdhcyBzZW50ICovDQoJ
 aWYoaXN0YXQgJiBCRkVfSVNUQVRfVFgpDQoJCWJmZV90eGVvZihzYyk7DQoN
 CgkvKiBXZSBoYXZlIHBhY2tldHMgcGVuZGluZywgZmlyZSB0aGVtIG91dCAq
 LyANCglpZiAoaWZwLT5pZl9mbGFncyAmIElGRl9SVU5OSU5HICYmIGlmcC0+
 aWZfc25kLmlmcV9oZWFkICE9IE5VTEwpDQoJCWJmZV9zdGFydChpZnApOw0K
 DQoJQkZFX1VOTE9DSyhzYyk7DQp9DQoNCnN0YXRpYyBpbnQNCmJmZV9lbmNh
 cChzdHJ1Y3QgYmZlX3NvZnRjICpzYywgc3RydWN0IG1idWYgKm1faGVhZCwg
 dV9pbnQzMl90ICp0eGlkeCkNCnsNCglzdHJ1Y3QgYmZlX2Rlc2MgKmQgPSBO
 VUxMOw0KCXN0cnVjdCBiZmVfZGF0YSAqciA9IE5VTEw7DQoJc3RydWN0IG1i
 dWYgICAgICptOw0KCXVfaW50MzJfdCAgICAgICBmcmFnLCBjdXIsIGNudCA9
 IDA7DQoJaW50IGNoYWlubGVuID0gMDsNCg0KCWlmKEJGRV9UWF9MSVNUX0NO
 VCAtIHNjLT5iZmVfdHhfY250IDwgMikNCgkJcmV0dXJuKEVOT0JVRlMpOw0K
 DQoJLyoNCgkgKiBDb3VudCB0aGUgbnVtYmVyIG9mIGZyYWdzIGluIHRoaXMg
 Y2hhaW4gdG8gc2VlIGlmDQoJICogd2UgbmVlZCB0byBtX2RlZnJhZy4gIFNp
 bmNlIHRoZSBkZXNjcmlwdG9yIGxpc3QgaXMgc2hhcmVkDQoJICogYnkgYWxs
 IHBhY2tldHMsIHdlJ2xsIG1fZGVmcmFnIGxvbmcgY2hhaW5zIHNvIHRoYXQg
 dGhleQ0KCSAqIGRvIG5vdCB1c2UgdXAgdGhlIGVudGlyZSBsaXN0LCBldmVu
 IGlmIHRoZXkgd291bGQgZml0Lg0KCSAqLw0KCWZvcihtID0gbV9oZWFkOyBt
 ICE9IE5VTEw7IG0gPSBtLT5tX25leHQpIA0KCQljaGFpbmxlbisrOw0KDQoN
 CglpZiAoKGNoYWlubGVuID4gQkZFX1RYX0xJU1RfQ05UIC8gNCkgfHwgDQoJ
 CQkoKEJGRV9UWF9MSVNUX0NOVCAtIChjaGFpbmxlbiArIHNjLT5iZmVfdHhf
 Y250KSkgPCAyKSkgew0KCQltID0gbV9kZWZyYWcobV9oZWFkLCBNX0RPTlRX
 QUlUKTsNCgkJaWYgKG0gPT0gTlVMTCkgDQoJCQlyZXR1cm4oRU5PQlVGUyk7
 DQoJCW1faGVhZCA9IG07DQoJfQ0KDQoJLyoNCgkgKiBTdGFydCBwYWNraW5n
 IHRoZSBtYnVmcyBpbiB0aGlzIGNoYWluIGludG8NCgkgKiB0aGUgZnJhZ21l
 bnQgcG9pbnRlcnMuIFN0b3Agd2hlbiB3ZSBydW4gb3V0DQoJICogb2YgZnJh
 Z21lbnRzIG9yIGhpdCB0aGUgZW5kIG9mIHRoZSBtYnVmIGNoYWluLg0KCSAq
 Lw0KCW0gPSBtX2hlYWQ7DQoJY3VyID0gZnJhZyA9ICp0eGlkeDsNCgljbnQg
 PSAwOw0KDQoJZm9yKG0gPSBtX2hlYWQ7IG0gIT0gTlVMTDsgbSA9IG0tPm1f
 bmV4dCkgew0KCQlpZihtLT5tX2xlbiAhPSAwKSB7DQoJCQlpZigoQkZFX1RY
 X0xJU1RfQ05UIC0gKHNjLT5iZmVfdHhfY250ICsgY250KSkgPCAyKQ0KCQkJ
 CXJldHVybihFTk9CVUZTKTsNCg0KCQkJZCA9ICZzYy0+YmZlX3R4X2xpc3Rb
 Y3VyXTsNCgkJCXIgPSAmc2MtPmJmZV90eF9yaW5nW2N1cl07DQoJCQlkLT5i
 ZmVfY3RybCA9IEJGRV9ERVNDX0xFTiAmIG0tPm1fbGVuOw0KCQkJLyogYWx3
 YXlzIGludHRlcnVwdCBvbiBjb21wbGV0aW9uICovDQoJCQlkLT5iZmVfY3Ry
 bCB8PSBCRkVfREVTQ19JT0M7DQoJCQlpZihjbnQgPT0gMCkNCgkJCQkvKiBT
 ZXQgc3RhcnQgb2YgZnJhbWUgKi8NCgkJCQlkLT5iZmVfY3RybCB8PSBCRkVf
 REVTQ19TT0Y7DQoJCQlpZihjdXIgPT0gQkZFX1RYX0xJU1RfQ05UIC0gMSkN
 CgkJCQkvKiBUZWxsIHRoZSBjaGlwIHRvIHdyYXAgdG8gdGhlIHN0YXJ0IG9m
 IHRoZSBkZXNjcmlwdG9yIGxpc3QgKi8NCgkJCQlkLT5iZmVfY3RybCB8PSBC
 RkVfREVTQ19FT1Q7DQoNCgkJCWJ1c19kbWFtYXBfbG9hZChzYy0+YmZlX3Rh
 Zywgci0+YmZlX21hcCwgbXRvZChtLCB2b2lkKiksIG0tPm1fbGVuLCANCgkJ
 CQkJYmZlX2RtYV9tYXBfZGVzYywgZCwgMCk7DQoJCQlidXNfZG1hbWFwX3N5
 bmMoc2MtPmJmZV90YWcsIHItPmJmZV9tYXAsIEJVU19ETUFTWU5DX1BSRVJF
 QUQpOw0KDQoJCQlmcmFnID0gY3VyOw0KICAgICAgICAgICAgQkZFX0lOQyhj
 dXIsIEJGRV9UWF9MSVNUX0NOVCk7DQoJCQljbnQrKzsNCgkJfQ0KCX0NCg0K
 CWlmIChtICE9IE5VTEwpDQoJCXJldHVybihFTk9CVUZTKTsNCg0KCXNjLT5i
 ZmVfdHhfbGlzdFtmcmFnXS5iZmVfY3RybCB8PSBCRkVfREVTQ19FT0Y7DQoJ
 c2MtPmJmZV90eF9yaW5nW2ZyYWddLmJmZV9tYnVmID0gbV9oZWFkOw0KCWJ1
 c19kbWFtYXBfc3luYyhzYy0+YmZlX3R4X3RhZywgc2MtPmJmZV90eF9tYXAs
 IEJVU19ETUFTWU5DX1BSRVJFQUQpOw0KDQoJKnR4aWR4ID0gY3VyOw0KCXNj
 LT5iZmVfdHhfY250ICs9IGNudDsNCglyZXR1cm4gKDApOw0KfQ0KDQovKg0K
 ICogU2V0IHVwIHRvIHRyYW5zbWl0IGEgcGFja2V0DQogKi8NCnN0YXRpYyB2
 b2lkDQpiZmVfc3RhcnQoc3RydWN0IGlmbmV0ICppZnApDQp7DQoJc3RydWN0
 IGJmZV9zb2Z0YyAqc2M7DQoJc3RydWN0IG1idWYgKm1faGVhZCA9IE5VTEw7
 DQoJaW50IGlkeDsNCg0KCXNjID0gaWZwLT5pZl9zb2Z0YzsNCglpZHggPSBz
 Yy0+YmZlX3R4X3Byb2Q7DQoNCglCRkVfTE9DSyhzYyk7DQoNCgkvKiANCgkg
 KiBub3QgbXVjaCBwb2ludCB0cnlpbmcgdG8gc2VuZCBpZiB0aGUgbGluayBp
 cyBkb3duIG9yIHdlIGhhdmUgbm90aGluZyB0bw0KCSAqIHNlbmQNCgkgKi8N
 CglpZiAoIXNjLT5iZmVfbGluayAmJiBpZnAtPmlmX3NuZC5pZnFfbGVuIDwg
 MTApIHsNCgkJQkZFX1VOTE9DSyhzYyk7DQoJCXJldHVybjsNCgl9DQoNCglp
 ZiAoaWZwLT5pZl9mbGFncyAmIElGRl9PQUNUSVZFKSB7DQoJCUJGRV9VTkxP
 Q0soc2MpOw0KCQlyZXR1cm47DQoJfQ0KDQoJd2hpbGUoc2MtPmJmZV90eF9y
 aW5nW2lkeF0uYmZlX21idWYgPT0gTlVMTCkgew0KCQlJRl9ERVFVRVVFKCZp
 ZnAtPmlmX3NuZCwgbV9oZWFkKTsNCgkJaWYobV9oZWFkID09IE5VTEwpDQoJ
 CQlicmVhazsNCg0KCQkvKiANCgkJICogUGFjayB0aGUgZGF0YSBpbnRvIHRo
 ZSB0eCByaW5nLiAgSWYgd2UgZG9udCBoYXZlIGVub3VnaCByb29tLCBsZXQN
 CgkJICogdGhlIGNoaXAgZHJhaW4gdGhlIHJpbmcNCgkJICovDQoJCWlmKGJm
 ZV9lbmNhcChzYywgbV9oZWFkLCAmaWR4KSkgew0KCQkJSUZfUFJFUEVORCgm
 aWZwLT5pZl9zbmQsIG1faGVhZCk7DQoJCQlpZnAtPmlmX2ZsYWdzIHw9IElG
 Rl9PQUNUSVZFOw0KCQkJYnJlYWs7DQoJCX0NCg0KCQkvKg0KCQkgKiBJZiB0
 aGVyZSdzIGEgQlBGIGxpc3RlbmVyLCBib3VuY2UgYSBjb3B5IG9mIHRoaXMg
 ZnJhbWUNCgkJICogdG8gaGltLg0KCQkgKi8NCgkJQlBGX01UQVAoaWZwLCBt
 X2hlYWQpOw0KCX0NCg0KCXNjLT5iZmVfdHhfcHJvZCA9IGlkeDsNCgkvKiBU
 cmFuc21pdCAtIHR3aWNlIGR1ZSB0byBhcHBhcmVudCBoYXJkd2FyZSBidWcg
 Ki8NCglDU1JfV1JJVEVfNChzYywgQkZFX0RNQVRYX1BUUiwgaWR4ICogc2l6
 ZW9mKHN0cnVjdCBiZmVfZGVzYykpOw0KCUNTUl9XUklURV80KHNjLCBCRkVf
 RE1BVFhfUFRSLCBpZHggKiBzaXplb2Yoc3RydWN0IGJmZV9kZXNjKSk7DQoN
 CgkvKg0KCSAqIFNldCBhIHRpbWVvdXQgaW4gY2FzZSB0aGUgY2hpcCBnb2Vz
 IG91dCB0byBsdW5jaC4NCgkgKi8NCglpZnAtPmlmX3RpbWVyID0gNTsNCglC
 RkVfVU5MT0NLKHNjKTsNCn0NCg0Kc3RhdGljIHZvaWQNCmJmZV9pbml0KHZv
 aWQgKnhzYykNCnsNCglzdHJ1Y3QgYmZlX3NvZnRjICpzYyA9IChzdHJ1Y3Qg
 YmZlX3NvZnRjKil4c2M7DQoJc3RydWN0IGlmbmV0ICppZnAgPSAmc2MtPmFy
 cGNvbS5hY19pZjsNCg0KCUJGRV9MT0NLKHNjKTsNCg0KCWlmIChpZnAtPmlm
 X2ZsYWdzICYgSUZGX1JVTk5JTkcpIHsNCgkJQkZFX1VOTE9DSyhzYyk7DQoJ
 CXJldHVybjsNCgl9DQoNCgliZmVfc3RvcChzYyk7DQoJYmZlX2NoaXBfcmVz
 ZXQoc2MpOw0KDQoJaWYgKGJmZV9saXN0X3J4X2luaXQoc2MpID09IEVOT0JV
 RlMpIHsNCgkJcHJpbnRmKCJiZmUlZDogYmZlX2luaXQgZmFpbGVkLiBOb3Qg
 ZW5vdWdoIG1lbW9yeSBmb3IgbGlzdCBidWZmZXJzXG4iLA0KCQkJCXNjLT5i
 ZmVfdW5pdCk7DQoJCWJmZV9zdG9wKHNjKTsNCgkJcmV0dXJuOw0KCX0NCg0K
 CWJmZV9zZXRfcnhfbW9kZShzYyk7DQoNCgkvKiBFbmFibGUgdGhlIGNoaXAg
 YW5kIGNvcmUgKi8NCglCRkVfT1Ioc2MsIEJGRV9FTkVUX0NUUkwsIEJGRV9F
 TkVUX0VOQUJMRSk7DQoJLyogRW5hYmxlIGludGVycnVwdHMgKi8NCglDU1Jf
 V1JJVEVfNChzYywgQkZFX0lNQVNLLCBCRkVfSU1BU0tfREVGKTsNCg0KCWJm
 ZV9pZm1lZGlhX3VwZChpZnApOw0KCWlmcC0+aWZfZmxhZ3MgfD0gSUZGX1JV
 Tk5JTkc7DQoJaWZwLT5pZl9mbGFncyAmPSB+SUZGX09BQ1RJVkU7DQoNCglz
 Yy0+YmZlX3N0YXRfY2ggPSB0aW1lb3V0KGJmZV90aWNrLCBzYywgaHopOw0K
 CUJGRV9VTkxPQ0soc2MpOw0KfQ0KDQovKg0KICogU2V0IG1lZGlhIG9wdGlv
 bnMuDQogKi8NCnN0YXRpYyBpbnQNCmJmZV9pZm1lZGlhX3VwZChzdHJ1Y3Qg
 aWZuZXQgKmlmcCkNCnsNCglzdHJ1Y3QgYmZlX3NvZnRjICpzYzsNCglzdHJ1
 Y3QgbWlpX2RhdGEgKm1paTsNCg0KCXNjID0gaWZwLT5pZl9zb2Z0YzsNCg0K
 CUJGRV9MT0NLKHNjKTsNCg0KCW1paSA9IGRldmljZV9nZXRfc29mdGMoc2Mt
 PmJmZV9taWlidXMpOw0KCXNjLT5iZmVfbGluayA9IDA7DQoJaWYgKG1paS0+
 bWlpX2luc3RhbmNlKSB7DQoJCXN0cnVjdCBtaWlfc29mdGMgKm1paXNjOw0K
 CQlmb3IgKG1paXNjID0gTElTVF9GSVJTVCgmbWlpLT5taWlfcGh5cyk7IG1p
 aXNjICE9IE5VTEw7DQoJCQkJbWlpc2MgPSBMSVNUX05FWFQobWlpc2MsIG1p
 aV9saXN0KSkNCgkJCW1paV9waHlfcmVzZXQobWlpc2MpOw0KCX0NCgltaWlf
 bWVkaWFjaGcobWlpKTsNCg0KCUJGRV9VTkxPQ0soc2MpOw0KCXJldHVybigw
 KTsNCn0NCg0KLyoNCiAqIFJlcG9ydCBjdXJyZW50IG1lZGlhIHN0YXR1cy4N
 CiAqLw0Kc3RhdGljIHZvaWQNCmJmZV9pZm1lZGlhX3N0cyhzdHJ1Y3QgaWZu
 ZXQgKmlmcCwgc3RydWN0IGlmbWVkaWFyZXEgKmlmbXIpDQp7DQoJc3RydWN0
 IGJmZV9zb2Z0YyAqc2MgPSBpZnAtPmlmX3NvZnRjOw0KCXN0cnVjdCBtaWlf
 ZGF0YSAqbWlpOw0KDQoJQkZFX0xPQ0soc2MpOw0KDQoJbWlpID0gZGV2aWNl
 X2dldF9zb2Z0YyhzYy0+YmZlX21paWJ1cyk7DQoJbWlpX3BvbGxzdGF0KG1p
 aSk7DQoJaWZtci0+aWZtX2FjdGl2ZSA9IG1paS0+bWlpX21lZGlhX2FjdGl2
 ZTsNCglpZm1yLT5pZm1fc3RhdHVzID0gbWlpLT5taWlfbWVkaWFfc3RhdHVz
 Ow0KDQoJQkZFX1VOTE9DSyhzYyk7DQp9DQoNCnN0YXRpYyBpbnQNCmJmZV9p
 b2N0bChzdHJ1Y3QgaWZuZXQgKmlmcCwgdV9sb25nIGNvbW1hbmQsIGNhZGRy
 X3QgZGF0YSkNCnsNCglzdHJ1Y3QgYmZlX3NvZnRjICpzYyA9IGlmcC0+aWZf
 c29mdGM7DQoJc3RydWN0IGlmcmVxICppZnIgPSAoc3RydWN0IGlmcmVxICop
 IGRhdGE7DQoJc3RydWN0IG1paV9kYXRhICptaWk7DQoJaW50IGVycm9yID0g
 MDsNCg0KCUJGRV9MT0NLKHNjKTsNCg0KCXN3aXRjaChjb21tYW5kKSB7DQoJ
 CWNhc2UgU0lPQ1NJRkZMQUdTOg0KCQkJaWYoaWZwLT5pZl9mbGFncyAmIElG
 Rl9VUCkNCgkJCQlpZihpZnAtPmlmX2ZsYWdzICYgSUZGX1JVTk5JTkcpDQoJ
 CQkJCWJmZV9zZXRfcnhfbW9kZShzYyk7DQoJCQkJZWxzZQ0KCQkJCQliZmVf
 aW5pdChzYyk7DQoJCQllbHNlIGlmKGlmcC0+aWZfZmxhZ3MgJiBJRkZfUlVO
 TklORykNCgkJCQliZmVfc3RvcChzYyk7DQoJCQlicmVhazsNCgkJY2FzZSBT
 SU9DQURETVVMVEk6DQoJCWNhc2UgU0lPQ0RFTE1VTFRJOg0KCQkJaWYoaWZw
 LT5pZl9mbGFncyAmIElGRl9SVU5OSU5HKQ0KCQkJCWJmZV9zZXRfcnhfbW9k
 ZShzYyk7DQoJCQlicmVhazsNCgkJY2FzZSBTSU9DR0lGTUVESUE6DQoJCWNh
 c2UgU0lPQ1NJRk1FRElBOg0KCQkJbWlpID0gZGV2aWNlX2dldF9zb2Z0Yyhz
 Yy0+YmZlX21paWJ1cyk7DQoJCQllcnJvciA9IGlmbWVkaWFfaW9jdGwoaWZw
 LCBpZnIsICZtaWktPm1paV9tZWRpYSwgY29tbWFuZCk7DQoJCQlicmVhazsN
 CgkJZGVmYXVsdDoNCgkJCWVycm9yID0gZXRoZXJfaW9jdGwoaWZwLCBjb21t
 YW5kLCBkYXRhKTsgDQoJCQlicmVhazsNCgl9DQoNCglCRkVfVU5MT0NLKHNj
 KTsNCglyZXR1cm4gZXJyb3I7DQp9DQoNCnN0YXRpYyB2b2lkDQpiZmVfd2F0
 Y2hkb2coc3RydWN0IGlmbmV0ICppZnApDQp7DQoJc3RydWN0IGJmZV9zb2Z0
 YyAqc2M7DQoNCglzYyA9IGlmcC0+aWZfc29mdGM7DQoNCglCRkVfTE9DSyhz
 Yyk7DQoNCglwcmludGYoImJmZSVkOiB3YXRjaGRvZyB0aW1lb3V0IC0tIHJl
 c2V0dGluZ1xuIiwgc2MtPmJmZV91bml0KTsNCg0KCWlmcC0+aWZfZmxhZ3Mg
 Jj0gfklGRl9SVU5OSU5HOw0KCWJmZV9pbml0KHNjKTsNCg0KCWlmcC0+aWZf
 b2Vycm9ycysrOw0KDQoJQkZFX1VOTE9DSyhzYyk7DQp9DQoNCnN0YXRpYyB2
 b2lkDQpiZmVfdGljayh2b2lkICp4c2MpDQp7DQoJc3RydWN0IGJmZV9zb2Z0
 YyAqc2MgPSB4c2M7DQoJc3RydWN0IG1paV9kYXRhICptaWk7DQoNCglpZiAo
 c2MgPT0gTlVMTCkNCgkJcmV0dXJuOw0KDQoJQkZFX0xPQ0soc2MpOw0KDQoJ
 bWlpID0gZGV2aWNlX2dldF9zb2Z0YyhzYy0+YmZlX21paWJ1cyk7DQoNCgli
 ZmVfc3RhdHNfdXBkYXRlKHNjKTsNCglzYy0+YmZlX3N0YXRfY2ggPSB0aW1l
 b3V0KGJmZV90aWNrLCBzYywgaHopOw0KDQoJaWYoc2MtPmJmZV9saW5rKSB7
 DQoJCUJGRV9VTkxPQ0soc2MpOw0KCQlyZXR1cm47DQoJfQ0KDQoJbWlpX3Rp
 Y2sobWlpKTsNCglpZiAoIXNjLT5iZmVfbGluayAmJiBtaWktPm1paV9tZWRp
 YV9zdGF0dXMgJiBJRk1fQUNUSVZFICYmDQoJCQlJRk1fU1VCVFlQRShtaWkt
 Pm1paV9tZWRpYV9hY3RpdmUpICE9IElGTV9OT05FKSANCgkJc2MtPmJmZV9s
 aW5rKys7DQoNCglCRkVfVU5MT0NLKHNjKTsNCn0NCg0KLyoNCiAqIFN0b3Ag
 dGhlIGFkYXB0ZXIgYW5kIGZyZWUgYW55IG1idWZzIGFsbG9jYXRlZCB0byB0
 aGUNCiAqIFJYIGFuZCBUWCBsaXN0cy4NCiAqLw0Kc3RhdGljIHZvaWQNCmJm
 ZV9zdG9wKHN0cnVjdCBiZmVfc29mdGMgKnNjKQ0Kew0KCXN0cnVjdCBpZm5l
 dCAqaWZwOw0KDQoJQkZFX0xPQ0soc2MpOw0KDQoJdW50aW1lb3V0KGJmZV90
 aWNrLCBzYywgc2MtPmJmZV9zdGF0X2NoKTsNCg0KCWlmcCA9ICZzYy0+YXJw
 Y29tLmFjX2lmOw0KDQoJYmZlX2NoaXBfaGFsdChzYyk7DQogICAgYmZlX3R4
 X3JpbmdfZnJlZShzYyk7DQoJYmZlX3J4X3JpbmdfZnJlZShzYyk7DQoNCglp
 ZnAtPmlmX2ZsYWdzICY9IH4oSUZGX1JVTk5JTkcgfCBJRkZfT0FDVElWRSk7
 DQoNCglCRkVfVU5MT0NLKHNjKTsNCn0NCg==
 
 ---559023410-851401618-1084200166=:27340--

From: Jianqin Qu <jqu@its.brooklyn.cuny.edu>
To: bug-followup@freebsd.org
Cc: jqu@its.brooklyn.cuny.edu
Subject: [patch]Re: i386/64656: Bugs with Ethernet driver "bfe"
Date: Fri, 14 May 2004 21:56:55 -0400 (EDT)

 Sorry, the patch attached with previous message are either wrong
 or somehow gargbled. So now I'm putting it on the URL:
 
      http://www.jexplore.com/~jqu/bfe_current.patch
 
 The patch is made against FreeBSD-current, but it's tested to work
 for FreeBSD-5.2.1-Release too. It should work for 5.2 as well.
 Please check out and have a try. Just type:
     # cd /usr/src
     # patch < /path/bfe_current.patch
 
 
 Jianqin Qu
 

From: Jianqin Qu <jqu@its.brooklyn.cuny.edu>
To: freebsd-gnats-submit@FreeBSD.org, jqu@its.brooklyn.cuny.edu
Cc:  
Subject: Re: i386/64656: Bugs with Ethernet driver "bfe"[patch]
Date: Sat, 10 May 2003 20:01:54 +0800

 This is a multi-part message in MIME format.
 --------------090505010100030000050608
 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
 Content-Transfer-Encoding: 7bit
 
 More tests showed that this problem does not appear every time at boot 
 on my Dell Optiplex 160L.
  
 I found a tempory workaround for that.  When the problem occurs, simply 
 shut down your computer completely (not just switch off the power button 
 on your computer, but also detach your power cable!!! )   and  wait for 
 sufficiently long time  and  then restart your computer to boot into 
 FreeBSD 5.2.1 directly.   Here sufficiently long time varies, but 30 
 minutes seems sufficient for my case most of time.
 
 If  you switch off your computer power button without unplugging the 
 power cable and the LED light on the system board is on, then after some 
 time (several hours) when you boot your computer into FreeBSD 5.2.1, 
 this problem almost certainly occur.
 
 Rebooting into FreeBSD 5.2.1 release from another operating system 
 installed on the same box  may reproduce the problem too.  Particularly 
 rebooting into FreeBSD from a Linux system with a NIC driver of version 
 3.0.7 from BroadCom  always results in the occurence of this problem. 
 When the problem occurs, the link and activity indicator of the NIC are 
 both off.   So it seems the bfe driver fails to reset the NIC card to a 
 correct state in some cases.
 
 A patch with the bfe driver  is attached, which fixes the bug.  The 
 patch is against 5.2.1 Release and had been tested with it.   The 
 patched file "if_bfe.c" is also attached for reference.
 
 Jianqin
 
 --------------090505010100030000050608
 Content-Type: text/plain;
  name="tcp52.patch"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline;
  filename="tcp52.patch"
 
 ? tcp_reass-5.2.1-20040301.patch
 Index: tcp_input.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v
 retrieving revision 1.217.2.1
 diff -u -p -r1.217.2.1 tcp_input.c
 --- sys/netinet/tcp_input.c	9 Jan 2004 12:32:36 -0000	1.217.2.1
 +++ sys/netinet/tcp_input.c	1 Mar 2004 15:18:54 -0000
 @@ -57,6 +57,8 @@
  
  #include <machine/cpu.h>	/* before tcp_seq.h, for tcp_random18() */
  
 +#include <vm/uma.h>
 +
  #include <net/if.h>
  #include <net/route.h>
  
 @@ -97,8 +99,6 @@
  
  #include <machine/in_cksum.h>
  
 -MALLOC_DEFINE(M_TSEGQ, "tseg_qent", "TCP segment queue entry");
 -
  static const int tcprexmtthresh = 3;
  tcp_cc	tcp_ccgen;
  
 @@ -134,6 +134,24 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, rfc3
      &tcp_do_rfc3390, 0,
      "Enable RFC 3390 (Increasing TCP's Initial Congestion Window)");
  
 +SYSCTL_NODE(_net_inet_tcp, OID_AUTO, reass, CTLFLAG_RW, 0,
 +    "TCP Segment Reassembly Queue");
 +
 +static int tcp_reass_maxseg = 0;
 +SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, maxsegments, CTLFLAG_RDTUN,
 +    &tcp_reass_maxseg, 0,
 +    "Global maximum number of TCP Segments in Reassembly Queue");
 +
 +int tcp_reass_qsize = 0;
 +SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, cursegments, CTLFLAG_RD,
 +    &tcp_reass_qsize, 0,
 +    "Global number of TCP Segments currently in Reassembly Queue");
 +
 +static int tcp_reass_overflows = 0;
 +SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, overflows, CTLFLAG_RD,
 +    &tcp_reass_overflows, 0,
 +    "Global number of TCP Segment Reassembly Queue Overflows");
 +
  struct inpcbhead tcb;
  #define	tcb6	tcb  /* for KAME src sync over BSD*'s */
  struct inpcbinfo tcbinfo;
 @@ -174,6 +192,19 @@ do { \
  	    (tp->t_flags & TF_RXWIN0SENT) == 0) &&			\
  	    (tcp_delack_enabled || (tp->t_flags & TF_NEEDSYN)))
  
 +/* Initialize TCP reassembly queue */
 +uma_zone_t	tcp_reass_zone;
 +void
 +tcp_reass_init()
 +{
 +	tcp_reass_maxseg = nmbclusters / 16;
 +	TUNABLE_INT_FETCH("net.inet.tcp.reass.maxsegments",
 +	    &tcp_reass_maxseg);
 +	tcp_reass_zone = uma_zcreate("tcpreass", sizeof (struct tseg_qent),
 +	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
 +	uma_zone_set_max(tcp_reass_zone, tcp_reass_maxseg);
 +}
 +
  static int
  tcp_reass(tp, th, tlenp, m)
  	register struct tcpcb *tp;
 @@ -184,7 +215,7 @@ tcp_reass(tp, th, tlenp, m)
  	struct tseg_qent *q;
  	struct tseg_qent *p = NULL;
  	struct tseg_qent *nq;
 -	struct tseg_qent *te;
 +	struct tseg_qent *te = NULL;
  	struct socket *so = tp->t_inpcb->inp_socket;
  	int flags;
  
 @@ -195,9 +226,27 @@ tcp_reass(tp, th, tlenp, m)
  	if (th == 0)
  		goto present;
  
 -	/* Allocate a new queue entry. If we can't, just drop the pkt. XXX */
 -	MALLOC(te, struct tseg_qent *, sizeof (struct tseg_qent), M_TSEGQ,
 -	       M_NOWAIT);
 +	/*
 +	 * Limit the number of segments in the reassembly queue to prevent
 +	 * holding on to too many segments (and thus running out of mbufs).
 +	 * Make sure to let the missing segment through which caused this
 +	 * queue.  Always keep one global queue entry spare to be able to
 +	 * process the missing segment.
 +	 */
 +	if (th->th_seq != tp->rcv_nxt &&
 +	    tcp_reass_qsize + 1 >= tcp_reass_maxseg) {
 +		tcp_reass_overflows++;
 +		tcpstat.tcps_rcvmemdrop++;
 +		m_freem(m);
 +		return (0);
 +	}
 +	tcp_reass_qsize++;
 +
 +	/*
 +	 * Allocate a new queue entry. If we can't, or hit the zone limit
 +	 * just drop the pkt.
 +	 */
 +	te = uma_zalloc(tcp_reass_zone, M_NOWAIT);
  	if (te == NULL) {
  		tcpstat.tcps_rcvmemdrop++;
  		m_freem(m);
 @@ -227,7 +276,8 @@ tcp_reass(tp, th, tlenp, m)
  				tcpstat.tcps_rcvduppack++;
  				tcpstat.tcps_rcvdupbyte += *tlenp;
  				m_freem(m);
 -				FREE(te, M_TSEGQ);
 +				uma_zfree(tcp_reass_zone, te);
 +				tcp_reass_qsize--;
  				/*
  				 * Try to present any queued data
  				 * at the left window edge to the user.
 @@ -262,7 +312,8 @@ tcp_reass(tp, th, tlenp, m)
  		nq = LIST_NEXT(q, tqe_q);
  		LIST_REMOVE(q, tqe_q);
  		m_freem(q->tqe_m);
 -		FREE(q, M_TSEGQ);
 +		uma_zfree(tcp_reass_zone, q);
 +		tcp_reass_qsize--;
  		q = nq;
  	}
  
 @@ -296,7 +347,8 @@ present:
  			m_freem(q->tqe_m);
  		else
  			sbappendstream(&so->so_rcv, q->tqe_m);
 -		FREE(q, M_TSEGQ);
 +		uma_zfree(tcp_reass_zone, q);
 +		tcp_reass_qsize--;
  		q = nq;
  	} while (q && q->tqe_th->th_seq == tp->rcv_nxt);
  	ND6_HINT(tp);
 Index: tcp_subr.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/tcp_subr.c,v
 retrieving revision 1.169.2.3
 diff -u -p -r1.169.2.3 tcp_subr.c
 --- sys/netinet/tcp_subr.c	23 Feb 2004 15:32:55 -0000	1.169.2.3
 +++ sys/netinet/tcp_subr.c	1 Mar 2004 15:18:54 -0000
 @@ -286,6 +286,7 @@ tcp_init()
  	tcp_timer_init();
  	syncache_init();
  	tcp_hc_init();
 +	tcp_reass_init();
  }
  
  /*
 @@ -708,7 +709,8 @@ tcp_discardcb(tp)
  	while ((q = LIST_FIRST(&tp->t_segq)) != NULL) {
  		LIST_REMOVE(q, tqe_q);
  		m_freem(q->tqe_m);
 -		FREE(q, M_TSEGQ);
 +		uma_zfree(tcp_reass_zone, q);
 +		tcp_reass_qsize--;
  	}
  	inp->inp_ppcb = NULL;
  	tp->t_inpcb = NULL;
 @@ -769,7 +771,8 @@ tcp_drain()
  			            != NULL) {
  					LIST_REMOVE(te, tqe_q);
  					m_freem(te->tqe_m);
 -					FREE(te, M_TSEGQ);
 +					uma_zfree(tcp_reass_zone, te);
 +					tcp_reass_qsize--;
  				}
  			}
  			INP_UNLOCK(inpb);
 Index: tcp_var.h
 ===================================================================
 RCS file: /home/ncvs/src/sys/netinet/tcp_var.h,v
 retrieving revision 1.93.2.1
 diff -u -p -r1.93.2.1 tcp_var.h
 --- sys/netinet/tcp_var.h	9 Jan 2004 12:32:36 -0000	1.93.2.1
 +++ sys/netinet/tcp_var.h	1 Mar 2004 15:18:55 -0000
 @@ -54,9 +54,8 @@ struct tseg_qent {
  	struct	mbuf	*tqe_m;		/* mbuf contains packet */
  };
  LIST_HEAD(tsegqe_head, tseg_qent);
 -#ifdef MALLOC_DECLARE
 -MALLOC_DECLARE(M_TSEGQ);
 -#endif
 +extern int	tcp_reass_qsize;
 +extern struct uma_zone	*tcp_reass_zone;
  
  struct tcptemp {
  	u_char	tt_ipgen[40]; /* the size must be of max ip header, now IPv6 */
 @@ -514,6 +513,7 @@ struct tcpcb *
  int	 tcp_output(struct tcpcb *);
  struct inpcb *
  	 tcp_quench(struct inpcb *, int);
 +void	 tcp_reass_init(void);
  void	 tcp_respond(struct tcpcb *, void *,
  	    struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int);
  int	 tcp_twrespond(struct tcptw *, struct socket *, struct mbuf *, int);
 
 --------------090505010100030000050608
 Content-Type: text/plain;
  name="if_bfe.c"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline;
  filename="if_bfe.c"
 
 /*
  * Copyright (c) 2003 Stuart Walsh<stu@ipng.org.uk>
  * and Duncan Barclay<dmlb@dmlb.org>
  */
 
 /*
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 'AS IS' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sys/dev/bfe/if_bfe.c,v 1.4 2003/11/14 19:00:30 sam Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/sockio.h>
 #include <sys/mbuf.h>
 #include <sys/malloc.h>
 #include <sys/kernel.h>
 #include <sys/socket.h>
 #include <sys/queue.h>
 
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <net/ethernet.h>
 #include <net/if_dl.h>
 #include <net/if_media.h>
 
 #include <net/bpf.h>
 
 #include <net/if_types.h>
 #include <net/if_vlan_var.h>
 
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
 
 #include <machine/clock.h>      /* for DELAY */
 #include <machine/bus_memio.h>
 #include <machine/bus.h>
 #include <machine/resource.h>
 #include <sys/bus.h>
 #include <sys/rman.h>
 
 #include <dev/mii/mii.h>
 #include <dev/mii/miivar.h>
 #include "miidevs.h"
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 
 #include <dev/bfe/if_bfereg.h>
 
 MODULE_DEPEND(bfe, pci, 1, 1, 1);
 MODULE_DEPEND(bfe, ether, 1, 1, 1);
 MODULE_DEPEND(bfe, miibus, 1, 1, 1);
 
 /* "controller miibus0" required.  See GENERIC if you get errors here. */
 #include "miibus_if.h"
 
 #define BFE_DEVDESC_MAX		64	/* Maximum device description length */
 
 static struct bfe_type bfe_devs[] = {
 	{ BCOM_VENDORID, BCOM_DEVICEID_BCM4401,
 		"Broadcom BCM4401 Fast Ethernet" },
 		{ 0, 0, NULL }
 };
 
 static int  bfe_probe				(device_t);
 static int  bfe_attach				(device_t);
 static int  bfe_detach				(device_t);
 static void bfe_release_resources	(struct bfe_softc *);
 static void bfe_intr				(void *);
 static void bfe_start				(struct ifnet *);
 static int  bfe_ioctl				(struct ifnet *, u_long, caddr_t);
 static void bfe_init				(void *);
 static void bfe_stop				(struct bfe_softc *);
 static void bfe_watchdog			(struct ifnet *);
 static void bfe_shutdown			(device_t);
 static void bfe_tick				(void *);
 static void bfe_txeof				(struct bfe_softc *);
 static void bfe_rxeof				(struct bfe_softc *);
 static void bfe_set_rx_mode			(struct bfe_softc *);
 static int  bfe_list_rx_init		(struct bfe_softc *);
 static int  bfe_list_newbuf			(struct bfe_softc *, int, struct mbuf*);
 static void bfe_rx_ring_free		(struct bfe_softc *);
 
 static void bfe_pci_setup			(struct bfe_softc *, u_int32_t);
 static int  bfe_ifmedia_upd			(struct ifnet *);
 static void bfe_ifmedia_sts			(struct ifnet *, struct ifmediareq *);
 static int  bfe_miibus_readreg		(device_t, int, int);
 static int  bfe_miibus_writereg		(device_t, int, int, int);
 static void bfe_miibus_statchg		(device_t);
 static int  bfe_wait_bit			(struct bfe_softc *, u_int32_t, u_int32_t, 
 		u_long, const int);
 static void bfe_get_config			(struct bfe_softc *sc);
 static void bfe_read_eeprom			(struct bfe_softc *, u_int8_t *);
 static void bfe_stats_update		(struct bfe_softc *);
 static void bfe_clear_stats			(struct bfe_softc *);
 static int  bfe_readphy				(struct bfe_softc *, u_int32_t, u_int32_t*);
 static int  bfe_writephy			(struct bfe_softc *, u_int32_t, u_int32_t);
 static int  bfe_resetphy			(struct bfe_softc *);
 static int  bfe_setupphy			(struct bfe_softc *);
 static void bfe_chip_reset			(struct bfe_softc *);
 static void bfe_chip_halt			(struct bfe_softc *);
 static void bfe_core_reset			(struct bfe_softc *);
 static void bfe_core_disable		(struct bfe_softc *);
 static int  bfe_dma_alloc			(device_t);
 static void bfe_dma_map_desc		(void *, bus_dma_segment_t *, int, int);
 static void bfe_dma_map				(void *, bus_dma_segment_t *, int, int);
 static void bfe_cam_write			(struct bfe_softc *, u_char *, int);
 
 static device_method_t bfe_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		bfe_probe),
 	DEVMETHOD(device_attach,	bfe_attach),
 	DEVMETHOD(device_detach,	bfe_detach),
 	DEVMETHOD(device_shutdown,	bfe_shutdown),
 
 	/* bus interface */
 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
 	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
 
 	/* MII interface */
 	DEVMETHOD(miibus_readreg,	bfe_miibus_readreg),
 	DEVMETHOD(miibus_writereg,	bfe_miibus_writereg),
 	DEVMETHOD(miibus_statchg,	bfe_miibus_statchg),
 
 	{ 0, 0 }
 };
 
 static driver_t bfe_driver = {
 	"bfe",
 	bfe_methods,
 	sizeof(struct bfe_softc)
 };
 
 static devclass_t bfe_devclass;
 
 DRIVER_MODULE(bfe, pci, bfe_driver, bfe_devclass, 0, 0);
 DRIVER_MODULE(miibus, bfe, miibus_driver, miibus_devclass, 0, 0);
 
 /*
  * Probe for a Broadcom 4401 chip. 
  */
 static int
 bfe_probe(device_t dev)
 {
 	struct bfe_type *t;
 	struct bfe_softc *sc;
 
 	t = bfe_devs;
 
 	sc = device_get_softc(dev);
 	bzero(sc, sizeof(struct bfe_softc));
 	sc->bfe_unit = device_get_unit(dev);
 	sc->bfe_dev = dev;
 
 	while(t->bfe_name != NULL) {
 		if ((pci_get_vendor(dev) == t->bfe_vid) &&
 				(pci_get_device(dev) == t->bfe_did)) {
 			device_set_desc_copy(dev, t->bfe_name);
 			return(0);
 		}
 		t++;
 	}
 
 	return(ENXIO);
 }
 
 static int
 bfe_dma_alloc(device_t dev)
 {
 	struct bfe_softc *sc;
 	int error, i;
 
 	sc = device_get_softc(dev);
 
 	/* parent tag */
 	error = bus_dma_tag_create(NULL,  /* parent */
 			PAGE_SIZE, 0,             /* alignment, boundary */
 			BUS_SPACE_MAXADDR,        /* lowaddr */      
 			BUS_SPACE_MAXADDR_32BIT,  /* highaddr */
 			NULL, NULL,               /* filter, filterarg */
 			MAXBSIZE,                 /* maxsize */
 			BUS_SPACE_UNRESTRICTED,   /* num of segments */
 			BUS_SPACE_MAXSIZE_32BIT,  /* max segment size */
 			BUS_DMA_ALLOCNOW,         /* flags */
 			NULL, NULL,               /* lockfunc, lockarg */
 			&sc->bfe_parent_tag);
 
 	/* tag for TX ring */
 	error = bus_dma_tag_create(sc->bfe_parent_tag, BFE_TX_LIST_SIZE, 
 			BFE_TX_LIST_SIZE, BUS_SPACE_MAXADDR,  BUS_SPACE_MAXADDR, 
 			NULL, NULL, BFE_TX_LIST_SIZE, 1,  BUS_SPACE_MAXSIZE_32BIT,
 			0, NULL, NULL, &sc->bfe_tx_tag);
 
 	if (error) {
 		device_printf(dev, "could not allocate dma tag\n");
 		return(ENOMEM);
 	}
 
 	/* tag for RX ring */
 	error = bus_dma_tag_create(sc->bfe_parent_tag, BFE_RX_LIST_SIZE, 
 			BFE_RX_LIST_SIZE, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 
 			NULL, NULL, BFE_RX_LIST_SIZE, 1, BUS_SPACE_MAXSIZE_32BIT, 
 			0, NULL, NULL, &sc->bfe_rx_tag);
 
 	if (error) {
 		device_printf(dev, "could not allocate dma tag\n");
 		return(ENOMEM);
 	}
 
 	/* tag for mbufs */
 	error = bus_dma_tag_create(sc->bfe_parent_tag, ETHER_ALIGN, 0,
 			BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 
 			1, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, &sc->bfe_tag);
 
 	if (error) {
 		device_printf(dev, "could not allocate dma tag\n");
 		return(ENOMEM);
 	}
 
 	/* pre allocate dmamaps for RX list */
 	for (i = 0; i < BFE_RX_LIST_CNT; i++) {
 		error = bus_dmamap_create(sc->bfe_tag, 0, &sc->bfe_rx_ring[i].bfe_map);
 		if (error) {
 			device_printf(dev, "cannot create DMA map for RX\n");
 			return(ENOMEM);
 		}
 	}
 
 	/* pre allocate dmamaps for TX list */
 	for (i = 0; i < BFE_TX_LIST_CNT; i++) {
 		error = bus_dmamap_create(sc->bfe_tag, 0, &sc->bfe_tx_ring[i].bfe_map);
 		if (error) {
 			device_printf(dev, "cannot create DMA map for TX\n");
 			return(ENOMEM);
 		}
 	}
 
 	/* Alloc dma for rx ring */
 	error = bus_dmamem_alloc(sc->bfe_rx_tag, (void *)&sc->bfe_rx_list,
 			BUS_DMA_NOWAIT, &sc->bfe_rx_map);
 
 	if(error)
 		return(ENOMEM);
 
 	bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE);
 	error = bus_dmamap_load(sc->bfe_rx_tag, sc->bfe_rx_map,
 			sc->bfe_rx_list, sizeof(struct bfe_desc),
 			bfe_dma_map, &sc->bfe_rx_dma, 0);
 
 	if(error)
 		return(ENOMEM);
 
 	bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, BUS_DMASYNC_PREREAD);
 
 	error = bus_dmamem_alloc(sc->bfe_tx_tag, (void *)&sc->bfe_tx_list, 
 			BUS_DMA_NOWAIT, &sc->bfe_tx_map);
 	if (error) 
 		return(ENOMEM);
 
 
 	error = bus_dmamap_load(sc->bfe_tx_tag, sc->bfe_tx_map, 
 			sc->bfe_tx_list, sizeof(struct bfe_desc), 
 			bfe_dma_map, &sc->bfe_tx_dma, 0);
 	if(error)
 		return(ENOMEM);
 
 	bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE);
 	bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, BUS_DMASYNC_PREREAD);
 
 	return(0);
 }
 
 static int
 bfe_attach(device_t dev)
 {
 	struct ifnet *ifp;
 	struct bfe_softc *sc;
 	int unit, error = 0, rid;
 
 	sc = device_get_softc(dev);
 	mtx_init(&sc->bfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
 			MTX_DEF | MTX_RECURSE);
 
 	unit = device_get_unit(dev);
 	sc->bfe_dev = dev;
 	sc->bfe_unit = unit;
 
 	/*
 	 * Handle power management nonsense.
 	 */
 	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
 		u_int32_t membase, irq;
 
 		/* Save important PCI config data. */
 		membase = pci_read_config(dev, BFE_PCI_MEMLO, 4);
 		irq = pci_read_config(dev, BFE_PCI_INTLINE, 4);
 
 		/* Reset the power state. */
 		printf("bfe%d: chip is is in D%d power mode -- setting to D0\n", 
 				sc->bfe_unit, pci_get_powerstate(dev));
 
 		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
 
 		/* Restore PCI config data. */
 		pci_write_config(dev, BFE_PCI_MEMLO, membase, 4);
 		pci_write_config(dev, BFE_PCI_INTLINE, irq, 4);
 	}
 
 	/*
 	 * Map control/status registers.
 	 */
 	pci_enable_busmaster(dev);
 
 	rid = BFE_PCI_MEMLO;
 	sc->bfe_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, 
 			RF_ACTIVE);
 	if (sc->bfe_res == NULL) {
 		printf ("bfe%d: couldn't map memory\n", unit);
 		error = ENXIO;
 		goto fail;
 	}
 
 	sc->bfe_btag = rman_get_bustag(sc->bfe_res);
 	sc->bfe_bhandle = rman_get_bushandle(sc->bfe_res);
 	sc->bfe_vhandle = (vm_offset_t)rman_get_virtual(sc->bfe_res);
 
 	/* Allocate interrupt */
 	rid = 0;
 
 	sc->bfe_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
 			RF_SHAREABLE | RF_ACTIVE);
 	if (sc->bfe_irq == NULL) {
 		printf("bfe%d: couldn't map interrupt\n", unit);
 		error = ENXIO;
 		goto fail;
 	}
 
 	if (bfe_dma_alloc(dev)) {
 		printf("bfe%d: failed to allocate DMA resources\n", sc->bfe_unit);
 		bfe_release_resources(sc);
 		error = ENXIO;
 		goto fail;
 	}
 
 	/* Set up ifnet structure */
 	ifp = &sc->arpcom.ac_if;
 	ifp->if_softc = sc;
 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_ioctl = bfe_ioctl;
 	ifp->if_output = ether_output;
 	ifp->if_start = bfe_start;
 	ifp->if_watchdog = bfe_watchdog;
 	ifp->if_init = bfe_init;
 	ifp->if_mtu = ETHERMTU;
 	ifp->if_baudrate = 10000000;
 	ifp->if_snd.ifq_maxlen = BFE_TX_QLEN;
 
 	bfe_get_config(sc);
 
 	printf("bfe%d: Ethernet address: %6D\n", unit, sc->arpcom.ac_enaddr, ":");
 
 	/* Reset the chip and turn on the PHY */
 	bfe_chip_reset(sc);
 
 	if (mii_phy_probe(dev, &sc->bfe_miibus,
 				bfe_ifmedia_upd, bfe_ifmedia_sts)) {
 		printf("bfe%d: MII without any PHY!\n", sc->bfe_unit);
 		error = ENXIO;
 		goto fail;
 	}
 
 	ether_ifattach(ifp, sc->arpcom.ac_enaddr);
 	callout_handle_init(&sc->bfe_stat_ch);
 
 	/*
 	 * Hook interrupt last to avoid having to lock softc
 	 */
 	error = bus_setup_intr(dev, sc->bfe_irq, INTR_TYPE_NET,
 			bfe_intr, sc, &sc->bfe_intrhand);
 
 	if (error) {
 		bfe_release_resources(sc);
 		printf("bfe%d: couldn't set up irq\n", unit);
 		goto fail;
 	}
 fail:
 	if(error)
 		bfe_release_resources(sc);
 	return(error);
 }
 
 static int
 bfe_detach(device_t dev)
 {
 	struct bfe_softc *sc;
 	struct ifnet *ifp;
 
 	sc = device_get_softc(dev);
 
 	KASSERT(mtx_initialized(&sc->bfe_mtx), ("bfe mutex not initialized"));
 	BFE_LOCK(scp);
 
 	ifp = &sc->arpcom.ac_if;
 
 	if (device_is_attached(dev)) {
 		bfe_stop(sc);
 		ether_ifdetach(ifp);
 	}
 
 	bfe_chip_reset(sc);
 
 	bus_generic_detach(dev);
 	if(sc->bfe_miibus != NULL)
 		device_delete_child(dev, sc->bfe_miibus);
 
 	bfe_release_resources(sc);
 	BFE_UNLOCK(sc);
 	mtx_destroy(&sc->bfe_mtx);
 
 	return(0);
 }
 
 /*
  * Stop all chip I/O so that the kernel's probe routines don't
  * get confused by errant DMAs when rebooting.
  */
 static void
 bfe_shutdown(device_t dev)
 {
 	struct bfe_softc *sc;
 
 	sc = device_get_softc(dev);
 	BFE_LOCK(sc);
 	bfe_stop(sc); 
 
 	BFE_UNLOCK(sc);
 	return;
 }
 
 static int
 bfe_miibus_readreg(device_t dev, int phy, int reg)
 {
 	struct bfe_softc *sc;
 	u_int32_t ret;
 
 	sc = device_get_softc(dev);
 	if(phy != sc->bfe_phyaddr)
 		return(0);
 	bfe_readphy(sc, reg, &ret);
 
 	return(ret);
 }
 
 static int
 bfe_miibus_writereg(device_t dev, int phy, int reg, int val)
 {
 	struct bfe_softc *sc;
 
 	sc = device_get_softc(dev);
 	if(phy != sc->bfe_phyaddr)
 		return(0);
 	bfe_writephy(sc, reg, val); 
 
 	return(0);
 }
 
 static void
 bfe_miibus_statchg(device_t dev)
 {
 	return;
 }
 
 static void
 bfe_tx_ring_free(struct bfe_softc *sc)
 {
     int i;
     
     for(i = 0; i < BFE_TX_LIST_CNT; i++) {
         if(sc->bfe_tx_ring[i].bfe_mbuf != NULL) {
             m_freem(sc->bfe_tx_ring[i].bfe_mbuf);
             sc->bfe_tx_ring[i].bfe_mbuf = NULL;
             bus_dmamap_unload(sc->bfe_tag,
                     sc->bfe_tx_ring[i].bfe_map);
             bus_dmamap_destroy(sc->bfe_tag,
                     sc->bfe_tx_ring[i].bfe_map);
         }
     }
     bzero(sc->bfe_tx_list, BFE_TX_LIST_SIZE);
     bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, BUS_DMASYNC_PREREAD);
 }
 
 static void
 bfe_rx_ring_free(struct bfe_softc *sc)
 {
 	int i;
 
 	for (i = 0; i < BFE_RX_LIST_CNT; i++) {
 		if (sc->bfe_rx_ring[i].bfe_mbuf != NULL) {
 			m_freem(sc->bfe_rx_ring[i].bfe_mbuf);
 			sc->bfe_rx_ring[i].bfe_mbuf = NULL;
 			bus_dmamap_unload(sc->bfe_tag,
 					sc->bfe_rx_ring[i].bfe_map);
 			bus_dmamap_destroy(sc->bfe_tag,
 					sc->bfe_rx_ring[i].bfe_map);
 		}
 	}
 	bzero(sc->bfe_rx_list, BFE_RX_LIST_SIZE);
 	bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, BUS_DMASYNC_PREREAD);
 }
 
 
 static int 
 bfe_list_rx_init(struct bfe_softc *sc)
 {
 	int i;
 
 	for(i = 0; i < BFE_RX_LIST_CNT; i++) {
 		if(bfe_list_newbuf(sc, i, NULL) == ENOBUFS) 
 			return ENOBUFS;
 	}
 
 	bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, BUS_DMASYNC_PREREAD);
 	CSR_WRITE_4(sc, BFE_DMARX_PTR, (i * sizeof(struct bfe_desc)));
 
 	sc->bfe_rx_cons = 0;
 
 	return(0);
 }
 
 static int
 bfe_list_newbuf(struct bfe_softc *sc, int c, struct mbuf *m)
 {
 	struct bfe_rxheader *rx_header;
 	struct bfe_desc *d;
 	struct bfe_data *r;
 	u_int32_t ctrl;
 
 	if ((c < 0) || (c >= BFE_RX_LIST_CNT))
 		return(EINVAL);
 
 	if(m == NULL) {
 		m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
 		if(m == NULL)
 			return(ENOBUFS);
 		m->m_len = m->m_pkthdr.len = MCLBYTES;
 	}
 	else
 		m->m_data = m->m_ext.ext_buf;
 
 	rx_header = mtod(m, struct bfe_rxheader *);
 	rx_header->len = 0;
 	rx_header->flags = 0;
 
 	/* Map the mbuf into DMA */
 	sc->bfe_rx_cnt = c;
 	d = &sc->bfe_rx_list[c];
 	r = &sc->bfe_rx_ring[c];
 	bus_dmamap_load(sc->bfe_tag, r->bfe_map, mtod(m, void *), 
 			MCLBYTES, bfe_dma_map_desc, d, 0);
 	bus_dmamap_sync(sc->bfe_tag, r->bfe_map, BUS_DMASYNC_PREWRITE);
 
 	ctrl = ETHER_MAX_LEN + 32;
 
 	if(c == BFE_RX_LIST_CNT - 1)
 		ctrl |= BFE_DESC_EOT;
 
 	d->bfe_ctrl = ctrl;
 	r->bfe_mbuf = m;
 	bus_dmamap_sync(sc->bfe_rx_tag, sc->bfe_rx_map, BUS_DMASYNC_PREREAD);
 	return(0);
 }
 
 static void
 bfe_get_config(struct bfe_softc *sc)
 {
 	u_int8_t eeprom[128];
 
 	bfe_read_eeprom(sc, eeprom);
 
 	sc->arpcom.ac_enaddr[0] = eeprom[79];
 	sc->arpcom.ac_enaddr[1] = eeprom[78];
 	sc->arpcom.ac_enaddr[2] = eeprom[81];
 	sc->arpcom.ac_enaddr[3] = eeprom[80];
 	sc->arpcom.ac_enaddr[4] = eeprom[83];
 	sc->arpcom.ac_enaddr[5] = eeprom[82];
 
 	sc->bfe_phyaddr = eeprom[90] & 0x1f;
 	sc->bfe_mdc_port = (eeprom[90] >> 14) & 0x1;
 
 	sc->bfe_core_unit = 0; 
 	sc->bfe_dma_offset = BFE_PCI_DMA;
 }
 
 static void
 bfe_pci_setup(struct bfe_softc *sc, u_int32_t cores)
 {
 	u_int32_t bar_orig, pci_rev, val;
 
 	bar_orig = pci_read_config(sc->bfe_dev, BFE_BAR0_WIN, 4);
 	pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, BFE_REG_PCI, 4);
 	pci_rev = CSR_READ_4(sc, BFE_SBIDHIGH) & BFE_RC_MASK;
 
 	val = CSR_READ_4(sc, BFE_SBINTVEC);
 	val |= cores;
 	CSR_WRITE_4(sc, BFE_SBINTVEC, val);
 
 	val = CSR_READ_4(sc, BFE_SSB_PCI_TRANS_2);
 	val |= BFE_SSB_PCI_PREF | BFE_SSB_PCI_BURST;
 	CSR_WRITE_4(sc, BFE_SSB_PCI_TRANS_2, val);
 
 	pci_write_config(sc->bfe_dev, BFE_BAR0_WIN, bar_orig, 4);
 }
 
 static void 
 bfe_clear_stats(struct bfe_softc *sc)
 {
 	u_long reg;
 
 	BFE_LOCK(sc);
 
 	CSR_WRITE_4(sc, BFE_MIB_CTRL, BFE_MIB_CLR_ON_READ);
 	for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4)
 		CSR_READ_4(sc, reg);
 	for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4)
 		CSR_READ_4(sc, reg);
 
 	BFE_UNLOCK(sc);
 }
 
 static int 
 bfe_resetphy(struct bfe_softc *sc)
 {
 	u_int32_t val;
 
 	BFE_LOCK(sc);
 	bfe_writephy(sc, 0, BMCR_RESET);
 	DELAY(100);
 	bfe_readphy(sc, 0, &val);
 	if (val & BMCR_RESET) {
 		printf("bfe%d: PHY Reset would not complete.\n", sc->bfe_unit);
 		BFE_UNLOCK(sc);
 		return ENXIO;
 	}
 	BFE_UNLOCK(sc);
 	return 0;
 }
 
 static void
 bfe_chip_halt(struct bfe_softc *sc)
 {
 	BFE_LOCK(sc);
 	/* disable interrupts - not that it actually does..*/
 	CSR_WRITE_4(sc, BFE_IMASK, 0);
 	CSR_READ_4(sc, BFE_IMASK);
 
 	CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE);
 	bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 200, 1);
 
 	CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0);
 	CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0);
 	DELAY(10);
 
 	BFE_UNLOCK(sc);
 }
 
 static void
 bfe_chip_reset(struct bfe_softc *sc)
 {
 	u_int32_t val;    
 
 	BFE_LOCK(sc);
 
 	/* Set the interrupt vector for the enet core */
 	bfe_pci_setup(sc, BFE_INTVEC_ENET0);
 
 	/* is core up? */
 	val = CSR_READ_4(sc, BFE_SBTMSLOW) & (BFE_RESET | BFE_REJECT | BFE_CLOCK);
 	if (val == BFE_CLOCK) {
 		/* It is, so shut it down */
 		CSR_WRITE_4(sc, BFE_RCV_LAZY, 0);
 		CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE);
 		bfe_wait_bit(sc, BFE_ENET_CTRL, BFE_ENET_DISABLE, 100, 1);
 		CSR_WRITE_4(sc, BFE_DMATX_CTRL, 0);
 		sc->bfe_tx_cnt = sc->bfe_tx_prod = sc->bfe_tx_cons = 0;
 		if (CSR_READ_4(sc, BFE_DMARX_STAT) & BFE_STAT_EMASK) 
 			bfe_wait_bit(sc, BFE_DMARX_STAT, BFE_STAT_SIDLE, 100, 0);
 		CSR_WRITE_4(sc, BFE_DMARX_CTRL, 0);
 		sc->bfe_rx_prod = sc->bfe_rx_cons = 0;
 	}
 
 	bfe_core_reset(sc);
 	bfe_clear_stats(sc);
 
 	/*
 	 * We want the phy registers to be accessible even when
 	 * the driver is "downed" so initialize MDC preamble, frequency,
 	 * and whether internal or external phy here.
 	 */
 
 	/* 4402 has 62.5Mhz SB clock and internal phy */
 	CSR_WRITE_4(sc, BFE_MDIO_CTRL, 0x8d);
 
 	/* Internal or external PHY? */
 	val = CSR_READ_4(sc, BFE_DEVCTRL);
 	if(!(val & BFE_IPP)) 
 		CSR_WRITE_4(sc, BFE_ENET_CTRL, BFE_ENET_EPSEL);
 	else if(CSR_READ_4(sc, BFE_DEVCTRL) & BFE_EPR) {
 		BFE_AND(sc, BFE_DEVCTRL, ~BFE_EPR);
 		DELAY(100);
 	}
 
 	//BFE_OR(sc, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB);
 	BFE_OR(sc, BFE_MAC_CTRL, BFE_CTRL_CRC32_ENAB | 7 << 5);
 	CSR_WRITE_4(sc, BFE_RCV_LAZY, ((1 << BFE_LAZY_FC_SHIFT) & 
 				BFE_LAZY_FC_MASK));
 
 	/* 
 	 * We don't want lazy interrupts, so just send them at the end of a frame,
 	 * please 
 	 */
 	BFE_OR(sc, BFE_RCV_LAZY, 0);
 
 	/* Set max lengths, accounting for VLAN tags */
 	CSR_WRITE_4(sc, BFE_RXMAXLEN, ETHER_MAX_LEN+32);
 	CSR_WRITE_4(sc, BFE_TXMAXLEN, ETHER_MAX_LEN+32);
 
 	/* Set watermark XXX - magic */
 	CSR_WRITE_4(sc, BFE_TX_WMARK, 56);
 
 	/* 
 	 * Initialise DMA channels - not forgetting dma addresses need to be added
 	 * to BFE_PCI_DMA 
 	 */
 	CSR_WRITE_4(sc, BFE_DMATX_CTRL, BFE_TX_CTRL_ENABLE);
 	CSR_WRITE_4(sc, BFE_DMATX_ADDR, sc->bfe_tx_dma + BFE_PCI_DMA);
 
 	CSR_WRITE_4(sc, BFE_DMARX_CTRL, (BFE_RX_OFFSET << BFE_RX_CTRL_ROSHIFT) | 
 			BFE_RX_CTRL_ENABLE);
 	CSR_WRITE_4(sc, BFE_DMARX_ADDR, sc->bfe_rx_dma + BFE_PCI_DMA);
 
 	bfe_resetphy(sc);
 	bfe_setupphy(sc);
 
 	BFE_UNLOCK(sc);
 }
 
 static void
 bfe_core_disable(struct bfe_softc *sc)
 {
 	if((CSR_READ_4(sc, BFE_SBTMSLOW)) & BFE_RESET)
 		return;
 
 	/* 
 	 * Set reject, wait for it set, then wait for the core to stop being busy
 	 * Then set reset and reject and enable the clocks
 	 */
 	CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_CLOCK));
 	bfe_wait_bit(sc, BFE_SBTMSLOW, BFE_REJECT, 1000, 0);
 	bfe_wait_bit(sc, BFE_SBTMSHIGH, BFE_BUSY, 1000, 1);
 	CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_FGC | BFE_CLOCK | BFE_REJECT |
 				BFE_RESET));
 	CSR_READ_4(sc, BFE_SBTMSLOW);
 	DELAY(10);
 	/* Leave reset and reject set */
 	CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_REJECT | BFE_RESET));
 	DELAY(10);
 }
 
 static void
 bfe_core_reset(struct bfe_softc *sc)
 {
 	u_int32_t val;
 
 	/* Disable the core */
 	bfe_core_disable(sc);
 
 	/* and bring it back up */
 	CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_RESET | BFE_CLOCK | BFE_FGC));
 	CSR_READ_4(sc, BFE_SBTMSLOW);
 	DELAY(10);
 
 	/* Chip bug, clear SERR, IB and TO if they are set. */
 	if (CSR_READ_4(sc, BFE_SBTMSHIGH) & BFE_SERR)
 		CSR_WRITE_4(sc, BFE_SBTMSHIGH, 0);
 	val = CSR_READ_4(sc, BFE_SBIMSTATE);
 	if (val & (BFE_IBE | BFE_TO))
 		CSR_WRITE_4(sc, BFE_SBIMSTATE, val & ~(BFE_IBE | BFE_TO));
 
 	/* Clear reset and allow it to move through the core */
 	CSR_WRITE_4(sc, BFE_SBTMSLOW, (BFE_CLOCK | BFE_FGC));
 	CSR_READ_4(sc, BFE_SBTMSLOW);
 	DELAY(10);
 
 	/* Leave the clock set */
 	CSR_WRITE_4(sc, BFE_SBTMSLOW, BFE_CLOCK);
 	CSR_READ_4(sc, BFE_SBTMSLOW);
 	DELAY(10);
 }
 
 static void 
 bfe_cam_write(struct bfe_softc *sc, u_char *data, int index)
 {
 	u_int32_t val;
 
 	val  = ((u_int32_t) data[2]) << 24;
 	val |= ((u_int32_t) data[3]) << 16;
 	val |= ((u_int32_t) data[4]) <<  8;
 	val |= ((u_int32_t) data[5]);
 	CSR_WRITE_4(sc, BFE_CAM_DATA_LO, val);
 	val = (BFE_CAM_HI_VALID |
 			(((u_int32_t) data[0]) << 8) |
 			(((u_int32_t) data[1])));
 	CSR_WRITE_4(sc, BFE_CAM_DATA_HI, val);
 	CSR_WRITE_4(sc, BFE_CAM_CTRL, (BFE_CAM_WRITE |
 				(index << BFE_CAM_INDEX_SHIFT)));
 	bfe_wait_bit(sc, BFE_CAM_CTRL, BFE_CAM_BUSY, 10000, 1);
 }
 
 static void 
 bfe_set_rx_mode(struct bfe_softc *sc)
 {
 	struct ifnet *ifp = &sc->arpcom.ac_if;
 	struct ifmultiaddr  *ifma;
 	u_int32_t val;
 	int i = 0;
 
 	val = CSR_READ_4(sc, BFE_RXCONF);
 
 	if (ifp->if_flags & IFF_PROMISC)
 		val |= BFE_RXCONF_PROMISC;
 	else
 		val &= ~BFE_RXCONF_PROMISC;
 
 	if (ifp->if_flags & IFF_BROADCAST)
 		val &= ~BFE_RXCONF_DBCAST;
 	else
 		val |= BFE_RXCONF_DBCAST;
 
 
 	CSR_WRITE_4(sc, BFE_CAM_CTRL, 0);
 	bfe_cam_write(sc, sc->arpcom.ac_enaddr, i++);
 
 	if (ifp->if_flags & IFF_ALLMULTI)
 		val |= BFE_RXCONF_ALLMULTI;
 	else {
 		val &= ~BFE_RXCONF_ALLMULTI;
 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
 			if (ifma->ifma_addr->sa_family != AF_LINK)
 				continue;
 			bfe_cam_write(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
 					i++);
 		}
 	}
 
 	CSR_WRITE_4(sc, BFE_RXCONF, val);
 	BFE_OR(sc, BFE_CAM_CTRL, BFE_CAM_ENABLE);
 }
 
 static void
 bfe_dma_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 {
 	u_int32_t *ptr;
 
 	ptr = arg;
 	*ptr = segs->ds_addr;
 }
 
 static void
 bfe_dma_map_desc(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 {
 	struct bfe_desc *d;
 
 	d = arg;
 	/* The chip needs all addresses to be added to BFE_PCI_DMA */
 	d->bfe_addr = segs->ds_addr + BFE_PCI_DMA;
 }
 
 static void
 bfe_release_resources(struct bfe_softc *sc)
 {
 	device_t dev;
 	int i;
 
 	dev = sc->bfe_dev;
 
 	if (sc->bfe_vpd_prodname != NULL)
 		free(sc->bfe_vpd_prodname, M_DEVBUF);
 
 	if (sc->bfe_vpd_readonly != NULL)
 		free(sc->bfe_vpd_readonly, M_DEVBUF);
 
 	if (sc->bfe_intrhand != NULL)
 		bus_teardown_intr(dev, sc->bfe_irq, sc->bfe_intrhand);
 
 	if (sc->bfe_irq != NULL)
 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->bfe_irq);
 
 	if (sc->bfe_res != NULL)
 		bus_release_resource(dev, SYS_RES_MEMORY, 0x10, sc->bfe_res);
 
 	if(sc->bfe_tx_tag != NULL) {
 		bus_dmamap_unload(sc->bfe_tx_tag, sc->bfe_tx_map);
 		bus_dmamem_free(sc->bfe_tx_tag, sc->bfe_tx_list, sc->bfe_tx_map);
 		bus_dma_tag_destroy(sc->bfe_tx_tag);
 		sc->bfe_tx_tag = NULL;
 	}
 
 	if(sc->bfe_rx_tag != NULL) {
 		bus_dmamap_unload(sc->bfe_rx_tag, sc->bfe_rx_map);
 		bus_dmamem_free(sc->bfe_rx_tag, sc->bfe_rx_list, sc->bfe_rx_map);
 		bus_dma_tag_destroy(sc->bfe_rx_tag);
 		sc->bfe_rx_tag = NULL;
 	}
 
 	if(sc->bfe_tag != NULL) {
 		for(i = 0; i < BFE_TX_LIST_CNT; i++) {
 			bus_dmamap_destroy(sc->bfe_tag, sc->bfe_tx_ring[i].bfe_map);
 		}
 		bus_dma_tag_destroy(sc->bfe_tag);
         sc->bfe_tag = NULL;
 	}
 
 	if(sc->bfe_parent_tag != NULL)
 		bus_dma_tag_destroy(sc->bfe_parent_tag);
 
 	return;
 }
 
 static void
 bfe_read_eeprom(struct bfe_softc *sc, u_int8_t *data)
 {
 	long i;
 	u_int16_t *ptr = (u_int16_t *)data;
 
 	for(i = 0; i < 128; i += 2)
 		ptr[i/2] = CSR_READ_4(sc, 4096 + i);
 }
 
 static int
 bfe_wait_bit(struct bfe_softc *sc, u_int32_t reg, u_int32_t bit, 
 		u_long timeout, const int clear)
 {
 	u_long i;
 
 	for (i = 0; i < timeout; i++) {
 		u_int32_t val = CSR_READ_4(sc, reg);
 
 		if (clear && !(val & bit))
 			break;
 		if (!clear && (val & bit))
 			break;
 		DELAY(10);
 	}
 	if (i == timeout) {
 		printf("bfe%d: BUG!  Timeout waiting for bit %08x of register "
 				"%x to %s.\n", sc->bfe_unit, bit, reg, 
 				(clear ? "clear" : "set"));
 		return -1;
 	}
 	return 0;
 }
 
 static int
 bfe_readphy(struct bfe_softc *sc, u_int32_t reg, u_int32_t *val)
 {
 	int err; 
 
 	BFE_LOCK(sc);
 	/* Clear MII ISR */
 	CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII);
 	CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START |
 				(BFE_MDIO_OP_READ << BFE_MDIO_OP_SHIFT) |
 				(sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) |
 				(reg << BFE_MDIO_RA_SHIFT) |
 				(BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT)));
 	err = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0);
 	*val = CSR_READ_4(sc, BFE_MDIO_DATA) & BFE_MDIO_DATA_DATA;
 
 	BFE_UNLOCK(sc);
 	return err;
 }
 
 static int
 bfe_writephy(struct bfe_softc *sc, u_int32_t reg, u_int32_t val)
 {
 	int status;
 
 	BFE_LOCK(sc);
 	CSR_WRITE_4(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII);
 	CSR_WRITE_4(sc, BFE_MDIO_DATA, (BFE_MDIO_SB_START |
 				(BFE_MDIO_OP_WRITE << BFE_MDIO_OP_SHIFT) |
 				(sc->bfe_phyaddr << BFE_MDIO_PMD_SHIFT) |
 				(reg << BFE_MDIO_RA_SHIFT) |
 				(BFE_MDIO_TA_VALID << BFE_MDIO_TA_SHIFT) |
 				(val & BFE_MDIO_DATA_DATA)));
 	status = bfe_wait_bit(sc, BFE_EMAC_ISTAT, BFE_EMAC_INT_MII, 100, 0);
 	BFE_UNLOCK(sc);
 
 	return status;
 }
 
 /* 
  * XXX - I think this is handled by the PHY driver, but it can't hurt to do it
  * twice
  */
 static int
 bfe_setupphy(struct bfe_softc *sc)
 {
 	u_int32_t val;
 	BFE_LOCK(sc);
 
 	/* Enable activity LED */
 	bfe_readphy(sc, 26, &val);
 	bfe_writephy(sc, 26, val & 0x7fff); 
 	bfe_readphy(sc, 26, &val);
 
 	/* Enable traffic meter LED mode */
 	bfe_readphy(sc, 27, &val);
 	bfe_writephy(sc, 27, val | (1 << 6));
 
 	BFE_UNLOCK(sc);
 	return 0;
 }
 
 static void 
 bfe_stats_update(struct bfe_softc *sc)
 {
 	u_long reg;
 	u_int32_t *val;
 
 	val = &sc->bfe_hwstats.tx_good_octets;
 	for (reg = BFE_TX_GOOD_O; reg <= BFE_TX_PAUSE; reg += 4) {
 		*val++ += CSR_READ_4(sc, reg);
 	}
 	val = &sc->bfe_hwstats.rx_good_octets;
 	for (reg = BFE_RX_GOOD_O; reg <= BFE_RX_NPAUSE; reg += 4) {
 		*val++ += CSR_READ_4(sc, reg);
 	}
 }
 
 static void
 bfe_txeof(struct bfe_softc *sc)
 {
 	struct ifnet *ifp;
 	int i, chipidx;
 
 	BFE_LOCK(sc);
 
 	ifp = &sc->arpcom.ac_if;
 
 	chipidx = CSR_READ_4(sc, BFE_DMATX_STAT) & BFE_STAT_CDMASK;
 	chipidx /= sizeof(struct bfe_desc);
 
     i = sc->bfe_tx_cons;
 	/* Go through the mbufs and free those that have been transmitted */
     while(i != chipidx) {
 		struct bfe_data *r = &sc->bfe_tx_ring[i];
 		if(r->bfe_mbuf != NULL) {
 			ifp->if_opackets++;
 			m_freem(r->bfe_mbuf);
 			r->bfe_mbuf = NULL;
 			bus_dmamap_unload(sc->bfe_tag, r->bfe_map);
 		}
         sc->bfe_tx_cnt--;
         BFE_INC(i, BFE_TX_LIST_CNT);
 	}
 
 	if(i != sc->bfe_tx_cons) {
 		/* we freed up some mbufs */
 		sc->bfe_tx_cons = i;
 		ifp->if_flags &= ~IFF_OACTIVE;
 	}
 	if(sc->bfe_tx_cnt == 0)
 		ifp->if_timer = 0;
 	else
 		ifp->if_timer = 5;
 
 	BFE_UNLOCK(sc);
 }
 
 /* Pass a received packet up the stack */
 static void
 bfe_rxeof(struct bfe_softc *sc)
 {
 	struct mbuf *m;
 	struct ifnet *ifp;
 	struct bfe_rxheader *rxheader;
 	struct bfe_data *r;
 	int cons;
 	u_int32_t status, current, len, flags;
 
 	BFE_LOCK(sc);
 	cons = sc->bfe_rx_cons;
 	status = CSR_READ_4(sc, BFE_DMARX_STAT);
 	current = (status & BFE_STAT_CDMASK) / sizeof(struct bfe_desc);
 
 	ifp = &sc->arpcom.ac_if;
 
 	while(current != cons) {
 		r = &sc->bfe_rx_ring[cons];
 		m = r->bfe_mbuf;
 		rxheader = mtod(m, struct bfe_rxheader*);
 		bus_dmamap_sync(sc->bfe_tag, r->bfe_map, BUS_DMASYNC_POSTWRITE);
 		len = rxheader->len;
 		r->bfe_mbuf = NULL;
 
 		bus_dmamap_unload(sc->bfe_tag, r->bfe_map);
 		flags = rxheader->flags;
 
 		len -= ETHER_CRC_LEN;
 
 		/* flag an error and try again */
 		if ((len > ETHER_MAX_LEN+32) || (flags & BFE_RX_FLAG_ERRORS)) {
 			ifp->if_ierrors++;
 			if (flags & BFE_RX_FLAG_SERR)
 				ifp->if_collisions++;
 			bfe_list_newbuf(sc, cons, m);
 			continue;
 		}
 
 		/* Go past the rx header */
 		if (bfe_list_newbuf(sc, cons, NULL) == 0) {
 			m_adj(m, BFE_RX_OFFSET);
 			m->m_len = m->m_pkthdr.len = len;
 		} else {
 			bfe_list_newbuf(sc, cons, m);
 			ifp->if_ierrors++;
 			continue;
 		}
 
 		ifp->if_ipackets++;
 		m->m_pkthdr.rcvif = ifp;
 		BFE_UNLOCK(sc);
 		(*ifp->if_input)(ifp, m);
 		BFE_LOCK(sc);
 
         BFE_INC(cons, BFE_RX_LIST_CNT);
 	}
 	sc->bfe_rx_cons = cons;
 	BFE_UNLOCK(sc);
 }
 
 static void
 bfe_intr(void *xsc)
 {
 	struct bfe_softc *sc = xsc;
 	struct ifnet *ifp;
 	u_int32_t istat, imask, flag;
 
 	ifp = &sc->arpcom.ac_if;
 
 	BFE_LOCK(sc);
 
 	istat = CSR_READ_4(sc, BFE_ISTAT);
 	imask = CSR_READ_4(sc, BFE_IMASK);
 
 	/* 
 	 * Defer unsolicited interrupts - This is necessary because setting the
 	 * chips interrupt mask register to 0 doesn't actually stop the
 	 * interrupts
 	 */
 	istat &= imask;
 	CSR_WRITE_4(sc, BFE_ISTAT, istat);
 	CSR_READ_4(sc, BFE_ISTAT);
 
 	/* not expecting this interrupt, disregard it */
 	if(istat == 0) {
 		BFE_UNLOCK(sc);
 		return;
 	}
 
 	if(istat & BFE_ISTAT_ERRORS) {
 		flag = CSR_READ_4(sc, BFE_DMATX_STAT);
 		if(flag & BFE_STAT_EMASK)
 			ifp->if_oerrors++;
 
 		flag = CSR_READ_4(sc, BFE_DMARX_STAT);
 		if(flag & BFE_RX_FLAG_ERRORS)
 			ifp->if_ierrors++;
 
 		ifp->if_flags &= ~IFF_RUNNING;
 		bfe_init(sc);
 	}
 
 	/* A packet was received */
 	if(istat & BFE_ISTAT_RX)
 		bfe_rxeof(sc);
 
 	/* A packet was sent */
 	if(istat & BFE_ISTAT_TX)
 		bfe_txeof(sc);
 
 	/* We have packets pending, fire them out */ 
 	if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
 		bfe_start(ifp);
 
 	BFE_UNLOCK(sc);
 }
 
 static int
 bfe_encap(struct bfe_softc *sc, struct mbuf *m_head, u_int32_t *txidx)
 {
 	struct bfe_desc *d = NULL;
 	struct bfe_data *r = NULL;
 	struct mbuf     *m;
 	u_int32_t       frag, cur, cnt = 0;
 	int chainlen = 0;
 
 	if(BFE_TX_LIST_CNT - sc->bfe_tx_cnt < 2)
 		return(ENOBUFS);
 
 	/*
 	 * Count the number of frags in this chain to see if
 	 * we need to m_defrag.  Since the descriptor list is shared
 	 * by all packets, we'll m_defrag long chains so that they
 	 * do not use up the entire list, even if they would fit.
 	 */
 	for(m = m_head; m != NULL; m = m->m_next) 
 		chainlen++;
 
 
 	if ((chainlen > BFE_TX_LIST_CNT / 4) || 
 			((BFE_TX_LIST_CNT - (chainlen + sc->bfe_tx_cnt)) < 2)) {
 		m = m_defrag(m_head, M_DONTWAIT);
 		if (m == NULL) 
 			return(ENOBUFS);
 		m_head = m;
 	}
 
 	/*
 	 * Start packing the mbufs in this chain into
 	 * the fragment pointers. Stop when we run out
 	 * of fragments or hit the end of the mbuf chain.
 	 */
 	m = m_head;
 	cur = frag = *txidx;
 	cnt = 0;
 
 	for(m = m_head; m != NULL; m = m->m_next) {
 		if(m->m_len != 0) {
 			if((BFE_TX_LIST_CNT - (sc->bfe_tx_cnt + cnt)) < 2)
 				return(ENOBUFS);
 
 			d = &sc->bfe_tx_list[cur];
 			r = &sc->bfe_tx_ring[cur];
 			d->bfe_ctrl = BFE_DESC_LEN & m->m_len;
 			/* always intterupt on completion */
 			d->bfe_ctrl |= BFE_DESC_IOC;
 			if(cnt == 0)
 				/* Set start of frame */
 				d->bfe_ctrl |= BFE_DESC_SOF;
 			if(cur == BFE_TX_LIST_CNT - 1)
 				/* Tell the chip to wrap to the start of the descriptor list */
 				d->bfe_ctrl |= BFE_DESC_EOT;
 
 			bus_dmamap_load(sc->bfe_tag, r->bfe_map, mtod(m, void*), m->m_len, 
 					bfe_dma_map_desc, d, 0);
 			bus_dmamap_sync(sc->bfe_tag, r->bfe_map, BUS_DMASYNC_PREREAD);
 
 			frag = cur;
             BFE_INC(cur, BFE_TX_LIST_CNT);
 			cnt++;
 		}
 	}
 
 	if (m != NULL)
 		return(ENOBUFS);
 
 	sc->bfe_tx_list[frag].bfe_ctrl |= BFE_DESC_EOF;
 	sc->bfe_tx_ring[frag].bfe_mbuf = m_head;
 	bus_dmamap_sync(sc->bfe_tx_tag, sc->bfe_tx_map, BUS_DMASYNC_PREREAD);
 
 	*txidx = cur;
 	sc->bfe_tx_cnt += cnt;
 	return (0);
 }
 
 /*
  * Set up to transmit a packet
  */
 static void
 bfe_start(struct ifnet *ifp)
 {
 	struct bfe_softc *sc;
 	struct mbuf *m_head = NULL;
 	int idx;
 
 	sc = ifp->if_softc;
 	idx = sc->bfe_tx_prod;
 
 	BFE_LOCK(sc);
 
 	/* 
 	 * not much point trying to send if the link is down or we have nothing to
 	 * send
 	 */
 	if (!sc->bfe_link && ifp->if_snd.ifq_len < 10) {
 		BFE_UNLOCK(sc);
 		return;
 	}
 
 	if (ifp->if_flags & IFF_OACTIVE) {
 		BFE_UNLOCK(sc);
 		return;
 	}
 
 	while(sc->bfe_tx_ring[idx].bfe_mbuf == NULL) {
 		IF_DEQUEUE(&ifp->if_snd, m_head);
 		if(m_head == NULL)
 			break;
 
 		/* 
 		 * Pack the data into the tx ring.  If we dont have enough room, let
 		 * the chip drain the ring
 		 */
 		if(bfe_encap(sc, m_head, &idx)) {
 			IF_PREPEND(&ifp->if_snd, m_head);
 			ifp->if_flags |= IFF_OACTIVE;
 			break;
 		}
 
 		/*
 		 * If there's a BPF listener, bounce a copy of this frame
 		 * to him.
 		 */
 		BPF_MTAP(ifp, m_head);
 	}
 
 	sc->bfe_tx_prod = idx;
 	/* Transmit - twice due to apparent hardware bug */
 	CSR_WRITE_4(sc, BFE_DMATX_PTR, idx * sizeof(struct bfe_desc));
 	CSR_WRITE_4(sc, BFE_DMATX_PTR, idx * sizeof(struct bfe_desc));
 
 	/*
 	 * Set a timeout in case the chip goes out to lunch.
 	 */
 	ifp->if_timer = 5;
 	BFE_UNLOCK(sc);
 }
 
 static void
 bfe_init(void *xsc)
 {
 
     uint32_t val1, val2, val3;
 
 	struct bfe_softc *sc = (struct bfe_softc*)xsc;
 	struct ifnet *ifp = &sc->arpcom.ac_if;
 
 	BFE_LOCK(sc);
 
 	if (ifp->if_flags & IFF_RUNNING) {
 		BFE_UNLOCK(sc);
 		return;
 	}
 
 /* for test only */ 
 	val1 = CSR_READ_4(sc, BFE_CAM_CTRL);
     val2 = CSR_READ_4(sc, BFE_MAC_CTRL); 
 	val3 = CSR_READ_4(sc, BFE_ENET_CTRL);
 	printf("At entry: CAM_CTRL =%08x, MAC_CTRL =%08x, ENET_CTRL=%08x\n",
             val1, val2, val3);
 /* for test end */
 
 	bfe_stop(sc);
 	bfe_chip_reset(sc);
 
 /* for test only */ 
 	val1 = CSR_READ_4(sc, BFE_CAM_CTRL);
     val2 = CSR_READ_4(sc, BFE_MAC_CTRL); 
 	val3 = CSR_READ_4(sc, BFE_ENET_CTRL);
 	printf("After reset: CAM_CTRL =%08x, MAC_CTRL =%08x, ENET_CTRL=%08x\n",
             val1, val2, val3);
 /* for test end */
 
 	if (bfe_list_rx_init(sc) == ENOBUFS) {
 		printf("bfe%d: bfe_init failed. Not enough memory for list buffers\n",
 				sc->bfe_unit);
 		bfe_stop(sc);
 		return;
 	}
 
 	bfe_set_rx_mode(sc);
 
 	/* Enable the chip and core */
 	BFE_OR(sc, BFE_ENET_CTRL, BFE_ENET_ENABLE);
 	/* Enable interrupts */
 	CSR_WRITE_4(sc, BFE_IMASK, BFE_IMASK_DEF);
 
 	bfe_ifmedia_upd(ifp);
 	ifp->if_flags |= IFF_RUNNING;
 	ifp->if_flags &= ~IFF_OACTIVE;
 
 	sc->bfe_stat_ch = timeout(bfe_tick, sc, hz);
 	BFE_UNLOCK(sc);
 
 /* for test only */ 
 	val1 = CSR_READ_4(sc, BFE_CAM_CTRL);
     val2 = CSR_READ_4(sc, BFE_MAC_CTRL); 
 	val3 = CSR_READ_4(sc, BFE_ENET_CTRL);
 	printf("At exit: CAM_CTRL =%08x, MAC_CTRL =%08x, ENET_CTRL=%08x\n",
             val1, val2, val3);
 /* for test end */
 
 }
 
 /*
  * Set media options.
  */
 static int
 bfe_ifmedia_upd(struct ifnet *ifp)
 {
 	struct bfe_softc *sc;
 	struct mii_data *mii;
 
 	sc = ifp->if_softc;
 
 	BFE_LOCK(sc);
 
 	mii = device_get_softc(sc->bfe_miibus);
 	sc->bfe_link = 0;
 	if (mii->mii_instance) {
 		struct mii_softc *miisc;
 		for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
 				miisc = LIST_NEXT(miisc, mii_list))
 			mii_phy_reset(miisc);
 	}
 	mii_mediachg(mii);
 
 	BFE_UNLOCK(sc);
 	return(0);
 }
 
 /*
  * Report current media status.
  */
 static void
 bfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
 {
 	struct bfe_softc *sc = ifp->if_softc;
 	struct mii_data *mii;
 
 	BFE_LOCK(sc);
 
 	mii = device_get_softc(sc->bfe_miibus);
 	mii_pollstat(mii);
 	ifmr->ifm_active = mii->mii_media_active;
 	ifmr->ifm_status = mii->mii_media_status;
 
 	BFE_UNLOCK(sc);
 }
 
 static int
 bfe_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
 {
 	struct bfe_softc *sc = ifp->if_softc;
 	struct ifreq *ifr = (struct ifreq *) data;
 	struct mii_data *mii;
 	int error = 0;
 
 	BFE_LOCK(sc);
 
 	switch(command) {
 		case SIOCSIFFLAGS:
 			if(ifp->if_flags & IFF_UP)
 				if(ifp->if_flags & IFF_RUNNING)
 					bfe_set_rx_mode(sc);
 				else
 					bfe_init(sc);
 			else if(ifp->if_flags & IFF_RUNNING)
 				bfe_stop(sc);
 			break;
 		case SIOCADDMULTI:
 		case SIOCDELMULTI:
 			if(ifp->if_flags & IFF_RUNNING)
 				bfe_set_rx_mode(sc);
 			break;
 		case SIOCGIFMEDIA:
 		case SIOCSIFMEDIA:
 			mii = device_get_softc(sc->bfe_miibus);
 			error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
 			break;
 		default:
 			error = ether_ioctl(ifp, command, data); 
 			break;
 	}
 
 	BFE_UNLOCK(sc);
 	return error;
 }
 
 static void
 bfe_watchdog(struct ifnet *ifp)
 {
 	struct bfe_softc *sc;
 
 	sc = ifp->if_softc;
 
 	BFE_LOCK(sc);
 
 	printf("bfe%d: watchdog timeout -- resetting\n", sc->bfe_unit);
 
 	ifp->if_flags &= ~IFF_RUNNING;
 	bfe_init(sc);
 
 	ifp->if_oerrors++;
 
 	BFE_UNLOCK(sc);
 }
 
 static void
 bfe_tick(void *xsc)
 {
 	struct bfe_softc *sc = xsc;
 	struct mii_data *mii;
 
 	if (sc == NULL)
 		return;
 
 	BFE_LOCK(sc);
 
 	mii = device_get_softc(sc->bfe_miibus);
 
 	bfe_stats_update(sc);
 	sc->bfe_stat_ch = timeout(bfe_tick, sc, hz);
 
 	if(sc->bfe_link) {
 		BFE_UNLOCK(sc);
 		return;
 	}
 
 	mii_tick(mii);
 	if (!sc->bfe_link && mii->mii_media_status & IFM_ACTIVE &&
 			IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) 
 		sc->bfe_link++;
 
 	BFE_UNLOCK(sc);
 }
 
 /*
  * Stop the adapter and free any mbufs allocated to the
  * RX and TX lists.
  */
 static void
 bfe_stop(struct bfe_softc *sc)
 {
 	struct ifnet *ifp;
 
 	BFE_LOCK(sc);
 
 	untimeout(bfe_tick, sc, sc->bfe_stat_ch);
 
 	ifp = &sc->arpcom.ac_if;
 
 	bfe_chip_halt(sc);
     bfe_tx_ring_free(sc);
 	bfe_rx_ring_free(sc);
 
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 
 	BFE_UNLOCK(sc);
 }
 
 --------------090505010100030000050608--
 
State-Changed-From-To: open->closed 
State-Changed-By: dmlb 
State-Changed-When: Sun May 23 01:40:08 PDT 2004 
State-Changed-Why:  
Patch supplied commited to tree. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=64656 
>Unformatted:
