* Copyright (c) 1988 Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Digital Equipment Corp.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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
* @(#)if_qe.c 7.20 (Berkeley) 3/28/91
/* from @(#)if_qe.c 1.15 (ULTRIX) 4/16/86 */
/****************************************************************
* Licensed from Digital Equipment Corporation *
* Digital Equipment Corporation *
* Maynard, Massachusetts *
* The Information in this software is subject to change *
* without notice and should not be construed as a commitment *
* by Digital Equipment Corporation. Digital makes no *
* representations about the suitability of this software for *
* any purpose. It is supplied "As Is" without expressed or *
* If the Regents of the University of California or its *
* licensees modify the software in a manner creating *
* derivative copyright rights, appropriate copyright *
* legends may be placed on the derivative work in addition *
* to that set forth above. *
****************************************************************/
/* ---------------------------------------------------------------------
* Rename "unused_multi" to "qunused_multi" for extending Generic
* 18-mar-86 -- jaw br/cvec changed to NOT use registers.
* 12 March 86 -- Jeff Chase
* Modified to handle the new MCLGET macro
* Changed if_qe_data.c to use more receive buffers
* Added a flag to poke with adb to log qe_restarts on console
* Changed the watch dog timer from 30 seconds to 3. VMS is using
* less than 1 second in their's. Also turned the printf into an
* 09/16/85 -- Larry Cohen
* Add 43bsd alpha tape changes for subnet routing
* Panic on a non-existent memory interrupt and the case where a packet
* was chained. The first should never happen because non-existant
* memory interrupts cause a bus reset. The second should never happen
* because we hang 2k input buffers on the device.
* Fixed the broadcast loopback code to handle Clusters without
* Return default hardware address on ioctl request.
* Added internal extended loopback capability.
* Fixed bug that caused every other transmit descriptor to be used
* instead of every descriptor.
* Added watchdog timer to mask hardware bug that causes device lockup.
* Reworked driver to use q-bus mapping routines. MicroVAX-I now does
* copying instead of m-buf shuffleing.
* A number of deficencies in the hardware/firmware were compensated
* for. See comments in qestart and qerint.
* Added usage counts for multicast addresses.
* Updated general protocol support to allow access to the Ethernet
* Added support for new ioctls to add and delete multicast addresses
* and set the physical address.
* Add support for general protocols.
* Integrated Shannon changes. (allow arp above 1024 and ? )
* Initial version of driver. derived from IL driver.
* ---------------------------------------------------------------------
* Digital Q-BUS to NI Adapter
#include "netinet/in_systm.h"
#include "netinet/in_var.h"
#include "netinet/if_ether.h"
#include "netiso/iso_var.h"
extern char all_es_snpa
[], all_is_snpa
[], all_l1is_snpa
[], all_l2is_snpa
[];
#include "../include/pte.h"
#include "../include/cpu.h"
#include "../include/mtpr.h"
#include "../uba/ubareg.h"
#include "../uba/ubavar.h"
#if NQE == 1 && !defined(QNIVERT)
#define NRCV 15 /* Receive descriptors */
#define NRCV 10 /* Receive descriptors */
#define NXMT 5 /* Transmit descriptors */
#define NTOT (NXMT + NRCV)
#define QETIMEOUT 2 /* transmit timeout, must be > 1 */
#define QESLOWTIMEOUT 40 /* timeout when no xmits in progress */
* Ethernet software status per interface.
* Each interface is referenced by a network interface structure,
* qe_if, which the routing code uses to locate the interface.
* This structure contains the output queue for the interface, its address, ...
struct arpcom qe_ac
; /* Ethernet common part */
#define qe_if qe_ac.ac_if /* network-visible interface */
#define qe_addr qe_ac.ac_enaddr /* hardware Ethernet address */
struct ifubinfo qe_uba
; /* Q-bus resources */
struct ifrw qe_ifr
[NRCV
]; /* for receive buffers; */
struct ifxmt qe_ifw
[NXMT
]; /* for xmit buffers; */
int qe_flags
; /* software state */
#define QEF_FASTTIMEO 0x04
int setupaddr
; /* mapping info for setup pkts */
int ipl
; /* interrupt priority */
struct qe_ring
*rringaddr
; /* mapping info for rings */
struct qe_ring
*tringaddr
; /* "" */
struct qe_ring rring
[NRCV
+1]; /* Receive ring descriptors */
struct qe_ring tring
[NXMT
+1]; /* Transmit ring descriptors */
u_char setup_pkt
[16][8]; /* Setup packet */
int rindex
; /* Receive index */
int tindex
; /* Transmit index */
int otindex
; /* Old transmit index */
int qe_intvec
; /* Interrupt vector */
struct qedevice
*addr
; /* device addr */
int setupqueued
; /* setup packet queued */
int nxmit
; /* Transmits in progress */
int qe_restarts
; /* timeouts */
struct uba_device
*qeinfo
[NQE
];
extern struct timeval time
;
int qeprobe(), qeattach(), qeintr(), qetimeout();
int qeinit(), qeioctl(), qereset(), qestart();
struct uba_driver qedriver
=
{ qeprobe
, 0, qeattach
, 0, qestd
, "qe", qeinfo
};
#define QEUNIT(x) minor(x)
* The deqna shouldn't receive more than ETHERMTU + sizeof(struct ether_header)
* but will actually take in up to 2048 bytes. To guard against the receiver
* chaining buffers (which we aren't prepared to handle) we allocate 2kb
#define MAXPACKETSIZE 2048 /* Should really be ETHERMTU */
* Probe the QNA to see if it's there
register int br
, cvec
; /* r11, r10 value-result */
register struct qedevice
*addr
= (struct qedevice
*)reg
;
register struct qe_ring
*rp
;
register struct qe_ring
*prp
; /* physical rp */
register struct qe_softc
*sc
= &qe_softc
[ui
->ui_unit
];
br
= 0; cvec
= br
; br
= cvec
;
* The QNA interrupts on i/o operations. To do an I/O operation
* we have to setup the interface by transmitting a setup packet.
addr
->qe_csr
&= ~QE_RESET
;
addr
->qe_vector
= (uba_hd
[numuba
].uh_lastiv
-= 4);
* Map the communications area and the setup packet.
uballoc(0, (caddr_t
)sc
->setup_pkt
, sizeof(sc
->setup_pkt
), 0);
sc
->rringaddr
= (struct qe_ring
*) uballoc(0, (caddr_t
)sc
->rring
,
sizeof(struct qe_ring
) * (NTOT
+2), 0);
prp
= (struct qe_ring
*)UBAI_ADDR((int)sc
->rringaddr
);
* The QNA will loop the setup packet back to the receive ring
* for verification, therefore we initialize the first
* receive & transmit ring descriptors and link the setup packet
qeinitdesc(sc
->tring
, (caddr_t
)UBAI_ADDR(sc
->setupaddr
),
qeinitdesc(sc
->rring
, (caddr_t
)UBAI_ADDR(sc
->setupaddr
),
rp
= (struct qe_ring
*)sc
->tring
;
rp
->qe_flag
= rp
->qe_status1
= QE_NOTYET
;
rp
= (struct qe_ring
*)sc
->rring
;
rp
->qe_flag
= rp
->qe_status1
= QE_NOTYET
;
* Get the addr off of the interface and place it into the setup
* packet. This code looks strange due to the fact that the address
* is placed in the setup packet in col. major order.
for( i
= 0 ; i
< 6 ; i
++ )
sc
->setup_pkt
[i
][1] = addr
->qe_sta_addr
[i
];
* Start the interface and wait for the packet.
addr
->qe_csr
= QE_INT_ENABLE
| QE_XMIT_INT
| QE_RCV_INT
;
addr
->qe_rcvlist_lo
= (short)prp
;
addr
->qe_rcvlist_hi
= (short)((int)prp
>> 16);
addr
->qe_xmtlist_lo
= (short)prp
;
addr
->qe_xmtlist_hi
= (short)((int)prp
>> 16);
* All done with the bus resources.
ubarelse(0, &sc
->setupaddr
);
ubarelse(0, (int *)&sc
->rringaddr
);
sc
->ipl
= br
= qbgetpri();
return( sizeof(struct qedevice
) );
* Interface exists: make available by filling in network interface
* record. System will initialize the interface when it is ready
register struct qe_softc
*sc
= &qe_softc
[ui
->ui_unit
];
register struct ifnet
*ifp
= &sc
->qe_if
;
register struct qedevice
*addr
= (struct qedevice
*)ui
->ui_addr
;
ifp
->if_unit
= ui
->ui_unit
;
* The Deqna is cable of transmitting broadcasts, but
* doesn't listen to its own.
ifp
->if_flags
= IFF_BROADCAST
| IFF_SIMPLEX
;
* Read the address from the prom and save it.
sc
->setup_pkt
[i
][1] = sc
->qe_addr
[i
] = addr
->qe_sta_addr
[i
] & 0xff;
printf("qe%d: %s, hardware address %s\n", ui
->ui_unit
,
addr
->qe_vector
&01 ? "delqa":"deqna",
ether_sprintf(sc
->qe_addr
));
* Save the vector for initialization at reset time.
sc
->qe_intvec
= addr
->qe_vector
;
ifp
->if_output
= ether_output
;
ifp
->if_watchdog
= qetimeout
;
sc
->qe_uba
.iff_flags
= UBA_CANTWAIT
;
* Reset of interface after UNIBUS reset.
* If interface is on specified uba, reset its state.
register struct uba_device
*ui
;
if (unit
>= NQE
|| (ui
= qeinfo
[unit
]) == 0 || ui
->ui_alive
== 0 ||
qe_softc
[unit
].qe_if
.if_flags
&= ~IFF_RUNNING
;
* Initialization of interface.
register struct qe_softc
*sc
= &qe_softc
[unit
];
register struct uba_device
*ui
= qeinfo
[unit
];
register struct qedevice
*addr
= (struct qedevice
*)ui
->ui_addr
;
register struct ifnet
*ifp
= &sc
->qe_if
;
if (ifp
->if_addrlist
== (struct ifaddr
*)0)
if (sc
->qe_flags
& QEF_RUNNING
)
if ((ifp
->if_flags
& IFF_RUNNING
) == 0) {
* map the communications area onto the device
i
= uballoc(0, (caddr_t
)sc
->rring
,
sizeof(struct qe_ring
) * (NTOT
+2), 0);
sc
->rringaddr
= (struct qe_ring
*)UBAI_ADDR(i
);
sc
->tringaddr
= sc
->rringaddr
+ NRCV
+ 1;
i
= uballoc(0, (caddr_t
)sc
->setup_pkt
,
sizeof(sc
->setup_pkt
), 0);
sc
->setupaddr
= UBAI_ADDR(i
);
if (if_ubaminit(&sc
->qe_uba
, ui
->ui_ubanum
,
sizeof (struct ether_header
), (int)btoc(MAXPACKETSIZE
),
sc
->qe_ifr
, NRCV
, sc
->qe_ifw
, NXMT
) == 0) {
printf("qe%d: can't allocate uba resources\n", unit
);
sc
->qe_if
.if_flags
&= ~IFF_UP
;
* Init the buffer descriptors and indexes for each of the lists and
* loop them back to form a ring.
for (i
= 0; i
< NRCV
; i
++) {
qeinitdesc( &sc
->rring
[i
],
(caddr_t
)UBAI_ADDR(sc
->qe_ifr
[i
].ifrw_info
), MAXPACKETSIZE
);
sc
->rring
[i
].qe_flag
= sc
->rring
[i
].qe_status1
= QE_NOTYET
;
sc
->rring
[i
].qe_valid
= 1;
qeinitdesc(&sc
->rring
[i
], (caddr_t
)NULL
, 0);
sc
->rring
[i
].qe_addr_lo
= (short)sc
->rringaddr
;
sc
->rring
[i
].qe_addr_hi
= (short)((int)sc
->rringaddr
>> 16);
sc
->rring
[i
].qe_chain
= 1;
sc
->rring
[i
].qe_flag
= sc
->rring
[i
].qe_status1
= QE_NOTYET
;
sc
->rring
[i
].qe_valid
= 1;
for( i
= 0 ; i
<= NXMT
; i
++ )
qeinitdesc(&sc
->tring
[i
], (caddr_t
)NULL
, 0);
sc
->tring
[i
].qe_addr_lo
= (short)sc
->tringaddr
;
sc
->tring
[i
].qe_addr_hi
= (short)((int)sc
->tringaddr
>> 16);
sc
->tring
[i
].qe_chain
= 1;
sc
->tring
[i
].qe_flag
= sc
->tring
[i
].qe_status1
= QE_NOTYET
;
sc
->tring
[i
].qe_valid
= 1;
sc
->nxmit
= sc
->otindex
= sc
->tindex
= sc
->rindex
= 0;
* Take the interface out of reset, program the vector,
* enable interrupts, and tell the world we are up.
addr
->qe_vector
= sc
->qe_intvec
;
addr
->qe_csr
= QE_RCV_ENABLE
| QE_INT_ENABLE
| QE_XMIT_INT
|
addr
->qe_rcvlist_lo
= (short)sc
->rringaddr
;
addr
->qe_rcvlist_hi
= (short)((int)sc
->rringaddr
>> 16);
ifp
->if_flags
|= IFF_UP
| IFF_RUNNING
;
sc
->qe_flags
|= QEF_RUNNING
;
sc
->qe_if
.if_timer
= QESLOWTIMEOUT
; /* Start watchdog */
* Start output on interface.
struct uba_device
*ui
= qeinfo
[unit
];
register struct qe_softc
*sc
= &qe_softc
[unit
];
register struct qedevice
*addr
;
register struct qe_ring
*rp
;
addr
= (struct qedevice
*)ui
->ui_addr
;
* The deqna doesn't look at anything but the valid bit
* to determine if it should transmit this packet. If you have
* a ring and fill it the device will loop indefinately on the
* packet and continue to flood the net with packets until you
* break the ring. For this reason we never queue more than n-1
* packets in the transmit ring.
* The microcoders should have obeyed their own defination of the
* flag and status words, but instead we have to compensate.
sc
->tring
[index
].qe_valid
== 0 && sc
->nxmit
< (NXMT
-1) ;
sc
->tindex
= index
= ++index
% NXMT
){
buf_addr
= sc
->setupaddr
;
IF_DEQUEUE(&sc
->qe_if
.if_snd
, m
);
buf_addr
= sc
->qe_ifw
[index
].ifw_info
;
len
= if_ubaput(&sc
->qe_uba
, &sc
->qe_ifw
[index
], m
);
* Does buffer end on odd byte ?
rp
->qe_buf_len
= -(len
/2);
buf_addr
= UBAI_ADDR(buf_addr
);
rp
->qe_flag
= rp
->qe_status1
= QE_NOTYET
;
rp
->qe_addr_lo
= (short)buf_addr
;
rp
->qe_addr_hi
= (short)(buf_addr
>> 16);
rp
->qe_flag
= rp
->qe_status1
= QE_NOTYET
;
sc
->qe_flags
|= QEF_FASTTIMEO
;
sc
->qe_if
.if_timer
= QETIMEOUT
;
* See if the xmit list is invalid.
if( addr
->qe_csr
& QE_XL_INVALID
) {
buf_addr
= (int)(sc
->tringaddr
+index
);
addr
->qe_xmtlist_lo
= (short)buf_addr
;
addr
->qe_xmtlist_hi
= (short)(buf_addr
>> 16);
* Ethernet interface interrupt processor
register struct qe_softc
*sc
= &qe_softc
[unit
];
struct qedevice
*addr
= (struct qedevice
*)qeinfo
[unit
]->ui_addr
;
if (!(sc
->qe_flags
& QEF_FASTTIMEO
))
sc
->qe_if
.if_timer
= QESLOWTIMEOUT
; /* Restart timer clock */
addr
->qe_csr
= QE_RCV_ENABLE
| QE_INT_ENABLE
| QE_XMIT_INT
| QE_RCV_INT
| QE_ILOOP
;
if( csr
& QE_NEX_MEM_INT
)
printf("qe%d: Nonexistent memory interrupt\n", unit
);
if( addr
->qe_csr
& QE_RL_INVALID
&& sc
->rring
[sc
->rindex
].qe_status1
== QE_NOTYET
) {
buf_addr
= (int)&sc
->rringaddr
[sc
->rindex
];
addr
->qe_rcvlist_lo
= (short)buf_addr
;
addr
->qe_rcvlist_hi
= (short)(buf_addr
>> 16);
* Ethernet interface transmit interrupt.
register struct qe_softc
*sc
= &qe_softc
[unit
];
register struct qe_ring
*rp
;
register struct ifxmt
*ifxp
;
while( sc
->otindex
!= sc
->tindex
&& sc
->tring
[sc
->otindex
].qe_status1
!= QE_NOTYET
&& sc
->nxmit
> 0 ) {
* Save the status words from the descriptor so that it can
rp
= &sc
->tring
[sc
->otindex
];
status1
= rp
->qe_status1
;
setupflag
= rp
->qe_setup
;
len
= (-rp
->qe_buf_len
) * 2;
* Init the buffer descriptor
bzero((caddr_t
)rp
, sizeof(struct qe_ring
));
sc
->qe_flags
&= ~QEF_FASTTIMEO
;
sc
->qe_if
.if_timer
= QESLOWTIMEOUT
;
sc
->qe_if
.if_collisions
+= ( status1
& QE_CCNT
) >> 4;
ifxp
= &sc
->qe_ifw
[sc
->otindex
];
m_freem(ifxp
->ifw_xtofree
);
sc
->otindex
= ++sc
->otindex
% NXMT
;
(void) qestart( &sc
->qe_if
);
* Ethernet interface receiver interrupt.
* If can't determine length from type, then have to drop packet.
* Othewise decapsulate packet based on type and pass to type specific
* higher-level input routine.
register struct qe_softc
*sc
= &qe_softc
[unit
];
register struct qe_ring
*rp
;
int len
, status1
, status2
;
* Traverse the receive ring looking for packets to pass back.
* The search is complete when we find a descriptor not in use.
* As in the transmit case the deqna doesn't honor it's own protocols
* so there exists the possibility that the device can beat us around
* the ring. The proper way to guard against this is to insure that
* there is always at least one invalid descriptor. We chose instead
* to make the ring large enough to minimize the problem. With a ring
* size of 4 we haven't been able to see the problem. To be safe we
while (sc
->rring
[sc
->rindex
].qe_status1
== QE_NOTYET
&& nrcv
< NRCV
) {
* We got an interrupt but did not find an input packet
* where we expected one to be, probably because the ring
* We search forward to find a valid packet and start
* processing from there. If no valid packet is found it
* means we processed all the packets during a previous
* interrupt and that the QE_RCV_INT bit was set while
* we were processing one of these earlier packets. In
* this case we can safely ignore the interrupt (by dropping
* through the code below).
sc
->rindex
= (sc
->rindex
+ 1) % NRCV
;
log(LOG_ERR
, "qe%d: ring overrun, resync'd by skipping %d\n",
for( ; sc
->rring
[sc
->rindex
].qe_status1
!= QE_NOTYET
; sc
->rindex
= ++sc
->rindex
% NRCV
){
rp
= &sc
->rring
[sc
->rindex
];
status1
= rp
->qe_status1
;
status2
= rp
->qe_status2
;
bzero((caddr_t
)rp
, sizeof(struct qe_ring
));
if( (status1
& QE_MASK
) == QE_MASK
)
panic("qe: chained packet");
len
= ((status1
& QE_RBL_HI
) | (status2
& QE_RBL_LO
)) + 60;
if (status1
& QE_ERROR
) {
if ((status1
& QE_RUNT
) == 0)
* We don't process setup packets.
if( !(status1
& QE_ESETUP
) )
qeread(sc
, &sc
->qe_ifr
[sc
->rindex
],
len
- sizeof(struct ether_header
));
* Return the buffer to the ring
bufaddr
= (int)UBAI_ADDR(sc
->qe_ifr
[sc
->rindex
].ifrw_info
);
rp
->qe_buf_len
= -((MAXPACKETSIZE
)/2);
rp
->qe_addr_lo
= (short)bufaddr
;
rp
->qe_addr_hi
= (short)((int)bufaddr
>> 16);
rp
->qe_flag
= rp
->qe_status1
= QE_NOTYET
;
* Process an ioctl request.
register struct ifnet
*ifp
;
struct qe_softc
*sc
= &qe_softc
[ifp
->if_unit
];
struct ifaddr
*ifa
= (struct ifaddr
*)data
;
int s
= splimp(), error
= 0;
switch(ifa
->ifa_addr
->sa_family
) {
((struct arpcom
*)ifp
)->ac_ipaddr
=
arpwhohas((struct arpcom
*)ifp
, &IA_SIN(ifa
)->sin_addr
);
register struct ns_addr
*ina
= &(IA_SNS(ifa
)->sns_addr
);
ina
->x_host
= *(union ns_host
*)(sc
->qe_addr
);
qe_setaddr(ina
->x_host
.c_host
, ifp
->if_unit
);
if ((ifp
->if_flags
& IFF_UP
) == 0 &&
sc
->qe_flags
& QEF_RUNNING
) {
(qeinfo
[ifp
->if_unit
]->ui_addr
))->qe_csr
= QE_RESET
;
sc
->qe_flags
&= ~QEF_RUNNING
;
} else if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) ==
IFF_RUNNING
&& (sc
->qe_flags
& QEF_RUNNING
) == 0)
* set ethernet address for unit
qe_setaddr(physaddr
, unit
)
register struct qe_softc
*sc
= &qe_softc
[unit
];
sc
->setup_pkt
[i
][1] = sc
->qe_addr
[i
] = physaddr
[i
];
sc
->qe_flags
|= QEF_SETADDR
;
if (sc
->qe_if
.if_flags
& IFF_RUNNING
)
* Initialize a ring descriptor with mbuf allocation side effects
qeinitdesc(rp
, addr
, len
)
register struct qe_ring
*rp
;
caddr_t addr
; /* mapped address */
* clear the entire descriptor
bzero((caddr_t
)rp
, sizeof(struct qe_ring
));
rp
->qe_buf_len
= -(len
/2);
rp
->qe_addr_lo
= (short)addr
;
rp
->qe_addr_hi
= (short)((int)addr
>> 16);
* Build a setup packet - the physical address will already be present
* Copy the target address to the rest of the entries in this row.
for ( j
= 0; j
< 6 ; j
++ )
for ( i
= 2 ; i
< 8 ; i
++ )
sc
->setup_pkt
[j
][i
] = sc
->setup_pkt
[j
][1];
* Duplicate the first half.
bcopy((caddr_t
)sc
->setup_pkt
[0], (caddr_t
)sc
->setup_pkt
[8], 64);
* Fill in the broadcast (and ISO multicast) address(es).
for ( i
= 0; i
< 6 ; i
++ ) {
sc
->setup_pkt
[i
][2] = 0xff;
sc
->setup_pkt
[i
][3] = all_es_snpa
[i
];
sc
->setup_pkt
[i
][4] = all_is_snpa
[i
];
sc
->setup_pkt
[i
][5] = all_l1is_snpa
[i
];
sc
->setup_pkt
[i
][6] = all_l2is_snpa
[i
];
* Pass a packet to the higher levels.
* We deal with the trailer protocol here.
register struct qe_softc
*sc
;
* Deal with trailer protocol: if type is INET trailer
* get true type from first 16-bit word past data.
* Remember that type was trailer by setting off.
eh
= (struct ether_header
*)ifrw
->ifrw_addr
;
eh
->ether_type
= ntohs((u_short
)eh
->ether_type
);
#define qedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
if (eh
->ether_type
>= ETHERTYPE_TRAIL
&&
eh
->ether_type
< ETHERTYPE_TRAIL
+ETHERTYPE_NTRAILER
) {
off
= (eh
->ether_type
- ETHERTYPE_TRAIL
) * 512;
eh
->ether_type
= ntohs(*qedataaddr(eh
,off
, u_short
*));
resid
= ntohs(*(qedataaddr(eh
, off
+2, u_short
*)));
* Pull packet off interface. Off is nonzero if packet
* has trailing header; qeget will then force this header
* information to be at the front, but we still have to drop
* the type and length which are at the front of any trailer data.
m
= if_ubaget(&sc
->qe_uba
, ifrw
, len
, off
, &sc
->qe_if
);
ether_input(&sc
->qe_if
, eh
, m
);
* Watchdog timeout routine. There is a condition in the hardware that
* causes the board to lock up under heavy load. This routine detects
* the hang up and restarts the device.
register struct qe_softc
*sc
;
log(LOG_ERR
, "qe%d: transmit timeout, restarted %d\n",
unit
, sc
->qe_restarts
++);
* Restart for board lockup problem.
register struct qe_softc
*sc
;
register struct ifnet
*ifp
= &sc
->qe_if
;
register struct qedevice
*addr
= sc
->addr
;
register struct qe_ring
*rp
;
addr
->qe_csr
&= ~QE_RESET
;
for (i
= 0, rp
= sc
->tring
; i
< NXMT
; rp
++, i
++) {
rp
->qe_flag
= rp
->qe_status1
= QE_NOTYET
;
sc
->nxmit
= sc
->otindex
= sc
->tindex
= sc
->rindex
= 0;
addr
->qe_csr
= QE_RCV_ENABLE
| QE_INT_ENABLE
| QE_XMIT_INT
|
addr
->qe_rcvlist_lo
= (short)sc
->rringaddr
;
addr
->qe_rcvlist_hi
= (short)((int)sc
->rringaddr
>> 16);
sc
->qe_flags
|= QEF_RUNNING
;