OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [net/] [skfp/] [pcmplc.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/******************************************************************************
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
        PCM
19
        Physical Connection Management
20
*/
21
 
22
/*
23
 * Hardware independent state machine implemantation
24
 * The following external SMT functions are referenced :
25
 *
26
 *              queue_event()
27
 *              smt_timer_start()
28
 *              smt_timer_stop()
29
 *
30
 *      The following external HW dependent functions are referenced :
31
 *              sm_pm_control()
32
 *              sm_ph_linestate()
33
 *              sm_pm_ls_latch()
34
 *
35
 *      The following HW dependent events are required :
36
 *              PC_QLS
37
 *              PC_ILS
38
 *              PC_HLS
39
 *              PC_MLS
40
 *              PC_NSE
41
 *              PC_LEM
42
 *
43
 */
44
 
45
 
46
#include "h/types.h"
47
#include "h/fddi.h"
48
#include "h/smc.h"
49
#include "h/supern_2.h"
50
#define KERNEL
51
#include "h/smtstate.h"
52
 
53
#ifndef lint
54
static const char ID_sccs[] = "@(#)pcmplc.c     2.55 99/08/05 (C) SK " ;
55
#endif
56
 
57
#ifdef  FDDI_MIB
58
extern int snmp_fddi_trap(
59
#ifdef  ANSIC
60
struct s_smc    * smc, int  type, int  index
61
#endif
62
);
63
#endif
64
#ifdef  CONCENTRATOR
65
extern int plc_is_installed(
66
#ifdef  ANSIC
67
struct s_smc *smc ,
68
int p
69
#endif
70
) ;
71
#endif
72
/*
73
 * FSM Macros
74
 */
75
#define AFLAG           (0x20)
76
#define GO_STATE(x)     (mib->fddiPORTPCMState = (x)|AFLAG)
77
#define ACTIONS_DONE()  (mib->fddiPORTPCMState &= ~AFLAG)
78
#define ACTIONS(x)      (x|AFLAG)
79
 
80
/*
81
 * PCM states
82
 */
83
#define PC0_OFF                 0
84
#define PC1_BREAK               1
85
#define PC2_TRACE               2
86
#define PC3_CONNECT             3
87
#define PC4_NEXT                4
88
#define PC5_SIGNAL              5
89
#define PC6_JOIN                6
90
#define PC7_VERIFY              7
91
#define PC8_ACTIVE              8
92
#define PC9_MAINT               9
93
 
94
#ifdef  DEBUG
95
/*
96
 * symbolic state names
97
 */
98
static const char * const pcm_states[] =  {
99
        "PC0_OFF","PC1_BREAK","PC2_TRACE","PC3_CONNECT","PC4_NEXT",
100
        "PC5_SIGNAL","PC6_JOIN","PC7_VERIFY","PC8_ACTIVE","PC9_MAINT"
101
} ;
102
 
103
/*
104
 * symbolic event names
105
 */
106
static const char * const pcm_events[] = {
107
        "NONE","PC_START","PC_STOP","PC_LOOP","PC_JOIN","PC_SIGNAL",
108
        "PC_REJECT","PC_MAINT","PC_TRACE","PC_PDR",
109
        "PC_ENABLE","PC_DISABLE",
110
        "PC_QLS","PC_ILS","PC_MLS","PC_HLS","PC_LS_PDR","PC_LS_NONE",
111
        "PC_TIMEOUT_TB_MAX","PC_TIMEOUT_TB_MIN",
112
        "PC_TIMEOUT_C_MIN","PC_TIMEOUT_T_OUT",
113
        "PC_TIMEOUT_TL_MIN","PC_TIMEOUT_T_NEXT","PC_TIMEOUT_LCT",
114
        "PC_NSE","PC_LEM"
115
} ;
116
#endif
117
 
118
#ifdef  MOT_ELM
119
/*
120
 * PCL-S control register
121
 * this register in the PLC-S controls the scrambling parameters
122
 */
123
#define PLCS_CONTROL_C_U        0
124
#define PLCS_CONTROL_C_S        (PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \
125
                                 PL_C_CIPHER_ENABLE)
126
#define PLCS_FASSERT_U          0
127
#define PLCS_FASSERT_S          0xFd76  /* 52.0 us */
128
#define PLCS_FDEASSERT_U        0
129
#define PLCS_FDEASSERT_S        0
130
#else   /* nMOT_ELM */
131
/*
132
 * PCL-S control register
133
 * this register in the PLC-S controls the scrambling parameters
134
 * can be patched for ANSI compliance if standard changes
135
 */
136
static const u_char plcs_control_c_u[17] = "PLC_CNTRL_C_U=\0\0" ;
137
static const u_char plcs_control_c_s[17] = "PLC_CNTRL_C_S=\01\02" ;
138
 
139
#define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8))
140
#define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8))
141
#endif  /* nMOT_ELM */
142
 
143
/*
144
 * external vars
145
 */
146
/* struct definition see 'cmtdef.h' (also used by CFM) */
147
 
148
#define PS_OFF          0
149
#define PS_BIT3         1
150
#define PS_BIT4         2
151
#define PS_BIT7         3
152
#define PS_LCT          4
153
#define PS_BIT8         5
154
#define PS_JOIN         6
155
#define PS_ACTIVE       7
156
 
157
#define LCT_LEM_MAX     255
158
 
159
/*
160
 * PLC timing parameter
161
 */
162
 
163
#define PLC_MS(m)       ((int)((0x10000L-(m*100000L/2048))))
164
#define SLOW_TL_MIN     PLC_MS(6)
165
#define SLOW_C_MIN      PLC_MS(10)
166
 
167
static  const struct plt {
168
        int     timer ;                 /* relative plc timer address */
169
        int     para ;                  /* default timing parameters */
170
} pltm[] = {
171
        { PL_C_MIN, SLOW_C_MIN },       /* min t. to remain Connect State */
172
        { PL_TL_MIN, SLOW_TL_MIN },     /* min t. to transmit a Line State */
173
        { PL_TB_MIN, TP_TB_MIN },       /* min break time */
174
        { PL_T_OUT, TP_T_OUT },         /* Signaling timeout */
175
        { PL_LC_LENGTH, TP_LC_LENGTH }, /* Link Confidence Test Time */
176
        { PL_T_SCRUB, TP_T_SCRUB },     /* Scrub Time == MAC TVX time ! */
177
        { PL_NS_MAX, TP_NS_MAX },       /* max t. that noise is tolerated */
178
        { 0,0 }
179
} ;
180
 
181
/*
182
 * interrupt mask
183
 */
184
#ifdef  SUPERNET_3
185
/*
186
 * Do we need the EBUF error during signaling, too, to detect SUPERNET_3
187
 * PLL bug?
188
 */
189
static const int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
190
                        PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
191
#else   /* SUPERNET_3 */
192
/*
193
 * We do NOT need the elasticity buffer error during signaling.
194
 */
195
static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
196
                        PL_PCM_ENABLED | PL_SELF_TEST ;
197
#endif  /* SUPERNET_3 */
198
static const int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
199
                        PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
200
 
201
/* external functions */
202
void all_selection_criteria(struct s_smc *smc);
203
 
204
/* internal functions */
205
static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd);
206
static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy);
207
static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy);
208
static void reset_lem_struct(struct s_phy *phy);
209
static void plc_init(struct s_smc *smc, int p);
210
static void sm_ph_lem_start(struct s_smc *smc, int np, int threshold);
211
static void sm_ph_lem_stop(struct s_smc *smc, int np);
212
static void sm_ph_linestate(struct s_smc *smc, int phy, int ls);
213
static void real_init_plc(struct s_smc *smc);
214
 
215
/*
216
 * SMT timer interface
217
 *      start PCM timer 0
218
 */
219
static void start_pcm_timer0(struct s_smc *smc, u_long value, int event,
220
                             struct s_phy *phy)
221
{
222
        phy->timer0_exp = FALSE ;       /* clear timer event flag */
223
        smt_timer_start(smc,&phy->pcm_timer0,value,
224
                EV_TOKEN(EVENT_PCM+phy->np,event)) ;
225
}
226
/*
227
 * SMT timer interface
228
 *      stop PCM timer 0
229
 */
230
static void stop_pcm_timer0(struct s_smc *smc, struct s_phy *phy)
231
{
232
        if (phy->pcm_timer0.tm_active)
233
                smt_timer_stop(smc,&phy->pcm_timer0) ;
234
}
235
 
