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