162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *	(C)Copyright 1998,1999 SysKonnect,
562306a36Sopenharmony_ci *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *	See the file "skfddi.c" for further information.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *	The information in this file is provided "AS IS" without warranty.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci ******************************************************************************/
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define	HWMTM
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#ifndef FDDI
1662306a36Sopenharmony_ci#define	FDDI
1762306a36Sopenharmony_ci#endif
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "h/types.h"
2062306a36Sopenharmony_ci#include "h/fddi.h"
2162306a36Sopenharmony_ci#include "h/smc.h"
2262306a36Sopenharmony_ci#include "h/supern_2.h"
2362306a36Sopenharmony_ci#include "h/skfbiinc.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/*
2662306a36Sopenharmony_ci	-------------------------------------------------------------
2762306a36Sopenharmony_ci	DOCUMENTATION
2862306a36Sopenharmony_ci	-------------------------------------------------------------
2962306a36Sopenharmony_ci	BEGIN_MANUAL_ENTRY(DOCUMENTATION)
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci			T B D
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	END_MANUAL_ENTRY
3462306a36Sopenharmony_ci*/
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci	-------------------------------------------------------------
3762306a36Sopenharmony_ci	LOCAL VARIABLES:
3862306a36Sopenharmony_ci	-------------------------------------------------------------
3962306a36Sopenharmony_ci*/
4062306a36Sopenharmony_ci#ifdef COMMON_MB_POOL
4162306a36Sopenharmony_cistatic	SMbuf *mb_start;
4262306a36Sopenharmony_cistatic	SMbuf *mb_free;
4362306a36Sopenharmony_cistatic	int mb_init = FALSE ;
4462306a36Sopenharmony_cistatic	int call_count;
4562306a36Sopenharmony_ci#endif
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/*
4862306a36Sopenharmony_ci	-------------------------------------------------------------
4962306a36Sopenharmony_ci	EXTERNE VARIABLES:
5062306a36Sopenharmony_ci	-------------------------------------------------------------
5162306a36Sopenharmony_ci*/
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#ifdef	DEBUG
5462306a36Sopenharmony_ci#ifndef	DEBUG_BRD
5562306a36Sopenharmony_ciextern	struct smt_debug	debug ;
5662306a36Sopenharmony_ci#endif
5762306a36Sopenharmony_ci#endif
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#ifdef	NDIS_OS2
6062306a36Sopenharmony_ciextern	u_char	offDepth ;
6162306a36Sopenharmony_ciextern	u_char	force_irq_pending ;
6262306a36Sopenharmony_ci#endif
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/*
6562306a36Sopenharmony_ci	-------------------------------------------------------------
6662306a36Sopenharmony_ci	LOCAL FUNCTIONS:
6762306a36Sopenharmony_ci	-------------------------------------------------------------
6862306a36Sopenharmony_ci*/
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void queue_llc_rx(struct s_smc *smc, SMbuf *mb);
7162306a36Sopenharmony_cistatic void smt_to_llc(struct s_smc *smc, SMbuf *mb);
7262306a36Sopenharmony_cistatic void init_txd_ring(struct s_smc *smc);
7362306a36Sopenharmony_cistatic void init_rxd_ring(struct s_smc *smc);
7462306a36Sopenharmony_cistatic void queue_txd_mb(struct s_smc *smc, SMbuf *mb);
7562306a36Sopenharmony_cistatic u_long init_descr_ring(struct s_smc *smc, union s_fp_descr volatile *start,
7662306a36Sopenharmony_ci			      int count);
7762306a36Sopenharmony_cistatic u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue);
7862306a36Sopenharmony_cistatic u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue);
7962306a36Sopenharmony_cistatic SMbuf* get_llc_rx(struct s_smc *smc);
8062306a36Sopenharmony_cistatic SMbuf* get_txd_mb(struct s_smc *smc);
8162306a36Sopenharmony_cistatic void mac_drv_clear_txd(struct s_smc *smc);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/*
8462306a36Sopenharmony_ci	-------------------------------------------------------------
8562306a36Sopenharmony_ci	EXTERNAL FUNCTIONS:
8662306a36Sopenharmony_ci	-------------------------------------------------------------
8762306a36Sopenharmony_ci*/
8862306a36Sopenharmony_ci/*	The external SMT functions are listed in cmtdef.h */
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ciextern void* mac_drv_get_space(struct s_smc *smc, unsigned int size);
9162306a36Sopenharmony_ciextern void* mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size);
9262306a36Sopenharmony_ciextern void mac_drv_fill_rxd(struct s_smc *smc);
9362306a36Sopenharmony_ciextern void mac_drv_tx_complete(struct s_smc *smc,
9462306a36Sopenharmony_ci				volatile struct s_smt_fp_txd *txd);
9562306a36Sopenharmony_ciextern void mac_drv_rx_complete(struct s_smc *smc,
9662306a36Sopenharmony_ci				volatile struct s_smt_fp_rxd *rxd,
9762306a36Sopenharmony_ci				int frag_count, int len);
9862306a36Sopenharmony_ciextern void mac_drv_requeue_rxd(struct s_smc *smc,
9962306a36Sopenharmony_ci				volatile struct s_smt_fp_rxd *rxd,
10062306a36Sopenharmony_ci				int frag_count);
10162306a36Sopenharmony_ciextern void mac_drv_clear_rxd(struct s_smc *smc,
10262306a36Sopenharmony_ci			      volatile struct s_smt_fp_rxd *rxd, int frag_count);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#ifdef	USE_OS_CPY
10562306a36Sopenharmony_ciextern void hwm_cpy_rxd2mb(void);
10662306a36Sopenharmony_ciextern void hwm_cpy_txd2mb(void);
10762306a36Sopenharmony_ci#endif
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#ifdef	ALL_RX_COMPLETE
11062306a36Sopenharmony_ciextern void mac_drv_all_receives_complete(void);
11162306a36Sopenharmony_ci#endif
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ciextern u_long mac_drv_virt2phys(struct s_smc *smc, void *virt);
11462306a36Sopenharmony_ciextern u_long dma_master(struct s_smc *smc, void *virt, int len, int flag);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci#ifdef	NDIS_OS2
11762306a36Sopenharmony_ciextern void post_proc(void);
11862306a36Sopenharmony_ci#else
11962306a36Sopenharmony_ciextern void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr,
12062306a36Sopenharmony_ci			 int flag);
12162306a36Sopenharmony_ci#endif
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ciextern int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead,
12462306a36Sopenharmony_ci			   int la_len);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/*
12762306a36Sopenharmony_ci	-------------------------------------------------------------
12862306a36Sopenharmony_ci	PUBLIC FUNCTIONS:
12962306a36Sopenharmony_ci	-------------------------------------------------------------
13062306a36Sopenharmony_ci*/
13162306a36Sopenharmony_civoid process_receive(struct s_smc *smc);
13262306a36Sopenharmony_civoid fddi_isr(struct s_smc *smc);
13362306a36Sopenharmony_civoid smt_free_mbuf(struct s_smc *smc, SMbuf *mb);
13462306a36Sopenharmony_civoid init_driver_fplus(struct s_smc *smc);
13562306a36Sopenharmony_civoid mac_drv_rx_mode(struct s_smc *smc, int mode);
13662306a36Sopenharmony_civoid init_fddi_driver(struct s_smc *smc, u_char *mac_addr);
13762306a36Sopenharmony_civoid mac_drv_clear_tx_queue(struct s_smc *smc);
13862306a36Sopenharmony_civoid mac_drv_clear_rx_queue(struct s_smc *smc);
13962306a36Sopenharmony_civoid hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
14062306a36Sopenharmony_ci		 int frame_status);
14162306a36Sopenharmony_civoid hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
14262306a36Sopenharmony_ci		 int frame_status);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ciint mac_drv_init(struct s_smc *smc);
14562306a36Sopenharmony_ciint hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len,
14662306a36Sopenharmony_ci		int frame_status);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ciu_int mac_drv_check_space(void);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ciSMbuf* smt_get_mbuf(struct s_smc *smc);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci#ifdef DEBUG
15362306a36Sopenharmony_ci	void mac_drv_debug_lev(struct s_smc *smc, int flag, int lev);
15462306a36Sopenharmony_ci#endif
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/*
15762306a36Sopenharmony_ci	-------------------------------------------------------------
15862306a36Sopenharmony_ci	MACROS:
15962306a36Sopenharmony_ci	-------------------------------------------------------------
16062306a36Sopenharmony_ci*/
16162306a36Sopenharmony_ci#ifndef	UNUSED
16262306a36Sopenharmony_ci#ifdef	lint
16362306a36Sopenharmony_ci#define UNUSED(x)	(x) = (x)
16462306a36Sopenharmony_ci#else
16562306a36Sopenharmony_ci#define UNUSED(x)
16662306a36Sopenharmony_ci#endif
16762306a36Sopenharmony_ci#endif
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci#ifdef	USE_CAN_ADDR
17062306a36Sopenharmony_ci#define MA		smc->hw.fddi_canon_addr.a
17162306a36Sopenharmony_ci#define	GROUP_ADDR_BIT	0x01
17262306a36Sopenharmony_ci#else
17362306a36Sopenharmony_ci#define	MA		smc->hw.fddi_home_addr.a
17462306a36Sopenharmony_ci#define	GROUP_ADDR_BIT	0x80
17562306a36Sopenharmony_ci#endif
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci#define RXD_TXD_COUNT	(HWM_ASYNC_TXD_COUNT+HWM_SYNC_TXD_COUNT+\
17862306a36Sopenharmony_ci			SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT)
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci#ifdef	MB_OUTSIDE_SMC
18162306a36Sopenharmony_ci#define	EXT_VIRT_MEM	((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd) +\
18262306a36Sopenharmony_ci			MAX_MBUF*sizeof(SMbuf))
18362306a36Sopenharmony_ci#define	EXT_VIRT_MEM_2	((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd))
18462306a36Sopenharmony_ci#else
18562306a36Sopenharmony_ci#define	EXT_VIRT_MEM	((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd))
18662306a36Sopenharmony_ci#endif
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/*
18962306a36Sopenharmony_ci	 * define critical read for 16 Bit drivers
19062306a36Sopenharmony_ci	 */
19162306a36Sopenharmony_ci#if	defined(NDIS_OS2) || defined(ODI2)
19262306a36Sopenharmony_ci#define CR_READ(var)	((var) & 0xffff0000 | ((var) & 0xffff))
19362306a36Sopenharmony_ci#else
19462306a36Sopenharmony_ci#define CR_READ(var)	(__le32)(var)
19562306a36Sopenharmony_ci#endif
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci#define IMASK_SLOW	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
19862306a36Sopenharmony_ci			 IS_MINTR1 | IS_MINTR2 | IS_MINTR3 | IS_R1_P | \
19962306a36Sopenharmony_ci			 IS_R1_C | IS_XA_C | IS_XS_C)
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/*
20262306a36Sopenharmony_ci	-------------------------------------------------------------
20362306a36Sopenharmony_ci	INIT- AND SMT FUNCTIONS:
20462306a36Sopenharmony_ci	-------------------------------------------------------------
20562306a36Sopenharmony_ci*/
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci/*
20962306a36Sopenharmony_ci *	BEGIN_MANUAL_ENTRY(mac_drv_check_space)
21062306a36Sopenharmony_ci *	u_int mac_drv_check_space()
21162306a36Sopenharmony_ci *
21262306a36Sopenharmony_ci *	function	DOWNCALL	(drvsr.c)
21362306a36Sopenharmony_ci *			This function calculates the needed non virtual
21462306a36Sopenharmony_ci *			memory for MBufs, RxD and TxD descriptors etc.
21562306a36Sopenharmony_ci *			needed by the driver.
21662306a36Sopenharmony_ci *
21762306a36Sopenharmony_ci *	return		u_int	memory in bytes
21862306a36Sopenharmony_ci *
21962306a36Sopenharmony_ci *	END_MANUAL_ENTRY
22062306a36Sopenharmony_ci */
22162306a36Sopenharmony_ciu_int mac_drv_check_space(void)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci#ifdef	MB_OUTSIDE_SMC
22462306a36Sopenharmony_ci#ifdef	COMMON_MB_POOL
22562306a36Sopenharmony_ci	call_count++ ;
22662306a36Sopenharmony_ci	if (call_count == 1) {
22762306a36Sopenharmony_ci		return EXT_VIRT_MEM;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci	else {
23062306a36Sopenharmony_ci		return EXT_VIRT_MEM_2;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci#else
23362306a36Sopenharmony_ci	return EXT_VIRT_MEM;
23462306a36Sopenharmony_ci#endif
23562306a36Sopenharmony_ci#else
23662306a36Sopenharmony_ci	return 0;
23762306a36Sopenharmony_ci#endif
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci/*
24162306a36Sopenharmony_ci *	BEGIN_MANUAL_ENTRY(mac_drv_init)
24262306a36Sopenharmony_ci *	void mac_drv_init(smc)
24362306a36Sopenharmony_ci *
24462306a36Sopenharmony_ci *	function	DOWNCALL	(drvsr.c)
24562306a36Sopenharmony_ci *			In this function the hardware module allocates it's
24662306a36Sopenharmony_ci *			memory.
24762306a36Sopenharmony_ci *			The operating system dependent module should call
24862306a36Sopenharmony_ci *			mac_drv_init once, after the adatper is detected.
24962306a36Sopenharmony_ci *	END_MANUAL_ENTRY
25062306a36Sopenharmony_ci */
25162306a36Sopenharmony_ciint mac_drv_init(struct s_smc *smc)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	if (sizeof(struct s_smt_fp_rxd) % 16) {
25462306a36Sopenharmony_ci		SMT_PANIC(smc,HWM_E0001,HWM_E0001_MSG) ;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci	if (sizeof(struct s_smt_fp_txd) % 16) {
25762306a36Sopenharmony_ci		SMT_PANIC(smc,HWM_E0002,HWM_E0002_MSG) ;
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/*
26162306a36Sopenharmony_ci	 * get the required memory for the RxDs and TxDs
26262306a36Sopenharmony_ci	 */
26362306a36Sopenharmony_ci	if (!(smc->os.hwm.descr_p = (union s_fp_descr volatile *)
26462306a36Sopenharmony_ci		mac_drv_get_desc_mem(smc,(u_int)
26562306a36Sopenharmony_ci		(RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)))) {
26662306a36Sopenharmony_ci		return 1;	/* no space the hwm modul can't work */
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/*
27062306a36Sopenharmony_ci	 * get the memory for the SMT MBufs
27162306a36Sopenharmony_ci	 */
27262306a36Sopenharmony_ci#ifndef	MB_OUTSIDE_SMC
27362306a36Sopenharmony_ci	smc->os.hwm.mbuf_pool.mb_start=(SMbuf *)(&smc->os.hwm.mbuf_pool.mb[0]) ;
27462306a36Sopenharmony_ci#else
27562306a36Sopenharmony_ci#ifndef	COMMON_MB_POOL
27662306a36Sopenharmony_ci	if (!(smc->os.hwm.mbuf_pool.mb_start = (SMbuf *) mac_drv_get_space(smc,
27762306a36Sopenharmony_ci		MAX_MBUF*sizeof(SMbuf)))) {
27862306a36Sopenharmony_ci		return 1;	/* no space the hwm modul can't work */
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci#else
28162306a36Sopenharmony_ci	if (!mb_start) {
28262306a36Sopenharmony_ci		if (!(mb_start = (SMbuf *) mac_drv_get_space(smc,
28362306a36Sopenharmony_ci			MAX_MBUF*sizeof(SMbuf)))) {
28462306a36Sopenharmony_ci			return 1;	/* no space the hwm modul can't work */
28562306a36Sopenharmony_ci		}
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci#endif
28862306a36Sopenharmony_ci#endif
28962306a36Sopenharmony_ci	return 0;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci/*
29362306a36Sopenharmony_ci *	BEGIN_MANUAL_ENTRY(init_driver_fplus)
29462306a36Sopenharmony_ci *	init_driver_fplus(smc)
29562306a36Sopenharmony_ci *
29662306a36Sopenharmony_ci * Sets hardware modul specific values for the mode register 2
29762306a36Sopenharmony_ci * (e.g. the byte alignment for the received frames, the position of the
29862306a36Sopenharmony_ci *	 least significant byte etc.)
29962306a36Sopenharmony_ci *	END_MANUAL_ENTRY
30062306a36Sopenharmony_ci */
30162306a36Sopenharmony_civoid init_driver_fplus(struct s_smc *smc)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	smc->hw.fp.mdr2init = FM_LSB | FM_BMMODE | FM_ENNPRQ | FM_ENHSRQ | 3 ;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci#ifdef	PCI
30662306a36Sopenharmony_ci	smc->hw.fp.mdr2init |= FM_CHKPAR | FM_PARITY ;
30762306a36Sopenharmony_ci#endif
30862306a36Sopenharmony_ci	smc->hw.fp.mdr3init = FM_MENRQAUNLCK | FM_MENRS ;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci#ifdef	USE_CAN_ADDR
31162306a36Sopenharmony_ci	/* enable address bit swapping */
31262306a36Sopenharmony_ci	smc->hw.fp.frselreg_init = FM_ENXMTADSWAP | FM_ENRCVADSWAP ;
31362306a36Sopenharmony_ci#endif
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic u_long init_descr_ring(struct s_smc *smc,
31762306a36Sopenharmony_ci			      union s_fp_descr volatile *start,
31862306a36Sopenharmony_ci			      int count)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	int i ;
32162306a36Sopenharmony_ci	union s_fp_descr volatile *d1 ;
32262306a36Sopenharmony_ci	union s_fp_descr volatile *d2 ;
32362306a36Sopenharmony_ci	u_long	phys ;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	DB_GEN(3, "descr ring starts at = %p", start);
32662306a36Sopenharmony_ci	for (i=count-1, d1=start; i ; i--) {
32762306a36Sopenharmony_ci		d2 = d1 ;
32862306a36Sopenharmony_ci		d1++ ;		/* descr is owned by the host */
32962306a36Sopenharmony_ci		d2->r.rxd_rbctrl = cpu_to_le32(BMU_CHECK) ;
33062306a36Sopenharmony_ci		d2->r.rxd_next = &d1->r ;
33162306a36Sopenharmony_ci		phys = mac_drv_virt2phys(smc,(void *)d1) ;
33262306a36Sopenharmony_ci		d2->r.rxd_nrdadr = cpu_to_le32(phys) ;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci	DB_GEN(3, "descr ring ends at = %p", d1);
33562306a36Sopenharmony_ci	d1->r.rxd_rbctrl = cpu_to_le32(BMU_CHECK) ;
33662306a36Sopenharmony_ci	d1->r.rxd_next = &start->r ;
33762306a36Sopenharmony_ci	phys = mac_drv_virt2phys(smc,(void *)start) ;
33862306a36Sopenharmony_ci	d1->r.rxd_nrdadr = cpu_to_le32(phys) ;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	for (i=count, d1=start; i ; i--) {
34162306a36Sopenharmony_ci		DRV_BUF_FLUSH(&d1->r,DDI_DMA_SYNC_FORDEV) ;
34262306a36Sopenharmony_ci		d1++;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	return phys;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic void init_txd_ring(struct s_smc *smc)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct s_smt_fp_txd volatile *ds ;
35062306a36Sopenharmony_ci	struct s_smt_tx_queue *queue ;
35162306a36Sopenharmony_ci	u_long	phys ;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/*
35462306a36Sopenharmony_ci	 * initialize the transmit descriptors
35562306a36Sopenharmony_ci	 */
35662306a36Sopenharmony_ci	ds = (struct s_smt_fp_txd volatile *) ((char *)smc->os.hwm.descr_p +
35762306a36Sopenharmony_ci		SMT_R1_RXD_COUNT*sizeof(struct s_smt_fp_rxd)) ;
35862306a36Sopenharmony_ci	queue = smc->hw.fp.tx[QUEUE_A0] ;
35962306a36Sopenharmony_ci	DB_GEN(3, "Init async TxD ring, %d TxDs", HWM_ASYNC_TXD_COUNT);
36062306a36Sopenharmony_ci	(void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
36162306a36Sopenharmony_ci		HWM_ASYNC_TXD_COUNT) ;
36262306a36Sopenharmony_ci	phys = le32_to_cpu(ds->txd_ntdadr) ;
36362306a36Sopenharmony_ci	ds++ ;
36462306a36Sopenharmony_ci	queue->tx_curr_put = queue->tx_curr_get = ds ;
36562306a36Sopenharmony_ci	ds-- ;
36662306a36Sopenharmony_ci	queue->tx_free = HWM_ASYNC_TXD_COUNT ;
36762306a36Sopenharmony_ci	queue->tx_used = 0 ;
36862306a36Sopenharmony_ci	outpd(ADDR(B5_XA_DA),phys) ;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	ds = (struct s_smt_fp_txd volatile *) ((char *)ds +
37162306a36Sopenharmony_ci		HWM_ASYNC_TXD_COUNT*sizeof(struct s_smt_fp_txd)) ;
37262306a36Sopenharmony_ci	queue = smc->hw.fp.tx[QUEUE_S] ;
37362306a36Sopenharmony_ci	DB_GEN(3, "Init sync TxD ring, %d TxDs", HWM_SYNC_TXD_COUNT);
37462306a36Sopenharmony_ci	(void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
37562306a36Sopenharmony_ci		HWM_SYNC_TXD_COUNT) ;
37662306a36Sopenharmony_ci	phys = le32_to_cpu(ds->txd_ntdadr) ;
37762306a36Sopenharmony_ci	ds++ ;
37862306a36Sopenharmony_ci	queue->tx_curr_put = queue->tx_curr_get = ds ;
37962306a36Sopenharmony_ci	queue->tx_free = HWM_SYNC_TXD_COUNT ;
38062306a36Sopenharmony_ci	queue->tx_used = 0 ;
38162306a36Sopenharmony_ci	outpd(ADDR(B5_XS_DA),phys) ;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic void init_rxd_ring(struct s_smc *smc)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct s_smt_fp_rxd volatile *ds ;
38762306a36Sopenharmony_ci	struct s_smt_rx_queue *queue ;
38862306a36Sopenharmony_ci	u_long	phys ;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	/*
39162306a36Sopenharmony_ci	 * initialize the receive descriptors
39262306a36Sopenharmony_ci	 */
39362306a36Sopenharmony_ci	ds = (struct s_smt_fp_rxd volatile *) smc->os.hwm.descr_p ;
39462306a36Sopenharmony_ci	queue = smc->hw.fp.rx[QUEUE_R1] ;
39562306a36Sopenharmony_ci	DB_GEN(3, "Init RxD ring, %d RxDs", SMT_R1_RXD_COUNT);
39662306a36Sopenharmony_ci	(void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
39762306a36Sopenharmony_ci		SMT_R1_RXD_COUNT) ;
39862306a36Sopenharmony_ci	phys = le32_to_cpu(ds->rxd_nrdadr) ;
39962306a36Sopenharmony_ci	ds++ ;
40062306a36Sopenharmony_ci	queue->rx_curr_put = queue->rx_curr_get = ds ;
40162306a36Sopenharmony_ci	queue->rx_free = SMT_R1_RXD_COUNT ;
40262306a36Sopenharmony_ci	queue->rx_used = 0 ;
40362306a36Sopenharmony_ci	outpd(ADDR(B4_R1_DA),phys) ;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci/*
40762306a36Sopenharmony_ci *	BEGIN_MANUAL_ENTRY(init_fddi_driver)
40862306a36Sopenharmony_ci *	void init_fddi_driver(smc,mac_addr)
40962306a36Sopenharmony_ci *
41062306a36Sopenharmony_ci * initializes the driver and it's variables
41162306a36Sopenharmony_ci *
41262306a36Sopenharmony_ci *	END_MANUAL_ENTRY
41362306a36Sopenharmony_ci */
41462306a36Sopenharmony_civoid init_fddi_driver(struct s_smc *smc, u_char *mac_addr)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	SMbuf	*mb ;
41762306a36Sopenharmony_ci	int	i ;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	init_board(smc,mac_addr) ;
42062306a36Sopenharmony_ci	(void)init_fplus(smc) ;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/*
42362306a36Sopenharmony_ci	 * initialize the SMbufs for the SMT
42462306a36Sopenharmony_ci	 */
42562306a36Sopenharmony_ci#ifndef	COMMON_MB_POOL
42662306a36Sopenharmony_ci	mb = smc->os.hwm.mbuf_pool.mb_start ;
42762306a36Sopenharmony_ci	smc->os.hwm.mbuf_pool.mb_free = (SMbuf *)NULL ;
42862306a36Sopenharmony_ci	for (i = 0; i < MAX_MBUF; i++) {
42962306a36Sopenharmony_ci		mb->sm_use_count = 1 ;
43062306a36Sopenharmony_ci		smt_free_mbuf(smc,mb)	;
43162306a36Sopenharmony_ci		mb++ ;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci#else
43462306a36Sopenharmony_ci	mb = mb_start ;
43562306a36Sopenharmony_ci	if (!mb_init) {
43662306a36Sopenharmony_ci		mb_free = 0 ;
43762306a36Sopenharmony_ci		for (i = 0; i < MAX_MBUF; i++) {
43862306a36Sopenharmony_ci			mb->sm_use_count = 1 ;
43962306a36Sopenharmony_ci			smt_free_mbuf(smc,mb)	;
44062306a36Sopenharmony_ci			mb++ ;
44162306a36Sopenharmony_ci		}
44262306a36Sopenharmony_ci		mb_init = TRUE ;
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci#endif
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	/*
44762306a36Sopenharmony_ci	 * initialize the other variables
44862306a36Sopenharmony_ci	 */
44962306a36Sopenharmony_ci	smc->os.hwm.llc_rx_pipe = smc->os.hwm.llc_rx_tail = (SMbuf *)NULL ;
45062306a36Sopenharmony_ci	smc->os.hwm.txd_tx_pipe = smc->os.hwm.txd_tx_tail = NULL ;
45162306a36Sopenharmony_ci	smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = smc->os.hwm.pass_DB = 0 ;
45262306a36Sopenharmony_ci	smc->os.hwm.pass_llc_promisc = TRUE ;
45362306a36Sopenharmony_ci	smc->os.hwm.queued_rx_frames = smc->os.hwm.queued_txd_mb = 0 ;
45462306a36Sopenharmony_ci	smc->os.hwm.detec_count = 0 ;
45562306a36Sopenharmony_ci	smc->os.hwm.rx_break = 0 ;
45662306a36Sopenharmony_ci	smc->os.hwm.rx_len_error = 0 ;
45762306a36Sopenharmony_ci	smc->os.hwm.isr_flag = FALSE ;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/*
46062306a36Sopenharmony_ci	 * make sure that the start pointer is 16 byte aligned
46162306a36Sopenharmony_ci	 */
46262306a36Sopenharmony_ci	i = 16 - ((long)smc->os.hwm.descr_p & 0xf) ;
46362306a36Sopenharmony_ci	if (i != 16) {
46462306a36Sopenharmony_ci		DB_GEN(3, "i = %d", i);
46562306a36Sopenharmony_ci		smc->os.hwm.descr_p = (union s_fp_descr volatile *)
46662306a36Sopenharmony_ci			((char *)smc->os.hwm.descr_p+i) ;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci	DB_GEN(3, "pt to descr area = %p", smc->os.hwm.descr_p);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	init_txd_ring(smc) ;
47162306a36Sopenharmony_ci	init_rxd_ring(smc) ;
47262306a36Sopenharmony_ci	mac_drv_fill_rxd(smc) ;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	init_plc(smc) ;
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ciSMbuf *smt_get_mbuf(struct s_smc *smc)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	register SMbuf	*mb ;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci#ifndef	COMMON_MB_POOL
48362306a36Sopenharmony_ci	mb = smc->os.hwm.mbuf_pool.mb_free ;
48462306a36Sopenharmony_ci#else
48562306a36Sopenharmony_ci	mb = mb_free ;
48662306a36Sopenharmony_ci#endif
48762306a36Sopenharmony_ci	if (mb) {
48862306a36Sopenharmony_ci#ifndef	COMMON_MB_POOL
48962306a36Sopenharmony_ci		smc->os.hwm.mbuf_pool.mb_free = mb->sm_next ;
49062306a36Sopenharmony_ci#else
49162306a36Sopenharmony_ci		mb_free = mb->sm_next ;
49262306a36Sopenharmony_ci#endif
49362306a36Sopenharmony_ci		mb->sm_off = 8 ;
49462306a36Sopenharmony_ci		mb->sm_use_count = 1 ;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci	DB_GEN(3, "get SMbuf: mb = %p", mb);
49762306a36Sopenharmony_ci	return mb;	/* May be NULL */
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_civoid smt_free_mbuf(struct s_smc *smc, SMbuf *mb)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	if (mb) {
50462306a36Sopenharmony_ci		mb->sm_use_count-- ;
50562306a36Sopenharmony_ci		DB_GEN(3, "free_mbuf: sm_use_count = %d", mb->sm_use_count);
50662306a36Sopenharmony_ci		/*
50762306a36Sopenharmony_ci		 * If the use_count is != zero the MBuf is queued
50862306a36Sopenharmony_ci		 * more than once and must not queued into the
50962306a36Sopenharmony_ci		 * free MBuf queue
51062306a36Sopenharmony_ci		 */
51162306a36Sopenharmony_ci		if (!mb->sm_use_count) {
51262306a36Sopenharmony_ci			DB_GEN(3, "free SMbuf: mb = %p", mb);
51362306a36Sopenharmony_ci#ifndef	COMMON_MB_POOL
51462306a36Sopenharmony_ci			mb->sm_next = smc->os.hwm.mbuf_pool.mb_free ;
51562306a36Sopenharmony_ci			smc->os.hwm.mbuf_pool.mb_free = mb ;
51662306a36Sopenharmony_ci#else
51762306a36Sopenharmony_ci			mb->sm_next = mb_free ;
51862306a36Sopenharmony_ci			mb_free = mb ;
51962306a36Sopenharmony_ci#endif
52062306a36Sopenharmony_ci		}
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci	else
52362306a36Sopenharmony_ci		SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci/*
52862306a36Sopenharmony_ci *	BEGIN_MANUAL_ENTRY(mac_drv_repair_descr)
52962306a36Sopenharmony_ci *	void mac_drv_repair_descr(smc)
53062306a36Sopenharmony_ci *
53162306a36Sopenharmony_ci * function	called from SMT	(HWM / hwmtm.c)
53262306a36Sopenharmony_ci *		The BMU is idle when this function is called.
53362306a36Sopenharmony_ci *		Mac_drv_repair_descr sets up the physical address
53462306a36Sopenharmony_ci *		for all receive and transmit queues where the BMU
53562306a36Sopenharmony_ci *		should continue.
53662306a36Sopenharmony_ci *		It may be that the BMU was reseted during a fragmented
53762306a36Sopenharmony_ci *		transfer. In this case there are some fragments which will
53862306a36Sopenharmony_ci *		never completed by the BMU. The OWN bit of this fragments
53962306a36Sopenharmony_ci *		must be switched to be owned by the host.
54062306a36Sopenharmony_ci *
54162306a36Sopenharmony_ci *		Give a start command to the receive BMU.
54262306a36Sopenharmony_ci *		Start the transmit BMUs if transmit frames pending.
54362306a36Sopenharmony_ci *
54462306a36Sopenharmony_ci *	END_MANUAL_ENTRY
54562306a36Sopenharmony_ci */
54662306a36Sopenharmony_civoid mac_drv_repair_descr(struct s_smc *smc)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	u_long	phys ;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (smc->hw.hw_state != STOPPED) {
55162306a36Sopenharmony_ci		SK_BREAK() ;
55262306a36Sopenharmony_ci		SMT_PANIC(smc,HWM_E0013,HWM_E0013_MSG) ;
55362306a36Sopenharmony_ci		return ;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	/*
55762306a36Sopenharmony_ci	 * repair tx queues: don't start
55862306a36Sopenharmony_ci	 */
55962306a36Sopenharmony_ci	phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_A0]) ;
56062306a36Sopenharmony_ci	outpd(ADDR(B5_XA_DA),phys) ;
56162306a36Sopenharmony_ci	if (smc->hw.fp.tx_q[QUEUE_A0].tx_used) {
56262306a36Sopenharmony_ci		outpd(ADDR(B0_XA_CSR),CSR_START) ;
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci	phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_S]) ;
56562306a36Sopenharmony_ci	outpd(ADDR(B5_XS_DA),phys) ;
56662306a36Sopenharmony_ci	if (smc->hw.fp.tx_q[QUEUE_S].tx_used) {
56762306a36Sopenharmony_ci		outpd(ADDR(B0_XS_CSR),CSR_START) ;
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	/*
57162306a36Sopenharmony_ci	 * repair rx queues
57262306a36Sopenharmony_ci	 */
57362306a36Sopenharmony_ci	phys = repair_rxd_ring(smc,smc->hw.fp.rx[QUEUE_R1]) ;
57462306a36Sopenharmony_ci	outpd(ADDR(B4_R1_DA),phys) ;
57562306a36Sopenharmony_ci	outpd(ADDR(B0_R1_CSR),CSR_START) ;
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	int i ;
58162306a36Sopenharmony_ci	int tx_used ;
58262306a36Sopenharmony_ci	u_long phys ;
58362306a36Sopenharmony_ci	u_long tbctrl ;
58462306a36Sopenharmony_ci	struct s_smt_fp_txd volatile *t ;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	SK_UNUSED(smc) ;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	t = queue->tx_curr_get ;
58962306a36Sopenharmony_ci	tx_used = queue->tx_used ;
59062306a36Sopenharmony_ci	for (i = tx_used+queue->tx_free-1 ; i ; i-- ) {
59162306a36Sopenharmony_ci		t = t->txd_next ;
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci	phys = le32_to_cpu(t->txd_ntdadr) ;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	t = queue->tx_curr_get ;
59662306a36Sopenharmony_ci	while (tx_used) {
59762306a36Sopenharmony_ci		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ;
59862306a36Sopenharmony_ci		tbctrl = le32_to_cpu(t->txd_tbctrl) ;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci		if (tbctrl & BMU_OWN) {
60162306a36Sopenharmony_ci			if (tbctrl & BMU_STF) {
60262306a36Sopenharmony_ci				break ;		/* exit the loop */
60362306a36Sopenharmony_ci			}
60462306a36Sopenharmony_ci			else {
60562306a36Sopenharmony_ci				/*
60662306a36Sopenharmony_ci				 * repair the descriptor
60762306a36Sopenharmony_ci				 */
60862306a36Sopenharmony_ci				t->txd_tbctrl &= ~cpu_to_le32(BMU_OWN) ;
60962306a36Sopenharmony_ci			}
61062306a36Sopenharmony_ci		}
61162306a36Sopenharmony_ci		phys = le32_to_cpu(t->txd_ntdadr) ;
61262306a36Sopenharmony_ci		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
61362306a36Sopenharmony_ci		t = t->txd_next ;
61462306a36Sopenharmony_ci		tx_used-- ;
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci	return phys;
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci/*
62062306a36Sopenharmony_ci * Repairs the receive descriptor ring and returns the physical address
62162306a36Sopenharmony_ci * where the BMU should continue working.
62262306a36Sopenharmony_ci *
62362306a36Sopenharmony_ci *	o The physical address where the BMU was stopped has to be
62462306a36Sopenharmony_ci *	  determined. This is the next RxD after rx_curr_get with an OWN
62562306a36Sopenharmony_ci *	  bit set.
62662306a36Sopenharmony_ci *	o The BMU should start working at beginning of the next frame.
62762306a36Sopenharmony_ci *	  RxDs with an OWN bit set but with a reset STF bit should be
62862306a36Sopenharmony_ci *	  skipped and owned by the driver (OWN = 0).
62962306a36Sopenharmony_ci */
63062306a36Sopenharmony_cistatic u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	int i ;
63362306a36Sopenharmony_ci	int rx_used ;
63462306a36Sopenharmony_ci	u_long phys ;
63562306a36Sopenharmony_ci	u_long rbctrl ;
63662306a36Sopenharmony_ci	struct s_smt_fp_rxd volatile *r ;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	SK_UNUSED(smc) ;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	r = queue->rx_curr_get ;
64162306a36Sopenharmony_ci	rx_used = queue->rx_used ;
64262306a36Sopenharmony_ci	for (i = SMT_R1_RXD_COUNT-1 ; i ; i-- ) {
64362306a36Sopenharmony_ci		r = r->rxd_next ;
64462306a36Sopenharmony_ci	}
64562306a36Sopenharmony_ci	phys = le32_to_cpu(r->rxd_nrdadr) ;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	r = queue->rx_curr_get ;
64862306a36Sopenharmony_ci	while (rx_used) {
64962306a36Sopenharmony_ci		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
65062306a36Sopenharmony_ci		rbctrl = le32_to_cpu(r->rxd_rbctrl) ;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci		if (rbctrl & BMU_OWN) {
65362306a36Sopenharmony_ci			if (rbctrl & BMU_STF) {
65462306a36Sopenharmony_ci				break ;		/* exit the loop */
65562306a36Sopenharmony_ci			}
65662306a36Sopenharmony_ci			else {
65762306a36Sopenharmony_ci				/*
65862306a36Sopenharmony_ci				 * repair the descriptor
65962306a36Sopenharmony_ci				 */
66062306a36Sopenharmony_ci				r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ;
66162306a36Sopenharmony_ci			}
66262306a36Sopenharmony_ci		}
66362306a36Sopenharmony_ci		phys = le32_to_cpu(r->rxd_nrdadr) ;
66462306a36Sopenharmony_ci		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
66562306a36Sopenharmony_ci		r = r->rxd_next ;
66662306a36Sopenharmony_ci		rx_used-- ;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci	return phys;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci/*
67362306a36Sopenharmony_ci	-------------------------------------------------------------
67462306a36Sopenharmony_ci	INTERRUPT SERVICE ROUTINE:
67562306a36Sopenharmony_ci	-------------------------------------------------------------
67662306a36Sopenharmony_ci*/
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci/*
67962306a36Sopenharmony_ci *	BEGIN_MANUAL_ENTRY(fddi_isr)
68062306a36Sopenharmony_ci *	void fddi_isr(smc)
68162306a36Sopenharmony_ci *
68262306a36Sopenharmony_ci * function	DOWNCALL	(drvsr.c)
68362306a36Sopenharmony_ci *		interrupt service routine, handles the interrupt requests
68462306a36Sopenharmony_ci *		generated by the FDDI adapter.
68562306a36Sopenharmony_ci *
68662306a36Sopenharmony_ci * NOTE:	The operating system dependent module must guarantee that the
68762306a36Sopenharmony_ci *		interrupts of the adapter are disabled when it calls fddi_isr.
68862306a36Sopenharmony_ci *
68962306a36Sopenharmony_ci *	About the USE_BREAK_ISR mechanismn:
69062306a36Sopenharmony_ci *
69162306a36Sopenharmony_ci *	The main requirement of this mechanismn is to force an timer IRQ when
69262306a36Sopenharmony_ci *	leaving process_receive() with leave_isr set. process_receive() may
69362306a36Sopenharmony_ci *	be called at any time from anywhere!
69462306a36Sopenharmony_ci *	To be sure we don't miss such event we set 'force_irq' per default.
69562306a36Sopenharmony_ci *	We have to force and Timer IRQ if 'smc->os.hwm.leave_isr' AND
69662306a36Sopenharmony_ci *	'force_irq' are set. 'force_irq' may be reset if a receive complete
69762306a36Sopenharmony_ci *	IRQ is pending.
69862306a36Sopenharmony_ci *
69962306a36Sopenharmony_ci *	END_MANUAL_ENTRY
70062306a36Sopenharmony_ci */
70162306a36Sopenharmony_civoid fddi_isr(struct s_smc *smc)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci	u_long		is ;		/* ISR source */
70462306a36Sopenharmony_ci	u_short		stu, stl ;
70562306a36Sopenharmony_ci	SMbuf		*mb ;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci#ifdef	USE_BREAK_ISR
70862306a36Sopenharmony_ci	int	force_irq ;
70962306a36Sopenharmony_ci#endif
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci#ifdef	ODI2
71262306a36Sopenharmony_ci	if (smc->os.hwm.rx_break) {
71362306a36Sopenharmony_ci		mac_drv_fill_rxd(smc) ;
71462306a36Sopenharmony_ci		if (smc->hw.fp.rx_q[QUEUE_R1].rx_used > 0) {
71562306a36Sopenharmony_ci			smc->os.hwm.rx_break = 0 ;
71662306a36Sopenharmony_ci			process_receive(smc) ;
71762306a36Sopenharmony_ci		}
71862306a36Sopenharmony_ci		else {
71962306a36Sopenharmony_ci			smc->os.hwm.detec_count = 0 ;
72062306a36Sopenharmony_ci			smt_force_irq(smc) ;
72162306a36Sopenharmony_ci		}
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci#endif
72462306a36Sopenharmony_ci	smc->os.hwm.isr_flag = TRUE ;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci#ifdef	USE_BREAK_ISR
72762306a36Sopenharmony_ci	force_irq = TRUE ;
72862306a36Sopenharmony_ci	if (smc->os.hwm.leave_isr) {
72962306a36Sopenharmony_ci		smc->os.hwm.leave_isr = FALSE ;
73062306a36Sopenharmony_ci		process_receive(smc) ;
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci#endif
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	while ((is = GET_ISR() & ISR_MASK)) {
73562306a36Sopenharmony_ci		NDD_TRACE("CH0B",is,0,0) ;
73662306a36Sopenharmony_ci		DB_GEN(7, "ISA = 0x%lx", is);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci		if (is & IMASK_SLOW) {
73962306a36Sopenharmony_ci			NDD_TRACE("CH1b",is,0,0) ;
74062306a36Sopenharmony_ci			if (is & IS_PLINT1) {	/* PLC1 */
74162306a36Sopenharmony_ci				plc1_irq(smc) ;
74262306a36Sopenharmony_ci			}
74362306a36Sopenharmony_ci			if (is & IS_PLINT2) {	/* PLC2 */
74462306a36Sopenharmony_ci				plc2_irq(smc) ;
74562306a36Sopenharmony_ci			}
74662306a36Sopenharmony_ci			if (is & IS_MINTR1) {	/* FORMAC+ STU1(U/L) */
74762306a36Sopenharmony_ci				stu = inpw(FM_A(FM_ST1U)) ;
74862306a36Sopenharmony_ci				stl = inpw(FM_A(FM_ST1L)) ;
74962306a36Sopenharmony_ci				DB_GEN(6, "Slow transmit complete");
75062306a36Sopenharmony_ci				mac1_irq(smc,stu,stl) ;
75162306a36Sopenharmony_ci			}
75262306a36Sopenharmony_ci			if (is & IS_MINTR2) {	/* FORMAC+ STU2(U/L) */
75362306a36Sopenharmony_ci				stu= inpw(FM_A(FM_ST2U)) ;
75462306a36Sopenharmony_ci				stl= inpw(FM_A(FM_ST2L)) ;
75562306a36Sopenharmony_ci				DB_GEN(6, "Slow receive complete");
75662306a36Sopenharmony_ci				DB_GEN(7, "stl = %x : stu = %x", stl, stu);
75762306a36Sopenharmony_ci				mac2_irq(smc,stu,stl) ;
75862306a36Sopenharmony_ci			}
75962306a36Sopenharmony_ci			if (is & IS_MINTR3) {	/* FORMAC+ STU3(U/L) */
76062306a36Sopenharmony_ci				stu= inpw(FM_A(FM_ST3U)) ;
76162306a36Sopenharmony_ci				stl= inpw(FM_A(FM_ST3L)) ;
76262306a36Sopenharmony_ci				DB_GEN(6, "FORMAC Mode Register 3");
76362306a36Sopenharmony_ci				mac3_irq(smc,stu,stl) ;
76462306a36Sopenharmony_ci			}
76562306a36Sopenharmony_ci			if (is & IS_TIMINT) {	/* Timer 82C54-2 */
76662306a36Sopenharmony_ci				timer_irq(smc) ;
76762306a36Sopenharmony_ci#ifdef	NDIS_OS2
76862306a36Sopenharmony_ci				force_irq_pending = 0 ;
76962306a36Sopenharmony_ci#endif
77062306a36Sopenharmony_ci				/*
77162306a36Sopenharmony_ci				 * out of RxD detection
77262306a36Sopenharmony_ci				 */
77362306a36Sopenharmony_ci				if (++smc->os.hwm.detec_count > 4) {
77462306a36Sopenharmony_ci					/*
77562306a36Sopenharmony_ci					 * check out of RxD condition
77662306a36Sopenharmony_ci					 */
77762306a36Sopenharmony_ci					 process_receive(smc) ;
77862306a36Sopenharmony_ci				}
77962306a36Sopenharmony_ci			}
78062306a36Sopenharmony_ci			if (is & IS_TOKEN) {	/* Restricted Token Monitor */
78162306a36Sopenharmony_ci				rtm_irq(smc) ;
78262306a36Sopenharmony_ci			}
78362306a36Sopenharmony_ci			if (is & IS_R1_P) {	/* Parity error rx queue 1 */
78462306a36Sopenharmony_ci				/* clear IRQ */
78562306a36Sopenharmony_ci				outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_P) ;
78662306a36Sopenharmony_ci				SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ;
78762306a36Sopenharmony_ci			}
78862306a36Sopenharmony_ci			if (is & IS_R1_C) {	/* Encoding error rx queue 1 */
78962306a36Sopenharmony_ci				/* clear IRQ */
79062306a36Sopenharmony_ci				outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_C) ;
79162306a36Sopenharmony_ci				SMT_PANIC(smc,HWM_E0005,HWM_E0005_MSG) ;
79262306a36Sopenharmony_ci			}
79362306a36Sopenharmony_ci			if (is & IS_XA_C) {	/* Encoding error async tx q */
79462306a36Sopenharmony_ci				/* clear IRQ */
79562306a36Sopenharmony_ci				outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_C) ;
79662306a36Sopenharmony_ci				SMT_PANIC(smc,HWM_E0006,HWM_E0006_MSG) ;
79762306a36Sopenharmony_ci			}
79862306a36Sopenharmony_ci			if (is & IS_XS_C) {	/* Encoding error sync tx q */
79962306a36Sopenharmony_ci				/* clear IRQ */
80062306a36Sopenharmony_ci				outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_C) ;
80162306a36Sopenharmony_ci				SMT_PANIC(smc,HWM_E0007,HWM_E0007_MSG) ;
80262306a36Sopenharmony_ci			}
80362306a36Sopenharmony_ci		}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci		/*
80662306a36Sopenharmony_ci		 *	Fast Tx complete Async/Sync Queue (BMU service)
80762306a36Sopenharmony_ci		 */
80862306a36Sopenharmony_ci		if (is & (IS_XS_F|IS_XA_F)) {
80962306a36Sopenharmony_ci			DB_GEN(6, "Fast tx complete queue");
81062306a36Sopenharmony_ci			/*
81162306a36Sopenharmony_ci			 * clear IRQ, Note: no IRQ is lost, because
81262306a36Sopenharmony_ci			 * 	we always service both queues
81362306a36Sopenharmony_ci			 */
81462306a36Sopenharmony_ci			outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_F) ;
81562306a36Sopenharmony_ci			outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_F) ;
81662306a36Sopenharmony_ci			mac_drv_clear_txd(smc) ;
81762306a36Sopenharmony_ci			llc_restart_tx(smc) ;
81862306a36Sopenharmony_ci		}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci		/*
82162306a36Sopenharmony_ci		 *	Fast Rx Complete (BMU service)
82262306a36Sopenharmony_ci		 */
82362306a36Sopenharmony_ci		if (is & IS_R1_F) {
82462306a36Sopenharmony_ci			DB_GEN(6, "Fast receive complete");
82562306a36Sopenharmony_ci			/* clear IRQ */
82662306a36Sopenharmony_ci#ifndef USE_BREAK_ISR
82762306a36Sopenharmony_ci			outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ;
82862306a36Sopenharmony_ci			process_receive(smc) ;
82962306a36Sopenharmony_ci#else
83062306a36Sopenharmony_ci			process_receive(smc) ;
83162306a36Sopenharmony_ci			if (smc->os.hwm.leave_isr) {
83262306a36Sopenharmony_ci				force_irq = FALSE ;
83362306a36Sopenharmony_ci			} else {
83462306a36Sopenharmony_ci				outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ;
83562306a36Sopenharmony_ci				process_receive(smc) ;
83662306a36Sopenharmony_ci			}
83762306a36Sopenharmony_ci#endif
83862306a36Sopenharmony_ci		}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci#ifndef	NDIS_OS2
84162306a36Sopenharmony_ci		while ((mb = get_llc_rx(smc))) {
84262306a36Sopenharmony_ci			smt_to_llc(smc,mb) ;
84362306a36Sopenharmony_ci		}
84462306a36Sopenharmony_ci#else
84562306a36Sopenharmony_ci		if (offDepth)
84662306a36Sopenharmony_ci			post_proc() ;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci		while (!offDepth && (mb = get_llc_rx(smc))) {
84962306a36Sopenharmony_ci			smt_to_llc(smc,mb) ;
85062306a36Sopenharmony_ci		}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci		if (!offDepth && smc->os.hwm.rx_break) {
85362306a36Sopenharmony_ci			process_receive(smc) ;
85462306a36Sopenharmony_ci		}
85562306a36Sopenharmony_ci#endif
85662306a36Sopenharmony_ci		if (smc->q.ev_get != smc->q.ev_put) {
85762306a36Sopenharmony_ci			NDD_TRACE("CH2a",0,0,0) ;
85862306a36Sopenharmony_ci			ev_dispatcher(smc) ;
85962306a36Sopenharmony_ci		}
86062306a36Sopenharmony_ci#ifdef	NDIS_OS2
86162306a36Sopenharmony_ci		post_proc() ;
86262306a36Sopenharmony_ci		if (offDepth) {		/* leave fddi_isr because */
86362306a36Sopenharmony_ci			break ;		/* indications not allowed */
86462306a36Sopenharmony_ci		}
86562306a36Sopenharmony_ci#endif
86662306a36Sopenharmony_ci#ifdef	USE_BREAK_ISR
86762306a36Sopenharmony_ci		if (smc->os.hwm.leave_isr) {
86862306a36Sopenharmony_ci			break ;		/* leave fddi_isr */
86962306a36Sopenharmony_ci		}
87062306a36Sopenharmony_ci#endif
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci		/* NOTE: when the isr is left, no rx is pending */
87362306a36Sopenharmony_ci	}	/* end of interrupt source polling loop */
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci#ifdef	USE_BREAK_ISR
87662306a36Sopenharmony_ci	if (smc->os.hwm.leave_isr && force_irq) {
87762306a36Sopenharmony_ci		smt_force_irq(smc) ;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci#endif
88062306a36Sopenharmony_ci	smc->os.hwm.isr_flag = FALSE ;
88162306a36Sopenharmony_ci	NDD_TRACE("CH0E",0,0,0) ;
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci/*
88662306a36Sopenharmony_ci	-------------------------------------------------------------
88762306a36Sopenharmony_ci	RECEIVE FUNCTIONS:
88862306a36Sopenharmony_ci	-------------------------------------------------------------
88962306a36Sopenharmony_ci*/
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci#ifndef	NDIS_OS2
89262306a36Sopenharmony_ci/*
89362306a36Sopenharmony_ci *	BEGIN_MANUAL_ENTRY(mac_drv_rx_mode)
89462306a36Sopenharmony_ci *	void mac_drv_rx_mode(smc,mode)
89562306a36Sopenharmony_ci *
89662306a36Sopenharmony_ci * function	DOWNCALL	(fplus.c)
89762306a36Sopenharmony_ci *		Corresponding to the parameter mode, the operating system
89862306a36Sopenharmony_ci *		dependent module can activate several receive modes.
89962306a36Sopenharmony_ci *
90062306a36Sopenharmony_ci * para	mode	= 1:	RX_ENABLE_ALLMULTI	enable all multicasts
90162306a36Sopenharmony_ci *		= 2:	RX_DISABLE_ALLMULTI	disable "enable all multicasts"
90262306a36Sopenharmony_ci *		= 3:	RX_ENABLE_PROMISC	enable promiscuous
90362306a36Sopenharmony_ci *		= 4:	RX_DISABLE_PROMISC	disable promiscuous
90462306a36Sopenharmony_ci *		= 5:	RX_ENABLE_NSA		enable rec. of all NSA frames
90562306a36Sopenharmony_ci *			(disabled after 'driver reset' & 'set station address')
90662306a36Sopenharmony_ci *		= 6:	RX_DISABLE_NSA		disable rec. of all NSA frames
90762306a36Sopenharmony_ci *
90862306a36Sopenharmony_ci *		= 21:	RX_ENABLE_PASS_SMT	( see description )
90962306a36Sopenharmony_ci *		= 22:	RX_DISABLE_PASS_SMT	(  "	   "	  )
91062306a36Sopenharmony_ci *		= 23:	RX_ENABLE_PASS_NSA	(  "	   "	  )
91162306a36Sopenharmony_ci *		= 24:	RX_DISABLE_PASS_NSA	(  "	   "	  )
91262306a36Sopenharmony_ci *		= 25:	RX_ENABLE_PASS_DB	(  "	   "	  )
91362306a36Sopenharmony_ci *		= 26:	RX_DISABLE_PASS_DB	(  "	   "	  )
91462306a36Sopenharmony_ci *		= 27:	RX_DISABLE_PASS_ALL	(  "	   "	  )
91562306a36Sopenharmony_ci *		= 28:	RX_DISABLE_LLC_PROMISC	(  "	   "	  )
91662306a36Sopenharmony_ci *		= 29:	RX_ENABLE_LLC_PROMISC	(  "	   "	  )
91762306a36Sopenharmony_ci *
91862306a36Sopenharmony_ci *
91962306a36Sopenharmony_ci *		RX_ENABLE_PASS_SMT / RX_DISABLE_PASS_SMT
92062306a36Sopenharmony_ci *
92162306a36Sopenharmony_ci *		If the operating system dependent module activates the
92262306a36Sopenharmony_ci *		mode RX_ENABLE_PASS_SMT, the hardware module
92362306a36Sopenharmony_ci *		duplicates all SMT frames with the frame control
92462306a36Sopenharmony_ci *		FC_SMT_INFO and passes them to the LLC receive channel
92562306a36Sopenharmony_ci *		by calling mac_drv_rx_init.
92662306a36Sopenharmony_ci *		The SMT Frames which are sent by the local SMT and the NSA
92762306a36Sopenharmony_ci *		frames whose A- and C-Indicator is not set are also duplicated
92862306a36Sopenharmony_ci *		and passed.
92962306a36Sopenharmony_ci *		The receive mode RX_DISABLE_PASS_SMT disables the passing
93062306a36Sopenharmony_ci *		of SMT frames.
93162306a36Sopenharmony_ci *
93262306a36Sopenharmony_ci *		RX_ENABLE_PASS_NSA / RX_DISABLE_PASS_NSA
93362306a36Sopenharmony_ci *
93462306a36Sopenharmony_ci *		If the operating system dependent module activates the
93562306a36Sopenharmony_ci *		mode RX_ENABLE_PASS_NSA, the hardware module
93662306a36Sopenharmony_ci *		duplicates all NSA frames with frame control FC_SMT_NSA
93762306a36Sopenharmony_ci *		and a set A-Indicator and passed them to the LLC
93862306a36Sopenharmony_ci *		receive channel by calling mac_drv_rx_init.
93962306a36Sopenharmony_ci *		All NSA Frames which are sent by the local SMT
94062306a36Sopenharmony_ci *		are also duplicated and passed.
94162306a36Sopenharmony_ci *		The receive mode RX_DISABLE_PASS_NSA disables the passing
94262306a36Sopenharmony_ci *		of NSA frames with the A- or C-Indicator set.
94362306a36Sopenharmony_ci *
94462306a36Sopenharmony_ci * NOTE:	For fear that the hardware module receives NSA frames with
94562306a36Sopenharmony_ci *		a reset A-Indicator, the operating system dependent module
94662306a36Sopenharmony_ci *		has to call mac_drv_rx_mode with the mode RX_ENABLE_NSA
94762306a36Sopenharmony_ci *		before activate the RX_ENABLE_PASS_NSA mode and after every
94862306a36Sopenharmony_ci *		'driver reset' and 'set station address'.
94962306a36Sopenharmony_ci *
95062306a36Sopenharmony_ci *		RX_ENABLE_PASS_DB / RX_DISABLE_PASS_DB
95162306a36Sopenharmony_ci *
95262306a36Sopenharmony_ci *		If the operating system dependent module activates the
95362306a36Sopenharmony_ci *		mode RX_ENABLE_PASS_DB, direct BEACON frames
95462306a36Sopenharmony_ci *		(FC_BEACON frame control) are passed to the LLC receive
95562306a36Sopenharmony_ci *		channel by mac_drv_rx_init.
95662306a36Sopenharmony_ci *		The receive mode RX_DISABLE_PASS_DB disables the passing
95762306a36Sopenharmony_ci *		of direct BEACON frames.
95862306a36Sopenharmony_ci *
95962306a36Sopenharmony_ci *		RX_DISABLE_PASS_ALL
96062306a36Sopenharmony_ci *
96162306a36Sopenharmony_ci *		Disables all special receives modes. It is equal to
96262306a36Sopenharmony_ci *		call mac_drv_set_rx_mode successively with the
96362306a36Sopenharmony_ci *		parameters RX_DISABLE_NSA, RX_DISABLE_PASS_SMT,
96462306a36Sopenharmony_ci *		RX_DISABLE_PASS_NSA and RX_DISABLE_PASS_DB.
96562306a36Sopenharmony_ci *
96662306a36Sopenharmony_ci *		RX_ENABLE_LLC_PROMISC
96762306a36Sopenharmony_ci *
96862306a36Sopenharmony_ci *		(default) all received LLC frames and all SMT/NSA/DBEACON
96962306a36Sopenharmony_ci *		frames depending on the attitude of the flags
97062306a36Sopenharmony_ci *		PASS_SMT/PASS_NSA/PASS_DBEACON will be delivered to the
97162306a36Sopenharmony_ci *		LLC layer
97262306a36Sopenharmony_ci *
97362306a36Sopenharmony_ci *		RX_DISABLE_LLC_PROMISC
97462306a36Sopenharmony_ci *
97562306a36Sopenharmony_ci *		all received SMT/NSA/DBEACON frames depending on the
97662306a36Sopenharmony_ci *		attitude of the flags PASS_SMT/PASS_NSA/PASS_DBEACON
97762306a36Sopenharmony_ci *		will be delivered to the LLC layer.
97862306a36Sopenharmony_ci *		all received LLC frames with a directed address, Multicast
97962306a36Sopenharmony_ci *		or Broadcast address will be delivered to the LLC
98062306a36Sopenharmony_ci *		layer too.
98162306a36Sopenharmony_ci *
98262306a36Sopenharmony_ci *	END_MANUAL_ENTRY
98362306a36Sopenharmony_ci */
98462306a36Sopenharmony_civoid mac_drv_rx_mode(struct s_smc *smc, int mode)
98562306a36Sopenharmony_ci{
98662306a36Sopenharmony_ci	switch(mode) {
98762306a36Sopenharmony_ci	case RX_ENABLE_PASS_SMT:
98862306a36Sopenharmony_ci		smc->os.hwm.pass_SMT = TRUE ;
98962306a36Sopenharmony_ci		break ;
99062306a36Sopenharmony_ci	case RX_DISABLE_PASS_SMT:
99162306a36Sopenharmony_ci		smc->os.hwm.pass_SMT = FALSE ;
99262306a36Sopenharmony_ci		break ;
99362306a36Sopenharmony_ci	case RX_ENABLE_PASS_NSA:
99462306a36Sopenharmony_ci		smc->os.hwm.pass_NSA = TRUE ;
99562306a36Sopenharmony_ci		break ;
99662306a36Sopenharmony_ci	case RX_DISABLE_PASS_NSA:
99762306a36Sopenharmony_ci		smc->os.hwm.pass_NSA = FALSE ;
99862306a36Sopenharmony_ci		break ;
99962306a36Sopenharmony_ci	case RX_ENABLE_PASS_DB:
100062306a36Sopenharmony_ci		smc->os.hwm.pass_DB = TRUE ;
100162306a36Sopenharmony_ci		break ;
100262306a36Sopenharmony_ci	case RX_DISABLE_PASS_DB:
100362306a36Sopenharmony_ci		smc->os.hwm.pass_DB = FALSE ;
100462306a36Sopenharmony_ci		break ;
100562306a36Sopenharmony_ci	case RX_DISABLE_PASS_ALL:
100662306a36Sopenharmony_ci		smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = FALSE ;
100762306a36Sopenharmony_ci		smc->os.hwm.pass_DB = FALSE ;
100862306a36Sopenharmony_ci		smc->os.hwm.pass_llc_promisc = TRUE ;
100962306a36Sopenharmony_ci		mac_set_rx_mode(smc,RX_DISABLE_NSA) ;
101062306a36Sopenharmony_ci		break ;
101162306a36Sopenharmony_ci	case RX_DISABLE_LLC_PROMISC:
101262306a36Sopenharmony_ci		smc->os.hwm.pass_llc_promisc = FALSE ;
101362306a36Sopenharmony_ci		break ;
101462306a36Sopenharmony_ci	case RX_ENABLE_LLC_PROMISC:
101562306a36Sopenharmony_ci		smc->os.hwm.pass_llc_promisc = TRUE ;
101662306a36Sopenharmony_ci		break ;
101762306a36Sopenharmony_ci	case RX_ENABLE_ALLMULTI:
101862306a36Sopenharmony_ci	case RX_DISABLE_ALLMULTI:
101962306a36Sopenharmony_ci	case RX_ENABLE_PROMISC:
102062306a36Sopenharmony_ci	case RX_DISABLE_PROMISC:
102162306a36Sopenharmony_ci	case RX_ENABLE_NSA:
102262306a36Sopenharmony_ci	case RX_DISABLE_NSA:
102362306a36Sopenharmony_ci	default:
102462306a36Sopenharmony_ci		mac_set_rx_mode(smc,mode) ;
102562306a36Sopenharmony_ci		break ;
102662306a36Sopenharmony_ci	}
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci#endif	/* ifndef NDIS_OS2 */
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci/*
103162306a36Sopenharmony_ci * process receive queue
103262306a36Sopenharmony_ci */
103362306a36Sopenharmony_civoid process_receive(struct s_smc *smc)
103462306a36Sopenharmony_ci{
103562306a36Sopenharmony_ci	int i ;
103662306a36Sopenharmony_ci	int n ;
103762306a36Sopenharmony_ci	int frag_count ;		/* number of RxDs of the curr rx buf */
103862306a36Sopenharmony_ci	int used_frags ;		/* number of RxDs of the curr frame */
103962306a36Sopenharmony_ci	struct s_smt_rx_queue *queue ;	/* points to the queue ctl struct */
104062306a36Sopenharmony_ci	struct s_smt_fp_rxd volatile *r ;	/* rxd pointer */
104162306a36Sopenharmony_ci	struct s_smt_fp_rxd volatile *rxd ;	/* first rxd of rx frame */
104262306a36Sopenharmony_ci	u_long rbctrl ;			/* receive buffer control word */
104362306a36Sopenharmony_ci	u_long rfsw ;			/* receive frame status word */
104462306a36Sopenharmony_ci	u_short rx_used ;
104562306a36Sopenharmony_ci	u_char far *virt ;
104662306a36Sopenharmony_ci	char far *data ;
104762306a36Sopenharmony_ci	SMbuf *mb ;
104862306a36Sopenharmony_ci	u_char fc ;			/* Frame control */
104962306a36Sopenharmony_ci	int len ;			/* Frame length */
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	smc->os.hwm.detec_count = 0 ;
105262306a36Sopenharmony_ci	queue = smc->hw.fp.rx[QUEUE_R1] ;
105362306a36Sopenharmony_ci	NDD_TRACE("RHxB",0,0,0) ;
105462306a36Sopenharmony_ci	for ( ; ; ) {
105562306a36Sopenharmony_ci		r = queue->rx_curr_get ;
105662306a36Sopenharmony_ci		rx_used = queue->rx_used ;
105762306a36Sopenharmony_ci		frag_count = 0 ;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci#ifdef	USE_BREAK_ISR
106062306a36Sopenharmony_ci		if (smc->os.hwm.leave_isr) {
106162306a36Sopenharmony_ci			goto rx_end ;
106262306a36Sopenharmony_ci		}
106362306a36Sopenharmony_ci#endif
106462306a36Sopenharmony_ci#ifdef	NDIS_OS2
106562306a36Sopenharmony_ci		if (offDepth) {
106662306a36Sopenharmony_ci			smc->os.hwm.rx_break = 1 ;
106762306a36Sopenharmony_ci			goto rx_end ;
106862306a36Sopenharmony_ci		}
106962306a36Sopenharmony_ci		smc->os.hwm.rx_break = 0 ;
107062306a36Sopenharmony_ci#endif
107162306a36Sopenharmony_ci#ifdef	ODI2
107262306a36Sopenharmony_ci		if (smc->os.hwm.rx_break) {
107362306a36Sopenharmony_ci			goto rx_end ;
107462306a36Sopenharmony_ci		}
107562306a36Sopenharmony_ci#endif
107662306a36Sopenharmony_ci		n = 0 ;
107762306a36Sopenharmony_ci		do {
107862306a36Sopenharmony_ci			DB_RX(5, "Check RxD %p for OWN and EOF", r);
107962306a36Sopenharmony_ci			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
108062306a36Sopenharmony_ci			rbctrl = le32_to_cpu(CR_READ(r->rxd_rbctrl));
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci			if (rbctrl & BMU_OWN) {
108362306a36Sopenharmony_ci				NDD_TRACE("RHxE",r,rfsw,rbctrl) ;
108462306a36Sopenharmony_ci				DB_RX(4, "End of RxDs");
108562306a36Sopenharmony_ci				goto rx_end ;
108662306a36Sopenharmony_ci			}
108762306a36Sopenharmony_ci			/*
108862306a36Sopenharmony_ci			 * out of RxD detection
108962306a36Sopenharmony_ci			 */
109062306a36Sopenharmony_ci			if (!rx_used) {
109162306a36Sopenharmony_ci				SK_BREAK() ;
109262306a36Sopenharmony_ci				SMT_PANIC(smc,HWM_E0009,HWM_E0009_MSG) ;
109362306a36Sopenharmony_ci				/* Either we don't have an RxD or all
109462306a36Sopenharmony_ci				 * RxDs are filled. Therefore it's allowed
109562306a36Sopenharmony_ci				 * for to set the STOPPED flag */
109662306a36Sopenharmony_ci				smc->hw.hw_state = STOPPED ;
109762306a36Sopenharmony_ci				mac_drv_clear_rx_queue(smc) ;
109862306a36Sopenharmony_ci				smc->hw.hw_state = STARTED ;
109962306a36Sopenharmony_ci				mac_drv_fill_rxd(smc) ;
110062306a36Sopenharmony_ci				smc->os.hwm.detec_count = 0 ;
110162306a36Sopenharmony_ci				goto rx_end ;
110262306a36Sopenharmony_ci			}
110362306a36Sopenharmony_ci			rfsw = le32_to_cpu(r->rxd_rfsw) ;
110462306a36Sopenharmony_ci			if ((rbctrl & BMU_STF) != ((rbctrl & BMU_ST_BUF) <<5)) {
110562306a36Sopenharmony_ci				/*
110662306a36Sopenharmony_ci				 * The BMU_STF bit is deleted, 1 frame is
110762306a36Sopenharmony_ci				 * placed into more than 1 rx buffer
110862306a36Sopenharmony_ci				 *
110962306a36Sopenharmony_ci				 * skip frame by setting the rx len to 0
111062306a36Sopenharmony_ci				 *
111162306a36Sopenharmony_ci				 * if fragment count == 0
111262306a36Sopenharmony_ci				 *	The missing STF bit belongs to the
111362306a36Sopenharmony_ci				 *	current frame, search for the
111462306a36Sopenharmony_ci				 *	EOF bit to complete the frame
111562306a36Sopenharmony_ci				 * else
111662306a36Sopenharmony_ci				 *	the fragment belongs to the next frame,
111762306a36Sopenharmony_ci				 *	exit the loop and process the frame
111862306a36Sopenharmony_ci				 */
111962306a36Sopenharmony_ci				SK_BREAK() ;
112062306a36Sopenharmony_ci				rfsw = 0 ;
112162306a36Sopenharmony_ci				if (frag_count) {
112262306a36Sopenharmony_ci					break ;
112362306a36Sopenharmony_ci				}
112462306a36Sopenharmony_ci			}
112562306a36Sopenharmony_ci			n += rbctrl & 0xffff ;
112662306a36Sopenharmony_ci			r = r->rxd_next ;
112762306a36Sopenharmony_ci			frag_count++ ;
112862306a36Sopenharmony_ci			rx_used-- ;
112962306a36Sopenharmony_ci		} while (!(rbctrl & BMU_EOF)) ;
113062306a36Sopenharmony_ci		used_frags = frag_count ;
113162306a36Sopenharmony_ci		DB_RX(5, "EOF set in RxD, used_frags = %d", used_frags);
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci		/* may be next 2 DRV_BUF_FLUSH() can be skipped, because */
113462306a36Sopenharmony_ci		/* BMU_ST_BUF will not be changed by the ASIC */
113562306a36Sopenharmony_ci		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
113662306a36Sopenharmony_ci		while (rx_used && !(r->rxd_rbctrl & cpu_to_le32(BMU_ST_BUF))) {
113762306a36Sopenharmony_ci			DB_RX(5, "Check STF bit in %p", r);
113862306a36Sopenharmony_ci			r = r->rxd_next ;
113962306a36Sopenharmony_ci			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
114062306a36Sopenharmony_ci			frag_count++ ;
114162306a36Sopenharmony_ci			rx_used-- ;
114262306a36Sopenharmony_ci		}
114362306a36Sopenharmony_ci		DB_RX(5, "STF bit found");
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci		/*
114662306a36Sopenharmony_ci		 * The received frame is finished for the process receive
114762306a36Sopenharmony_ci		 */
114862306a36Sopenharmony_ci		rxd = queue->rx_curr_get ;
114962306a36Sopenharmony_ci		queue->rx_curr_get = r ;
115062306a36Sopenharmony_ci		queue->rx_free += frag_count ;
115162306a36Sopenharmony_ci		queue->rx_used = rx_used ;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci		/*
115462306a36Sopenharmony_ci		 * ASIC Errata no. 7 (STF - Bit Bug)
115562306a36Sopenharmony_ci		 */
115662306a36Sopenharmony_ci		rxd->rxd_rbctrl &= cpu_to_le32(~BMU_STF) ;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci		for (r=rxd, i=frag_count ; i ; r=r->rxd_next, i--){
115962306a36Sopenharmony_ci			DB_RX(5, "dma_complete for RxD %p", r);
116062306a36Sopenharmony_ci			dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR);
116162306a36Sopenharmony_ci		}
116262306a36Sopenharmony_ci		smc->hw.fp.err_stats.err_valid++ ;
116362306a36Sopenharmony_ci		smc->mib.m[MAC0].fddiMACCopied_Ct++ ;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci		/* the length of the data including the FC */
116662306a36Sopenharmony_ci		len = (rfsw & RD_LENGTH) - 4 ;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci		DB_RX(4, "frame length = %d", len);
116962306a36Sopenharmony_ci		/*
117062306a36Sopenharmony_ci		 * check the frame_length and all error flags
117162306a36Sopenharmony_ci		 */
117262306a36Sopenharmony_ci		if (rfsw & (RX_MSRABT|RX_FS_E|RX_FS_CRC|RX_FS_IMPL)){
117362306a36Sopenharmony_ci			if (rfsw & RD_S_MSRABT) {
117462306a36Sopenharmony_ci				DB_RX(2, "Frame aborted by the FORMAC");
117562306a36Sopenharmony_ci				smc->hw.fp.err_stats.err_abort++ ;
117662306a36Sopenharmony_ci			}
117762306a36Sopenharmony_ci			/*
117862306a36Sopenharmony_ci			 * check frame status
117962306a36Sopenharmony_ci			 */
118062306a36Sopenharmony_ci			if (rfsw & RD_S_SEAC2) {
118162306a36Sopenharmony_ci				DB_RX(2, "E-Indicator set");
118262306a36Sopenharmony_ci				smc->hw.fp.err_stats.err_e_indicator++ ;
118362306a36Sopenharmony_ci			}
118462306a36Sopenharmony_ci			if (rfsw & RD_S_SFRMERR) {
118562306a36Sopenharmony_ci				DB_RX(2, "CRC error");
118662306a36Sopenharmony_ci				smc->hw.fp.err_stats.err_crc++ ;
118762306a36Sopenharmony_ci			}
118862306a36Sopenharmony_ci			if (rfsw & RX_FS_IMPL) {
118962306a36Sopenharmony_ci				DB_RX(2, "Implementer frame");
119062306a36Sopenharmony_ci				smc->hw.fp.err_stats.err_imp_frame++ ;
119162306a36Sopenharmony_ci			}
119262306a36Sopenharmony_ci			goto abort_frame ;
119362306a36Sopenharmony_ci		}
119462306a36Sopenharmony_ci		if (len > FDDI_RAW_MTU-4) {
119562306a36Sopenharmony_ci			DB_RX(2, "Frame too long error");
119662306a36Sopenharmony_ci			smc->hw.fp.err_stats.err_too_long++ ;
119762306a36Sopenharmony_ci			goto abort_frame ;
119862306a36Sopenharmony_ci		}
119962306a36Sopenharmony_ci		/*
120062306a36Sopenharmony_ci		 * SUPERNET 3 Bug: FORMAC delivers status words
120162306a36Sopenharmony_ci		 * of aborted frames to the BMU
120262306a36Sopenharmony_ci		 */
120362306a36Sopenharmony_ci		if (len <= 4) {
120462306a36Sopenharmony_ci			DB_RX(2, "Frame length = 0");
120562306a36Sopenharmony_ci			goto abort_frame ;
120662306a36Sopenharmony_ci		}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci		if (len != (n-4)) {
120962306a36Sopenharmony_ci			DB_RX(4, "BMU: rx len differs: [%d:%d]", len, n);
121062306a36Sopenharmony_ci			smc->os.hwm.rx_len_error++ ;
121162306a36Sopenharmony_ci			goto abort_frame ;
121262306a36Sopenharmony_ci		}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci		/*
121562306a36Sopenharmony_ci		 * Check SA == MA
121662306a36Sopenharmony_ci		 */
121762306a36Sopenharmony_ci		virt = (u_char far *) rxd->rxd_virt ;
121862306a36Sopenharmony_ci		DB_RX(2, "FC = %x", *virt);
121962306a36Sopenharmony_ci		if (virt[12] == MA[5] &&
122062306a36Sopenharmony_ci		    virt[11] == MA[4] &&
122162306a36Sopenharmony_ci		    virt[10] == MA[3] &&
122262306a36Sopenharmony_ci		    virt[9] == MA[2] &&
122362306a36Sopenharmony_ci		    virt[8] == MA[1] &&
122462306a36Sopenharmony_ci		    (virt[7] & ~GROUP_ADDR_BIT) == MA[0]) {
122562306a36Sopenharmony_ci			goto abort_frame ;
122662306a36Sopenharmony_ci		}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci		/*
122962306a36Sopenharmony_ci		 * test if LLC frame
123062306a36Sopenharmony_ci		 */
123162306a36Sopenharmony_ci		if (rfsw & RX_FS_LLC) {
123262306a36Sopenharmony_ci			/*
123362306a36Sopenharmony_ci			 * if pass_llc_promisc is disable
123462306a36Sopenharmony_ci			 *	if DA != Multicast or Broadcast or DA!=MA
123562306a36Sopenharmony_ci			 *		abort the frame
123662306a36Sopenharmony_ci			 */
123762306a36Sopenharmony_ci			if (!smc->os.hwm.pass_llc_promisc) {
123862306a36Sopenharmony_ci				if(!(virt[1] & GROUP_ADDR_BIT)) {
123962306a36Sopenharmony_ci					if (virt[6] != MA[5] ||
124062306a36Sopenharmony_ci					    virt[5] != MA[4] ||
124162306a36Sopenharmony_ci					    virt[4] != MA[3] ||
124262306a36Sopenharmony_ci					    virt[3] != MA[2] ||
124362306a36Sopenharmony_ci					    virt[2] != MA[1] ||
124462306a36Sopenharmony_ci					    virt[1] != MA[0]) {
124562306a36Sopenharmony_ci						DB_RX(2, "DA != MA and not multi- or broadcast");
124662306a36Sopenharmony_ci						goto abort_frame ;
124762306a36Sopenharmony_ci					}
124862306a36Sopenharmony_ci				}
124962306a36Sopenharmony_ci			}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci			/*
125262306a36Sopenharmony_ci			 * LLC frame received
125362306a36Sopenharmony_ci			 */
125462306a36Sopenharmony_ci			DB_RX(4, "LLC - receive");
125562306a36Sopenharmony_ci			mac_drv_rx_complete(smc,rxd,frag_count,len) ;
125662306a36Sopenharmony_ci		}
125762306a36Sopenharmony_ci		else {
125862306a36Sopenharmony_ci			if (!(mb = smt_get_mbuf(smc))) {
125962306a36Sopenharmony_ci				smc->hw.fp.err_stats.err_no_buf++ ;
126062306a36Sopenharmony_ci				DB_RX(4, "No SMbuf; receive terminated");
126162306a36Sopenharmony_ci				goto abort_frame ;
126262306a36Sopenharmony_ci			}
126362306a36Sopenharmony_ci			data = smtod(mb,char *) - 1 ;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci			/*
126662306a36Sopenharmony_ci			 * copy the frame into a SMT_MBuf
126762306a36Sopenharmony_ci			 */
126862306a36Sopenharmony_ci#ifdef USE_OS_CPY
126962306a36Sopenharmony_ci			hwm_cpy_rxd2mb(rxd,data,len) ;
127062306a36Sopenharmony_ci#else
127162306a36Sopenharmony_ci			for (r=rxd, i=used_frags ; i ; r=r->rxd_next, i--){
127262306a36Sopenharmony_ci				n = le32_to_cpu(r->rxd_rbctrl) & RD_LENGTH ;
127362306a36Sopenharmony_ci				DB_RX(6, "cp SMT frame to mb: len = %d", n);
127462306a36Sopenharmony_ci				memcpy(data,r->rxd_virt,n) ;
127562306a36Sopenharmony_ci				data += n ;
127662306a36Sopenharmony_ci			}
127762306a36Sopenharmony_ci			data = smtod(mb,char *) - 1 ;
127862306a36Sopenharmony_ci#endif
127962306a36Sopenharmony_ci			fc = *(char *)mb->sm_data = *data ;
128062306a36Sopenharmony_ci			mb->sm_len = len - 1 ;		/* len - fc */
128162306a36Sopenharmony_ci			data++ ;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci			/*
128462306a36Sopenharmony_ci			 * SMT frame received
128562306a36Sopenharmony_ci			 */
128662306a36Sopenharmony_ci			switch(fc) {
128762306a36Sopenharmony_ci			case FC_SMT_INFO :
128862306a36Sopenharmony_ci				smc->hw.fp.err_stats.err_smt_frame++ ;
128962306a36Sopenharmony_ci				DB_RX(5, "SMT frame received");
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci				if (smc->os.hwm.pass_SMT) {
129262306a36Sopenharmony_ci					DB_RX(5, "pass SMT frame");
129362306a36Sopenharmony_ci					mac_drv_rx_complete(smc, rxd,
129462306a36Sopenharmony_ci						frag_count,len) ;
129562306a36Sopenharmony_ci				}
129662306a36Sopenharmony_ci				else {
129762306a36Sopenharmony_ci					DB_RX(5, "requeue RxD");
129862306a36Sopenharmony_ci					mac_drv_requeue_rxd(smc,rxd,frag_count);
129962306a36Sopenharmony_ci				}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci				smt_received_pack(smc,mb,(int)(rfsw>>25)) ;
130262306a36Sopenharmony_ci				break ;
130362306a36Sopenharmony_ci			case FC_SMT_NSA :
130462306a36Sopenharmony_ci				smc->hw.fp.err_stats.err_smt_frame++ ;
130562306a36Sopenharmony_ci				DB_RX(5, "SMT frame received");
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci				/* if pass_NSA set pass the NSA frame or */
130862306a36Sopenharmony_ci				/* pass_SMT set and the A-Indicator */
130962306a36Sopenharmony_ci				/* is not set, pass the NSA frame */
131062306a36Sopenharmony_ci				if (smc->os.hwm.pass_NSA ||
131162306a36Sopenharmony_ci					(smc->os.hwm.pass_SMT &&
131262306a36Sopenharmony_ci					!(rfsw & A_INDIC))) {
131362306a36Sopenharmony_ci					DB_RX(5, "pass SMT frame");
131462306a36Sopenharmony_ci					mac_drv_rx_complete(smc, rxd,
131562306a36Sopenharmony_ci						frag_count,len) ;
131662306a36Sopenharmony_ci				}
131762306a36Sopenharmony_ci				else {
131862306a36Sopenharmony_ci					DB_RX(5, "requeue RxD");
131962306a36Sopenharmony_ci					mac_drv_requeue_rxd(smc,rxd,frag_count);
132062306a36Sopenharmony_ci				}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci				smt_received_pack(smc,mb,(int)(rfsw>>25)) ;
132362306a36Sopenharmony_ci				break ;
132462306a36Sopenharmony_ci			case FC_BEACON :
132562306a36Sopenharmony_ci				if (smc->os.hwm.pass_DB) {
132662306a36Sopenharmony_ci					DB_RX(5, "pass DB frame");
132762306a36Sopenharmony_ci					mac_drv_rx_complete(smc, rxd,
132862306a36Sopenharmony_ci						frag_count,len) ;
132962306a36Sopenharmony_ci				}
133062306a36Sopenharmony_ci				else {
133162306a36Sopenharmony_ci					DB_RX(5, "requeue RxD");
133262306a36Sopenharmony_ci					mac_drv_requeue_rxd(smc,rxd,frag_count);
133362306a36Sopenharmony_ci				}
133462306a36Sopenharmony_ci				smt_free_mbuf(smc,mb) ;
133562306a36Sopenharmony_ci				break ;
133662306a36Sopenharmony_ci			default :
133762306a36Sopenharmony_ci				/*
133862306a36Sopenharmony_ci				 * unknown FC abort the frame
133962306a36Sopenharmony_ci				 */
134062306a36Sopenharmony_ci				DB_RX(2, "unknown FC error");
134162306a36Sopenharmony_ci				smt_free_mbuf(smc,mb) ;
134262306a36Sopenharmony_ci				DB_RX(5, "requeue RxD");
134362306a36Sopenharmony_ci				mac_drv_requeue_rxd(smc,rxd,frag_count) ;
134462306a36Sopenharmony_ci				if ((fc & 0xf0) == FC_MAC)
134562306a36Sopenharmony_ci					smc->hw.fp.err_stats.err_mac_frame++ ;
134662306a36Sopenharmony_ci				else
134762306a36Sopenharmony_ci					smc->hw.fp.err_stats.err_imp_frame++ ;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci				break ;
135062306a36Sopenharmony_ci			}
135162306a36Sopenharmony_ci		}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci		DB_RX(3, "next RxD is %p", queue->rx_curr_get);
135462306a36Sopenharmony_ci		NDD_TRACE("RHx1",queue->rx_curr_get,0,0) ;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci		continue ;
135762306a36Sopenharmony_ci	/*--------------------------------------------------------------------*/
135862306a36Sopenharmony_ciabort_frame:
135962306a36Sopenharmony_ci		DB_RX(5, "requeue RxD");
136062306a36Sopenharmony_ci		mac_drv_requeue_rxd(smc,rxd,frag_count) ;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci		DB_RX(3, "next RxD is %p", queue->rx_curr_get);
136362306a36Sopenharmony_ci		NDD_TRACE("RHx2",queue->rx_curr_get,0,0) ;
136462306a36Sopenharmony_ci	}
136562306a36Sopenharmony_cirx_end:
136662306a36Sopenharmony_ci#ifdef	ALL_RX_COMPLETE
136762306a36Sopenharmony_ci	mac_drv_all_receives_complete(smc) ;
136862306a36Sopenharmony_ci#endif
136962306a36Sopenharmony_ci	return ;	/* lint bug: needs return detect end of function */
137062306a36Sopenharmony_ci}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_cistatic void smt_to_llc(struct s_smc *smc, SMbuf *mb)
137362306a36Sopenharmony_ci{
137462306a36Sopenharmony_ci	u_char	fc ;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	DB_RX(4, "send a queued frame to the llc layer");
137762306a36Sopenharmony_ci	smc->os.hwm.r.len = mb->sm_len ;
137862306a36Sopenharmony_ci	smc->os.hwm.r.mb_pos = smtod(mb,char *) ;
137962306a36Sopenharmony_ci	fc = *smc->os.hwm.r.mb_pos ;
138062306a36Sopenharmony_ci	(void)mac_drv_rx_init(smc,(int)mb->sm_len,(int)fc,
138162306a36Sopenharmony_ci		smc->os.hwm.r.mb_pos,(int)mb->sm_len) ;
138262306a36Sopenharmony_ci	smt_free_mbuf(smc,mb) ;
138362306a36Sopenharmony_ci}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci/*
138662306a36Sopenharmony_ci *	BEGIN_MANUAL_ENTRY(hwm_rx_frag)
138762306a36Sopenharmony_ci *	void hwm_rx_frag(smc,virt,phys,len,frame_status)
138862306a36Sopenharmony_ci *
138962306a36Sopenharmony_ci * function	MACRO		(hardware module, hwmtm.h)
139062306a36Sopenharmony_ci *		This function calls dma_master for preparing the
139162306a36Sopenharmony_ci *		system hardware for the DMA transfer and initializes
139262306a36Sopenharmony_ci *		the current RxD with the length and the physical and
139362306a36Sopenharmony_ci *		virtual address of the fragment. Furthermore, it sets the
139462306a36Sopenharmony_ci *		STF and EOF bits depending on the frame status byte,
139562306a36Sopenharmony_ci *		switches the OWN flag of the RxD, so that it is owned by the
139662306a36Sopenharmony_ci *		adapter and issues an rx_start.
139762306a36Sopenharmony_ci *
139862306a36Sopenharmony_ci * para	virt	virtual pointer to the fragment
139962306a36Sopenharmony_ci *	len	the length of the fragment
140062306a36Sopenharmony_ci *	frame_status	status of the frame, see design description
140162306a36Sopenharmony_ci *
140262306a36Sopenharmony_ci * NOTE:	It is possible to call this function with a fragment length
140362306a36Sopenharmony_ci *		of zero.
140462306a36Sopenharmony_ci *
140562306a36Sopenharmony_ci *	END_MANUAL_ENTRY
140662306a36Sopenharmony_ci */
140762306a36Sopenharmony_civoid hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
140862306a36Sopenharmony_ci		 int frame_status)
140962306a36Sopenharmony_ci{
141062306a36Sopenharmony_ci	struct s_smt_fp_rxd volatile *r ;
141162306a36Sopenharmony_ci	__le32	rbctrl;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	NDD_TRACE("RHfB",virt,len,frame_status) ;
141462306a36Sopenharmony_ci	DB_RX(2, "hwm_rx_frag: len = %d, frame_status = %x", len, frame_status);
141562306a36Sopenharmony_ci	r = smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put ;
141662306a36Sopenharmony_ci	r->rxd_virt = virt ;
141762306a36Sopenharmony_ci	r->rxd_rbadr = cpu_to_le32(phys) ;
141862306a36Sopenharmony_ci	rbctrl = cpu_to_le32( (((__u32)frame_status &
141962306a36Sopenharmony_ci		(FIRST_FRAG|LAST_FRAG))<<26) |
142062306a36Sopenharmony_ci		(((u_long) frame_status & FIRST_FRAG) << 21) |
142162306a36Sopenharmony_ci		BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len) ;
142262306a36Sopenharmony_ci	r->rxd_rbctrl = rbctrl ;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
142562306a36Sopenharmony_ci	outpd(ADDR(B0_R1_CSR),CSR_START) ;
142662306a36Sopenharmony_ci	smc->hw.fp.rx_q[QUEUE_R1].rx_free-- ;
142762306a36Sopenharmony_ci	smc->hw.fp.rx_q[QUEUE_R1].rx_used++ ;
142862306a36Sopenharmony_ci	smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put = r->rxd_next ;
142962306a36Sopenharmony_ci	NDD_TRACE("RHfE",r,le32_to_cpu(r->rxd_rbadr),0) ;
143062306a36Sopenharmony_ci}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci/*
143362306a36Sopenharmony_ci *	BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue)
143462306a36Sopenharmony_ci *
143562306a36Sopenharmony_ci * void mac_drv_clear_rx_queue(smc)
143662306a36Sopenharmony_ci * struct s_smc *smc ;
143762306a36Sopenharmony_ci *
143862306a36Sopenharmony_ci * function	DOWNCALL	(hardware module, hwmtm.c)
143962306a36Sopenharmony_ci *		mac_drv_clear_rx_queue is called by the OS-specific module
144062306a36Sopenharmony_ci *		after it has issued a card_stop.
144162306a36Sopenharmony_ci *		In this case, the frames in the receive queue are obsolete and
144262306a36Sopenharmony_ci *		should be removed. For removing mac_drv_clear_rx_queue
144362306a36Sopenharmony_ci *		calls dma_master for each RxD and mac_drv_clear_rxd for each
144462306a36Sopenharmony_ci *		receive buffer.
144562306a36Sopenharmony_ci *
144662306a36Sopenharmony_ci * NOTE:	calling sequence card_stop:
144762306a36Sopenharmony_ci *		CLI_FBI(), card_stop(),
144862306a36Sopenharmony_ci *		mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(),
144962306a36Sopenharmony_ci *
145062306a36Sopenharmony_ci * NOTE:	The caller is responsible that the BMUs are idle
145162306a36Sopenharmony_ci *		when this function is called.
145262306a36Sopenharmony_ci *
145362306a36Sopenharmony_ci *	END_MANUAL_ENTRY
145462306a36Sopenharmony_ci */
145562306a36Sopenharmony_civoid mac_drv_clear_rx_queue(struct s_smc *smc)
145662306a36Sopenharmony_ci{
145762306a36Sopenharmony_ci	struct s_smt_fp_rxd volatile *r ;
145862306a36Sopenharmony_ci	struct s_smt_fp_rxd volatile *next_rxd ;
145962306a36Sopenharmony_ci	struct s_smt_rx_queue *queue ;
146062306a36Sopenharmony_ci	int frag_count ;
146162306a36Sopenharmony_ci	int i ;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	if (smc->hw.hw_state != STOPPED) {
146462306a36Sopenharmony_ci		SK_BREAK() ;
146562306a36Sopenharmony_ci		SMT_PANIC(smc,HWM_E0012,HWM_E0012_MSG) ;
146662306a36Sopenharmony_ci		return ;
146762306a36Sopenharmony_ci	}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	queue = smc->hw.fp.rx[QUEUE_R1] ;
147062306a36Sopenharmony_ci	DB_RX(5, "clear_rx_queue");
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	/*
147362306a36Sopenharmony_ci	 * dma_complete and mac_drv_clear_rxd for all RxDs / receive buffers
147462306a36Sopenharmony_ci	 */
147562306a36Sopenharmony_ci	r = queue->rx_curr_get ;
147662306a36Sopenharmony_ci	while (queue->rx_used) {
147762306a36Sopenharmony_ci		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
147862306a36Sopenharmony_ci		DB_RX(5, "switch OWN bit of RxD 0x%p", r);
147962306a36Sopenharmony_ci		r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ;
148062306a36Sopenharmony_ci		frag_count = 1 ;
148162306a36Sopenharmony_ci		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
148262306a36Sopenharmony_ci		r = r->rxd_next ;
148362306a36Sopenharmony_ci		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
148462306a36Sopenharmony_ci		while (r != queue->rx_curr_put &&
148562306a36Sopenharmony_ci			!(r->rxd_rbctrl & cpu_to_le32(BMU_ST_BUF))) {
148662306a36Sopenharmony_ci			DB_RX(5, "Check STF bit in %p", r);
148762306a36Sopenharmony_ci			r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ;
148862306a36Sopenharmony_ci			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
148962306a36Sopenharmony_ci			r = r->rxd_next ;
149062306a36Sopenharmony_ci			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
149162306a36Sopenharmony_ci			frag_count++ ;
149262306a36Sopenharmony_ci		}
149362306a36Sopenharmony_ci		DB_RX(5, "STF bit found");
149462306a36Sopenharmony_ci		next_rxd = r ;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci		for (r=queue->rx_curr_get,i=frag_count; i ; r=r->rxd_next,i--){
149762306a36Sopenharmony_ci			DB_RX(5, "dma_complete for RxD %p", r);
149862306a36Sopenharmony_ci			dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR);
149962306a36Sopenharmony_ci		}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci		DB_RX(5, "mac_drv_clear_rxd: RxD %p frag_count %d",
150262306a36Sopenharmony_ci		      queue->rx_curr_get, frag_count);
150362306a36Sopenharmony_ci		mac_drv_clear_rxd(smc,queue->rx_curr_get,frag_count) ;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci		queue->rx_curr_get = next_rxd ;
150662306a36Sopenharmony_ci		queue->rx_used -= frag_count ;
150762306a36Sopenharmony_ci		queue->rx_free += frag_count ;
150862306a36Sopenharmony_ci	}
150962306a36Sopenharmony_ci}
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci/*
151362306a36Sopenharmony_ci	-------------------------------------------------------------
151462306a36Sopenharmony_ci	SEND FUNCTIONS:
151562306a36Sopenharmony_ci	-------------------------------------------------------------
151662306a36Sopenharmony_ci*/
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci/*
151962306a36Sopenharmony_ci *	BEGIN_MANUAL_ENTRY(hwm_tx_init)
152062306a36Sopenharmony_ci *	int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status)
152162306a36Sopenharmony_ci *
152262306a36Sopenharmony_ci * function	DOWN_CALL	(hardware module, hwmtm.c)
152362306a36Sopenharmony_ci *		hwm_tx_init checks if the frame can be sent through the
152462306a36Sopenharmony_ci *		corresponding send queue.
152562306a36Sopenharmony_ci *
152662306a36Sopenharmony_ci * para	fc	the frame control. To determine through which
152762306a36Sopenharmony_ci *		send queue the frame should be transmitted.
152862306a36Sopenharmony_ci *		0x50 - 0x57:	asynchronous LLC frame
152962306a36Sopenharmony_ci *		0xD0 - 0xD7:	synchronous LLC frame
153062306a36Sopenharmony_ci *		0x41, 0x4F:	SMT frame to the network
153162306a36Sopenharmony_ci *		0x42:		SMT frame to the network and to the local SMT
153262306a36Sopenharmony_ci *		0x43:		SMT frame to the local SMT
153362306a36Sopenharmony_ci *	frag_count	count of the fragments for this frame
153462306a36Sopenharmony_ci *	frame_len	length of the frame
153562306a36Sopenharmony_ci *	frame_status	status of the frame, the send queue bit is already
153662306a36Sopenharmony_ci *			specified
153762306a36Sopenharmony_ci *
153862306a36Sopenharmony_ci * return		frame_status
153962306a36Sopenharmony_ci *
154062306a36Sopenharmony_ci *	END_MANUAL_ENTRY
154162306a36Sopenharmony_ci */
154262306a36Sopenharmony_ciint hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len,
154362306a36Sopenharmony_ci		int frame_status)
154462306a36Sopenharmony_ci{
154562306a36Sopenharmony_ci	NDD_TRACE("THiB",fc,frag_count,frame_len) ;
154662306a36Sopenharmony_ci	smc->os.hwm.tx_p = smc->hw.fp.tx[frame_status & QUEUE_A0] ;
154762306a36Sopenharmony_ci	smc->os.hwm.tx_descr = TX_DESCRIPTOR | (((u_long)(frame_len-1)&3)<<27) ;
154862306a36Sopenharmony_ci	smc->os.hwm.tx_len = frame_len ;
154962306a36Sopenharmony_ci	DB_TX(3, "hwm_tx_init: fc = %x, len = %d", fc, frame_len);
155062306a36Sopenharmony_ci	if ((fc & ~(FC_SYNC_BIT|FC_LLC_PRIOR)) == FC_ASYNC_LLC) {
155162306a36Sopenharmony_ci		frame_status |= LAN_TX ;
155262306a36Sopenharmony_ci	}
155362306a36Sopenharmony_ci	else {
155462306a36Sopenharmony_ci		switch (fc) {
155562306a36Sopenharmony_ci		case FC_SMT_INFO :
155662306a36Sopenharmony_ci		case FC_SMT_NSA :
155762306a36Sopenharmony_ci			frame_status |= LAN_TX ;
155862306a36Sopenharmony_ci			break ;
155962306a36Sopenharmony_ci		case FC_SMT_LOC :
156062306a36Sopenharmony_ci			frame_status |= LOC_TX ;
156162306a36Sopenharmony_ci			break ;
156262306a36Sopenharmony_ci		case FC_SMT_LAN_LOC :
156362306a36Sopenharmony_ci			frame_status |= LAN_TX | LOC_TX ;
156462306a36Sopenharmony_ci			break ;
156562306a36Sopenharmony_ci		default :
156662306a36Sopenharmony_ci			SMT_PANIC(smc,HWM_E0010,HWM_E0010_MSG) ;
156762306a36Sopenharmony_ci		}
156862306a36Sopenharmony_ci	}
156962306a36Sopenharmony_ci	if (!smc->hw.mac_ring_is_up) {
157062306a36Sopenharmony_ci		frame_status &= ~LAN_TX ;
157162306a36Sopenharmony_ci		frame_status |= RING_DOWN ;
157262306a36Sopenharmony_ci		DB_TX(2, "Ring is down: terminate LAN_TX");
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci	if (frag_count > smc->os.hwm.tx_p->tx_free) {
157562306a36Sopenharmony_ci#ifndef	NDIS_OS2
157662306a36Sopenharmony_ci		mac_drv_clear_txd(smc) ;
157762306a36Sopenharmony_ci		if (frag_count > smc->os.hwm.tx_p->tx_free) {
157862306a36Sopenharmony_ci			DB_TX(2, "Out of TxDs, terminate LAN_TX");
157962306a36Sopenharmony_ci			frame_status &= ~LAN_TX ;
158062306a36Sopenharmony_ci			frame_status |= OUT_OF_TXD ;
158162306a36Sopenharmony_ci		}
158262306a36Sopenharmony_ci#else
158362306a36Sopenharmony_ci		DB_TX(2, "Out of TxDs, terminate LAN_TX");
158462306a36Sopenharmony_ci		frame_status &= ~LAN_TX ;
158562306a36Sopenharmony_ci		frame_status |= OUT_OF_TXD ;
158662306a36Sopenharmony_ci#endif
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci	DB_TX(3, "frame_status = %x", frame_status);
158962306a36Sopenharmony_ci	NDD_TRACE("THiE",frame_status,smc->os.hwm.tx_p->tx_free,0) ;
159062306a36Sopenharmony_ci	return frame_status;
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci/*
159462306a36Sopenharmony_ci *	BEGIN_MANUAL_ENTRY(hwm_tx_frag)
159562306a36Sopenharmony_ci *	void hwm_tx_frag(smc,virt,phys,len,frame_status)
159662306a36Sopenharmony_ci *
159762306a36Sopenharmony_ci * function	DOWNCALL	(hardware module, hwmtm.c)
159862306a36Sopenharmony_ci *		If the frame should be sent to the LAN, this function calls
159962306a36Sopenharmony_ci *		dma_master, fills the current TxD with the virtual and the
160062306a36Sopenharmony_ci *		physical address, sets the STF and EOF bits dependent on
160162306a36Sopenharmony_ci *		the frame status, and requests the BMU to start the
160262306a36Sopenharmony_ci *		transmit.
160362306a36Sopenharmony_ci *		If the frame should be sent to the local SMT, an SMT_MBuf
160462306a36Sopenharmony_ci *		is allocated if the FIRST_FRAG bit is set in the frame_status.
160562306a36Sopenharmony_ci *		The fragment of the frame is copied into the SMT MBuf.
160662306a36Sopenharmony_ci *		The function smt_received_pack is called if the LAST_FRAG
160762306a36Sopenharmony_ci *		bit is set in the frame_status word.
160862306a36Sopenharmony_ci *
160962306a36Sopenharmony_ci * para	virt	virtual pointer to the fragment
161062306a36Sopenharmony_ci *	len	the length of the fragment
161162306a36Sopenharmony_ci *	frame_status	status of the frame, see design description
161262306a36Sopenharmony_ci *
161362306a36Sopenharmony_ci * return	nothing returned, no parameter is modified
161462306a36Sopenharmony_ci *
161562306a36Sopenharmony_ci * NOTE:	It is possible to invoke this macro with a fragment length
161662306a36Sopenharmony_ci *		of zero.
161762306a36Sopenharmony_ci *
161862306a36Sopenharmony_ci *	END_MANUAL_ENTRY
161962306a36Sopenharmony_ci */
162062306a36Sopenharmony_civoid hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
162162306a36Sopenharmony_ci		 int frame_status)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	struct s_smt_fp_txd volatile *t ;
162462306a36Sopenharmony_ci	struct s_smt_tx_queue *queue ;
162562306a36Sopenharmony_ci	__le32	tbctrl ;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	queue = smc->os.hwm.tx_p ;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	NDD_TRACE("THfB",virt,len,frame_status) ;
163062306a36Sopenharmony_ci	/* Bug fix: AF / May 31 1999 (#missing)
163162306a36Sopenharmony_ci	 * snmpinfo problem reported by IBM is caused by invalid
163262306a36Sopenharmony_ci	 * t-pointer (txd) if LAN_TX is not set but LOC_TX only.
163362306a36Sopenharmony_ci	 * Set: t = queue->tx_curr_put  here !
163462306a36Sopenharmony_ci	 */
163562306a36Sopenharmony_ci	t = queue->tx_curr_put ;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	DB_TX(2, "hwm_tx_frag: len = %d, frame_status = %x", len, frame_status);
163862306a36Sopenharmony_ci	if (frame_status & LAN_TX) {
163962306a36Sopenharmony_ci		/* '*t' is already defined */
164062306a36Sopenharmony_ci		DB_TX(3, "LAN_TX: TxD = %p, virt = %p", t, virt);
164162306a36Sopenharmony_ci		t->txd_virt = virt ;
164262306a36Sopenharmony_ci		t->txd_txdscr = cpu_to_le32(smc->os.hwm.tx_descr) ;
164362306a36Sopenharmony_ci		t->txd_tbadr = cpu_to_le32(phys) ;
164462306a36Sopenharmony_ci		tbctrl = cpu_to_le32((((__u32)frame_status &
164562306a36Sopenharmony_ci			(FIRST_FRAG|LAST_FRAG|EN_IRQ_EOF))<< 26) |
164662306a36Sopenharmony_ci			BMU_OWN|BMU_CHECK |len) ;
164762306a36Sopenharmony_ci		t->txd_tbctrl = tbctrl ;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci#ifndef	AIX
165062306a36Sopenharmony_ci		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
165162306a36Sopenharmony_ci		outpd(queue->tx_bmu_ctl,CSR_START) ;
165262306a36Sopenharmony_ci#else	/* ifndef AIX */
165362306a36Sopenharmony_ci		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
165462306a36Sopenharmony_ci		if (frame_status & QUEUE_A0) {
165562306a36Sopenharmony_ci			outpd(ADDR(B0_XA_CSR),CSR_START) ;
165662306a36Sopenharmony_ci		}
165762306a36Sopenharmony_ci		else {
165862306a36Sopenharmony_ci			outpd(ADDR(B0_XS_CSR),CSR_START) ;
165962306a36Sopenharmony_ci		}
166062306a36Sopenharmony_ci#endif
166162306a36Sopenharmony_ci		queue->tx_free-- ;
166262306a36Sopenharmony_ci		queue->tx_used++ ;
166362306a36Sopenharmony_ci		queue->tx_curr_put = t->txd_next ;
166462306a36Sopenharmony_ci		if (frame_status & LAST_FRAG) {
166562306a36Sopenharmony_ci			smc->mib.m[MAC0].fddiMACTransmit_Ct++ ;
166662306a36Sopenharmony_ci		}
166762306a36Sopenharmony_ci	}
166862306a36Sopenharmony_ci	if (frame_status & LOC_TX) {
166962306a36Sopenharmony_ci		DB_TX(3, "LOC_TX:");
167062306a36Sopenharmony_ci		if (frame_status & FIRST_FRAG) {
167162306a36Sopenharmony_ci			if(!(smc->os.hwm.tx_mb = smt_get_mbuf(smc))) {
167262306a36Sopenharmony_ci				smc->hw.fp.err_stats.err_no_buf++ ;
167362306a36Sopenharmony_ci				DB_TX(4, "No SMbuf; transmit terminated");
167462306a36Sopenharmony_ci			}
167562306a36Sopenharmony_ci			else {
167662306a36Sopenharmony_ci				smc->os.hwm.tx_data =
167762306a36Sopenharmony_ci					smtod(smc->os.hwm.tx_mb,char *) - 1 ;
167862306a36Sopenharmony_ci#ifdef USE_OS_CPY
167962306a36Sopenharmony_ci#ifdef PASS_1ST_TXD_2_TX_COMP
168062306a36Sopenharmony_ci				hwm_cpy_txd2mb(t,smc->os.hwm.tx_data,
168162306a36Sopenharmony_ci					smc->os.hwm.tx_len) ;
168262306a36Sopenharmony_ci#endif
168362306a36Sopenharmony_ci#endif
168462306a36Sopenharmony_ci			}
168562306a36Sopenharmony_ci		}
168662306a36Sopenharmony_ci		if (smc->os.hwm.tx_mb) {
168762306a36Sopenharmony_ci#ifndef	USE_OS_CPY
168862306a36Sopenharmony_ci			DB_TX(3, "copy fragment into MBuf");
168962306a36Sopenharmony_ci			memcpy(smc->os.hwm.tx_data,virt,len) ;
169062306a36Sopenharmony_ci			smc->os.hwm.tx_data += len ;
169162306a36Sopenharmony_ci#endif
169262306a36Sopenharmony_ci			if (frame_status & LAST_FRAG) {
169362306a36Sopenharmony_ci#ifdef	USE_OS_CPY
169462306a36Sopenharmony_ci#ifndef PASS_1ST_TXD_2_TX_COMP
169562306a36Sopenharmony_ci				/*
169662306a36Sopenharmony_ci				 * hwm_cpy_txd2mb(txd,data,len) copies 'len'
169762306a36Sopenharmony_ci				 * bytes from the virtual pointer in 'rxd'
169862306a36Sopenharmony_ci				 * to 'data'. The virtual pointer of the
169962306a36Sopenharmony_ci				 * os-specific tx-buffer should be written
170062306a36Sopenharmony_ci				 * in the LAST txd.
170162306a36Sopenharmony_ci				 */
170262306a36Sopenharmony_ci				hwm_cpy_txd2mb(t,smc->os.hwm.tx_data,
170362306a36Sopenharmony_ci					smc->os.hwm.tx_len) ;
170462306a36Sopenharmony_ci#endif	/* nPASS_1ST_TXD_2_TX_COMP */
170562306a36Sopenharmony_ci#endif	/* USE_OS_CPY */
170662306a36Sopenharmony_ci				smc->os.hwm.tx_data =
170762306a36Sopenharmony_ci					smtod(smc->os.hwm.tx_mb,char *) - 1 ;
170862306a36Sopenharmony_ci				*(char *)smc->os.hwm.tx_mb->sm_data =
170962306a36Sopenharmony_ci					*smc->os.hwm.tx_data ;
171062306a36Sopenharmony_ci				smc->os.hwm.tx_data++ ;
171162306a36Sopenharmony_ci				smc->os.hwm.tx_mb->sm_len =
171262306a36Sopenharmony_ci					smc->os.hwm.tx_len - 1 ;
171362306a36Sopenharmony_ci				DB_TX(3, "pass LLC frame to SMT");
171462306a36Sopenharmony_ci				smt_received_pack(smc,smc->os.hwm.tx_mb,
171562306a36Sopenharmony_ci						RD_FS_LOCAL) ;
171662306a36Sopenharmony_ci			}
171762306a36Sopenharmony_ci		}
171862306a36Sopenharmony_ci	}
171962306a36Sopenharmony_ci	NDD_TRACE("THfE",t,queue->tx_free,0) ;
172062306a36Sopenharmony_ci}
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci/*
172462306a36Sopenharmony_ci * queues a receive for later send
172562306a36Sopenharmony_ci */
172662306a36Sopenharmony_cistatic void queue_llc_rx(struct s_smc *smc, SMbuf *mb)
172762306a36Sopenharmony_ci{
172862306a36Sopenharmony_ci	DB_GEN(4, "queue_llc_rx: mb = %p", mb);
172962306a36Sopenharmony_ci	smc->os.hwm.queued_rx_frames++ ;
173062306a36Sopenharmony_ci	mb->sm_next = (SMbuf *)NULL ;
173162306a36Sopenharmony_ci	if (smc->os.hwm.llc_rx_pipe == NULL) {
173262306a36Sopenharmony_ci		smc->os.hwm.llc_rx_pipe = mb ;
173362306a36Sopenharmony_ci	}
173462306a36Sopenharmony_ci	else {
173562306a36Sopenharmony_ci		smc->os.hwm.llc_rx_tail->sm_next = mb ;
173662306a36Sopenharmony_ci	}
173762306a36Sopenharmony_ci	smc->os.hwm.llc_rx_tail = mb ;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	/*
174062306a36Sopenharmony_ci	 * force an timer IRQ to receive the data
174162306a36Sopenharmony_ci	 */
174262306a36Sopenharmony_ci	if (!smc->os.hwm.isr_flag) {
174362306a36Sopenharmony_ci		smt_force_irq(smc) ;
174462306a36Sopenharmony_ci	}
174562306a36Sopenharmony_ci}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci/*
174862306a36Sopenharmony_ci * get a SMbuf from the llc_rx_queue
174962306a36Sopenharmony_ci */
175062306a36Sopenharmony_cistatic SMbuf *get_llc_rx(struct s_smc *smc)
175162306a36Sopenharmony_ci{
175262306a36Sopenharmony_ci	SMbuf	*mb ;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	if ((mb = smc->os.hwm.llc_rx_pipe)) {
175562306a36Sopenharmony_ci		smc->os.hwm.queued_rx_frames-- ;
175662306a36Sopenharmony_ci		smc->os.hwm.llc_rx_pipe = mb->sm_next ;
175762306a36Sopenharmony_ci	}
175862306a36Sopenharmony_ci	DB_GEN(4, "get_llc_rx: mb = 0x%p", mb);
175962306a36Sopenharmony_ci	return mb;
176062306a36Sopenharmony_ci}
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci/*
176362306a36Sopenharmony_ci * queues a transmit SMT MBuf during the time were the MBuf is
176462306a36Sopenharmony_ci * queued the TxD ring
176562306a36Sopenharmony_ci */
176662306a36Sopenharmony_cistatic void queue_txd_mb(struct s_smc *smc, SMbuf *mb)
176762306a36Sopenharmony_ci{
176862306a36Sopenharmony_ci	DB_GEN(4, "_rx: queue_txd_mb = %p", mb);
176962306a36Sopenharmony_ci	smc->os.hwm.queued_txd_mb++ ;
177062306a36Sopenharmony_ci	mb->sm_next = (SMbuf *)NULL ;
177162306a36Sopenharmony_ci	if (smc->os.hwm.txd_tx_pipe == NULL) {
177262306a36Sopenharmony_ci		smc->os.hwm.txd_tx_pipe = mb ;
177362306a36Sopenharmony_ci	}
177462306a36Sopenharmony_ci	else {
177562306a36Sopenharmony_ci		smc->os.hwm.txd_tx_tail->sm_next = mb ;
177662306a36Sopenharmony_ci	}
177762306a36Sopenharmony_ci	smc->os.hwm.txd_tx_tail = mb ;
177862306a36Sopenharmony_ci}
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci/*
178162306a36Sopenharmony_ci * get a SMbuf from the txd_tx_queue
178262306a36Sopenharmony_ci */
178362306a36Sopenharmony_cistatic SMbuf *get_txd_mb(struct s_smc *smc)
178462306a36Sopenharmony_ci{
178562306a36Sopenharmony_ci	SMbuf *mb ;
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	if ((mb = smc->os.hwm.txd_tx_pipe)) {
178862306a36Sopenharmony_ci		smc->os.hwm.queued_txd_mb-- ;
178962306a36Sopenharmony_ci		smc->os.hwm.txd_tx_pipe = mb->sm_next ;
179062306a36Sopenharmony_ci	}
179162306a36Sopenharmony_ci	DB_GEN(4, "get_txd_mb: mb = 0x%p", mb);
179262306a36Sopenharmony_ci	return mb;
179362306a36Sopenharmony_ci}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci/*
179662306a36Sopenharmony_ci *	SMT Send function
179762306a36Sopenharmony_ci */
179862306a36Sopenharmony_civoid smt_send_mbuf(struct s_smc *smc, SMbuf *mb, int fc)
179962306a36Sopenharmony_ci{
180062306a36Sopenharmony_ci	char far *data ;
180162306a36Sopenharmony_ci	int	len ;
180262306a36Sopenharmony_ci	int	n ;
180362306a36Sopenharmony_ci	int	i ;
180462306a36Sopenharmony_ci	int	frag_count ;
180562306a36Sopenharmony_ci	int	frame_status ;
180662306a36Sopenharmony_ci	SK_LOC_DECL(char far,*virt[3]) ;
180762306a36Sopenharmony_ci	int	frag_len[3] ;
180862306a36Sopenharmony_ci	struct s_smt_tx_queue *queue ;
180962306a36Sopenharmony_ci	struct s_smt_fp_txd volatile *t ;
181062306a36Sopenharmony_ci	u_long	phys ;
181162306a36Sopenharmony_ci	__le32	tbctrl;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	NDD_TRACE("THSB",mb,fc,0) ;
181462306a36Sopenharmony_ci	DB_TX(4, "smt_send_mbuf: mb = 0x%p, fc = 0x%x", mb, fc);
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	mb->sm_off-- ;	/* set to fc */
181762306a36Sopenharmony_ci	mb->sm_len++ ;	/* + fc */
181862306a36Sopenharmony_ci	data = smtod(mb,char *) ;
181962306a36Sopenharmony_ci	*data = fc ;
182062306a36Sopenharmony_ci	if (fc == FC_SMT_LOC)
182162306a36Sopenharmony_ci		*data = FC_SMT_INFO ;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	/*
182462306a36Sopenharmony_ci	 * determine the frag count and the virt addresses of the frags
182562306a36Sopenharmony_ci	 */
182662306a36Sopenharmony_ci	frag_count = 0 ;
182762306a36Sopenharmony_ci	len = mb->sm_len ;
182862306a36Sopenharmony_ci	while (len) {
182962306a36Sopenharmony_ci		n = SMT_PAGESIZE - ((long)data & (SMT_PAGESIZE-1)) ;
183062306a36Sopenharmony_ci		if (n >= len) {
183162306a36Sopenharmony_ci			n = len ;
183262306a36Sopenharmony_ci		}
183362306a36Sopenharmony_ci		DB_TX(5, "frag: virt/len = 0x%p/%d", data, n);
183462306a36Sopenharmony_ci		virt[frag_count] = data ;
183562306a36Sopenharmony_ci		frag_len[frag_count] = n ;
183662306a36Sopenharmony_ci		frag_count++ ;
183762306a36Sopenharmony_ci		len -= n ;
183862306a36Sopenharmony_ci		data += n ;
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	/*
184262306a36Sopenharmony_ci	 * determine the frame status
184362306a36Sopenharmony_ci	 */
184462306a36Sopenharmony_ci	queue = smc->hw.fp.tx[QUEUE_A0] ;
184562306a36Sopenharmony_ci	if (fc == FC_BEACON || fc == FC_SMT_LOC) {
184662306a36Sopenharmony_ci		frame_status = LOC_TX ;
184762306a36Sopenharmony_ci	}
184862306a36Sopenharmony_ci	else {
184962306a36Sopenharmony_ci		frame_status = LAN_TX ;
185062306a36Sopenharmony_ci		if ((smc->os.hwm.pass_NSA &&(fc == FC_SMT_NSA)) ||
185162306a36Sopenharmony_ci		   (smc->os.hwm.pass_SMT &&(fc == FC_SMT_INFO)))
185262306a36Sopenharmony_ci			frame_status |= LOC_TX ;
185362306a36Sopenharmony_ci	}
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	if (!smc->hw.mac_ring_is_up || frag_count > queue->tx_free) {
185662306a36Sopenharmony_ci		frame_status &= ~LAN_TX;
185762306a36Sopenharmony_ci		if (frame_status) {
185862306a36Sopenharmony_ci			DB_TX(2, "Ring is down: terminate LAN_TX");
185962306a36Sopenharmony_ci		}
186062306a36Sopenharmony_ci		else {
186162306a36Sopenharmony_ci			DB_TX(2, "Ring is down: terminate transmission");
186262306a36Sopenharmony_ci			smt_free_mbuf(smc,mb) ;
186362306a36Sopenharmony_ci			return ;
186462306a36Sopenharmony_ci		}
186562306a36Sopenharmony_ci	}
186662306a36Sopenharmony_ci	DB_TX(5, "frame_status = 0x%x", frame_status);
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	if ((frame_status & LAN_TX) && (frame_status & LOC_TX)) {
186962306a36Sopenharmony_ci		mb->sm_use_count = 2 ;
187062306a36Sopenharmony_ci	}
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	if (frame_status & LAN_TX) {
187362306a36Sopenharmony_ci		t = queue->tx_curr_put ;
187462306a36Sopenharmony_ci		frame_status |= FIRST_FRAG ;
187562306a36Sopenharmony_ci		for (i = 0; i < frag_count; i++) {
187662306a36Sopenharmony_ci			DB_TX(5, "init TxD = 0x%p", t);
187762306a36Sopenharmony_ci			if (i == frag_count-1) {
187862306a36Sopenharmony_ci				frame_status |= LAST_FRAG ;
187962306a36Sopenharmony_ci				t->txd_txdscr = cpu_to_le32(TX_DESCRIPTOR |
188062306a36Sopenharmony_ci					(((__u32)(mb->sm_len-1)&3) << 27)) ;
188162306a36Sopenharmony_ci			}
188262306a36Sopenharmony_ci			t->txd_virt = virt[i] ;
188362306a36Sopenharmony_ci			phys = dma_master(smc, (void far *)virt[i],
188462306a36Sopenharmony_ci				frag_len[i], DMA_RD|SMT_BUF) ;
188562306a36Sopenharmony_ci			t->txd_tbadr = cpu_to_le32(phys) ;
188662306a36Sopenharmony_ci			tbctrl = cpu_to_le32((((__u32)frame_status &
188762306a36Sopenharmony_ci				(FIRST_FRAG|LAST_FRAG)) << 26) |
188862306a36Sopenharmony_ci				BMU_OWN | BMU_CHECK | BMU_SMT_TX |frag_len[i]) ;
188962306a36Sopenharmony_ci			t->txd_tbctrl = tbctrl ;
189062306a36Sopenharmony_ci#ifndef	AIX
189162306a36Sopenharmony_ci			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
189262306a36Sopenharmony_ci			outpd(queue->tx_bmu_ctl,CSR_START) ;
189362306a36Sopenharmony_ci#else
189462306a36Sopenharmony_ci			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
189562306a36Sopenharmony_ci			outpd(ADDR(B0_XA_CSR),CSR_START) ;
189662306a36Sopenharmony_ci#endif
189762306a36Sopenharmony_ci			frame_status &= ~FIRST_FRAG ;
189862306a36Sopenharmony_ci			queue->tx_curr_put = t = t->txd_next ;
189962306a36Sopenharmony_ci			queue->tx_free-- ;
190062306a36Sopenharmony_ci			queue->tx_used++ ;
190162306a36Sopenharmony_ci		}
190262306a36Sopenharmony_ci		smc->mib.m[MAC0].fddiMACTransmit_Ct++ ;
190362306a36Sopenharmony_ci		queue_txd_mb(smc,mb) ;
190462306a36Sopenharmony_ci	}
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	if (frame_status & LOC_TX) {
190762306a36Sopenharmony_ci		DB_TX(5, "pass Mbuf to LLC queue");
190862306a36Sopenharmony_ci		queue_llc_rx(smc,mb) ;
190962306a36Sopenharmony_ci	}
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	/*
191262306a36Sopenharmony_ci	 * We need to unqueue the free SMT_MBUFs here, because it may
191362306a36Sopenharmony_ci	 * be that the SMT want's to send more than 1 frame for one down call
191462306a36Sopenharmony_ci	 */
191562306a36Sopenharmony_ci	mac_drv_clear_txd(smc) ;
191662306a36Sopenharmony_ci	NDD_TRACE("THSE",t,queue->tx_free,frag_count) ;
191762306a36Sopenharmony_ci}
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci/*	BEGIN_MANUAL_ENTRY(mac_drv_clear_txd)
192062306a36Sopenharmony_ci *	void mac_drv_clear_txd(smc)
192162306a36Sopenharmony_ci *
192262306a36Sopenharmony_ci * function	DOWNCALL	(hardware module, hwmtm.c)
192362306a36Sopenharmony_ci *		mac_drv_clear_txd searches in both send queues for TxD's
192462306a36Sopenharmony_ci *		which were finished by the adapter. It calls dma_complete
192562306a36Sopenharmony_ci *		for each TxD. If the last fragment of an LLC frame is
192662306a36Sopenharmony_ci *		reached, it calls mac_drv_tx_complete to release the
192762306a36Sopenharmony_ci *		send buffer.
192862306a36Sopenharmony_ci *
192962306a36Sopenharmony_ci * return	nothing
193062306a36Sopenharmony_ci *
193162306a36Sopenharmony_ci *	END_MANUAL_ENTRY
193262306a36Sopenharmony_ci */
193362306a36Sopenharmony_cistatic void mac_drv_clear_txd(struct s_smc *smc)
193462306a36Sopenharmony_ci{
193562306a36Sopenharmony_ci	struct s_smt_tx_queue *queue ;
193662306a36Sopenharmony_ci	struct s_smt_fp_txd volatile *t1 ;
193762306a36Sopenharmony_ci	struct s_smt_fp_txd volatile *t2 = NULL ;
193862306a36Sopenharmony_ci	SMbuf *mb ;
193962306a36Sopenharmony_ci	u_long	tbctrl ;
194062306a36Sopenharmony_ci	int i ;
194162306a36Sopenharmony_ci	int frag_count ;
194262306a36Sopenharmony_ci	int n ;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	NDD_TRACE("THcB",0,0,0) ;
194562306a36Sopenharmony_ci	for (i = QUEUE_S; i <= QUEUE_A0; i++) {
194662306a36Sopenharmony_ci		queue = smc->hw.fp.tx[i] ;
194762306a36Sopenharmony_ci		t1 = queue->tx_curr_get ;
194862306a36Sopenharmony_ci		DB_TX(5, "clear_txd: QUEUE = %d (0=sync/1=async)", i);
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci		for ( ; ; ) {
195162306a36Sopenharmony_ci			frag_count = 0 ;
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci			do {
195462306a36Sopenharmony_ci				DRV_BUF_FLUSH(t1,DDI_DMA_SYNC_FORCPU) ;
195562306a36Sopenharmony_ci				DB_TX(5, "check OWN/EOF bit of TxD 0x%p", t1);
195662306a36Sopenharmony_ci				tbctrl = le32_to_cpu(CR_READ(t1->txd_tbctrl));
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci				if (tbctrl & BMU_OWN || !queue->tx_used){
195962306a36Sopenharmony_ci					DB_TX(4, "End of TxDs queue %d", i);
196062306a36Sopenharmony_ci					goto free_next_queue ;	/* next queue */
196162306a36Sopenharmony_ci				}
196262306a36Sopenharmony_ci				t1 = t1->txd_next ;
196362306a36Sopenharmony_ci				frag_count++ ;
196462306a36Sopenharmony_ci			} while (!(tbctrl & BMU_EOF)) ;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci			t1 = queue->tx_curr_get ;
196762306a36Sopenharmony_ci			for (n = frag_count; n; n--) {
196862306a36Sopenharmony_ci				tbctrl = le32_to_cpu(t1->txd_tbctrl) ;
196962306a36Sopenharmony_ci				dma_complete(smc,
197062306a36Sopenharmony_ci					(union s_fp_descr volatile *) t1,
197162306a36Sopenharmony_ci					(int) (DMA_RD |
197262306a36Sopenharmony_ci					((tbctrl & BMU_SMT_TX) >> 18))) ;
197362306a36Sopenharmony_ci				t2 = t1 ;
197462306a36Sopenharmony_ci				t1 = t1->txd_next ;
197562306a36Sopenharmony_ci			}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci			if (tbctrl & BMU_SMT_TX) {
197862306a36Sopenharmony_ci				mb = get_txd_mb(smc) ;
197962306a36Sopenharmony_ci				smt_free_mbuf(smc,mb) ;
198062306a36Sopenharmony_ci			}
198162306a36Sopenharmony_ci			else {
198262306a36Sopenharmony_ci#ifndef PASS_1ST_TXD_2_TX_COMP
198362306a36Sopenharmony_ci				DB_TX(4, "mac_drv_tx_comp for TxD 0x%p", t2);
198462306a36Sopenharmony_ci				mac_drv_tx_complete(smc,t2) ;
198562306a36Sopenharmony_ci#else
198662306a36Sopenharmony_ci				DB_TX(4, "mac_drv_tx_comp for TxD 0x%x",
198762306a36Sopenharmony_ci				      queue->tx_curr_get);
198862306a36Sopenharmony_ci				mac_drv_tx_complete(smc,queue->tx_curr_get) ;
198962306a36Sopenharmony_ci#endif
199062306a36Sopenharmony_ci			}
199162306a36Sopenharmony_ci			queue->tx_curr_get = t1 ;
199262306a36Sopenharmony_ci			queue->tx_free += frag_count ;
199362306a36Sopenharmony_ci			queue->tx_used -= frag_count ;
199462306a36Sopenharmony_ci		}
199562306a36Sopenharmony_cifree_next_queue: ;
199662306a36Sopenharmony_ci	}
199762306a36Sopenharmony_ci	NDD_TRACE("THcE",0,0,0) ;
199862306a36Sopenharmony_ci}
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci/*
200162306a36Sopenharmony_ci *	BEGINN_MANUAL_ENTRY(mac_drv_clear_tx_queue)
200262306a36Sopenharmony_ci *
200362306a36Sopenharmony_ci * void mac_drv_clear_tx_queue(smc)
200462306a36Sopenharmony_ci * struct s_smc *smc ;
200562306a36Sopenharmony_ci *
200662306a36Sopenharmony_ci * function	DOWNCALL	(hardware module, hwmtm.c)
200762306a36Sopenharmony_ci *		mac_drv_clear_tx_queue is called from the SMT when
200862306a36Sopenharmony_ci *		the RMT state machine has entered the ISOLATE state.
200962306a36Sopenharmony_ci *		This function is also called by the os-specific module
201062306a36Sopenharmony_ci *		after it has called the function card_stop().
201162306a36Sopenharmony_ci *		In this case, the frames in the send queues are obsolete and
201262306a36Sopenharmony_ci *		should be removed.
201362306a36Sopenharmony_ci *
201462306a36Sopenharmony_ci * note		calling sequence:
201562306a36Sopenharmony_ci *		CLI_FBI(), card_stop(),
201662306a36Sopenharmony_ci *		mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(),
201762306a36Sopenharmony_ci *
201862306a36Sopenharmony_ci * NOTE:	The caller is responsible that the BMUs are idle
201962306a36Sopenharmony_ci *		when this function is called.
202062306a36Sopenharmony_ci *
202162306a36Sopenharmony_ci *	END_MANUAL_ENTRY
202262306a36Sopenharmony_ci */
202362306a36Sopenharmony_civoid mac_drv_clear_tx_queue(struct s_smc *smc)
202462306a36Sopenharmony_ci{
202562306a36Sopenharmony_ci	struct s_smt_fp_txd volatile *t ;
202662306a36Sopenharmony_ci	struct s_smt_tx_queue *queue ;
202762306a36Sopenharmony_ci	int tx_used ;
202862306a36Sopenharmony_ci	int i ;
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	if (smc->hw.hw_state != STOPPED) {
203162306a36Sopenharmony_ci		SK_BREAK() ;
203262306a36Sopenharmony_ci		SMT_PANIC(smc,HWM_E0011,HWM_E0011_MSG) ;
203362306a36Sopenharmony_ci		return ;
203462306a36Sopenharmony_ci	}
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci	for (i = QUEUE_S; i <= QUEUE_A0; i++) {
203762306a36Sopenharmony_ci		queue = smc->hw.fp.tx[i] ;
203862306a36Sopenharmony_ci		DB_TX(5, "clear_tx_queue: QUEUE = %d (0=sync/1=async)", i);
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci		/*
204162306a36Sopenharmony_ci		 * switch the OWN bit of all pending frames to the host
204262306a36Sopenharmony_ci		 */
204362306a36Sopenharmony_ci		t = queue->tx_curr_get ;
204462306a36Sopenharmony_ci		tx_used = queue->tx_used ;
204562306a36Sopenharmony_ci		while (tx_used) {
204662306a36Sopenharmony_ci			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ;
204762306a36Sopenharmony_ci			DB_TX(5, "switch OWN bit of TxD 0x%p", t);
204862306a36Sopenharmony_ci			t->txd_tbctrl &= ~cpu_to_le32(BMU_OWN) ;
204962306a36Sopenharmony_ci			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
205062306a36Sopenharmony_ci			t = t->txd_next ;
205162306a36Sopenharmony_ci			tx_used-- ;
205262306a36Sopenharmony_ci		}
205362306a36Sopenharmony_ci	}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	/*
205662306a36Sopenharmony_ci	 * release all TxD's for both send queues
205762306a36Sopenharmony_ci	 */
205862306a36Sopenharmony_ci	mac_drv_clear_txd(smc) ;
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	for (i = QUEUE_S; i <= QUEUE_A0; i++) {
206162306a36Sopenharmony_ci		queue = smc->hw.fp.tx[i] ;
206262306a36Sopenharmony_ci		t = queue->tx_curr_get ;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci		/*
206562306a36Sopenharmony_ci		 * write the phys pointer of the NEXT descriptor into the
206662306a36Sopenharmony_ci		 * BMU's current address descriptor pointer and set
206762306a36Sopenharmony_ci		 * tx_curr_get and tx_curr_put to this position
206862306a36Sopenharmony_ci		 */
206962306a36Sopenharmony_ci		if (i == QUEUE_S) {
207062306a36Sopenharmony_ci			outpd(ADDR(B5_XS_DA),le32_to_cpu(t->txd_ntdadr)) ;
207162306a36Sopenharmony_ci		}
207262306a36Sopenharmony_ci		else {
207362306a36Sopenharmony_ci			outpd(ADDR(B5_XA_DA),le32_to_cpu(t->txd_ntdadr)) ;
207462306a36Sopenharmony_ci		}
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci		queue->tx_curr_put = queue->tx_curr_get->txd_next ;
207762306a36Sopenharmony_ci		queue->tx_curr_get = queue->tx_curr_put ;
207862306a36Sopenharmony_ci	}
207962306a36Sopenharmony_ci}
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci/*
208362306a36Sopenharmony_ci	-------------------------------------------------------------
208462306a36Sopenharmony_ci	TEST FUNCTIONS:
208562306a36Sopenharmony_ci	-------------------------------------------------------------
208662306a36Sopenharmony_ci*/
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci#ifdef	DEBUG
208962306a36Sopenharmony_ci/*
209062306a36Sopenharmony_ci *	BEGIN_MANUAL_ENTRY(mac_drv_debug_lev)
209162306a36Sopenharmony_ci *	void mac_drv_debug_lev(smc,flag,lev)
209262306a36Sopenharmony_ci *
209362306a36Sopenharmony_ci * function	DOWNCALL	(drvsr.c)
209462306a36Sopenharmony_ci *		To get a special debug info the user can assign a debug level
209562306a36Sopenharmony_ci *		to any debug flag.
209662306a36Sopenharmony_ci *
209762306a36Sopenharmony_ci * para	flag	debug flag, possible values are:
209862306a36Sopenharmony_ci *			= 0:	reset all debug flags (the defined level is
209962306a36Sopenharmony_ci *				ignored)
210062306a36Sopenharmony_ci *			= 1:	debug.d_smtf
210162306a36Sopenharmony_ci *			= 2:	debug.d_smt
210262306a36Sopenharmony_ci *			= 3:	debug.d_ecm
210362306a36Sopenharmony_ci *			= 4:	debug.d_rmt
210462306a36Sopenharmony_ci *			= 5:	debug.d_cfm
210562306a36Sopenharmony_ci *			= 6:	debug.d_pcm
210662306a36Sopenharmony_ci *
210762306a36Sopenharmony_ci *			= 10:	debug.d_os.hwm_rx (hardware module receive path)
210862306a36Sopenharmony_ci *			= 11:	debug.d_os.hwm_tx(hardware module transmit path)
210962306a36Sopenharmony_ci *			= 12:	debug.d_os.hwm_gen(hardware module general flag)
211062306a36Sopenharmony_ci *
211162306a36Sopenharmony_ci *	lev	debug level
211262306a36Sopenharmony_ci *
211362306a36Sopenharmony_ci *	END_MANUAL_ENTRY
211462306a36Sopenharmony_ci */
211562306a36Sopenharmony_civoid mac_drv_debug_lev(struct s_smc *smc, int flag, int lev)
211662306a36Sopenharmony_ci{
211762306a36Sopenharmony_ci	switch(flag) {
211862306a36Sopenharmony_ci	case (int)NULL:
211962306a36Sopenharmony_ci		DB_P.d_smtf = DB_P.d_smt = DB_P.d_ecm = DB_P.d_rmt = 0 ;
212062306a36Sopenharmony_ci		DB_P.d_cfm = 0 ;
212162306a36Sopenharmony_ci		DB_P.d_os.hwm_rx = DB_P.d_os.hwm_tx = DB_P.d_os.hwm_gen = 0 ;
212262306a36Sopenharmony_ci#ifdef	SBA
212362306a36Sopenharmony_ci		DB_P.d_sba = 0 ;
212462306a36Sopenharmony_ci#endif
212562306a36Sopenharmony_ci#ifdef	ESS
212662306a36Sopenharmony_ci		DB_P.d_ess = 0 ;
212762306a36Sopenharmony_ci#endif
212862306a36Sopenharmony_ci		break ;
212962306a36Sopenharmony_ci	case DEBUG_SMTF:
213062306a36Sopenharmony_ci		DB_P.d_smtf = lev ;
213162306a36Sopenharmony_ci		break ;
213262306a36Sopenharmony_ci	case DEBUG_SMT:
213362306a36Sopenharmony_ci		DB_P.d_smt = lev ;
213462306a36Sopenharmony_ci		break ;
213562306a36Sopenharmony_ci	case DEBUG_ECM:
213662306a36Sopenharmony_ci		DB_P.d_ecm = lev ;
213762306a36Sopenharmony_ci		break ;
213862306a36Sopenharmony_ci	case DEBUG_RMT:
213962306a36Sopenharmony_ci		DB_P.d_rmt = lev ;
214062306a36Sopenharmony_ci		break ;
214162306a36Sopenharmony_ci	case DEBUG_CFM:
214262306a36Sopenharmony_ci		DB_P.d_cfm = lev ;
214362306a36Sopenharmony_ci		break ;
214462306a36Sopenharmony_ci	case DEBUG_PCM:
214562306a36Sopenharmony_ci		DB_P.d_pcm = lev ;
214662306a36Sopenharmony_ci		break ;
214762306a36Sopenharmony_ci	case DEBUG_SBA:
214862306a36Sopenharmony_ci#ifdef	SBA
214962306a36Sopenharmony_ci		DB_P.d_sba = lev ;
215062306a36Sopenharmony_ci#endif
215162306a36Sopenharmony_ci		break ;
215262306a36Sopenharmony_ci	case DEBUG_ESS:
215362306a36Sopenharmony_ci#ifdef	ESS
215462306a36Sopenharmony_ci		DB_P.d_ess = lev ;
215562306a36Sopenharmony_ci#endif
215662306a36Sopenharmony_ci		break ;
215762306a36Sopenharmony_ci	case DB_HWM_RX:
215862306a36Sopenharmony_ci		DB_P.d_os.hwm_rx = lev ;
215962306a36Sopenharmony_ci		break ;
216062306a36Sopenharmony_ci	case DB_HWM_TX:
216162306a36Sopenharmony_ci		DB_P.d_os.hwm_tx = lev ;
216262306a36Sopenharmony_ci		break ;
216362306a36Sopenharmony_ci	case DB_HWM_GEN:
216462306a36Sopenharmony_ci		DB_P.d_os.hwm_gen = lev ;
216562306a36Sopenharmony_ci		break ;
216662306a36Sopenharmony_ci	default:
216762306a36Sopenharmony_ci		break ;
216862306a36Sopenharmony_ci	}
216962306a36Sopenharmony_ci}
217062306a36Sopenharmony_ci#endif
2171