236
/*
237
        init PCM state machine (called by driver)
238
        clear all PCM vars and flags
239
*/
240
void pcm_init(struct s_smc *smc)
241
{
242
        int             i ;
243
        int             np ;
244
        struct s_phy    *phy ;
245
        struct fddi_mib_p       *mib ;
246
 
247
        for (np = 0,phy = smc->y ; np < NUMPHYS ; np++,phy++) {
248
                /* Indicates the type of PHY being used */
249
                mib = phy->mib ;
250
                mib->fddiPORTPCMState = ACTIONS(PC0_OFF) ;
251
                phy->np = np ;
252
                switch (smc->s.sas) {
253
#ifdef  CONCENTRATOR
254
                case SMT_SAS :
255
                        mib->fddiPORTMy_Type = (np == PS) ? TS : TM ;
256
                        break ;
257
                case SMT_DAS :
258
                        mib->fddiPORTMy_Type = (np == PA) ? TA :
259
                                        (np == PB) ? TB : TM ;
260
                        break ;
261
                case SMT_NAC :
262
                        mib->fddiPORTMy_Type = TM ;
263
                        break;
264
#else
265
                case SMT_SAS :
266
                        mib->fddiPORTMy_Type = (np == PS) ? TS : TNONE ;
267
                        mib->fddiPORTHardwarePresent = (np == PS) ? TRUE :
268
                                        FALSE ;
269
#ifndef SUPERNET_3
270
                        smc->y[PA].mib->fddiPORTPCMState = PC0_OFF ;
271
#else
272
                        smc->y[PB].mib->fddiPORTPCMState = PC0_OFF ;
273
#endif
274
                        break ;
275
                case SMT_DAS :
276
                        mib->fddiPORTMy_Type = (np == PB) ? TB : TA ;
277
                        break ;
278
#endif
279
                }
280
                /*
281
                 * set PMD-type
282
                 */
283
                phy->pmd_scramble = 0 ;
284
                switch (phy->pmd_type[PMD_SK_PMD]) {
285
                case 'P' :
286
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ;
287
                        break ;
288
                case 'L' :
289
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_LCF ;
290
                        break ;
291
                case 'D' :
292
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
293
                        break ;
294
                case 'S' :
295
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
296
                        phy->pmd_scramble = TRUE ;
297
                        break ;
298
                case 'U' :
299
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
300
                        phy->pmd_scramble = TRUE ;
301
                        break ;
302
                case '1' :
303
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
304
                        break ;
305
                case '2' :
306
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
307
                        break ;
308
                case '3' :
309
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
310
                        break ;
311
                case '4' :
312
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
313
                        break ;
314
                case 'H' :
315
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
316
                        break ;
317
                case 'I' :
318
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
319
                        break ;
320
                case 'G' :
321
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
322
                        break ;
323
                default:
324
                        mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
325
                        break ;
326
                }
327
                /*
328
                 * A and B port can be on primary and secondary path
329
                 */
330
                switch (mib->fddiPORTMy_Type) {
331
                case TA :
332
                        mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
333
                        mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
334
                        mib->fddiPORTRequestedPaths[2] =
335
                                MIB_P_PATH_LOCAL |
336
                                MIB_P_PATH_CON_ALTER |
337
                                MIB_P_PATH_SEC_PREFER ;
338
                        mib->fddiPORTRequestedPaths[3] =
339
                                MIB_P_PATH_LOCAL |
340
                                MIB_P_PATH_CON_ALTER |
341
                                MIB_P_PATH_SEC_PREFER |
342
                                MIB_P_PATH_THRU ;
343
                        break ;
344
                case TB :
345
                        mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
346
                        mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
347
                        mib->fddiPORTRequestedPaths[2] =
348
                                MIB_P_PATH_LOCAL |
349
                                MIB_P_PATH_PRIM_PREFER ;
350
                        mib->fddiPORTRequestedPaths[3] =
351
                                MIB_P_PATH_LOCAL |
352
                                MIB_P_PATH_PRIM_PREFER |
353
                                MIB_P_PATH_CON_PREFER |
354
                                MIB_P_PATH_THRU ;
355
                        break ;
356
                case TS :
357
                        mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
358
                        mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
359
                        mib->fddiPORTRequestedPaths[2] =
360
                                MIB_P_PATH_LOCAL |
361
                                MIB_P_PATH_CON_ALTER |
362
                                MIB_P_PATH_PRIM_PREFER ;
363
                        mib->fddiPORTRequestedPaths[3] =
364
                                MIB_P_PATH_LOCAL |
365
                                MIB_P_PATH_CON_ALTER |
366
                                MIB_P_PATH_PRIM_PREFER ;
367
                        break ;
368
                case TM :
369
                        mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
370
                        mib->fddiPORTRequestedPaths[2] =
371
                                MIB_P_PATH_LOCAL |
372
                                MIB_P_PATH_SEC_ALTER |
373
                                MIB_P_PATH_PRIM_ALTER ;
374
                        mib->fddiPORTRequestedPaths[3] = 0 ;
375
                        break ;
376
                }
377
 
378
                phy->pc_lem_fail = FALSE ;
379
                mib->fddiPORTPCMStateX = mib->fddiPORTPCMState ;
380
                mib->fddiPORTLCTFail_Ct = 0 ;
381
                mib->fddiPORTBS_Flag = 0 ;
382
                mib->fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
383
                mib->fddiPORTNeighborType = TNONE ;
384
                phy->ls_flag = 0 ;
385
                phy->rc_flag = 0 ;
386
                phy->tc_flag = 0 ;
387
                phy->td_flag = 0 ;
388
                if (np >= PM)
389
                        phy->phy_name = '0' + np - PM ;
390
                else
391
                        phy->phy_name = 'A' + np ;
392
                phy->wc_flag = FALSE ;          /* set by SMT */
393
                memset((char *)&phy->lem,0,sizeof(struct lem_counter)) ;
394
                reset_lem_struct(phy) ;
395
                memset((char *)&phy->plc,0,sizeof(struct s_plc)) ;
396
                phy->plc.p_state = PS_OFF ;
397
                for (i = 0 ; i < NUMBITS ; i++) {
398
                        phy->t_next[i] = 0 ;
399
                }
400
        }
401
        real_init_plc(smc) ;
402
}
403
 
404
void init_plc(struct s_smc *smc)
405
{
406
        SK_UNUSED(smc) ;
407
 
408
        /*
409
         * dummy
410
         * this is an obsolete public entry point that has to remain
411
         * for compat. It is used by various drivers.
412
         * the work is now done in real_init_plc()
413
         * which is called from pcm_init() ;
414
         */
415
}
416
 
417
static void real_init_plc(struct s_smc *smc)
418
{
419
        int     p ;
420
 
421
        for (p = 0 ; p < NUMPHYS ; p++)
422
                plc_init(smc,p) ;
423
}
424
 
425
static void plc_init(struct s_smc *smc, int p)
426
{
427
        int     i ;
428
#ifndef MOT_ELM
429
        int     rev ;   /* Revision of PLC-x */
430
#endif  /* MOT_ELM */
431
 
432
        /* transit PCM state machine to MAINT state */
433
        outpw(PLC(p,PL_CNTRL_B),0) ;
434
        outpw(PLC(p,PL_CNTRL_B),PL_PCM_STOP) ;
435
        outpw(PLC(p,PL_CNTRL_A),0) ;
436
 
437
        /*
438
         * if PLC-S then set control register C
439
         */
440
#ifndef MOT_ELM
441
        rev = inpw(PLC(p,PL_STATUS_A)) & PLC_REV_MASK ;
442
        if (rev != PLC_REVISION_A)
443
#endif  /* MOT_ELM */
444
        {
445
                if (smc->y[p].pmd_scramble) {
446
                        outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_S) ;
447
#ifdef  MOT_ELM
448
                        outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_S) ;
449
                        outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_S) ;
450
#endif  /* MOT_ELM */
451
                }
452
                else {
453
                        outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_U) ;
454
#ifdef  MOT_ELM
455
                        outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_U) ;
456
                        outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_U) ;
457
#endif  /* MOT_ELM */
458
                }
459
        }
460
 
461
        /*
462
         * set timer register
463
         */
464
        for ( i = 0 ; pltm[i].timer; i++)        /* set timer parameter reg */
465
                outpw(PLC(p,pltm[i].timer),pltm[i].para) ;
466
 
467
        (void)inpw(PLC(p,PL_INTR_EVENT)) ;      /* clear interrupt event reg */
468
        plc_clear_irq(smc,p) ;
469
        outpw(PLC(p,PL_INTR_MASK),plc_imsk_na); /* enable non active irq's */
470
 
471
        /*
472
         * if PCM is configured for class s, it will NOT go to the
473
         * REMOVE state if offline (page 3-36;)
474
         * in the concentrator, all inactive PHYS always must be in
475
         * the remove state
476
         * there's no real need to use this feature at all ..
477
         */
478
#ifndef CONCENTRATOR
479
        if ((smc->s.sas == SMT_SAS) && (p == PS)) {
480
                outpw(PLC(p,PL_CNTRL_B),PL_CLASS_S) ;
481
        }
482
#endif
483
}
484
 
485
/*
486
 * control PCM state machine
487
 */
488
static void plc_go_state(struct s_smc *smc, int p, int state)
489
{
490
        HW_PTR port ;
491
        int val ;
492
 
493
        SK_UNUSED(smc) ;
494
 
495
        port = (HW_PTR) (PLC(p,PL_CNTRL_B)) ;
496
        val = inpw(port) & ~(PL_PCM_CNTRL | PL_MAINT) ;
497
        outpw(port,val) ;
498
        outpw(port,val | state) ;
499
}
500
 
501
/*
502
 * read current line state (called by ECM & PCM)
503
 */
504
int sm_pm_get_ls(struct s_smc *smc, int phy)
505
{
506
        int     state ;
507
 
508
#ifdef  CONCENTRATOR
509
        if (!plc_is_installed(smc,phy))
510
                return(PC_QLS) ;
511
#endif
512
 
513
        state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ;
514
        switch(state) {
515
        case PL_L_QLS:
516
                state = PC_QLS ;
517
                break ;
518
        case PL_L_MLS:
519
                state = PC_MLS ;
520
                break ;
521
        case PL_L_HLS:
522
                state = PC_HLS ;
523
                break ;
524
        case PL_L_ILS4:
525
        case PL_L_ILS16:
526
                state = PC_ILS ;
527
                break ;
528
        case PL_L_ALS:
529
                state = PC_LS_PDR ;
530
                break ;
531
        default :
532
                state = PC_LS_NONE ;
533
        }
534
        return(state) ;
535
}
536
 
537
static int plc_send_bits(struct s_smc *smc, struct s_phy *phy, int len)
538
{
539
        int np = phy->np ;              /* PHY index */
540
        int     n ;
541
        int     i ;
542
 
543
        SK_UNUSED(smc) ;
544
 
545
        /* create bit vector */
546
        for (i = len-1,n = 0 ; i >= 0 ; i--) {
547
                n = (n<<1) | phy->t_val[phy->bitn+i] ;
548
        }
549
        if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) {
550
#if     0
551
                printf("PL_PCM_SIGNAL is set\n") ;
552
#endif
553
                return(1) ;
554
        }
555
        /* write bit[n] & length = 1 to regs */
556
        outpw(PLC(np,PL_VECTOR_LEN),len-1) ;    /* len=nr-1 */
557
        outpw(PLC(np,PL_XMIT_VECTOR),n) ;
558
#ifdef  DEBUG
559
#if 1
560
#ifdef  DEBUG_BRD
561
        if (smc->debug.d_plc & 0x80)
562
#else
563
        if (debug.d_plc & 0x80)
