brintos

brintos / linux-shallow public Read only

0
0
Text · 12.1 KiB · e9b9614 Raw
578 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/******************************************************************************3 *4 *	(C)Copyright 1998,1999 SysKonnect,5 *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.6 *7 *	See the file "skfddi.c" for further information.8 *9 *	The information in this file is provided "AS IS" without warranty.10 *11 ******************************************************************************/12 13/*14 * FBI board dependent Driver for SMT and LLC15 */16 17#include "h/types.h"18#include "h/fddi.h"19#include "h/smc.h"20#include "h/supern_2.h"21#include "h/skfbiinc.h"22#include <linux/bitrev.h>23#include <linux/pci.h>24 25/*26 * PCM active state27 */28#define PC8_ACTIVE	829 30#define	LED_Y_ON	0x11	/* Used for ring up/down indication */31#define	LED_Y_OFF	0x1032 33 34#define MS2BCLK(x)	((x)*12500L)35 36/*37 * valid configuration values are:38 */39 40/*41 *	xPOS_ID:xxxx42 *	|	\  /43 *	|	 \/44 *	|	  --------------------- the patched POS_ID of the Adapter45 *	|				xxxx = (Vendor ID low byte,46 *	|					Vendor ID high byte,47 *	|					Device ID low byte,48 *	|					Device ID high byte)49 *	+------------------------------ the patched oem_id must be50 *					'S' for SK or 'I' for IBM51 *					this is a short id for the driver.52 */53#ifndef MULT_OEM54#ifndef	OEM_CONCEPT55const u_char oem_id[] = "xPOS_ID:xxxx" ;56#else	/* OEM_CONCEPT */57const u_char oem_id[] = OEM_ID ;58#endif	/* OEM_CONCEPT */59#define	ID_BYTE0	860#define	OEMID(smc,i)	oem_id[ID_BYTE0 + i]61#else	/* MULT_OEM */62const struct s_oem_ids oem_ids[] = {63#include "oemids.h"64{0}65};66#define	OEMID(smc,i)	smc->hw.oem_id->oi_id[i]67#endif	/* MULT_OEM */68 69/* Prototypes of external functions */70#ifdef AIX71extern int AIX_vpdReadByte() ;72#endif73 74 75/* Prototype of a local function. */76static void smt_stop_watchdog(struct s_smc *smc);77 78/*79 * FDDI card reset80 */81static void card_start(struct s_smc *smc)82{83	int i ;84#ifdef	PCI85	u_char	rev_id ;86	u_short word;87#endif88 89	smt_stop_watchdog(smc) ;90 91#ifdef	PCI92	/*93	 * make sure no transfer activity is pending94	 */95	outpw(FM_A(FM_MDREG1),FM_MINIT) ;96	outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;97	hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ;98	/*99	 * now reset everything100	 */101	outp(ADDR(B0_CTRL),CTRL_RST_SET) ;	/* reset for all chips */102	i = (int) inp(ADDR(B0_CTRL)) ;		/* do dummy read */103	SK_UNUSED(i) ;				/* Make LINT happy. */104	outp(ADDR(B0_CTRL), CTRL_RST_CLR) ;105 106	/*107	 * Reset all bits in the PCI STATUS register108	 */109	outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_ON) ;	/* enable for writes */110	word = inpw(PCI_C(PCI_STATUS)) ;111	outpw(PCI_C(PCI_STATUS), word | PCI_STATUS_ERROR_BITS);112	outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_OFF) ;	/* disable writes */113 114	/*115	 * Release the reset of all the State machines116	 * Release Master_Reset117	 * Release HPI_SM_Reset118	 */119	outp(ADDR(B0_CTRL), CTRL_MRST_CLR|CTRL_HPI_CLR) ;120 121	/*122	 * determine the adapter type123	 * Note: Do it here, because some drivers may call card_start() once124	 *	 at very first before any other initialization functions is125	 *	 executed.126	 */127	rev_id = inp(PCI_C(PCI_REVISION_ID)) ;128	if ((rev_id & 0xf0) == SK_ML_ID_1 || (rev_id & 0xf0) == SK_ML_ID_2) {129		smc->hw.hw_is_64bit = TRUE ;130	} else {131		smc->hw.hw_is_64bit = FALSE ;132	}133 134	/*135	 * Watermark initialization136	 */137	if (!smc->hw.hw_is_64bit) {138		outpd(ADDR(B4_R1_F), RX_WATERMARK) ;139		outpd(ADDR(B5_XA_F), TX_WATERMARK) ;140		outpd(ADDR(B5_XS_F), TX_WATERMARK) ;141	}142 143	outp(ADDR(B0_CTRL),CTRL_RST_CLR) ;	/* clear the reset chips */144	outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_ON|LED_GB_OFF) ; /* ye LED on */145 146	/* init the timer value for the watch dog 2,5 minutes */147	outpd(ADDR(B2_WDOG_INI),0x6FC23AC0) ;148 149	/* initialize the ISR mask */150	smc->hw.is_imask = ISR_MASK ;151	smc->hw.hw_state = STOPPED ;152#endif153	GET_PAGE(0) ;		/* necessary for BOOT */154}155 156void card_stop(struct s_smc *smc)157{158	smt_stop_watchdog(smc) ;159	smc->hw.mac_ring_is_up = 0 ;		/* ring down */160 161#ifdef	PCI162	/*163	 * make sure no transfer activity is pending164	 */165	outpw(FM_A(FM_MDREG1),FM_MINIT) ;166	outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;167	hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ;168	/*169	 * now reset everything170	 */171	outp(ADDR(B0_CTRL),CTRL_RST_SET) ;	/* reset for all chips */172	outp(ADDR(B0_CTRL),CTRL_RST_CLR) ;	/* reset for all chips */173	outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_OFF|LED_GB_OFF) ; /* all LEDs off */174	smc->hw.hw_state = STOPPED ;175#endif176}177/*--------------------------- ISR handling ----------------------------------*/178 179void mac1_irq(struct s_smc *smc, u_short stu, u_short stl)180{181	int	restart_tx = 0 ;182again:183 184	/*185	 * parity error: note encoding error is not possible in tag mode186	 */187	if (stl & (FM_SPCEPDS  |	/* parity err. syn.q.*/188		   FM_SPCEPDA0 |	/* parity err. a.q.0 */189		   FM_SPCEPDA1)) {	/* parity err. a.q.1 */190		SMT_PANIC(smc,SMT_E0134, SMT_E0134_MSG) ;191	}192	/*193	 * buffer underrun: can only occur if a tx threshold is specified194	 */195	if (stl & (FM_STBURS  |		/* tx buffer underrun syn.q.*/196		   FM_STBURA0 |		/* tx buffer underrun a.q.0 */197		   FM_STBURA1)) {	/* tx buffer underrun a.q.2 */198		SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ;199	}200 201	if ( (stu & (FM_SXMTABT |		/* transmit abort */202		     FM_STXABRS |		/* syn. tx abort */203		     FM_STXABRA0)) ||		/* asyn. tx abort */204	     (stl & (FM_SQLCKS |		/* lock for syn. q. */205		     FM_SQLCKA0)) ) {		/* lock for asyn. q. */206		formac_tx_restart(smc) ;	/* init tx */207		restart_tx = 1 ;208		stu = inpw(FM_A(FM_ST1U)) ;209		stl = inpw(FM_A(FM_ST1L)) ;210		stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ;211		if (stu || stl)212			goto again ;213	}214 215	if (stu & (FM_STEFRMA0 |	/* end of asyn tx */216		    FM_STEFRMS)) {	/* end of sync tx */217		restart_tx = 1 ;218	}219 220	if (restart_tx)221		llc_restart_tx(smc) ;222}223 224/*225 * interrupt source= plc1226 * this function is called in nwfbisr.asm227 */228void plc1_irq(struct s_smc *smc)229{230	u_short	st = inpw(PLC(PB,PL_INTR_EVENT)) ;231 232	plc_irq(smc,PB,st) ;233}234 235/*236 * interrupt source= plc2237 * this function is called in nwfbisr.asm238 */239void plc2_irq(struct s_smc *smc)240{241	u_short	st = inpw(PLC(PA,PL_INTR_EVENT)) ;242 243	plc_irq(smc,PA,st) ;244}245 246 247/*248 * interrupt source= timer249 */250void timer_irq(struct s_smc *smc)251{252	hwt_restart(smc);253	smc->hw.t_stop = smc->hw.t_start;254	smt_timer_done(smc) ;255}256 257/*258 * return S-port (PA or PB)259 */260int pcm_get_s_port(struct s_smc *smc)261{262	SK_UNUSED(smc) ;263	return PS;264}265 266/*267 * Station Label = "FDDI-XYZ" where268 *269 *	X = connector type270 *	Y = PMD type271 *	Z = port type272 */273#define STATION_LABEL_CONNECTOR_OFFSET	5274#define STATION_LABEL_PMD_OFFSET	6275#define STATION_LABEL_PORT_OFFSET	7276 277void read_address(struct s_smc *smc, u_char *mac_addr)278{279	char ConnectorType ;280	char PmdType ;281	int	i ;282 283#ifdef	PCI284	for (i = 0; i < 6; i++) {	/* read mac address from board */285		smc->hw.fddi_phys_addr.a[i] =286			bitrev8(inp(ADDR(B2_MAC_0+i)));287	}288#endif289 290	ConnectorType = inp(ADDR(B2_CONN_TYP)) ;291	PmdType = inp(ADDR(B2_PMD_TYP)) ;292 293	smc->y[PA].pmd_type[PMD_SK_CONN] =294	smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ;295	smc->y[PA].pmd_type[PMD_SK_PMD ] =296	smc->y[PB].pmd_type[PMD_SK_PMD ] = PmdType ;297 298	if (mac_addr) {299		for (i = 0; i < 6 ;i++) {300			smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ;301			smc->hw.fddi_home_addr.a[i] = bitrev8(mac_addr[i]);302		}303		return ;304	}305	smc->hw.fddi_home_addr = smc->hw.fddi_phys_addr ;306 307	for (i = 0; i < 6 ;i++) {308		smc->hw.fddi_canon_addr.a[i] =309			bitrev8(smc->hw.fddi_phys_addr.a[i]);310	}311}312 313/*314 * FDDI card soft reset315 */316void init_board(struct s_smc *smc, u_char *mac_addr)317{318	card_start(smc) ;319	read_address(smc,mac_addr) ;320 321	if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL))322		smc->s.sas = SMT_SAS ;	/* Single att. station */323	else324		smc->s.sas = SMT_DAS ;	/* Dual att. station */325 326	if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST))327		smc->mib.fddiSMTBypassPresent = 0 ;328		/* without opt. bypass */329	else330		smc->mib.fddiSMTBypassPresent = 1 ;331		/* with opt. bypass */332}333 334/*335 * insert or deinsert optical bypass (called by ECM)336 */337void sm_pm_bypass_req(struct s_smc *smc, int mode)338{339	DB_ECMN(1, "ECM : sm_pm_bypass_req(%s)",340		mode == BP_INSERT ? "BP_INSERT" : "BP_DEINSERT");341 342	if (smc->s.sas != SMT_DAS)343		return ;344 345#ifdef	PCI346	switch(mode) {347	case BP_INSERT :348		outp(ADDR(B0_DAS),DAS_BYP_INS) ;	/* insert station */349		break ;350	case BP_DEINSERT :351		outp(ADDR(B0_DAS),DAS_BYP_RMV) ;	/* bypass station */352		break ;353	}354#endif355}356 357/*358 * check if bypass connected359 */360int sm_pm_bypass_present(struct s_smc *smc)361{362	return (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE : FALSE;363}364 365void plc_clear_irq(struct s_smc *smc, int p)366{367	SK_UNUSED(p) ;368 369	SK_UNUSED(smc) ;370}371 372 373/*374 * led_indication called by rmt_indication() and375 * pcm_state_change()376 *377 * Input:378 *	smc:	SMT context379 *	led_event:380 *	0	Only switch green LEDs according to their respective PCM state381 *	LED_Y_OFF	just switch yellow LED off382 *	LED_Y_ON	just switch yello LED on383 */384static void led_indication(struct s_smc *smc, int led_event)385{386	/* use smc->hw.mac_ring_is_up == TRUE 387	 * as indication for Ring Operational388	 */389	u_short			led_state ;390	struct s_phy		*phy ;391	struct fddi_mib_p	*mib_a ;392	struct fddi_mib_p	*mib_b ;393 394	phy = &smc->y[PA] ;395	mib_a = phy->mib ;396	phy = &smc->y[PB] ;397	mib_b = phy->mib ;398 399#ifdef	PCI400        led_state = 0 ;401	402	/* Ring up = yellow led OFF*/403	if (led_event == LED_Y_ON) {404		led_state |= LED_MY_ON ;405	}406	else if (led_event == LED_Y_OFF) {407		led_state |= LED_MY_OFF ;408	}409	else {	/* PCM state changed */410		/* Link at Port A/S = green led A ON */411		if (mib_a->fddiPORTPCMState == PC8_ACTIVE) {	412			led_state |= LED_GA_ON ;413		}414		else {415			led_state |= LED_GA_OFF ;416		}417		418		/* Link at Port B = green led B ON */419		if (mib_b->fddiPORTPCMState == PC8_ACTIVE) {420			led_state |= LED_GB_ON ;421		}422		else {423			led_state |= LED_GB_OFF ;424		}425	}426 427        outp(ADDR(B0_LED), led_state) ;428#endif	/* PCI */429 430}431 432 433void pcm_state_change(struct s_smc *smc, int plc, int p_state)434{435	/*436	 * the current implementation of pcm_state_change() in the driver437	 * parts must be renamed to drv_pcm_state_change() which will be called438	 * now after led_indication.439	 */440	DRV_PCM_STATE_CHANGE(smc,plc,p_state) ;441	442	led_indication(smc,0) ;443}444 445 446void rmt_indication(struct s_smc *smc, int i)447{448	/* Call a driver special function if defined */449	DRV_RMT_INDICATION(smc,i) ;450 451        led_indication(smc, i ? LED_Y_OFF : LED_Y_ON) ;452}453 454 455/*456 * llc_recover_tx called by init_tx (fplus.c)457 */458void llc_recover_tx(struct s_smc *smc)459{460#ifdef	LOAD_GEN461	extern	int load_gen_flag ;462 463	load_gen_flag = 0 ;464#endif465#ifndef	SYNC466	smc->hw.n_a_send= 0 ;467#else468	SK_UNUSED(smc) ;469#endif470}471 472#ifdef MULT_OEM473static int is_equal_num(char comp1[], char comp2[], int num)474{475	int i ;476 477	for (i = 0 ; i < num ; i++) {478		if (comp1[i] != comp2[i])479			return 0;480	}481		return 1;482}	/* is_equal_num */483 484 485/*486 * set the OEM ID defaults, and test the contents of the OEM data base487 * The default OEM is the first ACTIVE entry in the OEM data base 488 *489 * returns:	0	success490 *		1	error in data base491 *		2	data base empty492 *		3	no active entry	493 */494int set_oi_id_def(struct s_smc *smc)495{496	int sel_id ;497	int i ;498	int act_entries ;499 500	i = 0 ;501	sel_id = -1 ;502	act_entries = FALSE ;503	smc->hw.oem_id = 0 ;504	smc->hw.oem_min_status = OI_STAT_ACTIVE ;505	506	/* check OEM data base */507	while (oem_ids[i].oi_status) {508		switch (oem_ids[i].oi_status) {509		case OI_STAT_ACTIVE:510			act_entries = TRUE ;	/* we have active IDs */511			if (sel_id == -1)512				sel_id = i ;	/* save the first active ID */513		case OI_STAT_VALID:514		case OI_STAT_PRESENT:515			i++ ;516			break ;			/* entry ok */517		default:518			return 1;		/* invalid oi_status */519		}520	}521 522	if (i == 0)523		return 2;524	if (!act_entries)525		return 3;526 527	/* ok, we have a valid OEM data base with an active entry */528	smc->hw.oem_id = (struct s_oem_ids *)  &oem_ids[sel_id] ;529	return 0;530}531#endif	/* MULT_OEM */532 533void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr)534{535	int i ;536 537	for (i = 0 ; i < 6 ; i++)538		bia_addr->a[i] = bitrev8(smc->hw.fddi_phys_addr.a[i]);539}540 541void smt_start_watchdog(struct s_smc *smc)542{543	SK_UNUSED(smc) ;	/* Make LINT happy. */544 545#ifndef	DEBUG546 547#ifdef	PCI548	if (smc->hw.wdog_used) {549		outpw(ADDR(B2_WDOG_CRTL),TIM_START) ;	/* Start timer. */550	}551#endif552 553#endif	/* DEBUG */554}555 556static void smt_stop_watchdog(struct s_smc *smc)557{558	SK_UNUSED(smc) ;	/* Make LINT happy. */559#ifndef	DEBUG560 561#ifdef	PCI562	if (smc->hw.wdog_used) {563		outpw(ADDR(B2_WDOG_CRTL),TIM_STOP) ;	/* Stop timer. */564	}565#endif566 567#endif	/* DEBUG */568}569 570#ifdef	PCI571 572void mac_do_pci_fix(struct s_smc *smc)573{574	SK_UNUSED(smc) ;575}576#endif	/* PCI */577 578