xref: /openbmc/linux/drivers/net/fddi/skfp/hwmtm.c (revision b4aadd20)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
233f810b2SJeff Kirsher /******************************************************************************
333f810b2SJeff Kirsher  *
433f810b2SJeff Kirsher  *	(C)Copyright 1998,1999 SysKonnect,
533f810b2SJeff Kirsher  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
633f810b2SJeff Kirsher  *
733f810b2SJeff Kirsher  *	See the file "skfddi.c" for further information.
833f810b2SJeff Kirsher  *
933f810b2SJeff Kirsher  *	The information in this file is provided "AS IS" without warranty.
1033f810b2SJeff Kirsher  *
1133f810b2SJeff Kirsher  ******************************************************************************/
1233f810b2SJeff Kirsher 
1333f810b2SJeff Kirsher #define	HWMTM
1433f810b2SJeff Kirsher 
1533f810b2SJeff Kirsher #ifndef FDDI
1633f810b2SJeff Kirsher #define	FDDI
1733f810b2SJeff Kirsher #endif
1833f810b2SJeff Kirsher 
1933f810b2SJeff Kirsher #include "h/types.h"
2033f810b2SJeff Kirsher #include "h/fddi.h"
2133f810b2SJeff Kirsher #include "h/smc.h"
2233f810b2SJeff Kirsher #include "h/supern_2.h"
2333f810b2SJeff Kirsher #include "h/skfbiinc.h"
2433f810b2SJeff Kirsher 
2533f810b2SJeff Kirsher /*
2633f810b2SJeff Kirsher 	-------------------------------------------------------------
2733f810b2SJeff Kirsher 	DOCUMENTATION
2833f810b2SJeff Kirsher 	-------------------------------------------------------------
2933f810b2SJeff Kirsher 	BEGIN_MANUAL_ENTRY(DOCUMENTATION)
3033f810b2SJeff Kirsher 
3133f810b2SJeff Kirsher 			T B D
3233f810b2SJeff Kirsher 
3333f810b2SJeff Kirsher 	END_MANUAL_ENTRY
3433f810b2SJeff Kirsher */
3533f810b2SJeff Kirsher /*
3633f810b2SJeff Kirsher 	-------------------------------------------------------------
3733f810b2SJeff Kirsher 	LOCAL VARIABLES:
3833f810b2SJeff Kirsher 	-------------------------------------------------------------
3933f810b2SJeff Kirsher */
4033f810b2SJeff Kirsher #ifdef COMMON_MB_POOL
41*b4aadd20SWen Zhiwei static	SMbuf *mb_start;
42*b4aadd20SWen Zhiwei static	SMbuf *mb_free;
4333f810b2SJeff Kirsher static	int mb_init = FALSE ;
44*b4aadd20SWen Zhiwei static	int call_count;
4533f810b2SJeff Kirsher #endif
4633f810b2SJeff Kirsher 
4733f810b2SJeff Kirsher /*
4833f810b2SJeff Kirsher 	-------------------------------------------------------------
4933f810b2SJeff Kirsher 	EXTERNE VARIABLES:
5033f810b2SJeff Kirsher 	-------------------------------------------------------------
5133f810b2SJeff Kirsher */
5233f810b2SJeff Kirsher 
5333f810b2SJeff Kirsher #ifdef	DEBUG
5433f810b2SJeff Kirsher #ifndef	DEBUG_BRD
5533f810b2SJeff Kirsher extern	struct smt_debug	debug ;
5633f810b2SJeff Kirsher #endif
5733f810b2SJeff Kirsher #endif
5833f810b2SJeff Kirsher 
5933f810b2SJeff Kirsher #ifdef	NDIS_OS2
6033f810b2SJeff Kirsher extern	u_char	offDepth ;
6133f810b2SJeff Kirsher extern	u_char	force_irq_pending ;
6233f810b2SJeff Kirsher #endif
6333f810b2SJeff Kirsher 
6433f810b2SJeff Kirsher /*
6533f810b2SJeff Kirsher 	-------------------------------------------------------------
6633f810b2SJeff Kirsher 	LOCAL FUNCTIONS:
6733f810b2SJeff Kirsher 	-------------------------------------------------------------
6833f810b2SJeff Kirsher */
6933f810b2SJeff Kirsher 
7033f810b2SJeff Kirsher static void queue_llc_rx(struct s_smc *smc, SMbuf *mb);
7133f810b2SJeff Kirsher static void smt_to_llc(struct s_smc *smc, SMbuf *mb);
7233f810b2SJeff Kirsher static void init_txd_ring(struct s_smc *smc);
7333f810b2SJeff Kirsher static void init_rxd_ring(struct s_smc *smc);
7433f810b2SJeff Kirsher static void queue_txd_mb(struct s_smc *smc, SMbuf *mb);
7533f810b2SJeff Kirsher static u_long init_descr_ring(struct s_smc *smc, union s_fp_descr volatile *start,
7633f810b2SJeff Kirsher 			      int count);
7733f810b2SJeff Kirsher static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue);
7833f810b2SJeff Kirsher static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue);
7933f810b2SJeff Kirsher static SMbuf* get_llc_rx(struct s_smc *smc);
8033f810b2SJeff Kirsher static SMbuf* get_txd_mb(struct s_smc *smc);
8133f810b2SJeff Kirsher static void mac_drv_clear_txd(struct s_smc *smc);
8233f810b2SJeff Kirsher 
8333f810b2SJeff Kirsher /*
8433f810b2SJeff Kirsher 	-------------------------------------------------------------
8533f810b2SJeff Kirsher 	EXTERNAL FUNCTIONS:
8633f810b2SJeff Kirsher 	-------------------------------------------------------------
8733f810b2SJeff Kirsher */
8833f810b2SJeff Kirsher /*	The external SMT functions are listed in cmtdef.h */
8933f810b2SJeff Kirsher 
9033f810b2SJeff Kirsher extern void* mac_drv_get_space(struct s_smc *smc, unsigned int size);
9133f810b2SJeff Kirsher extern void* mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size);
9233f810b2SJeff Kirsher extern void mac_drv_fill_rxd(struct s_smc *smc);
9333f810b2SJeff Kirsher extern void mac_drv_tx_complete(struct s_smc *smc,
9433f810b2SJeff Kirsher 				volatile struct s_smt_fp_txd *txd);
9533f810b2SJeff Kirsher extern void mac_drv_rx_complete(struct s_smc *smc,
9633f810b2SJeff Kirsher 				volatile struct s_smt_fp_rxd *rxd,
9733f810b2SJeff Kirsher 				int frag_count, int len);
9833f810b2SJeff Kirsher extern void mac_drv_requeue_rxd(struct s_smc *smc,
9933f810b2SJeff Kirsher 				volatile struct s_smt_fp_rxd *rxd,
10033f810b2SJeff Kirsher 				int frag_count);
10133f810b2SJeff Kirsher extern void mac_drv_clear_rxd(struct s_smc *smc,
10233f810b2SJeff Kirsher 			      volatile struct s_smt_fp_rxd *rxd, int frag_count);
10333f810b2SJeff Kirsher 
10433f810b2SJeff Kirsher #ifdef	USE_OS_CPY
10533f810b2SJeff Kirsher extern void hwm_cpy_rxd2mb(void);
10633f810b2SJeff Kirsher extern void hwm_cpy_txd2mb(void);
10733f810b2SJeff Kirsher #endif
10833f810b2SJeff Kirsher 
10933f810b2SJeff Kirsher #ifdef	ALL_RX_COMPLETE
11033f810b2SJeff Kirsher extern void mac_drv_all_receives_complete(void);
11133f810b2SJeff Kirsher #endif
11233f810b2SJeff Kirsher 
11333f810b2SJeff Kirsher extern u_long mac_drv_virt2phys(struct s_smc *smc, void *virt);
11433f810b2SJeff Kirsher extern u_long dma_master(struct s_smc *smc, void *virt, int len, int flag);
11533f810b2SJeff Kirsher 
11633f810b2SJeff Kirsher #ifdef	NDIS_OS2
11733f810b2SJeff Kirsher extern void post_proc(void);
11833f810b2SJeff Kirsher #else
11933f810b2SJeff Kirsher extern void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr,
12033f810b2SJeff Kirsher 			 int flag);
12133f810b2SJeff Kirsher #endif
12233f810b2SJeff Kirsher 
12333f810b2SJeff Kirsher extern int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead,
12433f810b2SJeff Kirsher 			   int la_len);
12533f810b2SJeff Kirsher 
12633f810b2SJeff Kirsher /*
12733f810b2SJeff Kirsher 	-------------------------------------------------------------
12833f810b2SJeff Kirsher 	PUBLIC FUNCTIONS:
12933f810b2SJeff Kirsher 	-------------------------------------------------------------
13033f810b2SJeff Kirsher */
13133f810b2SJeff Kirsher void process_receive(struct s_smc *smc);
13233f810b2SJeff Kirsher void fddi_isr(struct s_smc *smc);
13333f810b2SJeff Kirsher void smt_free_mbuf(struct s_smc *smc, SMbuf *mb);
13433f810b2SJeff Kirsher void init_driver_fplus(struct s_smc *smc);
13533f810b2SJeff Kirsher void mac_drv_rx_mode(struct s_smc *smc, int mode);
13633f810b2SJeff Kirsher void init_fddi_driver(struct s_smc *smc, u_char *mac_addr);
13733f810b2SJeff Kirsher void mac_drv_clear_tx_queue(struct s_smc *smc);
13833f810b2SJeff Kirsher void mac_drv_clear_rx_queue(struct s_smc *smc);
13933f810b2SJeff Kirsher void hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
14033f810b2SJeff Kirsher 		 int frame_status);
14133f810b2SJeff Kirsher void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
14233f810b2SJeff Kirsher 		 int frame_status);
14333f810b2SJeff Kirsher 
14433f810b2SJeff Kirsher int mac_drv_init(struct s_smc *smc);
14533f810b2SJeff Kirsher int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len,
14633f810b2SJeff Kirsher 		int frame_status);
14733f810b2SJeff Kirsher 
14833f810b2SJeff Kirsher u_int mac_drv_check_space(void);
14933f810b2SJeff Kirsher 
15033f810b2SJeff Kirsher SMbuf* smt_get_mbuf(struct s_smc *smc);
15133f810b2SJeff Kirsher 
15233f810b2SJeff Kirsher #ifdef DEBUG
1535671e8c1SJoe Perches 	void mac_drv_debug_lev(struct s_smc *smc, int flag, int lev);
15433f810b2SJeff Kirsher #endif
15533f810b2SJeff Kirsher 
15633f810b2SJeff Kirsher /*
15733f810b2SJeff Kirsher 	-------------------------------------------------------------
15833f810b2SJeff Kirsher 	MACROS:
15933f810b2SJeff Kirsher 	-------------------------------------------------------------
16033f810b2SJeff Kirsher */
16133f810b2SJeff Kirsher #ifndef	UNUSED
16233f810b2SJeff Kirsher #ifdef	lint
16333f810b2SJeff Kirsher #define UNUSED(x)	(x) = (x)
16433f810b2SJeff Kirsher #else
16533f810b2SJeff Kirsher #define UNUSED(x)
16633f810b2SJeff Kirsher #endif
16733f810b2SJeff Kirsher #endif
16833f810b2SJeff Kirsher 
16933f810b2SJeff Kirsher #ifdef	USE_CAN_ADDR
17033f810b2SJeff Kirsher #define MA		smc->hw.fddi_canon_addr.a
17133f810b2SJeff Kirsher #define	GROUP_ADDR_BIT	0x01
17233f810b2SJeff Kirsher #else
17333f810b2SJeff Kirsher #define	MA		smc->hw.fddi_home_addr.a
17433f810b2SJeff Kirsher #define	GROUP_ADDR_BIT	0x80
17533f810b2SJeff Kirsher #endif
17633f810b2SJeff Kirsher 
17733f810b2SJeff Kirsher #define RXD_TXD_COUNT	(HWM_ASYNC_TXD_COUNT+HWM_SYNC_TXD_COUNT+\
17833f810b2SJeff Kirsher 			SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT)
17933f810b2SJeff Kirsher 
18033f810b2SJeff Kirsher #ifdef	MB_OUTSIDE_SMC
18133f810b2SJeff Kirsher #define	EXT_VIRT_MEM	((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd) +\
18233f810b2SJeff Kirsher 			MAX_MBUF*sizeof(SMbuf))
18333f810b2SJeff Kirsher #define	EXT_VIRT_MEM_2	((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd))
18433f810b2SJeff Kirsher #else
18533f810b2SJeff Kirsher #define	EXT_VIRT_MEM	((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd))
18633f810b2SJeff Kirsher #endif
18733f810b2SJeff Kirsher 
18833f810b2SJeff Kirsher 	/*
18933f810b2SJeff Kirsher 	 * define critical read for 16 Bit drivers
19033f810b2SJeff Kirsher 	 */
19133f810b2SJeff Kirsher #if	defined(NDIS_OS2) || defined(ODI2)
19233f810b2SJeff Kirsher #define CR_READ(var)	((var) & 0xffff0000 | ((var) & 0xffff))
19333f810b2SJeff Kirsher #else
19433f810b2SJeff Kirsher #define CR_READ(var)	(__le32)(var)
19533f810b2SJeff Kirsher #endif
19633f810b2SJeff Kirsher 
19733f810b2SJeff Kirsher #define IMASK_SLOW	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
19833f810b2SJeff Kirsher 			 IS_MINTR1 | IS_MINTR2 | IS_MINTR3 | IS_R1_P | \
19933f810b2SJeff Kirsher 			 IS_R1_C | IS_XA_C | IS_XS_C)
20033f810b2SJeff Kirsher 
20133f810b2SJeff Kirsher /*
20233f810b2SJeff Kirsher 	-------------------------------------------------------------
20333f810b2SJeff Kirsher 	INIT- AND SMT FUNCTIONS:
20433f810b2SJeff Kirsher 	-------------------------------------------------------------
20533f810b2SJeff Kirsher */
20633f810b2SJeff Kirsher 
20733f810b2SJeff Kirsher 
20833f810b2SJeff Kirsher /*
20933f810b2SJeff Kirsher  *	BEGIN_MANUAL_ENTRY(mac_drv_check_space)
21033f810b2SJeff Kirsher  *	u_int mac_drv_check_space()
21133f810b2SJeff Kirsher  *
21233f810b2SJeff Kirsher  *	function	DOWNCALL	(drvsr.c)
21333f810b2SJeff Kirsher  *			This function calculates the needed non virtual
21433f810b2SJeff Kirsher  *			memory for MBufs, RxD and TxD descriptors etc.
21533f810b2SJeff Kirsher  *			needed by the driver.
21633f810b2SJeff Kirsher  *
21733f810b2SJeff Kirsher  *	return		u_int	memory in bytes
21833f810b2SJeff Kirsher  *
21933f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
22033f810b2SJeff Kirsher  */
mac_drv_check_space(void)22133f810b2SJeff Kirsher u_int mac_drv_check_space(void)
22233f810b2SJeff Kirsher {
22333f810b2SJeff Kirsher #ifdef	MB_OUTSIDE_SMC
22433f810b2SJeff Kirsher #ifdef	COMMON_MB_POOL
22533f810b2SJeff Kirsher 	call_count++ ;
22633f810b2SJeff Kirsher 	if (call_count == 1) {
22733f810b2SJeff Kirsher 		return EXT_VIRT_MEM;
22833f810b2SJeff Kirsher 	}
22933f810b2SJeff Kirsher 	else {
23033f810b2SJeff Kirsher 		return EXT_VIRT_MEM_2;
23133f810b2SJeff Kirsher 	}
23233f810b2SJeff Kirsher #else
23333f810b2SJeff Kirsher 	return EXT_VIRT_MEM;
23433f810b2SJeff Kirsher #endif
23533f810b2SJeff Kirsher #else
23633f810b2SJeff Kirsher 	return 0;
23733f810b2SJeff Kirsher #endif
23833f810b2SJeff Kirsher }
23933f810b2SJeff Kirsher 
24033f810b2SJeff Kirsher /*
24133f810b2SJeff Kirsher  *	BEGIN_MANUAL_ENTRY(mac_drv_init)
24233f810b2SJeff Kirsher  *	void mac_drv_init(smc)
24333f810b2SJeff Kirsher  *
24433f810b2SJeff Kirsher  *	function	DOWNCALL	(drvsr.c)
24533f810b2SJeff Kirsher  *			In this function the hardware module allocates it's
24633f810b2SJeff Kirsher  *			memory.
24733f810b2SJeff Kirsher  *			The operating system dependent module should call
24833f810b2SJeff Kirsher  *			mac_drv_init once, after the adatper is detected.
24933f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
25033f810b2SJeff Kirsher  */
mac_drv_init(struct s_smc * smc)25133f810b2SJeff Kirsher int mac_drv_init(struct s_smc *smc)
25233f810b2SJeff Kirsher {
25333f810b2SJeff Kirsher 	if (sizeof(struct s_smt_fp_rxd) % 16) {
25433f810b2SJeff Kirsher 		SMT_PANIC(smc,HWM_E0001,HWM_E0001_MSG) ;
25533f810b2SJeff Kirsher 	}
25633f810b2SJeff Kirsher 	if (sizeof(struct s_smt_fp_txd) % 16) {
25733f810b2SJeff Kirsher 		SMT_PANIC(smc,HWM_E0002,HWM_E0002_MSG) ;
25833f810b2SJeff Kirsher 	}
25933f810b2SJeff Kirsher 
26033f810b2SJeff Kirsher 	/*
26133f810b2SJeff Kirsher 	 * get the required memory for the RxDs and TxDs
26233f810b2SJeff Kirsher 	 */
26333f810b2SJeff Kirsher 	if (!(smc->os.hwm.descr_p = (union s_fp_descr volatile *)
26433f810b2SJeff Kirsher 		mac_drv_get_desc_mem(smc,(u_int)
26533f810b2SJeff Kirsher 		(RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)))) {
26633f810b2SJeff Kirsher 		return 1;	/* no space the hwm modul can't work */
26733f810b2SJeff Kirsher 	}
26833f810b2SJeff Kirsher 
26933f810b2SJeff Kirsher 	/*
27033f810b2SJeff Kirsher 	 * get the memory for the SMT MBufs
27133f810b2SJeff Kirsher 	 */
27233f810b2SJeff Kirsher #ifndef	MB_OUTSIDE_SMC
27333f810b2SJeff Kirsher 	smc->os.hwm.mbuf_pool.mb_start=(SMbuf *)(&smc->os.hwm.mbuf_pool.mb[0]) ;
27433f810b2SJeff Kirsher #else
27533f810b2SJeff Kirsher #ifndef	COMMON_MB_POOL
27633f810b2SJeff Kirsher 	if (!(smc->os.hwm.mbuf_pool.mb_start = (SMbuf *) mac_drv_get_space(smc,
27733f810b2SJeff Kirsher 		MAX_MBUF*sizeof(SMbuf)))) {
27833f810b2SJeff Kirsher 		return 1;	/* no space the hwm modul can't work */
27933f810b2SJeff Kirsher 	}
28033f810b2SJeff Kirsher #else
28133f810b2SJeff Kirsher 	if (!mb_start) {
28233f810b2SJeff Kirsher 		if (!(mb_start = (SMbuf *) mac_drv_get_space(smc,
28333f810b2SJeff Kirsher 			MAX_MBUF*sizeof(SMbuf)))) {
28433f810b2SJeff Kirsher 			return 1;	/* no space the hwm modul can't work */
28533f810b2SJeff Kirsher 		}
28633f810b2SJeff Kirsher 	}
28733f810b2SJeff Kirsher #endif
28833f810b2SJeff Kirsher #endif
28933f810b2SJeff Kirsher 	return 0;
29033f810b2SJeff Kirsher }
29133f810b2SJeff Kirsher 
29233f810b2SJeff Kirsher /*
29333f810b2SJeff Kirsher  *	BEGIN_MANUAL_ENTRY(init_driver_fplus)
29433f810b2SJeff Kirsher  *	init_driver_fplus(smc)
29533f810b2SJeff Kirsher  *
29633f810b2SJeff Kirsher  * Sets hardware modul specific values for the mode register 2
29733f810b2SJeff Kirsher  * (e.g. the byte alignment for the received frames, the position of the
29833f810b2SJeff Kirsher  *	 least significant byte etc.)
29933f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
30033f810b2SJeff Kirsher  */
init_driver_fplus(struct s_smc * smc)30133f810b2SJeff Kirsher void init_driver_fplus(struct s_smc *smc)
30233f810b2SJeff Kirsher {
30333f810b2SJeff Kirsher 	smc->hw.fp.mdr2init = FM_LSB | FM_BMMODE | FM_ENNPRQ | FM_ENHSRQ | 3 ;
30433f810b2SJeff Kirsher 
30533f810b2SJeff Kirsher #ifdef	PCI
30633f810b2SJeff Kirsher 	smc->hw.fp.mdr2init |= FM_CHKPAR | FM_PARITY ;
30733f810b2SJeff Kirsher #endif
30833f810b2SJeff Kirsher 	smc->hw.fp.mdr3init = FM_MENRQAUNLCK | FM_MENRS ;
30933f810b2SJeff Kirsher 
31033f810b2SJeff Kirsher #ifdef	USE_CAN_ADDR
31133f810b2SJeff Kirsher 	/* enable address bit swapping */
31233f810b2SJeff Kirsher 	smc->hw.fp.frselreg_init = FM_ENXMTADSWAP | FM_ENRCVADSWAP ;
31333f810b2SJeff Kirsher #endif
31433f810b2SJeff Kirsher }
31533f810b2SJeff Kirsher 
init_descr_ring(struct s_smc * smc,union s_fp_descr volatile * start,int count)31633f810b2SJeff Kirsher static u_long init_descr_ring(struct s_smc *smc,
31733f810b2SJeff Kirsher 			      union s_fp_descr volatile *start,
31833f810b2SJeff Kirsher 			      int count)
31933f810b2SJeff Kirsher {
32033f810b2SJeff Kirsher 	int i ;
32133f810b2SJeff Kirsher 	union s_fp_descr volatile *d1 ;
32233f810b2SJeff Kirsher 	union s_fp_descr volatile *d2 ;
32333f810b2SJeff Kirsher 	u_long	phys ;
32433f810b2SJeff Kirsher 
3255dbc6530SJoe Perches 	DB_GEN(3, "descr ring starts at = %p", start);
32633f810b2SJeff Kirsher 	for (i=count-1, d1=start; i ; i--) {
32733f810b2SJeff Kirsher 		d2 = d1 ;
32833f810b2SJeff Kirsher 		d1++ ;		/* descr is owned by the host */
32933f810b2SJeff Kirsher 		d2->r.rxd_rbctrl = cpu_to_le32(BMU_CHECK) ;
33033f810b2SJeff Kirsher 		d2->r.rxd_next = &d1->r ;
33133f810b2SJeff Kirsher 		phys = mac_drv_virt2phys(smc,(void *)d1) ;
33233f810b2SJeff Kirsher 		d2->r.rxd_nrdadr = cpu_to_le32(phys) ;
33333f810b2SJeff Kirsher 	}
3345dbc6530SJoe Perches 	DB_GEN(3, "descr ring ends at = %p", d1);
33533f810b2SJeff Kirsher 	d1->r.rxd_rbctrl = cpu_to_le32(BMU_CHECK) ;
33633f810b2SJeff Kirsher 	d1->r.rxd_next = &start->r ;
33733f810b2SJeff Kirsher 	phys = mac_drv_virt2phys(smc,(void *)start) ;
33833f810b2SJeff Kirsher 	d1->r.rxd_nrdadr = cpu_to_le32(phys) ;
33933f810b2SJeff Kirsher 
34033f810b2SJeff Kirsher 	for (i=count, d1=start; i ; i--) {
34133f810b2SJeff Kirsher 		DRV_BUF_FLUSH(&d1->r,DDI_DMA_SYNC_FORDEV) ;
34233f810b2SJeff Kirsher 		d1++;
34333f810b2SJeff Kirsher 	}
34433f810b2SJeff Kirsher 	return phys;
34533f810b2SJeff Kirsher }
34633f810b2SJeff Kirsher 
init_txd_ring(struct s_smc * smc)34733f810b2SJeff Kirsher static void init_txd_ring(struct s_smc *smc)
34833f810b2SJeff Kirsher {
34933f810b2SJeff Kirsher 	struct s_smt_fp_txd volatile *ds ;
35033f810b2SJeff Kirsher 	struct s_smt_tx_queue *queue ;
35133f810b2SJeff Kirsher 	u_long	phys ;
35233f810b2SJeff Kirsher 
35333f810b2SJeff Kirsher 	/*
35433f810b2SJeff Kirsher 	 * initialize the transmit descriptors
35533f810b2SJeff Kirsher 	 */
35633f810b2SJeff Kirsher 	ds = (struct s_smt_fp_txd volatile *) ((char *)smc->os.hwm.descr_p +
35733f810b2SJeff Kirsher 		SMT_R1_RXD_COUNT*sizeof(struct s_smt_fp_rxd)) ;
35833f810b2SJeff Kirsher 	queue = smc->hw.fp.tx[QUEUE_A0] ;
3595dbc6530SJoe Perches 	DB_GEN(3, "Init async TxD ring, %d TxDs", HWM_ASYNC_TXD_COUNT);
36033f810b2SJeff Kirsher 	(void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
36133f810b2SJeff Kirsher 		HWM_ASYNC_TXD_COUNT) ;
36233f810b2SJeff Kirsher 	phys = le32_to_cpu(ds->txd_ntdadr) ;
36333f810b2SJeff Kirsher 	ds++ ;
36433f810b2SJeff Kirsher 	queue->tx_curr_put = queue->tx_curr_get = ds ;
36533f810b2SJeff Kirsher 	ds-- ;
36633f810b2SJeff Kirsher 	queue->tx_free = HWM_ASYNC_TXD_COUNT ;
36733f810b2SJeff Kirsher 	queue->tx_used = 0 ;
36833f810b2SJeff Kirsher 	outpd(ADDR(B5_XA_DA),phys) ;
36933f810b2SJeff Kirsher 
37033f810b2SJeff Kirsher 	ds = (struct s_smt_fp_txd volatile *) ((char *)ds +
37133f810b2SJeff Kirsher 		HWM_ASYNC_TXD_COUNT*sizeof(struct s_smt_fp_txd)) ;
37233f810b2SJeff Kirsher 	queue = smc->hw.fp.tx[QUEUE_S] ;
3735dbc6530SJoe Perches 	DB_GEN(3, "Init sync TxD ring, %d TxDs", HWM_SYNC_TXD_COUNT);
37433f810b2SJeff Kirsher 	(void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
37533f810b2SJeff Kirsher 		HWM_SYNC_TXD_COUNT) ;
37633f810b2SJeff Kirsher 	phys = le32_to_cpu(ds->txd_ntdadr) ;
37733f810b2SJeff Kirsher 	ds++ ;
37833f810b2SJeff Kirsher 	queue->tx_curr_put = queue->tx_curr_get = ds ;
37933f810b2SJeff Kirsher 	queue->tx_free = HWM_SYNC_TXD_COUNT ;
38033f810b2SJeff Kirsher 	queue->tx_used = 0 ;
38133f810b2SJeff Kirsher 	outpd(ADDR(B5_XS_DA),phys) ;
38233f810b2SJeff Kirsher }
38333f810b2SJeff Kirsher 
init_rxd_ring(struct s_smc * smc)38433f810b2SJeff Kirsher static void init_rxd_ring(struct s_smc *smc)
38533f810b2SJeff Kirsher {
38633f810b2SJeff Kirsher 	struct s_smt_fp_rxd volatile *ds ;
38733f810b2SJeff Kirsher 	struct s_smt_rx_queue *queue ;
38833f810b2SJeff Kirsher 	u_long	phys ;
38933f810b2SJeff Kirsher 
39033f810b2SJeff Kirsher 	/*
39133f810b2SJeff Kirsher 	 * initialize the receive descriptors
39233f810b2SJeff Kirsher 	 */
39333f810b2SJeff Kirsher 	ds = (struct s_smt_fp_rxd volatile *) smc->os.hwm.descr_p ;
39433f810b2SJeff Kirsher 	queue = smc->hw.fp.rx[QUEUE_R1] ;
3955dbc6530SJoe Perches 	DB_GEN(3, "Init RxD ring, %d RxDs", SMT_R1_RXD_COUNT);
39633f810b2SJeff Kirsher 	(void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
39733f810b2SJeff Kirsher 		SMT_R1_RXD_COUNT) ;
39833f810b2SJeff Kirsher 	phys = le32_to_cpu(ds->rxd_nrdadr) ;
39933f810b2SJeff Kirsher 	ds++ ;
40033f810b2SJeff Kirsher 	queue->rx_curr_put = queue->rx_curr_get = ds ;
40133f810b2SJeff Kirsher 	queue->rx_free = SMT_R1_RXD_COUNT ;
40233f810b2SJeff Kirsher 	queue->rx_used = 0 ;
40333f810b2SJeff Kirsher 	outpd(ADDR(B4_R1_DA),phys) ;
40433f810b2SJeff Kirsher }
40533f810b2SJeff Kirsher 
40633f810b2SJeff Kirsher /*
40733f810b2SJeff Kirsher  *	BEGIN_MANUAL_ENTRY(init_fddi_driver)
40833f810b2SJeff Kirsher  *	void init_fddi_driver(smc,mac_addr)
40933f810b2SJeff Kirsher  *
41033f810b2SJeff Kirsher  * initializes the driver and it's variables
41133f810b2SJeff Kirsher  *
41233f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
41333f810b2SJeff Kirsher  */
init_fddi_driver(struct s_smc * smc,u_char * mac_addr)41433f810b2SJeff Kirsher void init_fddi_driver(struct s_smc *smc, u_char *mac_addr)
41533f810b2SJeff Kirsher {
41633f810b2SJeff Kirsher 	SMbuf	*mb ;
41733f810b2SJeff Kirsher 	int	i ;
41833f810b2SJeff Kirsher 
41933f810b2SJeff Kirsher 	init_board(smc,mac_addr) ;
42033f810b2SJeff Kirsher 	(void)init_fplus(smc) ;
42133f810b2SJeff Kirsher 
42233f810b2SJeff Kirsher 	/*
42333f810b2SJeff Kirsher 	 * initialize the SMbufs for the SMT
42433f810b2SJeff Kirsher 	 */
42533f810b2SJeff Kirsher #ifndef	COMMON_MB_POOL
42633f810b2SJeff Kirsher 	mb = smc->os.hwm.mbuf_pool.mb_start ;
42733f810b2SJeff Kirsher 	smc->os.hwm.mbuf_pool.mb_free = (SMbuf *)NULL ;
42833f810b2SJeff Kirsher 	for (i = 0; i < MAX_MBUF; i++) {
42933f810b2SJeff Kirsher 		mb->sm_use_count = 1 ;
43033f810b2SJeff Kirsher 		smt_free_mbuf(smc,mb)	;
43133f810b2SJeff Kirsher 		mb++ ;
43233f810b2SJeff Kirsher 	}
43333f810b2SJeff Kirsher #else
43433f810b2SJeff Kirsher 	mb = mb_start ;
43533f810b2SJeff Kirsher 	if (!mb_init) {
43633f810b2SJeff Kirsher 		mb_free = 0 ;
43733f810b2SJeff Kirsher 		for (i = 0; i < MAX_MBUF; i++) {
43833f810b2SJeff Kirsher 			mb->sm_use_count = 1 ;
43933f810b2SJeff Kirsher 			smt_free_mbuf(smc,mb)	;
44033f810b2SJeff Kirsher 			mb++ ;
44133f810b2SJeff Kirsher 		}
44233f810b2SJeff Kirsher 		mb_init = TRUE ;
44333f810b2SJeff Kirsher 	}
44433f810b2SJeff Kirsher #endif
44533f810b2SJeff Kirsher 
44633f810b2SJeff Kirsher 	/*
44733f810b2SJeff Kirsher 	 * initialize the other variables
44833f810b2SJeff Kirsher 	 */
44933f810b2SJeff Kirsher 	smc->os.hwm.llc_rx_pipe = smc->os.hwm.llc_rx_tail = (SMbuf *)NULL ;
45033f810b2SJeff Kirsher 	smc->os.hwm.txd_tx_pipe = smc->os.hwm.txd_tx_tail = NULL ;
45133f810b2SJeff Kirsher 	smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = smc->os.hwm.pass_DB = 0 ;
45233f810b2SJeff Kirsher 	smc->os.hwm.pass_llc_promisc = TRUE ;
45333f810b2SJeff Kirsher 	smc->os.hwm.queued_rx_frames = smc->os.hwm.queued_txd_mb = 0 ;
45433f810b2SJeff Kirsher 	smc->os.hwm.detec_count = 0 ;
45533f810b2SJeff Kirsher 	smc->os.hwm.rx_break = 0 ;
45633f810b2SJeff Kirsher 	smc->os.hwm.rx_len_error = 0 ;
45733f810b2SJeff Kirsher 	smc->os.hwm.isr_flag = FALSE ;
45833f810b2SJeff Kirsher 
45933f810b2SJeff Kirsher 	/*
46033f810b2SJeff Kirsher 	 * make sure that the start pointer is 16 byte aligned
46133f810b2SJeff Kirsher 	 */
46233f810b2SJeff Kirsher 	i = 16 - ((long)smc->os.hwm.descr_p & 0xf) ;
46333f810b2SJeff Kirsher 	if (i != 16) {
4645dbc6530SJoe Perches 		DB_GEN(3, "i = %d", i);
46533f810b2SJeff Kirsher 		smc->os.hwm.descr_p = (union s_fp_descr volatile *)
46633f810b2SJeff Kirsher 			((char *)smc->os.hwm.descr_p+i) ;
46733f810b2SJeff Kirsher 	}
4685dbc6530SJoe Perches 	DB_GEN(3, "pt to descr area = %p", smc->os.hwm.descr_p);
46933f810b2SJeff Kirsher 
47033f810b2SJeff Kirsher 	init_txd_ring(smc) ;
47133f810b2SJeff Kirsher 	init_rxd_ring(smc) ;
47233f810b2SJeff Kirsher 	mac_drv_fill_rxd(smc) ;
47333f810b2SJeff Kirsher 
47433f810b2SJeff Kirsher 	init_plc(smc) ;
47533f810b2SJeff Kirsher }
47633f810b2SJeff Kirsher 
47733f810b2SJeff Kirsher 
smt_get_mbuf(struct s_smc * smc)47833f810b2SJeff Kirsher SMbuf *smt_get_mbuf(struct s_smc *smc)
47933f810b2SJeff Kirsher {
48033f810b2SJeff Kirsher 	register SMbuf	*mb ;
48133f810b2SJeff Kirsher 
48233f810b2SJeff Kirsher #ifndef	COMMON_MB_POOL
48333f810b2SJeff Kirsher 	mb = smc->os.hwm.mbuf_pool.mb_free ;
48433f810b2SJeff Kirsher #else
48533f810b2SJeff Kirsher 	mb = mb_free ;
48633f810b2SJeff Kirsher #endif
48733f810b2SJeff Kirsher 	if (mb) {
48833f810b2SJeff Kirsher #ifndef	COMMON_MB_POOL
48933f810b2SJeff Kirsher 		smc->os.hwm.mbuf_pool.mb_free = mb->sm_next ;
49033f810b2SJeff Kirsher #else
49133f810b2SJeff Kirsher 		mb_free = mb->sm_next ;
49233f810b2SJeff Kirsher #endif
49333f810b2SJeff Kirsher 		mb->sm_off = 8 ;
49433f810b2SJeff Kirsher 		mb->sm_use_count = 1 ;
49533f810b2SJeff Kirsher 	}
4965dbc6530SJoe Perches 	DB_GEN(3, "get SMbuf: mb = %p", mb);
49733f810b2SJeff Kirsher 	return mb;	/* May be NULL */
49833f810b2SJeff Kirsher }
49933f810b2SJeff Kirsher 
smt_free_mbuf(struct s_smc * smc,SMbuf * mb)50033f810b2SJeff Kirsher void smt_free_mbuf(struct s_smc *smc, SMbuf *mb)
50133f810b2SJeff Kirsher {
50233f810b2SJeff Kirsher 
50333f810b2SJeff Kirsher 	if (mb) {
50433f810b2SJeff Kirsher 		mb->sm_use_count-- ;
5055dbc6530SJoe Perches 		DB_GEN(3, "free_mbuf: sm_use_count = %d", mb->sm_use_count);
50633f810b2SJeff Kirsher 		/*
50733f810b2SJeff Kirsher 		 * If the use_count is != zero the MBuf is queued
50833f810b2SJeff Kirsher 		 * more than once and must not queued into the
50933f810b2SJeff Kirsher 		 * free MBuf queue
51033f810b2SJeff Kirsher 		 */
51133f810b2SJeff Kirsher 		if (!mb->sm_use_count) {
5125dbc6530SJoe Perches 			DB_GEN(3, "free SMbuf: mb = %p", mb);
51333f810b2SJeff Kirsher #ifndef	COMMON_MB_POOL
51433f810b2SJeff Kirsher 			mb->sm_next = smc->os.hwm.mbuf_pool.mb_free ;
51533f810b2SJeff Kirsher 			smc->os.hwm.mbuf_pool.mb_free = mb ;
51633f810b2SJeff Kirsher #else
51733f810b2SJeff Kirsher 			mb->sm_next = mb_free ;
51833f810b2SJeff Kirsher 			mb_free = mb ;
51933f810b2SJeff Kirsher #endif
52033f810b2SJeff Kirsher 		}
52133f810b2SJeff Kirsher 	}
52233f810b2SJeff Kirsher 	else
52333f810b2SJeff Kirsher 		SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ;
52433f810b2SJeff Kirsher }
52533f810b2SJeff Kirsher 
52633f810b2SJeff Kirsher 
52733f810b2SJeff Kirsher /*
52833f810b2SJeff Kirsher  *	BEGIN_MANUAL_ENTRY(mac_drv_repair_descr)
52933f810b2SJeff Kirsher  *	void mac_drv_repair_descr(smc)
53033f810b2SJeff Kirsher  *
53133f810b2SJeff Kirsher  * function	called from SMT	(HWM / hwmtm.c)
53233f810b2SJeff Kirsher  *		The BMU is idle when this function is called.
53333f810b2SJeff Kirsher  *		Mac_drv_repair_descr sets up the physical address
53433f810b2SJeff Kirsher  *		for all receive and transmit queues where the BMU
53533f810b2SJeff Kirsher  *		should continue.
53633f810b2SJeff Kirsher  *		It may be that the BMU was reseted during a fragmented
53733f810b2SJeff Kirsher  *		transfer. In this case there are some fragments which will
53833f810b2SJeff Kirsher  *		never completed by the BMU. The OWN bit of this fragments
53933f810b2SJeff Kirsher  *		must be switched to be owned by the host.
54033f810b2SJeff Kirsher  *
54133f810b2SJeff Kirsher  *		Give a start command to the receive BMU.
54233f810b2SJeff Kirsher  *		Start the transmit BMUs if transmit frames pending.
54333f810b2SJeff Kirsher  *
54433f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
54533f810b2SJeff Kirsher  */
mac_drv_repair_descr(struct s_smc * smc)54633f810b2SJeff Kirsher void mac_drv_repair_descr(struct s_smc *smc)
54733f810b2SJeff Kirsher {
54833f810b2SJeff Kirsher 	u_long	phys ;
54933f810b2SJeff Kirsher 
55033f810b2SJeff Kirsher 	if (smc->hw.hw_state != STOPPED) {
55133f810b2SJeff Kirsher 		SK_BREAK() ;
55233f810b2SJeff Kirsher 		SMT_PANIC(smc,HWM_E0013,HWM_E0013_MSG) ;
55333f810b2SJeff Kirsher 		return ;
55433f810b2SJeff Kirsher 	}
55533f810b2SJeff Kirsher 
55633f810b2SJeff Kirsher 	/*
55733f810b2SJeff Kirsher 	 * repair tx queues: don't start
55833f810b2SJeff Kirsher 	 */
55933f810b2SJeff Kirsher 	phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_A0]) ;
56033f810b2SJeff Kirsher 	outpd(ADDR(B5_XA_DA),phys) ;
56133f810b2SJeff Kirsher 	if (smc->hw.fp.tx_q[QUEUE_A0].tx_used) {
56233f810b2SJeff Kirsher 		outpd(ADDR(B0_XA_CSR),CSR_START) ;
56333f810b2SJeff Kirsher 	}
56433f810b2SJeff Kirsher 	phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_S]) ;
56533f810b2SJeff Kirsher 	outpd(ADDR(B5_XS_DA),phys) ;
56633f810b2SJeff Kirsher 	if (smc->hw.fp.tx_q[QUEUE_S].tx_used) {
56733f810b2SJeff Kirsher 		outpd(ADDR(B0_XS_CSR),CSR_START) ;
56833f810b2SJeff Kirsher 	}
56933f810b2SJeff Kirsher 
57033f810b2SJeff Kirsher 	/*
57133f810b2SJeff Kirsher 	 * repair rx queues
57233f810b2SJeff Kirsher 	 */
57333f810b2SJeff Kirsher 	phys = repair_rxd_ring(smc,smc->hw.fp.rx[QUEUE_R1]) ;
57433f810b2SJeff Kirsher 	outpd(ADDR(B4_R1_DA),phys) ;
57533f810b2SJeff Kirsher 	outpd(ADDR(B0_R1_CSR),CSR_START) ;
57633f810b2SJeff Kirsher }
57733f810b2SJeff Kirsher 
repair_txd_ring(struct s_smc * smc,struct s_smt_tx_queue * queue)57833f810b2SJeff Kirsher static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue)
57933f810b2SJeff Kirsher {
58033f810b2SJeff Kirsher 	int i ;
58133f810b2SJeff Kirsher 	int tx_used ;
58233f810b2SJeff Kirsher 	u_long phys ;
58333f810b2SJeff Kirsher 	u_long tbctrl ;
58433f810b2SJeff Kirsher 	struct s_smt_fp_txd volatile *t ;
58533f810b2SJeff Kirsher 
58633f810b2SJeff Kirsher 	SK_UNUSED(smc) ;
58733f810b2SJeff Kirsher 
58833f810b2SJeff Kirsher 	t = queue->tx_curr_get ;
58933f810b2SJeff Kirsher 	tx_used = queue->tx_used ;
59033f810b2SJeff Kirsher 	for (i = tx_used+queue->tx_free-1 ; i ; i-- ) {
59133f810b2SJeff Kirsher 		t = t->txd_next ;
59233f810b2SJeff Kirsher 	}
59333f810b2SJeff Kirsher 	phys = le32_to_cpu(t->txd_ntdadr) ;
59433f810b2SJeff Kirsher 
59533f810b2SJeff Kirsher 	t = queue->tx_curr_get ;
59633f810b2SJeff Kirsher 	while (tx_used) {
59733f810b2SJeff Kirsher 		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ;
59833f810b2SJeff Kirsher 		tbctrl = le32_to_cpu(t->txd_tbctrl) ;
59933f810b2SJeff Kirsher 
60033f810b2SJeff Kirsher 		if (tbctrl & BMU_OWN) {
60133f810b2SJeff Kirsher 			if (tbctrl & BMU_STF) {
60233f810b2SJeff Kirsher 				break ;		/* exit the loop */
60333f810b2SJeff Kirsher 			}
60433f810b2SJeff Kirsher 			else {
60533f810b2SJeff Kirsher 				/*
60633f810b2SJeff Kirsher 				 * repair the descriptor
60733f810b2SJeff Kirsher 				 */
60833f810b2SJeff Kirsher 				t->txd_tbctrl &= ~cpu_to_le32(BMU_OWN) ;
60933f810b2SJeff Kirsher 			}
61033f810b2SJeff Kirsher 		}
61133f810b2SJeff Kirsher 		phys = le32_to_cpu(t->txd_ntdadr) ;
61233f810b2SJeff Kirsher 		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
61333f810b2SJeff Kirsher 		t = t->txd_next ;
61433f810b2SJeff Kirsher 		tx_used-- ;
61533f810b2SJeff Kirsher 	}
61633f810b2SJeff Kirsher 	return phys;
61733f810b2SJeff Kirsher }
61833f810b2SJeff Kirsher 
61933f810b2SJeff Kirsher /*
62033f810b2SJeff Kirsher  * Repairs the receive descriptor ring and returns the physical address
62133f810b2SJeff Kirsher  * where the BMU should continue working.
62233f810b2SJeff Kirsher  *
62333f810b2SJeff Kirsher  *	o The physical address where the BMU was stopped has to be
62433f810b2SJeff Kirsher  *	  determined. This is the next RxD after rx_curr_get with an OWN
62533f810b2SJeff Kirsher  *	  bit set.
62633f810b2SJeff Kirsher  *	o The BMU should start working at beginning of the next frame.
62733f810b2SJeff Kirsher  *	  RxDs with an OWN bit set but with a reset STF bit should be
62833f810b2SJeff Kirsher  *	  skipped and owned by the driver (OWN = 0).
62933f810b2SJeff Kirsher  */
repair_rxd_ring(struct s_smc * smc,struct s_smt_rx_queue * queue)63033f810b2SJeff Kirsher static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue)
63133f810b2SJeff Kirsher {
63233f810b2SJeff Kirsher 	int i ;
63333f810b2SJeff Kirsher 	int rx_used ;
63433f810b2SJeff Kirsher 	u_long phys ;
63533f810b2SJeff Kirsher 	u_long rbctrl ;
63633f810b2SJeff Kirsher 	struct s_smt_fp_rxd volatile *r ;
63733f810b2SJeff Kirsher 
63833f810b2SJeff Kirsher 	SK_UNUSED(smc) ;
63933f810b2SJeff Kirsher 
64033f810b2SJeff Kirsher 	r = queue->rx_curr_get ;
64133f810b2SJeff Kirsher 	rx_used = queue->rx_used ;
64233f810b2SJeff Kirsher 	for (i = SMT_R1_RXD_COUNT-1 ; i ; i-- ) {
64333f810b2SJeff Kirsher 		r = r->rxd_next ;
64433f810b2SJeff Kirsher 	}
64533f810b2SJeff Kirsher 	phys = le32_to_cpu(r->rxd_nrdadr) ;
64633f810b2SJeff Kirsher 
64733f810b2SJeff Kirsher 	r = queue->rx_curr_get ;
64833f810b2SJeff Kirsher 	while (rx_used) {
64933f810b2SJeff Kirsher 		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
65033f810b2SJeff Kirsher 		rbctrl = le32_to_cpu(r->rxd_rbctrl) ;
65133f810b2SJeff Kirsher 
65233f810b2SJeff Kirsher 		if (rbctrl & BMU_OWN) {
65333f810b2SJeff Kirsher 			if (rbctrl & BMU_STF) {
65433f810b2SJeff Kirsher 				break ;		/* exit the loop */
65533f810b2SJeff Kirsher 			}
65633f810b2SJeff Kirsher 			else {
65733f810b2SJeff Kirsher 				/*
65833f810b2SJeff Kirsher 				 * repair the descriptor
65933f810b2SJeff Kirsher 				 */
66033f810b2SJeff Kirsher 				r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ;
66133f810b2SJeff Kirsher 			}
66233f810b2SJeff Kirsher 		}
66333f810b2SJeff Kirsher 		phys = le32_to_cpu(r->rxd_nrdadr) ;
66433f810b2SJeff Kirsher 		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
66533f810b2SJeff Kirsher 		r = r->rxd_next ;
66633f810b2SJeff Kirsher 		rx_used-- ;
66733f810b2SJeff Kirsher 	}
66833f810b2SJeff Kirsher 	return phys;
66933f810b2SJeff Kirsher }
67033f810b2SJeff Kirsher 
67133f810b2SJeff Kirsher 
67233f810b2SJeff Kirsher /*
67333f810b2SJeff Kirsher 	-------------------------------------------------------------
67433f810b2SJeff Kirsher 	INTERRUPT SERVICE ROUTINE:
67533f810b2SJeff Kirsher 	-------------------------------------------------------------
67633f810b2SJeff Kirsher */
67733f810b2SJeff Kirsher 
67833f810b2SJeff Kirsher /*
67933f810b2SJeff Kirsher  *	BEGIN_MANUAL_ENTRY(fddi_isr)
68033f810b2SJeff Kirsher  *	void fddi_isr(smc)
68133f810b2SJeff Kirsher  *
68233f810b2SJeff Kirsher  * function	DOWNCALL	(drvsr.c)
68333f810b2SJeff Kirsher  *		interrupt service routine, handles the interrupt requests
68433f810b2SJeff Kirsher  *		generated by the FDDI adapter.
68533f810b2SJeff Kirsher  *
68633f810b2SJeff Kirsher  * NOTE:	The operating system dependent module must guarantee that the
68733f810b2SJeff Kirsher  *		interrupts of the adapter are disabled when it calls fddi_isr.
68833f810b2SJeff Kirsher  *
68933f810b2SJeff Kirsher  *	About the USE_BREAK_ISR mechanismn:
69033f810b2SJeff Kirsher  *
69133f810b2SJeff Kirsher  *	The main requirement of this mechanismn is to force an timer IRQ when
69233f810b2SJeff Kirsher  *	leaving process_receive() with leave_isr set. process_receive() may
69333f810b2SJeff Kirsher  *	be called at any time from anywhere!
69433f810b2SJeff Kirsher  *	To be sure we don't miss such event we set 'force_irq' per default.
69533f810b2SJeff Kirsher  *	We have to force and Timer IRQ if 'smc->os.hwm.leave_isr' AND
69633f810b2SJeff Kirsher  *	'force_irq' are set. 'force_irq' may be reset if a receive complete
69733f810b2SJeff Kirsher  *	IRQ is pending.
69833f810b2SJeff Kirsher  *
69933f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
70033f810b2SJeff Kirsher  */
fddi_isr(struct s_smc * smc)70133f810b2SJeff Kirsher void fddi_isr(struct s_smc *smc)
70233f810b2SJeff Kirsher {
70333f810b2SJeff Kirsher 	u_long		is ;		/* ISR source */
70433f810b2SJeff Kirsher 	u_short		stu, stl ;
70533f810b2SJeff Kirsher 	SMbuf		*mb ;
70633f810b2SJeff Kirsher 
70733f810b2SJeff Kirsher #ifdef	USE_BREAK_ISR
70833f810b2SJeff Kirsher 	int	force_irq ;
70933f810b2SJeff Kirsher #endif
71033f810b2SJeff Kirsher 
71133f810b2SJeff Kirsher #ifdef	ODI2
71233f810b2SJeff Kirsher 	if (smc->os.hwm.rx_break) {
71333f810b2SJeff Kirsher 		mac_drv_fill_rxd(smc) ;
71433f810b2SJeff Kirsher 		if (smc->hw.fp.rx_q[QUEUE_R1].rx_used > 0) {
71533f810b2SJeff Kirsher 			smc->os.hwm.rx_break = 0 ;
71633f810b2SJeff Kirsher 			process_receive(smc) ;
71733f810b2SJeff Kirsher 		}
71833f810b2SJeff Kirsher 		else {
71933f810b2SJeff Kirsher 			smc->os.hwm.detec_count = 0 ;
72033f810b2SJeff Kirsher 			smt_force_irq(smc) ;
72133f810b2SJeff Kirsher 		}
72233f810b2SJeff Kirsher 	}
72333f810b2SJeff Kirsher #endif
72433f810b2SJeff Kirsher 	smc->os.hwm.isr_flag = TRUE ;
72533f810b2SJeff Kirsher 
72633f810b2SJeff Kirsher #ifdef	USE_BREAK_ISR
72733f810b2SJeff Kirsher 	force_irq = TRUE ;
72833f810b2SJeff Kirsher 	if (smc->os.hwm.leave_isr) {
72933f810b2SJeff Kirsher 		smc->os.hwm.leave_isr = FALSE ;
73033f810b2SJeff Kirsher 		process_receive(smc) ;
73133f810b2SJeff Kirsher 	}
73233f810b2SJeff Kirsher #endif
73333f810b2SJeff Kirsher 
73433f810b2SJeff Kirsher 	while ((is = GET_ISR() & ISR_MASK)) {
73533f810b2SJeff Kirsher 		NDD_TRACE("CH0B",is,0,0) ;
7365dbc6530SJoe Perches 		DB_GEN(7, "ISA = 0x%lx", is);
73733f810b2SJeff Kirsher 
73833f810b2SJeff Kirsher 		if (is & IMASK_SLOW) {
73933f810b2SJeff Kirsher 			NDD_TRACE("CH1b",is,0,0) ;
74033f810b2SJeff Kirsher 			if (is & IS_PLINT1) {	/* PLC1 */
74133f810b2SJeff Kirsher 				plc1_irq(smc) ;
74233f810b2SJeff Kirsher 			}
74333f810b2SJeff Kirsher 			if (is & IS_PLINT2) {	/* PLC2 */
74433f810b2SJeff Kirsher 				plc2_irq(smc) ;
74533f810b2SJeff Kirsher 			}
74633f810b2SJeff Kirsher 			if (is & IS_MINTR1) {	/* FORMAC+ STU1(U/L) */
74733f810b2SJeff Kirsher 				stu = inpw(FM_A(FM_ST1U)) ;
74833f810b2SJeff Kirsher 				stl = inpw(FM_A(FM_ST1L)) ;
7495dbc6530SJoe Perches 				DB_GEN(6, "Slow transmit complete");
75033f810b2SJeff Kirsher 				mac1_irq(smc,stu,stl) ;
75133f810b2SJeff Kirsher 			}
75233f810b2SJeff Kirsher 			if (is & IS_MINTR2) {	/* FORMAC+ STU2(U/L) */
75333f810b2SJeff Kirsher 				stu= inpw(FM_A(FM_ST2U)) ;
75433f810b2SJeff Kirsher 				stl= inpw(FM_A(FM_ST2L)) ;
7555dbc6530SJoe Perches 				DB_GEN(6, "Slow receive complete");
7565dbc6530SJoe Perches 				DB_GEN(7, "stl = %x : stu = %x", stl, stu);
75733f810b2SJeff Kirsher 				mac2_irq(smc,stu,stl) ;
75833f810b2SJeff Kirsher 			}
75933f810b2SJeff Kirsher 			if (is & IS_MINTR3) {	/* FORMAC+ STU3(U/L) */
76033f810b2SJeff Kirsher 				stu= inpw(FM_A(FM_ST3U)) ;
76133f810b2SJeff Kirsher 				stl= inpw(FM_A(FM_ST3L)) ;
7625dbc6530SJoe Perches 				DB_GEN(6, "FORMAC Mode Register 3");
76333f810b2SJeff Kirsher 				mac3_irq(smc,stu,stl) ;
76433f810b2SJeff Kirsher 			}
76533f810b2SJeff Kirsher 			if (is & IS_TIMINT) {	/* Timer 82C54-2 */
76633f810b2SJeff Kirsher 				timer_irq(smc) ;
76733f810b2SJeff Kirsher #ifdef	NDIS_OS2
76833f810b2SJeff Kirsher 				force_irq_pending = 0 ;
76933f810b2SJeff Kirsher #endif
77033f810b2SJeff Kirsher 				/*
77133f810b2SJeff Kirsher 				 * out of RxD detection
77233f810b2SJeff Kirsher 				 */
77333f810b2SJeff Kirsher 				if (++smc->os.hwm.detec_count > 4) {
77433f810b2SJeff Kirsher 					/*
77533f810b2SJeff Kirsher 					 * check out of RxD condition
77633f810b2SJeff Kirsher 					 */
77733f810b2SJeff Kirsher 					 process_receive(smc) ;
77833f810b2SJeff Kirsher 				}
77933f810b2SJeff Kirsher 			}
78033f810b2SJeff Kirsher 			if (is & IS_TOKEN) {	/* Restricted Token Monitor */
78133f810b2SJeff Kirsher 				rtm_irq(smc) ;
78233f810b2SJeff Kirsher 			}
78333f810b2SJeff Kirsher 			if (is & IS_R1_P) {	/* Parity error rx queue 1 */
78433f810b2SJeff Kirsher 				/* clear IRQ */
78533f810b2SJeff Kirsher 				outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_P) ;
78633f810b2SJeff Kirsher 				SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ;
78733f810b2SJeff Kirsher 			}
78833f810b2SJeff Kirsher 			if (is & IS_R1_C) {	/* Encoding error rx queue 1 */
78933f810b2SJeff Kirsher 				/* clear IRQ */
79033f810b2SJeff Kirsher 				outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_C) ;
79133f810b2SJeff Kirsher 				SMT_PANIC(smc,HWM_E0005,HWM_E0005_MSG) ;
79233f810b2SJeff Kirsher 			}
79333f810b2SJeff Kirsher 			if (is & IS_XA_C) {	/* Encoding error async tx q */
79433f810b2SJeff Kirsher 				/* clear IRQ */
79533f810b2SJeff Kirsher 				outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_C) ;
79633f810b2SJeff Kirsher 				SMT_PANIC(smc,HWM_E0006,HWM_E0006_MSG) ;
79733f810b2SJeff Kirsher 			}
79833f810b2SJeff Kirsher 			if (is & IS_XS_C) {	/* Encoding error sync tx q */
79933f810b2SJeff Kirsher 				/* clear IRQ */
80033f810b2SJeff Kirsher 				outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_C) ;
80133f810b2SJeff Kirsher 				SMT_PANIC(smc,HWM_E0007,HWM_E0007_MSG) ;
80233f810b2SJeff Kirsher 			}
80333f810b2SJeff Kirsher 		}
80433f810b2SJeff Kirsher 
80533f810b2SJeff Kirsher 		/*
80633f810b2SJeff Kirsher 		 *	Fast Tx complete Async/Sync Queue (BMU service)
80733f810b2SJeff Kirsher 		 */
80833f810b2SJeff Kirsher 		if (is & (IS_XS_F|IS_XA_F)) {
8095dbc6530SJoe Perches 			DB_GEN(6, "Fast tx complete queue");
81033f810b2SJeff Kirsher 			/*
81133f810b2SJeff Kirsher 			 * clear IRQ, Note: no IRQ is lost, because
81233f810b2SJeff Kirsher 			 * 	we always service both queues
81333f810b2SJeff Kirsher 			 */
81433f810b2SJeff Kirsher 			outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_F) ;
81533f810b2SJeff Kirsher 			outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_F) ;
81633f810b2SJeff Kirsher 			mac_drv_clear_txd(smc) ;
81733f810b2SJeff Kirsher 			llc_restart_tx(smc) ;
81833f810b2SJeff Kirsher 		}
81933f810b2SJeff Kirsher 
82033f810b2SJeff Kirsher 		/*
82133f810b2SJeff Kirsher 		 *	Fast Rx Complete (BMU service)
82233f810b2SJeff Kirsher 		 */
82333f810b2SJeff Kirsher 		if (is & IS_R1_F) {
8245dbc6530SJoe Perches 			DB_GEN(6, "Fast receive complete");
82533f810b2SJeff Kirsher 			/* clear IRQ */
82633f810b2SJeff Kirsher #ifndef USE_BREAK_ISR
82733f810b2SJeff Kirsher 			outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ;
82833f810b2SJeff Kirsher 			process_receive(smc) ;
82933f810b2SJeff Kirsher #else
83033f810b2SJeff Kirsher 			process_receive(smc) ;
83133f810b2SJeff Kirsher 			if (smc->os.hwm.leave_isr) {
83233f810b2SJeff Kirsher 				force_irq = FALSE ;
83333f810b2SJeff Kirsher 			} else {
83433f810b2SJeff Kirsher 				outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ;
83533f810b2SJeff Kirsher 				process_receive(smc) ;
83633f810b2SJeff Kirsher 			}
83733f810b2SJeff Kirsher #endif
83833f810b2SJeff Kirsher 		}
83933f810b2SJeff Kirsher 
84033f810b2SJeff Kirsher #ifndef	NDIS_OS2
84133f810b2SJeff Kirsher 		while ((mb = get_llc_rx(smc))) {
84233f810b2SJeff Kirsher 			smt_to_llc(smc,mb) ;
84333f810b2SJeff Kirsher 		}
84433f810b2SJeff Kirsher #else
84533f810b2SJeff Kirsher 		if (offDepth)
84633f810b2SJeff Kirsher 			post_proc() ;
84733f810b2SJeff Kirsher 
84833f810b2SJeff Kirsher 		while (!offDepth && (mb = get_llc_rx(smc))) {
84933f810b2SJeff Kirsher 			smt_to_llc(smc,mb) ;
85033f810b2SJeff Kirsher 		}
85133f810b2SJeff Kirsher 
85233f810b2SJeff Kirsher 		if (!offDepth && smc->os.hwm.rx_break) {
85333f810b2SJeff Kirsher 			process_receive(smc) ;
85433f810b2SJeff Kirsher 		}
85533f810b2SJeff Kirsher #endif
85633f810b2SJeff Kirsher 		if (smc->q.ev_get != smc->q.ev_put) {
85733f810b2SJeff Kirsher 			NDD_TRACE("CH2a",0,0,0) ;
85833f810b2SJeff Kirsher 			ev_dispatcher(smc) ;
85933f810b2SJeff Kirsher 		}
86033f810b2SJeff Kirsher #ifdef	NDIS_OS2
86133f810b2SJeff Kirsher 		post_proc() ;
86233f810b2SJeff Kirsher 		if (offDepth) {		/* leave fddi_isr because */
86333f810b2SJeff Kirsher 			break ;		/* indications not allowed */
86433f810b2SJeff Kirsher 		}
86533f810b2SJeff Kirsher #endif
86633f810b2SJeff Kirsher #ifdef	USE_BREAK_ISR
86733f810b2SJeff Kirsher 		if (smc->os.hwm.leave_isr) {
86833f810b2SJeff Kirsher 			break ;		/* leave fddi_isr */
86933f810b2SJeff Kirsher 		}
87033f810b2SJeff Kirsher #endif
87133f810b2SJeff Kirsher 
87233f810b2SJeff Kirsher 		/* NOTE: when the isr is left, no rx is pending */
87333f810b2SJeff Kirsher 	}	/* end of interrupt source polling loop */
87433f810b2SJeff Kirsher 
87533f810b2SJeff Kirsher #ifdef	USE_BREAK_ISR
87633f810b2SJeff Kirsher 	if (smc->os.hwm.leave_isr && force_irq) {
87733f810b2SJeff Kirsher 		smt_force_irq(smc) ;
87833f810b2SJeff Kirsher 	}
87933f810b2SJeff Kirsher #endif
88033f810b2SJeff Kirsher 	smc->os.hwm.isr_flag = FALSE ;
88133f810b2SJeff Kirsher 	NDD_TRACE("CH0E",0,0,0) ;
88233f810b2SJeff Kirsher }
88333f810b2SJeff Kirsher 
88433f810b2SJeff Kirsher 
88533f810b2SJeff Kirsher /*
88633f810b2SJeff Kirsher 	-------------------------------------------------------------
88733f810b2SJeff Kirsher 	RECEIVE FUNCTIONS:
88833f810b2SJeff Kirsher 	-------------------------------------------------------------
88933f810b2SJeff Kirsher */
89033f810b2SJeff Kirsher 
89133f810b2SJeff Kirsher #ifndef	NDIS_OS2
89233f810b2SJeff Kirsher /*
89333f810b2SJeff Kirsher  *	BEGIN_MANUAL_ENTRY(mac_drv_rx_mode)
89433f810b2SJeff Kirsher  *	void mac_drv_rx_mode(smc,mode)
89533f810b2SJeff Kirsher  *
89633f810b2SJeff Kirsher  * function	DOWNCALL	(fplus.c)
89733f810b2SJeff Kirsher  *		Corresponding to the parameter mode, the operating system
89833f810b2SJeff Kirsher  *		dependent module can activate several receive modes.
89933f810b2SJeff Kirsher  *
90033f810b2SJeff Kirsher  * para	mode	= 1:	RX_ENABLE_ALLMULTI	enable all multicasts
90133f810b2SJeff Kirsher  *		= 2:	RX_DISABLE_ALLMULTI	disable "enable all multicasts"
90233f810b2SJeff Kirsher  *		= 3:	RX_ENABLE_PROMISC	enable promiscuous
90333f810b2SJeff Kirsher  *		= 4:	RX_DISABLE_PROMISC	disable promiscuous
90433f810b2SJeff Kirsher  *		= 5:	RX_ENABLE_NSA		enable rec. of all NSA frames
90533f810b2SJeff Kirsher  *			(disabled after 'driver reset' & 'set station address')
90633f810b2SJeff Kirsher  *		= 6:	RX_DISABLE_NSA		disable rec. of all NSA frames
90733f810b2SJeff Kirsher  *
90833f810b2SJeff Kirsher  *		= 21:	RX_ENABLE_PASS_SMT	( see description )
90933f810b2SJeff Kirsher  *		= 22:	RX_DISABLE_PASS_SMT	(  "	   "	  )
91033f810b2SJeff Kirsher  *		= 23:	RX_ENABLE_PASS_NSA	(  "	   "	  )
91133f810b2SJeff Kirsher  *		= 24:	RX_DISABLE_PASS_NSA	(  "	   "	  )
91233f810b2SJeff Kirsher  *		= 25:	RX_ENABLE_PASS_DB	(  "	   "	  )
91333f810b2SJeff Kirsher  *		= 26:	RX_DISABLE_PASS_DB	(  "	   "	  )
91433f810b2SJeff Kirsher  *		= 27:	RX_DISABLE_PASS_ALL	(  "	   "	  )
91533f810b2SJeff Kirsher  *		= 28:	RX_DISABLE_LLC_PROMISC	(  "	   "	  )
91633f810b2SJeff Kirsher  *		= 29:	RX_ENABLE_LLC_PROMISC	(  "	   "	  )
91733f810b2SJeff Kirsher  *
91833f810b2SJeff Kirsher  *
91933f810b2SJeff Kirsher  *		RX_ENABLE_PASS_SMT / RX_DISABLE_PASS_SMT
92033f810b2SJeff Kirsher  *
92133f810b2SJeff Kirsher  *		If the operating system dependent module activates the
92233f810b2SJeff Kirsher  *		mode RX_ENABLE_PASS_SMT, the hardware module
92333f810b2SJeff Kirsher  *		duplicates all SMT frames with the frame control
92433f810b2SJeff Kirsher  *		FC_SMT_INFO and passes them to the LLC receive channel
92533f810b2SJeff Kirsher  *		by calling mac_drv_rx_init.
92633f810b2SJeff Kirsher  *		The SMT Frames which are sent by the local SMT and the NSA
92733f810b2SJeff Kirsher  *		frames whose A- and C-Indicator is not set are also duplicated
92833f810b2SJeff Kirsher  *		and passed.
92933f810b2SJeff Kirsher  *		The receive mode RX_DISABLE_PASS_SMT disables the passing
93033f810b2SJeff Kirsher  *		of SMT frames.
93133f810b2SJeff Kirsher  *
93233f810b2SJeff Kirsher  *		RX_ENABLE_PASS_NSA / RX_DISABLE_PASS_NSA
93333f810b2SJeff Kirsher  *
93433f810b2SJeff Kirsher  *		If the operating system dependent module activates the
93533f810b2SJeff Kirsher  *		mode RX_ENABLE_PASS_NSA, the hardware module
93633f810b2SJeff Kirsher  *		duplicates all NSA frames with frame control FC_SMT_NSA
93733f810b2SJeff Kirsher  *		and a set A-Indicator and passed them to the LLC
93833f810b2SJeff Kirsher  *		receive channel by calling mac_drv_rx_init.
93933f810b2SJeff Kirsher  *		All NSA Frames which are sent by the local SMT
94033f810b2SJeff Kirsher  *		are also duplicated and passed.
94133f810b2SJeff Kirsher  *		The receive mode RX_DISABLE_PASS_NSA disables the passing
94233f810b2SJeff Kirsher  *		of NSA frames with the A- or C-Indicator set.
94333f810b2SJeff Kirsher  *
94433f810b2SJeff Kirsher  * NOTE:	For fear that the hardware module receives NSA frames with
94533f810b2SJeff Kirsher  *		a reset A-Indicator, the operating system dependent module
94633f810b2SJeff Kirsher  *		has to call mac_drv_rx_mode with the mode RX_ENABLE_NSA
94733f810b2SJeff Kirsher  *		before activate the RX_ENABLE_PASS_NSA mode and after every
94833f810b2SJeff Kirsher  *		'driver reset' and 'set station address'.
94933f810b2SJeff Kirsher  *
95033f810b2SJeff Kirsher  *		RX_ENABLE_PASS_DB / RX_DISABLE_PASS_DB
95133f810b2SJeff Kirsher  *
95233f810b2SJeff Kirsher  *		If the operating system dependent module activates the
95333f810b2SJeff Kirsher  *		mode RX_ENABLE_PASS_DB, direct BEACON frames
95433f810b2SJeff Kirsher  *		(FC_BEACON frame control) are passed to the LLC receive
95533f810b2SJeff Kirsher  *		channel by mac_drv_rx_init.
95633f810b2SJeff Kirsher  *		The receive mode RX_DISABLE_PASS_DB disables the passing
95733f810b2SJeff Kirsher  *		of direct BEACON frames.
95833f810b2SJeff Kirsher  *
95933f810b2SJeff Kirsher  *		RX_DISABLE_PASS_ALL
96033f810b2SJeff Kirsher  *
96133f810b2SJeff Kirsher  *		Disables all special receives modes. It is equal to
96233f810b2SJeff Kirsher  *		call mac_drv_set_rx_mode successively with the
96333f810b2SJeff Kirsher  *		parameters RX_DISABLE_NSA, RX_DISABLE_PASS_SMT,
96433f810b2SJeff Kirsher  *		RX_DISABLE_PASS_NSA and RX_DISABLE_PASS_DB.
96533f810b2SJeff Kirsher  *
96633f810b2SJeff Kirsher  *		RX_ENABLE_LLC_PROMISC
96733f810b2SJeff Kirsher  *
96833f810b2SJeff Kirsher  *		(default) all received LLC frames and all SMT/NSA/DBEACON
96933f810b2SJeff Kirsher  *		frames depending on the attitude of the flags
97033f810b2SJeff Kirsher  *		PASS_SMT/PASS_NSA/PASS_DBEACON will be delivered to the
97133f810b2SJeff Kirsher  *		LLC layer
97233f810b2SJeff Kirsher  *
97333f810b2SJeff Kirsher  *		RX_DISABLE_LLC_PROMISC
97433f810b2SJeff Kirsher  *
97533f810b2SJeff Kirsher  *		all received SMT/NSA/DBEACON frames depending on the
97633f810b2SJeff Kirsher  *		attitude of the flags PASS_SMT/PASS_NSA/PASS_DBEACON
97733f810b2SJeff Kirsher  *		will be delivered to the LLC layer.
97833f810b2SJeff Kirsher  *		all received LLC frames with a directed address, Multicast
97933f810b2SJeff Kirsher  *		or Broadcast address will be delivered to the LLC
98033f810b2SJeff Kirsher  *		layer too.
98133f810b2SJeff Kirsher  *
98233f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
98333f810b2SJeff Kirsher  */
mac_drv_rx_mode(struct s_smc * smc,int mode)98433f810b2SJeff Kirsher void mac_drv_rx_mode(struct s_smc *smc, int mode)
98533f810b2SJeff Kirsher {
98633f810b2SJeff Kirsher 	switch(mode) {
98733f810b2SJeff Kirsher 	case RX_ENABLE_PASS_SMT:
98833f810b2SJeff Kirsher 		smc->os.hwm.pass_SMT = TRUE ;
98933f810b2SJeff Kirsher 		break ;
99033f810b2SJeff Kirsher 	case RX_DISABLE_PASS_SMT:
99133f810b2SJeff Kirsher 		smc->os.hwm.pass_SMT = FALSE ;
99233f810b2SJeff Kirsher 		break ;
99333f810b2SJeff Kirsher 	case RX_ENABLE_PASS_NSA:
99433f810b2SJeff Kirsher 		smc->os.hwm.pass_NSA = TRUE ;
99533f810b2SJeff Kirsher 		break ;
99633f810b2SJeff Kirsher 	case RX_DISABLE_PASS_NSA:
99733f810b2SJeff Kirsher 		smc->os.hwm.pass_NSA = FALSE ;
99833f810b2SJeff Kirsher 		break ;
99933f810b2SJeff Kirsher 	case RX_ENABLE_PASS_DB:
100033f810b2SJeff Kirsher 		smc->os.hwm.pass_DB = TRUE ;
100133f810b2SJeff Kirsher 		break ;
100233f810b2SJeff Kirsher 	case RX_DISABLE_PASS_DB:
100333f810b2SJeff Kirsher 		smc->os.hwm.pass_DB = FALSE ;
100433f810b2SJeff Kirsher 		break ;
100533f810b2SJeff Kirsher 	case RX_DISABLE_PASS_ALL:
100633f810b2SJeff Kirsher 		smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = FALSE ;
100733f810b2SJeff Kirsher 		smc->os.hwm.pass_DB = FALSE ;
100833f810b2SJeff Kirsher 		smc->os.hwm.pass_llc_promisc = TRUE ;
100933f810b2SJeff Kirsher 		mac_set_rx_mode(smc,RX_DISABLE_NSA) ;
101033f810b2SJeff Kirsher 		break ;
101133f810b2SJeff Kirsher 	case RX_DISABLE_LLC_PROMISC:
101233f810b2SJeff Kirsher 		smc->os.hwm.pass_llc_promisc = FALSE ;
101333f810b2SJeff Kirsher 		break ;
101433f810b2SJeff Kirsher 	case RX_ENABLE_LLC_PROMISC:
101533f810b2SJeff Kirsher 		smc->os.hwm.pass_llc_promisc = TRUE ;
101633f810b2SJeff Kirsher 		break ;
101733f810b2SJeff Kirsher 	case RX_ENABLE_ALLMULTI:
101833f810b2SJeff Kirsher 	case RX_DISABLE_ALLMULTI:
101933f810b2SJeff Kirsher 	case RX_ENABLE_PROMISC:
102033f810b2SJeff Kirsher 	case RX_DISABLE_PROMISC:
102133f810b2SJeff Kirsher 	case RX_ENABLE_NSA:
102233f810b2SJeff Kirsher 	case RX_DISABLE_NSA:
102333f810b2SJeff Kirsher 	default:
102433f810b2SJeff Kirsher 		mac_set_rx_mode(smc,mode) ;
102533f810b2SJeff Kirsher 		break ;
102633f810b2SJeff Kirsher 	}
102733f810b2SJeff Kirsher }
102833f810b2SJeff Kirsher #endif	/* ifndef NDIS_OS2 */
102933f810b2SJeff Kirsher 
103033f810b2SJeff Kirsher /*
103133f810b2SJeff Kirsher  * process receive queue
103233f810b2SJeff Kirsher  */
process_receive(struct s_smc * smc)103333f810b2SJeff Kirsher void process_receive(struct s_smc *smc)
103433f810b2SJeff Kirsher {
103533f810b2SJeff Kirsher 	int i ;
103633f810b2SJeff Kirsher 	int n ;
103733f810b2SJeff Kirsher 	int frag_count ;		/* number of RxDs of the curr rx buf */
103833f810b2SJeff Kirsher 	int used_frags ;		/* number of RxDs of the curr frame */
103933f810b2SJeff Kirsher 	struct s_smt_rx_queue *queue ;	/* points to the queue ctl struct */
104033f810b2SJeff Kirsher 	struct s_smt_fp_rxd volatile *r ;	/* rxd pointer */
104133f810b2SJeff Kirsher 	struct s_smt_fp_rxd volatile *rxd ;	/* first rxd of rx frame */
104233f810b2SJeff Kirsher 	u_long rbctrl ;			/* receive buffer control word */
104333f810b2SJeff Kirsher 	u_long rfsw ;			/* receive frame status word */
104433f810b2SJeff Kirsher 	u_short rx_used ;
104533f810b2SJeff Kirsher 	u_char far *virt ;
104633f810b2SJeff Kirsher 	char far *data ;
104733f810b2SJeff Kirsher 	SMbuf *mb ;
104833f810b2SJeff Kirsher 	u_char fc ;			/* Frame control */
104933f810b2SJeff Kirsher 	int len ;			/* Frame length */
105033f810b2SJeff Kirsher 
105133f810b2SJeff Kirsher 	smc->os.hwm.detec_count = 0 ;
105233f810b2SJeff Kirsher 	queue = smc->hw.fp.rx[QUEUE_R1] ;
105333f810b2SJeff Kirsher 	NDD_TRACE("RHxB",0,0,0) ;
105433f810b2SJeff Kirsher 	for ( ; ; ) {
105533f810b2SJeff Kirsher 		r = queue->rx_curr_get ;
105633f810b2SJeff Kirsher 		rx_used = queue->rx_used ;
105733f810b2SJeff Kirsher 		frag_count = 0 ;
105833f810b2SJeff Kirsher 
105933f810b2SJeff Kirsher #ifdef	USE_BREAK_ISR
106033f810b2SJeff Kirsher 		if (smc->os.hwm.leave_isr) {
106133f810b2SJeff Kirsher 			goto rx_end ;
106233f810b2SJeff Kirsher 		}
106333f810b2SJeff Kirsher #endif
106433f810b2SJeff Kirsher #ifdef	NDIS_OS2
106533f810b2SJeff Kirsher 		if (offDepth) {
106633f810b2SJeff Kirsher 			smc->os.hwm.rx_break = 1 ;
106733f810b2SJeff Kirsher 			goto rx_end ;
106833f810b2SJeff Kirsher 		}
106933f810b2SJeff Kirsher 		smc->os.hwm.rx_break = 0 ;
107033f810b2SJeff Kirsher #endif
107133f810b2SJeff Kirsher #ifdef	ODI2
107233f810b2SJeff Kirsher 		if (smc->os.hwm.rx_break) {
107333f810b2SJeff Kirsher 			goto rx_end ;
107433f810b2SJeff Kirsher 		}
107533f810b2SJeff Kirsher #endif
107633f810b2SJeff Kirsher 		n = 0 ;
107733f810b2SJeff Kirsher 		do {
10785dbc6530SJoe Perches 			DB_RX(5, "Check RxD %p for OWN and EOF", r);
107933f810b2SJeff Kirsher 			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
108033f810b2SJeff Kirsher 			rbctrl = le32_to_cpu(CR_READ(r->rxd_rbctrl));
108133f810b2SJeff Kirsher 
108233f810b2SJeff Kirsher 			if (rbctrl & BMU_OWN) {
108333f810b2SJeff Kirsher 				NDD_TRACE("RHxE",r,rfsw,rbctrl) ;
10845dbc6530SJoe Perches 				DB_RX(4, "End of RxDs");
108533f810b2SJeff Kirsher 				goto rx_end ;
108633f810b2SJeff Kirsher 			}
108733f810b2SJeff Kirsher 			/*
108833f810b2SJeff Kirsher 			 * out of RxD detection
108933f810b2SJeff Kirsher 			 */
109033f810b2SJeff Kirsher 			if (!rx_used) {
109133f810b2SJeff Kirsher 				SK_BREAK() ;
109233f810b2SJeff Kirsher 				SMT_PANIC(smc,HWM_E0009,HWM_E0009_MSG) ;
109333f810b2SJeff Kirsher 				/* Either we don't have an RxD or all
109433f810b2SJeff Kirsher 				 * RxDs are filled. Therefore it's allowed
109533f810b2SJeff Kirsher 				 * for to set the STOPPED flag */
109633f810b2SJeff Kirsher 				smc->hw.hw_state = STOPPED ;
109733f810b2SJeff Kirsher 				mac_drv_clear_rx_queue(smc) ;
109833f810b2SJeff Kirsher 				smc->hw.hw_state = STARTED ;
109933f810b2SJeff Kirsher 				mac_drv_fill_rxd(smc) ;
110033f810b2SJeff Kirsher 				smc->os.hwm.detec_count = 0 ;
110133f810b2SJeff Kirsher 				goto rx_end ;
110233f810b2SJeff Kirsher 			}
110333f810b2SJeff Kirsher 			rfsw = le32_to_cpu(r->rxd_rfsw) ;
110433f810b2SJeff Kirsher 			if ((rbctrl & BMU_STF) != ((rbctrl & BMU_ST_BUF) <<5)) {
110533f810b2SJeff Kirsher 				/*
110633f810b2SJeff Kirsher 				 * The BMU_STF bit is deleted, 1 frame is
110733f810b2SJeff Kirsher 				 * placed into more than 1 rx buffer
110833f810b2SJeff Kirsher 				 *
110933f810b2SJeff Kirsher 				 * skip frame by setting the rx len to 0
111033f810b2SJeff Kirsher 				 *
111133f810b2SJeff Kirsher 				 * if fragment count == 0
111233f810b2SJeff Kirsher 				 *	The missing STF bit belongs to the
111333f810b2SJeff Kirsher 				 *	current frame, search for the
111433f810b2SJeff Kirsher 				 *	EOF bit to complete the frame
111533f810b2SJeff Kirsher 				 * else
111633f810b2SJeff Kirsher 				 *	the fragment belongs to the next frame,
111733f810b2SJeff Kirsher 				 *	exit the loop and process the frame
111833f810b2SJeff Kirsher 				 */
111933f810b2SJeff Kirsher 				SK_BREAK() ;
112033f810b2SJeff Kirsher 				rfsw = 0 ;
112133f810b2SJeff Kirsher 				if (frag_count) {
112233f810b2SJeff Kirsher 					break ;
112333f810b2SJeff Kirsher 				}
112433f810b2SJeff Kirsher 			}
112533f810b2SJeff Kirsher 			n += rbctrl & 0xffff ;
112633f810b2SJeff Kirsher 			r = r->rxd_next ;
112733f810b2SJeff Kirsher 			frag_count++ ;
112833f810b2SJeff Kirsher 			rx_used-- ;
112933f810b2SJeff Kirsher 		} while (!(rbctrl & BMU_EOF)) ;
113033f810b2SJeff Kirsher 		used_frags = frag_count ;
11315dbc6530SJoe Perches 		DB_RX(5, "EOF set in RxD, used_frags = %d", used_frags);
113233f810b2SJeff Kirsher 
113333f810b2SJeff Kirsher 		/* may be next 2 DRV_BUF_FLUSH() can be skipped, because */
113433f810b2SJeff Kirsher 		/* BMU_ST_BUF will not be changed by the ASIC */
113533f810b2SJeff Kirsher 		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
113633f810b2SJeff Kirsher 		while (rx_used && !(r->rxd_rbctrl & cpu_to_le32(BMU_ST_BUF))) {
11375dbc6530SJoe Perches 			DB_RX(5, "Check STF bit in %p", r);
113833f810b2SJeff Kirsher 			r = r->rxd_next ;
113933f810b2SJeff Kirsher 			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
114033f810b2SJeff Kirsher 			frag_count++ ;
114133f810b2SJeff Kirsher 			rx_used-- ;
114233f810b2SJeff Kirsher 		}
11435dbc6530SJoe Perches 		DB_RX(5, "STF bit found");
114433f810b2SJeff Kirsher 
114533f810b2SJeff Kirsher 		/*
114633f810b2SJeff Kirsher 		 * The received frame is finished for the process receive
114733f810b2SJeff Kirsher 		 */
114833f810b2SJeff Kirsher 		rxd = queue->rx_curr_get ;
114933f810b2SJeff Kirsher 		queue->rx_curr_get = r ;
115033f810b2SJeff Kirsher 		queue->rx_free += frag_count ;
115133f810b2SJeff Kirsher 		queue->rx_used = rx_used ;
115233f810b2SJeff Kirsher 
115333f810b2SJeff Kirsher 		/*
115433f810b2SJeff Kirsher 		 * ASIC Errata no. 7 (STF - Bit Bug)
115533f810b2SJeff Kirsher 		 */
115633f810b2SJeff Kirsher 		rxd->rxd_rbctrl &= cpu_to_le32(~BMU_STF) ;
115733f810b2SJeff Kirsher 
115833f810b2SJeff Kirsher 		for (r=rxd, i=frag_count ; i ; r=r->rxd_next, i--){
11595dbc6530SJoe Perches 			DB_RX(5, "dma_complete for RxD %p", r);
116033f810b2SJeff Kirsher 			dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR);
116133f810b2SJeff Kirsher 		}
116233f810b2SJeff Kirsher 		smc->hw.fp.err_stats.err_valid++ ;
116333f810b2SJeff Kirsher 		smc->mib.m[MAC0].fddiMACCopied_Ct++ ;
116433f810b2SJeff Kirsher 
116533f810b2SJeff Kirsher 		/* the length of the data including the FC */
116633f810b2SJeff Kirsher 		len = (rfsw & RD_LENGTH) - 4 ;
116733f810b2SJeff Kirsher 
11685dbc6530SJoe Perches 		DB_RX(4, "frame length = %d", len);
116933f810b2SJeff Kirsher 		/*
117033f810b2SJeff Kirsher 		 * check the frame_length and all error flags
117133f810b2SJeff Kirsher 		 */
117233f810b2SJeff Kirsher 		if (rfsw & (RX_MSRABT|RX_FS_E|RX_FS_CRC|RX_FS_IMPL)){
117333f810b2SJeff Kirsher 			if (rfsw & RD_S_MSRABT) {
11745dbc6530SJoe Perches 				DB_RX(2, "Frame aborted by the FORMAC");
117533f810b2SJeff Kirsher 				smc->hw.fp.err_stats.err_abort++ ;
117633f810b2SJeff Kirsher 			}
117733f810b2SJeff Kirsher 			/*
117833f810b2SJeff Kirsher 			 * check frame status
117933f810b2SJeff Kirsher 			 */
118033f810b2SJeff Kirsher 			if (rfsw & RD_S_SEAC2) {
11815dbc6530SJoe Perches 				DB_RX(2, "E-Indicator set");
118233f810b2SJeff Kirsher 				smc->hw.fp.err_stats.err_e_indicator++ ;
118333f810b2SJeff Kirsher 			}
118433f810b2SJeff Kirsher 			if (rfsw & RD_S_SFRMERR) {
11855dbc6530SJoe Perches 				DB_RX(2, "CRC error");
118633f810b2SJeff Kirsher 				smc->hw.fp.err_stats.err_crc++ ;
118733f810b2SJeff Kirsher 			}
118833f810b2SJeff Kirsher 			if (rfsw & RX_FS_IMPL) {
11895dbc6530SJoe Perches 				DB_RX(2, "Implementer frame");
119033f810b2SJeff Kirsher 				smc->hw.fp.err_stats.err_imp_frame++ ;
119133f810b2SJeff Kirsher 			}
119233f810b2SJeff Kirsher 			goto abort_frame ;
119333f810b2SJeff Kirsher 		}
119433f810b2SJeff Kirsher 		if (len > FDDI_RAW_MTU-4) {
11955dbc6530SJoe Perches 			DB_RX(2, "Frame too long error");
119633f810b2SJeff Kirsher 			smc->hw.fp.err_stats.err_too_long++ ;
119733f810b2SJeff Kirsher 			goto abort_frame ;
119833f810b2SJeff Kirsher 		}
119933f810b2SJeff Kirsher 		/*
120033f810b2SJeff Kirsher 		 * SUPERNET 3 Bug: FORMAC delivers status words
1201d97c6f68SWeitao Hou 		 * of aborted frames to the BMU
120233f810b2SJeff Kirsher 		 */
120333f810b2SJeff Kirsher 		if (len <= 4) {
12045dbc6530SJoe Perches 			DB_RX(2, "Frame length = 0");
120533f810b2SJeff Kirsher 			goto abort_frame ;
120633f810b2SJeff Kirsher 		}
120733f810b2SJeff Kirsher 
120833f810b2SJeff Kirsher 		if (len != (n-4)) {
12095dbc6530SJoe Perches 			DB_RX(4, "BMU: rx len differs: [%d:%d]", len, n);
121033f810b2SJeff Kirsher 			smc->os.hwm.rx_len_error++ ;
121133f810b2SJeff Kirsher 			goto abort_frame ;
121233f810b2SJeff Kirsher 		}
121333f810b2SJeff Kirsher 
121433f810b2SJeff Kirsher 		/*
121533f810b2SJeff Kirsher 		 * Check SA == MA
121633f810b2SJeff Kirsher 		 */
121733f810b2SJeff Kirsher 		virt = (u_char far *) rxd->rxd_virt ;
12185dbc6530SJoe Perches 		DB_RX(2, "FC = %x", *virt);
121933f810b2SJeff Kirsher 		if (virt[12] == MA[5] &&
122033f810b2SJeff Kirsher 		    virt[11] == MA[4] &&
122133f810b2SJeff Kirsher 		    virt[10] == MA[3] &&
122233f810b2SJeff Kirsher 		    virt[9] == MA[2] &&
122333f810b2SJeff Kirsher 		    virt[8] == MA[1] &&
122433f810b2SJeff Kirsher 		    (virt[7] & ~GROUP_ADDR_BIT) == MA[0]) {
122533f810b2SJeff Kirsher 			goto abort_frame ;
122633f810b2SJeff Kirsher 		}
122733f810b2SJeff Kirsher 
122833f810b2SJeff Kirsher 		/*
122933f810b2SJeff Kirsher 		 * test if LLC frame
123033f810b2SJeff Kirsher 		 */
123133f810b2SJeff Kirsher 		if (rfsw & RX_FS_LLC) {
123233f810b2SJeff Kirsher 			/*
123333f810b2SJeff Kirsher 			 * if pass_llc_promisc is disable
123433f810b2SJeff Kirsher 			 *	if DA != Multicast or Broadcast or DA!=MA
123533f810b2SJeff Kirsher 			 *		abort the frame
123633f810b2SJeff Kirsher 			 */
123733f810b2SJeff Kirsher 			if (!smc->os.hwm.pass_llc_promisc) {
123833f810b2SJeff Kirsher 				if(!(virt[1] & GROUP_ADDR_BIT)) {
123933f810b2SJeff Kirsher 					if (virt[6] != MA[5] ||
124033f810b2SJeff Kirsher 					    virt[5] != MA[4] ||
124133f810b2SJeff Kirsher 					    virt[4] != MA[3] ||
124233f810b2SJeff Kirsher 					    virt[3] != MA[2] ||
124333f810b2SJeff Kirsher 					    virt[2] != MA[1] ||
124433f810b2SJeff Kirsher 					    virt[1] != MA[0]) {
12455dbc6530SJoe Perches 						DB_RX(2, "DA != MA and not multi- or broadcast");
124633f810b2SJeff Kirsher 						goto abort_frame ;
124733f810b2SJeff Kirsher 					}
124833f810b2SJeff Kirsher 				}
124933f810b2SJeff Kirsher 			}
125033f810b2SJeff Kirsher 
125133f810b2SJeff Kirsher 			/*
125233f810b2SJeff Kirsher 			 * LLC frame received
125333f810b2SJeff Kirsher 			 */
12545dbc6530SJoe Perches 			DB_RX(4, "LLC - receive");
125533f810b2SJeff Kirsher 			mac_drv_rx_complete(smc,rxd,frag_count,len) ;
125633f810b2SJeff Kirsher 		}
125733f810b2SJeff Kirsher 		else {
125833f810b2SJeff Kirsher 			if (!(mb = smt_get_mbuf(smc))) {
125933f810b2SJeff Kirsher 				smc->hw.fp.err_stats.err_no_buf++ ;
12605dbc6530SJoe Perches 				DB_RX(4, "No SMbuf; receive terminated");
126133f810b2SJeff Kirsher 				goto abort_frame ;
126233f810b2SJeff Kirsher 			}
126333f810b2SJeff Kirsher 			data = smtod(mb,char *) - 1 ;
126433f810b2SJeff Kirsher 
126533f810b2SJeff Kirsher 			/*
126633f810b2SJeff Kirsher 			 * copy the frame into a SMT_MBuf
126733f810b2SJeff Kirsher 			 */
126833f810b2SJeff Kirsher #ifdef USE_OS_CPY
126933f810b2SJeff Kirsher 			hwm_cpy_rxd2mb(rxd,data,len) ;
127033f810b2SJeff Kirsher #else
127133f810b2SJeff Kirsher 			for (r=rxd, i=used_frags ; i ; r=r->rxd_next, i--){
127233f810b2SJeff Kirsher 				n = le32_to_cpu(r->rxd_rbctrl) & RD_LENGTH ;
12735dbc6530SJoe Perches 				DB_RX(6, "cp SMT frame to mb: len = %d", n);
127433f810b2SJeff Kirsher 				memcpy(data,r->rxd_virt,n) ;
127533f810b2SJeff Kirsher 				data += n ;
127633f810b2SJeff Kirsher 			}
127733f810b2SJeff Kirsher 			data = smtod(mb,char *) - 1 ;
127833f810b2SJeff Kirsher #endif
127933f810b2SJeff Kirsher 			fc = *(char *)mb->sm_data = *data ;
128033f810b2SJeff Kirsher 			mb->sm_len = len - 1 ;		/* len - fc */
128133f810b2SJeff Kirsher 			data++ ;
128233f810b2SJeff Kirsher 
128333f810b2SJeff Kirsher 			/*
128433f810b2SJeff Kirsher 			 * SMT frame received
128533f810b2SJeff Kirsher 			 */
128633f810b2SJeff Kirsher 			switch(fc) {
128733f810b2SJeff Kirsher 			case FC_SMT_INFO :
128833f810b2SJeff Kirsher 				smc->hw.fp.err_stats.err_smt_frame++ ;
12895dbc6530SJoe Perches 				DB_RX(5, "SMT frame received");
129033f810b2SJeff Kirsher 
129133f810b2SJeff Kirsher 				if (smc->os.hwm.pass_SMT) {
12925dbc6530SJoe Perches 					DB_RX(5, "pass SMT frame");
129333f810b2SJeff Kirsher 					mac_drv_rx_complete(smc, rxd,
129433f810b2SJeff Kirsher 						frag_count,len) ;
129533f810b2SJeff Kirsher 				}
129633f810b2SJeff Kirsher 				else {
12975dbc6530SJoe Perches 					DB_RX(5, "requeue RxD");
129833f810b2SJeff Kirsher 					mac_drv_requeue_rxd(smc,rxd,frag_count);
129933f810b2SJeff Kirsher 				}
130033f810b2SJeff Kirsher 
130133f810b2SJeff Kirsher 				smt_received_pack(smc,mb,(int)(rfsw>>25)) ;
130233f810b2SJeff Kirsher 				break ;
130333f810b2SJeff Kirsher 			case FC_SMT_NSA :
130433f810b2SJeff Kirsher 				smc->hw.fp.err_stats.err_smt_frame++ ;
13055dbc6530SJoe Perches 				DB_RX(5, "SMT frame received");
130633f810b2SJeff Kirsher 
130733f810b2SJeff Kirsher 				/* if pass_NSA set pass the NSA frame or */
130833f810b2SJeff Kirsher 				/* pass_SMT set and the A-Indicator */
130933f810b2SJeff Kirsher 				/* is not set, pass the NSA frame */
131033f810b2SJeff Kirsher 				if (smc->os.hwm.pass_NSA ||
131133f810b2SJeff Kirsher 					(smc->os.hwm.pass_SMT &&
131233f810b2SJeff Kirsher 					!(rfsw & A_INDIC))) {
13135dbc6530SJoe Perches 					DB_RX(5, "pass SMT frame");
131433f810b2SJeff Kirsher 					mac_drv_rx_complete(smc, rxd,
131533f810b2SJeff Kirsher 						frag_count,len) ;
131633f810b2SJeff Kirsher 				}
131733f810b2SJeff Kirsher 				else {
13185dbc6530SJoe Perches 					DB_RX(5, "requeue RxD");
131933f810b2SJeff Kirsher 					mac_drv_requeue_rxd(smc,rxd,frag_count);
132033f810b2SJeff Kirsher 				}
132133f810b2SJeff Kirsher 
132233f810b2SJeff Kirsher 				smt_received_pack(smc,mb,(int)(rfsw>>25)) ;
132333f810b2SJeff Kirsher 				break ;
132433f810b2SJeff Kirsher 			case FC_BEACON :
132533f810b2SJeff Kirsher 				if (smc->os.hwm.pass_DB) {
13265dbc6530SJoe Perches 					DB_RX(5, "pass DB frame");
132733f810b2SJeff Kirsher 					mac_drv_rx_complete(smc, rxd,
132833f810b2SJeff Kirsher 						frag_count,len) ;
132933f810b2SJeff Kirsher 				}
133033f810b2SJeff Kirsher 				else {
13315dbc6530SJoe Perches 					DB_RX(5, "requeue RxD");
133233f810b2SJeff Kirsher 					mac_drv_requeue_rxd(smc,rxd,frag_count);
133333f810b2SJeff Kirsher 				}
133433f810b2SJeff Kirsher 				smt_free_mbuf(smc,mb) ;
133533f810b2SJeff Kirsher 				break ;
133633f810b2SJeff Kirsher 			default :
133733f810b2SJeff Kirsher 				/*
1338d97c6f68SWeitao Hou 				 * unknown FC abort the frame
133933f810b2SJeff Kirsher 				 */
13405dbc6530SJoe Perches 				DB_RX(2, "unknown FC error");
134133f810b2SJeff Kirsher 				smt_free_mbuf(smc,mb) ;
13425dbc6530SJoe Perches 				DB_RX(5, "requeue RxD");
134333f810b2SJeff Kirsher 				mac_drv_requeue_rxd(smc,rxd,frag_count) ;
134433f810b2SJeff Kirsher 				if ((fc & 0xf0) == FC_MAC)
134533f810b2SJeff Kirsher 					smc->hw.fp.err_stats.err_mac_frame++ ;
134633f810b2SJeff Kirsher 				else
134733f810b2SJeff Kirsher 					smc->hw.fp.err_stats.err_imp_frame++ ;
134833f810b2SJeff Kirsher 
134933f810b2SJeff Kirsher 				break ;
135033f810b2SJeff Kirsher 			}
135133f810b2SJeff Kirsher 		}
135233f810b2SJeff Kirsher 
13535dbc6530SJoe Perches 		DB_RX(3, "next RxD is %p", queue->rx_curr_get);
135433f810b2SJeff Kirsher 		NDD_TRACE("RHx1",queue->rx_curr_get,0,0) ;
135533f810b2SJeff Kirsher 
135633f810b2SJeff Kirsher 		continue ;
135733f810b2SJeff Kirsher 	/*--------------------------------------------------------------------*/
135833f810b2SJeff Kirsher abort_frame:
13595dbc6530SJoe Perches 		DB_RX(5, "requeue RxD");
136033f810b2SJeff Kirsher 		mac_drv_requeue_rxd(smc,rxd,frag_count) ;
136133f810b2SJeff Kirsher 
13625dbc6530SJoe Perches 		DB_RX(3, "next RxD is %p", queue->rx_curr_get);
136333f810b2SJeff Kirsher 		NDD_TRACE("RHx2",queue->rx_curr_get,0,0) ;
136433f810b2SJeff Kirsher 	}
136533f810b2SJeff Kirsher rx_end:
136633f810b2SJeff Kirsher #ifdef	ALL_RX_COMPLETE
136733f810b2SJeff Kirsher 	mac_drv_all_receives_complete(smc) ;
136833f810b2SJeff Kirsher #endif
136933f810b2SJeff Kirsher 	return ;	/* lint bug: needs return detect end of function */
137033f810b2SJeff Kirsher }
137133f810b2SJeff Kirsher 
smt_to_llc(struct s_smc * smc,SMbuf * mb)137233f810b2SJeff Kirsher static void smt_to_llc(struct s_smc *smc, SMbuf *mb)
137333f810b2SJeff Kirsher {
137433f810b2SJeff Kirsher 	u_char	fc ;
137533f810b2SJeff Kirsher 
13765dbc6530SJoe Perches 	DB_RX(4, "send a queued frame to the llc layer");
137733f810b2SJeff Kirsher 	smc->os.hwm.r.len = mb->sm_len ;
137833f810b2SJeff Kirsher 	smc->os.hwm.r.mb_pos = smtod(mb,char *) ;
137933f810b2SJeff Kirsher 	fc = *smc->os.hwm.r.mb_pos ;
138033f810b2SJeff Kirsher 	(void)mac_drv_rx_init(smc,(int)mb->sm_len,(int)fc,
138133f810b2SJeff Kirsher 		smc->os.hwm.r.mb_pos,(int)mb->sm_len) ;
138233f810b2SJeff Kirsher 	smt_free_mbuf(smc,mb) ;
138333f810b2SJeff Kirsher }
138433f810b2SJeff Kirsher 
138533f810b2SJeff Kirsher /*
138633f810b2SJeff Kirsher  *	BEGIN_MANUAL_ENTRY(hwm_rx_frag)
138733f810b2SJeff Kirsher  *	void hwm_rx_frag(smc,virt,phys,len,frame_status)
138833f810b2SJeff Kirsher  *
138933f810b2SJeff Kirsher  * function	MACRO		(hardware module, hwmtm.h)
139033f810b2SJeff Kirsher  *		This function calls dma_master for preparing the
139133f810b2SJeff Kirsher  *		system hardware for the DMA transfer and initializes
139233f810b2SJeff Kirsher  *		the current RxD with the length and the physical and
139333f810b2SJeff Kirsher  *		virtual address of the fragment. Furthermore, it sets the
139433f810b2SJeff Kirsher  *		STF and EOF bits depending on the frame status byte,
139533f810b2SJeff Kirsher  *		switches the OWN flag of the RxD, so that it is owned by the
139633f810b2SJeff Kirsher  *		adapter and issues an rx_start.
139733f810b2SJeff Kirsher  *
139833f810b2SJeff Kirsher  * para	virt	virtual pointer to the fragment
139933f810b2SJeff Kirsher  *	len	the length of the fragment
140033f810b2SJeff Kirsher  *	frame_status	status of the frame, see design description
140133f810b2SJeff Kirsher  *
140233f810b2SJeff Kirsher  * NOTE:	It is possible to call this function with a fragment length
140333f810b2SJeff Kirsher  *		of zero.
140433f810b2SJeff Kirsher  *
140533f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
140633f810b2SJeff Kirsher  */
hwm_rx_frag(struct s_smc * smc,char far * virt,u_long phys,int len,int frame_status)140733f810b2SJeff Kirsher void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
140833f810b2SJeff Kirsher 		 int frame_status)
140933f810b2SJeff Kirsher {
141033f810b2SJeff Kirsher 	struct s_smt_fp_rxd volatile *r ;
141133f810b2SJeff Kirsher 	__le32	rbctrl;
141233f810b2SJeff Kirsher 
141333f810b2SJeff Kirsher 	NDD_TRACE("RHfB",virt,len,frame_status) ;
14145dbc6530SJoe Perches 	DB_RX(2, "hwm_rx_frag: len = %d, frame_status = %x", len, frame_status);
141533f810b2SJeff Kirsher 	r = smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put ;
141633f810b2SJeff Kirsher 	r->rxd_virt = virt ;
141733f810b2SJeff Kirsher 	r->rxd_rbadr = cpu_to_le32(phys) ;
141833f810b2SJeff Kirsher 	rbctrl = cpu_to_le32( (((__u32)frame_status &
141933f810b2SJeff Kirsher 		(FIRST_FRAG|LAST_FRAG))<<26) |
142033f810b2SJeff Kirsher 		(((u_long) frame_status & FIRST_FRAG) << 21) |
142133f810b2SJeff Kirsher 		BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len) ;
142233f810b2SJeff Kirsher 	r->rxd_rbctrl = rbctrl ;
142333f810b2SJeff Kirsher 
142433f810b2SJeff Kirsher 	DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
142533f810b2SJeff Kirsher 	outpd(ADDR(B0_R1_CSR),CSR_START) ;
142633f810b2SJeff Kirsher 	smc->hw.fp.rx_q[QUEUE_R1].rx_free-- ;
142733f810b2SJeff Kirsher 	smc->hw.fp.rx_q[QUEUE_R1].rx_used++ ;
142833f810b2SJeff Kirsher 	smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put = r->rxd_next ;
142933f810b2SJeff Kirsher 	NDD_TRACE("RHfE",r,le32_to_cpu(r->rxd_rbadr),0) ;
143033f810b2SJeff Kirsher }
143133f810b2SJeff Kirsher 
143233f810b2SJeff Kirsher /*
143333f810b2SJeff Kirsher  *	BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue)
143433f810b2SJeff Kirsher  *
143533f810b2SJeff Kirsher  * void mac_drv_clear_rx_queue(smc)
143633f810b2SJeff Kirsher  * struct s_smc *smc ;
143733f810b2SJeff Kirsher  *
143833f810b2SJeff Kirsher  * function	DOWNCALL	(hardware module, hwmtm.c)
143933f810b2SJeff Kirsher  *		mac_drv_clear_rx_queue is called by the OS-specific module
144033f810b2SJeff Kirsher  *		after it has issued a card_stop.
144133f810b2SJeff Kirsher  *		In this case, the frames in the receive queue are obsolete and
144233f810b2SJeff Kirsher  *		should be removed. For removing mac_drv_clear_rx_queue
144333f810b2SJeff Kirsher  *		calls dma_master for each RxD and mac_drv_clear_rxd for each
144433f810b2SJeff Kirsher  *		receive buffer.
144533f810b2SJeff Kirsher  *
144633f810b2SJeff Kirsher  * NOTE:	calling sequence card_stop:
144733f810b2SJeff Kirsher  *		CLI_FBI(), card_stop(),
144833f810b2SJeff Kirsher  *		mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(),
144933f810b2SJeff Kirsher  *
145033f810b2SJeff Kirsher  * NOTE:	The caller is responsible that the BMUs are idle
145133f810b2SJeff Kirsher  *		when this function is called.
145233f810b2SJeff Kirsher  *
145333f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
145433f810b2SJeff Kirsher  */
mac_drv_clear_rx_queue(struct s_smc * smc)145533f810b2SJeff Kirsher void mac_drv_clear_rx_queue(struct s_smc *smc)
145633f810b2SJeff Kirsher {
145733f810b2SJeff Kirsher 	struct s_smt_fp_rxd volatile *r ;
145833f810b2SJeff Kirsher 	struct s_smt_fp_rxd volatile *next_rxd ;
145933f810b2SJeff Kirsher 	struct s_smt_rx_queue *queue ;
146033f810b2SJeff Kirsher 	int frag_count ;
146133f810b2SJeff Kirsher 	int i ;
146233f810b2SJeff Kirsher 
146333f810b2SJeff Kirsher 	if (smc->hw.hw_state != STOPPED) {
146433f810b2SJeff Kirsher 		SK_BREAK() ;
146533f810b2SJeff Kirsher 		SMT_PANIC(smc,HWM_E0012,HWM_E0012_MSG) ;
146633f810b2SJeff Kirsher 		return ;
146733f810b2SJeff Kirsher 	}
146833f810b2SJeff Kirsher 
146933f810b2SJeff Kirsher 	queue = smc->hw.fp.rx[QUEUE_R1] ;
14705dbc6530SJoe Perches 	DB_RX(5, "clear_rx_queue");
147133f810b2SJeff Kirsher 
147233f810b2SJeff Kirsher 	/*
147333f810b2SJeff Kirsher 	 * dma_complete and mac_drv_clear_rxd for all RxDs / receive buffers
147433f810b2SJeff Kirsher 	 */
147533f810b2SJeff Kirsher 	r = queue->rx_curr_get ;
147633f810b2SJeff Kirsher 	while (queue->rx_used) {
147733f810b2SJeff Kirsher 		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
14785dbc6530SJoe Perches 		DB_RX(5, "switch OWN bit of RxD 0x%p", r);
147933f810b2SJeff Kirsher 		r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ;
148033f810b2SJeff Kirsher 		frag_count = 1 ;
148133f810b2SJeff Kirsher 		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
148233f810b2SJeff Kirsher 		r = r->rxd_next ;
148333f810b2SJeff Kirsher 		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
148433f810b2SJeff Kirsher 		while (r != queue->rx_curr_put &&
148533f810b2SJeff Kirsher 			!(r->rxd_rbctrl & cpu_to_le32(BMU_ST_BUF))) {
14865dbc6530SJoe Perches 			DB_RX(5, "Check STF bit in %p", r);
148733f810b2SJeff Kirsher 			r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ;
148833f810b2SJeff Kirsher 			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
148933f810b2SJeff Kirsher 			r = r->rxd_next ;
149033f810b2SJeff Kirsher 			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
149133f810b2SJeff Kirsher 			frag_count++ ;
149233f810b2SJeff Kirsher 		}
14935dbc6530SJoe Perches 		DB_RX(5, "STF bit found");
149433f810b2SJeff Kirsher 		next_rxd = r ;
149533f810b2SJeff Kirsher 
149633f810b2SJeff Kirsher 		for (r=queue->rx_curr_get,i=frag_count; i ; r=r->rxd_next,i--){
14975dbc6530SJoe Perches 			DB_RX(5, "dma_complete for RxD %p", r);
149833f810b2SJeff Kirsher 			dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR);
149933f810b2SJeff Kirsher 		}
150033f810b2SJeff Kirsher 
15015dbc6530SJoe Perches 		DB_RX(5, "mac_drv_clear_rxd: RxD %p frag_count %d",
15025dbc6530SJoe Perches 		      queue->rx_curr_get, frag_count);
150333f810b2SJeff Kirsher 		mac_drv_clear_rxd(smc,queue->rx_curr_get,frag_count) ;
150433f810b2SJeff Kirsher 
150533f810b2SJeff Kirsher 		queue->rx_curr_get = next_rxd ;
150633f810b2SJeff Kirsher 		queue->rx_used -= frag_count ;
150733f810b2SJeff Kirsher 		queue->rx_free += frag_count ;
150833f810b2SJeff Kirsher 	}
150933f810b2SJeff Kirsher }
151033f810b2SJeff Kirsher 
151133f810b2SJeff Kirsher 
151233f810b2SJeff Kirsher /*
151333f810b2SJeff Kirsher 	-------------------------------------------------------------
151433f810b2SJeff Kirsher 	SEND FUNCTIONS:
151533f810b2SJeff Kirsher 	-------------------------------------------------------------
151633f810b2SJeff Kirsher */
151733f810b2SJeff Kirsher 
151833f810b2SJeff Kirsher /*
151933f810b2SJeff Kirsher  *	BEGIN_MANUAL_ENTRY(hwm_tx_init)
152033f810b2SJeff Kirsher  *	int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status)
152133f810b2SJeff Kirsher  *
152233f810b2SJeff Kirsher  * function	DOWN_CALL	(hardware module, hwmtm.c)
152333f810b2SJeff Kirsher  *		hwm_tx_init checks if the frame can be sent through the
152433f810b2SJeff Kirsher  *		corresponding send queue.
152533f810b2SJeff Kirsher  *
152633f810b2SJeff Kirsher  * para	fc	the frame control. To determine through which
152733f810b2SJeff Kirsher  *		send queue the frame should be transmitted.
152833f810b2SJeff Kirsher  *		0x50 - 0x57:	asynchronous LLC frame
152933f810b2SJeff Kirsher  *		0xD0 - 0xD7:	synchronous LLC frame
153033f810b2SJeff Kirsher  *		0x41, 0x4F:	SMT frame to the network
153133f810b2SJeff Kirsher  *		0x42:		SMT frame to the network and to the local SMT
153233f810b2SJeff Kirsher  *		0x43:		SMT frame to the local SMT
153333f810b2SJeff Kirsher  *	frag_count	count of the fragments for this frame
153433f810b2SJeff Kirsher  *	frame_len	length of the frame
153533f810b2SJeff Kirsher  *	frame_status	status of the frame, the send queue bit is already
153633f810b2SJeff Kirsher  *			specified
153733f810b2SJeff Kirsher  *
153833f810b2SJeff Kirsher  * return		frame_status
153933f810b2SJeff Kirsher  *
154033f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
154133f810b2SJeff Kirsher  */
hwm_tx_init(struct s_smc * smc,u_char fc,int frag_count,int frame_len,int frame_status)154233f810b2SJeff Kirsher int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len,
154333f810b2SJeff Kirsher 		int frame_status)
154433f810b2SJeff Kirsher {
154533f810b2SJeff Kirsher 	NDD_TRACE("THiB",fc,frag_count,frame_len) ;
154633f810b2SJeff Kirsher 	smc->os.hwm.tx_p = smc->hw.fp.tx[frame_status & QUEUE_A0] ;
154733f810b2SJeff Kirsher 	smc->os.hwm.tx_descr = TX_DESCRIPTOR | (((u_long)(frame_len-1)&3)<<27) ;
154833f810b2SJeff Kirsher 	smc->os.hwm.tx_len = frame_len ;
15495dbc6530SJoe Perches 	DB_TX(3, "hwm_tx_init: fc = %x, len = %d", fc, frame_len);
155033f810b2SJeff Kirsher 	if ((fc & ~(FC_SYNC_BIT|FC_LLC_PRIOR)) == FC_ASYNC_LLC) {
155133f810b2SJeff Kirsher 		frame_status |= LAN_TX ;
155233f810b2SJeff Kirsher 	}
155333f810b2SJeff Kirsher 	else {
155433f810b2SJeff Kirsher 		switch (fc) {
155533f810b2SJeff Kirsher 		case FC_SMT_INFO :
155633f810b2SJeff Kirsher 		case FC_SMT_NSA :
155733f810b2SJeff Kirsher 			frame_status |= LAN_TX ;
155833f810b2SJeff Kirsher 			break ;
155933f810b2SJeff Kirsher 		case FC_SMT_LOC :
156033f810b2SJeff Kirsher 			frame_status |= LOC_TX ;
156133f810b2SJeff Kirsher 			break ;
156233f810b2SJeff Kirsher 		case FC_SMT_LAN_LOC :
156333f810b2SJeff Kirsher 			frame_status |= LAN_TX | LOC_TX ;
156433f810b2SJeff Kirsher 			break ;
156533f810b2SJeff Kirsher 		default :
156633f810b2SJeff Kirsher 			SMT_PANIC(smc,HWM_E0010,HWM_E0010_MSG) ;
156733f810b2SJeff Kirsher 		}
156833f810b2SJeff Kirsher 	}
156933f810b2SJeff Kirsher 	if (!smc->hw.mac_ring_is_up) {
157033f810b2SJeff Kirsher 		frame_status &= ~LAN_TX ;
157133f810b2SJeff Kirsher 		frame_status |= RING_DOWN ;
15725dbc6530SJoe Perches 		DB_TX(2, "Ring is down: terminate LAN_TX");
157333f810b2SJeff Kirsher 	}
157433f810b2SJeff Kirsher 	if (frag_count > smc->os.hwm.tx_p->tx_free) {
157533f810b2SJeff Kirsher #ifndef	NDIS_OS2
157633f810b2SJeff Kirsher 		mac_drv_clear_txd(smc) ;
157733f810b2SJeff Kirsher 		if (frag_count > smc->os.hwm.tx_p->tx_free) {
15785dbc6530SJoe Perches 			DB_TX(2, "Out of TxDs, terminate LAN_TX");
157933f810b2SJeff Kirsher 			frame_status &= ~LAN_TX ;
158033f810b2SJeff Kirsher 			frame_status |= OUT_OF_TXD ;
158133f810b2SJeff Kirsher 		}
158233f810b2SJeff Kirsher #else
15835dbc6530SJoe Perches 		DB_TX(2, "Out of TxDs, terminate LAN_TX");
158433f810b2SJeff Kirsher 		frame_status &= ~LAN_TX ;
158533f810b2SJeff Kirsher 		frame_status |= OUT_OF_TXD ;
158633f810b2SJeff Kirsher #endif
158733f810b2SJeff Kirsher 	}
15885dbc6530SJoe Perches 	DB_TX(3, "frame_status = %x", frame_status);
158933f810b2SJeff Kirsher 	NDD_TRACE("THiE",frame_status,smc->os.hwm.tx_p->tx_free,0) ;
159033f810b2SJeff Kirsher 	return frame_status;
159133f810b2SJeff Kirsher }
159233f810b2SJeff Kirsher 
159333f810b2SJeff Kirsher /*
159433f810b2SJeff Kirsher  *	BEGIN_MANUAL_ENTRY(hwm_tx_frag)
159533f810b2SJeff Kirsher  *	void hwm_tx_frag(smc,virt,phys,len,frame_status)
159633f810b2SJeff Kirsher  *
159733f810b2SJeff Kirsher  * function	DOWNCALL	(hardware module, hwmtm.c)
159833f810b2SJeff Kirsher  *		If the frame should be sent to the LAN, this function calls
159933f810b2SJeff Kirsher  *		dma_master, fills the current TxD with the virtual and the
160033f810b2SJeff Kirsher  *		physical address, sets the STF and EOF bits dependent on
160133f810b2SJeff Kirsher  *		the frame status, and requests the BMU to start the
160233f810b2SJeff Kirsher  *		transmit.
160333f810b2SJeff Kirsher  *		If the frame should be sent to the local SMT, an SMT_MBuf
160433f810b2SJeff Kirsher  *		is allocated if the FIRST_FRAG bit is set in the frame_status.
160533f810b2SJeff Kirsher  *		The fragment of the frame is copied into the SMT MBuf.
160633f810b2SJeff Kirsher  *		The function smt_received_pack is called if the LAST_FRAG
160733f810b2SJeff Kirsher  *		bit is set in the frame_status word.
160833f810b2SJeff Kirsher  *
160933f810b2SJeff Kirsher  * para	virt	virtual pointer to the fragment
161033f810b2SJeff Kirsher  *	len	the length of the fragment
161133f810b2SJeff Kirsher  *	frame_status	status of the frame, see design description
161233f810b2SJeff Kirsher  *
161333f810b2SJeff Kirsher  * return	nothing returned, no parameter is modified
161433f810b2SJeff Kirsher  *
161533f810b2SJeff Kirsher  * NOTE:	It is possible to invoke this macro with a fragment length
161633f810b2SJeff Kirsher  *		of zero.
161733f810b2SJeff Kirsher  *
161833f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
161933f810b2SJeff Kirsher  */
hwm_tx_frag(struct s_smc * smc,char far * virt,u_long phys,int len,int frame_status)162033f810b2SJeff Kirsher void hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
162133f810b2SJeff Kirsher 		 int frame_status)
162233f810b2SJeff Kirsher {
162333f810b2SJeff Kirsher 	struct s_smt_fp_txd volatile *t ;
162433f810b2SJeff Kirsher 	struct s_smt_tx_queue *queue ;
162533f810b2SJeff Kirsher 	__le32	tbctrl ;
162633f810b2SJeff Kirsher 
162733f810b2SJeff Kirsher 	queue = smc->os.hwm.tx_p ;
162833f810b2SJeff Kirsher 
162933f810b2SJeff Kirsher 	NDD_TRACE("THfB",virt,len,frame_status) ;
163033f810b2SJeff Kirsher 	/* Bug fix: AF / May 31 1999 (#missing)
163133f810b2SJeff Kirsher 	 * snmpinfo problem reported by IBM is caused by invalid
163233f810b2SJeff Kirsher 	 * t-pointer (txd) if LAN_TX is not set but LOC_TX only.
163333f810b2SJeff Kirsher 	 * Set: t = queue->tx_curr_put  here !
163433f810b2SJeff Kirsher 	 */
163533f810b2SJeff Kirsher 	t = queue->tx_curr_put ;
163633f810b2SJeff Kirsher 
16375dbc6530SJoe Perches 	DB_TX(2, "hwm_tx_frag: len = %d, frame_status = %x", len, frame_status);
163833f810b2SJeff Kirsher 	if (frame_status & LAN_TX) {
163933f810b2SJeff Kirsher 		/* '*t' is already defined */
16405dbc6530SJoe Perches 		DB_TX(3, "LAN_TX: TxD = %p, virt = %p", t, virt);
164133f810b2SJeff Kirsher 		t->txd_virt = virt ;
164233f810b2SJeff Kirsher 		t->txd_txdscr = cpu_to_le32(smc->os.hwm.tx_descr) ;
164333f810b2SJeff Kirsher 		t->txd_tbadr = cpu_to_le32(phys) ;
164433f810b2SJeff Kirsher 		tbctrl = cpu_to_le32((((__u32)frame_status &
164533f810b2SJeff Kirsher 			(FIRST_FRAG|LAST_FRAG|EN_IRQ_EOF))<< 26) |
164633f810b2SJeff Kirsher 			BMU_OWN|BMU_CHECK |len) ;
164733f810b2SJeff Kirsher 		t->txd_tbctrl = tbctrl ;
164833f810b2SJeff Kirsher 
164933f810b2SJeff Kirsher #ifndef	AIX
165033f810b2SJeff Kirsher 		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
165133f810b2SJeff Kirsher 		outpd(queue->tx_bmu_ctl,CSR_START) ;
165233f810b2SJeff Kirsher #else	/* ifndef AIX */
165333f810b2SJeff Kirsher 		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
165433f810b2SJeff Kirsher 		if (frame_status & QUEUE_A0) {
165533f810b2SJeff Kirsher 			outpd(ADDR(B0_XA_CSR),CSR_START) ;
165633f810b2SJeff Kirsher 		}
165733f810b2SJeff Kirsher 		else {
165833f810b2SJeff Kirsher 			outpd(ADDR(B0_XS_CSR),CSR_START) ;
165933f810b2SJeff Kirsher 		}
166033f810b2SJeff Kirsher #endif
166133f810b2SJeff Kirsher 		queue->tx_free-- ;
166233f810b2SJeff Kirsher 		queue->tx_used++ ;
166333f810b2SJeff Kirsher 		queue->tx_curr_put = t->txd_next ;
166433f810b2SJeff Kirsher 		if (frame_status & LAST_FRAG) {
166533f810b2SJeff Kirsher 			smc->mib.m[MAC0].fddiMACTransmit_Ct++ ;
166633f810b2SJeff Kirsher 		}
166733f810b2SJeff Kirsher 	}
166833f810b2SJeff Kirsher 	if (frame_status & LOC_TX) {
16695dbc6530SJoe Perches 		DB_TX(3, "LOC_TX:");
167033f810b2SJeff Kirsher 		if (frame_status & FIRST_FRAG) {
167133f810b2SJeff Kirsher 			if(!(smc->os.hwm.tx_mb = smt_get_mbuf(smc))) {
167233f810b2SJeff Kirsher 				smc->hw.fp.err_stats.err_no_buf++ ;
16735dbc6530SJoe Perches 				DB_TX(4, "No SMbuf; transmit terminated");
167433f810b2SJeff Kirsher 			}
167533f810b2SJeff Kirsher 			else {
167633f810b2SJeff Kirsher 				smc->os.hwm.tx_data =
167733f810b2SJeff Kirsher 					smtod(smc->os.hwm.tx_mb,char *) - 1 ;
167833f810b2SJeff Kirsher #ifdef USE_OS_CPY
167933f810b2SJeff Kirsher #ifdef PASS_1ST_TXD_2_TX_COMP
168033f810b2SJeff Kirsher 				hwm_cpy_txd2mb(t,smc->os.hwm.tx_data,
168133f810b2SJeff Kirsher 					smc->os.hwm.tx_len) ;
168233f810b2SJeff Kirsher #endif
168333f810b2SJeff Kirsher #endif
168433f810b2SJeff Kirsher 			}
168533f810b2SJeff Kirsher 		}
168633f810b2SJeff Kirsher 		if (smc->os.hwm.tx_mb) {
168733f810b2SJeff Kirsher #ifndef	USE_OS_CPY
16885dbc6530SJoe Perches 			DB_TX(3, "copy fragment into MBuf");
168933f810b2SJeff Kirsher 			memcpy(smc->os.hwm.tx_data,virt,len) ;
169033f810b2SJeff Kirsher 			smc->os.hwm.tx_data += len ;
169133f810b2SJeff Kirsher #endif
169233f810b2SJeff Kirsher 			if (frame_status & LAST_FRAG) {
169333f810b2SJeff Kirsher #ifdef	USE_OS_CPY
169433f810b2SJeff Kirsher #ifndef PASS_1ST_TXD_2_TX_COMP
169533f810b2SJeff Kirsher 				/*
169633f810b2SJeff Kirsher 				 * hwm_cpy_txd2mb(txd,data,len) copies 'len'
169733f810b2SJeff Kirsher 				 * bytes from the virtual pointer in 'rxd'
169833f810b2SJeff Kirsher 				 * to 'data'. The virtual pointer of the
169933f810b2SJeff Kirsher 				 * os-specific tx-buffer should be written
170033f810b2SJeff Kirsher 				 * in the LAST txd.
170133f810b2SJeff Kirsher 				 */
170233f810b2SJeff Kirsher 				hwm_cpy_txd2mb(t,smc->os.hwm.tx_data,
170333f810b2SJeff Kirsher 					smc->os.hwm.tx_len) ;
170433f810b2SJeff Kirsher #endif	/* nPASS_1ST_TXD_2_TX_COMP */
170533f810b2SJeff Kirsher #endif	/* USE_OS_CPY */
170633f810b2SJeff Kirsher 				smc->os.hwm.tx_data =
170733f810b2SJeff Kirsher 					smtod(smc->os.hwm.tx_mb,char *) - 1 ;
170833f810b2SJeff Kirsher 				*(char *)smc->os.hwm.tx_mb->sm_data =
170933f810b2SJeff Kirsher 					*smc->os.hwm.tx_data ;
171033f810b2SJeff Kirsher 				smc->os.hwm.tx_data++ ;
171133f810b2SJeff Kirsher 				smc->os.hwm.tx_mb->sm_len =
171233f810b2SJeff Kirsher 					smc->os.hwm.tx_len - 1 ;
17135dbc6530SJoe Perches 				DB_TX(3, "pass LLC frame to SMT");
171433f810b2SJeff Kirsher 				smt_received_pack(smc,smc->os.hwm.tx_mb,
171533f810b2SJeff Kirsher 						RD_FS_LOCAL) ;
171633f810b2SJeff Kirsher 			}
171733f810b2SJeff Kirsher 		}
171833f810b2SJeff Kirsher 	}
171933f810b2SJeff Kirsher 	NDD_TRACE("THfE",t,queue->tx_free,0) ;
172033f810b2SJeff Kirsher }
172133f810b2SJeff Kirsher 
172233f810b2SJeff Kirsher 
172333f810b2SJeff Kirsher /*
172433f810b2SJeff Kirsher  * queues a receive for later send
172533f810b2SJeff Kirsher  */
queue_llc_rx(struct s_smc * smc,SMbuf * mb)172633f810b2SJeff Kirsher static void queue_llc_rx(struct s_smc *smc, SMbuf *mb)
172733f810b2SJeff Kirsher {
17285dbc6530SJoe Perches 	DB_GEN(4, "queue_llc_rx: mb = %p", mb);
172933f810b2SJeff Kirsher 	smc->os.hwm.queued_rx_frames++ ;
173033f810b2SJeff Kirsher 	mb->sm_next = (SMbuf *)NULL ;
173133f810b2SJeff Kirsher 	if (smc->os.hwm.llc_rx_pipe == NULL) {
173233f810b2SJeff Kirsher 		smc->os.hwm.llc_rx_pipe = mb ;
173333f810b2SJeff Kirsher 	}
173433f810b2SJeff Kirsher 	else {
173533f810b2SJeff Kirsher 		smc->os.hwm.llc_rx_tail->sm_next = mb ;
173633f810b2SJeff Kirsher 	}
173733f810b2SJeff Kirsher 	smc->os.hwm.llc_rx_tail = mb ;
173833f810b2SJeff Kirsher 
173933f810b2SJeff Kirsher 	/*
174033f810b2SJeff Kirsher 	 * force an timer IRQ to receive the data
174133f810b2SJeff Kirsher 	 */
174233f810b2SJeff Kirsher 	if (!smc->os.hwm.isr_flag) {
174333f810b2SJeff Kirsher 		smt_force_irq(smc) ;
174433f810b2SJeff Kirsher 	}
174533f810b2SJeff Kirsher }
174633f810b2SJeff Kirsher 
174733f810b2SJeff Kirsher /*
174833f810b2SJeff Kirsher  * get a SMbuf from the llc_rx_queue
174933f810b2SJeff Kirsher  */
get_llc_rx(struct s_smc * smc)175033f810b2SJeff Kirsher static SMbuf *get_llc_rx(struct s_smc *smc)
175133f810b2SJeff Kirsher {
175233f810b2SJeff Kirsher 	SMbuf	*mb ;
175333f810b2SJeff Kirsher 
175433f810b2SJeff Kirsher 	if ((mb = smc->os.hwm.llc_rx_pipe)) {
175533f810b2SJeff Kirsher 		smc->os.hwm.queued_rx_frames-- ;
175633f810b2SJeff Kirsher 		smc->os.hwm.llc_rx_pipe = mb->sm_next ;
175733f810b2SJeff Kirsher 	}
17585dbc6530SJoe Perches 	DB_GEN(4, "get_llc_rx: mb = 0x%p", mb);
175933f810b2SJeff Kirsher 	return mb;
176033f810b2SJeff Kirsher }
176133f810b2SJeff Kirsher 
176233f810b2SJeff Kirsher /*
176333f810b2SJeff Kirsher  * queues a transmit SMT MBuf during the time were the MBuf is
176433f810b2SJeff Kirsher  * queued the TxD ring
176533f810b2SJeff Kirsher  */
queue_txd_mb(struct s_smc * smc,SMbuf * mb)176633f810b2SJeff Kirsher static void queue_txd_mb(struct s_smc *smc, SMbuf *mb)
176733f810b2SJeff Kirsher {
17685dbc6530SJoe Perches 	DB_GEN(4, "_rx: queue_txd_mb = %p", mb);
176933f810b2SJeff Kirsher 	smc->os.hwm.queued_txd_mb++ ;
177033f810b2SJeff Kirsher 	mb->sm_next = (SMbuf *)NULL ;
177133f810b2SJeff Kirsher 	if (smc->os.hwm.txd_tx_pipe == NULL) {
177233f810b2SJeff Kirsher 		smc->os.hwm.txd_tx_pipe = mb ;
177333f810b2SJeff Kirsher 	}
177433f810b2SJeff Kirsher 	else {
177533f810b2SJeff Kirsher 		smc->os.hwm.txd_tx_tail->sm_next = mb ;
177633f810b2SJeff Kirsher 	}
177733f810b2SJeff Kirsher 	smc->os.hwm.txd_tx_tail = mb ;
177833f810b2SJeff Kirsher }
177933f810b2SJeff Kirsher 
178033f810b2SJeff Kirsher /*
178133f810b2SJeff Kirsher  * get a SMbuf from the txd_tx_queue
178233f810b2SJeff Kirsher  */
get_txd_mb(struct s_smc * smc)178333f810b2SJeff Kirsher static SMbuf *get_txd_mb(struct s_smc *smc)
178433f810b2SJeff Kirsher {
178533f810b2SJeff Kirsher 	SMbuf *mb ;
178633f810b2SJeff Kirsher 
178733f810b2SJeff Kirsher 	if ((mb = smc->os.hwm.txd_tx_pipe)) {
178833f810b2SJeff Kirsher 		smc->os.hwm.queued_txd_mb-- ;
178933f810b2SJeff Kirsher 		smc->os.hwm.txd_tx_pipe = mb->sm_next ;
179033f810b2SJeff Kirsher 	}
17915dbc6530SJoe Perches 	DB_GEN(4, "get_txd_mb: mb = 0x%p", mb);
179233f810b2SJeff Kirsher 	return mb;
179333f810b2SJeff Kirsher }
179433f810b2SJeff Kirsher 
179533f810b2SJeff Kirsher /*
179633f810b2SJeff Kirsher  *	SMT Send function
179733f810b2SJeff Kirsher  */
smt_send_mbuf(struct s_smc * smc,SMbuf * mb,int fc)179833f810b2SJeff Kirsher void smt_send_mbuf(struct s_smc *smc, SMbuf *mb, int fc)
179933f810b2SJeff Kirsher {
180033f810b2SJeff Kirsher 	char far *data ;
180133f810b2SJeff Kirsher 	int	len ;
180233f810b2SJeff Kirsher 	int	n ;
180333f810b2SJeff Kirsher 	int	i ;
180433f810b2SJeff Kirsher 	int	frag_count ;
180533f810b2SJeff Kirsher 	int	frame_status ;
180633f810b2SJeff Kirsher 	SK_LOC_DECL(char far,*virt[3]) ;
180733f810b2SJeff Kirsher 	int	frag_len[3] ;
180833f810b2SJeff Kirsher 	struct s_smt_tx_queue *queue ;
180933f810b2SJeff Kirsher 	struct s_smt_fp_txd volatile *t ;
181033f810b2SJeff Kirsher 	u_long	phys ;
181133f810b2SJeff Kirsher 	__le32	tbctrl;
181233f810b2SJeff Kirsher 
181333f810b2SJeff Kirsher 	NDD_TRACE("THSB",mb,fc,0) ;
18145dbc6530SJoe Perches 	DB_TX(4, "smt_send_mbuf: mb = 0x%p, fc = 0x%x", mb, fc);
181533f810b2SJeff Kirsher 
181633f810b2SJeff Kirsher 	mb->sm_off-- ;	/* set to fc */
181733f810b2SJeff Kirsher 	mb->sm_len++ ;	/* + fc */
181833f810b2SJeff Kirsher 	data = smtod(mb,char *) ;
181933f810b2SJeff Kirsher 	*data = fc ;
182033f810b2SJeff Kirsher 	if (fc == FC_SMT_LOC)
182133f810b2SJeff Kirsher 		*data = FC_SMT_INFO ;
182233f810b2SJeff Kirsher 
182333f810b2SJeff Kirsher 	/*
182433f810b2SJeff Kirsher 	 * determine the frag count and the virt addresses of the frags
182533f810b2SJeff Kirsher 	 */
182633f810b2SJeff Kirsher 	frag_count = 0 ;
182733f810b2SJeff Kirsher 	len = mb->sm_len ;
182833f810b2SJeff Kirsher 	while (len) {
182933f810b2SJeff Kirsher 		n = SMT_PAGESIZE - ((long)data & (SMT_PAGESIZE-1)) ;
183033f810b2SJeff Kirsher 		if (n >= len) {
183133f810b2SJeff Kirsher 			n = len ;
183233f810b2SJeff Kirsher 		}
18335dbc6530SJoe Perches 		DB_TX(5, "frag: virt/len = 0x%p/%d", data, n);
183433f810b2SJeff Kirsher 		virt[frag_count] = data ;
183533f810b2SJeff Kirsher 		frag_len[frag_count] = n ;
183633f810b2SJeff Kirsher 		frag_count++ ;
183733f810b2SJeff Kirsher 		len -= n ;
183833f810b2SJeff Kirsher 		data += n ;
183933f810b2SJeff Kirsher 	}
184033f810b2SJeff Kirsher 
184133f810b2SJeff Kirsher 	/*
184233f810b2SJeff Kirsher 	 * determine the frame status
184333f810b2SJeff Kirsher 	 */
184433f810b2SJeff Kirsher 	queue = smc->hw.fp.tx[QUEUE_A0] ;
184533f810b2SJeff Kirsher 	if (fc == FC_BEACON || fc == FC_SMT_LOC) {
184633f810b2SJeff Kirsher 		frame_status = LOC_TX ;
184733f810b2SJeff Kirsher 	}
184833f810b2SJeff Kirsher 	else {
184933f810b2SJeff Kirsher 		frame_status = LAN_TX ;
185033f810b2SJeff Kirsher 		if ((smc->os.hwm.pass_NSA &&(fc == FC_SMT_NSA)) ||
185133f810b2SJeff Kirsher 		   (smc->os.hwm.pass_SMT &&(fc == FC_SMT_INFO)))
185233f810b2SJeff Kirsher 			frame_status |= LOC_TX ;
185333f810b2SJeff Kirsher 	}
185433f810b2SJeff Kirsher 
185533f810b2SJeff Kirsher 	if (!smc->hw.mac_ring_is_up || frag_count > queue->tx_free) {
185633f810b2SJeff Kirsher 		frame_status &= ~LAN_TX;
185733f810b2SJeff Kirsher 		if (frame_status) {
18585dbc6530SJoe Perches 			DB_TX(2, "Ring is down: terminate LAN_TX");
185933f810b2SJeff Kirsher 		}
186033f810b2SJeff Kirsher 		else {
18615dbc6530SJoe Perches 			DB_TX(2, "Ring is down: terminate transmission");
186233f810b2SJeff Kirsher 			smt_free_mbuf(smc,mb) ;
186333f810b2SJeff Kirsher 			return ;
186433f810b2SJeff Kirsher 		}
186533f810b2SJeff Kirsher 	}
18665dbc6530SJoe Perches 	DB_TX(5, "frame_status = 0x%x", frame_status);
186733f810b2SJeff Kirsher 
186833f810b2SJeff Kirsher 	if ((frame_status & LAN_TX) && (frame_status & LOC_TX)) {
186933f810b2SJeff Kirsher 		mb->sm_use_count = 2 ;
187033f810b2SJeff Kirsher 	}
187133f810b2SJeff Kirsher 
187233f810b2SJeff Kirsher 	if (frame_status & LAN_TX) {
187333f810b2SJeff Kirsher 		t = queue->tx_curr_put ;
187433f810b2SJeff Kirsher 		frame_status |= FIRST_FRAG ;
187533f810b2SJeff Kirsher 		for (i = 0; i < frag_count; i++) {
18765dbc6530SJoe Perches 			DB_TX(5, "init TxD = 0x%p", t);
187733f810b2SJeff Kirsher 			if (i == frag_count-1) {
187833f810b2SJeff Kirsher 				frame_status |= LAST_FRAG ;
187933f810b2SJeff Kirsher 				t->txd_txdscr = cpu_to_le32(TX_DESCRIPTOR |
188033f810b2SJeff Kirsher 					(((__u32)(mb->sm_len-1)&3) << 27)) ;
188133f810b2SJeff Kirsher 			}
188233f810b2SJeff Kirsher 			t->txd_virt = virt[i] ;
188333f810b2SJeff Kirsher 			phys = dma_master(smc, (void far *)virt[i],
188433f810b2SJeff Kirsher 				frag_len[i], DMA_RD|SMT_BUF) ;
188533f810b2SJeff Kirsher 			t->txd_tbadr = cpu_to_le32(phys) ;
188633f810b2SJeff Kirsher 			tbctrl = cpu_to_le32((((__u32)frame_status &
188733f810b2SJeff Kirsher 				(FIRST_FRAG|LAST_FRAG)) << 26) |
188833f810b2SJeff Kirsher 				BMU_OWN | BMU_CHECK | BMU_SMT_TX |frag_len[i]) ;
188933f810b2SJeff Kirsher 			t->txd_tbctrl = tbctrl ;
189033f810b2SJeff Kirsher #ifndef	AIX
189133f810b2SJeff Kirsher 			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
189233f810b2SJeff Kirsher 			outpd(queue->tx_bmu_ctl,CSR_START) ;
189333f810b2SJeff Kirsher #else
189433f810b2SJeff Kirsher 			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
189533f810b2SJeff Kirsher 			outpd(ADDR(B0_XA_CSR),CSR_START) ;
189633f810b2SJeff Kirsher #endif
189733f810b2SJeff Kirsher 			frame_status &= ~FIRST_FRAG ;
189833f810b2SJeff Kirsher 			queue->tx_curr_put = t = t->txd_next ;
189933f810b2SJeff Kirsher 			queue->tx_free-- ;
190033f810b2SJeff Kirsher 			queue->tx_used++ ;
190133f810b2SJeff Kirsher 		}
190233f810b2SJeff Kirsher 		smc->mib.m[MAC0].fddiMACTransmit_Ct++ ;
190333f810b2SJeff Kirsher 		queue_txd_mb(smc,mb) ;
190433f810b2SJeff Kirsher 	}
190533f810b2SJeff Kirsher 
190633f810b2SJeff Kirsher 	if (frame_status & LOC_TX) {
19075dbc6530SJoe Perches 		DB_TX(5, "pass Mbuf to LLC queue");
190833f810b2SJeff Kirsher 		queue_llc_rx(smc,mb) ;
190933f810b2SJeff Kirsher 	}
191033f810b2SJeff Kirsher 
191133f810b2SJeff Kirsher 	/*
191233f810b2SJeff Kirsher 	 * We need to unqueue the free SMT_MBUFs here, because it may
191333f810b2SJeff Kirsher 	 * be that the SMT want's to send more than 1 frame for one down call
191433f810b2SJeff Kirsher 	 */
191533f810b2SJeff Kirsher 	mac_drv_clear_txd(smc) ;
191633f810b2SJeff Kirsher 	NDD_TRACE("THSE",t,queue->tx_free,frag_count) ;
191733f810b2SJeff Kirsher }
191833f810b2SJeff Kirsher 
191933f810b2SJeff Kirsher /*	BEGIN_MANUAL_ENTRY(mac_drv_clear_txd)
192033f810b2SJeff Kirsher  *	void mac_drv_clear_txd(smc)
192133f810b2SJeff Kirsher  *
192233f810b2SJeff Kirsher  * function	DOWNCALL	(hardware module, hwmtm.c)
192333f810b2SJeff Kirsher  *		mac_drv_clear_txd searches in both send queues for TxD's
192433f810b2SJeff Kirsher  *		which were finished by the adapter. It calls dma_complete
192533f810b2SJeff Kirsher  *		for each TxD. If the last fragment of an LLC frame is
192633f810b2SJeff Kirsher  *		reached, it calls mac_drv_tx_complete to release the
192733f810b2SJeff Kirsher  *		send buffer.
192833f810b2SJeff Kirsher  *
192933f810b2SJeff Kirsher  * return	nothing
193033f810b2SJeff Kirsher  *
193133f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
193233f810b2SJeff Kirsher  */
mac_drv_clear_txd(struct s_smc * smc)193333f810b2SJeff Kirsher static void mac_drv_clear_txd(struct s_smc *smc)
193433f810b2SJeff Kirsher {
193533f810b2SJeff Kirsher 	struct s_smt_tx_queue *queue ;
193633f810b2SJeff Kirsher 	struct s_smt_fp_txd volatile *t1 ;
193733f810b2SJeff Kirsher 	struct s_smt_fp_txd volatile *t2 = NULL ;
193833f810b2SJeff Kirsher 	SMbuf *mb ;
193933f810b2SJeff Kirsher 	u_long	tbctrl ;
194033f810b2SJeff Kirsher 	int i ;
194133f810b2SJeff Kirsher 	int frag_count ;
194233f810b2SJeff Kirsher 	int n ;
194333f810b2SJeff Kirsher 
194433f810b2SJeff Kirsher 	NDD_TRACE("THcB",0,0,0) ;
194533f810b2SJeff Kirsher 	for (i = QUEUE_S; i <= QUEUE_A0; i++) {
194633f810b2SJeff Kirsher 		queue = smc->hw.fp.tx[i] ;
194733f810b2SJeff Kirsher 		t1 = queue->tx_curr_get ;
19485dbc6530SJoe Perches 		DB_TX(5, "clear_txd: QUEUE = %d (0=sync/1=async)", i);
194933f810b2SJeff Kirsher 
195033f810b2SJeff Kirsher 		for ( ; ; ) {
195133f810b2SJeff Kirsher 			frag_count = 0 ;
195233f810b2SJeff Kirsher 
195333f810b2SJeff Kirsher 			do {
195433f810b2SJeff Kirsher 				DRV_BUF_FLUSH(t1,DDI_DMA_SYNC_FORCPU) ;
19555dbc6530SJoe Perches 				DB_TX(5, "check OWN/EOF bit of TxD 0x%p", t1);
195633f810b2SJeff Kirsher 				tbctrl = le32_to_cpu(CR_READ(t1->txd_tbctrl));
195733f810b2SJeff Kirsher 
195833f810b2SJeff Kirsher 				if (tbctrl & BMU_OWN || !queue->tx_used){
19595dbc6530SJoe Perches 					DB_TX(4, "End of TxDs queue %d", i);
196033f810b2SJeff Kirsher 					goto free_next_queue ;	/* next queue */
196133f810b2SJeff Kirsher 				}
196233f810b2SJeff Kirsher 				t1 = t1->txd_next ;
196333f810b2SJeff Kirsher 				frag_count++ ;
196433f810b2SJeff Kirsher 			} while (!(tbctrl & BMU_EOF)) ;
196533f810b2SJeff Kirsher 
196633f810b2SJeff Kirsher 			t1 = queue->tx_curr_get ;
196733f810b2SJeff Kirsher 			for (n = frag_count; n; n--) {
196833f810b2SJeff Kirsher 				tbctrl = le32_to_cpu(t1->txd_tbctrl) ;
196933f810b2SJeff Kirsher 				dma_complete(smc,
197033f810b2SJeff Kirsher 					(union s_fp_descr volatile *) t1,
197133f810b2SJeff Kirsher 					(int) (DMA_RD |
197233f810b2SJeff Kirsher 					((tbctrl & BMU_SMT_TX) >> 18))) ;
197333f810b2SJeff Kirsher 				t2 = t1 ;
197433f810b2SJeff Kirsher 				t1 = t1->txd_next ;
197533f810b2SJeff Kirsher 			}
197633f810b2SJeff Kirsher 
197733f810b2SJeff Kirsher 			if (tbctrl & BMU_SMT_TX) {
197833f810b2SJeff Kirsher 				mb = get_txd_mb(smc) ;
197933f810b2SJeff Kirsher 				smt_free_mbuf(smc,mb) ;
198033f810b2SJeff Kirsher 			}
198133f810b2SJeff Kirsher 			else {
198233f810b2SJeff Kirsher #ifndef PASS_1ST_TXD_2_TX_COMP
19835dbc6530SJoe Perches 				DB_TX(4, "mac_drv_tx_comp for TxD 0x%p", t2);
198433f810b2SJeff Kirsher 				mac_drv_tx_complete(smc,t2) ;
198533f810b2SJeff Kirsher #else
19865dbc6530SJoe Perches 				DB_TX(4, "mac_drv_tx_comp for TxD 0x%x",
19875dbc6530SJoe Perches 				      queue->tx_curr_get);
198833f810b2SJeff Kirsher 				mac_drv_tx_complete(smc,queue->tx_curr_get) ;
198933f810b2SJeff Kirsher #endif
199033f810b2SJeff Kirsher 			}
199133f810b2SJeff Kirsher 			queue->tx_curr_get = t1 ;
199233f810b2SJeff Kirsher 			queue->tx_free += frag_count ;
199333f810b2SJeff Kirsher 			queue->tx_used -= frag_count ;
199433f810b2SJeff Kirsher 		}
199533f810b2SJeff Kirsher free_next_queue: ;
199633f810b2SJeff Kirsher 	}
199733f810b2SJeff Kirsher 	NDD_TRACE("THcE",0,0,0) ;
199833f810b2SJeff Kirsher }
199933f810b2SJeff Kirsher 
200033f810b2SJeff Kirsher /*
200133f810b2SJeff Kirsher  *	BEGINN_MANUAL_ENTRY(mac_drv_clear_tx_queue)
200233f810b2SJeff Kirsher  *
200333f810b2SJeff Kirsher  * void mac_drv_clear_tx_queue(smc)
200433f810b2SJeff Kirsher  * struct s_smc *smc ;
200533f810b2SJeff Kirsher  *
200633f810b2SJeff Kirsher  * function	DOWNCALL	(hardware module, hwmtm.c)
200733f810b2SJeff Kirsher  *		mac_drv_clear_tx_queue is called from the SMT when
200833f810b2SJeff Kirsher  *		the RMT state machine has entered the ISOLATE state.
200933f810b2SJeff Kirsher  *		This function is also called by the os-specific module
201033f810b2SJeff Kirsher  *		after it has called the function card_stop().
201133f810b2SJeff Kirsher  *		In this case, the frames in the send queues are obsolete and
201233f810b2SJeff Kirsher  *		should be removed.
201333f810b2SJeff Kirsher  *
201433f810b2SJeff Kirsher  * note		calling sequence:
201533f810b2SJeff Kirsher  *		CLI_FBI(), card_stop(),
201633f810b2SJeff Kirsher  *		mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(),
201733f810b2SJeff Kirsher  *
201833f810b2SJeff Kirsher  * NOTE:	The caller is responsible that the BMUs are idle
201933f810b2SJeff Kirsher  *		when this function is called.
202033f810b2SJeff Kirsher  *
202133f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
202233f810b2SJeff Kirsher  */
mac_drv_clear_tx_queue(struct s_smc * smc)202333f810b2SJeff Kirsher void mac_drv_clear_tx_queue(struct s_smc *smc)
202433f810b2SJeff Kirsher {
202533f810b2SJeff Kirsher 	struct s_smt_fp_txd volatile *t ;
202633f810b2SJeff Kirsher 	struct s_smt_tx_queue *queue ;
202733f810b2SJeff Kirsher 	int tx_used ;
202833f810b2SJeff Kirsher 	int i ;
202933f810b2SJeff Kirsher 
203033f810b2SJeff Kirsher 	if (smc->hw.hw_state != STOPPED) {
203133f810b2SJeff Kirsher 		SK_BREAK() ;
203233f810b2SJeff Kirsher 		SMT_PANIC(smc,HWM_E0011,HWM_E0011_MSG) ;
203333f810b2SJeff Kirsher 		return ;
203433f810b2SJeff Kirsher 	}
203533f810b2SJeff Kirsher 
203633f810b2SJeff Kirsher 	for (i = QUEUE_S; i <= QUEUE_A0; i++) {
203733f810b2SJeff Kirsher 		queue = smc->hw.fp.tx[i] ;
20385dbc6530SJoe Perches 		DB_TX(5, "clear_tx_queue: QUEUE = %d (0=sync/1=async)", i);
203933f810b2SJeff Kirsher 
204033f810b2SJeff Kirsher 		/*
204133f810b2SJeff Kirsher 		 * switch the OWN bit of all pending frames to the host
204233f810b2SJeff Kirsher 		 */
204333f810b2SJeff Kirsher 		t = queue->tx_curr_get ;
204433f810b2SJeff Kirsher 		tx_used = queue->tx_used ;
204533f810b2SJeff Kirsher 		while (tx_used) {
204633f810b2SJeff Kirsher 			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ;
20475dbc6530SJoe Perches 			DB_TX(5, "switch OWN bit of TxD 0x%p", t);
204833f810b2SJeff Kirsher 			t->txd_tbctrl &= ~cpu_to_le32(BMU_OWN) ;
204933f810b2SJeff Kirsher 			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
205033f810b2SJeff Kirsher 			t = t->txd_next ;
205133f810b2SJeff Kirsher 			tx_used-- ;
205233f810b2SJeff Kirsher 		}
205333f810b2SJeff Kirsher 	}
205433f810b2SJeff Kirsher 
205533f810b2SJeff Kirsher 	/*
205633f810b2SJeff Kirsher 	 * release all TxD's for both send queues
205733f810b2SJeff Kirsher 	 */
205833f810b2SJeff Kirsher 	mac_drv_clear_txd(smc) ;
205933f810b2SJeff Kirsher 
206033f810b2SJeff Kirsher 	for (i = QUEUE_S; i <= QUEUE_A0; i++) {
206133f810b2SJeff Kirsher 		queue = smc->hw.fp.tx[i] ;
206233f810b2SJeff Kirsher 		t = queue->tx_curr_get ;
206333f810b2SJeff Kirsher 
206433f810b2SJeff Kirsher 		/*
206533f810b2SJeff Kirsher 		 * write the phys pointer of the NEXT descriptor into the
206633f810b2SJeff Kirsher 		 * BMU's current address descriptor pointer and set
206733f810b2SJeff Kirsher 		 * tx_curr_get and tx_curr_put to this position
206833f810b2SJeff Kirsher 		 */
206933f810b2SJeff Kirsher 		if (i == QUEUE_S) {
207033f810b2SJeff Kirsher 			outpd(ADDR(B5_XS_DA),le32_to_cpu(t->txd_ntdadr)) ;
207133f810b2SJeff Kirsher 		}
207233f810b2SJeff Kirsher 		else {
207333f810b2SJeff Kirsher 			outpd(ADDR(B5_XA_DA),le32_to_cpu(t->txd_ntdadr)) ;
207433f810b2SJeff Kirsher 		}
207533f810b2SJeff Kirsher 
207633f810b2SJeff Kirsher 		queue->tx_curr_put = queue->tx_curr_get->txd_next ;
207733f810b2SJeff Kirsher 		queue->tx_curr_get = queue->tx_curr_put ;
207833f810b2SJeff Kirsher 	}
207933f810b2SJeff Kirsher }
208033f810b2SJeff Kirsher 
208133f810b2SJeff Kirsher 
208233f810b2SJeff Kirsher /*
208333f810b2SJeff Kirsher 	-------------------------------------------------------------
208433f810b2SJeff Kirsher 	TEST FUNCTIONS:
208533f810b2SJeff Kirsher 	-------------------------------------------------------------
208633f810b2SJeff Kirsher */
208733f810b2SJeff Kirsher 
208833f810b2SJeff Kirsher #ifdef	DEBUG
208933f810b2SJeff Kirsher /*
209033f810b2SJeff Kirsher  *	BEGIN_MANUAL_ENTRY(mac_drv_debug_lev)
209133f810b2SJeff Kirsher  *	void mac_drv_debug_lev(smc,flag,lev)
209233f810b2SJeff Kirsher  *
209333f810b2SJeff Kirsher  * function	DOWNCALL	(drvsr.c)
209433f810b2SJeff Kirsher  *		To get a special debug info the user can assign a debug level
209533f810b2SJeff Kirsher  *		to any debug flag.
209633f810b2SJeff Kirsher  *
209733f810b2SJeff Kirsher  * para	flag	debug flag, possible values are:
209833f810b2SJeff Kirsher  *			= 0:	reset all debug flags (the defined level is
209933f810b2SJeff Kirsher  *				ignored)
210033f810b2SJeff Kirsher  *			= 1:	debug.d_smtf
210133f810b2SJeff Kirsher  *			= 2:	debug.d_smt
210233f810b2SJeff Kirsher  *			= 3:	debug.d_ecm
210333f810b2SJeff Kirsher  *			= 4:	debug.d_rmt
210433f810b2SJeff Kirsher  *			= 5:	debug.d_cfm
210533f810b2SJeff Kirsher  *			= 6:	debug.d_pcm
210633f810b2SJeff Kirsher  *
210733f810b2SJeff Kirsher  *			= 10:	debug.d_os.hwm_rx (hardware module receive path)
210833f810b2SJeff Kirsher  *			= 11:	debug.d_os.hwm_tx(hardware module transmit path)
210933f810b2SJeff Kirsher  *			= 12:	debug.d_os.hwm_gen(hardware module general flag)
211033f810b2SJeff Kirsher  *
211133f810b2SJeff Kirsher  *	lev	debug level
211233f810b2SJeff Kirsher  *
211333f810b2SJeff Kirsher  *	END_MANUAL_ENTRY
211433f810b2SJeff Kirsher  */
mac_drv_debug_lev(struct s_smc * smc,int flag,int lev)211533f810b2SJeff Kirsher void mac_drv_debug_lev(struct s_smc *smc, int flag, int lev)
211633f810b2SJeff Kirsher {
211733f810b2SJeff Kirsher 	switch(flag) {
211833f810b2SJeff Kirsher 	case (int)NULL:
211933f810b2SJeff Kirsher 		DB_P.d_smtf = DB_P.d_smt = DB_P.d_ecm = DB_P.d_rmt = 0 ;
212033f810b2SJeff Kirsher 		DB_P.d_cfm = 0 ;
212133f810b2SJeff Kirsher 		DB_P.d_os.hwm_rx = DB_P.d_os.hwm_tx = DB_P.d_os.hwm_gen = 0 ;
212233f810b2SJeff Kirsher #ifdef	SBA
212333f810b2SJeff Kirsher 		DB_P.d_sba = 0 ;
212433f810b2SJeff Kirsher #endif
212533f810b2SJeff Kirsher #ifdef	ESS
212633f810b2SJeff Kirsher 		DB_P.d_ess = 0 ;
212733f810b2SJeff Kirsher #endif
212833f810b2SJeff Kirsher 		break ;
212933f810b2SJeff Kirsher 	case DEBUG_SMTF:
213033f810b2SJeff Kirsher 		DB_P.d_smtf = lev ;
213133f810b2SJeff Kirsher 		break ;
213233f810b2SJeff Kirsher 	case DEBUG_SMT:
213333f810b2SJeff Kirsher 		DB_P.d_smt = lev ;
213433f810b2SJeff Kirsher 		break ;
213533f810b2SJeff Kirsher 	case DEBUG_ECM:
213633f810b2SJeff Kirsher 		DB_P.d_ecm = lev ;
213733f810b2SJeff Kirsher 		break ;
213833f810b2SJeff Kirsher 	case DEBUG_RMT:
213933f810b2SJeff Kirsher 		DB_P.d_rmt = lev ;
214033f810b2SJeff Kirsher 		break ;
214133f810b2SJeff Kirsher 	case DEBUG_CFM:
214233f810b2SJeff Kirsher 		DB_P.d_cfm = lev ;
214333f810b2SJeff Kirsher 		break ;
214433f810b2SJeff Kirsher 	case DEBUG_PCM:
214533f810b2SJeff Kirsher 		DB_P.d_pcm = lev ;
214633f810b2SJeff Kirsher 		break ;
214733f810b2SJeff Kirsher 	case DEBUG_SBA:
214833f810b2SJeff Kirsher #ifdef	SBA
214933f810b2SJeff Kirsher 		DB_P.d_sba = lev ;
215033f810b2SJeff Kirsher #endif
215133f810b2SJeff Kirsher 		break ;
215233f810b2SJeff Kirsher 	case DEBUG_ESS:
215333f810b2SJeff Kirsher #ifdef	ESS
215433f810b2SJeff Kirsher 		DB_P.d_ess = lev ;
215533f810b2SJeff Kirsher #endif
215633f810b2SJeff Kirsher 		break ;
215733f810b2SJeff Kirsher 	case DB_HWM_RX:
215833f810b2SJeff Kirsher 		DB_P.d_os.hwm_rx = lev ;
215933f810b2SJeff Kirsher 		break ;
216033f810b2SJeff Kirsher 	case DB_HWM_TX:
216133f810b2SJeff Kirsher 		DB_P.d_os.hwm_tx = lev ;
216233f810b2SJeff Kirsher 		break ;
216333f810b2SJeff Kirsher 	case DB_HWM_GEN:
216433f810b2SJeff Kirsher 		DB_P.d_os.hwm_gen = lev ;
216533f810b2SJeff Kirsher 		break ;
216633f810b2SJeff Kirsher 	default:
216733f810b2SJeff Kirsher 		break ;
216833f810b2SJeff Kirsher 	}
216933f810b2SJeff Kirsher }
217033f810b2SJeff Kirsher #endif
2171