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