564
#endif
565
                printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ;
566
#endif
567
#endif
568
        return(0) ;
569
}
570
 
571
/*
572
 * config plc muxes
573
 */
574
void plc_config_mux(struct s_smc *smc, int mux)
575
{
576
        if (smc->s.sas != SMT_DAS)
577
                return ;
578
        if (mux == MUX_WRAPB) {
579
                SETMASK(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ;
580
                SETMASK(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP,PL_SC_REM_LOOP) ;
581
        }
582
        else {
583
                CLEAR(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL) ;
584
                CLEAR(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP) ;
585
        }
586
        CLEAR(PLC(PB,PL_CNTRL_B),PL_CONFIG_CNTRL) ;
587
        CLEAR(PLC(PB,PL_CNTRL_A),PL_SC_REM_LOOP) ;
588
}
589
 
590
/*
591
        PCM state machine
592
        called by dispatcher  & fddi_init() (driver)
593
        do
594
                display state change
595
                process event
596
        until SM is stable
597
*/
598
void pcm(struct s_smc *smc, const int np, int event)
599
{
600
        int     state ;
601
        int     oldstate ;
602
        struct s_phy    *phy ;
603
        struct fddi_mib_p       *mib ;
604
 
605
#ifndef CONCENTRATOR
606
        /*
607
         * ignore 2nd PHY if SAS
608
         */
609
        if ((np != PS) && (smc->s.sas == SMT_SAS))
610
                return ;
611
#endif
612
        phy = &smc->y[np] ;
613
        mib = phy->mib ;
614
        oldstate = mib->fddiPORTPCMState ;
615
        do {
616
                DB_PCM("PCM %c: state %s",
617
                        phy->phy_name,
618
                        (mib->fddiPORTPCMState & AFLAG) ? "ACTIONS " : "") ;
619
                DB_PCM("%s, event %s\n",
620
                        pcm_states[mib->fddiPORTPCMState & ~AFLAG],
621
                        pcm_events[event]) ;
622
                state = mib->fddiPORTPCMState ;
623
                pcm_fsm(smc,phy,event) ;
624
                event = 0 ;
625
        } while (state != mib->fddiPORTPCMState) ;
626
        /*
627
         * because the PLC does the bit signaling for us,
628
         * we're always in SIGNAL state
629
         * the MIB want's to see CONNECT
630
         * we therefore fake an entry in the MIB
631
         */
632
        if (state == PC5_SIGNAL)
633
                mib->fddiPORTPCMStateX = PC3_CONNECT ;
634
        else
635
                mib->fddiPORTPCMStateX = state ;
636
 
637
#ifndef SLIM_SMT
638
        /*
639
         * path change
640
         */
641
        if (    mib->fddiPORTPCMState != oldstate &&
642
                ((oldstate == PC8_ACTIVE) || (mib->fddiPORTPCMState == PC8_ACTIVE))) {
643
                smt_srf_event(smc,SMT_EVENT_PORT_PATH_CHANGE,
644
                        (int) (INDEX_PORT+ phy->np),0) ;
645
        }
646
#endif
647
 
648
#ifdef FDDI_MIB
649
        /* check whether a snmp-trap has to be sent */
650
 
651
        if ( mib->fddiPORTPCMState != oldstate ) {
652
                /* a real state change took place */
653
                DB_SNMP ("PCM from %d to %d\n", oldstate, mib->fddiPORTPCMState);
654
                if ( mib->fddiPORTPCMState == PC0_OFF ) {
655
                        /* send first trap */
656
                        snmp_fddi_trap (smc, 1, (int) mib->fddiPORTIndex );
657
                } else if ( oldstate == PC0_OFF ) {
658
                        /* send second trap */
659
                        snmp_fddi_trap (smc, 2, (int) mib->fddiPORTIndex );
660
                } else if ( mib->fddiPORTPCMState != PC2_TRACE &&
661
                        oldstate == PC8_ACTIVE ) {
662
                        /* send third trap */
663
                        snmp_fddi_trap (smc, 3, (int) mib->fddiPORTIndex );
664
                } else if ( mib->fddiPORTPCMState == PC8_ACTIVE ) {
665
                        /* send fourth trap */
666
                        snmp_fddi_trap (smc, 4, (int) mib->fddiPORTIndex );
667
                }
668
        }
669
#endif
670
 
671
        pcm_state_change(smc,np,state) ;
672
}
673
 
674
/*
675
 * PCM state machine
676
 */
677
static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd)
678
{
679
        int     i ;
680
        int     np = phy->np ;          /* PHY index */
681
        struct s_plc    *plc ;
682
        struct fddi_mib_p       *mib ;
683
#ifndef MOT_ELM
684
        u_short plc_rev ;               /* Revision of the plc */
685
#endif  /* nMOT_ELM */
686
 
687
        plc = &phy->plc ;
688
        mib = phy->mib ;
689
 
690
        /*
691
         * general transitions independent of state
692
         */
693
        switch (cmd) {
694
        case PC_STOP :
695
                /*PC00-PC80*/
696
                if (mib->fddiPORTPCMState != PC9_MAINT) {
697
                        GO_STATE(PC0_OFF) ;
698
                        AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
699
                                FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP,
700
                                smt_get_port_event_word(smc));
701
                }
702
                return ;
703
        case PC_START :
704
                /*PC01-PC81*/
705
                if (mib->fddiPORTPCMState != PC9_MAINT)
706
                        GO_STATE(PC1_BREAK) ;
707
                return ;
708
        case PC_DISABLE :
709
                /* PC09-PC99 */
710
                GO_STATE(PC9_MAINT) ;
711
                AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
712
                        FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED,
713
                        smt_get_port_event_word(smc));
714
                return ;
715
        case PC_TIMEOUT_LCT :
716
                /* if long or extended LCT */
717
                stop_pcm_timer0(smc,phy) ;
718
                CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
719
                /* end of LCT is indicate by PCM_CODE (initiate PCM event) */
720
                return ;
721
        }
722
 
723
        switch(mib->fddiPORTPCMState) {
724
        case ACTIONS(PC0_OFF) :
725
                stop_pcm_timer0(smc,phy) ;
726
                outpw(PLC(np,PL_CNTRL_A),0) ;
727
                CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
728
                CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
729
                sm_ph_lem_stop(smc,np) ;                /* disable LEM */
730
                phy->cf_loop = FALSE ;
731
                phy->cf_join = FALSE ;
732
                queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
733
                plc_go_state(smc,np,PL_PCM_STOP) ;
734
                mib->fddiPORTConnectState = PCM_DISABLED ;
735
                ACTIONS_DONE() ;
736
                break ;
737
        case PC0_OFF:
738
                /*PC09*/
739
                if (cmd == PC_MAINT) {
740
                        GO_STATE(PC9_MAINT) ;
741
                        break ;
742
                }
743
                break ;
744
        case ACTIONS(PC1_BREAK) :
745
                /* Stop the LCT timer if we came from Signal state */
746
                stop_pcm_timer0(smc,phy) ;
747
                ACTIONS_DONE() ;
748
                plc_go_state(smc,np,0) ;
749
                CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
750
                CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
751
                sm_ph_lem_stop(smc,np) ;                /* disable LEM */
752
                /*
753
                 * if vector is already loaded, go to OFF to clear PCM_SIGNAL
754
                 */
755
#if     0
756
                if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) {
757
                        plc_go_state(smc,np,PL_PCM_STOP) ;
758
                        /* TB_MIN ? */
759
                }
760
#endif
761
                /*
762
                 * Go to OFF state in any case.
763
                 */
764
                plc_go_state(smc,np,PL_PCM_STOP) ;
765
 
766
                if (mib->fddiPORTPC_Withhold == PC_WH_NONE)
767
                        mib->fddiPORTConnectState = PCM_CONNECTING ;
768
                phy->cf_loop = FALSE ;
769
                phy->cf_join = FALSE ;
770
                queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
771
                phy->ls_flag = FALSE ;
772
                phy->pc_mode = PM_NONE ;        /* needed by CFM */
773
                phy->bitn = 0 ;                  /* bit signaling start bit */
774
                for (i = 0 ; i < 3 ; i++)
775
                        pc_tcode_actions(smc,i,phy) ;
776
 
777
                /* Set the non-active interrupt mask register */
778
                outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ;
779
 
780
                /*
781
                 * If the LCT was stopped. There might be a
782
                 * PCM_CODE interrupt event present.
783
                 * This must be cleared.
784
                 */
785
                (void)inpw(PLC(np,PL_INTR_EVENT)) ;
786
#ifndef MOT_ELM
787
                /* Get the plc revision for revision dependent code */
788
                plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ;
789
 
790
                if (plc_rev != PLC_REV_SN3)
791
#endif  /* MOT_ELM */
792
                {
793
                        /*
794
                         * No supernet III PLC, so set Xmit verctor and
795
                         * length BEFORE starting the state machine.
796
                         */
797
                        if (plc_send_bits(smc,phy,3)) {
798
                                return ;
799
                        }
800
                }
801
 
802
                /*
803
                 * Now give the Start command.
804
                 * - The start command shall be done before setting the bits
805
                 *   to be signaled. (In PLC-S description and PLCS in SN3.
806
                 * - The start command shall be issued AFTER setting the
807
                 *   XMIT vector and the XMIT length register.
808
                 *
809
                 * We do it exactly according this specs for the old PLC and
810
                 * the new PLCS inside the SN3.
811
                 * For the usual PLCS we try it the way it is done for the
812
                 * old PLC and set the XMIT registers again, if the PLC is
813
                 * not in SIGNAL state. This is done according to an PLCS
814
                 * errata workaround.
815
                 */
816
 
817
                plc_go_state(smc,np,PL_PCM_START) ;
818
 
819
                /*
820
                 * workaround for PLC-S eng. sample errata
821
                 */
822
#ifdef  MOT_ELM
823
                if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL))
824
#else   /* nMOT_ELM */
825
                if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) !=
826
                        PLC_REVISION_A) &&
827
                        !(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL))
