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