• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/net/skfp/
1/******************************************************************************
2 *
3 *	(C)Copyright 1998,1999 SysKonnect,
4 *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
5 *
6 *	See the file "skfddi.c" for further information.
7 *
8 *	This program is free software; you can redistribute it and/or modify
9 *	it under the terms of the GNU General Public License as published by
10 *	the Free Software Foundation; either version 2 of the License, or
11 *	(at your option) any later version.
12 *
13 *	The information in this file is provided "AS IS" without warranty.
14 *
15 ******************************************************************************/
16
17/*
18 * FBI board dependent Driver for SMT and LLC
19 */
20
21#include "h/types.h"
22#include "h/fddi.h"
23#include "h/smc.h"
24#include "h/supern_2.h"
25#include "h/skfbiinc.h"
26#include <linux/bitrev.h>
27
28#ifndef	lint
29static const char ID_sccs[] = "@(#)drvfbi.c	1.63 99/02/11 (C) SK " ;
30#endif
31
32/*
33 * PCM active state
34 */
35#define PC8_ACTIVE	8
36
37#define	LED_Y_ON	0x11	/* Used for ring up/down indication */
38#define	LED_Y_OFF	0x10
39
40
41#define MS2BCLK(x)	((x)*12500L)
42
43/*
44 * valid configuration values are:
45 */
46
47#ifndef MULT_OEM
48#ifndef	OEM_CONCEPT
49const u_char oem_id[] = "xPOS_ID:xxxx" ;
50#else	/* OEM_CONCEPT */
51const u_char oem_id[] = OEM_ID ;
52#endif	/* OEM_CONCEPT */
53#define	ID_BYTE0	8
54#define	OEMID(smc,i)	oem_id[ID_BYTE0 + i]
55#else	/* MULT_OEM */
56const struct s_oem_ids oem_ids[] = {
57#include "oemids.h"
58{0}
59};
60#define	OEMID(smc,i)	smc->hw.oem_id->oi_id[i]
61#endif	/* MULT_OEM */
62
63/* Prototypes of external functions */
64#ifdef AIX
65extern int AIX_vpdReadByte() ;
66#endif
67
68
69/* Prototype of a local function. */
70static void smt_stop_watchdog(struct s_smc *smc);
71
72/*
73 * FDDI card reset
74 */
75static void card_start(struct s_smc *smc)
76{
77	int i ;
78#ifdef	PCI
79	u_char	rev_id ;
80	u_short word;
81#endif
82
83	smt_stop_watchdog(smc) ;
84
85#ifdef	PCI
86	/*
87	 * make sure no transfer activity is pending
88	 */
89	outpw(FM_A(FM_MDREG1),FM_MINIT) ;
90	outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
91	hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ;
92	/*
93	 * now reset everything
94	 */
95	outp(ADDR(B0_CTRL),CTRL_RST_SET) ;	/* reset for all chips */
96	i = (int) inp(ADDR(B0_CTRL)) ;		/* do dummy read */
97	SK_UNUSED(i) ;				/* Make LINT happy. */
98	outp(ADDR(B0_CTRL), CTRL_RST_CLR) ;
99
100	/*
101	 * Reset all bits in the PCI STATUS register
102	 */
103	outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_ON) ;	/* enable for writes */
104	word = inpw(PCI_C(PCI_STATUS)) ;
105	outpw(PCI_C(PCI_STATUS), word | PCI_ERRBITS) ;
106	outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_OFF) ;	/* disable writes */
107
108	/*
109	 * Release the reset of all the State machines
110	 * Release Master_Reset
111	 * Release HPI_SM_Reset
112	 */
113	outp(ADDR(B0_CTRL), CTRL_MRST_CLR|CTRL_HPI_CLR) ;
114
115	/*
116	 * determine the adapter type
117	 * Note: Do it here, because some drivers may call card_start() once
118	 *	 at very first before any other initialization functions is
119	 *	 executed.
120	 */
121	rev_id = inp(PCI_C(PCI_REV_ID)) ;
122	if ((rev_id & 0xf0) == SK_ML_ID_1 || (rev_id & 0xf0) == SK_ML_ID_2) {
123		smc->hw.hw_is_64bit = TRUE ;
124	} else {
125		smc->hw.hw_is_64bit = FALSE ;
126	}
127
128	/*
129	 * Watermark initialization
130	 */
131	if (!smc->hw.hw_is_64bit) {
132		outpd(ADDR(B4_R1_F), RX_WATERMARK) ;
133		outpd(ADDR(B5_XA_F), TX_WATERMARK) ;
134		outpd(ADDR(B5_XS_F), TX_WATERMARK) ;
135	}
136
137	outp(ADDR(B0_CTRL),CTRL_RST_CLR) ;	/* clear the reset chips */
138	outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_ON|LED_GB_OFF) ; /* ye LED on */
139
140	/* init the timer value for the watch dog 2,5 minutes */
141	outpd(ADDR(B2_WDOG_INI),0x6FC23AC0) ;
142
143	/* initialize the ISR mask */
144	smc->hw.is_imask = ISR_MASK ;
145	smc->hw.hw_state = STOPPED ;
146#endif
147	GET_PAGE(0) ;		/* necessary for BOOT */
148}
149
150void card_stop(struct s_smc *smc)
151{
152	smt_stop_watchdog(smc) ;
153	smc->hw.mac_ring_is_up = 0 ;		/* ring down */
154
155#ifdef	PCI
156	/*
157	 * make sure no transfer activity is pending
158	 */
159	outpw(FM_A(FM_MDREG1),FM_MINIT) ;
160	outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
161	hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ;
162	/*
163	 * now reset everything
164	 */
165	outp(ADDR(B0_CTRL),CTRL_RST_SET) ;	/* reset for all chips */
166	outp(ADDR(B0_CTRL),CTRL_RST_CLR) ;	/* reset for all chips */
167	outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_OFF|LED_GB_OFF) ; /* all LEDs off */
168	smc->hw.hw_state = STOPPED ;
169#endif
170}
171/*--------------------------- ISR handling ----------------------------------*/
172
173void mac1_irq(struct s_smc *smc, u_short stu, u_short stl)
174{
175	int	restart_tx = 0 ;
176again:
177
178	/*
179	 * parity error: note encoding error is not possible in tag mode
180	 */
181	if (stl & (FM_SPCEPDS  |	/* parity err. syn.q.*/
182		   FM_SPCEPDA0 |	/* parity err. a.q.0 */
183		   FM_SPCEPDA1)) {	/* parity err. a.q.1 */
184		SMT_PANIC(smc,SMT_E0134, SMT_E0134_MSG) ;
185	}
186	/*
187	 * buffer underrun: can only occur if a tx threshold is specified
188	 */
189	if (stl & (FM_STBURS  |		/* tx buffer underrun syn.q.*/
190		   FM_STBURA0 |		/* tx buffer underrun a.q.0 */
191		   FM_STBURA1)) {	/* tx buffer underrun a.q.2 */
192		SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ;
193	}
194
195	if ( (stu & (FM_SXMTABT |		/* transmit abort */
196		     FM_STXABRS |		/* syn. tx abort */
197		     FM_STXABRA0)) ||		/* asyn. tx abort */
198	     (stl & (FM_SQLCKS |		/* lock for syn. q. */
199		     FM_SQLCKA0)) ) {		/* lock for asyn. q. */
200		formac_tx_restart(smc) ;	/* init tx */
201		restart_tx = 1 ;
202		stu = inpw(FM_A(FM_ST1U)) ;
203		stl = inpw(FM_A(FM_ST1L)) ;
204		stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ;
205		if (stu || stl)
206			goto again ;
207	}
208
209	if (stu & (FM_STEFRMA0 |	/* end of asyn tx */
210		    FM_STEFRMS)) {	/* end of sync tx */
211		restart_tx = 1 ;
212	}
213
214	if (restart_tx)
215		llc_restart_tx(smc) ;
216}
217
218/*
219 * interrupt source= plc1
220 * this function is called in nwfbisr.asm
221 */
222void plc1_irq(struct s_smc *smc)
223{
224	u_short	st = inpw(PLC(PB,PL_INTR_EVENT)) ;
225
226	plc_irq(smc,PB,st) ;
227}
228
229/*
230 * interrupt source= plc2
231 * this function is called in nwfbisr.asm
232 */
233void plc2_irq(struct s_smc *smc)
234{
235	u_short	st = inpw(PLC(PA,PL_INTR_EVENT)) ;
236
237	plc_irq(smc,PA,st) ;
238}
239
240
241/*
242 * interrupt source= timer
243 */
244void timer_irq(struct s_smc *smc)
245{
246	hwt_restart(smc);
247	smc->hw.t_stop = smc->hw.t_start;
248	smt_timer_done(smc) ;
249}
250
251/*
252 * return S-port (PA or PB)
253 */
254int pcm_get_s_port(struct s_smc *smc)
255{
256	SK_UNUSED(smc) ;
257	return(PS) ;
258}
259
260/*
261 * Station Label = "FDDI-XYZ" where
262 *
263 *	X = connector type
264 *	Y = PMD type
265 *	Z = port type
266 */
267#define STATION_LABEL_CONNECTOR_OFFSET	5
268#define STATION_LABEL_PMD_OFFSET	6
269#define STATION_LABEL_PORT_OFFSET	7
270
271void read_address(struct s_smc *smc, u_char *mac_addr)
272{
273	char ConnectorType ;
274	char PmdType ;
275	int	i ;
276
277#ifdef	PCI
278	for (i = 0; i < 6; i++) {	/* read mac address from board */
279		smc->hw.fddi_phys_addr.a[i] =
280			bitrev8(inp(ADDR(B2_MAC_0+i)));
281	}
282#endif
283
284	ConnectorType = inp(ADDR(B2_CONN_TYP)) ;
285	PmdType = inp(ADDR(B2_PMD_TYP)) ;
286
287	smc->y[PA].pmd_type[PMD_SK_CONN] =
288	smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ;
289	smc->y[PA].pmd_type[PMD_SK_PMD ] =
290	smc->y[PB].pmd_type[PMD_SK_PMD ] = PmdType ;
291
292	if (mac_addr) {
293		for (i = 0; i < 6 ;i++) {
294			smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ;
295			smc->hw.fddi_home_addr.a[i] = bitrev8(mac_addr[i]);
296		}
297		return ;
298	}
299	smc->hw.fddi_home_addr = smc->hw.fddi_phys_addr ;
300
301	for (i = 0; i < 6 ;i++) {
302		smc->hw.fddi_canon_addr.a[i] =
303			bitrev8(smc->hw.fddi_phys_addr.a[i]);
304	}
305}
306
307/*
308 * FDDI card soft reset
309 */
310void init_board(struct s_smc *smc, u_char *mac_addr)
311{
312	card_start(smc) ;
313	read_address(smc,mac_addr) ;
314
315	if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL))
316		smc->s.sas = SMT_SAS ;	/* Single att. station */
317	else
318		smc->s.sas = SMT_DAS ;	/* Dual att. station */
319
320	if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST))
321		smc->mib.fddiSMTBypassPresent = 0 ;
322		/* without opt. bypass */
323	else
324		smc->mib.fddiSMTBypassPresent = 1 ;
325		/* with opt. bypass */
326}
327
328/*
329 * insert or deinsert optical bypass (called by ECM)
330 */
331void sm_pm_bypass_req(struct s_smc *smc, int mode)
332{
333	DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ?
334					"BP_INSERT" : "BP_DEINSERT",0) ;
335
336	if (smc->s.sas != SMT_DAS)
337		return ;
338
339#ifdef	PCI
340	switch(mode) {
341	case BP_INSERT :
342		outp(ADDR(B0_DAS),DAS_BYP_INS) ;	/* insert station */
343		break ;
344	case BP_DEINSERT :
345		outp(ADDR(B0_DAS),DAS_BYP_RMV) ;	/* bypass station */
346		break ;
347	}
348#endif
349}
350
351/*
352 * check if bypass connected
353 */
354int sm_pm_bypass_present(struct s_smc *smc)
355{
356	return(	(inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ;
357}
358
359void plc_clear_irq(struct s_smc *smc, int p)
360{
361	SK_UNUSED(p) ;
362
363	SK_UNUSED(smc) ;
364}
365
366
367/*
368 * led_indication called by rmt_indication() and
369 * pcm_state_change()
370 *
371 * Input:
372 *	smc:	SMT context
373 *	led_event:
374 *	0	Only switch green LEDs according to their respective PCM state
375 *	LED_Y_OFF	just switch yellow LED off
376 *	LED_Y_ON	just switch yello LED on
377 */
378static void led_indication(struct s_smc *smc, int led_event)
379{
380	/* use smc->hw.mac_ring_is_up == TRUE
381	 * as indication for Ring Operational
382	 */
383	u_short			led_state ;
384	struct s_phy		*phy ;
385	struct fddi_mib_p	*mib_a ;
386	struct fddi_mib_p	*mib_b ;
387
388	phy = &smc->y[PA] ;
389	mib_a = phy->mib ;
390	phy = &smc->y[PB] ;
391	mib_b = phy->mib ;
392
393#ifdef	PCI
394        led_state = 0 ;
395
396	/* Ring up = yellow led OFF*/
397	if (led_event == LED_Y_ON) {
398		led_state |= LED_MY_ON ;
399	}
400	else if (led_event == LED_Y_OFF) {
401		led_state |= LED_MY_OFF ;
402	}
403	else {	/* PCM state changed */
404		/* Link at Port A/S = green led A ON */
405		if (mib_a->fddiPORTPCMState == PC8_ACTIVE) {
406			led_state |= LED_GA_ON ;
407		}
408		else {
409			led_state |= LED_GA_OFF ;
410		}
411
412		/* Link at Port B = green led B ON */
413		if (mib_b->fddiPORTPCMState == PC8_ACTIVE) {
414			led_state |= LED_GB_ON ;
415		}
416		else {
417			led_state |= LED_GB_OFF ;
418		}
419	}
420
421        outp(ADDR(B0_LED), led_state) ;
422#endif	/* PCI */
423
424}
425
426
427void pcm_state_change(struct s_smc *smc, int plc, int p_state)
428{
429	/*
430	 * the current implementation of pcm_state_change() in the driver
431	 * parts must be renamed to drv_pcm_state_change() which will be called
432	 * now after led_indication.
433	 */
434	DRV_PCM_STATE_CHANGE(smc,plc,p_state) ;
435
436	led_indication(smc,0) ;
437}
438
439
440void rmt_indication(struct s_smc *smc, int i)
441{
442	/* Call a driver special function if defined */
443	DRV_RMT_INDICATION(smc,i) ;
444
445        led_indication(smc, i ? LED_Y_OFF : LED_Y_ON) ;
446}
447
448
449/*
450 * llc_recover_tx called by init_tx (fplus.c)
451 */
452void llc_recover_tx(struct s_smc *smc)
453{
454#ifdef	LOAD_GEN
455	extern	int load_gen_flag ;
456
457	load_gen_flag = 0 ;
458#endif
459#ifndef	SYNC
460	smc->hw.n_a_send= 0 ;
461#else
462	SK_UNUSED(smc) ;
463#endif
464}
465
466#ifdef MULT_OEM
467static int is_equal_num(char comp1[], char comp2[], int num)
468{
469	int i ;
470
471	for (i = 0 ; i < num ; i++) {
472		if (comp1[i] != comp2[i])
473			return (0) ;
474	}
475		return (1) ;
476}	/* is_equal_num */
477
478
479/*
480 * set the OEM ID defaults, and test the contents of the OEM data base
481 * The default OEM is the first ACTIVE entry in the OEM data base
482 *
483 * returns:	0	success
484 *		1	error in data base
485 *		2	data base empty
486 *		3	no active entry
487 */
488int set_oi_id_def(struct s_smc *smc)
489{
490	int sel_id ;
491	int i ;
492	int act_entries ;
493
494	i = 0 ;
495	sel_id = -1 ;
496	act_entries = FALSE ;
497	smc->hw.oem_id = 0 ;
498	smc->hw.oem_min_status = OI_STAT_ACTIVE ;
499
500	/* check OEM data base */
501	while (oem_ids[i].oi_status) {
502		switch (oem_ids[i].oi_status) {
503		case OI_STAT_ACTIVE:
504			act_entries = TRUE ;	/* we have active IDs */
505			if (sel_id == -1)
506				sel_id = i ;	/* save the first active ID */
507		case OI_STAT_VALID:
508		case OI_STAT_PRESENT:
509			i++ ;
510			break ;			/* entry ok */
511		default:
512			return (1) ;		/* invalid oi_status */
513		}
514	}
515
516	if (i == 0)
517		return (2) ;
518	if (!act_entries)
519		return (3) ;
520
521	/* ok, we have a valid OEM data base with an active entry */
522	smc->hw.oem_id = (struct s_oem_ids *)  &oem_ids[sel_id] ;
523	return (0) ;
524}
525#endif	/* MULT_OEM */
526
527void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr)
528{
529	int i ;
530
531	for (i = 0 ; i < 6 ; i++)
532		bia_addr->a[i] = bitrev8(smc->hw.fddi_phys_addr.a[i]);
533}
534
535void smt_start_watchdog(struct s_smc *smc)
536{
537	SK_UNUSED(smc) ;	/* Make LINT happy. */
538
539#ifndef	DEBUG
540
541#ifdef	PCI
542	if (smc->hw.wdog_used) {
543		outpw(ADDR(B2_WDOG_CRTL),TIM_START) ;	/* Start timer. */
544	}
545#endif
546
547#endif	/* DEBUG */
548}
549
550static void smt_stop_watchdog(struct s_smc *smc)
551{
552	SK_UNUSED(smc) ;	/* Make LINT happy. */
553#ifndef	DEBUG
554
555#ifdef	PCI
556	if (smc->hw.wdog_used) {
557		outpw(ADDR(B2_WDOG_CRTL),TIM_STOP) ;	/* Stop timer. */
558	}
559#endif
560
561#endif	/* DEBUG */
562}
563
564#ifdef	PCI
565
566void mac_do_pci_fix(struct s_smc *smc)
567{
568	SK_UNUSED(smc) ;
569}
570#endif	/* PCI */
571