828
#endif  /* nMOT_ELM */
829
                {
830
                        /*
831
                         * Set register again (PLCS errata) or the first time
832
                         * (new SN3 PLCS).
833
                         */
834
                        (void) plc_send_bits(smc,phy,3) ;
835
                }
836
                /*
837
                 * end of workaround
838
                 */
839
 
840
                GO_STATE(PC5_SIGNAL) ;
841
                plc->p_state = PS_BIT3 ;
842
                plc->p_bits = 3 ;
843
                plc->p_start = 0 ;
844
 
845
                break ;
846
        case PC1_BREAK :
847
                break ;
848
        case ACTIONS(PC2_TRACE) :
849
                plc_go_state(smc,np,PL_PCM_TRACE) ;
850
                ACTIONS_DONE() ;
851
                break ;
852
        case PC2_TRACE :
853
                break ;
854
 
855
        case PC3_CONNECT :      /* these states are done by hardware */
856
        case PC4_NEXT :
857
                break ;
858
 
859
        case ACTIONS(PC5_SIGNAL) :
860
                ACTIONS_DONE() ;
861
        case PC5_SIGNAL :
862
                if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT))
863
                        break ;
864
                switch (plc->p_state) {
865
                case PS_BIT3 :
866
                        for (i = 0 ; i <= 2 ; i++)
867
                                pc_rcode_actions(smc,i,phy) ;
868
                        pc_tcode_actions(smc,3,phy) ;
869
                        plc->p_state = PS_BIT4 ;
870
                        plc->p_bits = 1 ;
871
                        plc->p_start = 3 ;
872
                        phy->bitn = 3 ;
873
                        if (plc_send_bits(smc,phy,1)) {
874
                                return ;
875
                        }
876
                        break ;
877
                case PS_BIT4 :
878
                        pc_rcode_actions(smc,3,phy) ;
879
                        for (i = 4 ; i <= 6 ; i++)
880
                                pc_tcode_actions(smc,i,phy) ;
881
                        plc->p_state = PS_BIT7 ;
882
                        plc->p_bits = 3 ;
883
                        plc->p_start = 4 ;
884
                        phy->bitn = 4 ;
885
                        if (plc_send_bits(smc,phy,3)) {
886
                                return ;
887
                        }
888
                        break ;
889
                case PS_BIT7 :
890
                        for (i = 3 ; i <= 6 ; i++)
891
                                pc_rcode_actions(smc,i,phy) ;
892
                        plc->p_state = PS_LCT ;
893
                        plc->p_bits = 0 ;
894
                        plc->p_start = 7 ;
895
                        phy->bitn = 7 ;
896
                sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */
897
                        /* start LCT */
898
                        i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ;
899
                        outpw(PLC(np,PL_CNTRL_B),i) ;   /* must be cleared */
900
                        outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ;
901
                        break ;
902
                case PS_LCT :
903
                        /* check for local LCT failure */
904
                        pc_tcode_actions(smc,7,phy) ;
905
                        /*
906
                         * set tval[7]
907
                         */
908
                        plc->p_state = PS_BIT8 ;
909
                        plc->p_bits = 1 ;
910
                        plc->p_start = 7 ;
911
                        phy->bitn = 7 ;
912
                        if (plc_send_bits(smc,phy,1)) {
913
                                return ;
914
                        }
915
                        break ;
916
                case PS_BIT8 :
917
                        /* check for remote LCT failure */
918
                        pc_rcode_actions(smc,7,phy) ;
919
                        if (phy->t_val[7] || phy->r_val[7]) {
920
                                plc_go_state(smc,np,PL_PCM_STOP) ;
921
                                GO_STATE(PC1_BREAK) ;
922
                                break ;
923
                        }
924
                        for (i = 8 ; i <= 9 ; i++)
925
                                pc_tcode_actions(smc,i,phy) ;
926
                        plc->p_state = PS_JOIN ;
927
                        plc->p_bits = 2 ;
928
                        plc->p_start = 8 ;
929
                        phy->bitn = 8 ;
930
                        if (plc_send_bits(smc,phy,2)) {
931
                                return ;
932
                        }
933
                        break ;
934
                case PS_JOIN :
935
                        for (i = 8 ; i <= 9 ; i++)
936
                                pc_rcode_actions(smc,i,phy) ;
937
                        plc->p_state = PS_ACTIVE ;
938
                        GO_STATE(PC6_JOIN) ;
939
                        break ;
940
                }
941
                break ;
942
 
943
        case ACTIONS(PC6_JOIN) :
944
                /*
945
                 * prevent mux error when going from WRAP_A to WRAP_B
946
                 */
947
                if (smc->s.sas == SMT_DAS && np == PB &&
948
                        (smc->y[PA].pc_mode == PM_TREE ||
949
                         smc->y[PB].pc_mode == PM_TREE)) {
950
                        SETMASK(PLC(np,PL_CNTRL_A),
951
                                PL_SC_REM_LOOP,PL_SC_REM_LOOP) ;
952
                        SETMASK(PLC(np,PL_CNTRL_B),
953
                                PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ;
954
                }
955
                SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
956
                SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
957
                ACTIONS_DONE() ;
958
                cmd = 0 ;
959
                /* fall thru */
960
        case PC6_JOIN :
961
                switch (plc->p_state) {
962
                case PS_ACTIVE:
963
                        /*PC88b*/
964
                        if (!phy->cf_join) {
965
                                phy->cf_join = TRUE ;
966
                                queue_event(smc,EVENT_CFM,CF_JOIN+np) ; ;
967
                        }
968
                        if (cmd == PC_JOIN)
969
                                GO_STATE(PC8_ACTIVE) ;
970
                        /*PC82*/
971
                        if (cmd == PC_TRACE) {
972
                                GO_STATE(PC2_TRACE) ;
973
                                break ;
974
                        }
975
                        break ;
976
                }
977
                break ;
978
 
979
        case PC7_VERIFY :
980
                break ;
981
 
982
        case ACTIONS(PC8_ACTIVE) :
983
                /*
984
                 * start LEM for SMT
985
                 */
986
                sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ;
987
 
988
                phy->tr_flag = FALSE ;
989
                mib->fddiPORTConnectState = PCM_ACTIVE ;
990
 
991
                /* Set the active interrupt mask register */
992
                outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ;
993
 
994
                ACTIONS_DONE() ;
995
                break ;
996
        case PC8_ACTIVE :
997
                /*PC81 is done by PL_TNE_EXPIRED irq */
998
                /*PC82*/
999
                if (cmd == PC_TRACE) {
1000
                        GO_STATE(PC2_TRACE) ;
1001
                        break ;
1002
                }
1003
                /*PC88c: is done by TRACE_PROP irq */
1004
 
1005
                break ;
1006
        case ACTIONS(PC9_MAINT) :
1007
                stop_pcm_timer0(smc,phy) ;
1008
                CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
1009
                CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
1010
                CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; /* disable LEM int. */
1011
                sm_ph_lem_stop(smc,np) ;                /* disable LEM */
1012
                phy->cf_loop = FALSE ;
1013
                phy->cf_join = FALSE ;
1014
                queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
1015
                plc_go_state(smc,np,PL_PCM_STOP) ;
1016
                mib->fddiPORTConnectState = PCM_DISABLED ;
1017
                SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ;
1018
                sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ;
1019
                outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ;
1020
                ACTIONS_DONE() ;
1021
                break ;
1022
        case PC9_MAINT :
1023
                DB_PCMN(1,"PCM %c : MAINT\n",phy->phy_name,0) ;
1024
                /*PC90*/
1025
                if (cmd == PC_ENABLE) {
1026
                        GO_STATE(PC0_OFF) ;
1027
                        break ;
1028
                }
1029
                break ;
1030
 
1031
        default:
1032
                SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ;
1033
                break ;
1034
        }
1035
}
1036
 
1037
/*
1038
 * force line state on a PHY output     (only in MAINT state)
1039
 */
1040
static void sm_ph_linestate(struct s_smc *smc, int phy, int ls)
1041
{
1042
        int     cntrl ;
1043
 
1044
        SK_UNUSED(smc) ;
1045
 
1046
        cntrl = (inpw(PLC(phy,PL_CNTRL_B)) & ~PL_MAINT_LS) |
1047
                                                PL_PCM_STOP | PL_MAINT ;
1048
        switch(ls) {
1049
        case PC_QLS:            /* Force Quiet */
1050
                cntrl |= PL_M_QUI0 ;
1051
                break ;
1052
        case PC_MLS:            /* Force Master */
1053
                cntrl |= PL_M_MASTR ;
1054
                break ;
1055
        case PC_HLS:            /* Force Halt */
1056
                cntrl |= PL_M_HALT ;
1057
                break ;
1058
        default :
1059
        case PC_ILS:            /* Force Idle */
1060
                cntrl |= PL_M_IDLE ;
1061
                break ;
1062
        case PC_LS_PDR:         /* Enable repeat filter */
1063
                cntrl |= PL_M_TPDR ;
1064
                break ;
1065
        }
1066
        outpw(PLC(phy,PL_CNTRL_B),cntrl) ;
1067
}
1068
 
1069
static void reset_lem_struct(struct s_phy *phy)
1070
{
1071
        struct lem_counter *lem = &phy->lem ;
1072
 
1073
        phy->mib->fddiPORTLer_Estimate = 15 ;
1074
        lem->lem_float_ber = 15 * 100 ;
1075
}
1076
 
1077
/*
1078
 * link error monitor
1079
 */
