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