drvfbi.c 12 KB

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