1080
static void lem_evaluate(struct s_smc *smc, struct s_phy *phy)
1081
{
1082
        int ber ;
1083
        u_long errors ;
1084
        struct lem_counter *lem = &phy->lem ;
1085
        struct fddi_mib_p       *mib ;
1086
        int                     cond ;
1087
 
1088
        mib = phy->mib ;
1089
 
1090
        if (!lem->lem_on)
1091
                return ;
1092
 
1093
        errors = inpw(PLC(((int) phy->np),PL_LINK_ERR_CTR)) ;
1094
        lem->lem_errors += errors ;
1095
        mib->fddiPORTLem_Ct += errors ;
1096
 
1097
        errors = lem->lem_errors ;
1098
        /*
1099
         * calculation is called on a intervall of 8 seconds
1100
         *      -> this means, that one error in 8 sec. is one of 8*125*10E6
1101
         *      the same as BER = 10E-9
1102
         * Please note:
1103
         *      -> 9 errors in 8 seconds mean:
1104
         *         BER = 9 * 10E-9  and this is
1105
         *          < 10E-8, so the limit of 10E-8 is not reached!
1106
         */
1107
 
1108
                if (!errors)            ber = 15 ;
1109
        else    if (errors <= 9)        ber = 9 ;
1110
        else    if (errors <= 99)       ber = 8 ;
1111
        else    if (errors <= 999)      ber = 7 ;
1112
        else    if (errors <= 9999)     ber = 6 ;
1113
        else    if (errors <= 99999)    ber = 5 ;
1114
        else    if (errors <= 999999)   ber = 4 ;
1115
        else    if (errors <= 9999999)  ber = 3 ;
1116
        else    if (errors <= 99999999) ber = 2 ;
1117
        else    if (errors <= 999999999) ber = 1 ;
1118
        else                            ber = 0 ;
1119
 
1120
        /*
1121
         * weighted average
1122
         */
1123
        ber *= 100 ;
1124
        lem->lem_float_ber = lem->lem_float_ber * 7 + ber * 3 ;
1125
        lem->lem_float_ber /= 10 ;
1126
        mib->fddiPORTLer_Estimate = lem->lem_float_ber / 100 ;
1127
        if (mib->fddiPORTLer_Estimate < 4) {
1128
                mib->fddiPORTLer_Estimate = 4 ;
1129
        }
1130
 
1131
        if (lem->lem_errors) {
1132
                DB_PCMN(1,"LEM %c :\n",phy->np == PB? 'B' : 'A',0) ;
1133
                DB_PCMN(1,"errors      : %ld\n",lem->lem_errors,0) ;
1134
                DB_PCMN(1,"sum_errors  : %ld\n",mib->fddiPORTLem_Ct,0) ;
1135
                DB_PCMN(1,"current BER : 10E-%d\n",ber/100,0) ;
1136
                DB_PCMN(1,"float BER   : 10E-(%d/100)\n",lem->lem_float_ber,0) ;
1137
                DB_PCMN(1,"avg. BER    : 10E-%d\n",
1138
                        mib->fddiPORTLer_Estimate,0) ;
1139
        }
1140
 
1141
        lem->lem_errors = 0L ;
1142
 
1143
#ifndef SLIM_SMT
1144
        cond = (mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Alarm) ?
1145
                TRUE : FALSE ;
1146
#ifdef  SMT_EXT_CUTOFF
1147
        smt_ler_alarm_check(smc,phy,cond) ;
1148
#endif  /* nSMT_EXT_CUTOFF */
1149
        if (cond != mib->fddiPORTLerFlag) {
1150
                smt_srf_event(smc,SMT_COND_PORT_LER,
1151
                        (int) (INDEX_PORT+ phy->np) ,cond) ;
1152
        }
1153
#endif
1154
 
1155
        if (    mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Cutoff) {
1156
                phy->pc_lem_fail = TRUE ;               /* flag */
1157
                mib->fddiPORTLem_Reject_Ct++ ;
1158
                /*
1159
                 * "forgive 10e-2" if we cutoff so we can come
1160
                 * up again ..
1161
                 */
1162
                lem->lem_float_ber += 2*100 ;
1163
 
1164
                /*PC81b*/
1165
#ifdef  CONCENTRATOR
1166
                DB_PCMN(1,"PCM: LER cutoff on port %d cutoff %d\n",
1167
                        phy->np, mib->fddiPORTLer_Cutoff) ;
1168
#endif
1169
#ifdef  SMT_EXT_CUTOFF
1170
                smt_port_off_event(smc,phy->np);
1171
#else   /* nSMT_EXT_CUTOFF */
1172
                queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ;
1173
#endif  /* nSMT_EXT_CUTOFF */
1174
        }
1175
}
1176
 
1177
/*
1178
 * called by SMT to calculate LEM bit error rate
1179
 */
1180
void sm_lem_evaluate(struct s_smc *smc)
1181
{
1182
        int np ;
1183
 
1184
        for (np = 0 ; np < NUMPHYS ; np++)
1185
                lem_evaluate(smc,&smc->y[np]) ;
1186
}
1187
 
1188
static void lem_check_lct(struct s_smc *smc, struct s_phy *phy)
1189
{
1190
        struct lem_counter      *lem = &phy->lem ;
1191
        struct fddi_mib_p       *mib ;
1192
        int errors ;
1193
 
1194
        mib = phy->mib ;
1195
 
1196
        phy->pc_lem_fail = FALSE ;              /* flag */
1197
        errors = inpw(PLC(((int)phy->np),PL_LINK_ERR_CTR)) ;
1198
        lem->lem_errors += errors ;
1199
        mib->fddiPORTLem_Ct += errors ;
1200
        if (lem->lem_errors) {
1201
                switch(phy->lc_test) {
1202
                case LC_SHORT:
1203
                        if (lem->lem_errors >= smc->s.lct_short)
1204
                                phy->pc_lem_fail = TRUE ;
1205
                        break ;
1206
                case LC_MEDIUM:
1207
                        if (lem->lem_errors >= smc->s.lct_medium)
1208
                                phy->pc_lem_fail = TRUE ;
1209
                        break ;
1210
                case LC_LONG:
1211
                        if (lem->lem_errors >= smc->s.lct_long)
1212
                                phy->pc_lem_fail = TRUE ;
1213
                        break ;
1214
                case LC_EXTENDED:
1215
                        if (lem->lem_errors >= smc->s.lct_extended)
1216
                                phy->pc_lem_fail = TRUE ;
1217
                        break ;
1218
                }
1219
                DB_PCMN(1," >>errors : %d\n",lem->lem_errors,0) ;
1220
        }
1221
        if (phy->pc_lem_fail) {
1222
                mib->fddiPORTLCTFail_Ct++ ;
1223
                mib->fddiPORTLem_Reject_Ct++ ;
1224
        }
1225
        else
1226
                mib->fddiPORTLCTFail_Ct = 0 ;
1227
}
1228
 
1229
/*
1230
 * LEM functions
1231
 */
1232
static void sm_ph_lem_start(struct s_smc *smc, int np, int threshold)
1233
{
1234
        struct lem_counter *lem = &smc->y[np].lem ;
1235
 
1236
        lem->lem_on = 1 ;
1237
        lem->lem_errors = 0L ;
1238
 
1239
        /* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too
1240
         * often.
1241
         */
1242
 
1243
        outpw(PLC(np,PL_LE_THRESHOLD),threshold) ;
1244
        (void)inpw(PLC(np,PL_LINK_ERR_CTR)) ;   /* clear error counter */
1245
 
1246
        /* enable LE INT */
1247
        SETMASK(PLC(np,PL_INTR_MASK),PL_LE_CTR,PL_LE_CTR) ;
1248
}
1249
 
1250
static void sm_ph_lem_stop(struct s_smc *smc, int np)
1251
{
1252
        struct lem_counter *lem = &smc->y[np].lem ;
1253
 
1254
        lem->lem_on = 0 ;
1255
        CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ;
1256
}
1257
 
1258
/* ARGSUSED */
1259
void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off)
1260
/* int on_off;  en- or disable ident. ls */
1261
{
1262
        SK_UNUSED(smc) ;
1263
 
1264
        phy = phy ; on_off = on_off ;
1265
}
1266
 
1267
 
1268
/*
1269
 * PCM pseudo code
1270
 * receive actions are called AFTER the bit n is received,
1271
 * i.e. if pc_rcode_actions(5) is called, bit 6 is the next bit to be received
1272
 */
1273
 
1274
/*
1275
 * PCM pseudo code 5.1 .. 6.1
1276
 */
1277
static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy)
1278
{
1279
        struct fddi_mib_p       *mib ;
1280
 
1281
        mib = phy->mib ;
1282
 
1283
        DB_PCMN(1,"SIG rec %x %x: \n", bit,phy->r_val[bit] ) ;
1284
        bit++ ;
1285
 
1286
        switch(bit) {
1287
        case 0:
1288
        case 1:
1289
        case 2:
1290
                break ;
1291
        case 3 :
1292
                if (phy->r_val[1] == 0 && phy->r_val[2] == 0)
1293
                        mib->fddiPORTNeighborType = TA ;
1294
                else if (phy->r_val[1] == 0 && phy->r_val[2] == 1)
1295
                        mib->fddiPORTNeighborType = TB ;
1296
                else if (phy->r_val[1] == 1 && phy->r_val[2] == 0)
1297
                        mib->fddiPORTNeighborType = TS ;
1298
                else if (phy->r_val[1] == 1 && phy->r_val[2] == 1)
1299
                        mib->fddiPORTNeighborType = TM ;
1300
                break ;
1301
        case 4:
1302
                if (mib->fddiPORTMy_Type == TM &&
1303
                        mib->fddiPORTNeighborType == TM) {
1304
                        DB_PCMN(1,"PCM %c : E100 withhold M-M\n",
1305
                                phy->phy_name,0) ;
1306
                        mib->fddiPORTPC_Withhold = PC_WH_M_M ;
1307
                        RS_SET(smc,RS_EVENT) ;
1308
                }
1309
                else if (phy->t_val[3] || phy->r_val[3]) {
1310
                        mib->fddiPORTPC_Withhold = PC_WH_NONE ;
1311
                        if (mib->fddiPORTMy_Type == TM ||
1312
                            mib->fddiPORTNeighborType == TM)
1313
                                phy->pc_mode = PM_TREE ;
1314
                        else
1315
                                phy->pc_mode = PM_PEER ;
1316
 
1317
                        /* reevaluate the selection criteria (wc_flag) */
1318
                        all_selection_criteria (smc);
1319
 
1320
                        if (phy->wc_flag) {
1321
                                mib->fddiPORTPC_Withhold = PC_WH_PATH ;
1322
                        }
1323
                }
1324
                else {
1325
                        mib->fddiPORTPC_Withhold = PC_WH_OTHER ;
1326
                        RS_SET(smc,RS_EVENT) ;
1327
                        DB_PCMN(1,"PCM %c : E101 withhold other\n",
1328
                                phy->phy_name,0) ;
1329
                }
1330
                phy->twisted = ((mib->fddiPORTMy_Type != TS) &&
1331
                                (mib->fddiPORTMy_Type != TM) &&
1332
                                (mib->fddiPORTNeighborType ==
1333
                                mib->fddiPORTMy_Type)) ;
1334
                if (phy->twisted) {
1335
                        DB_PCMN(1,"PCM %c : E102 !!! TWISTED !!!\n",
1336
                                phy->phy_name,0) ;
1337
                }
1338
                break ;
1339
        case 5 :
1340
                break ;
1341
        case 6:
1342
                if (phy->t_val[4] || phy->r_val[4]) {
1343
                        if ((phy->t_val[4] && phy->t_val[5]) ||
1344
                            (phy->r_val[4] && phy->r_val[5]) )
1345
                                phy->lc_test = LC_EXTENDED ;
1346
                        else
1347
                                phy->lc_test = LC_LONG ;
1348
                }
1349
                else if (phy->t_val[5] || phy->r_val[5])
1350
                        phy->lc_test = LC_MEDIUM ;
1351
                else
1352
                        phy->lc_test = LC_SHORT ;
1353
                switch (phy->lc_test) {
1354
                case LC_SHORT :                         /* 50ms */
1355
                        outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LENGTH ) ;
1356
                        phy->t_next[7] = smc->s.pcm_lc_short ;
1357
                        break ;
1358
                case LC_MEDIUM :                        /* 500ms */
1359
                        outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LONGLN ) ;
1360
                        phy->t_next[7] = smc->s.pcm_lc_medium ;
1361
                        break ;
1362
                case LC_LONG :
1363
                        SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ;
1364
                        phy->t_next[7] = smc->s.pcm_lc_long ;
1365
                        break ;
1366
                case LC_EXTENDED :
1367
                        SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ;
1368
                        phy->t_next[7] = smc->s.pcm_lc_extended ;
1369
                        break ;
1370
                }
1371
                if (phy->t_next[7] > smc->s.pcm_lc_medium) {
1372
                        start_pcm_timer0(smc,phy->t_next[7],PC_TIMEOUT_LCT,phy);
1373
                }
1374
                DB_PCMN(1,"LCT timer = %ld us\n", phy->t_next[7], 0) ;
1375
                phy->t_next[9] = smc->s.pcm_t_next_9 ;
1376
                break ;
1377
        case 7:
1378
                if (phy->t_val[6]) {
1379
                        phy->cf_loop = TRUE ;
1380
                }
1381
                phy->td_flag = TRUE ;
1382
                break ;
1383
        case 8:
1384
                if (phy->t_val[7] || phy->r_val[7]) {
1385
                        DB_PCMN(1,"PCM %c : E103 LCT fail %s\n",
1386
                                phy->phy_name,phy->t_val[7]? "local":"remote") ;
1387
                        queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ;
1388
                }
1389
                break ;
1390
        case 9:
1391
                if (phy->t_val[8] || phy->r_val[8]) {
1392
                        if (phy->t_val[8])
1393
                                phy->cf_loop = TRUE ;
1394
                        phy->td_flag = TRUE ;
1395
                }
1396
                break ;
1397
        case 10:
1398
                if (phy->r_val[9]) {
1399
                        /* neighbor intends to have MAC on output */ ;
1400
                        mib->fddiPORTMacIndicated.R_val = TRUE ;
1401
                }
1402
                else {
1403
                        /* neighbor does not intend to have MAC on output */ ;
1404
                        mib->fddiPORTMacIndicated.R_val = FALSE ;
1405
                }
1406
                break ;
1407
        }
1408
}
1409
 
1410
/*
1411
 * PCM pseudo code 5.1 .. 6.1
1412
 */
1413
static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy)
1414
{
1415
        int     np = phy->np ;
1416
        struct fddi_mib_p       *mib ;
1417
 
1418
        mib = phy->mib ;
1419
 
1420
        switch(bit) {
1421
        case 0:
1422
                phy->t_val[0] = 0 ;               /* no escape used */
1423
                break ;
1424
        case 1:
1425
                if (mib->fddiPORTMy_Type == TS || mib->fddiPORTMy_Type == TM)
1426
                        phy->t_val[1] = 1 ;
1427
                else
1428
                        phy->t_val[1] = 0 ;
1429
                break ;
1430
        case 2 :
1431
                if (mib->fddiPORTMy_Type == TB || mib->fddiPORTMy_Type == TM)
1432
                        phy->t_val[2] = 1 ;
1433
                else
1434
                        phy->t_val[2] = 0 ;
1435
                break ;
1436
        case 3:
1437
                {
1438
                int     type,ne ;
1439
                int     policy ;
1440
 
1441
                type = mib->fddiPORTMy_Type ;
1442
                ne = mib->fddiPORTNeighborType ;
1443
                policy = smc->mib.fddiSMTConnectionPolicy ;
1444
 
1445
                phy->t_val[3] = 1 ;     /* Accept connection */
1446
                switch (type) {
1447
                case TA :
1448
                        if (
1449
                                ((policy & POLICY_AA) && ne == TA) ||
1450
                                ((policy & POLICY_AB) && ne == TB) ||
1451
                                ((policy & POLICY_AS) && ne == TS) ||
1452
                                ((policy & POLICY_AM) && ne == TM) )
1453
                                phy->t_val[3] = 0 ;      /* Reject */
1454
                        break ;
1455
                case TB :
1456
                        if (
1457
                                ((policy & POLICY_BA) && ne == TA) ||
1458
                                ((policy & POLICY_BB) && ne == TB) ||
1459
                                ((policy & POLICY_BS) && ne == TS) ||
1460
                                ((policy & POLICY_BM) && ne == TM) )
1461
                                phy->t_val[3] = 0 ;      /* Reject */
1462
                        break ;
1463
                case TS :
1464
                        if (
1465
                                ((policy & POLICY_SA) && ne == TA) ||
1466
                                ((policy & POLICY_SB) && ne == TB) ||
1467
                                ((policy & POLICY_SS) && ne == TS) ||
1468
                                ((policy & POLICY_SM) && ne == TM) )
1469
                                phy->t_val[3] = 0 ;      /* Reject */
1470
                        break ;
1471
                case TM :
1472
                        if (    ne == TM ||
1473
                                ((policy & POLICY_MA) && ne == TA) ||
1474
                                ((policy & POLICY_MB) && ne == TB) ||
1475
                                ((policy & POLICY_MS) && ne == TS) ||
1476
                                ((policy & POLICY_MM) && ne == TM) )
1477
                                phy->t_val[3] = 0 ;      /* Reject */
1478
                        break ;
1479
                }
1480
#ifndef SLIM_SMT
1481
                /*
1482
                 * detect undesirable connection attempt event
1483
                 */
1484
                if (    (type == TA && ne == TA ) ||
1485
                        (type == TA && ne == TS ) ||
1486
                        (type == TB && ne == TB ) ||
1487
                        (type == TB && ne == TS ) ||
1488
                        (type == TS && ne == TA ) ||
1489
                        (type == TS && ne == TB ) ) {
1490
                        smt_srf_event(smc,SMT_EVENT_PORT_CONNECTION,
1491
                                (int) (INDEX_PORT+ phy->np) ,0) ;
1492
                }
1493
#endif
1494
                }
1495
                break ;
1496
        case 4:
1497
                if (mib->fddiPORTPC_Withhold == PC_WH_NONE) {
1498
                        if (phy->pc_lem_fail) {
1499
                                phy->t_val[4] = 1 ;     /* long */
1500
                                phy->t_val[5] = 0 ;
1501
                        }
1502
                        else {
1503
                                phy->t_val[4] = 0 ;
1504
                                if (mib->fddiPORTLCTFail_Ct > 0)
1505
                                        phy->t_val[5] = 1 ;     /* medium */
1506
                                else
1507
                                        phy->t_val[5] = 0 ;      /* short */
1508
 
1509
                                /*
1510
                                 * Implementers choice: use medium
1511
                                 * instead of short when undesired
1512
                                 * connection attempt is made.
1513
                                 */
1514
                                if (phy->wc_flag)
1515
                                        phy->t_val[5] = 1 ;     /* medium */
1516
                        }
1517
                        mib->fddiPORTConnectState = PCM_CONNECTING ;
1518
                }
1519
                else {
1520
                        mib->fddiPORTConnectState = PCM_STANDBY ;
1521
                        phy->t_val[4] = 1 ;     /* extended */
1522
                        phy->t_val[5] = 1 ;
1523
                }
1524
                break ;
1525
        case 5:
1526
                break ;
1527
        case 6:
1528
                /* we do NOT have a MAC for LCT */
1529
                phy->t_val[6] = 0 ;
1530
                break ;
1531
        case 7:
1532
                phy->cf_loop = FALSE ;
1533
                lem_check_lct(smc,phy) ;
1534
                if (phy->pc_lem_fail) {
1535
                        DB_PCMN(1,"PCM %c : E104 LCT failed\n",
1536
                                phy->phy_name,0) ;
1537
                        phy->t_val[7] = 1 ;
1538
                }
1539
                else
1540
                        phy->t_val[7] = 0 ;
1541
                break ;
1542
        case 8:
1543
                phy->t_val[8] = 0 ;      /* Don't request MAC loopback */
1544
                break ;
1545
        case 9:
1546
                phy->cf_loop = 0 ;
1547
                if ((mib->fddiPORTPC_Withhold != PC_WH_NONE) ||
1548
                     ((smc->s.sas == SMT_DAS) && (phy->wc_flag))) {
1549
                        queue_event(smc,EVENT_PCM+np,PC_START) ;
1550
                        break ;
1551
                }
1552
                phy->t_val[9] = FALSE ;
1553
                switch (smc->s.sas) {
1554
                case SMT_DAS :
1555
                        /*
1556
                         * MAC intended on output
1557
                         */
1558
                        if (phy->pc_mode == PM_TREE) {
1559
                                if ((np == PB) || ((np == PA) &&
1560
                                (smc->y[PB].mib->fddiPORTConnectState !=
1561
                                        PCM_ACTIVE)))
1562
                                        phy->t_val[9] = TRUE ;
1563
                        }
1564
                        else {
1565
                                if (np == PB)
1566
                                        phy->t_val[9] = TRUE ;
1567
                        }
1568
                        break ;
1569
                case SMT_SAS :
1570
                        if (np == PS)
1571
                                phy->t_val[9] = TRUE ;
1572
                        break ;
1573
#ifdef  CONCENTRATOR
1574
                case SMT_NAC :
1575
                        /*
1576
                         * MAC intended on output
1577
                         */
1578
                        if (np == PB)
1579
                                phy->t_val[9] = TRUE ;
1580
                        break ;
1581
#endif
1582
                }
1583
                mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ;
1584
                break ;
1585
        }
1586
        DB_PCMN(1,"SIG snd %x %x: \n", bit,phy->t_val[bit] ) ;
1587
}
1588
 
1589
/*
1590
 * return status twisted (called by SMT)
1591
 */
1592
int pcm_status_twisted(struct s_smc *smc)
1593
{
1594
        int     twist = 0 ;
1595
        if (smc->s.sas != SMT_DAS)
1596
                return(0) ;
1597
        if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE))
1598
                twist |= 1 ;
1599
        if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE))
1600
                twist |= 2 ;
1601
        return(twist) ;
1602
}
1603
 
1604
/*
1605
 * return status        (called by SMT)
1606
 *      type
1607
 *      state
1608
 *      remote phy type
1609
 *      remote mac yes/no
1610
 */
1611
void pcm_status_state(struct s_smc *smc, int np, int *type, int *state,
1612
                      int *remote, int *mac)
1613
{
1614
        struct s_phy    *phy = &smc->y[np] ;
1615
        struct fddi_mib_p       *mib ;
1616
 
1617
        mib = phy->mib ;
1618
 
1619
        /* remote PHY type and MAC - set only if active */
1620
        *mac = 0 ;
1621
        *type = mib->fddiPORTMy_Type ;          /* our PHY type */
1622
        *state = mib->fddiPORTConnectState ;
1623
        *remote = mib->fddiPORTNeighborType ;
1624
 
1625
        switch(mib->fddiPORTPCMState) {
1626
        case PC8_ACTIVE :
1627
                *mac = mib->fddiPORTMacIndicated.R_val ;
1628
                break ;
1629
        }
1630
}
1631
 
1632
/*
1633
 * return rooted station status (called by SMT)
1634
 */
1635
int pcm_rooted_station(struct s_smc *smc)
1636
{
1637
        int     n ;
1638
 
1639
        for (n = 0 ; n < NUMPHYS ; n++) {
1640
                if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE &&
1641
                    smc->y[n].mib->fddiPORTNeighborType == TM)
1642
                        return(0) ;
1643
        }
1644
        return(1) ;
1645
}
1646
 
1647
/*
1648
 * Interrupt actions for PLC & PCM events
1649
 */
1650
void plc_irq(struct s_smc *smc, int np, unsigned int cmd)
1651
/* int np;      PHY index */
1652
{
1653
        struct s_phy *phy = &smc->y[np] ;
1654
        struct s_plc *plc = &phy->plc ;
1655
        int             n ;
1656
#ifdef  SUPERNET_3
1657
        int             corr_mask ;
1658
#endif  /* SUPERNET_3 */
1659
        int             i ;
1660
 
1661
        if (np >= smc->s.numphys) {
1662
                plc->soft_err++ ;
1663
                return ;
1664
        }
1665
        if (cmd & PL_EBUF_ERR) {        /* elastic buff. det. over-|underflow*/
1666
                /*
1667
                 * Check whether the SRF Condition occurred.
1668
                 */
1669
                if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){
1670
                        /*
1671
                         * This is the real Elasticity Error.
1672
                         * More than one in a row are treated as a
1673
                         * single one.
1674
                         * Only count this in the active state.
1675
                         */
1676
                        phy->mib->fddiPORTEBError_Ct ++ ;
1677
 
1678
                }
1679
 
1680
                plc->ebuf_err++ ;
1681
                if (plc->ebuf_cont <= 1000) {
1682
                        /*
1683
                         * Prevent counter from being wrapped after
1684
                         * hanging years in that interrupt.
1685
                         */
1686
                        plc->ebuf_cont++ ;      /* Ebuf continous error */
1687
                }
1688
 
1689
#ifdef  SUPERNET_3
1690
                if (plc->ebuf_cont == 1000 &&
1691
                        ((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) ==
1692
                        PLC_REV_SN3)) {
1693
                        /*
1694
                         * This interrupt remeained high for at least
1695
                         * 1000 consecutive interrupt calls.
1696
                         *
1697
                         * This is caused by a hardware error of the
1698
                         * ORION part of the Supernet III chipset.
1699
                         *
1700
                         * Disable this bit from the mask.
1701
                         */
1702
                        corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ;
1703
                        outpw(PLC(np,PL_INTR_MASK),corr_mask);
1704
 
1705
                        /*
1706
                         * Disconnect from the ring.
1707
                         * Call the driver with the reset indication.
1708
                         */
1709
                        queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
1710
 
1711
                        /*
1712
                         * Make an error log entry.
1713
                         */
1714
                        SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ;
1715
 
1716
                        /*
1717
                         * Indicate the Reset.
1718
                         */
1719
                        drv_reset_indication(smc) ;
1720
                }
1721
#endif  /* SUPERNET_3 */
1722
        } else {
1723
                /* Reset the continous error variable */
1724
                plc->ebuf_cont = 0 ;     /* reset Ebuf continous error */
1725
        }
1726
        if (cmd & PL_PHYINV) {          /* physical layer invalid signal */
1727
                plc->phyinv++ ;
1728
        }
1729
        if (cmd & PL_VSYM_CTR) {        /* violation symbol counter has incr.*/
1730
                plc->vsym_ctr++ ;
1731
        }
1732
        if (cmd & PL_MINI_CTR) {        /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/
1733
                plc->mini_ctr++ ;
1734
        }
1735
        if (cmd & PL_LE_CTR) {          /* link error event counter */
1736
                int     j ;
1737
 
1738
                /*
1739
                 * note: PL_LINK_ERR_CTR MUST be read to clear it
1740
                 */
1741
                j = inpw(PLC(np,PL_LE_THRESHOLD)) ;
1742
                i = inpw(PLC(np,PL_LINK_ERR_CTR)) ;
1743
 
1744
                if (i < j) {
1745
                        /* wrapped around */
1746
                        i += 256 ;
1747
                }
1748
 
1749
                if (phy->lem.lem_on) {
1750
                        /* Note: Lem errors shall only be counted when
1751
                         * link is ACTIVE or LCT is active.
1752
                         */
1753
                        phy->lem.lem_errors += i ;
1754
                        phy->mib->fddiPORTLem_Ct += i ;
1755
                }
1756
        }
1757
        if (cmd & PL_TPC_EXPIRED) {     /* TPC timer reached zero */
1758
                if (plc->p_state == PS_LCT) {
1759
                        /*
1760
                         * end of LCT
1761
                         */
1762
                        ;
1763
                }
1764
                plc->tpc_exp++ ;
1765
        }
1766
        if (cmd & PL_LS_MATCH) {        /* LS == LS in PLC_CNTRL_B's MATCH_LS*/
1767
                switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) {
1768
                case PL_I_IDLE :        phy->curr_ls = PC_ILS ;         break ;
1769
                case PL_I_HALT :        phy->curr_ls = PC_HLS ;         break ;
1770
                case PL_I_MASTR :       phy->curr_ls = PC_MLS ;         break ;
1771
                case PL_I_QUIET :       phy->curr_ls = PC_QLS ;         break ;
1772
                }
1773
        }
1774
        if (cmd & PL_PCM_BREAK) {       /* PCM has entered the BREAK state */
1775
                int     reason;
1776
 
1777
                reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ;
1778
 
1779
                switch (reason) {
1780
                case PL_B_PCS :         plc->b_pcs++ ;  break ;
1781
                case PL_B_TPC :         plc->b_tpc++ ;  break ;
1782
                case PL_B_TNE :         plc->b_tne++ ;  break ;
1783
                case PL_B_QLS :         plc->b_qls++ ;  break ;
1784
                case PL_B_ILS :         plc->b_ils++ ;  break ;
1785
                case PL_B_HLS :         plc->b_hls++ ;  break ;
1786
                }
1787
 
1788
                /*jd 05-Aug-1999 changed: Bug #10419 */
1789
                DB_PCMN(1,"PLC %d: MDcF = %x\n", np, smc->e.DisconnectFlag);
1790
                if (smc->e.DisconnectFlag == FALSE) {
1791
                        DB_PCMN(1,"PLC %d: restart (reason %x)\n", np, reason);
1792
                        queue_event(smc,EVENT_PCM+np,PC_START) ;
1793
                }
1794
                else {
1795
                        DB_PCMN(1,"PLC %d: NO!! restart (reason %x)\n", np, reason);
1796
                }
1797
                return ;
1798
        }
1799
        /*
1800
         * If both CODE & ENABLE are set ignore enable
1801
         */
1802
        if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */
1803
                queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ;
1804
                n = inpw(PLC(np,PL_RCV_VECTOR)) ;
1805
                for (i = 0 ; i < plc->p_bits ; i++) {
1806
                        phy->r_val[plc->p_start+i] = n & 1 ;
1807
                        n >>= 1 ;
1808
                }
1809
        }
1810
        else if (cmd & PL_PCM_ENABLED) { /* asserted SC_JOIN, scrub.completed*/
1811
                queue_event(smc,EVENT_PCM+np,PC_JOIN) ;
1812
        }
1813
        if (cmd & PL_TRACE_PROP) {      /* MLS while PC8_ACTIV || PC2_TRACE */
1814
                /*PC22b*/
1815
                if (!phy->tr_flag) {
1816
                        DB_PCMN(1,"PCM : irq TRACE_PROP %d %d\n",
1817
                                np,smc->mib.fddiSMTECMState) ;
1818
                        phy->tr_flag = TRUE ;
1819
                        smc->e.trace_prop |= ENTITY_BIT(ENTITY_PHY(np)) ;
1820
                        queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
1821
                }
1822
        }
1823
        /*
1824
         * filter PLC glitch ???
1825
         * QLS || HLS only while in PC2_TRACE state
1826
         */
1827
        if ((cmd & PL_SELF_TEST) && (phy->mib->fddiPORTPCMState == PC2_TRACE)) {
1828
                /*PC22a*/
1829
                if (smc->e.path_test == PT_PASSED) {
1830
                        DB_PCMN(1,"PCM : state = %s %d\n", get_pcmstate(smc,np),
1831
                                phy->mib->fddiPORTPCMState) ;
1832
 
1833
                        smc->e.path_test = PT_PENDING ;
1834
                        queue_event(smc,EVENT_ECM,EC_PATH_TEST) ;
1835
                }
1836
        }
1837
        if (cmd & PL_TNE_EXPIRED) {     /* TNE: length of noise events */
1838
                /* break_required (TNE > NS_Max) */
1839
                if (phy->mib->fddiPORTPCMState == PC8_ACTIVE) {
1840
                        if (!phy->tr_flag) {
1841
                           DB_PCMN(1,"PCM %c : PC81 %s\n",phy->phy_name,"NSE");
1842
                           queue_event(smc,EVENT_PCM+np,PC_START) ;
1843
                           return ;
1844
                        }
1845
                }
1846
        }
1847
#if     0
1848
        if (cmd & PL_NP_ERR) {          /* NP has requested to r/w an inv reg*/
1849
                /*
1850
                 * It's a bug by AMD
1851
                 */
1852
                plc->np_err++ ;
1853
        }
1854
        /* pin inactiv (GND) */
1855
        if (cmd & PL_PARITY_ERR) {      /* p. error dedected on TX9-0 inp */
1856
                plc->parity_err++ ;
1857
        }
1858
        if (cmd & PL_LSDO) {            /* carrier detected */
1859
                ;
1860
        }
1861
#endif
1862
}
1863
 
1864
#ifdef  DEBUG
1865
/*
1866
 * fill state struct
1867
 */
1868
void pcm_get_state(struct s_smc *smc, struct smt_state *state)
1869
{
1870
        struct s_phy    *phy ;
1871
        struct pcm_state *pcs ;
1872
        int     i ;
1873
        int     ii ;
1874
        short   rbits ;
1875
        short   tbits ;
1876
        struct fddi_mib_p       *mib ;
1877
 
1878
        for (i = 0, phy = smc->y, pcs = state->pcm_state ; i < NUMPHYS ;
1879
                i++ , phy++, pcs++ ) {
1880
                mib = phy->mib ;
1881
                pcs->pcm_type = (u_char) mib->fddiPORTMy_Type ;
1882
                pcs->pcm_state = (u_char) mib->fddiPORTPCMState ;
1883
                pcs->pcm_mode = phy->pc_mode ;
1884
                pcs->pcm_neighbor = (u_char) mib->fddiPORTNeighborType ;
1885
                pcs->pcm_bsf = mib->fddiPORTBS_Flag ;
1886
                pcs->pcm_lsf = phy->ls_flag ;
1887
                pcs->pcm_lct_fail = (u_char) mib->fddiPORTLCTFail_Ct ;
1888
                pcs->pcm_ls_rx = LS2MIB(sm_pm_get_ls(smc,i)) ;
1889
                for (ii = 0, rbits = tbits = 0 ; ii < NUMBITS ; ii++) {
1890
                        rbits <<= 1 ;
1891
                        tbits <<= 1 ;
1892
                        if (phy->r_val[NUMBITS-1-ii])
1893
                                rbits |= 1 ;
1894
                        if (phy->t_val[NUMBITS-1-ii])
1895
                                tbits |= 1 ;
1896
                }
1897
                pcs->pcm_r_val = rbits ;
1898
                pcs->pcm_t_val = tbits ;
1899
        }
1900
}
1901
 
1902
int get_pcm_state(struct s_smc *smc, int np)
1903
{
1904
        int pcs ;
1905
 
1906
        SK_UNUSED(smc) ;
1907
 
1908
        switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) {
1909
                case PL_PC0 :   pcs = PC_STOP ;         break ;
1910
                case PL_PC1 :   pcs = PC_START ;        break ;
1911
                case PL_PC2 :   pcs = PC_TRACE ;        break ;
1912
                case PL_PC3 :   pcs = PC_SIGNAL ;       break ;
1913
                case PL_PC4 :   pcs = PC_SIGNAL ;       break ;
1914
                case PL_PC5 :   pcs = PC_SIGNAL ;       break ;
1915
                case PL_PC6 :   pcs = PC_JOIN ;         break ;
1916
                case PL_PC7 :   pcs = PC_JOIN ;         break ;
1917
                case PL_PC8 :   pcs = PC_ENABLE ;       break ;
1918
                case PL_PC9 :   pcs = PC_MAINT ;        break ;
1919
                default :       pcs = PC_DISABLE ;      break ;
1920
        }
1921
        return(pcs) ;
1922
}
1923
 
1924
char *get_linestate(struct s_smc *smc, int np)
1925
{
1926
        char *ls = "" ;
1927
 
1928
        SK_UNUSED(smc) ;
1929
 
1930
        switch (inpw(PLC(np,PL_STATUS_A)) & PL_LINE_ST) {
1931
                case PL_L_NLS : ls = "NOISE" ;  break ;
1932
                case PL_L_ALS : ls = "ACTIV" ;  break ;
1933
                case PL_L_UND : ls = "UNDEF" ;  break ;
1934
                case PL_L_ILS4: ls = "ILS 4" ;  break ;
1935
                case PL_L_QLS : ls = "QLS" ;    break ;
1936
                case PL_L_MLS : ls = "MLS" ;    break ;
1937
                case PL_L_HLS : ls = "HLS" ;    break ;
1938
                case PL_L_ILS16:ls = "ILS16" ;  break ;
1939
#ifdef  lint
1940
                default:        ls = "unknown" ; break ;
1941
#endif
1942
        }
1943
        return(ls) ;
1944
}
1945
 
1946
char *get_pcmstate(struct s_smc *smc, int np)
1947
{
1948
        char *pcs ;
1949
 
1950
        SK_UNUSED(smc) ;
1951
 
1952
        switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) {
1953
                case PL_PC0 :   pcs = "OFF" ;           break ;
1954
                case PL_PC1 :   pcs = "BREAK" ;         break ;
1955
                case PL_PC2 :   pcs = "TRACE" ;         break ;
1956
                case PL_PC3 :   pcs = "CONNECT";        break ;
1957
                case PL_PC4 :   pcs = "NEXT" ;          break ;
1958
                case PL_PC5 :   pcs = "SIGNAL" ;        break ;
1959
                case PL_PC6 :   pcs = "JOIN" ;          break ;
1960
                case PL_PC7 :   pcs = "VERIFY" ;        break ;
1961
                case PL_PC8 :   pcs = "ACTIV" ;         break ;
1962
                case PL_PC9 :   pcs = "MAINT" ;         break ;
1963
                default :       pcs = "UNKNOWN" ;       break ;
1964
        }
1965
        return(pcs) ;
1966
}
1967
 
1968
void list_phy(struct s_smc *smc)
1969
{
1970
        struct s_plc *plc ;
1971
        int np ;
1972
 
1973
        for (np = 0 ; np < NUMPHYS ; np++) {
1974
                plc  = &smc->y[np].plc ;
1975
                printf("PHY %d:\tERRORS\t\t\tBREAK_REASONS\t\tSTATES:\n",np) ;
1976
                printf("\tsoft_error: %ld \t\tPC_Start : %ld\n",
1977
                                                plc->soft_err,plc->b_pcs);
1978
                printf("\tparity_err: %ld \t\tTPC exp. : %ld\t\tLine: %s\n",
1979
                        plc->parity_err,plc->b_tpc,get_linestate(smc,np)) ;
1980
                printf("\tebuf_error: %ld \t\tTNE exp. : %ld\n",
1981
                                                plc->ebuf_err,plc->b_tne) ;
1982
                printf("\tphyinvalid: %ld \t\tQLS det. : %ld\t\tPCM : %s\n",
1983
                        plc->phyinv,plc->b_qls,get_pcmstate(smc,np)) ;
1984
                printf("\tviosym_ctr: %ld \t\tILS det. : %ld\n",
1985
                                                plc->vsym_ctr,plc->b_ils)  ;
1986
                printf("\tmingap_ctr: %ld \t\tHLS det. : %ld\n",
1987
                                                plc->mini_ctr,plc->b_hls) ;
1988
                printf("\tnodepr_err: %ld\n",plc->np_err) ;
1989
                printf("\tTPC_exp : %ld\n",plc->tpc_exp) ;
1990
                printf("\tLEM_err : %ld\n",smc->y[np].lem.lem_errors) ;
1991
        }
1992
}
1993
 
1994
 
1995
#ifdef  CONCENTRATOR
1996
void pcm_lem_dump(struct s_smc *smc)
1997
{
1998
        int             i ;
1999
        struct s_phy    *phy ;
2000
        struct fddi_mib_p       *mib ;
2001
 
2002
        char            *entostring() ;
2003
 
2004
        printf("PHY     errors  BER\n") ;
2005
        printf("----------------------\n") ;
2006
        for (i = 0,phy = smc->y ; i < NUMPHYS ; i++,phy++) {
2007
                if (!plc_is_installed(smc,i))
2008
                        continue ;
2009
                mib = phy->mib ;
2010
                printf("%s\t%ld\t10E-%d\n",
2011
                        entostring(smc,ENTITY_PHY(i)),
2012
                        mib->fddiPORTLem_Ct,
2013
                        mib->fddiPORTLer_Estimate) ;
2014
        }
2015
}
2016
#endif
2017
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.