diff options
Diffstat (limited to 'drivers/staging/cxt1e1')
29 files changed, 10049 insertions, 0 deletions
diff --git a/drivers/staging/cxt1e1/Kconfig b/drivers/staging/cxt1e1/Kconfig new file mode 100644 index 00000000000..947f42a65c5 --- /dev/null +++ b/drivers/staging/cxt1e1/Kconfig @@ -0,0 +1,21 @@ +config CXT1E1 + tristate "SBE wanPMC-C[421]E1T1 hardware support" + depends on HDLC && PCI + ---help--- + This driver supports the SBE wanPMC-CxT1E1 1, 2 and 4 port T3 + channelized stream WAN adapter card which contains a HDLC/Transparent + mode controller. + + If you want to compile this driver as a module say M here. + The module will be called 'cxt1e1'. + + If unsure, say N. + +config SBE_PMCC4_NCOMM + bool "SBE PMCC4 NCOMM support" + depends on CXT1E1 + ---help--- + SBE supplies optional support for NCOMM products. + + If you have purchased this optional support you must say Y + here to allow the driver to operate with the NCOMM product. diff --git a/drivers/staging/cxt1e1/Makefile b/drivers/staging/cxt1e1/Makefile new file mode 100644 index 00000000000..b879e7b553c --- /dev/null +++ b/drivers/staging/cxt1e1/Makefile @@ -0,0 +1,18 @@ +obj-$(CONFIG_CXT1E1) += cxt1e1.o + +ccflags-y := -DSBE_PMCC4_ENABLE +ccflags-y += -DSBE_ISR_TASKLET + +cxt1e1-y := \ + musycc.o \ + pmcc4_drv.o \ + comet.o \ + linux.o \ + functions.o \ + hwprobe.o \ + pmc93x6_eeprom.o \ + sbecrc.o \ + comet_tables.o \ + sbeid.o + +cxt1e1-$(CONFIG_PROC_FS) += sbeproc.o diff --git a/drivers/staging/cxt1e1/comet.c b/drivers/staging/cxt1e1/comet.c new file mode 100644 index 00000000000..7005ad02233 --- /dev/null +++ b/drivers/staging/cxt1e1/comet.c @@ -0,0 +1,596 @@ +/* Copyright (C) 2003-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/io.h> +#include <linux/hdlc.h> +#include "pmcc4_sysdep.h" +#include "sbecom_inline_linux.h" +#include "libsbew.h" +#include "pmcc4.h" +#include "comet.h" +#include "comet_tables.h" + + +#define COMET_NUM_SAMPLES 24 /* Number of entries in the waveform table */ +#define COMET_NUM_UNITS 5 /* Number of points per entry in table */ + +/* forward references */ +static void SetPwrLevel(struct s_comet_reg *comet); +static void WrtRcvEqualizerTbl(ci_t *ci, struct s_comet_reg *comet, + u_int32_t *table); +static void WrtXmtWaveformTbl(ci_t *ci, struct s_comet_reg *comet, + u_int8_t table[COMET_NUM_SAMPLES] + [COMET_NUM_UNITS]); + + +static void *TWV_table[12] = { + TWVLongHaul0DB, TWVLongHaul7_5DB, TWVLongHaul15DB, TWVLongHaul22_5DB, + TWVShortHaul0, TWVShortHaul1, TWVShortHaul2, TWVShortHaul3, + TWVShortHaul4, TWVShortHaul5, + /** PORT POINT - 75 Ohm not supported **/ + TWV_E1_75Ohm, + TWV_E1_120Ohm +}; + + +static int +lbo_tbl_lkup(int t1, int lbo) { + /* error switches to default */ + if ((lbo < CFG_LBO_LH0) || (lbo > CFG_LBO_E120)) { + if (t1) + /* default T1 waveform table */ + lbo = CFG_LBO_LH0; + + else + /* default E1 waveform table */ + lbo = CFG_LBO_E120; + } + /* make index ZERO relative */ + return lbo - 1; +} + +void init_comet(void *ci, struct s_comet_reg *comet, u_int32_t port_mode, + int clockmaster, u_int8_t moreParams) +{ + u_int8_t isT1mode; + /* T1 default */ + u_int8_t tix = CFG_LBO_LH0; + isT1mode = IS_FRAME_ANY_T1(port_mode); + /* T1 or E1 */ + if (isT1mode) { + /* Select T1 Mode & PIO output enabled */ + pci_write_32((u_int32_t *) &comet->gbl_cfg, 0xa0); + /* default T1 waveform table */ + tix = lbo_tbl_lkup(isT1mode, CFG_LBO_LH0); + } else { + /* Select E1 Mode & PIO output enabled */ + pci_write_32((u_int32_t *) &comet->gbl_cfg, 0x81); + /* default E1 waveform table */ + tix = lbo_tbl_lkup(isT1mode, CFG_LBO_E120); + } + + if (moreParams & CFG_LBO_MASK) + /* dial-in requested waveform table */ + tix = lbo_tbl_lkup(isT1mode, moreParams & CFG_LBO_MASK); + /* Tx line Intfc cfg Set for analog & no special patterns */ + /* Transmit Line Interface Config. */ + pci_write_32((u_int32_t *) &comet->tx_line_cfg, 0x00); + /* master test Ignore Test settings for now */ + /* making sure it's Default value */ + pci_write_32((u_int32_t *) &comet->mtest, 0x00); + /* Turn on Center (CENT) and everything else off */ + /* RJAT cfg */ + pci_write_32((u_int32_t *) &comet->rjat_cfg, 0x10); + /* Set Jitter Attenuation to recommend T1 values */ + if (isT1mode) { + /* RJAT Divider N1 Control */ + pci_write_32((u_int32_t *) &comet->rjat_n1clk, 0x2F); + /* RJAT Divider N2 Control */ + pci_write_32((u_int32_t *) &comet->rjat_n2clk, 0x2F); + } else { + /* RJAT Divider N1 Control */ + pci_write_32((u_int32_t *) &comet->rjat_n1clk, 0xFF); + /* RJAT Divider N2 Control */ + pci_write_32((u_int32_t *) &comet->rjat_n2clk, 0xFF); + } + + /* Turn on Center (CENT) and everything else off */ + /* TJAT Config. */ + pci_write_32((u_int32_t *) &comet->tjat_cfg, 0x10); + + /* Do not bypass jitter attenuation and bypass elastic store */ + /* rx opts */ + pci_write_32((u_int32_t *) &comet->rx_opt, 0x00); + + /* TJAT ctrl & TJAT divider ctrl */ + /* Set Jitter Attenuation to recommended T1 values */ + if (isT1mode) { + /* TJAT Divider N1 Control */ + pci_write_32((u_int32_t *) &comet->tjat_n1clk, 0x2F); + /* TJAT Divider N2 Control */ + pci_write_32((u_int32_t *) &comet->tjat_n2clk, 0x2F); + } else { + /* TJAT Divider N1 Control */ + pci_write_32((u_int32_t *) &comet->tjat_n1clk, 0xFF); + /* TJAT Divider N2 Control */ + pci_write_32((u_int32_t *) &comet->tjat_n2clk, 0xFF); + } + + /* 1c: rx ELST cfg 20: tx ELST cfg 28&38: rx&tx data link ctrl */ + + /* Select 193-bit frame format */ + if (isT1mode) { + pci_write_32((u_int32_t *) &comet->rx_elst_cfg, 0x00); + pci_write_32((u_int32_t *) &comet->tx_elst_cfg, 0x00); + } else { + /* Select 256-bit frame format */ + pci_write_32((u_int32_t *) &comet->rx_elst_cfg, 0x03); + pci_write_32((u_int32_t *) &comet->tx_elst_cfg, 0x03); + /* disable T1 data link receive */ + pci_write_32((u_int32_t *) &comet->rxce1_ctl, 0x00); + /* disable T1 data link transmit */ + pci_write_32((u_int32_t *) &comet->txci1_ctl, 0x00); + } + + /* the following is a default value */ + /* Enable 8 out of 10 validation */ + /* t1RBOC enable(BOC:BitOriented Code) */ + pci_write_32((u_int32_t *) &comet->t1_rboc_ena, 0x00); + if (isT1mode) { + /* IBCD cfg: aka Inband Code Detection ** loopback code length + * set to + */ + /* 6 bit down, 5 bit up (assert) */ + pci_write_32((u_int32_t *) &comet->ibcd_cfg, 0x04); + /* line loopback activate pattern */ + pci_write_32((u_int32_t *) &comet->ibcd_act, 0x08); + /* deactivate code pattern (i.e.001) */ + pci_write_32((u_int32_t *) &comet->ibcd_deact, 0x24); + } + /* 10: CDRC cfg 28&38: rx&tx data link 1 ctrl 48: t1 frmr cfg */ + /* 50: SIGX cfg, COSS (change of signaling state) 54: XBAS cfg */ + /* 60: t1 ALMI cfg */ + /* Configure Line Coding */ + + switch (port_mode) { + /* 1 - T1 B8ZS */ + case CFG_FRAME_SF: + pci_write_32((u_int32_t *) &comet->cdrc_cfg, 0); + pci_write_32((u_int32_t *) &comet->t1_frmr_cfg, 0); + pci_write_32((u_int32_t *) &comet->sigx_cfg, 0); + /* 5:B8ZS */ + pci_write_32((u_int32_t *) &comet->t1_xbas_cfg, 0x20); + pci_write_32((u_int32_t *) &comet->t1_almi_cfg, 0); + break; + /* 2 - T1 B8ZS */ + case CFG_FRAME_ESF: + pci_write_32((u_int32_t *) &comet->cdrc_cfg, 0); + /* Bit 5: T1 DataLink Enable */ + pci_write_32((u_int32_t *) &comet->rxce1_ctl, 0x20); + /* 5: T1 DataLink Enable */ + pci_write_32((u_int32_t *) &comet->txci1_ctl, 0x20); + /* 4:ESF 5:ESFFA */ + pci_write_32((u_int32_t *) &comet->t1_frmr_cfg, 0x30); + /* 2:ESF */ + pci_write_32((u_int32_t *) &comet->sigx_cfg, 0x04); + /* 4:ESF 5:B8ZS */ + pci_write_32((u_int32_t *) &comet->t1_xbas_cfg, 0x30); + /* 4:ESF */ + pci_write_32((u_int32_t *) &comet->t1_almi_cfg, 0x10); + break; + /* 3 - HDB3 */ + case CFG_FRAME_E1PLAIN: + pci_write_32((u_int32_t *) &comet->cdrc_cfg, 0); + pci_write_32((u_int32_t *) &comet->sigx_cfg, 0); + pci_write_32((u_int32_t *) &comet->e1_tran_cfg, 0); + pci_write_32((u_int32_t *) &comet->e1_frmr_aopts, 0x40); + break; + /* 4 - HDB3 */ + case CFG_FRAME_E1CAS: + pci_write_32((u_int32_t *) &comet->cdrc_cfg, 0); + pci_write_32((u_int32_t *) &comet->sigx_cfg, 0); + pci_write_32((u_int32_t *) &comet->e1_tran_cfg, 0x60); + pci_write_32((u_int32_t *) &comet->e1_frmr_aopts, 0); + break; + /* 5 - HDB3 */ + case CFG_FRAME_E1CRC: + pci_write_32((u_int32_t *) &comet->cdrc_cfg, 0); + pci_write_32((u_int32_t *) &comet->sigx_cfg, 0); + pci_write_32((u_int32_t *) &comet->e1_tran_cfg, 0x10); + pci_write_32((u_int32_t *) &comet->e1_frmr_aopts, 0xc2); + break; + /* 6 - HDB3 */ + case CFG_FRAME_E1CRC_CAS: + pci_write_32((u_int32_t *) &comet->cdrc_cfg, 0); + pci_write_32((u_int32_t *) &comet->sigx_cfg, 0); + pci_write_32((u_int32_t *) &comet->e1_tran_cfg, 0x70); + pci_write_32((u_int32_t *) &comet->e1_frmr_aopts, 0x82); + break; + /* 7 - T1 AMI */ + case CFG_FRAME_SF_AMI: + /* Enable AMI Line Decoding */ + pci_write_32((u_int32_t *) &comet->cdrc_cfg, 0x80); + pci_write_32((u_int32_t *) &comet->t1_frmr_cfg, 0); + pci_write_32((u_int32_t *) &comet->t1_xbas_cfg, 0); + pci_write_32((u_int32_t *) &comet->t1_almi_cfg, 0); + pci_write_32((u_int32_t *) &comet->sigx_cfg, 0); + break; + /* 8 - T1 AMI */ + case CFG_FRAME_ESF_AMI: + /* Enable AMI Line Decoding */ + pci_write_32((u_int32_t *) &comet->cdrc_cfg, 0x80); + /* 5: T1 DataLink Enable */ + pci_write_32((u_int32_t *) &comet->rxce1_ctl, 0x20); + /* 5: T1 DataLink Enable */ + pci_write_32((u_int32_t *) &comet->txci1_ctl, 0x20); + /* Bit 4:ESF 5:ESFFA */ + pci_write_32((u_int32_t *) &comet->t1_frmr_cfg, 0x30); + /* 2:ESF */ + pci_write_32((u_int32_t *) &comet->sigx_cfg, 0x04); + /* 4:ESF */ + pci_write_32((u_int32_t *) &comet->t1_xbas_cfg, 0x10); + /* 4:ESF */ + pci_write_32((u_int32_t *) &comet->t1_almi_cfg, 0x10); + break; + /* 9 - AMI */ + case CFG_FRAME_E1PLAIN_AMI: + /* Enable AMI Line Decoding */ + pci_write_32((u_int32_t *) &comet->cdrc_cfg, 0x80); + pci_write_32((u_int32_t *) &comet->sigx_cfg, 0); + pci_write_32((u_int32_t *) &comet->e1_tran_cfg, 0x80); + pci_write_32((u_int32_t *) &comet->e1_frmr_aopts, 0x40); + break; + /* 10 - AMI */ + case CFG_FRAME_E1CAS_AMI: + /* Enable AMI Line Decoding */ + pci_write_32((u_int32_t *) &comet->cdrc_cfg, 0x80); + pci_write_32((u_int32_t *) &comet->sigx_cfg, 0); + pci_write_32((u_int32_t *) &comet->e1_tran_cfg, 0xe0); + pci_write_32((u_int32_t *) &comet->e1_frmr_aopts, 0); + break; + /* 11 - AMI */ + case CFG_FRAME_E1CRC_AMI: + /* Enable AMI Line Decoding */ + pci_write_32((u_int32_t *) &comet->cdrc_cfg, 0x80); + pci_write_32((u_int32_t *) &comet->sigx_cfg, 0); + pci_write_32((u_int32_t *) &comet->e1_tran_cfg, 0x90); + pci_write_32((u_int32_t *) &comet->e1_frmr_aopts, 0xc2); + break; + /* 12 - AMI */ + case CFG_FRAME_E1CRC_CAS_AMI: + /* Enable AMI Line Decoding */ + pci_write_32((u_int32_t *) &comet->cdrc_cfg, 0x80); + pci_write_32((u_int32_t *) &comet->sigx_cfg, 0); + pci_write_32((u_int32_t *) &comet->e1_tran_cfg, 0xf0); + pci_write_32((u_int32_t *) &comet->e1_frmr_aopts, 0x82); + break; + } /* end switch */ + + /*** + * Set Full Frame mode (NXDSO[1] = 0, NXDSO[0] = 0) + * CMODE=1: Clock slave mode with BRCLK as an input, + * DE=0: Use falling edge of BRCLK for data, + * FE=0: Use falling edge of BRCLK for frame, + * CMS=0: Use backplane freq, + * RATE[1:0]=0,0: T1 + ***/ + + + /* 0x30: "BRIF cfg"; 0x20 is 'CMODE', 0x03 is (bit) rate */ + /* note "rate bits can only be set once after reset" */ + if (clockmaster) { + /* CMODE == clockMode, 0=clock master + * (so all 3 others should be slave) + */ + /* rate = 1.544 Mb/s */ + if (isT1mode) + /* Comet 0 Master Mode(CMODE=0) */ + pci_write_32((u_int32_t *) &comet->brif_cfg, 0x00); + /* rate = 2.048 Mb/s */ + else + /* Comet 0 Master Mode(CMODE=0) */ + pci_write_32((u_int32_t *) &comet->brif_cfg, 0x01); + + /* 31: BRIF frame pulse cfg 06: tx timing options */ + + /* Master Mode i.e.FPMODE=0 (@0x20) */ + pci_write_32((u_int32_t *) &comet->brif_fpcfg, 0x00); + if ((moreParams & CFG_CLK_PORT_MASK) == CFG_CLK_PORT_INTERNAL) { + if (cxt1e1_log_level >= LOG_SBEBUG12) + pr_info(">> %s: clockmaster internal clock\n", + __func__); + /* internal oscillator */ + pci_write_32((u_int32_t *) &comet->tx_time, 0x0d); + } else { + /* external clock source */ + if (cxt1e1_log_level >= LOG_SBEBUG12) + pr_info(">> %s: clockmaster external clock\n", + __func__); + /* loop timing(external) */ + pci_write_32((u_int32_t *) &comet->tx_time, 0x09); + } + + } else { + /* slave */ + if (isT1mode) + /* Slave Mode(CMODE=1, see above) */ + pci_write_32((u_int32_t *) &comet->brif_cfg, 0x20); + else + /* Slave Mode(CMODE=1)*/ + pci_write_32((u_int32_t *) &comet->brif_cfg, 0x21); + /* Slave Mode i.e. FPMODE=1 (@0x20) */ + pci_write_32((u_int32_t *) &comet->brif_fpcfg, 0x20); + if (cxt1e1_log_level >= LOG_SBEBUG12) + pr_info(">> %s: clockslave internal clock\n", __func__); + /* oscillator timing */ + pci_write_32((u_int32_t *) &comet->tx_time, 0x0d); + } + + /* 32: BRIF parity F-bit cfg */ + /* Totem-pole operation */ + /* Receive Backplane Parity/F-bit */ + pci_write_32((u_int32_t *) &comet->brif_pfcfg, 0x01); + + /* dc: RLPS equalizer V ref */ + /* Configuration */ + if (isT1mode) + /* RLPS Equalizer Voltage */ + pci_write_32((u_int32_t *) &comet->rlps_eqvr, 0x2c); + else + /* RLPS Equalizer Voltage */ + pci_write_32((u_int32_t *) &comet->rlps_eqvr, 0x34); + + /* Reserved bit set and SQUELCH enabled */ + /* f8: RLPS cfg & status f9: RLPS ALOS detect/clear threshold */ + /* RLPS Configuration Status */ + pci_write_32((u_int32_t *) &comet->rlps_cfgsts, 0x11); + if (isT1mode) + /* ? */ + pci_write_32((u_int32_t *) &comet->rlps_alos_thresh, 0x55); + else + /* ? */ + pci_write_32((u_int32_t *) &comet->rlps_alos_thresh, 0x22); + + + /* Set Full Frame mode (NXDSO[1] = 0, NXDSO[0] = 0) */ + /* CMODE=0: Clock slave mode with BTCLK as an input, DE=1: Use rising */ + /* edge of BTCLK for data, FE=1: Use rising edge of BTCLK for frame, */ + /* CMS=0: Use backplane freq, RATE[1:0]=0,0: T1 */ + /*** Transmit side is always an Input, Slave Clock*/ + /* 40: BTIF cfg 41: loop timing(external) */ + /*BTIF frame pulse cfg */ + if (isT1mode) + /* BTIF Configuration Reg. */ + pci_write_32((u_int32_t *) &comet->btif_cfg, 0x38); + else + /* BTIF Configuration Reg. */ + pci_write_32((u_int32_t *) &comet->btif_cfg, 0x39); + /* BTIF Frame Pulse Config. */ + pci_write_32((u_int32_t *) &comet->btif_fpcfg, 0x01); + + /* 0a: master diag 06: tx timing options */ + /* if set Comet to loop back */ + + /* Comets set to normal */ + pci_write_32((u_int32_t *) &comet->mdiag, 0x00); + + /* BTCLK driven by TCLKI internally (crystal driven) and Xmt Elasted */ + /* Store is enabled. */ + + WrtXmtWaveformTbl(ci, comet, TWV_table[tix]); + if (isT1mode) + WrtRcvEqualizerTbl((ci_t *) ci, comet, &T1_Equalizer[0]); + else + WrtRcvEqualizerTbl((ci_t *) ci, comet, &E1_Equalizer[0]); + SetPwrLevel(comet); +} + +/* +** Name: WrtXmtWaveform +** Description: Formulate the Data for the Pulse Waveform Storage +** Write register, (F2), from the sample and unit inputs. +** Write the data to the Pulse Waveform Storage Data register. +** Returns: Nothing +*/ +static void +WrtXmtWaveform(ci_t *ci, struct s_comet_reg *comet, u_int32_t sample, + u_int32_t unit, u_int8_t data) +{ + u_int8_t WaveformAddr; + + WaveformAddr = (sample << 3) + (unit & 7); + pci_write_32((u_int32_t *) &comet->xlpg_pwave_addr, WaveformAddr); + /* for write order preservation when Optimizing driver */ + pci_flush_write(ci); + pci_write_32((u_int32_t *) &comet->xlpg_pwave_data, 0x7F & data); +} + +/* +** Name: WrtXmtWaveformTbl +** Description: Fill in the Transmit Waveform Values +** for driving the transmitter DAC. +** Returns: Nothing +*/ +static void +WrtXmtWaveformTbl(ci_t *ci, struct s_comet_reg *comet, + u_int8_t table[COMET_NUM_SAMPLES][COMET_NUM_UNITS]) +{ + u_int32_t sample, unit; + + for (sample = 0; sample < COMET_NUM_SAMPLES; sample++) { + for (unit = 0; unit < COMET_NUM_UNITS; unit++) + WrtXmtWaveform(ci, comet, sample, unit, + table[sample][unit]); + } + + /* Enable transmitter and set output amplitude */ + pci_write_32((u_int32_t *) &comet->xlpg_cfg, + table[COMET_NUM_SAMPLES][0]); +} + + +/* +** Name: WrtXmtWaveform +** Description: Fill in the Receive Equalizer RAM from the desired +** table. +** Returns: Nothing +** +** Remarks: Per PM4351 Device Errata, Receive Equalizer RAM Initialization +** is coded with early setup of indirect address. +*/ + +static void +WrtRcvEqualizerTbl(ci_t *ci, struct s_comet_reg *comet, u_int32_t *table) +{ + u_int32_t ramaddr; + u_int32_t value; + + for (ramaddr = 0; ramaddr < 256; ramaddr++) { + /*** the following lines are per Errata 7, 2.5 ***/ + { + /* Set up for a read operation */ + pci_write_32((u_int32_t *) &comet->rlps_eq_rwsel, 0x80); + /* for write order preservation when Optimizing driver */ + pci_flush_write(ci); + /* write the addr, initiate a read */ + pci_write_32((u_int32_t *) &comet->rlps_eq_iaddr, + (u_int8_t) ramaddr); + /* for write order preservation when Optimizing driver */ + pci_flush_write(ci); + /* + * wait 3 line rate clock cycles to ensure address bits are + * captured by T1/E1 clock + */ + + /* 683ns * 3 = 1366 ns, approx 2us (but use 4us) */ + OS_uwait(4, "wret"); + } + + value = *table++; + pci_write_32((u_int32_t *) &comet->rlps_idata3, + (u_int8_t) (value >> 24)); + pci_write_32((u_int32_t *) &comet->rlps_idata2, + (u_int8_t) (value >> 16)); + pci_write_32((u_int32_t *) &comet->rlps_idata1, + (u_int8_t) (value >> 8)); + pci_write_32((u_int32_t *) &comet->rlps_idata0, (u_int8_t) value); + /* for write order preservation when Optimizing driver */ + pci_flush_write(ci); + + /* Storing RAM address, causes RAM to be updated */ + + /* Set up for a write operation */ + pci_write_32((u_int32_t *) &comet->rlps_eq_rwsel, 0); + /* for write order preservation when optimizing driver */ + pci_flush_write(ci); + /* write the addr, initiate a read */ + pci_write_32((u_int32_t *) &comet->rlps_eq_iaddr, + (u_int8_t) ramaddr); + /* for write order preservation when optimizing driver */ + pci_flush_write(ci); + + /* + * wait 3 line rate clock cycles to ensure address bits are captured + * by T1/E1 clock + */ + /* 683ns * 3 = 1366 ns, approx 2us (but use 4us) */ + OS_uwait(4, "wret"); + } + + /* Enable Equalizer & set it to use 256 periods */ + pci_write_32((u_int32_t *) &comet->rlps_eq_cfg, 0xCB); +} + + +/* +** Name: SetPwrLevel +** Description: Implement power level setting algorithm described below +** Returns: Nothing +*/ + +static void +SetPwrLevel(struct s_comet_reg *comet) +{ + u_int32_t temp; + +/* +** Algorithm to Balance the Power Distribution of Ttip Tring +** +** Zero register F6 +** Write 0x01 to register F4 +** Write another 0x01 to register F4 +** Read register F4 +** Remove the 0x01 bit by Anding register F4 with 0xFE +** Write the resultant value to register F4 +** Repeat these steps for register F5 +** Write 0x01 to register F6 +*/ + /* XLPG Fuse Data Select */ + pci_write_32((u_int32_t *) &comet->xlpg_fdata_sel, 0x00); + /* XLPG Analog Test Positive control */ + pci_write_32((u_int32_t *) &comet->xlpg_atest_pctl, 0x01); + pci_write_32((u_int32_t *) &comet->xlpg_atest_pctl, 0x01); + temp = pci_read_32((u_int32_t *) &comet->xlpg_atest_pctl) & 0xfe; + pci_write_32((u_int32_t *) &comet->xlpg_atest_pctl, temp); + pci_write_32((u_int32_t *) &comet->xlpg_atest_nctl, 0x01); + pci_write_32((u_int32_t *) &comet->xlpg_atest_nctl, 0x01); + /* XLPG Analog Test Negative control */ + temp = pci_read_32((u_int32_t *) &comet->xlpg_atest_nctl) & 0xfe; + pci_write_32((u_int32_t *) &comet->xlpg_atest_nctl, temp); + /* XLPG */ + pci_write_32((u_int32_t *) &comet->xlpg_fdata_sel, 0x01); +} + + +/* +** Name: SetCometOps +** Description: Set up the selected Comet's clock edge drive for both +** the transmit out the analog side and receive to the +** backplane side. +** Returns: Nothing +*/ +#if 0 +static void +SetCometOps(struct s_comet_reg *comet) +{ + u_int8_t rd_value; + + if (comet == mConfig.C4Func1Base + (COMET0_OFFSET >> 2)) { + /* read the BRIF Configuration */ + rd_value = (u_int8_t) pci_read_32((u_int32_t *) + &comet->brif_cfg); + rd_value &= ~0x20; + pci_write_32((u_int32_t *) &comet->brif_cfg, + (u_int32_t) rd_value); + /* read the BRIF Frame Pulse Configuration */ + rd_value = (u_int8_t) pci_read_32((u_int32_t *) + &comet->brif_fpcfg); + rd_value &= ~0x20; + pci_write_32((u_int32_t *) &comet->brif_fpcfg, + (u_int8_t) rd_value); + } else { + /* read the BRIF Configuration */ + rd_value = (u_int8_t) pci_read_32((u_int32_t *) &comet->brif_cfg); + rd_value |= 0x20; + pci_write_32((u_int32_t *) &comet->brif_cfg, (u_int32_t) rd_value); + /* read the BRIF Frame Pulse Configuration */ + rd_value = (u_int8_t) pci_read_32((u_int32_t *) &comet->brif_fpcfg); + rd_value |= 0x20; + pci_write_32(u_int32_t *) & comet->brif_fpcfg, (u_int8_t) rd_value); + } +} +#endif + +/*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/comet.h b/drivers/staging/cxt1e1/comet.h new file mode 100644 index 00000000000..d5d286e47a4 --- /dev/null +++ b/drivers/staging/cxt1e1/comet.h @@ -0,0 +1,353 @@ +#ifndef _INC_COMET_H_ +#define _INC_COMET_H_ + +/*----------------------------------------------------------------------------- + * comet.h - + * + * Copyright (C) 2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + *----------------------------------------------------------------------------- + */ + +#include <linux/types.h> + +#define VINT32 volatile u_int32_t + +struct s_comet_reg { + VINT32 gbl_cfg; /* 00 Global Cfg */ + VINT32 clkmon; /* 01 Clk Monitor */ + VINT32 rx_opt; /* 02 RX Options */ + VINT32 rx_line_cfg; /* 03 RX Line Interface Cfg */ + VINT32 tx_line_cfg; /* 04 TX Line Interface Cfg */ + VINT32 tx_frpass; /* 05 TX Framing & Bypass Options */ + VINT32 tx_time; /* 06 TX Timing Options */ + VINT32 intr_1; /* 07 Intr Source #1 */ + VINT32 intr_2; /* 08 Intr Source #2 */ + VINT32 intr_3; /* 09 Intr Source #3 */ + VINT32 mdiag; /* 0A Master Diagnostics */ + VINT32 mtest; /* 0B Master Test */ + VINT32 adiag; /* 0C Analog Diagnostics */ + VINT32 rev_id; /* 0D Rev/Chip Id/Global PMON Update */ +#define pmon rev_id + VINT32 reset; /* 0E Reset */ + VINT32 prgd_phctl; /* 0F PRGD Positioning/Ctl & HDLC Ctl */ + VINT32 cdrc_cfg; /* 10 CDRC Cfg */ + VINT32 cdrc_ien; /* 11 CDRC Intr Enable */ + VINT32 cdrc_ists; /* 12 CDRC Intr Sts */ + VINT32 cdrc_alos; /* 13 CDRC Alternate Loss of Signal */ + + VINT32 rjat_ists; /* 14 RJAT Intr Sts */ + VINT32 rjat_n1clk; /* 15 RJAT Reference Clk Divisor (N1) Ctl */ + VINT32 rjat_n2clk; /* 16 RJAT Output Clk Divisor (N2) Ctl */ + VINT32 rjat_cfg; /* 17 RJAT Cfg */ + + VINT32 tjat_ists; /* 18 TJAT Intr Sts */ + VINT32 tjat_n1clk; /* 19 TJAT Reference Clk Divisor (N1) Ctl */ + VINT32 tjat_n2clk; /* 1A TJAT Output Clk Divisor (N2) Ctl */ + VINT32 tjat_cfg; /* 1B TJAT Cfg */ + + VINT32 rx_elst_cfg; /* 1C RX-ELST Cfg */ + VINT32 rx_elst_ists; /* 1D RX-ELST Intr Sts */ + VINT32 rx_elst_idle; /* 1E RX-ELST Idle Code */ + VINT32 _rx_elst_res1f; /* 1F RX-ELST Reserved */ + + VINT32 tx_elst_cfg; /* 20 TX-ELST Cfg */ + VINT32 tx_elst_ists; /* 21 TX-ELST Intr Sts */ + VINT32 _tx_elst_res22; /* 22 TX-ELST Reserved */ + VINT32 _tx_elst_res23; /* 23 TX-ELST Reserved */ + VINT32 __res24; /* 24 Reserved */ + VINT32 __res25; /* 25 Reserved */ + VINT32 __res26; /* 26 Reserved */ + VINT32 __res27; /* 27 Reserved */ + + VINT32 rxce1_ctl; /* 28 RXCE RX Data Link 1 Ctl */ + VINT32 rxce1_bits; /* 29 RXCE RX Data Link 1 Bit Select */ + VINT32 rxce2_ctl; /* 2A RXCE RX Data Link 2 Ctl */ + VINT32 rxce2_bits; /* 2B RXCE RX Data Link 2 Bit Select */ + VINT32 rxce3_ctl; /* 2C RXCE RX Data Link 3 Ctl */ + VINT32 rxce3_bits; /* 2D RXCE RX Data Link 3 Bit Select */ + VINT32 _rxce_res2E; /* 2E RXCE Reserved */ + VINT32 _rxce_res2F; /* 2F RXCE Reserved */ + + VINT32 brif_cfg; /* 30 BRIF RX Backplane Cfg */ + VINT32 brif_fpcfg; /* 31 BRIF RX Backplane Frame Pulse Cfg */ + VINT32 brif_pfcfg; /* 32 BRIF RX Backplane Parity/F-Bit Cfg */ + VINT32 brif_tsoff; /* 33 BRIF RX Backplane Time Slot Offset */ + VINT32 brif_boff; /* 34 BRIF RX Backplane Bit Offset */ + VINT32 _brif_res35; /* 35 BRIF RX Backplane Reserved */ + VINT32 _brif_res36; /* 36 BRIF RX Backplane Reserved */ + VINT32 _brif_res37; /* 37 BRIF RX Backplane Reserved */ + + VINT32 txci1_ctl; /* 38 TXCI TX Data Link 1 Ctl */ + VINT32 txci1_bits; /* 39 TXCI TX Data Link 2 Bit Select */ + VINT32 txci2_ctl; /* 3A TXCI TX Data Link 1 Ctl */ + VINT32 txci2_bits; /* 3B TXCI TX Data Link 2 Bit Select */ + VINT32 txci3_ctl; /* 3C TXCI TX Data Link 1 Ctl */ + VINT32 txci3_bits; /* 3D TXCI TX Data Link 2 Bit Select */ + VINT32 _txci_res3E; /* 3E TXCI Reserved */ + VINT32 _txci_res3F; /* 3F TXCI Reserved */ + + VINT32 btif_cfg; /* 40 BTIF TX Backplane Cfg */ + VINT32 btif_fpcfg; /* 41 BTIF TX Backplane Frame Pulse Cfg */ + VINT32 btif_pcfgsts; /* 42 BTIF TX Backplane Parity Cfg & Sts */ + VINT32 btif_tsoff; /* 43 BTIF TX Backplane Time Slot Offset */ + VINT32 btif_boff; /* 44 BTIF TX Backplane Bit Offset */ + VINT32 _btif_res45; /* 45 BTIF TX Backplane Reserved */ + VINT32 _btif_res46; /* 46 BTIF TX Backplane Reserved */ + VINT32 _btif_res47; /* 47 BTIF TX Backplane Reserved */ + VINT32 t1_frmr_cfg; /* 48 T1 FRMR Cfg */ + VINT32 t1_frmr_ien; /* 49 T1 FRMR Intr Enable */ + VINT32 t1_frmr_ists; /* 4A T1 FRMR Intr Sts */ + VINT32 __res_4B; /* 4B Reserved */ + VINT32 ibcd_cfg; /* 4C IBCD Cfg */ + VINT32 ibcd_ies; /* 4D IBCD Intr Enable/Sts */ + VINT32 ibcd_act; /* 4E IBCD Activate Code */ + VINT32 ibcd_deact; /* 4F IBCD Deactivate Code */ + + VINT32 sigx_cfg; /* 50 SIGX Cfg/Change of Signaling State */ + VINT32 sigx_acc_cos; /* 51 SIGX + * uP Access Sts/Change of Signaling State */ + VINT32 sigx_iac_cos; /* 52 SIGX Channel Indirect + * Addr/Ctl/Change of Signaling State */ + VINT32 sigx_idb_cos; /* 53 SIGX Channel Indirect Data + * Buffer/Change of Signaling State */ + + VINT32 t1_xbas_cfg; /* 54 T1 XBAS Cfg */ + VINT32 t1_xbas_altx; /* 55 T1 XBAS Alarm TX */ + VINT32 t1_xibc_ctl; /* 56 T1 XIBC Ctl */ + VINT32 t1_xibc_lbcode; /* 57 T1 XIBC Loopback Code */ + + VINT32 pmon_ies; /* 58 PMON Intr Enable/Sts */ + VINT32 pmon_fberr; /* 59 PMON Framing Bit Err Cnt */ + VINT32 pmon_feb_lsb; /* 5A PMON + * OFF/COFA/Far End Block Err Cnt (LSB) */ + VINT32 pmon_feb_msb; /* 5B PMON + * OFF/COFA/Far End Block Err Cnt (MSB) */ + VINT32 pmon_bed_lsb; /* 5C PMON Bit/Err/CRCE Cnt (LSB) */ + VINT32 pmon_bed_msb; /* 5D PMON Bit/Err/CRCE Cnt (MSB) */ + VINT32 pmon_lvc_lsb; /* 5E PMON LVC Cnt (LSB) */ + VINT32 pmon_lvc_msb; /* 5F PMON LVC Cnt (MSB) */ + + VINT32 t1_almi_cfg; /* 60 T1 ALMI Cfg */ + VINT32 t1_almi_ien; /* 61 T1 ALMI Intr Enable */ + VINT32 t1_almi_ists; /* 62 T1 ALMI Intr Sts */ + VINT32 t1_almi_detsts; /* 63 T1 ALMI Alarm Detection Sts */ + + VINT32 _t1_pdvd_res64; /* 64 T1 PDVD Reserved */ + VINT32 t1_pdvd_ies; /* 65 T1 PDVD Intr Enable/Sts */ + VINT32 _t1_xboc_res66; /* 66 T1 XBOC Reserved */ + VINT32 t1_xboc_code; /* 67 T1 XBOC Code */ + VINT32 _t1_xpde_res68; /* 68 T1 XPDE Reserved */ + VINT32 t1_xpde_ies; /* 69 T1 XPDE Intr Enable/Sts */ + + VINT32 t1_rboc_ena; /* 6A T1 RBOC Enable */ + VINT32 t1_rboc_sts; /* 6B T1 RBOC Code Sts */ + + VINT32 t1_tpsc_cfg; /* 6C TPSC Cfg */ + VINT32 t1_tpsc_sts; /* 6D TPSC uP Access Sts */ + VINT32 t1_tpsc_ciaddr; /* 6E TPSC Channel Indirect + * Addr/Ctl */ + VINT32 t1_tpsc_cidata; /* 6F TPSC Channel Indirect Data + * Buffer */ + VINT32 t1_rpsc_cfg; /* 70 RPSC Cfg */ + VINT32 t1_rpsc_sts; /* 71 RPSC uP Access Sts */ + VINT32 t1_rpsc_ciaddr; /* 72 RPSC Channel Indirect + * Addr/Ctl */ + VINT32 t1_rpsc_cidata; /* 73 RPSC Channel Indirect Data + * Buffer */ + VINT32 __res74; /* 74 Reserved */ + VINT32 __res75; /* 75 Reserved */ + VINT32 __res76; /* 76 Reserved */ + VINT32 __res77; /* 77 Reserved */ + + VINT32 t1_aprm_cfg; /* 78 T1 APRM Cfg/Ctl */ + VINT32 t1_aprm_load; /* 79 T1 APRM Manual Load */ + VINT32 t1_aprm_ists; /* 7A T1 APRM Intr Sts */ + VINT32 t1_aprm_1sec_2; /* 7B T1 APRM One Second Content Octet 2 */ + VINT32 t1_aprm_1sec_3; /* 7C T1 APRM One Second Content Octet 3 */ + VINT32 t1_aprm_1sec_4; /* 7D T1 APRM One Second Content Octet 4 */ + VINT32 t1_aprm_1sec_5; /* 7E T1 APRM + * One Second Content MSB (Octect 5) */ + VINT32 t1_aprm_1sec_6; /* 7F T1 APRM + * One Second Content MSB (Octect 6) */ + + VINT32 e1_tran_cfg; /* 80 E1 TRAN Cfg */ + VINT32 e1_tran_txalarm; /* 81 E1 TRAN TX Alarm/Diagnostic Ctl */ + VINT32 e1_tran_intctl; /* 82 E1 TRAN International Ctl */ + VINT32 e1_tran_extrab; /* 83 E1 TRAN Extra Bits Ctl */ + VINT32 e1_tran_ien; /* 84 E1 TRAN Intr Enable */ + VINT32 e1_tran_ists; /* 85 E1 TRAN Intr Sts */ + VINT32 e1_tran_nats; /* 86 E1 TRAN National Bit Codeword + * Select */ + VINT32 e1_tran_nat; /* 87 E1 TRAN National Bit Codeword */ + VINT32 __res88; /* 88 Reserved */ + VINT32 __res89; /* 89 Reserved */ + VINT32 __res8A; /* 8A Reserved */ + VINT32 __res8B; /* 8B Reserved */ + + VINT32 _t1_frmr_res8C; /* 8C T1 FRMR Reserved */ + VINT32 _t1_frmr_res8D; /* 8D T1 FRMR Reserved */ + VINT32 __res8E; /* 8E Reserved */ + VINT32 __res8F; /* 8F Reserved */ + + VINT32 e1_frmr_aopts; /* 90 E1 FRMR Frame Alignment Options */ + VINT32 e1_frmr_mopts; /* 91 E1 FRMR Maintenance Mode Options */ + VINT32 e1_frmr_ien; /* 92 E1 FRMR Framing Sts Intr Enable */ + VINT32 e1_frmr_mien; /* 93 E1 FRMR + * Maintenance/Alarm Sts Intr Enable */ + VINT32 e1_frmr_ists; /* 94 E1 FRMR Framing Sts Intr Indication */ + VINT32 e1_frmr_mists; /* 95 E1 FRMR + * Maintenance/Alarm Sts Indication Enable */ + VINT32 e1_frmr_sts; /* 96 E1 FRMR Framing Sts */ + VINT32 e1_frmr_masts; /* 97 E1 FRMR Maintenance/Alarm Sts */ + VINT32 e1_frmr_nat_bits; /* 98 E1 FRMR International/National Bits */ + VINT32 e1_frmr_crc_lsb; /* 99 E1 FRMR CRC Err Cnt - LSB */ + VINT32 e1_frmr_crc_msb; /* 9A E1 FRMR CRC Err Cnt - MSB */ + VINT32 e1_frmr_nat_ien; /* 9B E1 FRMR + * National Bit Codeword Intr Enables */ + VINT32 e1_frmr_nat_ists; /* 9C E1 FRMR + * National Bit Codeword Intr/Sts */ + VINT32 e1_frmr_nat; /* 9D E1 FRMR National Bit Codewords */ + VINT32 e1_frmr_fp_ien; /* 9E E1 FRMR + * Frame Pulse/Alarm Intr Enables */ + VINT32 e1_frmr_fp_ists; /* 9F E1 FRMR Frame Pulse/Alarm Intr/Sts */ + + VINT32 __resA0; /* A0 Reserved */ + VINT32 __resA1; /* A1 Reserved */ + VINT32 __resA2; /* A2 Reserved */ + VINT32 __resA3; /* A3 Reserved */ + VINT32 __resA4; /* A4 Reserved */ + VINT32 __resA5; /* A5 Reserved */ + VINT32 __resA6; /* A6 Reserved */ + VINT32 __resA7; /* A7 Reserved */ + + VINT32 tdpr1_cfg; /* A8 TDPR #1 Cfg */ + VINT32 tdpr1_utl; /* A9 TDPR #1 Upper TX Threshold */ + VINT32 tdpr1_ltl; /* AA TDPR #1 Lower TX Threshold */ + VINT32 tdpr1_ien; /* AB TDPR #1 Intr Enable */ + VINT32 tdpr1_ists; /* AC TDPR #1 Intr Sts/UDR Clear */ + VINT32 tdpr1_data; /* AD TDPR #1 TX Data */ + VINT32 __resAE; /* AE Reserved */ + VINT32 __resAF; /* AF Reserved */ + VINT32 tdpr2_cfg; /* B0 TDPR #2 Cfg */ + VINT32 tdpr2_utl; /* B1 TDPR #2 Upper TX Threshold */ + VINT32 tdpr2_ltl; /* B2 TDPR #2 Lower TX Threshold */ + VINT32 tdpr2_ien; /* B3 TDPR #2 Intr Enable */ + VINT32 tdpr2_ists; /* B4 TDPR #2 Intr Sts/UDR Clear */ + VINT32 tdpr2_data; /* B5 TDPR #2 TX Data */ + VINT32 __resB6; /* B6 Reserved */ + VINT32 __resB7; /* B7 Reserved1 */ + VINT32 tdpr3_cfg; /* B8 TDPR #3 Cfg */ + VINT32 tdpr3_utl; /* B9 TDPR #3 Upper TX Threshold */ + VINT32 tdpr3_ltl; /* BA TDPR #3 Lower TX Threshold */ + VINT32 tdpr3_ien; /* BB TDPR #3 Intr Enable */ + VINT32 tdpr3_ists; /* BC TDPR #3 Intr Sts/UDR Clear */ + VINT32 tdpr3_data; /* BD TDPR #3 TX Data */ + VINT32 __resBE; /* BE Reserved */ + VINT32 __resBF; /* BF Reserved */ + + VINT32 rdlc1_cfg; /* C0 RDLC #1 Cfg */ + VINT32 rdlc1_intctl; /* C1 RDLC #1 Intr Ctl */ + VINT32 rdlc1_sts; /* C2 RDLC #1 Sts */ + VINT32 rdlc1_data; /* C3 RDLC #1 Data */ + VINT32 rdlc1_paddr; /* C4 RDLC #1 Primary Addr Match */ + VINT32 rdlc1_saddr; /* C5 RDLC #1 Secondary Addr Match */ + VINT32 __resC6; /* C6 Reserved */ + VINT32 __resC7; /* C7 Reserved */ + VINT32 rdlc2_cfg; /* C8 RDLC #2 Cfg */ + VINT32 rdlc2_intctl; /* C9 RDLC #2 Intr Ctl */ + VINT32 rdlc2_sts; /* CA RDLC #2 Sts */ + VINT32 rdlc2_data; /* CB RDLC #2 Data */ + VINT32 rdlc2_paddr; /* CC RDLC #2 Primary Addr Match */ + VINT32 rdlc2_saddr; /* CD RDLC #2 Secondary Addr Match */ + VINT32 __resCE; /* CE Reserved */ + VINT32 __resCF; /* CF Reserved */ + VINT32 rdlc3_cfg; /* D0 RDLC #3 Cfg */ + VINT32 rdlc3_intctl; /* D1 RDLC #3 Intr Ctl */ + VINT32 rdlc3_sts; /* D2 RDLC #3 Sts */ + VINT32 rdlc3_data; /* D3 RDLC #3 Data */ + VINT32 rdlc3_paddr; /* D4 RDLC #3 Primary Addr Match */ + VINT32 rdlc3_saddr; /* D5 RDLC #3 Secondary Addr Match */ + + VINT32 csu_cfg; /* D6 CSU Cfg */ + VINT32 _csu_resD7; /* D7 CSU Reserved */ + + VINT32 rlps_idata3; /* D8 RLPS Indirect Data, 24-31 */ + VINT32 rlps_idata2; /* D9 RLPS Indirect Data, 16-23 */ + VINT32 rlps_idata1; /* DA RLPS Indirect Data, 8-15 */ + VINT32 rlps_idata0; /* DB RLPS Indirect Data, 0-7 */ + VINT32 rlps_eqvr; /* DC RLPS Equalizer Voltage Reference + * (E1 missing) */ + VINT32 _rlps_resDD; /* DD RLPS Reserved */ + VINT32 _rlps_resDE; /* DE RLPS Reserved */ + VINT32 _rlps_resDF; /* DF RLPS Reserved */ + + VINT32 prgd_ctl; /* E0 PRGD Ctl */ + VINT32 prgd_ies; /* E1 PRGD Intr Enable/Sts */ + VINT32 prgd_shift_len; /* E2 PRGD Shift Length */ + VINT32 prgd_tap; /* E3 PRGD Tap */ + VINT32 prgd_errin; /* E4 PRGD Err Insertion */ + VINT32 _prgd_resE5; /* E5 PRGD Reserved */ + VINT32 _prgd_resE6; /* E6 PRGD Reserved */ + VINT32 _prgd_resE7; /* E7 PRGD Reserved */ + VINT32 prgd_patin1; /* E8 PRGD Pattern Insertion #1 */ + VINT32 prgd_patin2; /* E9 PRGD Pattern Insertion #2 */ + VINT32 prgd_patin3; /* EA PRGD Pattern Insertion #3 */ + VINT32 prgd_patin4; /* EB PRGD Pattern Insertion #4 */ + VINT32 prgd_patdet1; /* EC PRGD Pattern Detector #1 */ + VINT32 prgd_patdet2; /* ED PRGD Pattern Detector #2 */ + VINT32 prgd_patdet3; /* EE PRGD Pattern Detector #3 */ + VINT32 prgd_patdet4; /* EF PRGD Pattern Detector #4 */ + + VINT32 xlpg_cfg; /* F0 XLPG Line Driver Cfg */ + VINT32 xlpg_ctlsts; /* F1 XLPG Ctl/Sts */ + VINT32 xlpg_pwave_addr; /* F2 XLPG + * Pulse Waveform Storage Write Addr */ + VINT32 xlpg_pwave_data; /* F3 XLPG Pulse Waveform Storage Data */ + VINT32 xlpg_atest_pctl; /* F4 XLPG Analog Test Positive Ctl */ + VINT32 xlpg_atest_nctl; /* F5 XLPG Analog Test Negative Ctl */ + VINT32 xlpg_fdata_sel; /* F6 XLPG Fuse Data Select */ + VINT32 _xlpg_resF7; /* F7 XLPG Reserved */ + + VINT32 rlps_cfgsts; /* F8 RLPS Cfg & Sts */ + VINT32 rlps_alos_thresh; /* F9 RLPS + * ALOS Detection/Clearance Threshold */ + VINT32 rlps_alos_dper; /* FA RLPS ALOS Detection Period */ + VINT32 rlps_alos_cper; /* FB RLPS ALOS Clearance Period */ + VINT32 rlps_eq_iaddr; /* FC RLPS Equalization Indirect Addr */ + VINT32 rlps_eq_rwsel; /* FD RLPS Equalization Read/WriteB Select */ + VINT32 rlps_eq_ctlsts; /* FE RLPS Equalizer Loop Sts & Ctl */ + VINT32 rlps_eq_cfg; /* FF RLPS Equalizer Cfg */ +}; + +/* 00AH: MDIAG Register bit definitions */ +#define COMET_MDIAG_ID5 0x40 +#define COMET_MDIAG_LBMASK 0x3F +#define COMET_MDIAG_PAYLB 0x20 +#define COMET_MDIAG_LINELB 0x10 +#define COMET_MDIAG_RAIS 0x08 +#define COMET_MDIAG_DDLB 0x04 +#define COMET_MDIAG_TXMFP 0x02 +#define COMET_MDIAG_TXLOS 0x01 +#define COMET_MDIAG_LBOFF 0x00 + +#undef VINT32 + +#ifdef __KERNEL__ +extern void +init_comet(void *, struct s_comet_reg *, u_int32_t, int, u_int8_t); +#endif + +#endif /* _INC_COMET_H_ */ diff --git a/drivers/staging/cxt1e1/comet_tables.c b/drivers/staging/cxt1e1/comet_tables.c new file mode 100644 index 00000000000..e96665ea366 --- /dev/null +++ b/drivers/staging/cxt1e1/comet_tables.c @@ -0,0 +1,538 @@ +/*----------------------------------------------------------------------------- + * comet_tables.c - waveform tables for the PM4351 'COMET' + * + * Copyright (C) 2003-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + *----------------------------------------------------------------------------- + */ + +#include <linux/types.h> +#include "comet_tables.h" + +/***************************************************************************** +* +* Array names: +* +* TWVLongHaul0DB +* TWVLongHaul7_5DB +* TWVLongHaul15DB +* TWVLongHaul22_5DB +* TWVShortHaul0 +* TWVShortHaul1 +* TWVShortHaul2 +* TWVShortHaul3 +* TWVShortHaul4 +* TWVShortHaul5 +* TWV_E1_120Ohm +* TWV_E1_75Ohm <not supported> +* T1_Equalizer +* E1_Equalizer +* +*****************************************************************************/ + +u_int8_t TWVLongHaul0DB[25][5] =/* T1 Long Haul 0 DB */ +{ + {0x00, 0x44, 0x00, 0x00, 0x00}, /* Sample 0 */ + {0x0A, 0x44, 0x00, 0x00, 0x00}, /* Sample 1 */ + {0x20, 0x43, 0x00, 0x00, 0x00}, /* Sample 2 */ + {0x32, 0x43, 0x00, 0x00, 0x00}, /* Sample 3 */ + {0x3E, 0x42, 0x00, 0x00, 0x00}, /* Sample 4 */ + {0x3D, 0x42, 0x00, 0x00, 0x00}, /* Sample 5 */ + {0x3C, 0x41, 0x00, 0x00, 0x00}, /* Sample 6 */ + {0x3B, 0x41, 0x00, 0x00, 0x00}, /* Sample 7 */ + {0x3A, 0x00, 0x00, 0x00, 0x00}, /* Sample 8 */ + {0x39, 0x00, 0x00, 0x00, 0x00}, /* Sample 9 */ + {0x39, 0x00, 0x00, 0x00, 0x00}, /* Sample 10 */ + {0x38, 0x00, 0x00, 0x00, 0x00}, /* Sample 11 */ + {0x37, 0x00, 0x00, 0x00, 0x00}, /* Sample 12 */ + {0x36, 0x00, 0x00, 0x00, 0x00}, /* Sample 13 */ + {0x34, 0x00, 0x00, 0x00, 0x00}, /* Sample 14 */ + {0x29, 0x00, 0x00, 0x00, 0x00}, /* Sample 15 */ + {0x4F, 0x00, 0x00, 0x00, 0x00}, /* Sample 16 */ + {0x4C, 0x00, 0x00, 0x00, 0x00}, /* Sample 17 */ + {0x4A, 0x00, 0x00, 0x00, 0x00}, /* Sample 18 */ + {0x49, 0x00, 0x00, 0x00, 0x00}, /* Sample 19 */ + {0x47, 0x00, 0x00, 0x00, 0x00}, /* Sample 20 */ + {0x47, 0x00, 0x00, 0x00, 0x00}, /* Sample 21 */ + {0x46, 0x00, 0x00, 0x00, 0x00}, /* Sample 22 */ + {0x46, 0x00, 0x00, 0x00, 0x00}, /* Sample 23 */ + {0x0C} /* PMC's suggested value */ +/* {0x14} Output Amplitude */ +}; + +u_int8_t TWVLongHaul7_5DB[25][5] = /* T1 Long Haul 7.5 DB */ +{ + {0x00, 0x10, 0x00, 0x00, 0x00}, /* Sample 0 */ + {0x01, 0x0E, 0x00, 0x00, 0x00}, /* Sample 1 */ + {0x02, 0x0C, 0x00, 0x00, 0x00}, /* Sample 2 */ + {0x04, 0x0A, 0x00, 0x00, 0x00}, /* Sample 3 */ + {0x08, 0x08, 0x00, 0x00, 0x00}, /* Sample 4 */ + {0x0C, 0x06, 0x00, 0x00, 0x00}, /* Sample 5 */ + {0x10, 0x04, 0x00, 0x00, 0x00}, /* Sample 6 */ + {0x16, 0x02, 0x00, 0x00, 0x00}, /* Sample 7 */ + {0x1A, 0x01, 0x00, 0x00, 0x00}, /* Sample 8 */ + {0x1E, 0x00, 0x00, 0x00, 0x00}, /* Sample 9 */ + {0x22, 0x00, 0x00, 0x00, 0x00}, /* Sample 10 */ + {0x26, 0x00, 0x00, 0x00, 0x00}, /* Sample 11 */ + {0x2A, 0x00, 0x00, 0x00, 0x00}, /* Sample 12 */ + {0x2B, 0x00, 0x00, 0x00, 0x00}, /* Sample 13 */ + {0x2C, 0x00, 0x00, 0x00, 0x00}, /* Sample 14 */ + {0x2D, 0x00, 0x00, 0x00, 0x00}, /* Sample 15 */ + {0x2C, 0x00, 0x00, 0x00, 0x00}, /* Sample 16 */ + {0x28, 0x00, 0x00, 0x00, 0x00}, /* Sample 17 */ + {0x24, 0x00, 0x00, 0x00, 0x00}, /* Sample 18 */ + {0x20, 0x00, 0x00, 0x00, 0x00}, /* Sample 19 */ + {0x1C, 0x00, 0x00, 0x00, 0x00}, /* Sample 20 */ + {0x18, 0x00, 0x00, 0x00, 0x00}, /* Sample 21 */ + {0x14, 0x00, 0x00, 0x00, 0x00}, /* Sample 22 */ + {0x12, 0x00, 0x00, 0x00, 0x00}, /* Sample 23 */ + {0x07} /* PMC's suggested value */ +/* { 0x0A } Output Amplitude */ +}; + +u_int8_t TWVLongHaul15DB[25][5] = /* T1 Long Haul 15 DB */ +{ + {0x00, 0x2A, 0x09, 0x01, 0x00}, /* Sample 0 */ + {0x00, 0x28, 0x08, 0x01, 0x00}, /* Sample 1 */ + {0x00, 0x26, 0x08, 0x01, 0x00}, /* Sample 2 */ + {0x00, 0x24, 0x07, 0x01, 0x00}, /* Sample 3 */ + {0x01, 0x22, 0x07, 0x01, 0x00}, /* Sample 4 */ + {0x02, 0x20, 0x06, 0x01, 0x00}, /* Sample 5 */ + {0x04, 0x1E, 0x06, 0x01, 0x00}, /* Sample 6 */ + {0x07, 0x1C, 0x05, 0x00, 0x00}, /* Sample 7 */ + {0x0A, 0x1B, 0x05, 0x00, 0x00}, /* Sample 8 */ + {0x0D, 0x19, 0x05, 0x00, 0x00}, /* Sample 9 */ + {0x10, 0x18, 0x04, 0x00, 0x00}, /* Sample 10 */ + {0x14, 0x16, 0x04, 0x00, 0x00}, /* Sample 11 */ + {0x18, 0x15, 0x04, 0x00, 0x00}, /* Sample 12 */ + {0x1B, 0x13, 0x03, 0x00, 0x00}, /* Sample 13 */ + {0x1E, 0x12, 0x03, 0x00, 0x00}, /* Sample 14 */ + {0x21, 0x10, 0x03, 0x00, 0x00}, /* Sample 15 */ + {0x24, 0x0F, 0x03, 0x00, 0x00}, /* Sample 16 */ + {0x27, 0x0D, 0x03, 0x00, 0x00}, /* Sample 17 */ + {0x2A, 0x0D, 0x02, 0x00, 0x00}, /* Sample 18 */ + {0x2D, 0x0B, 0x02, 0x00, 0x00}, /* Sample 19 */ + {0x30, 0x0B, 0x02, 0x00, 0x00}, /* Sample 20 */ + {0x30, 0x0A, 0x02, 0x00, 0x00}, /* Sample 21 */ + {0x2E, 0x0A, 0x02, 0x00, 0x00}, /* Sample 22 */ + {0x2C, 0x09, 0x02, 0x00, 0x00}, /* Sample 23 */ + {0x03} /* Output Amplitude */ +}; + +u_int8_t TWVLongHaul22_5DB[25][5] = /* T1 Long Haul 22.5 DB */ +{ + {0x00, 0x1F, 0x16, 0x06, 0x01}, /* Sample 0 */ + {0x00, 0x20, 0x15, 0x05, 0x01}, /* Sample 1 */ + {0x00, 0x21, 0x15, 0x05, 0x01}, /* Sample 2 */ + {0x00, 0x22, 0x14, 0x05, 0x01}, /* Sample 3 */ + {0x00, 0x22, 0x13, 0x04, 0x00}, /* Sample 4 */ + {0x00, 0x23, 0x12, 0x04, 0x00}, /* Sample 5 */ + {0x01, 0x23, 0x12, 0x04, 0x00}, /* Sample 6 */ + {0x01, 0x24, 0x11, 0x03, 0x00}, /* Sample 7 */ + {0x01, 0x23, 0x10, 0x03, 0x00}, /* Sample 8 */ + {0x02, 0x23, 0x10, 0x03, 0x00}, /* Sample 9 */ + {0x03, 0x22, 0x0F, 0x03, 0x00}, /* Sample 10 */ + {0x05, 0x22, 0x0E, 0x03, 0x00}, /* Sample 11 */ + {0x07, 0x21, 0x0E, 0x02, 0x00}, /* Sample 12 */ + {0x09, 0x20, 0x0D, 0x02, 0x00}, /* Sample 13 */ + {0x0B, 0x1E, 0x0C, 0x02, 0x00}, /* Sample 14 */ + {0x0E, 0x1D, 0x0C, 0x02, 0x00}, /* Sample 15 */ + {0x10, 0x1B, 0x0B, 0x02, 0x00}, /* Sample 16 */ + {0x13, 0x1B, 0x0A, 0x02, 0x00}, /* Sample 17 */ + {0x15, 0x1A, 0x0A, 0x02, 0x00}, /* Sample 18 */ + {0x17, 0x19, 0x09, 0x01, 0x00}, /* Sample 19 */ + {0x19, 0x19, 0x08, 0x01, 0x00}, /* Sample 20 */ + {0x1B, 0x18, 0x08, 0x01, 0x00}, /* Sample 21 */ + {0x1D, 0x17, 0x07, 0x01, 0x00}, /* Sample 22 */ + {0x1E, 0x17, 0x06, 0x01, 0x00}, /* Sample 23 */ + {0x02} /* Output Amplitude */ +}; + +u_int8_t TWVShortHaul0[25][5] = /* T1 Short Haul 0 - 110 ft */ +{ + {0x00, 0x45, 0x00, 0x00, 0x00}, /* Sample 0 */ + {0x0A, 0x44, 0x00, 0x00, 0x00}, /* Sample 1 */ + {0x20, 0x43, 0x00, 0x00, 0x00}, /* Sample 2 */ + {0x3F, 0x43, 0x00, 0x00, 0x00}, /* Sample 3 */ + {0x3F, 0x42, 0x00, 0x00, 0x00}, /* Sample 4 */ + {0x3F, 0x42, 0x00, 0x00, 0x00}, /* Sample 5 */ + {0x3C, 0x41, 0x00, 0x00, 0x00}, /* Sample 6 */ + {0x3B, 0x41, 0x00, 0x00, 0x00}, /* Sample 7 */ + {0x3A, 0x00, 0x00, 0x00, 0x00}, /* Sample 8 */ + {0x39, 0x00, 0x00, 0x00, 0x00}, /* Sample 9 */ + {0x39, 0x00, 0x00, 0x00, 0x00}, /* Sample 10 */ + {0x38, 0x00, 0x00, 0x00, 0x00}, /* Sample 11 */ + {0x37, 0x00, 0x00, 0x00, 0x00}, /* Sample 12 */ + {0x36, 0x00, 0x00, 0x00, 0x00}, /* Sample 13 */ + {0x34, 0x00, 0x00, 0x00, 0x00}, /* Sample 14 */ + {0x29, 0x00, 0x00, 0x00, 0x00}, /* Sample 15 */ + {0x59, 0x00, 0x00, 0x00, 0x00}, /* Sample 16 */ + {0x55, 0x00, 0x00, 0x00, 0x00}, /* Sample 17 */ + {0x50, 0x00, 0x00, 0x00, 0x00}, /* Sample 18 */ + {0x4D, 0x00, 0x00, 0x00, 0x00}, /* Sample 19 */ + {0x4A, 0x00, 0x00, 0x00, 0x00}, /* Sample 20 */ + {0x48, 0x00, 0x00, 0x00, 0x00}, /* Sample 21 */ + {0x46, 0x00, 0x00, 0x00, 0x00}, /* Sample 22 */ + {0x46, 0x00, 0x00, 0x00, 0x00}, /* Sample 23 */ + {0x0C} /* Output Amplitude */ +}; + +u_int8_t TWVShortHaul1[25][5] = /* T1 Short Haul 110 - 220 ft */ +{ + {0x00, 0x44, 0x00, 0x00, 0x00}, /* Sample 0 */ + {0x0A, 0x44, 0x00, 0x00, 0x00}, /* Sample 1 */ + {0x3F, 0x43, 0x00, 0x00, 0x00}, /* Sample 2 */ + {0x3F, 0x43, 0x00, 0x00, 0x00}, /* Sample 3 */ + {0x36, 0x42, 0x00, 0x00, 0x00}, /* Sample 4 */ + {0x34, 0x42, 0x00, 0x00, 0x00}, /* Sample 5 */ + {0x30, 0x41, 0x00, 0x00, 0x00}, /* Sample 6 */ + {0x2F, 0x41, 0x00, 0x00, 0x00}, /* Sample 7 */ + {0x2E, 0x00, 0x00, 0x00, 0x00}, /* Sample 8 */ + {0x2D, 0x00, 0x00, 0x00, 0x00}, /* Sample 9 */ + {0x2C, 0x00, 0x00, 0x00, 0x00}, /* Sample 10 */ + {0x2B, 0x00, 0x00, 0x00, 0x00}, /* Sample 11 */ + {0x2A, 0x00, 0x00, 0x00, 0x00}, /* Sample 12 */ + {0x28, 0x00, 0x00, 0x00, 0x00}, /* Sample 13 */ + {0x26, 0x00, 0x00, 0x00, 0x00}, /* Sample 14 */ + {0x4A, 0x00, 0x00, 0x00, 0x00}, /* Sample 15 */ + {0x68, 0x00, 0x00, 0x00, 0x00}, /* Sample 16 */ + {0x54, 0x00, 0x00, 0x00, 0x00}, /* Sample 17 */ + {0x4F, 0x00, 0x00, 0x00, 0x00}, /* Sample 18 */ + {0x4A, 0x00, 0x00, 0x00, 0x00}, /* Sample 19 */ + {0x49, 0x00, 0x00, 0x00, 0x00}, /* Sample 20 */ + {0x47, 0x00, 0x00, 0x00, 0x00}, /* Sample 21 */ + {0x47, 0x00, 0x00, 0x00, 0x00}, /* Sample 22 */ + {0x46, 0x00, 0x00, 0x00, 0x00}, /* Sample 23 */ + {0x10} /* Output Amplitude */ +}; + +u_int8_t TWVShortHaul2[25][5] = /* T1 Short Haul 220 - 330 ft */ +{ + {0x00, 0x44, 0x00, 0x00, 0x00}, /* Sample 0 */ + {0x0A, 0x44, 0x00, 0x00, 0x00}, /* Sample 1 */ + {0x3F, 0x43, 0x00, 0x00, 0x00}, /* Sample 2 */ + {0x3A, 0x43, 0x00, 0x00, 0x00}, /* Sample 3 */ + {0x3A, 0x42, 0x00, 0x00, 0x00}, /* Sample 4 */ + {0x38, 0x42, 0x00, 0x00, 0x00}, /* Sample 5 */ + {0x30, 0x41, 0x00, 0x00, 0x00}, /* Sample 6 */ + {0x2F, 0x41, 0x00, 0x00, 0x00}, /* Sample 7 */ + {0x2E, 0x00, 0x00, 0x00, 0x00}, /* Sample 8 */ + {0x2D, 0x00, 0x00, 0x00, 0x00}, /* Sample 9 */ + {0x2C, 0x00, 0x00, 0x00, 0x00}, /* Sample 10 */ + {0x2B, 0x00, 0x00, 0x00, 0x00}, /* Sample 11 */ + {0x2A, 0x00, 0x00, 0x00, 0x00}, /* Sample 12 */ + {0x29, 0x00, 0x00, 0x00, 0x00}, /* Sample 13 */ + {0x23, 0x00, 0x00, 0x00, 0x00}, /* Sample 14 */ + {0x4A, 0x00, 0x00, 0x00, 0x00}, /* Sample 15 */ + {0x6C, 0x00, 0x00, 0x00, 0x00}, /* Sample 16 */ + {0x60, 0x00, 0x00, 0x00, 0x00}, /* Sample 17 */ + {0x4F, 0x00, 0x00, 0x00, 0x00}, /* Sample 18 */ + {0x4A, 0x00, 0x00, 0x00, 0x00}, /* Sample 19 */ + {0x49, 0x00, 0x00, 0x00, 0x00}, /* Sample 20 */ + {0x47, 0x00, 0x00, 0x00, 0x00}, /* Sample 21 */ + {0x47, 0x00, 0x00, 0x00, 0x00}, /* Sample 22 */ + {0x46, 0x00, 0x00, 0x00, 0x00}, /* Sample 23 */ + {0x11} /* Output Amplitude */ +}; + +u_int8_t TWVShortHaul3[25][5] = /* T1 Short Haul 330 - 440 ft */ +{ + {0x00, 0x44, 0x00, 0x00, 0x00}, /* Sample 0 */ + {0x0A, 0x44, 0x00, 0x00, 0x00}, /* Sample 1 */ + {0x3F, 0x43, 0x00, 0x00, 0x00}, /* Sample 2 */ + {0x3F, 0x43, 0x00, 0x00, 0x00}, /* Sample 3 */ + {0x3F, 0x42, 0x00, 0x00, 0x00}, /* Sample 4 */ + {0x3F, 0x42, 0x00, 0x00, 0x00}, /* Sample 5 */ + {0x2F, 0x41, 0x00, 0x00, 0x00}, /* Sample 6 */ + {0x2E, 0x41, 0x00, 0x00, 0x00}, /* Sample 7 */ + {0x2D, 0x00, 0x00, 0x00, 0x00}, /* Sample 8 */ + {0x2C, 0x00, 0x00, 0x00, 0x00}, /* Sample 9 */ + {0x2B, 0x00, 0x00, 0x00, 0x00}, /* Sample 10 */ + {0x2A, 0x00, 0x00, 0x00, 0x00}, /* Sample 11 */ + {0x29, 0x00, 0x00, 0x00, 0x00}, /* Sample 12 */ + {0x28, 0x00, 0x00, 0x00, 0x00}, /* Sample 13 */ + {0x19, 0x00, 0x00, 0x00, 0x00}, /* Sample 14 */ + {0x4A, 0x00, 0x00, 0x00, 0x00}, /* Sample 15 */ + {0x7F, 0x00, 0x00, 0x00, 0x00}, /* Sample 16 */ + {0x60, 0x00, 0x00, 0x00, 0x00}, /* Sample 17 */ + {0x4F, 0x00, 0x00, 0x00, 0x00}, /* Sample 18 */ + {0x4A, 0x00, 0x00, 0x00, 0x00}, /* Sample 19 */ + {0x49, 0x00, 0x00, 0x00, 0x00}, /* Sample 20 */ + {0x47, 0x00, 0x00, 0x00, 0x00}, /* Sample 21 */ + {0x47, 0x00, 0x00, 0x00, 0x00}, /* Sample 22 */ + {0x46, 0x00, 0x00, 0x00, 0x00}, /* Sample 23 */ + {0x12} /* Output Amplitude */ +}; + +u_int8_t TWVShortHaul4[25][5] = /* T1 Short Haul 440 - 550 ft */ +{ + {0x00, 0x44, 0x00, 0x00, 0x00}, /* Sample 0 */ + {0x0A, 0x44, 0x00, 0x00, 0x00}, /* Sample 1 */ + {0x3F, 0x43, 0x00, 0x00, 0x00}, /* Sample 2 */ + {0x3F, 0x43, 0x00, 0x00, 0x00}, /* Sample 3 */ + {0x3F, 0x42, 0x00, 0x00, 0x00}, /* Sample 4 */ + {0x3F, 0x42, 0x00, 0x00, 0x00}, /* Sample 5 */ + {0x30, 0x41, 0x00, 0x00, 0x00}, /* Sample 6 */ + {0x2B, 0x41, 0x00, 0x00, 0x00}, /* Sample 7 */ + {0x2A, 0x00, 0x00, 0x00, 0x00}, /* Sample 8 */ + {0x29, 0x00, 0x00, 0x00, 0x00}, /* Sample 9 */ + {0x28, 0x00, 0x00, 0x00, 0x00}, /* Sample 10 */ + {0x27, 0x00, 0x00, 0x00, 0x00}, /* Sample 11 */ + {0x26, 0x00, 0x00, 0x00, 0x00}, /* Sample 12 */ + {0x26, 0x00, 0x00, 0x00, 0x00}, /* Sample 13 */ + {0x24, 0x00, 0x00, 0x00, 0x00}, /* Sample 14 */ + {0x4A, 0x00, 0x00, 0x00, 0x00}, /* Sample 15 */ + {0x7F, 0x00, 0x00, 0x00, 0x00}, /* Sample 16 */ + {0x7F, 0x00, 0x00, 0x00, 0x00}, /* Sample 17 */ + {0x4F, 0x00, 0x00, 0x00, 0x00}, /* Sample 18 */ + {0x4A, 0x00, 0x00, 0x00, 0x00}, /* Sample 19 */ + {0x49, 0x00, 0x00, 0x00, 0x00}, /* Sample 20 */ + {0x47, 0x00, 0x00, 0x00, 0x00}, /* Sample 21 */ + {0x47, 0x00, 0x00, 0x00, 0x00}, /* Sample 22 */ + {0x46, 0x00, 0x00, 0x00, 0x00}, /* Sample 23 */ + {0x14} /* Output Amplitude */ +}; + +u_int8_t TWVShortHaul5[25][5] = /* T1 Short Haul 550 - 660 ft */ +{ + {0x00, 0x44, 0x00, 0x00, 0x00}, /* Sample 0 */ + {0x0A, 0x44, 0x00, 0x00, 0x00}, /* Sample 1 */ + {0x3F, 0x43, 0x00, 0x00, 0x00}, /* Sample 2 */ + {0x3F, 0x43, 0x00, 0x00, 0x00}, /* Sample 3 */ + {0x3F, 0x42, 0x00, 0x00, 0x00}, /* Sample 4 */ + {0x3F, 0x42, 0x00, 0x00, 0x00}, /* Sample 5 */ + {0x3F, 0x41, 0x00, 0x00, 0x00}, /* Sample 6 */ + {0x30, 0x41, 0x00, 0x00, 0x00}, /* Sample 7 */ + {0x2A, 0x00, 0x00, 0x00, 0x00}, /* Sample 8 */ + {0x29, 0x00, 0x00, 0x00, 0x00}, /* Sample 9 */ + {0x28, 0x00, 0x00, 0x00, 0x00}, /* Sample 10 */ + {0x27, 0x00, 0x00, 0x00, 0x00}, /* Sample 11 */ + {0x26, 0x00, 0x00, 0x00, 0x00}, /* Sample 12 */ + {0x25, 0x00, 0x00, 0x00, 0x00}, /* Sample 13 */ + {0x24, 0x00, 0x00, 0x00, 0x00}, /* Sample 14 */ + {0x4A, 0x00, 0x00, 0x00, 0x00}, /* Sample 15 */ + {0x7F, 0x00, 0x00, 0x00, 0x00}, /* Sample 16 */ + {0x7F, 0x00, 0x00, 0x00, 0x00}, /* Sample 17 */ + {0x5F, 0x00, 0x00, 0x00, 0x00}, /* Sample 18 */ + {0x50, 0x00, 0x00, 0x00, 0x00}, /* Sample 19 */ + {0x49, 0x00, 0x00, 0x00, 0x00}, /* Sample 20 */ + {0x47, 0x00, 0x00, 0x00, 0x00}, /* Sample 21 */ + {0x47, 0x00, 0x00, 0x00, 0x00}, /* Sample 22 */ + {0x46, 0x00, 0x00, 0x00, 0x00}, /* Sample 23 */ + {0x15} /* Output Amplitude */ +}; + +u_int8_t TWV_E1_120Ohm[25][5] = /* E1 120 Ohm */ +{ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 0 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 1 */ + {0x0A, 0x00, 0x00, 0x00, 0x00}, /* Sample 2 */ + {0x3F, 0x00, 0x00, 0x00, 0x00}, /* Sample 3 */ + {0x3F, 0x00, 0x00, 0x00, 0x00}, /* Sample 4 */ + {0x39, 0x00, 0x00, 0x00, 0x00}, /* Sample 5 */ + {0x38, 0x00, 0x00, 0x00, 0x00}, /* Sample 6 */ + {0x36, 0x00, 0x00, 0x00, 0x00}, /* Sample 7 */ + {0x36, 0x00, 0x00, 0x00, 0x00}, /* Sample 8 */ + {0x35, 0x00, 0x00, 0x00, 0x00}, /* Sample 9 */ + {0x35, 0x00, 0x00, 0x00, 0x00}, /* Sample 10 */ + {0x35, 0x00, 0x00, 0x00, 0x00}, /* Sample 11 */ + {0x35, 0x00, 0x00, 0x00, 0x00}, /* Sample 12 */ + {0x35, 0x00, 0x00, 0x00, 0x00}, /* Sample 13 */ + {0x35, 0x00, 0x00, 0x00, 0x00}, /* Sample 14 */ + {0x2D, 0x00, 0x00, 0x00, 0x00}, /* Sample 15 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 16 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 17 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 18 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 19 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 20 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 21 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 22 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 23 */ + {0x0C} /* PMC's suggested value */ +/* { 0x10 } Output Amplitude */ +}; + + + +u_int8_t TWV_E1_75Ohm[25][5] = /* E1 75 Ohm */ +{ +#ifdef PMCC4_DOES_NOT_SUPPORT + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 0 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 1 */ + {0x0A, 0x00, 0x00, 0x00, 0x00}, /* Sample 2 */ + {0x28, 0x00, 0x00, 0x00, 0x00}, /* Sample 3 */ + {0x3A, 0x00, 0x00, 0x00, 0x00}, /* Sample 4 */ + {0x3A, 0x00, 0x00, 0x00, 0x00}, /* Sample 5 */ + {0x3A, 0x00, 0x00, 0x00, 0x00}, /* Sample 6 */ + {0x3A, 0x00, 0x00, 0x00, 0x00}, /* Sample 7 */ + {0x3A, 0x00, 0x00, 0x00, 0x00}, /* Sample 8 */ + {0x3A, 0x00, 0x00, 0x00, 0x00}, /* Sample 9 */ + {0x3A, 0x00, 0x00, 0x00, 0x00}, /* Sample 10 */ + {0x3A, 0x00, 0x00, 0x00, 0x00}, /* Sample 11 */ + {0x3A, 0x00, 0x00, 0x00, 0x00}, /* Sample 12 */ + {0x3A, 0x00, 0x00, 0x00, 0x00}, /* Sample 13 */ + {0x32, 0x00, 0x00, 0x00, 0x00}, /* Sample 14 */ + {0x14, 0x00, 0x00, 0x00, 0x00}, /* Sample 15 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 16 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 17 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 18 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 19 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 20 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 21 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 22 */ + {0x00, 0x00, 0x00, 0x00, 0x00}, /* Sample 23 */ +#endif + {0x0C} /* Output Amplitude */ +}; + + +u_int32_t T1_Equalizer[256] = /* T1 Receiver Equalizer */ +{ + 0x03FE1840, 0x03F61840, 0x03EE1840, 0x03E61840, /* 000 - 003 */ + 0x03DE1840, 0x03D61840, 0x03D61840, 0x03D61840, /* 004 - 007 */ + 0x03CE1840, 0x03CE1840, 0x03CE1840, 0x03CE1840, /* 008 - 011 */ + 0x03C61840, 0x03C61840, 0x03C61840, 0x0BBE1840, /* 012 - 015 */ + 0x0BBE1840, 0x0BBE1840, 0x0BBE1840, 0x0BB61840, /* 016 - 019 */ + 0x0BB61840, 0x0BB61840, 0x0BB61840, 0x13AE1838, /* 020 - 023 */ + 0x13AE183C, 0x13AE1840, 0x13AE1840, 0x13AE1840, /* 024 - 027 */ + 0x13AE1840, 0x1BB618B8, 0x1BAE18B8, 0x1BAE18BC, /* 028 - 031 */ + 0x1BAE18C0, 0x1BAE18C0, 0x23A618C0, 0x23A618C0, /* 032 - 035 */ + 0x23A618C0, 0x23A618C0, 0x23A618C0, 0x239E18C0, /* 036 - 039 */ + 0x239E18C0, 0x239E18C0, 0x239E18C0, 0x239E18C0, /* 040 - 043 */ + 0x2B9618C0, 0x2B9618C0, 0x2B9618C0, 0x33961940, /* 044 - 047 */ + 0x37961940, 0x37961940, 0x37961940, 0x3F9E19C0, /* 048 - 051 */ + 0x3F9E19C0, 0x3F9E19C0, 0x3FA61A40, 0x3FA61A40, /* 052 - 055 */ + 0x3FA61A40, 0x3FA61A40, 0x3F9619C0, 0x3F9619C0, /* 056 - 059 */ + 0x3F9619C0, 0x3F9619C0, 0x479E1A40, 0x479E1A40, /* 060 - 063 */ + 0x479E1A40, 0x47961A40, 0x47961A40, 0x47961A40, /* 064 - 067 */ + 0x47961A40, 0x4F8E1A40, 0x4F8E1A40, 0x4F8E1A40, /* 068 - 071 */ + 0x4F8E1A40, 0x4F8E1A40, 0x57861A40, 0x57861A40, /* 072 - 075 */ + 0x57861A40, 0x57861A40, 0x57861A40, 0x5F861AC0, /* 076 - 079 */ + 0x5F861AC0, 0x5F861AC0, 0x5F861AC0, 0x5F861AC0, /* 080 - 083 */ + 0x5F861AC0, 0x5F7E1AC0, 0x5F7E1AC0, 0x5F7E1AC0, /* 084 - 087 */ + 0x5F7E1AC0, 0x5F7E1AC0, 0x677E2AC0, 0x677E2AC0, /* 088 - 091 */ + 0x677E2AC0, 0x677E2AC0, 0x67762AC0, 0x67762AC0, /* 092 - 095 */ + 0x67762AC0, 0x67762AC0, 0x67762AC0, 0x6F6E2AC0, /* 096 - 099 */ + 0x6F6E2AC0, 0x6F6E2AC0, 0x6F6E2AC0, 0x776E3AC0, /* 100 - 103 */ + 0x776E3AC0, 0x776E3AC0, 0x776E3AC0, 0x7F663AC0, /* 104 - 107 */ + 0x7F663AC0, 0x7F664AC0, 0x7F664AC0, 0x7F664AC0, /* 108 - 111 */ + 0x7F664AC0, 0x87665AC0, 0x87665AC0, 0x87665AC0, /* 112 - 115 */ + 0x87665AC0, 0x87665AC0, 0x875E5AC0, 0x875E5AC0, /* 116 - 119 */ + 0x875E5AC0, 0x875E5AC0, 0x875E5AC0, 0x8F5E6AC0, /* 120 - 123 */ + 0x8F5E6AC0, 0x8F5E6AC0, 0x8F5E6AC0, 0x975E7AC0, /* 124 - 127 */ + 0x975E7AC0, 0x975E7AC0, 0x975E7AC0, 0x9F5E8AC0, /* 128 - 131 */ + 0x9F5E8AC0, 0x9F5E8AC0, 0x9F5E8AC0, 0x9F5E8AC0, /* 132 - 135 */ + 0xA7569AC0, 0xA7569AC0, 0xA7569AC0, 0xA7569AC0, /* 136 - 139 */ + 0xA756AAC0, 0xA756AAC0, 0xA756AAC0, 0xAF4EAAC0, /* 140 - 143 */ + 0xAF4EAAC0, 0xAF4EAAC0, 0xAF4EAAC0, 0xAF4EAAC0, /* 144 - 147 */ + 0xB746AAC0, 0xB746AAC0, 0xB746AAC0, 0xB746AAC0, /* 148 - 151 */ + 0xB746AAC0, 0xB746AAC0, 0xB746AAC0, 0xB746BAC0, /* 152 - 155 */ + 0xB746BAC0, 0xB746BAC0, 0xBF4EBB40, 0xBF4EBB40, /* 156 - 159 */ + 0xBF4EBB40, 0xBF4EBB40, 0xBF4EBB40, 0xBF4EBB40, /* 160 - 163 */ + 0xBF4EBB40, 0xBF4EBB40, 0xBF4EBB40, 0xBE46CB40, /* 164 - 167 */ + 0xBE46CB40, 0xBE46CB40, 0xBE46CB40, 0xBE46CB40, /* 168 - 171 */ + 0xBE46CB40, 0xBE46DB40, 0xBE46DB40, 0xBE46DB40, /* 172 - 175 */ + 0xC63ECB40, 0xC63ECB40, 0xC63EDB40, 0xC63EDB40, /* 176 - 179 */ + 0xC63EDB40, 0xC644DB40, 0xC644DB40, 0xC644DB40, /* 180 - 183 */ + 0xC644DB40, 0xC63CDB40, 0xC63CDB40, 0xC63CDB40, /* 184 - 187 */ + 0xC63CDB40, 0xD634DB40, 0xD634DB40, 0xD634DB40, /* 188 - 191 */ + 0xD634DB40, 0xD634DB40, 0xDE2CDB3C, 0xDE2CDB3C, /* 192 - 195 */ + 0xDE2CDB3C, 0xE62CDB40, 0xE62CDB40, 0xE62CDB40, /* 196 - 199 */ + 0xE62CDB40, 0xE62CDB40, 0xE62CEB40, 0xE62CEB40, /* 200 - 203 */ + 0xE62CEB40, 0xEE2CFB40, 0xEE2CFB40, 0xEE2CFB40, /* 204 - 207 */ + 0xEE2D0B40, 0xEE2D0B40, 0xEE2D0B40, 0xEE2D0B40, /* 208 - 211 */ + 0xEE2D0B40, 0xF5250B38, 0xF5250B3C, 0xF5250B40, /* 212 - 215 */ + 0xF5251B40, 0xF5251B40, 0xF5251B40, 0xF5251B40, /* 216 - 219 */ + 0xF5251B40, 0xFD252B40, 0xFD252B40, 0xFD252B40, /* 220 - 223 */ + 0xFD252B40, 0xFD252740, 0xFD252740, 0xFD252740, /* 224 - 227 */ + 0xFD252340, 0xFD252340, 0xFD252340, 0xFD253340, /* 228 - 231 */ + 0xFD253340, 0xFD253340, 0xFD253340, 0xFD253340, /* 232 - 235 */ + 0xFD253340, 0xFD253340, 0xFD253340, 0xFC254340, /* 236 - 239 */ + 0xFD254340, 0xFD254340, 0xFD254344, 0xFC254348, /* 240 - 243 */ + 0xFC25434C, 0xFD2543BC, 0xFD2543C0, 0xFC2543C0, /* 244 - 247 */ + 0xFC2343C0, 0xFC2343C0, 0xFD2343C0, 0xFC2143C0, /* 248 - 251 */ + 0xFC2143C0, 0xFC2153C0, 0xFD2153C0, 0xFC2153C0 /* 252 - 255 */ +}; + + +u_int32_t E1_Equalizer[256] = /* E1 Receiver Equalizer */ +{ + 0x07DE182C, 0x07DE182C, 0x07D6182C, 0x07D6182C, /* 000 - 003 */ + 0x07D6182C, 0x07CE182C, 0x07CE182C, 0x07CE182C, /* 004 - 007 */ + 0x07C6182C, 0x07C6182C, 0x07C6182C, 0x07BE182C, /* 008 - 011 */ + 0x07BE182C, 0x07BE182C, 0x07BE182C, 0x07BE182C, /* 012 - 015 */ + 0x07B6182C, 0x07B6182C, 0x07B6182C, 0x07B6182C, /* 016 - 019 */ + 0x07B6182C, 0x07AE182C, 0x07AE182C, 0x07AE182C, /* 020 - 023 */ + 0x07AE182C, 0x07AE182C, 0x07B618AC, 0x07AE18AC, /* 024 - 027 */ + 0x07AE18AC, 0x07AE18AC, 0x07AE18AC, 0x07A618AC, /* 028 - 031 */ + 0x07A618AC, 0x07A618AC, 0x07A618AC, 0x079E18AC, /* 032 - 035 */ + 0x07A6192C, 0x07A6192C, 0x07A6192C, 0x0FA6192C, /* 036 - 039 */ + 0x0FA6192C, 0x0F9E192C, 0x0F9E192C, 0x0F9E192C, /* 040 - 043 */ + 0x179E192C, 0x17A619AC, 0x179E19AC, 0x179E19AC, /* 044 - 047 */ + 0x179619AC, 0x1F9619AC, 0x1F9619AC, 0x1F8E19AC, /* 048 - 051 */ + 0x1F8E19AC, 0x1F8E19AC, 0x278E19AC, 0x278E1A2C, /* 052 - 055 */ + 0x278E1A2C, 0x278E1A2C, 0x278E1A2C, 0x2F861A2C, /* 056 - 059 */ + 0x2F861A2C, 0x2F861A2C, 0x2F7E1A2C, 0x2F7E1A2C, /* 060 - 063 */ + 0x2F7E1A2C, 0x377E1A2C, 0x377E1AAC, 0x377E1AAC, /* 064 - 067 */ + 0x377E1AAC, 0x377E1AAC, 0x3F7E2AAC, 0x3F7E2AAC, /* 068 - 071 */ + 0x3F762AAC, 0x3F862B2C, 0x3F7E2B2C, 0x477E2B2C, /* 072 - 075 */ + 0x477E2F2C, 0x477E2F2C, 0x477E2F2C, 0x47762F2C, /* 076 - 079 */ + 0x4F762F2C, 0x4F762F2C, 0x4F6E2F2C, 0x4F6E2F2C, /* 080 - 083 */ + 0x4F6E2F2C, 0x576E2F2C, 0x576E2F2C, 0x576E3F2C, /* 084 - 087 */ + 0x576E3F2C, 0x576E3F2C, 0x5F6E3F2C, 0x5F6E4F2C, /* 088 - 091 */ + 0x5F6E4F2C, 0x5F6E4F2C, 0x5F664F2C, 0x67664F2C, /* 092 - 095 */ + 0x67664F2C, 0x675E4F2C, 0x675E4F2C, 0x67664F2C, /* 096 - 099 */ + 0x67664F2C, 0x67665F2C, 0x6F6E5F2C, 0x6F6E6F2C, /* 100 - 103 */ + 0x6F6E6F2C, 0x6F6E7F2C, 0x6F6E7F2C, 0x6F6E7F2C, /* 104 - 107 */ + 0x77667F2C, 0x77667F2C, 0x775E6F2C, 0x775E7F2C, /* 108 - 111 */ + 0x775E7F2C, 0x7F5E7F2C, 0x7F5E8F2C, 0x7F5E8F2C, /* 112 - 115 */ + 0x7F5E8F2C, 0x87568F2C, 0x87568F2C, 0x87568F2C, /* 116 - 119 */ + 0x874E8F2C, 0x874E8F2C, 0x874E8F2C, 0x8F4E9F2C, /* 120 - 123 */ + 0x8F4E9F2C, 0x8F4EAF2C, 0x8F4EAF2C, 0x8F4EAF2C, /* 124 - 127 */ + 0x974EAF2C, 0x974EAF2C, 0x974EAB2C, 0x974EAB2C, /* 128 - 131 */ + 0x974EAB2C, 0x9F4EAB2C, 0x9F4EBB2C, 0x9F4EBB2C, /* 132 - 135 */ + 0x9F4EBB2C, 0x9F4ECB2C, 0xA74ECB2C, 0xA74ECB2C, /* 136 - 139 */ + 0xA746CB2C, 0xA746CB2C, 0xA746CB2C, 0xA746DB2C, /* 140 - 143 */ + 0xAF46DB2C, 0xAF46EB2C, 0xAF46EB2C, 0xAF4EEB2C, /* 144 - 147 */ + 0xAE4EEB2C, 0xAE4EEB2C, 0xB546FB2C, 0xB554FB2C, /* 148 - 151 */ + 0xB54CEB2C, 0xB554FB2C, 0xB554FB2C, 0xBD54FB2C, /* 152 - 155 */ + 0xBD4CFB2C, 0xBD4CFB2C, 0xBD4CFB2C, 0xBD44EB2C, /* 156 - 159 */ + 0xC544FB2C, 0xC544FB2C, 0xC544FB2C, 0xC5450B2C, /* 160 - 163 */ + 0xC5450B2C, 0xC5450B2C, 0xCD450B2C, 0xCD450B2C, /* 164 - 167 */ + 0xCD3D0B2C, 0xCD3D0B2C, 0xCD3D0B2C, 0xD53D0B2C, /* 168 - 171 */ + 0xD53D0B2C, 0xD53D1B2C, 0xD53D1B2C, 0xD53D1B2C, /* 172 - 175 */ + 0xDD3D1B2C, 0xDD3D1B2C, 0xDD351B2C, 0xDD351B2C, /* 176 - 179 */ + 0xDD351B2C, 0xE5351B2C, 0xE5351B2C, 0xE52D1B2C, /* 180 - 183 */ + 0xE52D1B2C, 0xE52D3B2C, 0xED2D4B2C, 0xED2D1BA8, /* 184 - 187 */ + 0xED2D1BAC, 0xED2D17AC, 0xED2D17AC, 0xED2D27AC, /* 188 - 191 */ + 0xF52D27AC, 0xF52D27AC, 0xF52D2BAC, 0xF52D2BAC, /* 192 - 195 */ + 0xF52D2BAC, 0xFD2D2BAC, 0xFD2B2BAC, 0xFD2B2BAC, /* 196 - 199 */ + 0xFD2B2BAC, 0xFD2B2BAC, 0xFD232BAC, 0xFD232BAC, /* 200 - 203 */ + 0xFD232BAC, 0xFD212BAC, 0xFD212BAC, 0xFD292BAC, /* 204 - 207 */ + 0xFD292BAC, 0xFD2927AC, 0xFD2937AC, 0xFD2923AC, /* 208 - 211 */ + 0xFD2923AC, 0xFD2923AC, 0xFD2923AC, 0xFD2123AC, /* 212 - 215 */ + 0xFD2123AC, 0xFD2123AC, 0xFD2133AC, 0xFD2133AC, /* 216 - 219 */ + 0xFD2133AC, 0xFD2143AC, 0xFD2143AC, 0xFD2143AC, /* 220 - 223 */ + 0xFC2143AC, 0xFC2143AC, 0xFC1943AC, 0xFC1943AC, /* 224 - 227 */ + 0xFC1943AC, 0xFC1943AC, 0xFC1953AC, 0xFC1953AC, /* 228 - 231 */ + 0xFC1953AC, 0xFC1953AC, 0xFC1963AC, 0xFC1963AC, /* 232 - 235 */ + 0xFC1963AC, 0xFC1973AC, 0xFC1973AC, 0xFC1973AC, /* 236 - 239 */ + 0xFC1973AC, 0xFC1973AC, 0xFC1983AC, 0xFC1983AC, /* 240 - 243 */ + 0xFC1983AC, 0xFC1983AC, 0xFC1983AC, 0xFC1993AC, /* 244 - 247 */ + 0xFC1993AC, 0xFC1993AC, 0xFC19A3AC, 0xFC19A3AC, /* 248 - 251 */ + 0xFC19B3AC, 0xFC19B3AC, 0xFC19B3AC, 0xFC19B3AC /* 252 - 255 */ +}; + +/*** End-of-Files ***/ diff --git a/drivers/staging/cxt1e1/comet_tables.h b/drivers/staging/cxt1e1/comet_tables.h new file mode 100644 index 00000000000..3e2e5badf78 --- /dev/null +++ b/drivers/staging/cxt1e1/comet_tables.h @@ -0,0 +1,61 @@ +#ifndef _INC_COMET_TBLS_H_ +#define _INC_COMET_TBLS_H_ + +/*----------------------------------------------------------------------------- + * comet_tables.h - Waveform Tables for the PM4351 'COMET' + * + * Copyright (C) 2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + *----------------------------------------------------------------------------- + */ + + +/***************************************************************************** +* +* Array names: +* +* TWVLongHaul0DB +* TWVLongHaul7_5DB +* TWVLongHaul15DB +* TWVLongHaul22_5DB +* TWVShortHaul0 +* TWVShortHaul1 +* TWVShortHaul2 +* TWVShortHaul3 +* TWVShortHaul4 +* TWVShortHaul5 +* TWV_E1_120Ohm +* TWV_E1_75Ohm <not supported> +* T1_Equalizer +* E1_Equalizer +* +*****************************************************************************/ + +extern u_int8_t TWVLongHaul0DB[25][5]; /* T1 Long Haul 0 DB */ +extern u_int8_t TWVLongHaul7_5DB[25][5]; /* T1 Long Haul 7.5 DB */ +extern u_int8_t TWVLongHaul15DB[25][5]; /* T1 Long Haul 15 DB */ +extern u_int8_t TWVLongHaul22_5DB[25][5]; /* T1 Long Haul 22.5 DB */ +extern u_int8_t TWVShortHaul0[25][5]; /* T1 Short Haul 0-110 ft */ +extern u_int8_t TWVShortHaul1[25][5]; /* T1 Short Haul 110-220 ft */ +extern u_int8_t TWVShortHaul2[25][5]; /* T1 Short Haul 220-330 ft */ +extern u_int8_t TWVShortHaul3[25][5]; /* T1 Short Haul 330-440 ft */ +extern u_int8_t TWVShortHaul4[25][5]; /* T1 Short Haul 440-550 ft */ +extern u_int8_t TWVShortHaul5[25][5]; /* T1 Short Haul 550-660 ft */ +extern u_int8_t TWV_E1_75Ohm[25][5]; /* E1 75 Ohm */ +extern u_int8_t TWV_E1_120Ohm[25][5]; /* E1 120 Ohm */ +extern u_int32_t T1_Equalizer[256]; /* T1 Receiver Equalizer */ +extern u_int32_t E1_Equalizer[256]; /* E1 Receiver Equalizer */ + +#endif /* _INC_COMET_TBLS_H_ */ diff --git a/drivers/staging/cxt1e1/functions.c b/drivers/staging/cxt1e1/functions.c new file mode 100644 index 00000000000..65b6fc36edf --- /dev/null +++ b/drivers/staging/cxt1e1/functions.c @@ -0,0 +1,318 @@ +/* Copyright (C) 2003-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/slab.h> +#include <linux/io.h> +#include <asm/byteorder.h> +#include <linux/netdevice.h> +#include <linux/delay.h> +#include <linux/hdlc.h> +#include "pmcc4_sysdep.h" +#include "sbecom_inline_linux.h" +#include "libsbew.h" +#include "pmcc4.h" + + +#ifndef USE_MAX_INT_DELAY +static int dummy = 0; + +#endif + +extern int drvr_state; + + +#if 1 +u_int32_t +pci_read_32(u_int32_t *p) +{ +#ifdef FLOW_DEBUG + u_int32_t v; + + FLUSH_PCI_READ(); + v = le32_to_cpu(*p); + if (cxt1e1_log_level >= LOG_DEBUG) + pr_info("pci_read : %x = %x\n", (u_int32_t) p, v); + return v; +#else + FLUSH_PCI_READ(); /* */ + return le32_to_cpu(*p); +#endif +} + +void +pci_write_32(u_int32_t *p, u_int32_t v) +{ +#ifdef FLOW_DEBUG + if (cxt1e1_log_level >= LOG_DEBUG) + pr_info("pci_write: %x = %x\n", (u_int32_t) p, v); +#endif + *p = cpu_to_le32 (v); + FLUSH_PCI_WRITE(); /* This routine is called from routines + * which do multiple register writes + * which themselves need flushing between + * writes in order to guarantee write + * ordering. It is less code-cumbersome + * to flush here-in then to investigate + * and code the many other register + * writing routines. */ +} +#endif + + +void +pci_flush_write(ci_t *ci) +{ + volatile u_int32_t v; + + /* issue a PCI read to flush PCI write thru bridge */ + v = *(u_int32_t *) &ci->reg->glcd; /* any address would do */ + + /* + * return nothing, this just reads PCI bridge interface to flush + * previously written data + */ +} + + +static void +watchdog_func(unsigned long arg) +{ + struct watchdog *wd = (void *) arg; + + if (drvr_state != SBE_DRVR_AVAILABLE) { + if (cxt1e1_log_level >= LOG_MONITOR) + pr_warning("%s: drvr not available (%x)\n", + __func__, drvr_state); + return; + } + schedule_work(&wd->work); + mod_timer(&wd->h, jiffies + wd->ticks); +} + +int OS_init_watchdog(struct watchdog *wdp, void (*f) (void *), + void *c, int usec) +{ + wdp->func = f; + wdp->softc = c; + wdp->ticks = (HZ) * (usec / 1000) / 1000; + INIT_WORK(&wdp->work, (void *)f); + init_timer(&wdp->h); + { + ci_t *ci = (ci_t *) c; + + wdp->h.data = (unsigned long) &ci->wd; + } + wdp->h.function = watchdog_func; + return 0; +} + +void +OS_uwait(int usec, char *description) +{ + int tmp; + + if (usec >= 1000) { + mdelay(usec / 1000); + /* now delay residual */ + tmp = (usec / 1000) * 1000; /* round */ + tmp = usec - tmp; /* residual */ + if (tmp) { /* wait on residual */ + udelay(tmp); + } + } else { + udelay(usec); + } +} + +/* dummy short delay routine called as a subroutine so that compiler + * does not optimize/remove its intent (a short delay) + */ + +void +OS_uwait_dummy(void) +{ +#ifndef USE_MAX_INT_DELAY + dummy++; +#else + udelay(1); +#endif +} + + +void +OS_sem_init(void *sem, int state) +{ + switch (state) { + case SEM_TAKEN: + sema_init((struct semaphore *) sem, 0); + break; + case SEM_AVAILABLE: + sema_init((struct semaphore *) sem, 1); + break; + default: /* otherwise, set sem.count to state's + * value */ + sema_init(sem, state); + break; + } +} + + +int +sd_line_is_ok(void *user) +{ + struct net_device *ndev = (struct net_device *) user; + + return netif_carrier_ok(ndev); +} + +void +sd_line_is_up(void *user) +{ + struct net_device *ndev = (struct net_device *) user; + + netif_carrier_on(ndev); + return; +} + +void +sd_line_is_down(void *user) +{ + struct net_device *ndev = (struct net_device *) user; + + netif_carrier_off(ndev); + return; +} + +void +sd_disable_xmit(void *user) +{ + struct net_device *dev = (struct net_device *) user; + + netif_stop_queue(dev); + return; +} + +void +sd_enable_xmit(void *user) +{ + struct net_device *dev = (struct net_device *) user; + + netif_wake_queue(dev); + return; +} + +int +sd_queue_stopped(void *user) +{ + struct net_device *ndev = (struct net_device *) user; + + return netif_queue_stopped(ndev); +} + +void sd_recv_consume(void *token, size_t len, void *user) +{ + struct net_device *ndev = user; + struct sk_buff *skb = token; + + skb->dev = ndev; + skb_put(skb, len); + skb->protocol = hdlc_type_trans(skb, ndev); + netif_rx(skb); +} + + +/** + ** Read some reserved location w/in the COMET chip as a usable + ** VMETRO trigger point or other trace marking event. + **/ + +#include "comet.h" + +extern ci_t *CI; /* dummy pointer to board ZERO's data */ +void +VMETRO_TRIGGER(ci_t *ci, int x) +{ + struct s_comet_reg *comet; + volatile u_int32_t data; + + comet = ci->port[0].cometbase; /* default to COMET # 0 */ + + switch (x) { + default: + case 0: + data = pci_read_32((u_int32_t *) &comet->__res24); /* 0x90 */ + break; + case 1: + data = pci_read_32((u_int32_t *) &comet->__res25); /* 0x94 */ + break; + case 2: + data = pci_read_32((u_int32_t *) &comet->__res26); /* 0x98 */ + break; + case 3: + data = pci_read_32((u_int32_t *) &comet->__res27); /* 0x9C */ + break; + case 4: + data = pci_read_32((u_int32_t *) &comet->__res88); /* 0x220 */ + break; + case 5: + data = pci_read_32((u_int32_t *) &comet->__res89); /* 0x224 */ + break; + case 6: + data = pci_read_32((u_int32_t *) &comet->__res8A); /* 0x228 */ + break; + case 7: + data = pci_read_32((u_int32_t *) &comet->__res8B); /* 0x22C */ + break; + case 8: + data = pci_read_32((u_int32_t *) &comet->__resA0); /* 0x280 */ + break; + case 9: + data = pci_read_32((u_int32_t *) &comet->__resA1); /* 0x284 */ + break; + case 10: + data = pci_read_32((u_int32_t *) &comet->__resA2); /* 0x288 */ + break; + case 11: + data = pci_read_32((u_int32_t *) &comet->__resA3); /* 0x28C */ + break; + case 12: + data = pci_read_32((u_int32_t *) &comet->__resA4); /* 0x290 */ + break; + case 13: + data = pci_read_32((u_int32_t *) &comet->__resA5); /* 0x294 */ + break; + case 14: + data = pci_read_32((u_int32_t *) &comet->__resA6); /* 0x298 */ + break; + case 15: + data = pci_read_32((u_int32_t *) &comet->__resA7); /* 0x29C */ + break; + case 16: + data = pci_read_32((u_int32_t *) &comet->__res74); /* 0x1D0 */ + break; + case 17: + data = pci_read_32((u_int32_t *) &comet->__res75); /* 0x1D4 */ + break; + case 18: + data = pci_read_32((u_int32_t *) &comet->__res76); /* 0x1D8 */ + break; + case 19: + data = pci_read_32((u_int32_t *) &comet->__res77); /* 0x1DC */ + break; + } +} + + +/*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c new file mode 100644 index 00000000000..4fa27c8931b --- /dev/null +++ b/drivers/staging/cxt1e1/hwprobe.c @@ -0,0 +1,382 @@ +/* Copyright (C) 2007 One Stop Systems + * Copyright (C) 2003-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/netdevice.h> +#include <linux/hdlc.h> +#include <linux/if_arp.h> +#include <asm/uaccess.h> +#include <linux/rtnetlink.h> +#include <linux/pci.h> +#include "pmcc4_sysdep.h" +#include "sbecom_inline_linux.h" +#include "libsbew.h" +#include "pmcc4_private.h" +#include "pmcc4.h" +#include "pmcc4_ioctls.h" +#include "pmc93x6_eeprom.h" +#ifdef CONFIG_PROC_FS +#include "sbeproc.h" +#endif + +extern int error_flag; +extern int drvr_state; + +/* forward references */ +void c4_stopwd(ci_t *); +struct net_device * __init c4_add_dev(hdw_info_t *, int, unsigned long, + unsigned long, int, int); + + +struct s_hdw_info hdw_info[MAX_BOARDS]; + + +void __init +show_two(hdw_info_t *hi, int brdno) +{ + ci_t *ci; + struct pci_dev *pdev; + char *bid; + char banner[80]; + char sn[6] = {0,}; + + ci = (ci_t *)(netdev_priv(hi->ndev)); + bid = sbeid_get_bdname(ci); + switch (hi->promfmt) { + case PROM_FORMAT_TYPE1: + memcpy(sn, hi->mfg_info.pft1.Serial, 6); + break; + case PROM_FORMAT_TYPE2: + memcpy(sn, hi->mfg_info.pft2.Serial, 6); + break; + } + + sprintf(banner, "%s: %s S/N %06X, MUSYCC Rev %02X", + hi->devname, bid, + ((sn[3] << 16) & 0xff0000) | + ((sn[4] << 8) & 0x00ff00) | + (sn[5] & 0x0000ff), + (u_int8_t) hi->revid[0]); + + pr_info("%s\n", banner); + + pdev = hi->pdev[0]; + pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", + hi->devname, "MUSYCC", + (unsigned long) hi->addr_mapped[0], hi->addr[0], + hi->pci_busno, (u_int8_t) PCI_SLOT(pdev->devfn), + (u_int8_t) PCI_FUNC(pdev->devfn), pdev->irq); + + pdev = hi->pdev[1]; + pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", + hi->devname, "EBUS ", + (unsigned long) hi->addr_mapped[1], hi->addr[1], + hi->pci_busno, (u_int8_t) PCI_SLOT(pdev->devfn), + (u_int8_t) PCI_FUNC(pdev->devfn), pdev->irq); +} + + +void __init +hdw_sn_get(hdw_info_t *hi, int brdno) +{ + /* obtain hardware EEPROM information */ + long addr; + + addr = (long) hi->addr_mapped[1] + EEPROM_OFFSET; + + /* read EEPROM with largest known format size... */ + pmc_eeprom_read_buffer(addr, 0, (char *)hi->mfg_info.data, + sizeof(FLD_TYPE2)); + +#if 0 + { + unsigned char *ucp = (unsigned char *) &hi->mfg_info.data; + + pr_info("eeprom[00]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 0), *(ucp + 1), *(ucp + 2), *(ucp + 3), + *(ucp + 4), *(ucp + 5), *(ucp + 6), *(ucp + 7)); + pr_info("eeprom[08]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 8), *(ucp + 9), *(ucp + 10), *(ucp + 11), + *(ucp + 12), *(ucp + 13), *(ucp + 14), *(ucp + 15)); + pr_info("eeprom[16]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 16), *(ucp + 17), *(ucp + 18), *(ucp + 19), + *(ucp + 20), *(ucp + 21), *(ucp + 22), *(ucp + 23)); + pr_info("eeprom[24]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 24), *(ucp + 25), *(ucp + 26), *(ucp + 27), + *(ucp + 28), *(ucp + 29), *(ucp + 30), *(ucp + 31)); + pr_info("eeprom[32]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 32), *(ucp + 33), *(ucp + 34), *(ucp + 35), + *(ucp + 36), *(ucp + 37), *(ucp + 38), *(ucp + 39)); + pr_info("eeprom[40]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 40), *(ucp + 41), *(ucp + 42), *(ucp + 43), + *(ucp + 44), *(ucp + 45), *(ucp + 46), *(ucp + 47)); + } +#endif +#if 0 + pr_info("sn: %x %x %x %x %x %x\n", + hi->mfg_info.Serial[0], + hi->mfg_info.Serial[1], + hi->mfg_info.Serial[2], + hi->mfg_info.Serial[3], + hi->mfg_info.Serial[4], + hi->mfg_info.Serial[5]); +#endif + + hi->promfmt = pmc_verify_cksum(&hi->mfg_info.data); + if (hi->promfmt == PROM_FORMAT_Unk) { + /* bad crc, data is suspect */ + if (cxt1e1_log_level >= LOG_WARN) + pr_info("%s: EEPROM cksum error\n", hi->devname); + hi->mfg_info_sts = EEPROM_CRCERR; + } else + hi->mfg_info_sts = EEPROM_OK; +} + + + void __init +prep_hdw_info(void) +{ + hdw_info_t *hi; + int i; + + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + hi->pci_busno = 0xff; + hi->pci_slot = 0xff; + hi->pci_pin[0] = 0; + hi->pci_pin[1] = 0; + hi->ndev = NULL; + hi->addr[0] = 0L; + hi->addr[1] = 0L; + hi->addr_mapped[0] = NULL; + hi->addr_mapped[1] = NULL; + } +} + +void +cleanup_ioremap(void) +{ + hdw_info_t *hi; + int i; + + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot == 0xff) + break; + if (hi->addr_mapped[0]) { + iounmap(hi->addr_mapped[0]); + release_mem_region((long) hi->addr[0], hi->len[0]); + hi->addr_mapped[0] = NULL; + } + if (hi->addr_mapped[1]) { + iounmap(hi->addr_mapped[1]); + release_mem_region((long) hi->addr[1], hi->len[1]); + hi->addr_mapped[1] = NULL; + } + } +} + + +void +cleanup_devs(void) +{ + hdw_info_t *hi; + int i; + + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot == 0xff || !hi->ndev) + break; + c4_stopwd(netdev_priv(hi->ndev)); +#ifdef CONFIG_PROC_FS + sbecom_proc_brd_cleanup(netdev_priv(hi->ndev)); +#endif + unregister_netdev(hi->ndev); + free_irq(hi->pdev[0]->irq, hi->ndev); +#ifdef CONFIG_SBE_PMCC4_NCOMM + free_irq(hi->pdev[1]->irq, hi->ndev); +#endif + kfree(hi->ndev); + } +} + + +static int __init +c4_hdw_init(struct pci_dev *pdev, int found) +{ + hdw_info_t *hi; + int i; + int fun, slot; + unsigned char busno = 0xff; + + /* our MUSYCC chip supports two functions, 0 & 1 */ + fun = PCI_FUNC(pdev->devfn); + if (fun > 1) { + pr_warning("unexpected devfun: 0x%x\n", pdev->devfn); + return 0; + } + + /* obtain bus number */ + if (pdev->bus) + busno = pdev->bus->number; + else + busno = 0; /* default for system PCI inconsistency */ + slot = pdev->devfn & ~0x07; + + /* + * Functions 0 & 1 for a given board (identified by same bus(busno) and + * slot(slot)) are placed into the same 'hardware' structure. The first + * part of the board's functionality will be placed into an unpopulated + * element, identified by "slot==(0xff)". The second part of a board's + * functionality will match the previously loaded slot/busno. + */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + /* + * match with board's first found interface, otherwise this is + * fisrt found + */ + if ((hi->pci_slot == 0xff) || /* new board */ + ((hi->pci_slot == slot) && (hi->bus == pdev->bus))) + break; /* found for-loop exit */ + } + + /* no match in above loop means MAX exceeded */ + if (i == MAX_BOARDS) { + pr_warning("exceeded number of allowed devices (>%d)?\n", + MAX_BOARDS); + return 0; + } + + if (pdev->bus) + hi->pci_busno = pdev->bus->number; + else + hi->pci_busno = 0; /* default for system PCI inconsistency */ + + hi->pci_slot = slot; + pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &hi->pci_pin[fun]); + pci_read_config_byte(pdev, PCI_REVISION_ID, &hi->revid[fun]); + hi->bus = pdev->bus; + hi->addr[fun] = pci_resource_start(pdev, 0); + hi->len[fun] = pci_resource_end(pdev, 0) - hi->addr[fun] + 1; + hi->pdev[fun] = pdev; + + { + /* + * create device name from module name, plus add the appropriate + * board number + */ + char *cp = hi->devname; + + strcpy(cp, KBUILD_MODNAME); + cp += strlen(cp); /* reposition */ + *cp++ = '-'; + *cp++ = '0' + (found / 2); /* there are two found interfaces per + * board */ + *cp = 0; /* termination */ + } + + return 1; +} + +status_t __init +c4hw_attach_all(void) +{ + hdw_info_t *hi; + struct pci_dev *pdev = NULL; + int found = 0, i, j; + + error_flag = 0; + prep_hdw_info(); + /*** scan PCI bus for all possible boards */ + while ((pdev = pci_get_device(PCI_VENDOR_ID_CONEXANT, + PCI_DEVICE_ID_CN8474, + pdev))) { + if (c4_hdw_init(pdev, found)) + found++; + } + + if (!found) { + pr_warning("No boards found\n"); + return -ENODEV; + } + + /* sanity check for consistent hardware found */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot != 0xff && (!hi->addr[0] || !hi->addr[1])) { + pr_warning("%s: something very wrong with pci_get_device\n", + hi->devname); + return -EIO; + } + } + /* bring board's memory regions on/line */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot == 0xff) + break; + for (j = 0; j < 2; j++) { + if (!request_mem_region(hi->addr[j], hi->len[j], hi->devname)) { + pr_warning("%s: memory in use, addr=0x%lx, len=0x%lx ?\n", + hi->devname, hi->addr[j], hi->len[j]); + cleanup_ioremap(); + return -ENOMEM; + } + + hi->addr_mapped[j] = ioremap(hi->addr[j], hi->len[j]); + if (!hi->addr_mapped[j]) { + pr_warning("%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n", + hi->devname, hi->addr[j], hi->len[j]); + cleanup_ioremap(); + return -ENOMEM; + } +#ifdef SBE_MAP_DEBUG + pr_warning("%s: io remapped from phys %x to virt %x\n", + hi->devname, (u_int32_t) hi->addr[j], + (u_int32_t) hi->addr_mapped[j]); +#endif + } + } + + drvr_state = SBE_DRVR_AVAILABLE; + + /* Have now memory mapped all boards. Now allow board's access to system */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot == 0xff) + break; + if (pci_enable_device(hi->pdev[0]) || + pci_enable_device(hi->pdev[1])) { + drvr_state = SBE_DRVR_DOWN; + pr_warning("%s: failed to enable card %d slot %d\n", + hi->devname, i, hi->pci_slot); + cleanup_devs(); + cleanup_ioremap(); + return -EIO; + } + pci_set_master(hi->pdev[0]); + pci_set_master(hi->pdev[1]); + hi->ndev = c4_add_dev(hi, i, (long) hi->addr_mapped[0], + (long) hi->addr_mapped[1], + hi->pdev[0]->irq, + hi->pdev[1]->irq); + if (!hi->ndev) { + drvr_state = SBE_DRVR_DOWN; + cleanup_ioremap(); + /* NOTE: c4_add_dev() does its own device cleanup */ +#if 0 + cleanup_devs(); +#endif + return error_flag; /* error_flag set w/in add_dev() */ + } + show_two(hi, i); /* displays found information */ + } + return 0; +} + +/*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/libsbew.h b/drivers/staging/cxt1e1/libsbew.h new file mode 100644 index 00000000000..bd2bfba604b --- /dev/null +++ b/drivers/staging/cxt1e1/libsbew.h @@ -0,0 +1,549 @@ +#ifndef _INC_LIBSBEW_H_ +#define _INC_LIBSBEW_H_ + +/*----------------------------------------------------------------------------- + * libsbew.h - common library elements, charge across mulitple boards + * + * This file contains common Ioctl structures and contents definitions. + * + * Copyright (C) 2004-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + *----------------------------------------------------------------------------- + */ + +/********************************/ +/** set driver logging level **/ +/********************************/ + +/* routine/ioctl: wancfg_set_loglevel() - SBE_IOC_SET_LOGLEVEL */ + +#define LOG_NONE 0 +#define LOG_ERROR 1 +#define LOG_SBEBUG3 3 /* hidden, for development/debug usage */ +#define LOG_LSCHANGE 5 /* line state change logging */ +#define LOG_LSIMMEDIATE 6 /* line state change logging w/o hysterisis */ +#define LOG_WARN 8 +#define LOG_MONITOR 10 +#define LOG_SBEBUG12 12 /* hidden, for development/debug usage */ +#define LOG_MONITOR2 14 /* hidden, for development/debug usage */ +#define LOG_DEBUG 16 + + /* TEMPORARY DEFINES *//* RLD DEBUG */ +#define c4_LOG_NONE LOG_NONE +#define c4_LOG_ERROR LOG_ERROR +#define c4_LOG_WARN LOG_WARN +#define c4_LOG_sTrace LOG_MONITOR /* do some trace logging into + * functions */ +#define c4_LOG_DEBUG LOG_DEBUG +#define c4_LOG_MAX LOG_DEBUG + + + +/******************************/ +/** get driver information **/ +/******************************/ + +/* routine/ioctl: wancfg_get_drvinfo() - SBE_IOC_GET_DRVINFO */ + +#define REL_STRLEN 80 + struct sbe_drv_info + { + int rel_strlen; + char release[REL_STRLEN]; + }; + + +/*****************************/ +/** get board information **/ +/*****************************/ + +/* routine/ioctl: wancfg_get_brdinfo() - SBE_IOC_GET_BRDINFO */ + +#define CHNM_STRLEN 16 + struct sbe_brd_info + { + u_int32_t brd_id; /* SBE's unique PCI VENDOR/DEVID */ + u_int32_t brd_sn; + int brd_chan_cnt; /* number of channels being used */ + int brd_port_cnt; /* number of ports being used */ + unsigned char brdno; /* our board number */ + unsigned char brd_pci_speed; /* PCI speed, 33/66Mhz */ + u_int8_t brd_mac_addr[6]; + char first_iname[CHNM_STRLEN]; /* first assigned channel's + * interface name */ + char last_iname[CHNM_STRLEN]; /* last assigned channel's + * interface name */ + u_int8_t brd_hdw_id; /* on/board unique hdw ID */ + u_int8_t reserved8[3]; /* alignment preservation */ + u_int32_t reserved32[3]; /* size preservation */ + }; + +/* These IDs are sometimes available thru pci_ids.h, but not currently. */ + +#define PCI_VENDOR_ID_SBE 0x1176 +#define PCI_DEVICE_ID_WANPMC_C4T1E1 0x0701 /* BID 0x0X, BTYP 0x0X */ +#define PCI_DEVICE_ID_WANPTMC_C4T1E1 0x0702 /* BID 0x41 */ +#define PCI_DEVICE_ID_WANADAPT_HC4T1E1 0x0703 /* BID 0x44 */ +#define PCI_DEVICE_ID_WANPTMC_256T3_T1 0x0704 /* BID 0x42 (T1 Version) */ +#define PCI_DEVICE_ID_WANPCI_C4T1E1 0x0705 /* BID 0x1X, BTYP 0x0X */ +#define PCI_DEVICE_ID_WANPMC_C1T3 0x0706 /* BID 0x45 */ +#define PCI_DEVICE_ID_WANPCI_C2T1E1 0x0707 /* BID 0x1X, BTYP 0x2X */ +#define PCI_DEVICE_ID_WANPCI_C1T1E1 0x0708 /* BID 0x1X, BTYP 0x1X */ +#define PCI_DEVICE_ID_WANPMC_C2T1E1 0x0709 /* BID 0x0X, BTYP 0x2X */ +#define PCI_DEVICE_ID_WANPMC_C1T1E1 0x070A /* BID 0x0X, BTYP 0x1X */ +#define PCI_DEVICE_ID_WANPTMC_256T3_E1 0x070B /* BID 0x46 (E1 Version) */ +#define PCI_DEVICE_ID_WANPTMC_C24TE1 0x070C /* BID 0x47 */ +#define PCI_DEVICE_ID_WANPMC_C4T1E1_L 0x070D /* BID 0x2X, BTYPE 0x0X w/FP + * LEDs */ +#define PCI_DEVICE_ID_WANPMC_C2T1E1_L 0x070E /* BID 0x2X, BTYPE 0x2X w/FP + * LEDs */ +#define PCI_DEVICE_ID_WANPMC_C1T1E1_L 0x070F /* BID 0x2X, BTYPE 0x1X w/FP + * LEDs */ +#define PCI_DEVICE_ID_WANPMC_2SSI 0x0801 +#define PCI_DEVICE_ID_WANPCI_4SSI 0x0802 +#define PCI_DEVICE_ID_WANPMC_2T3E3 0x0900 /* BID 0x43 */ +#define SBE_BOARD_ID(v,id) ((v<<16) | id) + +#define BINFO_PCI_SPEED_unk 0 +#define BINFO_PCI_SPEED_33 1 +#define BINFO_PCI_SPEED_66 2 + +/***************************/ +/** obtain interface ID **/ +/***************************/ + +/* routine/ioctl: wancfg_get_iid() - SBE_IOC_IID_GET */ + + struct sbe_iid_info + { + u_int32_t channum; /* channel requested */ + char iname[CHNM_STRLEN]; /* channel's interface name */ + }; + +/**************************************/ +/** get board address information **/ +/**************************************/ + +/* routine/ioctl: wancfg_get_brdaddr() - SBE_IOC_BRDADDR_GET */ + + struct sbe_brd_addr + { + unsigned char func; /* select PCI address space function */ + unsigned char brdno; /* returns brdno requested */ + unsigned char irq; + unsigned char size; /* returns size of address */ +#define BRDADDR_SIZE_64 1 +#define BRDADDR_SIZE_32 2 + int reserved1; /* mod64 align, reserved for future use */ + + union + { + unsigned long virt64; /* virtual/mapped address */ + u_int32_t virt32[2]; + } v; + union + { + unsigned long phys64; /* physical bus address */ + u_int32_t phys32[2]; + } p; + int reserved2[4]; /* reserved for future use */ + }; + +/**********************************/ +/** read/write board registers **/ +/**********************************/ + +/* routine/ioctl: wancfg_read_vec() - SBE_IOC_READ_VEC */ +/* routine/ioctl: wancfg_write_vec() - SBE_IOC_WRITE_VEC */ + + struct sbecom_wrt_vec + { + u_int32_t reg; + u_int32_t data; + }; + +#define C1T3_CHIP_MSCC_32 0x01000000 +#define C1T3_CHIP_TECT3_8 0x02000000 +#define C1T3_CHIP_CPLD_8 0x03000000 +#define C1T3_CHIP_EEPROM_8 0x04000000 + +#define W256T3_CHIP_MUSYCC_32 0x02000000 +#define W256T3_CHIP_TEMUX_8 0x10000000 +#define W256T3_CHIP_T8110_8 0x20000000 +#define W256T3_CHIP_T8110_32 0x22000000 +#define W256T3_CHIP_CPLD_8 0x30000000 +#define W256T3_CHIP_EEPROM_8 0x40000000 + + +/**********************************/ +/** read write port parameters **/ +/**********************************/ + +/* routine/ioctl: wancfg_getset_port_param() - SBE_IOC_PORT_GET */ +/* routine/ioctl: wancfg_set_port_param() - SBE_IOC_PORT_SET */ + +/* NOTE: this structure supports hardware which supports individual per/port control */ + +struct sbecom_port_param +{ + u_int8_t portnum; + u_int8_t port_mode; /* variations of T1 or E1 mode */ + u_int8_t portStatus; + u_int8_t portP; /* more port parameters (clock source - 0x80; + * and LBO - 0xf; */ + /* bits 0x70 are reserved for future use ) */ +#ifdef SBE_PMCC4_ENABLE + u_int32_t hypersize; /* RLD DEBUG - add this in until I learn how to make this entry obsolete */ +#endif + int reserved[3-1]; /* reserved for future use */ + int _res[4]; +}; + +#define CFG_CLK_PORT_MASK 0x80 /* Loop timing */ +#define CFG_CLK_PORT_INTERNAL 0x80 /* Loop timing */ +#define CFG_CLK_PORT_EXTERNAL 0x00 /* Loop timing */ + +#define CFG_LBO_MASK 0x0F +#define CFG_LBO_unk 0 /* <not defined> */ +#define CFG_LBO_LH0 1 /* T1 Long Haul (default) */ +#define CFG_LBO_LH7_5 2 /* T1 Long Haul */ +#define CFG_LBO_LH15 3 /* T1 Long Haul */ +#define CFG_LBO_LH22_5 4 /* T1 Long Haul */ +#define CFG_LBO_SH110 5 /* T1 Short Haul */ +#define CFG_LBO_SH220 6 /* T1 Short Haul */ +#define CFG_LBO_SH330 7 /* T1 Short Haul */ +#define CFG_LBO_SH440 8 /* T1 Short Haul */ +#define CFG_LBO_SH550 9 /* T1 Short Haul */ +#define CFG_LBO_SH660 10 /* T1 Short Haul */ +#define CFG_LBO_E75 11 /* E1 75 Ohm */ +#define CFG_LBO_E120 12 /* E1 120 Ohm (default) */ + + +/*************************************/ +/** read write channel parameters **/ +/*************************************/ + +/* routine/ioctl: wancfg_getset_chan_param() - SBE_IOC_CHAN_GET */ +/* routine/ioctl: wancfg_set_chan_param() - SBE_IOC_CHAN_SET */ + +/* NOTE: this structure supports hardware which supports individual per/channel control */ + + struct sbecom_chan_param + { + u_int32_t channum; /* 0: */ +#ifdef SBE_PMCC4_ENABLE + u_int32_t card; /* RLD DEBUG - add this in until I learn how to make this entry obsolete */ + u_int32_t port; /* RLD DEBUG - add this in until I learn how to make this entry obsolete */ + u_int8_t bitmask[32]; +#endif + u_int32_t intr_mask; /* 4: interrupt mask, specify ored + * (SS7_)INTR_* to disable */ + u_int8_t status; /* 8: channel transceiver status (TX_ENABLED, + * RX_ENABLED) */ + u_int8_t chan_mode; /* 9: protocol mode */ + u_int8_t idlecode; /* A: idle code, in (FLAG_7E, FLAG_FF, + * FLAG_00) */ + u_int8_t pad_fill_count; /* B: pad fill count (1-127), 0 - pad + * fill disabled */ + u_int8_t data_inv; /* C: channel data inversion selection */ + u_int8_t mode_56k; /* D: 56kbps mode */ + u_int8_t reserved[2 + 8]; /* E: */ + }; + +/* SS7 interrupt signals <intr_mask> */ +#define SS7_INTR_SFILT 0x00000020 +#define SS7_INTR_SDEC 0x00000040 +#define SS7_INTR_SINC 0x00000080 +#define SS7_INTR_SUERR 0x00000100 +/* Other interrupts that can be masked */ +#define INTR_BUFF 0x00000002 +#define INTR_EOM 0x00000004 +#define INTR_MSG 0x00000008 +#define INTR_IDLE 0x00000010 + +/* transceiver status flags <status> */ +#define TX_ENABLED 0x01 +#define RX_ENABLED 0x02 + +/* Protocol modes <mode> */ +#define CFG_CH_PROTO_TRANS 0 +#define CFG_CH_PROTO_SS7 1 +#define CFG_CH_PROTO_HDLC_FCS16 2 +#define CFG_CH_PROTO_HDLC_FCS32 3 +#define CFG_CH_PROTO_ISLP_MODE 4 + +/* Possible idle code assignments <idlecode> */ +#define CFG_CH_FLAG_7E 0 +#define CFG_CH_FLAG_FF 1 +#define CFG_CH_FLAG_00 2 + +/* data inversion selection <data_inv> */ +#define CFG_CH_DINV_NONE 0x00 +#define CFG_CH_DINV_RX 0x01 +#define CFG_CH_DINV_TX 0x02 + + +/* Possible resettable chipsets/functions */ +#define RESET_DEV_TEMUX 1 +#define RESET_DEV_TECT3 RESET_DEV_TEMUX +#define RESET_DEV_PLL 2 + + +/*********************************************/ +/** read reset channel thruput statistics **/ +/*********************************************/ + +/* routine/ioctl: wancfg_get_chan_stats() - SBE_IOC_CHAN_GET_STAT */ +/* routine/ioctl: wancfg_del_chan_stats() - SBE_IOC_CHAN_DEL_STAT */ +/* routine/ioctl: wancfg_get_card_chan_stats() - SBE_IOC_CARD_CHAN_STAT */ + + struct sbecom_chan_stats + { + unsigned long rx_packets; /* total packets received */ + unsigned long tx_packets; /* total packets transmitted */ + unsigned long rx_bytes; /* total bytes received */ + unsigned long tx_bytes; /* total bytes transmitted */ + unsigned long rx_errors;/* bad packets received */ + unsigned long tx_errors;/* packet transmit problems */ + unsigned long rx_dropped; /* no space in linux buffers */ + unsigned long tx_dropped; /* no space available in linux */ + + /* detailed rx_errors: */ + unsigned long rx_length_errors; + unsigned long rx_over_errors; /* receiver ring buff overflow */ + unsigned long rx_crc_errors; /* recved pkt with crc error */ + unsigned long rx_frame_errors; /* recv'd frame alignment error */ + unsigned long rx_fifo_errors; /* recv'r fifo overrun */ + unsigned long rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + unsigned long tx_aborted_errors; + unsigned long tx_fifo_errors; + unsigned long tx_pending; + }; + + +/****************************************/ +/** read write card level parameters **/ +/****************************************/ + + /* NOTE: this structure supports hardware which supports per/card control */ + + struct sbecom_card_param + { + u_int8_t framing_type; /* 0: CBP or M13 */ + u_int8_t loopback; /* 1: one of LOOPBACK_* */ + u_int8_t line_build_out; /* 2: boolean */ + u_int8_t receive_eq; /* 3: boolean */ + u_int8_t transmit_ones; /* 4: boolean */ + u_int8_t clock; /* 5: 0 - internal, i>0 - external (recovered + * from framer i) */ + u_int8_t h110enable; /* 6: */ + u_int8_t disable_leds; /* 7: */ + u_int8_t reserved1; /* 8: available - old 256t3 hypersized, but + * never used */ + u_int8_t rear_io; /* 9: rear I/O off/on */ + u_int8_t disable_tx; /* A: disable TX off/on */ + u_int8_t mute_los; /* B: mute LOS off/on */ + u_int8_t los_threshold; /* C: LOS threshold norm/low + * (default: norm) */ + u_int8_t ds1_mode; /* D: DS1 mode T1/E1 (default: T1) */ + u_int8_t ds3_unchan; /* E: DS3 unchannelized mode off/on */ + u_int8_t reserved[1 + 16]; /* reserved for expansion - must be + * ZERO filled */ + }; + +/* framing types <framing_type> */ +#define FRAMING_M13 0 +#define FRAMING_CBP 1 + +/* card level loopback options <loopback> */ +#define CFG_CARD_LOOPBACK_NONE 0x00 +#define CFG_CARD_LOOPBACK_DIAG 0x01 +#define CFG_CARD_LOOPBACK_LINE 0x02 +#define CFG_CARD_LOOPBACK_PAYLOAD 0x03 + +/* line level loopback options <loopback> */ +#define CFG_LIU_LOOPBACK_NONE 0x00 +#define CFG_LIU_LOOPBACK_ANALOG 0x10 +#define CFG_LIU_LOOPBACK_DIGITAL 0x11 +#define CFG_LIU_LOOPBACK_REMOTE 0x12 + +/* card level clock options <clock> */ +#define CFG_CLK_INTERNAL 0x00 +#define CFG_CLK_EXTERNAL 0x01 + +/* legacy 256T3 loopback values */ +#define LOOPBACK_NONE 0 +#define LOOPBACK_LIU_ANALOG 1 +#define LOOPBACK_LIU_DIGITAL 2 +#define LOOPBACK_FRAMER_DS3 3 +#define LOOPBACK_FRAMER_T1 4 +#define LOOPBACK_LIU_REMOTE 5 + +/* DS1 mode <ds1_mode> */ +#define CFG_DS1_MODE_MASK 0x0f +#define CFG_DS1_MODE_T1 0x00 +#define CFG_DS1_MODE_E1 0x01 +#define CFG_DS1_MODE_CHANGE 0x80 + +/* DS3 unchannelized values <ds1_unchan> */ +#define CFG_DS3_UNCHAN_MASK 0x01 +#define CFG_DS3_UNCHAN_OFF 0x00 +#define CFG_DS3_UNCHAN_ON 0x01 + + +/************************************/ +/** read write framer parameters **/ +/************************************/ + +/* routine/ioctl: wancfg_get_framer() - SBE_IOC_FRAMER_GET */ +/* routine/ioctl: wancfg_set_framer() - SBE_IOC_FRAMER_SET */ + + struct sbecom_framer_param + { + u_int8_t framer_num; + u_int8_t frame_type; /* SF, ESF, E1PLAIN, E1CAS, E1CRC, E1CRC+CAS */ + u_int8_t loopback_type; /* DIGITAL, LINE, PAYLOAD */ + u_int8_t auto_alarms;/* auto alarms */ + u_int8_t reserved[12]; /* reserved for expansion - must be + * ZERO filled */ + }; + +/* frame types <frame_type> */ +#define CFG_FRAME_NONE 0 +#define CFG_FRAME_SF 1 /* T1 B8ZS */ +#define CFG_FRAME_ESF 2 /* T1 B8ZS */ +#define CFG_FRAME_E1PLAIN 3 /* HDB3 w/o CAS,CRC */ +#define CFG_FRAME_E1CAS 4 /* HDB3 */ +#define CFG_FRAME_E1CRC 5 /* HDB3 */ +#define CFG_FRAME_E1CRC_CAS 6 /* HDB3 */ +#define CFG_FRAME_SF_AMI 7 /* T1 AMI */ +#define CFG_FRAME_ESF_AMI 8 /* T1 AMI */ +#define CFG_FRAME_E1PLAIN_AMI 9 /* E1 AMI w/o CAS,CRC */ +#define CFG_FRAME_E1CAS_AMI 10 /* E1 AMI */ +#define CFG_FRAME_E1CRC_AMI 11 /* E1 AMI */ +#define CFG_FRAME_E1CRC_CAS_AMI 12 /* E1 AMI */ + +#define IS_FRAME_ANY_T1(field) \ + (((field) == CFG_FRAME_NONE) || \ + ((field) == CFG_FRAME_SF) || \ + ((field) == CFG_FRAME_ESF) || \ + ((field) == CFG_FRAME_SF_AMI) || \ + ((field) == CFG_FRAME_ESF_AMI)) + +#define IS_FRAME_ANY_T1ESF(field) \ + (((field) == CFG_FRAME_ESF) || \ + ((field) == CFG_FRAME_ESF_AMI)) + +#define IS_FRAME_ANY_E1(field) \ + (((field) == CFG_FRAME_E1PLAIN) || \ + ((field) == CFG_FRAME_E1CAS) || \ + ((field) == CFG_FRAME_E1CRC) || \ + ((field) == CFG_FRAME_E1CRC_CAS) || \ + ((field) == CFG_FRAME_E1PLAIN_AMI) || \ + ((field) == CFG_FRAME_E1CAS_AMI) || \ + ((field) == CFG_FRAME_E1CRC_AMI) || \ + ((field) == CFG_FRAME_E1CRC_CAS_AMI)) + +#define IS_FRAME_ANY_AMI(field) \ + (((field) == CFG_FRAME_SF_AMI) || \ + ((field) == CFG_FRAME_ESF_AMI) || \ + ((field) == CFG_FRAME_E1PLAIN_AMI) || \ + ((field) == CFG_FRAME_E1CAS_AMI) || \ + ((field) == CFG_FRAME_E1CRC_AMI) || \ + ((field) == CFG_FRAME_E1CRC_CAS_AMI)) + +/* frame level loopback options <loopback_type> */ +#define CFG_FRMR_LOOPBACK_NONE 0 +#define CFG_FRMR_LOOPBACK_DIAG 1 +#define CFG_FRMR_LOOPBACK_LINE 2 +#define CFG_FRMR_LOOPBACK_PAYLOAD 3 + + +/****************************************/ +/** read reset card error statistics **/ +/****************************************/ + +/* routine/ioctl: wancfg_get_card_stats() - SBE_IOC_CARD_GET_STAT */ +/* routine/ioctl: wancfg_del_card_stats() - SBE_IOC_CARD_DEL_STAT */ + + struct temux_card_stats + { + struct temux_stats + { + /* TEMUX DS3 PMON counters */ + u_int32_t lcv; + u_int32_t err_framing; + u_int32_t febe; + u_int32_t err_cpbit; + u_int32_t err_parity; + /* TEMUX DS3 FRMR status */ + u_int8_t los; + u_int8_t oof; + u_int8_t red; + u_int8_t yellow; + u_int8_t idle; + u_int8_t ais; + u_int8_t cbit; + /* TEMUX DS3 FEAC receiver */ + u_int8_t feac; + u_int8_t feac_last; + } t; + u_int32_t tx_pending; /* total */ + }; + +/**************************************************************/ + + struct wancfg + { + int cs, ds; + char *p; + }; + typedef struct wancfg wcfg_t; + + extern wcfg_t *wancfg_init(char *, char *); + extern int wancfg_card_blink(wcfg_t *, int); + extern int wancfg_ctl(wcfg_t *, int, void *, int, void *, int); + extern int wancfg_del_card_stats(wcfg_t *); + extern int wancfg_del_chan_stats(wcfg_t *, int); + extern int wancfg_enable_ports(wcfg_t *, int); + extern int wancfg_free(wcfg_t *); + extern int wancfg_get_brdaddr(wcfg_t *, struct sbe_brd_addr *); + extern int wancfg_get_brdinfo(wcfg_t *, struct sbe_brd_info *); + extern int wancfg_get_card(wcfg_t *, struct sbecom_card_param *); + extern int wancfg_get_card_chan_stats(wcfg_t *, struct sbecom_chan_stats *); + extern int wancfg_get_card_sn(wcfg_t *); + extern int wancfg_get_card_stats(wcfg_t *, struct temux_card_stats *); + extern int wancfg_get_chan(wcfg_t *, int, struct sbecom_chan_param *); + extern int wancfg_get_chan_stats(wcfg_t *, int, struct sbecom_chan_stats *); + extern int wancfg_get_drvinfo(wcfg_t *, int, struct sbe_drv_info *); + extern int wancfg_get_framer(wcfg_t *, int, struct sbecom_framer_param *); + extern int wancfg_get_iid(wcfg_t *, int, struct sbe_iid_info *); + extern int wancfg_get_sn(wcfg_t *, unsigned int *); + extern int wancfg_read(wcfg_t *, int, struct sbecom_wrt_vec *); + extern int wancfg_reset_device(wcfg_t *, int); + extern int wancfg_set_card(wcfg_t *, struct sbecom_card_param *); + extern int wancfg_set_chan(wcfg_t *, int, struct sbecom_chan_param *); + extern int wancfg_set_framer(wcfg_t *, int, struct sbecom_framer_param *); + extern int wancfg_set_loglevel(wcfg_t *, uint); + extern int wancfg_write(wcfg_t *, int, struct sbecom_wrt_vec *); + +#ifdef NOT_YET_COMMON + extern int wancfg_get_tsioc(wcfg_t *, struct wanc1t3_ts_hdr *, struct wanc1t3_ts_param *); + extern int wancfg_set_tsioc(wcfg_t *, struct wanc1t3_ts_param *); +#endif + +#endif /*** _INC_LIBSBEW_H_ ***/ diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c new file mode 100644 index 00000000000..09f3d5ca75a --- /dev/null +++ b/drivers/staging/cxt1e1/linux.c @@ -0,0 +1,1142 @@ +/* Copyright (C) 2007-2008 One Stop Systems + * Copyright (C) 2003-2006 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/types.h> +#include <linux/netdevice.h> +#include <linux/module.h> +#include <linux/hdlc.h> +#include <linux/if_arp.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <linux/rtnetlink.h> +#include <linux/skbuff.h> +#include "pmcc4_sysdep.h" +#include "sbecom_inline_linux.h" +#include "libsbew.h" +#include "pmcc4.h" +#include "pmcc4_ioctls.h" +#include "pmcc4_private.h" +#include "sbeproc.h" + +/******************************************************************************* + * Error out early if we have compiler trouble. + * + * (This section is included from the kernel's init/main.c as a friendly + * spiderman recommendation...) + * + * Versions of gcc older than that listed below may actually compile and link + * okay, but the end product can have subtle run time bugs. To avoid associated + * bogus bug reports, we flatly refuse to compile with a gcc that is known to be + * too old from the very beginning. + */ +#if (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 2) +#error Sorry, your GCC is too old. It builds incorrect kernels. +#endif + +#if __GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ == 0 +#warning gcc-4.1.0 is known to miscompile the kernel. A different compiler version is recommended. +#endif + +/*******************************************************************************/ + +#define CHANNAME "hdlc" + +/*******************************************************************/ +/* forward references */ +status_t c4_chan_work_init(mpi_t *, mch_t *); +void musycc_wq_chan_restart(void *); +status_t __init c4_init(ci_t *, u_char *, u_char *); +status_t __init c4_init2(ci_t *); +int __init c4hw_attach_all(void); +void __init hdw_sn_get(hdw_info_t *, int); + +#ifdef CONFIG_SBE_PMCC4_NCOMM +irqreturn_t c4_ebus_intr_th_handler(void *); + +#endif +int c4_frame_rw(ci_t *, struct sbecom_port_param *); +status_t c4_get_port(ci_t *, int); +int c4_loop_port(ci_t *, int, u_int8_t); +int c4_musycc_rw(ci_t *, struct c4_musycc_param *); +int c4_new_chan(ci_t *, int, int, void *); +status_t c4_set_port(ci_t *, int); +int c4_pld_rw(ci_t *, struct sbecom_port_param *); +void cleanup_devs(void); +void cleanup_ioremap(void); +status_t musycc_chan_down(ci_t *, int); +irqreturn_t musycc_intr_th_handler(void *); +int musycc_start_xmit(ci_t *, int, void *); + +extern ci_t *CI; +extern struct s_hdw_info hdw_info[]; + +int error_flag; /* module load error reporting */ +int cxt1e1_log_level = LOG_ERROR; +static int log_level_default = LOG_ERROR; +module_param(cxt1e1_log_level, int, 0444); + +int cxt1e1_max_mru = MUSYCC_MRU; +static int max_mru_default = MUSYCC_MRU; +module_param(cxt1e1_max_mru, int, 0444); + +int cxt1e1_max_mtu = MUSYCC_MTU; +int max_mtu_default = MUSYCC_MTU; +module_param(cxt1e1_max_mtu, int, 0444); + +int max_txdesc_used = MUSYCC_TXDESC_MIN; +int max_txdesc_default = MUSYCC_TXDESC_MIN; +module_param(max_txdesc_used, int, 0444); + +int max_rxdesc_used = MUSYCC_RXDESC_MIN; +int max_rxdesc_default = MUSYCC_RXDESC_MIN; +module_param(max_rxdesc_used, int, 0444); + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +void * +getuserbychan(int channum) +{ + mch_t *ch; + + ch = c4_find_chan(channum); + return ch ? ch->user : NULL; +} + + +char * +get_hdlc_name(hdlc_device *hdlc) +{ + struct c4_priv *priv = hdlc->priv; + struct net_device *dev = getuserbychan(priv->channum); + + return dev->name; +} + +/***************************************************************************/ +#include <linux/workqueue.h> + +/*** + * One workqueue (wq) per port (since musycc allows simultaneous group + * commands), with individual data for each channel: + * + * mpi_t -> struct workqueue_struct *wq_port; (dynamically allocated using + * create_workqueue()) + * + * With work structure (work) statically allocated for each channel: + * + * mch_t -> struct work_struct ch_work; (statically allocated using ???) + * + ***/ + + +/* + * Called by the start transmit routine when a channel TX_ENABLE is to be + * issued. This queues the transmission start request among other channels + * within a port's group. + */ +void +c4_wk_chan_restart(mch_t *ch) +{ + mpi_t *pi = ch->up; + +#ifdef RLD_RESTART_DEBUG + pr_info(">> %s: queueing Port %d Chan %d, mch_t @ %p\n", + __func__, pi->portnum, ch->channum, ch); +#endif + + /* create new entry w/in workqueue for this channel and let'er rip */ + + /** queue_work(struct workqueue_struct *queue, + ** struct work_struct *work); + **/ + queue_work(pi->wq_port, &ch->ch_work); +} + +status_t +c4_wk_chan_init(mpi_t *pi, mch_t *ch) +{ + /* + * this will be used to restart a stopped channel + */ + + /** INIT_WORK(struct work_struct *work, + ** void (*function)(void *), + ** void *data); + **/ + INIT_WORK(&ch->ch_work, (void *)musycc_wq_chan_restart); + return 0; /* success */ +} + +status_t +c4_wq_port_init(mpi_t *pi) +{ + + char name[16]; /* NOTE: name of the queue limited by system + * to 10 characters */ + if (pi->wq_port) + return 0; /* already initialized */ + + /* IE pmcc4-01 */ + snprintf(name, sizeof(name), "%s%d", pi->up->devname, pi->portnum); + +#ifdef RLD_RESTART_DEBUG + pr_info(">> %s: creating workqueue <%s> for Port %d.\n", + __func__, name, pi->portnum); /* RLD DEBUG */ +#endif + pi->wq_port = create_singlethread_workqueue(name); + if (!pi->wq_port) + return -ENOMEM; + return 0; /* success */ +} + +void +c4_wq_port_cleanup(mpi_t *pi) +{ + /* + * PORT POINT: cannot call this if WQ is statically allocated w/in + * structure since it calls kfree(wq); + */ + if (pi->wq_port) { + destroy_workqueue(pi->wq_port); /* this also calls + * flush_workqueue() */ + pi->wq_port = NULL; + } +} + +/***************************************************************************/ + +static irqreturn_t +c4_linux_interrupt(int irq, void *dev_instance) +{ + struct net_device *ndev = dev_instance; + + return musycc_intr_th_handler(netdev_priv(ndev)); +} + + +#ifdef CONFIG_SBE_PMCC4_NCOMM +static irqreturn_t +c4_ebus_interrupt(int irq, void *dev_instance) +{ + struct net_device *ndev = dev_instance; + + return c4_ebus_intr_th_handler(netdev_priv(ndev)); +} +#endif + + +static int +void_open(struct net_device *ndev) +{ + pr_info("%s: trying to open master device !\n", ndev->name); + return -1; +} + + +static int +chan_open(struct net_device *ndev) +{ + hdlc_device *hdlc = dev_to_hdlc(ndev); + const struct c4_priv *priv = hdlc->priv; + int ret; + + ret = hdlc_open(ndev); + if (ret) { + pr_info("hdlc_open failure, err %d.\n", ret); + return ret; + } + + ret = c4_chan_up(priv->ci, priv->channum); + if (ret < 0) + return ret; + try_module_get(THIS_MODULE); + netif_start_queue(ndev); + return 0; /* no error = success */ +} + + +static int +chan_close(struct net_device *ndev) +{ + hdlc_device *hdlc = dev_to_hdlc(ndev); + const struct c4_priv *priv = hdlc->priv; + + netif_stop_queue(ndev); + musycc_chan_down((ci_t *) 0, priv->channum); + hdlc_close(ndev); + module_put(THIS_MODULE); + return 0; +} + + +static int +chan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + return hdlc_ioctl(dev, ifr, cmd); +} + + +static int +chan_attach_noop(struct net_device *ndev, unsigned short foo_1, + unsigned short foo_2) +{ + /* our driver has nothing to do here, show's + * over, go home + */ + return 0; +} + + +static struct net_device_stats * +chan_get_stats(struct net_device *ndev) +{ + mch_t *ch; + struct net_device_stats *nstats; + struct sbecom_chan_stats *stats; + int channum; + + { + struct c4_priv *priv; + + priv = (struct c4_priv *)dev_to_hdlc(ndev)->priv; + channum = priv->channum; + } + + ch = c4_find_chan(channum); + if (ch == NULL) + return NULL; + + nstats = &ndev->stats; + stats = &ch->s; + + memset(nstats, 0, sizeof(struct net_device_stats)); + nstats->rx_packets = stats->rx_packets; + nstats->tx_packets = stats->tx_packets; + nstats->rx_bytes = stats->rx_bytes; + nstats->tx_bytes = stats->tx_bytes; + nstats->rx_errors = stats->rx_length_errors + + stats->rx_over_errors + + stats->rx_crc_errors + + stats->rx_frame_errors + + stats->rx_fifo_errors + + stats->rx_missed_errors; + nstats->tx_errors = stats->tx_dropped + + stats->tx_aborted_errors + + stats->tx_fifo_errors; + nstats->rx_dropped = stats->rx_dropped; + nstats->tx_dropped = stats->tx_dropped; + + nstats->rx_length_errors = stats->rx_length_errors; + nstats->rx_over_errors = stats->rx_over_errors; + nstats->rx_crc_errors = stats->rx_crc_errors; + nstats->rx_frame_errors = stats->rx_frame_errors; + nstats->rx_fifo_errors = stats->rx_fifo_errors; + nstats->rx_missed_errors = stats->rx_missed_errors; + + nstats->tx_aborted_errors = stats->tx_aborted_errors; + nstats->tx_fifo_errors = stats->tx_fifo_errors; + + return nstats; +} + + +static ci_t * +get_ci_by_dev(struct net_device *ndev) +{ + return (ci_t *)(netdev_priv(ndev)); +} + + +static int +c4_linux_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + const struct c4_priv *priv; + int rval; + + hdlc_device *hdlc = dev_to_hdlc(ndev); + + priv = hdlc->priv; + + rval = musycc_start_xmit(priv->ci, priv->channum, skb); + return rval; +} + +static const struct net_device_ops chan_ops = { + .ndo_open = chan_open, + .ndo_stop = chan_close, + .ndo_start_xmit = c4_linux_xmit, + .ndo_do_ioctl = chan_dev_ioctl, + .ndo_get_stats = chan_get_stats, +}; + +static struct net_device * +create_chan(struct net_device *ndev, ci_t *ci, + struct sbecom_chan_param *cp) +{ + hdlc_device *hdlc; + struct net_device *dev; + hdw_info_t *hi; + int ret; + + if (c4_find_chan(cp->channum)) + return NULL; /* channel already exists */ + + { + struct c4_priv *priv; + + /* allocate then fill in private data structure */ + priv = kzalloc(sizeof(struct c4_priv), GFP_KERNEL); + if (!priv) { + pr_warning("%s: no memory for net_device !\n", + ci->devname); + return NULL; + } + dev = alloc_hdlcdev(priv); + if (!dev) { + pr_warning("%s: no memory for hdlc_device !\n", + ci->devname); + kfree(priv); + return NULL; + } + priv->ci = ci; + priv->channum = cp->channum; + } + + hdlc = dev_to_hdlc(dev); + + dev->base_addr = 0; /* not I/O mapped */ + dev->irq = ndev->irq; + dev->type = ARPHRD_RAWHDLC; + *dev->name = 0; /* default ifconfig name = "hdlc" */ + + hi = (hdw_info_t *)ci->hdw_info; + if (hi->mfg_info_sts == EEPROM_OK) { + switch (hi->promfmt) { + case PROM_FORMAT_TYPE1: + memcpy(dev->dev_addr, + (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); + break; + case PROM_FORMAT_TYPE2: + memcpy(dev->dev_addr, + (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); + break; + default: + memset(dev->dev_addr, 0, 6); + break; + } + } else + memset(dev->dev_addr, 0, 6); + + hdlc->xmit = c4_linux_xmit; + + dev->netdev_ops = &chan_ops; + /* + * The native hdlc stack calls this 'attach' routine during + * hdlc_raw_ioctl(), passing parameters for line encoding and parity. + * Since hdlc_raw_ioctl() stack does not interrogate whether an 'attach' + * routine is actually registered or not, we supply a dummy routine which + * does nothing (since encoding and parity are setup for our driver via a + * special configuration application). + */ + + hdlc->attach = chan_attach_noop; + + /* needed due to Ioctl calling sequence */ + rtnl_unlock(); + ret = register_hdlc_device(dev); + /* NOTE: <stats> setting must occur AFTER registration in order to "take" */ + dev->tx_queue_len = MAX_DEFAULT_IFQLEN; + + /* needed due to Ioctl calling sequence */ + rtnl_lock(); + if (ret) { + if (cxt1e1_log_level >= LOG_WARN) + pr_info("%s: create_chan[%d] registration error = %d.\n", + ci->devname, cp->channum, ret); + /* cleanup */ + free_netdev(dev); + /* failed to register */ + return NULL; + } + return dev; +} + + +/* the idea here is to get port information and pass it back (using pointer) */ +static status_t +do_get_port(struct net_device *ndev, void *data) +{ + int ret; + ci_t *ci; /* ci stands for card information */ + struct sbecom_port_param pp;/* copy data to kernel land */ + + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + if (pp.portnum >= MUSYCC_NPORTS) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; /* get card info */ + + ret = c4_get_port(ci, pp.portnum); + if (ret < 0) + return ret; + if (copy_to_user(data, &ci->port[pp.portnum].p, + sizeof(struct sbecom_port_param))) + return -EFAULT; + return 0; +} + +/* this function copys the user data and then calls the real action function */ +static status_t +do_set_port(struct net_device *ndev, void *data) +{ + ci_t *ci; /* ci stands for card information */ + struct sbecom_port_param pp;/* copy data to kernel land */ + + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + if (pp.portnum >= MUSYCC_NPORTS) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; /* get card info */ + + if (pp.portnum >= ci->max_port) /* sanity check */ + return -ENXIO; + + memcpy(&ci->port[pp.portnum].p, &pp, sizeof(struct sbecom_port_param)); + return c4_set_port(ci, pp.portnum); +} + +/* work the port loopback mode as per directed */ +static status_t +do_port_loop(struct net_device *ndev, void *data) +{ + struct sbecom_port_param pp; + ci_t *ci; + + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + return c4_loop_port(ci, pp.portnum, pp.port_mode); +} + +/* set the specified register with the given value / or just read it */ +static status_t +do_framer_rw(struct net_device *ndev, void *data) +{ + struct sbecom_port_param pp; + ci_t *ci; + int ret; + + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + ret = c4_frame_rw(ci, &pp); + if (ret < 0) + return ret; + if (copy_to_user(data, &pp, sizeof(struct sbecom_port_param))) + return -EFAULT; + return 0; +} + +/* set the specified register with the given value / or just read it */ +static status_t +do_pld_rw(struct net_device *ndev, void *data) +{ + struct sbecom_port_param pp; + ci_t *ci; + int ret; + + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + + ret = c4_pld_rw(ci, &pp); + if (ret) + return ret; + if (copy_to_user(data, &pp, sizeof(struct sbecom_port_param))) + return -EFAULT; + return 0; +} + +/* set the specified register with the given value / or just read it */ +static status_t +do_musycc_rw(struct net_device *ndev, void *data) +{ + struct c4_musycc_param mp; + ci_t *ci; + int ret; + + if (copy_from_user(&mp, data, sizeof(struct c4_musycc_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + ret = c4_musycc_rw(ci, &mp); + if (ret < 0) + return ret; + if (copy_to_user(data, &mp, sizeof(struct c4_musycc_param))) + return -EFAULT; + return 0; +} + +static status_t +do_get_chan(struct net_device *ndev, void *data) +{ + struct sbecom_chan_param cp; + int ret; + + if (copy_from_user(&cp, data, + sizeof(struct sbecom_chan_param))) + return -EFAULT; + + ret = c4_get_chan(cp.channum, &cp); + if (ret < 0) + return ret; + + if (copy_to_user(data, &cp, sizeof(struct sbecom_chan_param))) + return -EFAULT; + return 0; +} + +static status_t +do_set_chan(struct net_device *ndev, void *data) +{ + struct sbecom_chan_param cp; + ci_t *ci; + + if (copy_from_user(&cp, data, sizeof(struct sbecom_chan_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + return c4_set_chan(cp.channum, &cp); +} + +static status_t +do_create_chan(struct net_device *ndev, void *data) +{ + ci_t *ci; + struct net_device *dev; + struct sbecom_chan_param cp; + int ret; + + if (copy_from_user(&cp, data, sizeof(struct sbecom_chan_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + dev = create_chan(ndev, ci, &cp); + if (!dev) + return -EBUSY; + ret = c4_new_chan(ci, cp.port, cp.channum, dev); + if (ret < 0) { + /* needed due to Ioctl calling sequence */ + rtnl_unlock(); + unregister_hdlc_device(dev); + /* needed due to Ioctl calling sequence */ + rtnl_lock(); + free_netdev(dev); + } + return ret; +} + +static status_t +do_get_chan_stats(struct net_device *ndev, void *data) +{ + struct c4_chan_stats_wrap ccs; + int ret; + + if (copy_from_user(&ccs, data, + sizeof(struct c4_chan_stats_wrap))) + return -EFAULT; + + ret = c4_get_chan_stats(ccs.channum, &ccs.stats); + if (ret < 0) + return ret; + + if (copy_to_user(data, &ccs, + sizeof(struct c4_chan_stats_wrap))) + return -EFAULT; + return 0; +} +static status_t +do_set_loglevel(struct net_device *ndev, void *data) +{ + unsigned int cxt1e1_log_level; + + if (copy_from_user(&cxt1e1_log_level, data, sizeof(int))) + return -EFAULT; + sbecom_set_loglevel(cxt1e1_log_level); + return 0; +} + +static status_t +do_deluser(struct net_device *ndev, int lockit) +{ + if (ndev->flags & IFF_UP) + return -EBUSY; + + { + ci_t *ci; + mch_t *ch; + const struct c4_priv *priv; + int channum; + + priv = (struct c4_priv *)dev_to_hdlc(ndev)->priv; + ci = priv->ci; + channum = priv->channum; + + ch = c4_find_chan(channum); + if (ch == NULL) + return -ENOENT; + ch->user = NULL; /* will be freed, below */ + } + + /* needed if Ioctl calling sequence */ + if (lockit) + rtnl_unlock(); + unregister_hdlc_device(ndev); + /* needed if Ioctl calling sequence */ + if (lockit) + rtnl_lock(); + free_netdev(ndev); + return 0; +} + +int +do_del_chan(struct net_device *musycc_dev, void *data) +{ + struct sbecom_chan_param cp; + char buf[sizeof(CHANNAME) + 3]; + struct net_device *dev; + int ret; + + if (copy_from_user(&cp, data, + sizeof(struct sbecom_chan_param))) + return -EFAULT; + if (cp.channum > 999) + return -EINVAL; + snprintf(buf, sizeof(buf), CHANNAME "%d", cp.channum); + dev = __dev_get_by_name(&init_net, buf); + if (!dev) + return -ENODEV; + ret = do_deluser(dev, 1); + if (ret) + return ret; + return c4_del_chan(cp.channum); +} +int c4_reset_board(void *); + +int +do_reset(struct net_device *musycc_dev, void *data) +{ + const struct c4_priv *priv; + int i; + + for (i = 0; i < 128; i++) { + struct net_device *ndev; + char buf[sizeof(CHANNAME) + 3]; + + sprintf(buf, CHANNAME "%d", i); + ndev = __dev_get_by_name(&init_net, buf); + if (!ndev) + continue; + priv = dev_to_hdlc(ndev)->priv; + + if ((unsigned long) (priv->ci) == + (unsigned long) (netdev_priv(musycc_dev))) { + ndev->flags &= ~IFF_UP; + netif_stop_queue(ndev); + do_deluser(ndev, 1); + } + } + return 0; +} + +int +do_reset_chan_stats(struct net_device *musycc_dev, void *data) +{ + struct sbecom_chan_param cp; + + if (copy_from_user(&cp, data, + sizeof(struct sbecom_chan_param))) + return -EFAULT; + return c4_del_chan_stats(cp.channum); +} + +static status_t +c4_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) +{ + ci_t *ci; + void *data; + int iocmd, iolen; + status_t ret; + static struct data { + union { + u_int8_t c; + u_int32_t i; + struct sbe_brd_info bip; + struct sbe_drv_info dip; + struct sbe_iid_info iip; + struct sbe_brd_addr bap; + struct sbecom_chan_stats stats; + struct sbecom_chan_param param; + struct temux_card_stats cards; + struct sbecom_card_param cardp; + struct sbecom_framer_param frp; + } u; + } arg; + + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (cmd != SIOCDEVPRIVATE + 15) + return -EINVAL; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + if (ci->state != C_RUNNING) + return -ENODEV; + if (copy_from_user(&iocmd, ifr->ifr_data, sizeof(iocmd))) + return -EFAULT; +#if 0 + if (copy_from_user(&len, ifr->ifr_data + sizeof(iocmd), sizeof(len))) + return -EFAULT; +#endif + +#if 0 + pr_info("c4_ioctl: iocmd %x, dir %x type %x nr %x iolen %d.\n", iocmd, + _IOC_DIR(iocmd), _IOC_TYPE(iocmd), _IOC_NR(iocmd), + _IOC_SIZE(iocmd)); +#endif + iolen = _IOC_SIZE(iocmd); + if (iolen > sizeof(arg)) + return -EFAULT; + data = ifr->ifr_data + sizeof(iocmd); + if (copy_from_user(&arg, data, iolen)) + return -EFAULT; + + ret = 0; + switch (iocmd) { + case SBE_IOC_PORT_GET: + ret = do_get_port(ndev, data); + break; + case SBE_IOC_PORT_SET: + ret = do_set_port(ndev, data); + break; + case SBE_IOC_CHAN_GET: + ret = do_get_chan(ndev, data); + break; + case SBE_IOC_CHAN_SET: + ret = do_set_chan(ndev, data); + break; + case C4_DEL_CHAN: + ret = do_del_chan(ndev, data); + break; + case SBE_IOC_CHAN_NEW: + ret = do_create_chan(ndev, data); + break; + case SBE_IOC_CHAN_GET_STAT: + ret = do_get_chan_stats(ndev, data); + break; + case SBE_IOC_LOGLEVEL: + ret = do_set_loglevel(ndev, data); + break; + case SBE_IOC_RESET_DEV: + ret = do_reset(ndev, data); + break; + case SBE_IOC_CHAN_DEL_STAT: + ret = do_reset_chan_stats(ndev, data); + break; + case C4_LOOP_PORT: + ret = do_port_loop(ndev, data); + break; + case C4_RW_FRMR: + ret = do_framer_rw(ndev, data); + break; + case C4_RW_MSYC: + ret = do_musycc_rw(ndev, data); + break; + case C4_RW_PLD: + ret = do_pld_rw(ndev, data); + break; + case SBE_IOC_IID_GET: + ret = (iolen == sizeof(struct sbe_iid_info)) ? + c4_get_iidinfo(ci, &arg.u.iip) : -EFAULT; + if (ret == 0) /* no error, copy data */ + if (copy_to_user(data, &arg, iolen)) + return -EFAULT; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static const struct net_device_ops c4_ops = { + .ndo_open = void_open, + .ndo_start_xmit = c4_linux_xmit, + .ndo_do_ioctl = c4_ioctl, +}; + +static void c4_setup(struct net_device *dev) +{ + dev->type = ARPHRD_VOID; + dev->netdev_ops = &c4_ops; +} + +struct net_device *__init +c4_add_dev(hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, + int irq0, int irq1) +{ + struct net_device *ndev; + ci_t *ci; + + ndev = alloc_netdev(sizeof(ci_t), SBE_IFACETMPL, c4_setup); + if (!ndev) { + pr_warning("%s: no memory for struct net_device !\n", + hi->devname); + error_flag = -ENOMEM; + return NULL; + } + ci = (ci_t *)(netdev_priv(ndev)); + ndev->irq = irq0; + + ci->hdw_info = hi; + ci->state = C_INIT; /* mark as hardware not available */ + ci->next = c4_list; + c4_list = ci; + ci->brdno = ci->next ? ci->next->brdno + 1 : 0; + + if (!CI) + CI = ci; /* DEBUG, only board 0 usage */ + + strcpy(ci->devname, hi->devname); + + /* tasklet */ +#if defined(SBE_ISR_TASKLET) + tasklet_init(&ci->ci_musycc_isr_tasklet, + (void (*) (unsigned long)) musycc_intr_bh_tasklet, + (unsigned long) ci); + + if (atomic_read(&ci->ci_musycc_isr_tasklet.count) == 0) + tasklet_disable_nosync(&ci->ci_musycc_isr_tasklet); +#elif defined(SBE_ISR_IMMEDIATE) + ci->ci_musycc_isr_tq.routine = (void *)(unsigned long)musycc_intr_bh_tasklet; + ci->ci_musycc_isr_tq.data = ci; +#endif + + + if (register_netdev(ndev) || + (c4_init(ci, (u_char *) f0, (u_char *) f1) != SBE_DRVR_SUCCESS)) { + kfree(netdev_priv(ndev)); + kfree(ndev); + error_flag = -ENODEV; + return NULL; + } + /************************************************************* + * int request_irq(unsigned int irq, + * void (*handler)(int, void *, struct pt_regs *), + * unsigned long flags, const char *dev_name, void *dev_id); + * wherein: + * irq -> The interrupt number that is being requested. + * handler -> Pointer to handling function being installed. + * flags -> A bit mask of options related to interrupt management. + * dev_name -> String used in /proc/interrupts to show owner of interrupt. + * dev_id -> Pointer (for shared interrupt lines) to point to its own + * private data area (to identify which device is interrupting). + * + * extern void free_irq(unsigned int irq, void *dev_id); + **************************************************************/ + + if (request_irq(irq0, &c4_linux_interrupt, + IRQF_SHARED, + ndev->name, ndev)) { + pr_warning("%s: MUSYCC could not get irq: %d\n", + ndev->name, irq0); + unregister_netdev(ndev); + kfree(netdev_priv(ndev)); + kfree(ndev); + error_flag = -EIO; + return NULL; + } +#ifdef CONFIG_SBE_PMCC4_NCOMM + if (request_irq(irq1, &c4_ebus_interrupt, IRQF_SHARED, ndev->name, ndev)) { + pr_warning("%s: EBUS could not get irq: %d\n", hi->devname, irq1); + unregister_netdev(ndev); + free_irq(irq0, ndev); + kfree(netdev_priv(ndev)); + kfree(ndev); + error_flag = -EIO; + return NULL; + } +#endif + + /* setup board identification information */ + + { + u_int32_t tmp; + + /* also sets PROM format type (promfmt) for later usage */ + hdw_sn_get(hi, brdno); + + switch (hi->promfmt) { + case PROM_FORMAT_TYPE1: + memcpy(ndev->dev_addr, + (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); + /* unaligned data acquisition */ + memcpy(&tmp, (FLD_TYPE1 *) (hi->mfg_info.pft1.Id), 4); + ci->brd_id = cpu_to_be32(tmp); + break; + case PROM_FORMAT_TYPE2: + memcpy(ndev->dev_addr, + (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); + /* unaligned data acquisition */ + memcpy(&tmp, (FLD_TYPE2 *) (hi->mfg_info.pft2.Id), 4); + ci->brd_id = cpu_to_be32(tmp); + break; + default: + ci->brd_id = 0; + memset(ndev->dev_addr, 0, 6); + break; + } + +#if 1 + /* requires bid to be preset */ + sbeid_set_hdwbid(ci); +#else + /* requires hdw_bid to be preset */ + sbeid_set_bdtype(ci); +#endif + } + +#ifdef CONFIG_PROC_FS + sbecom_proc_brd_init(ci); +#endif +#if defined(SBE_ISR_TASKLET) + tasklet_enable(&ci->ci_musycc_isr_tasklet); +#endif + + error_flag = c4_init2(ci); + if (error_flag != SBE_DRVR_SUCCESS) { +#ifdef CONFIG_PROC_FS + sbecom_proc_brd_cleanup(ci); +#endif + unregister_netdev(ndev); + free_irq(irq1, ndev); + free_irq(irq0, ndev); + kfree(netdev_priv(ndev)); + kfree(ndev); + /* failure, error_flag is set */ + return NULL; + } + return ndev; +} + +static int __init +c4_mod_init(void) +{ + int rtn; + + rtn = c4hw_attach_all(); + if (rtn) + return -rtn; /* installation failure - see system log */ + + /* housekeeping notifications */ + if (cxt1e1_log_level != log_level_default) + pr_info("NOTE: driver parameter <cxt1e1_log_level> changed from default %d to %d.\n", + log_level_default, cxt1e1_log_level); + if (cxt1e1_max_mru != max_mru_default) + pr_info("NOTE: driver parameter <cxt1e1_max_mru> changed from default %d to %d.\n", + max_mru_default, cxt1e1_max_mru); + if (cxt1e1_max_mtu != max_mtu_default) + pr_info("NOTE: driver parameter <cxt1e1_max_mtu> changed from default %d to %d.\n", + max_mtu_default, cxt1e1_max_mtu); + if (max_rxdesc_used != max_rxdesc_default) { + if (max_rxdesc_used > 2000) + max_rxdesc_used = 2000; /* out-of-bounds reset */ + pr_info("NOTE: driver parameter <max_rxdesc_used> changed from default %d to %d.\n", + max_rxdesc_default, max_rxdesc_used); + } + if (max_txdesc_used != max_txdesc_default) { + if (max_txdesc_used > 1000) + max_txdesc_used = 1000; /* out-of-bounds reset */ + pr_info("NOTE: driver parameter <max_txdesc_used> changed from default %d to %d.\n", + max_txdesc_default, max_txdesc_used); + } + return 0; /* installation success */ +} + + + /* + * find any still allocated hdlc registrations and unregister via call to + * do_deluser() + */ + +static void __exit +cleanup_hdlc(void) +{ + hdw_info_t *hi; + ci_t *ci; + struct net_device *ndev; + int i, j, k; + + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->ndev) { /* a board has been attached */ + ci = (ci_t *)(netdev_priv(hi->ndev)); + for (j = 0; j < ci->max_port; j++) + for (k = 0; k < MUSYCC_NCHANS; k++) { + ndev = ci->port[j].chan[k]->user; + if (ndev) + do_deluser(ndev, 0); + } + } + } +} + + +static void __exit +c4_mod_remove(void) +{ + cleanup_hdlc(); /* delete any missed channels */ + cleanup_devs(); + c4_cleanup(); + cleanup_ioremap(); + pr_info("SBE - driver removed.\n"); +} + +module_init(c4_mod_init); +module_exit(c4_mod_remove); + +MODULE_AUTHOR("SBE Technical Services <support@sbei.com>"); +MODULE_DESCRIPTION("wanPCI-CxT1E1 Generic HDLC WAN Driver module"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +/*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c new file mode 100644 index 00000000000..0bcbd8a3fc8 --- /dev/null +++ b/drivers/staging/cxt1e1/musycc.c @@ -0,0 +1,1720 @@ +static unsigned int max_intcnt; +static unsigned int max_bh; + +/*----------------------------------------------------------------------------- + * musycc.c - + * + * Copyright (C) 2007 One Stop Systems, Inc. + * Copyright (C) 2003-2006 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@onestopsystems.com + * One Stop Systems, Inc. Escondido, California U.S.A. + *----------------------------------------------------------------------------- + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/types.h> +#include "pmcc4_sysdep.h" +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include "sbecom_inline_linux.h" +#include "libsbew.h" +#include "pmcc4_private.h" +#include "pmcc4.h" +#include "musycc.h" + +#define sd_find_chan(ci,ch) c4_find_chan(ch) + + +/*******************************************************************/ +/* global driver variables */ +extern ci_t *c4_list; +extern int drvr_state; + +extern int cxt1e1_max_mru; +extern int cxt1e1_max_mtu; +extern int max_rxdesc_used; +extern int max_txdesc_used; +extern ci_t *CI; /* dummy pointr to board ZEROE's data - DEBUG + * USAGE */ + + +/*******************************************************************/ +/* forward references */ +void c4_fifo_free(mpi_t *, int); +void c4_wk_chan_restart(mch_t *); +void musycc_bh_tx_eom(mpi_t *, int); +int musycc_chan_up(ci_t *, int); +status_t __init musycc_init(ci_t *); +void musycc_intr_bh_tasklet(ci_t *); +void musycc_serv_req(mpi_t *, u_int32_t); +void musycc_update_timeslots(mpi_t *); + +/*******************************************************************/ + +static int +musycc_dump_rxbuffer_ring(mch_t *ch, int lockit) +{ + struct mdesc *m; + unsigned long flags = 0; + + u_int32_t status; + int n; + +#ifdef RLD_DUMP_BUFDATA + u_int32_t *dp; + int len = 0; +#endif + if (lockit) + spin_lock_irqsave(&ch->ch_rxlock, flags); + if (ch->rxd_num == 0) + pr_info(" ZERO receive buffers allocated for this channel."); + else { + FLUSH_MEM_READ(); + m = &ch->mdr[ch->rxix_irq_srv]; + for (n = ch->rxd_num; n; n--) { + status = le32_to_cpu(m->status); + pr_info("%c %08lx[%2d]: sts %08x (%c%c%c%c:%d.) Data [%08x] Next [%08x]\n", + (m == &ch->mdr[ch->rxix_irq_srv]) ? 'F' : ' ', + (unsigned long) m, n, + status, + m->data ? (status & HOST_RX_OWNED ? 'H' : 'M') : '-', + status & POLL_DISABLED ? 'P' : '-', + status & EOBIRQ_ENABLE ? 'b' : '-', + status & EOMIRQ_ENABLE ? 'm' : '-', + status & LENGTH_MASK, + le32_to_cpu(m->data), le32_to_cpu(m->next)); +#ifdef RLD_DUMP_BUFDATA + len = status & LENGTH_MASK; + +#if 1 + if (m->data && (status & HOST_RX_OWNED)) +#else + /* always dump regardless of valid RX data */ + if (m->data) +#endif + { + dp = (u_int32_t *)OS_phystov((void *)(le32_to_cpu(m->data))); + if (len >= 0x10) + pr_info(" %x[%x]: %08X %08X %08X %08x\n", + (u_int32_t)dp, len, + *dp, *(dp + 1), + *(dp + 2), *(dp + 3)); + else if (len >= 0x08) + pr_info(" %x[%x]: %08X %08X\n", + (u_int32_t)dp, len, + *dp, *(dp + 1)); + else + pr_info(" %x[%x]: %08X\n", + (u_int32_t)dp, + len, *dp); + } +#endif + m = m->snext; + } + } + pr_info("\n"); + + if (lockit) + spin_unlock_irqrestore(&ch->ch_rxlock, flags); + return 0; +} + +static int +musycc_dump_txbuffer_ring(mch_t *ch, int lockit) +{ + struct mdesc *m; + unsigned long flags = 0; + u_int32_t status; + int n; +#ifdef RLD_DUMP_BUFDATA + u_int32_t *dp; + int len = 0; +#endif + + if (lockit) + spin_lock_irqsave(&ch->ch_txlock, flags); + if (ch->txd_num == 0) + pr_info(" ZERO transmit buffers allocated for this channel."); + else { + FLUSH_MEM_READ(); + m = ch->txd_irq_srv; + for (n = ch->txd_num; n; n--) { + status = le32_to_cpu(m->status); + pr_info("%c%c %08lx[%2d]: sts %08x (%c%c%c%c:%d.) Data [%08x] Next [%08x]\n", + (m == ch->txd_usr_add) ? 'F' : ' ', + (m == ch->txd_irq_srv) ? 'L' : ' ', + (unsigned long) m, n, + status, + m->data ? (status & MUSYCC_TX_OWNED ? 'M' : 'H') : '-', + status & POLL_DISABLED ? 'P' : '-', + status & EOBIRQ_ENABLE ? 'b' : '-', + status & EOMIRQ_ENABLE ? 'm' : '-', + status & LENGTH_MASK, + le32_to_cpu(m->data), le32_to_cpu(m->next)); +#ifdef RLD_DUMP_BUFDATA + len = status & LENGTH_MASK; + + if (m->data) { + dp = (u_int32_t *)OS_phystov((void *)(le32_to_cpu(m->data))); + if (len >= 0x10) + pr_info(" %x[%x]: %08X %08X %08X %08x\n", + (u_int32_t) dp, len, + *dp, *(dp + 1), + *(dp + 2), *(dp + 3)); + else if (len >= 0x08) + pr_info(" %x[%x]: %08X %08X\n", + (u_int32_t)dp, len, + *dp, *(dp + 1)); + else + pr_info(" %x[%x]: %08X\n", + (u_int32_t)dp, len, *dp); + } +#endif + m = m->snext; + } + } /* -for- */ + pr_info("\n"); + + if (lockit) + spin_unlock_irqrestore(&ch->ch_txlock, flags); + return 0; +} + +/* + * The following supports a backdoor debug facility which can be used to + * display the state of a board's channel. + */ + +status_t +musycc_dump_ring(ci_t *ci, unsigned int chan) +{ + mch_t *ch; + int bh; + + if (chan >= MAX_CHANS_USED) + return SBE_DRVR_FAIL; /* E2BIG */ + + bh = atomic_read(&ci->bh_pending); + pr_info(">> bh_pend %d [%d] ihead %d itail %d [%d] th_cnt %d bh_cnt %d wdcnt %d note %d\n", + bh, max_bh, ci->iqp_headx, ci->iqp_tailx, max_intcnt, + ci->intlog.drvr_intr_thcount, + ci->intlog.drvr_intr_bhcount, + ci->wdcount, ci->wd_notify); + max_bh = 0; /* reset counter */ + max_intcnt = 0; /* reset counter */ + + ch = sd_find_chan(dummy, chan); + if (!ch) { + pr_info(">> musycc_dump_ring: channel %d not up.\n", chan); + return ENOENT; + } + pr_info(">> CI %p CHANNEL %3d @ %p: state %x status/p %x/%x\n", + ci, chan, ch, ch->state, + ch->status, ch->p.status); + pr_info("--------------------------------\n"); + pr_info("TX Buffer Ring - Channel %d, txd_num %d. (bd/ch pend %d %d), TXD required %d, txpkt %lu\n", + chan, ch->txd_num, + (u_int32_t)atomic_read(&ci->tx_pending), + (u_int32_t)atomic_read(&ch->tx_pending), + ch->txd_required, ch->s.tx_packets); + pr_info("++ User 0x%p IRQ_SRV 0x%p USR_ADD 0x%p QStopped %x, start_tx %x tx_full %d txd_free %d mode %x\n", + ch->user, ch->txd_irq_srv, ch->txd_usr_add, + sd_queue_stopped(ch->user), + ch->ch_start_tx, ch->tx_full, ch->txd_free, ch->p.chan_mode); + musycc_dump_txbuffer_ring(ch, 1); + pr_info("RX Buffer Ring - Channel %d, rxd_num %d. IRQ_SRV[%d] 0x%p, start_rx %x rxpkt %lu\n", + chan, ch->rxd_num, ch->rxix_irq_srv, + &ch->mdr[ch->rxix_irq_srv], ch->ch_start_rx, ch->s.rx_packets); + musycc_dump_rxbuffer_ring(ch, 1); + + return SBE_DRVR_SUCCESS; +} + + +status_t +musycc_dump_rings(ci_t *ci, unsigned int start_chan) +{ + unsigned int chan; + + for (chan = start_chan; chan < (start_chan + 5); chan++) + musycc_dump_ring(ci, chan); + return SBE_DRVR_SUCCESS; +} + + +/* + * NOTE on musycc_init_mdt(): These MUSYCC writes are only operational after + * a MUSYCC GROUP_INIT command has been issued. + */ + +void +musycc_init_mdt(mpi_t *pi) +{ + u_int32_t *addr, cfg; + int i; + + /* + * This Idle Code insertion takes effect prior to channel's first + * transmitted message. After that, each message contains its own Idle + * Code information which is to be issued after the message is + * transmitted (Ref.MUSYCC 5.2.2.3: MCENBL bit in Group Configuration + * Descriptor). + */ + + addr = (u_int32_t *) ((u_long) pi->reg + MUSYCC_MDT_BASE03_ADDR); + cfg = CFG_CH_FLAG_7E << IDLE_CODE; + + for (i = 0; i < 32; addr++, i++) + pci_write_32(addr, cfg); +} + + +/* Set TX thp to the next unprocessed md */ + +void +musycc_update_tx_thp(mch_t *ch) +{ + struct mdesc *md; + unsigned long flags; + + spin_lock_irqsave(&ch->ch_txlock, flags); + while (1) { + md = ch->txd_irq_srv; + FLUSH_MEM_READ(); + if (!md->data) { + /* No MDs with buffers to process */ + spin_unlock_irqrestore(&ch->ch_txlock, flags); + return; + } + if ((le32_to_cpu(md->status)) & MUSYCC_TX_OWNED) { + /* this is the MD to restart TX with */ + break; + } + /* + * Otherwise, we have a valid, host-owned message descriptor which + * has been successfully transmitted and whose buffer can be freed, + * so... process this MD, it's owned by the host. (This might give + * as a new, updated txd_irq_srv.) + */ + musycc_bh_tx_eom(ch->up, ch->gchan); + } + md = ch->txd_irq_srv; + ch->up->regram->thp[ch->gchan] = cpu_to_le32(OS_vtophys(md)); + FLUSH_MEM_WRITE(); + + if (ch->tx_full) { + ch->tx_full = 0; + ch->txd_required = 0; + sd_enable_xmit(ch->user); /* re-enable to catch flow controlled + * channel */ + } + spin_unlock_irqrestore(&ch->ch_txlock, flags); + +#ifdef RLD_TRANS_DEBUG + pr_info("++ musycc_update_tx_thp[%d]: setting thp = %p, sts %x\n", + ch->channum, md, md->status); +#endif +} + + +/* + * This is the workq task executed by the OS when our queue_work() is + * scheduled and run. It can fire off either RX or TX ACTIVATION depending + * upon the channel's ch_start_tx and ch_start_rx variables. This routine + * is implemented as a work queue so that the call to the service request is + * able to sleep, awaiting an interrupt acknowledgment response (SACK) from + * the hardware. + */ + +void +musycc_wq_chan_restart(void *arg) /* channel private structure */ +{ + mch_t *ch; + mpi_t *pi; + struct mdesc *md; + +#if defined(RLD_TRANS_DEBUG) || defined(RLD_RXACT_DEBUG) + static int hereb4 = 7; +#endif + + ch = container_of(arg, struct c4_chan_info, ch_work); + pi = ch->up; + +#ifdef RLD_TRANS_DEBUG + pr_info("wq_chan_restart[%d]: start_RT[%d/%d] status %x\n", + ch->channum, ch->ch_start_rx, ch->ch_start_tx, ch->status); + +#endif + + /**********************************/ + /** check for RX restart request **/ + /**********************************/ + + if ((ch->ch_start_rx) && (ch->status & RX_ENABLED)) { + + ch->ch_start_rx = 0; +#if defined(RLD_TRANS_DEBUG) || defined(RLD_RXACT_DEBUG) + if (hereb4) { /* RLD DEBUG */ + hereb4--; +#ifdef RLD_TRANS_DEBUG + md = &ch->mdr[ch->rxix_irq_srv]; + pr_info("++ musycc_wq_chan_restart[%d] CHAN RX ACTIVATE: rxix_irq_srv %d, md %p sts %x, rxpkt %lu\n", + ch->channum, ch->rxix_irq_srv, md, + le32_to_cpu(md->status), ch->s.rx_packets); +#elif defined(RLD_RXACT_DEBUG) + md = &ch->mdr[ch->rxix_irq_srv]; + pr_info("++ musycc_wq_chan_restart[%d] CHAN RX ACTIVATE: rxix_irq_srv %d, md %p sts %x, rxpkt %lu\n", + ch->channum, ch->rxix_irq_srv, + md, le32_to_cpu(md->status), + ch->s.rx_packets); + musycc_dump_rxbuffer_ring(ch, 1); /* RLD DEBUG */ +#endif + } +#endif + musycc_serv_req(pi, SR_CHANNEL_ACTIVATE | + SR_RX_DIRECTION | ch->gchan); + } + /**********************************/ + /** check for TX restart request **/ + /**********************************/ + + if ((ch->ch_start_tx) && (ch->status & TX_ENABLED)) { + /* find next unprocessed message, then set TX thp to it */ + musycc_update_tx_thp(ch); + + md = ch->txd_irq_srv; + if (!md) { +#ifdef RLD_TRANS_DEBUG + pr_info("-- musycc_wq_chan_restart[%d]: WARNING, starting NULL md\n", + ch->channum); +#endif + } else if (md->data && ((le32_to_cpu(md->status)) & + MUSYCC_TX_OWNED)) { + ch->ch_start_tx = 0; + +#ifdef RLD_TRANS_DEBUG + pr_info("++ musycc_wq_chan_restart() CHAN TX ACTIVATE: chan %d txd_irq_srv %p = sts %x, txpkt %lu\n", + ch->channum, ch->txd_irq_srv, + ch->txd_irq_srv->status, ch->s.tx_packets); +#endif + musycc_serv_req(pi, SR_CHANNEL_ACTIVATE | + SR_TX_DIRECTION | ch->gchan); + } +#ifdef RLD_RESTART_DEBUG + else { + /* retain request to start until retried and we have data to xmit */ + pr_info("-- musycc_wq_chan_restart[%d]: DELAYED due to md %p sts %x data %x, start_tx %x\n", + ch->channum, md, + le32_to_cpu(md->status), + le32_to_cpu(md->data), ch->ch_start_tx); + musycc_dump_txbuffer_ring(ch, 0); + } +#endif + } +} + + + /* + * Channel restart either fires of a workqueue request (2.6) or lodges a + * watchdog activation sequence (2.4). + */ + +void +musycc_chan_restart(mch_t *ch) +{ +#ifdef RLD_RESTART_DEBUG + pr_info("++ musycc_chan_restart[%d]: txd_irq_srv @ %p = sts %x\n", + ch->channum, ch->txd_irq_srv, ch->txd_irq_srv->status); +#endif + + /* 2.6 - find next unprocessed message, then set TX thp to it */ +#ifdef RLD_RESTART_DEBUG + pr_info(">> musycc_chan_restart: scheduling Chan %x workQ @ %p\n", + ch->channum, &ch->ch_work); +#endif + c4_wk_chan_restart(ch); /* work queue mechanism fires off: Ref: + * musycc_wq_chan_restart () */ +} + + +void +rld_put_led(mpi_t *pi, u_int32_t ledval) +{ + static u_int32_t led; + + if (ledval == 0) + led = 0; + else + led |= ledval; + + /* RLD DEBUG TRANHANG */ + pci_write_32((u_int32_t *) &pi->up->cpldbase->leds, led); +} + + +#define MUSYCC_SR_RETRY_CNT 9 + +void +musycc_serv_req(mpi_t *pi, u_int32_t req) +{ + volatile u_int32_t r; + int rcnt; + + /* + * PORT NOTE: Semaphore protect service loop guarantees only a single + * operation at a time. Per MUSYCC Manual - "Issuing service requests to + * the same channel group without first receiving ACK from each request + * may cause the host to lose track of which service request has been + * acknowledged." + */ + + SD_SEM_TAKE(&pi->sr_sem_busy, "serv"); /* only 1 thru here, per + * group */ + + if (pi->sr_last == req) { +#ifdef RLD_TRANS_DEBUG + pr_info(">> same SR, Port %d Req %x\n", pi->portnum, req); +#endif + + /* + * The most likely repeated request is the channel activation command + * which follows the occurrence of a Transparent mode TX ONR or a + * BUFF error. If the previous command was a CHANNEL ACTIVATE, + * precede it with a NOOP command in order maintain coherent control + * of this current (re)ACTIVATE. + */ + + r = (pi->sr_last & ~SR_GCHANNEL_MASK); + if ((r == (SR_CHANNEL_ACTIVATE | SR_TX_DIRECTION)) || + (r == (SR_CHANNEL_ACTIVATE | SR_RX_DIRECTION))) { +#ifdef RLD_TRANS_DEBUG + pr_info(">> same CHAN ACT SR, Port %d Req %x => issue SR_NOOP CMD\n", pi->portnum, req); +#endif + /* allow this next request */ + SD_SEM_GIVE(&pi->sr_sem_busy); + musycc_serv_req(pi, SR_NOOP); + /* relock & continue w/ original req */ + SD_SEM_TAKE(&pi->sr_sem_busy, "serv"); + } else if (req == SR_NOOP) { + /* no need to issue back-to-back + * SR_NOOP commands at this time + */ +#ifdef RLD_TRANS_DEBUG + pr_info(">> same Port SR_NOOP skipped, Port %d\n", + pi->portnum); +#endif + /* allow this next request */ + SD_SEM_GIVE(&pi->sr_sem_busy); + return; + } + } + rcnt = 0; + pi->sr_last = req; +rewrite: + pci_write_32((u_int32_t *) &pi->reg->srd, req); + FLUSH_MEM_WRITE(); + + /* + * Per MUSYCC Manual, Section 6.1,2 - "When writing an SCR service + * request, the host must ensure at least one PCI bus clock cycle has + * elapsed before writing another service request. To meet this minimum + * elapsed service request write timing interval, it is recommended that + * the host follow any SCR write with another operation which reads from + * the same address." + */ + + /* adhere to write timing imposition */ + r = pci_read_32((u_int32_t *) &pi->reg->srd); + + + if ((r != req) && (req != SR_CHIP_RESET) && + (++rcnt <= MUSYCC_SR_RETRY_CNT)) { + if (cxt1e1_log_level >= LOG_MONITOR) + pr_info("%s: %d - reissue srv req/last %x/%x (hdw reads %x), Chan %d.\n", + pi->up->devname, rcnt, req, pi->sr_last, r, + (pi->portnum * MUSYCC_NCHANS) + (req & 0x1f)); + /* this delay helps reduce reissue counts + * (reason not yet researched) + */ + OS_uwait_dummy(); + goto rewrite; + } + if (rcnt > MUSYCC_SR_RETRY_CNT) { + pr_warning("%s: failed service request (#%d)= %x, group %d.\n", + pi->up->devname, MUSYCC_SR_RETRY_CNT, + req, pi->portnum); + SD_SEM_GIVE(&pi->sr_sem_busy); /* allow any next request */ + return; + } + if (req == SR_CHIP_RESET) { + /* + * PORT NOTE: the CHIP_RESET command is NOT ack'd by the MUSYCC, thus + * the upcoming delay is used. Though the MUSYCC documentation + * suggests a read-after-write would supply the required delay, it's + * unclear what CPU/BUS clock speeds might have been assumed when + * suggesting this 'lack of ACK' workaround. Thus the use of uwait. + */ + OS_uwait(100000, "icard"); /* 100ms */ + } else { + FLUSH_MEM_READ(); + /* sleep until SACK interrupt occurs */ + SD_SEM_TAKE(&pi->sr_sem_wait, "sakack"); + } + SD_SEM_GIVE(&pi->sr_sem_busy); /* allow any next request */ +} + + +#ifdef SBE_PMCC4_ENABLE +void +musycc_update_timeslots(mpi_t *pi) +{ + int i, ch; + char e1mode = IS_FRAME_ANY_E1(pi->p.port_mode); + + for (i = 0; i < 32; i++) { + int usedby = 0, last = 0, ts, j, bits[8]; + + u_int8_t lastval = 0; + + if (((i == 0) && e1mode) || /* disable if E1 mode */ + ((i == 16) && ((pi->p.port_mode == CFG_FRAME_E1CRC_CAS) || + (pi->p.port_mode == CFG_FRAME_E1CRC_CAS_AMI))) || + ((i > 23) && (!e1mode))) /* disable if T1 mode */ + /* make tslot unavailable for this mode */ + pi->tsm[i] = 0xff; + else + /* make tslot available for assignment */ + pi->tsm[i] = 0x00; + for (j = 0; j < 8; j++) + bits[j] = -1; + for (ch = 0; ch < MUSYCC_NCHANS; ch++) { + if ((pi->chan[ch]->state == UP) && + (pi->chan[ch]->p.bitmask[i])) { + usedby++; + last = ch; + lastval = pi->chan[ch]->p.bitmask[i]; + for (j = 0; j < 8; j++) + if (lastval & (1 << j)) + bits[j] = ch; + pi->tsm[i] |= lastval; + } + } + if (!usedby) + ts = 0; + else if ((usedby == 1) && (lastval == 0xff)) + ts = (4 << 5) | last; + else if ((usedby == 1) && (lastval == 0x7f)) + ts = (5 << 5) | last; + else { + int idx; + + if (bits[0] < 0) + ts = (6 << 5) | (idx = last); + else + ts = (7 << 5) | (idx = bits[0]); + for (j = 1; j < 8; j++) { + pi->regram->rscm[idx * 8 + j] = + (bits[j] < 0) ? 0 : (0x80 | bits[j]); + pi->regram->tscm[idx * 8 + j] = + (bits[j] < 0) ? 0 : (0x80 | bits[j]); + } + } + pi->regram->rtsm[i] = ts; + pi->regram->ttsm[i] = ts; + } + FLUSH_MEM_WRITE(); + + musycc_serv_req(pi, SR_TIMESLOT_MAP | SR_RX_DIRECTION); + musycc_serv_req(pi, SR_TIMESLOT_MAP | SR_TX_DIRECTION); + musycc_serv_req(pi, SR_SUBCHANNEL_MAP | SR_RX_DIRECTION); + musycc_serv_req(pi, SR_SUBCHANNEL_MAP | SR_TX_DIRECTION); +} +#endif + + +#ifdef SBE_WAN256T3_ENABLE + void +musycc_update_timeslots(mpi_t *pi) +{ + mch_t *ch; + + u_int8_t ts, hmask, tsen; + int gchan; + int i; + +#ifdef SBE_PMCC4_ENABLE + hmask = (0x1f << pi->up->p.hypersize) & 0x1f; +#endif +#ifdef SBE_WAN256T3_ENABLE + hmask = (0x1f << hyperdummy) & 0x1f; +#endif + for (i = 0; i < 128; i++) { + gchan = ((pi->portnum * MUSYCC_NCHANS) + + (i & hmask)) % MUSYCC_NCHANS; + ch = pi->chan[gchan]; + if (ch->p.mode_56k) + tsen = MODE_56KBPS; + else + tsen = MODE_64KBPS; /* also the default */ + ts = ((pi->portnum % 4) == (i / 32)) ? (tsen << 5) | (i & hmask) : 0; + pi->regram->rtsm[i] = ts; + pi->regram->ttsm[i] = ts; + } + FLUSH_MEM_WRITE(); + musycc_serv_req(pi, SR_TIMESLOT_MAP | SR_RX_DIRECTION); + musycc_serv_req(pi, SR_TIMESLOT_MAP | SR_TX_DIRECTION); +} +#endif + + + /* + * This routine converts a generic library channel configuration parameter + * into a hardware specific register value (IE. MUSYCC CCD Register). + */ +u_int32_t +musycc_chan_proto(int proto) +{ + int reg; + + switch (proto) { + case CFG_CH_PROTO_TRANS: /* 0 */ + reg = MUSYCC_CCD_TRANS; + break; + case CFG_CH_PROTO_SS7: /* 1 */ + reg = MUSYCC_CCD_SS7; + break; + default: + case CFG_CH_PROTO_ISLP_MODE: /* 4 */ + case CFG_CH_PROTO_HDLC_FCS16: /* 2 */ + reg = MUSYCC_CCD_HDLC_FCS16; + break; + case CFG_CH_PROTO_HDLC_FCS32: /* 3 */ + reg = MUSYCC_CCD_HDLC_FCS32; + break; + } + + return reg; +} + +#ifdef SBE_WAN256T3_ENABLE +static void __init +musycc_init_port(mpi_t *pi) +{ + pci_write_32((u_int32_t *) &pi->reg->gbp, OS_vtophys(pi->regram)); + + pi->regram->grcd = + __constant_cpu_to_le32(MUSYCC_GRCD_RX_ENABLE | + MUSYCC_GRCD_TX_ENABLE | + MUSYCC_GRCD_SF_ALIGN | + MUSYCC_GRCD_SUBCHAN_DISABLE | + MUSYCC_GRCD_OOFMP_DISABLE | + MUSYCC_GRCD_COFAIRQ_DISABLE | + MUSYCC_GRCD_MC_ENABLE | + (MUSYCC_GRCD_POLLTH_32 << MUSYCC_GRCD_POLLTH_SHIFT)); + + pi->regram->pcd = + __constant_cpu_to_le32(MUSYCC_PCD_E1X4_MODE | + MUSYCC_PCD_TXDATA_RISING | + MUSYCC_PCD_TX_DRIVEN); + + /* Message length descriptor */ + pi->regram->mld = __constant_cpu_to_le32(cxt1e1_max_mru | (cxt1e1_max_mru << 16)); + FLUSH_MEM_WRITE(); + + musycc_serv_req(pi, SR_GROUP_INIT | SR_RX_DIRECTION); + musycc_serv_req(pi, SR_GROUP_INIT | SR_TX_DIRECTION); + + musycc_init_mdt(pi); + + musycc_update_timeslots(pi); +} +#endif + + +status_t __init +musycc_init(ci_t *ci) +{ + char *regaddr; /* temp for address boundary calculations */ + int i, gchan; + + OS_sem_init(&ci->sem_wdbusy, SEM_AVAILABLE); /* watchdog exclusion */ + + /* + * Per MUSYCC manual, Section 6.3.4 - "The host must allocate a dword + * aligned memory segment for interrupt queue pointers." + */ + +#define INT_QUEUE_BOUNDARY 4 + + regaddr = kzalloc((INT_QUEUE_SIZE + 1) * sizeof(u_int32_t), + GFP_KERNEL | GFP_DMA); + if (!regaddr) + return -ENOMEM; + ci->iqd_p_saved = regaddr; /* save orig value for free's usage */ + /* this calculates closest boundary */ + ci->iqd_p = (u_int32_t *) ((unsigned long)(regaddr + INT_QUEUE_BOUNDARY - 1) & + (~(INT_QUEUE_BOUNDARY - 1))); + + for (i = 0; i < INT_QUEUE_SIZE; i++) + ci->iqd_p[i] = __constant_cpu_to_le32(INT_EMPTY_ENTRY); + + for (i = 0; i < ci->max_port; i++) { + mpi_t *pi = &ci->port[i]; + + /* + * Per MUSYCC manual, Section 6.3.2 - "The host must allocate a 2KB + * bound memory segment for Channel Group 0." + */ + +#define GROUP_BOUNDARY 0x800 + + regaddr = kzalloc(sizeof(struct musycc_groupr) + GROUP_BOUNDARY, + GFP_KERNEL | GFP_DMA); + if (!regaddr) { + for (gchan = 0; gchan < i; gchan++) { + pi = &ci->port[gchan]; + kfree(pi->reg); + pi->reg = NULL; + } + return -ENOMEM; + } + pi->regram_saved = regaddr; /* save orig value for free's usage */ + /* this calculates closest boundary */ + pi->regram = (struct musycc_groupr *) ((unsigned long)(regaddr + GROUP_BOUNDARY - 1) & + (~(GROUP_BOUNDARY - 1))); + } + + /* any board centric MUSYCC commands will use group ZERO as its "home" */ + ci->regram = ci->port[0].regram; + musycc_serv_req(&ci->port[0], SR_CHIP_RESET); + + pci_write_32((u_int32_t *) &ci->reg->gbp, OS_vtophys(ci->regram)); + pci_flush_write(ci); +#ifdef CONFIG_SBE_PMCC4_NCOMM + ci->regram->__glcd = __constant_cpu_to_le32(GCD_MAGIC); +#else + /* standard driver POLLS for INTB via CPLD register */ + ci->regram->__glcd = __constant_cpu_to_le32(GCD_MAGIC | + MUSYCC_GCD_INTB_DISABLE); +#endif + + ci->regram->__iqp = cpu_to_le32(OS_vtophys(&ci->iqd_p[0])); + ci->regram->__iql = __constant_cpu_to_le32(INT_QUEUE_SIZE - 1); + pci_write_32((u_int32_t *) &ci->reg->dacbp, 0); + FLUSH_MEM_WRITE(); + + ci->state = C_RUNNING; /* mark as full interrupt processing + * available */ + + musycc_serv_req(&ci->port[0], SR_GLOBAL_INIT); /* FIRST INTERRUPT ! */ + + /* sanity check settable parameters */ + + if (cxt1e1_max_mru > 0xffe) { + pr_warning("Maximum allowed MRU exceeded, resetting %d to %d.\n", + cxt1e1_max_mru, 0xffe); + cxt1e1_max_mru = 0xffe; + } + if (cxt1e1_max_mtu > 0xffe) { + pr_warning("Maximum allowed MTU exceeded, resetting %d to %d.\n", + cxt1e1_max_mtu, 0xffe); + cxt1e1_max_mtu = 0xffe; + } +#ifdef SBE_WAN256T3_ENABLE + for (i = 0; i < MUSYCC_NPORTS; i++) + musycc_init_port(&ci->port[i]); +#endif + + return SBE_DRVR_SUCCESS; /* no error */ +} + + +void +musycc_bh_tx_eom(mpi_t *pi, int gchan) +{ + mch_t *ch; + struct mdesc *md; + + volatile u_int32_t status; + + ch = pi->chan[gchan]; + if (!ch || ch->state != UP) { + if (cxt1e1_log_level >= LOG_ERROR) + pr_info("%s: intr: xmit EOM on uninitialized channel %d\n", + pi->up->devname, gchan); + } + if (!ch || !ch->mdt) + return; /* note: mdt==0 implies a malloc() + * failure w/in chan_up() routine */ + + do { + FLUSH_MEM_READ(); + md = ch->txd_irq_srv; + status = le32_to_cpu(md->status); + + /* + * Note: Per MUSYCC Ref 6.4.9, the host does not poll a host-owned + * Transmit Buffer Descriptor during Transparent Mode. + */ + if (status & MUSYCC_TX_OWNED) { + int readCount, loopCount; + + /***********************************************************/ + /* HW Bug Fix */ + /* ---------- */ + /* Under certain PCI Bus loading conditions, the data */ + /* associated with an update of Shared Memory is delayed */ + /* relative to its PCI Interrupt. This is caught when */ + /* the host determines it does not yet OWN the descriptor. */ + /***********************************************************/ + + readCount = 0; + while (status & MUSYCC_TX_OWNED) { + for (loopCount = 0; loopCount < 0x30; loopCount++) + /* use call to avoid optimization + * removal of dummy delay */ + OS_uwait_dummy(); + FLUSH_MEM_READ(); + status = le32_to_cpu(md->status); + if (readCount++ > 40) + break; /* don't wait any longer */ + } + if (status & MUSYCC_TX_OWNED) { + if (cxt1e1_log_level >= LOG_MONITOR) { + pr_info("%s: Port %d Chan %2d - unexpected TX msg ownership intr (md %p sts %x)\n", + pi->up->devname, pi->portnum, + ch->channum, md, status); + pr_info("++ User 0x%p IRQ_SRV 0x%p USR_ADD 0x%p QStopped %x, start_tx %x tx_full %d txd_free %d mode %x\n", + ch->user, ch->txd_irq_srv, + ch->txd_usr_add, + sd_queue_stopped(ch->user), + ch->ch_start_tx, ch->tx_full, + ch->txd_free, ch->p.chan_mode); + musycc_dump_txbuffer_ring(ch, 0); + } + break; /* Not our mdesc, done */ + } else { + if (cxt1e1_log_level >= LOG_MONITOR) + pr_info("%s: Port %d Chan %2d - recovered TX msg ownership [%d] (md %p sts %x)\n", + pi->up->devname, pi->portnum, + ch->channum, readCount, + md, status); + } + } + ch->txd_irq_srv = md->snext; + + md->data = 0; + if (md->mem_token) { + /* upcount channel */ + atomic_sub(OS_mem_token_tlen(md->mem_token), + &ch->tx_pending); + /* upcount card */ + atomic_sub(OS_mem_token_tlen(md->mem_token), + &pi->up->tx_pending); +#ifdef SBE_WAN256T3_ENABLE + if (!atomic_read(&pi->up->tx_pending)) + wan256t3_led(pi->up, LED_TX, 0); +#endif + OS_mem_token_free_irq(md->mem_token); + md->mem_token = NULL; + } + md->status = 0; +#ifdef RLD_TXFULL_DEBUG + if (cxt1e1_log_level >= LOG_MONITOR2) + pr_info("~~ tx_eom: tx_full %x txd_free %d -> %d\n", + ch->tx_full, ch->txd_free, ch->txd_free + 1); +#endif + ++ch->txd_free; + FLUSH_MEM_WRITE(); + + if ((ch->p.chan_mode != CFG_CH_PROTO_TRANS) && + (status & EOBIRQ_ENABLE)) { + if (cxt1e1_log_level >= LOG_MONITOR) + pr_info("%s: Mode (%x) incorrect EOB status (%x)\n", + pi->up->devname, ch->p.chan_mode, + status); + if ((status & EOMIRQ_ENABLE) == 0) + break; + } + } while ((ch->p.chan_mode != CFG_CH_PROTO_TRANS) && + ((status & EOMIRQ_ENABLE) == 0)); + /* + * NOTE: (The above 'while' is coupled w/ previous 'do', way above.) Each + * Transparent data buffer has the EOB bit, and NOT the EOM bit, set and + * will furthermore have a separate IQD associated with each messages + * buffer. + */ + + FLUSH_MEM_READ(); + /* + * Smooth flow control hysterisis by maintaining task stoppage until half + * the available write buffers are available. + */ + if (ch->tx_full && (ch->txd_free >= (ch->txd_num / 2))) { + /* + * Then, only releave task stoppage if we actually have enough + * buffers to service the last requested packet. It may require MORE + * than half the available! + */ + if (ch->txd_free >= ch->txd_required) { + +#ifdef RLD_TXFULL_DEBUG + if (cxt1e1_log_level >= LOG_MONITOR2) + pr_info("tx_eom[%d]: enable xmit tx_full no more, txd_free %d txd_num/2 %d\n", + ch->channum, + ch->txd_free, ch->txd_num / 2); +#endif + ch->tx_full = 0; + ch->txd_required = 0; + /* re-enable to catch flow controlled channel */ + sd_enable_xmit(ch->user); + } + } +#ifdef RLD_TXFULL_DEBUG + else if (ch->tx_full) { + if (cxt1e1_log_level >= LOG_MONITOR2) + pr_info("tx_eom[%d]: bypass TX enable though room available? (txd_free %d txd_num/2 %d)\n", + ch->channum, + ch->txd_free, ch->txd_num / 2); + } +#endif + + FLUSH_MEM_WRITE(); +} + + +static void +musycc_bh_rx_eom(mpi_t *pi, int gchan) +{ + mch_t *ch; + void *m, *m2; + struct mdesc *md; + volatile u_int32_t status; + u_int32_t error; + + ch = pi->chan[gchan]; + if (!ch || ch->state != UP) { + if (cxt1e1_log_level > LOG_ERROR) + pr_info("%s: intr: receive EOM on uninitialized channel %d\n", + pi->up->devname, gchan); + return; + } + if (!ch->mdr) + return; /* can this happen ? */ + + for (;;) { + FLUSH_MEM_READ(); + md = &ch->mdr[ch->rxix_irq_srv]; + status = le32_to_cpu(md->status); + if (!(status & HOST_RX_OWNED)) + break; /* Not our mdesc, done */ + m = md->mem_token; + error = (status >> 16) & 0xf; + if (error == 0) { + { + m2 = OS_mem_token_alloc(cxt1e1_max_mru); + if (m2) { + /* substitute the mbuf+cluster */ + md->mem_token = m2; + md->data = cpu_to_le32(OS_vtophys( + OS_mem_token_data(m2))); + + /* pass the received mbuf upward */ + sd_recv_consume(m, status & LENGTH_MASK, + ch->user); + ch->s.rx_packets++; + ch->s.rx_bytes += status & LENGTH_MASK; + } else + ch->s.rx_dropped++; + } + } else if (error == ERR_FCS) + ch->s.rx_crc_errors++; + else if (error == ERR_ALIGN) + ch->s.rx_missed_errors++; + else if (error == ERR_ABT) + ch->s.rx_missed_errors++; + else if (error == ERR_LNG) + ch->s.rx_length_errors++; + else if (error == ERR_SHT) + ch->s.rx_length_errors++; + FLUSH_MEM_WRITE(); + status = cxt1e1_max_mru; + if (ch->p.chan_mode == CFG_CH_PROTO_TRANS) + status |= EOBIRQ_ENABLE; + md->status = cpu_to_le32(status); + + /* Check next mdesc in the ring */ + if (++ch->rxix_irq_srv >= ch->rxd_num) + ch->rxix_irq_srv = 0; + FLUSH_MEM_WRITE(); + } +} + + +irqreturn_t +musycc_intr_th_handler(void *devp) +{ + ci_t *ci = (ci_t *) devp; + volatile u_int32_t status, currInt = 0; + u_int32_t nextInt, intCnt; + + /* + * Hardware not available, potential interrupt hang. But since interrupt + * might be shared, just return. + */ + if (ci->state == C_INIT) + return IRQ_NONE; + /* + * Marked as hardware available. Don't service interrupts, just clear the + * event. + */ + + if (ci->state == C_IDLE) { + status = pci_read_32((u_int32_t *) &ci->reg->isd); + + /* clear the interrupt but process nothing else */ + pci_write_32((u_int32_t *) &ci->reg->isd, status); + return IRQ_HANDLED; + } + FLUSH_PCI_READ(); + FLUSH_MEM_READ(); + + status = pci_read_32((u_int32_t *) &ci->reg->isd); + nextInt = INTRPTS_NEXTINT(status); + intCnt = INTRPTS_INTCNT(status); + ci->intlog.drvr_intr_thcount++; + + /*********************************************************/ + /* HW Bug Fix */ + /* ---------- */ + /* Under certain PCI Bus loading conditions, the */ + /* MUSYCC looses the data associated with an update */ + /* of its ISD and erroneously returns the immediately */ + /* preceding 'nextInt' value. However, the 'intCnt' */ + /* value appears to be correct. By not starting service */ + /* where the 'missing' 'nextInt' SHOULD point causes */ + /* the IQD not to be serviced - the 'not serviced' */ + /* entries then remain and continue to increase as more */ + /* incorrect ISD's are encountered. */ + /*********************************************************/ + + if (nextInt != INTRPTS_NEXTINT(ci->intlog.this_status_new)) { + if (cxt1e1_log_level >= LOG_MONITOR) { + pr_info("%s: note - updated ISD from %08x to %08x\n", + ci->devname, status, + (status & (~INTRPTS_NEXTINT_M)) | + ci->intlog.this_status_new); + } + /* + * Replace bogus status with software corrected value. + * + * It's not known whether, during this problem occurrence, if the + * INTFULL bit is correctly reported or not. + */ + status = (status & (~INTRPTS_NEXTINT_M)) | + (ci->intlog.this_status_new); + nextInt = INTRPTS_NEXTINT(status); + } + /**********************************************/ + /* Cn847x Bug Fix */ + /* -------------- */ + /* Fix for inability to write back same index */ + /* as read for a full interrupt queue. */ + /**********************************************/ + + if (intCnt == INT_QUEUE_SIZE) + currInt = ((intCnt - 1) + nextInt) & (INT_QUEUE_SIZE - 1); + else + /************************************************/ + /* Interrupt Write Location Issues */ + /* ------------------------------- */ + /* When the interrupt status descriptor is */ + /* written, the interrupt line is de-asserted */ + /* by the Cn847x. In the case of MIPS */ + /* microprocessors, this must occur at the */ + /* beginning of the interrupt handler so that */ + /* the interrupt handle is not re-entered due */ + /* to interrupt dis-assertion latency. */ + /* In the case of all other processors, this */ + /* action should occur at the end of the */ + /* interrupt handler to avoid overwriting the */ + /* interrupt queue. */ + /************************************************/ + + if (intCnt) + currInt = (intCnt + nextInt) & (INT_QUEUE_SIZE - 1); + else { + /* + * NOTE: Servicing an interrupt whose ISD contains a count of ZERO + * can be indicative of a Shared Interrupt chain. Our driver can be + * called from the system's interrupt handler as a matter of the OS + * walking the chain. As the chain is walked, the interrupt will + * eventually be serviced by the correct driver/handler. + */ + return IRQ_NONE; + } + + ci->iqp_tailx = currInt; + + currInt <<= INTRPTS_NEXTINT_S; + ci->intlog.last_status_new = ci->intlog.this_status_new; + ci->intlog.this_status_new = currInt; + + if ((cxt1e1_log_level >= LOG_WARN) && (status & INTRPTS_INTFULL_M)) + pr_info("%s: Interrupt queue full condition occurred\n", + ci->devname); + if (cxt1e1_log_level >= LOG_DEBUG) + pr_info("%s: interrupts pending, isd @ 0x%p: %x curr %d cnt %d NEXT %d\n", + ci->devname, &ci->reg->isd, + status, nextInt, intCnt, + (intCnt + nextInt) & (INT_QUEUE_SIZE - 1)); + + FLUSH_MEM_WRITE(); +#if defined(SBE_ISR_TASKLET) + pci_write_32((u_int32_t *) &ci->reg->isd, currInt); + atomic_inc(&ci->bh_pending); + tasklet_schedule(&ci->ci_musycc_isr_tasklet); +#elif defined(SBE_ISR_IMMEDIATE) + pci_write_32((u_int32_t *) &ci->reg->isd, currInt); + atomic_inc(&ci->bh_pending); + queue_task(&ci->ci_musycc_isr_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +#elif defined(SBE_ISR_INLINE) + (void) musycc_intr_bh_tasklet(ci); + pci_write_32((u_int32_t *) &ci->reg->isd, currInt); +#endif + return IRQ_HANDLED; +} + + +#if defined(SBE_ISR_IMMEDIATE) +unsigned long +#else +void +#endif +musycc_intr_bh_tasklet(ci_t *ci) +{ + mpi_t *pi; + mch_t *ch; + unsigned int intCnt; + volatile u_int32_t currInt = 0; + volatile unsigned int headx, tailx; + int readCount, loopCount; + int group, gchan, event, err, tx; + u_int32_t badInt = INT_EMPTY_ENTRY; + u_int32_t badInt2 = INT_EMPTY_ENTRY2; + + /* + * Hardware not available, potential interrupt hang. But since interrupt + * might be shared, just return. + */ + if ((drvr_state != SBE_DRVR_AVAILABLE) || (ci->state == C_INIT)) { +#if defined(SBE_ISR_IMMEDIATE) + return 0L; +#else + return; +#endif + } +#if defined(SBE_ISR_TASKLET) || defined(SBE_ISR_IMMEDIATE) + if (drvr_state != SBE_DRVR_AVAILABLE) { +#if defined(SBE_ISR_TASKLET) + return; +#elif defined(SBE_ISR_IMMEDIATE) + return 0L; +#endif + } +#elif defined(SBE_ISR_INLINE) + /* no semaphore taken, no double checks */ +#endif + + ci->intlog.drvr_intr_bhcount++; + FLUSH_MEM_READ(); + { + unsigned int bh = atomic_read(&ci->bh_pending); + + max_bh = max(bh, max_bh); + } + atomic_set(&ci->bh_pending, 0);/* if here, no longer pending */ + while ((headx = ci->iqp_headx) != (tailx = ci->iqp_tailx)) { + intCnt = (tailx >= headx) ? (tailx - headx) : (tailx - headx + INT_QUEUE_SIZE); + currInt = le32_to_cpu(ci->iqd_p[headx]); + + max_intcnt = max(intCnt, max_intcnt); /* RLD DEBUG */ + + /**************************************************/ + /* HW Bug Fix */ + /* ---------- */ + /* The following code checks for the condition */ + /* of interrupt assertion before interrupt */ + /* queue update. This is a problem on several */ + /* PCI-Local bridge chips found on some products. */ + /**************************************************/ + + readCount = 0; + if ((currInt == badInt) || (currInt == badInt2)) + ci->intlog.drvr_int_failure++; + + while ((currInt == badInt) || (currInt == badInt2)) { + for (loopCount = 0; loopCount < 0x30; loopCount++) + /* use call to avoid optimization + * removal of dummy delay + */ + OS_uwait_dummy(); + FLUSH_MEM_READ(); + currInt = le32_to_cpu(ci->iqd_p[headx]); + if (readCount++ > 20) + break; + } + + /* catch failure of Bug Fix checking */ + if ((currInt == badInt) || (currInt == badInt2)) { + if (cxt1e1_log_level >= LOG_WARN) + pr_info("%s: Illegal Interrupt Detected @ 0x%p, mod %d.)\n", + ci->devname, &ci->iqd_p[headx], headx); + + /* + * If the descriptor has not recovered, then leaving the EMPTY + * entry set will not signal to the MUSYCC that this descriptor + * has been serviced. The Interrupt Queue can then start losing + * available descriptors and MUSYCC eventually encounters and + * reports the INTFULL condition. Per manual, changing any bit + * marks descriptor as available, thus the use of different + * EMPTY_ENTRY values. + */ + + if (currInt == badInt) + ci->iqd_p[headx] = __constant_cpu_to_le32(INT_EMPTY_ENTRY2); + else + ci->iqd_p[headx] = __constant_cpu_to_le32(INT_EMPTY_ENTRY); + /* insure wrapness */ + ci->iqp_headx = (headx + 1) & (INT_QUEUE_SIZE - 1); + FLUSH_MEM_WRITE(); + FLUSH_MEM_READ(); + continue; + } + group = INTRPT_GRP(currInt); + gchan = INTRPT_CH(currInt); + event = INTRPT_EVENT(currInt); + err = INTRPT_ERROR(currInt); + tx = currInt & INTRPT_DIR_M; + + ci->iqd_p[headx] = __constant_cpu_to_le32(INT_EMPTY_ENTRY); + FLUSH_MEM_WRITE(); + + if (cxt1e1_log_level >= LOG_DEBUG) { + if (err != 0) + pr_info(" %08x -> err: %2d,", currInt, err); + + pr_info("+ interrupt event: %d, grp: %d, chan: %2d, side: %cX\n", + event, group, gchan, tx ? 'T' : 'R'); + } + /* notice that here we assume 1-1 group - port mapping */ + pi = &ci->port[group]; + ch = pi->chan[gchan]; + switch (event) { + case EVE_SACK: /* Service Request Acknowledge */ + if (cxt1e1_log_level >= LOG_DEBUG) { + volatile u_int32_t r; + + r = pci_read_32((u_int32_t *) &pi->reg->srd); + pr_info("- SACK cmd: %08x (hdw= %08x)\n", + pi->sr_last, r); + } + /* wake up waiting process */ + SD_SEM_GIVE(&pi->sr_sem_wait); + break; + case EVE_CHABT: /* Change To Abort Code (0x7e -> 0xff) */ + case EVE_CHIC: /* Change To Idle Code (0xff -> 0x7e) */ + break; + case EVE_EOM: /* End Of Message */ + case EVE_EOB: /* End Of Buffer (Transparent mode) */ + if (tx) + musycc_bh_tx_eom(pi, gchan); + else + musycc_bh_rx_eom(pi, gchan); + /* + * MUSYCC Interrupt Descriptor section states that EOB and EOM + * can be combined with the NONE error (as well as others). So + * drop thru to catch this... + */ + case EVE_NONE: + if (err == ERR_SHT) + ch->s.rx_length_errors++; + break; + default: + if (cxt1e1_log_level >= LOG_WARN) + pr_info("%s: unexpected interrupt event: %d, iqd[%d]: %08x, port: %d\n", ci->devname, + event, headx, currInt, group); + break; + } /* switch on event */ + + + /* + * Per MUSYCC Manual, Section 6.4.8.3 [Transmit Errors], TX errors + * are service-affecting and require action to resume normal + * bit-level processing. + */ + + switch (err) { + case ERR_ONR: + /* + * Per MUSYCC manual, Section 6.4.8.3 [Transmit Errors], this + * error requires Transmit channel reactivation. + * + * Per MUSYCC manual, Section 6.4.8.4 [Receive Errors], this error + * requires Receive channel reactivation. + */ + if (tx) { + + /* + * TX ONR Error only occurs when channel is configured for + * Transparent Mode. However, this code will catch and + * re-activate on ANY TX ONR error. + */ + + /* + * Set flag to re-enable on any next transmit attempt. + */ + ch->ch_start_tx = CH_START_TX_ONR; + +#ifdef RLD_TRANS_DEBUG + if (1 || cxt1e1_log_level >= LOG_MONITOR) +#else + if (cxt1e1_log_level >= LOG_MONITOR) +#endif + { + pr_info("%s: TX buffer underflow [ONR] on channel %d, mode %x QStopped %x free %d\n", + ci->devname, ch->channum, + ch->p.chan_mode, + sd_queue_stopped(ch->user), + ch->txd_free); +#ifdef RLD_DEBUG + /* problem = ONR on HDLC mode */ + if (ch->p.chan_mode == 2) { + pr_info("++ Failed Last %x Next %x QStopped %x, start_tx %x tx_full %d txd_free %d mode %x\n", + (u_int32_t)ch->txd_irq_srv, + (u_int32_t)ch->txd_usr_add, + sd_queue_stopped(ch->user), + ch->ch_start_tx, + ch->tx_full, + ch->txd_free, + ch->p.chan_mode); + musycc_dump_txbuffer_ring(ch, 0); + } +#endif + } + } else { /* RX buffer overrun */ + /* + * Per MUSYCC manual, Section 6.4.8.4 [Receive Errors], + * channel recovery for this RX ONR error IS required. It is + * also suggested to increase the number of receive buffers + * for this channel. Receive channel reactivation IS + * required, and data has been lost. + */ + ch->s.rx_over_errors++; + ch->ch_start_rx = CH_START_RX_ONR; + + if (cxt1e1_log_level >= LOG_WARN) { + pr_info("%s: RX buffer overflow [ONR] on channel %d, mode %x\n", + ci->devname, ch->channum, + ch->p.chan_mode); +#ifdef RLD_DEBUG + musycc_dump_rxbuffer_ring(ch, 0); +#endif + } + } + musycc_chan_restart(ch); + break; + case ERR_BUF: + if (tx) { + ch->s.tx_fifo_errors++; + ch->ch_start_tx = CH_START_TX_BUF; + /* + * Per MUSYCC manual, Section 6.4.8.3 [Transmit Errors], + * this BUFF error requires Transmit channel reactivation. + */ + if (cxt1e1_log_level >= LOG_MONITOR) + pr_info("%s: TX buffer underrun [BUFF] on channel %d, mode %x\n", + ci->devname, ch->channum, + ch->p.chan_mode); + } else { /* RX buffer overrun */ + ch->s.rx_over_errors++; + /* + * Per MUSYCC manual, Section 6.4.8.4 [Receive Errors], HDLC + * mode requires NO recovery for this RX BUFF error is + * required. It is suggested to increase the FIFO buffer + * space for this channel. Receive channel reactivation is + * not required, but data has been lost. + */ + if (cxt1e1_log_level >= LOG_WARN) + pr_info("%s: RX buffer overrun [BUFF] on channel %d, mode %x\n", + ci->devname, ch->channum, + ch->p.chan_mode); + /* + * Per MUSYCC manual, Section 6.4.9.4 [Receive Errors], + * Transparent mode DOES require recovery for the RX BUFF + * error. It is suggested to increase the FIFO buffer space + * for this channel. Receive channel reactivation IS + * required and data has been lost. + */ + if (ch->p.chan_mode == CFG_CH_PROTO_TRANS) + ch->ch_start_rx = CH_START_RX_BUF; + } + + if (tx || (ch->p.chan_mode == CFG_CH_PROTO_TRANS)) + musycc_chan_restart(ch); + break; + default: + break; + } /* switch on err */ + + /* Check for interrupt lost condition */ + if ((currInt & INTRPT_ILOST_M) && + (cxt1e1_log_level >= LOG_ERROR)) + pr_info("%s: Interrupt queue overflow - ILOST asserted\n", + ci->devname); + /* insure wrapness */ + ci->iqp_headx = (headx + 1) & (INT_QUEUE_SIZE - 1); + FLUSH_MEM_WRITE(); + FLUSH_MEM_READ(); + } /* while */ + if ((cxt1e1_log_level >= LOG_MONITOR2) && + (ci->iqp_headx != ci->iqp_tailx)) { + int bh; + + bh = atomic_read(&CI->bh_pending); + pr_info("_bh_: late arrivals, head %d != tail %d, pending %d\n", + ci->iqp_headx, ci->iqp_tailx, bh); + } +#if defined(SBE_ISR_IMMEDIATE) + return 0L; +#endif + /* else, nothing returned */ +} + +#ifdef SBE_PMCC4_ENABLE + status_t +musycc_chan_down(ci_t *dummy, int channum) +{ + mpi_t *pi; + mch_t *ch; + int i, gchan; + + ch = sd_find_chan(dummy, channum); + if (!ch) + return -EINVAL; + pi = ch->up; + gchan = ch->gchan; + + /* Deactivate the channel */ + musycc_serv_req(pi, SR_CHANNEL_DEACTIVATE | SR_RX_DIRECTION | gchan); + ch->ch_start_rx = 0; + musycc_serv_req(pi, SR_CHANNEL_DEACTIVATE | SR_TX_DIRECTION | gchan); + ch->ch_start_tx = 0; + + if (ch->state == DOWN) + return 0; + ch->state = DOWN; + + pi->regram->thp[gchan] = 0; + pi->regram->tmp[gchan] = 0; + pi->regram->rhp[gchan] = 0; + pi->regram->rmp[gchan] = 0; + FLUSH_MEM_WRITE(); + for (i = 0; i < ch->txd_num; i++) + if (ch->mdt[i].mem_token) + OS_mem_token_free(ch->mdt[i].mem_token); + + for (i = 0; i < ch->rxd_num; i++) + if (ch->mdr[i].mem_token) + OS_mem_token_free(ch->mdr[i].mem_token); + + kfree(ch->mdr); + ch->mdr = NULL; + ch->rxd_num = 0; + kfree(ch->mdt); + ch->mdt = NULL; + ch->txd_num = 0; + + musycc_update_timeslots(pi); + c4_fifo_free(pi, ch->gchan); + + pi->openchans--; + return 0; +} +#endif + +int +musycc_start_xmit(ci_t *ci, int channum, void *mem_token) +{ + mch_t *ch; + struct mdesc *md; + void *m2; + int txd_need_cnt; + u_int32_t len; + + ch = sd_find_chan(ci, channum); + if (!ch) + return -ENOENT; + + /* full interrupt processing available */ + if (ci->state != C_RUNNING) + return -EINVAL; + if (ch->state != UP) + return -EINVAL; + + /* how else to flag unwritable state ? */ + if (!(ch->status & TX_ENABLED)) + return -EROFS; + +#ifdef RLD_TRANS_DEBUG + if (1 || cxt1e1_log_level >= LOG_MONITOR2) +#else + if (cxt1e1_log_level >= LOG_MONITOR2) +#endif + { + pr_info("++ start_xmt[%d]: state %x start %x full %d free %d required %d stopped %x\n", + channum, ch->state, ch->ch_start_tx, ch->tx_full, + ch->txd_free, ch->txd_required, + sd_queue_stopped(ch->user)); + } + /***********************************************/ + /** Determine total amount of data to be sent **/ + /***********************************************/ + m2 = mem_token; + txd_need_cnt = 0; + for (len = OS_mem_token_tlen(m2); len > 0; + m2 = (void *) OS_mem_token_next(m2)) { + if (!OS_mem_token_len(m2)) + continue; + txd_need_cnt++; + len -= OS_mem_token_len(m2); + } + + if (txd_need_cnt == 0) { + if (cxt1e1_log_level >= LOG_MONITOR2) + pr_info("%s channel %d: no TX data in User buffer\n", + ci->devname, channum); + OS_mem_token_free(mem_token); + return 0; /* no data to send */ + } + /*************************************************/ + /** Are there sufficient descriptors available? **/ + /*************************************************/ + if (txd_need_cnt > ch->txd_num) { /* never enough descriptors for this + * large a buffer */ + if (cxt1e1_log_level >= LOG_DEBUG) + pr_info("start_xmit: discarding buffer, insufficient descriptor cnt %d, need %d.\n", + ch->txd_num, txd_need_cnt + 1); + ch->s.tx_dropped++; + OS_mem_token_free(mem_token); + return 0; + } + + /************************************************************/ + /** flow control the line if not enough descriptors remain **/ + /************************************************************/ + if (txd_need_cnt > ch->txd_free) { + if (cxt1e1_log_level >= LOG_MONITOR2) + pr_info("start_xmit[%d]: EBUSY - need more descriptors, have %d of %d need %d\n", + channum, ch->txd_free, + ch->txd_num, txd_need_cnt); + ch->tx_full = 1; + ch->txd_required = txd_need_cnt; + sd_disable_xmit(ch->user); + return -EBUSY; /* tell user to try again later */ + } + /**************************************************/ + /** Put the user data into MUSYCC data buffer(s) **/ + /**************************************************/ + m2 = mem_token; + md = ch->txd_usr_add; /* get current available descriptor */ + + for (len = OS_mem_token_tlen(m2); len > 0; m2 = OS_mem_token_next(m2)) { + int u = OS_mem_token_len(m2); + + if (!u) + continue; + len -= u; + + /* + * Enable following chunks, yet wait to enable the FIRST chunk until + * after ALL subsequent chunks are setup. + */ + if (md != ch->txd_usr_add) /* not first chunk */ + /* transfer ownership from HOST to MUSYCC */ + u |= MUSYCC_TX_OWNED; + + if (len) /* not last chunk */ + u |= EOBIRQ_ENABLE; + else if (ch->p.chan_mode == CFG_CH_PROTO_TRANS) { + /* + * Per MUSYCC Ref 6.4.9 for Transparent Mode, the host must + * always clear EOMIRQ_ENABLE in every Transmit Buffer Descriptor + * (IE. don't set herein). + */ + u |= EOBIRQ_ENABLE; + } else + u |= EOMIRQ_ENABLE; /* EOM, last HDLC chunk */ + + + /* last chunk in hdlc mode */ + u |= (ch->p.idlecode << IDLE_CODE); + if (ch->p.pad_fill_count) { + u |= (PADFILL_ENABLE | (ch->p.pad_fill_count << EXTRA_FLAGS)); + } + /* Fill in mds on last segment, others set ZERO + * so that entire token is removed ONLY when ALL + * segments have been transmitted. + */ + md->mem_token = len ? NULL : mem_token; + + md->data = cpu_to_le32(OS_vtophys(OS_mem_token_data(m2))); + FLUSH_MEM_WRITE(); + md->status = cpu_to_le32(u); + --ch->txd_free; + md = md->snext; + } + FLUSH_MEM_WRITE(); + + + /* + * Now transfer ownership of first chunk from HOST to MUSYCC in order to + * fire-off this XMIT. + */ + ch->txd_usr_add->status |= __constant_cpu_to_le32(MUSYCC_TX_OWNED); + FLUSH_MEM_WRITE(); + ch->txd_usr_add = md; + + len = OS_mem_token_tlen(mem_token); + atomic_add(len, &ch->tx_pending); + atomic_add(len, &ci->tx_pending); + ch->s.tx_packets++; + ch->s.tx_bytes += len; + /* + * If an ONR was seen, then channel requires poking to restart + * transmission. + */ + if (ch->ch_start_tx) + musycc_chan_restart(ch); +#ifdef SBE_WAN256T3_ENABLE + wan256t3_led(ci, LED_TX, LEDV_G); +#endif + return 0; +} + + +/*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/musycc.h b/drivers/staging/cxt1e1/musycc.h new file mode 100644 index 00000000000..56fb42f0f64 --- /dev/null +++ b/drivers/staging/cxt1e1/musycc.h @@ -0,0 +1,427 @@ +#ifndef _INC_MUSYCC_H_ +#define _INC_MUSYCC_H_ + +/*----------------------------------------------------------------------------- + * musycc.h - Multichannel Synchronous Communications Controller + * CN8778/8474A/8472A/8471A + * + * Copyright (C) 2002-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + *----------------------------------------------------------------------------- + */ + +#include <linux/types.h> + +#define VINT8 volatile u_int8_t +#define VINT32 volatile u_int32_t + +#include "pmcc4_defs.h" + + +/*------------------------------------------------------------------------ +// Vendor, Board Identification definitions +//------------------------------------------------------------------------ +*/ + +#define PCI_VENDOR_ID_CONEXANT 0x14f1 +#define PCI_DEVICE_ID_CN8471 0x8471 +#define PCI_DEVICE_ID_CN8472 0x8472 +#define PCI_DEVICE_ID_CN8474 0x8474 +#define PCI_DEVICE_ID_CN8478 0x8478 +#define PCI_DEVICE_ID_CN8500 0x8500 +#define PCI_DEVICE_ID_CN8501 0x8501 +#define PCI_DEVICE_ID_CN8502 0x8502 +#define PCI_DEVICE_ID_CN8503 0x8503 + +#define INT_QUEUE_SIZE MUSYCC_NIQD + +/* RAM image of MUSYCC registers laid out as a C structure */ +struct musycc_groupr { + VINT32 thp[32]; /* Transmit Head Pointer [5-29] */ + VINT32 tmp[32]; /* Transmit Message Pointer [5-30] */ + VINT32 rhp[32]; /* Receive Head Pointer [5-29] */ + VINT32 rmp[32]; /* Receive Message Pointer [5-30] */ + VINT8 ttsm[128]; /* Time Slot Map [5-22] */ + VINT8 tscm[256]; /* Subchannel Map [5-24] */ + VINT32 tcct[32]; /* Channel Configuration [5-26] */ + VINT8 rtsm[128]; /* Time Slot Map [5-22] */ + VINT8 rscm[256]; /* Subchannel Map [5-24] */ + VINT32 rcct[32]; /* Channel Configuration [5-26] */ + VINT32 __glcd; /* Global Configuration Descriptor [5-10] */ + VINT32 __iqp; /* Interrupt Queue Pointer [5-36] */ + VINT32 __iql; /* Interrupt Queue Length [5-36] */ + VINT32 grcd; /* Group Configuration Descriptor [5-16] */ + VINT32 mpd; /* Memory Protection Descriptor [5-18] */ + VINT32 mld; /* Message Length Descriptor [5-20] */ + VINT32 pcd; /* Port Configuration Descriptor [5-19] */ +}; + +/* hardware MUSYCC registers laid out as a C structure */ +struct musycc_globalr { + VINT32 gbp; /* Group Base Pointer */ + VINT32 dacbp; /* Dual Address Cycle Base Pointer */ + VINT32 srd; /* Service Request Descriptor */ + VINT32 isd; /* Interrupt Service Descriptor */ + /* + * adjust __thp due to above 4 registers, which are not contained + * within musycc_groupr[]. All __XXX[] are just place holders, + * anyhow. + */ + VINT32 __thp[32 - 4]; /* Transmit Head Pointer [5-29] */ + VINT32 __tmp[32]; /* Transmit Message Pointer [5-30] */ + VINT32 __rhp[32]; /* Receive Head Pointer [5-29] */ + VINT32 __rmp[32]; /* Receive Message Pointer [5-30] */ + VINT8 ttsm[128]; /* Time Slot Map [5-22] */ + VINT8 tscm[256]; /* Subchannel Map [5-24] */ + VINT32 tcct[32]; /* Channel Configuration [5-26] */ + VINT8 rtsm[128]; /* Time Slot Map [5-22] */ + VINT8 rscm[256]; /* Subchannel Map [5-24] */ + VINT32 rcct[32]; /* Channel Configuration [5-26] */ + VINT32 glcd; /* Global Configuration Descriptor [5-10] */ + VINT32 iqp; /* Interrupt Queue Pointer [5-36] */ + VINT32 iql; /* Interrupt Queue Length [5-36] */ + VINT32 grcd; /* Group Configuration Descriptor [5-16] */ + VINT32 mpd; /* Memory Protection Descriptor [5-18] */ + VINT32 mld; /* Message Length Descriptor [5-20] */ + VINT32 pcd; /* Port Configuration Descriptor [5-19] */ + VINT32 rbist; /* Receive BIST status [5-4] */ + VINT32 tbist; /* Receive BIST status [5-4] */ +}; + +/* Global Config Descriptor bit macros */ +#define MUSYCC_GCD_ECLK_ENABLE 0x00000800 /* EBUS clock enable */ +#define MUSYCC_GCD_INTEL_SELECT 0x00000400 /* MPU type select */ +#define MUSYCC_GCD_INTA_DISABLE 0x00000008 /* PCI INTA disable */ +#define MUSYCC_GCD_INTB_DISABLE 0x00000004 /* PCI INTB disable */ +#define MUSYCC_GCD_BLAPSE 12 /* Position index for BLAPSE bit + * field */ +#define MUSYCC_GCD_ALAPSE 8 /* Position index for ALAPSE bit + * field */ +#define MUSYCC_GCD_ELAPSE 4 /* Position index for ELAPSE bit + * field */ +#define MUSYCC_GCD_PORTMAP_3 3 /* Reserved */ +#define MUSYCC_GCD_PORTMAP_2 2 /* Port 0=>Grp 0,1,2,3; Port 1=>Grp + * 4,5,6,7 */ +#define MUSYCC_GCD_PORTMAP_1 1 /* Port 0=>Grp 0,1; Port 1=>Grp 2,3, + * etc... */ +#define MUSYCC_GCD_PORTMAP_0 0 /* Port 0=>Grp 0; Port 1=>Grp 2, + * etc... */ + +/* and board specific assignments... */ +#ifdef SBE_WAN256T3_ENABLE +#define BLAPSE_VAL 0 +#define ALAPSE_VAL 0 +#define ELAPSE_VAL 7 +#define PORTMAP_VAL MUSYCC_GCD_PORTMAP_2 +#endif + +#ifdef SBE_PMCC4_ENABLE +#define BLAPSE_VAL 7 +#define ALAPSE_VAL 3 +#define ELAPSE_VAL 7 +#define PORTMAP_VAL MUSYCC_GCD_PORTMAP_0 +#endif + +#define GCD_MAGIC (((BLAPSE_VAL)<<(MUSYCC_GCD_BLAPSE)) | \ + ((ALAPSE_VAL)<<(MUSYCC_GCD_ALAPSE)) | \ + ((ELAPSE_VAL)<<(MUSYCC_GCD_ELAPSE)) | \ + (MUSYCC_GCD_ECLK_ENABLE) | PORTMAP_VAL) + +/* Group Config Descriptor bit macros */ +#define MUSYCC_GRCD_RX_ENABLE 0x00000001 /* Enable receive processing */ +#define MUSYCC_GRCD_TX_ENABLE 0x00000002 /* Enable transmit processing */ +#define MUSYCC_GRCD_SUBCHAN_DISABLE 0x00000004 /* Master disable for + * subchanneling */ +#define MUSYCC_GRCD_OOFMP_DISABLE 0x00000008 /* Out of Frame message + * processing disabled all + * channels */ +#define MUSYCC_GRCD_OOFIRQ_DISABLE 0x00000010 /* Out of Frame/In Frame irqs + * disabled */ +#define MUSYCC_GRCD_COFAIRQ_DISABLE 0x00000020 /* Change of Frame Alignment + * irq disabled */ +#define MUSYCC_GRCD_INHRBSD 0x00000100 /* Receive Buffer Status + * overwrite disabled */ +#define MUSYCC_GRCD_INHTBSD 0x00000200 /* Transmit Buffer Status + * overwrite disabled */ +#define MUSYCC_GRCD_SF_ALIGN 0x00008000 /* External frame sync */ +#define MUSYCC_GRCD_MC_ENABLE 0x00000040 /* Message configuration bits + * copy enable. Conexant sez + * turn this on */ +#define MUSYCC_GRCD_POLLTH_16 0x00000001 /* Poll every 16th frame */ +#define MUSYCC_GRCD_POLLTH_32 0x00000002 /* Poll every 32nd frame */ +#define MUSYCC_GRCD_POLLTH_64 0x00000003 /* Poll every 64th frame */ +#define MUSYCC_GRCD_POLLTH_SHIFT 10 /* Position index for poll throttle + * bit field */ +#define MUSYCC_GRCD_SUERM_THRESH_SHIFT 16 /* Position index for SUERM + * count threshold */ + +/* Port Config Descriptor bit macros */ +#define MUSYCC_PCD_E1X2_MODE 2 /* Port mode in bits 0-2. T1 and E1 */ +#define MUSYCC_PCD_E1X4_MODE 3 /* are defined in cn847x.h */ +#define MUSYCC_PCD_NX64_MODE 4 +#define MUSYCC_PCD_TXDATA_RISING 0x00000010 /* Sample Tx data on TCLK + * rising edge */ +#define MUSYCC_PCD_TXSYNC_RISING 0x00000020 /* Sample Tx frame sync on + * TCLK rising edge */ +#define MUSYCC_PCD_RXDATA_RISING 0x00000040 /* Sample Rx data on RCLK + * rising edge */ +#define MUSYCC_PCD_RXSYNC_RISING 0x00000080 /* Sample Rx frame sync on + * RCLK rising edge */ +#define MUSYCC_PCD_ROOF_RISING 0x00000100 /* Sample Rx Out Of Frame + * signal on RCLK rising edge */ +#define MUSYCC_PCD_TX_DRIVEN 0x00000200 /* No mapped timeslots causes + * logic 1 on output, else + * tristate */ +#define MUSYCC_PCD_PORTMODE_MASK 0xfffffff8 /* For changing the port mode + * between E1 and T1 */ + +/* Time Slot Descriptor bit macros */ +#define MUSYCC_TSD_MODE_64KBPS 4 +#define MUSYCC_TSD_MODE_56KBPS 5 +#define MUSYCC_TSD_SUBCHANNEL_WO_FIRST 6 +#define MUSYCC_TSD_SUBCHANNEL_WITH_FIRST 7 + +/* Message Descriptor bit macros */ +#define MUSYCC_MDT_BASE03_ADDR 0x00006000 + +/* Channel Config Descriptor bit macros */ +#define MUSYCC_CCD_BUFIRQ_DISABLE 0x00000002 /* BUFF and ONR irqs disabled */ +#define MUSYCC_CCD_EOMIRQ_DISABLE 0x00000004 /* EOM irq disabled */ +#define MUSYCC_CCD_MSGIRQ_DISABLE 0x00000008 /* LNG, FCS, ALIGN, and ABT + * irqs disabled */ +#define MUSYCC_CCD_IDLEIRQ_DISABLE 0x00000010 /* CHABT, CHIC, and SHT irqs + * disabled */ +#define MUSYCC_CCD_FILTIRQ_DISABLE 0x00000020 /* SFILT irq disabled */ +#define MUSYCC_CCD_SDECIRQ_DISABLE 0x00000040 /* SDEC irq disabled */ +#define MUSYCC_CCD_SINCIRQ_DISABLE 0x00000080 /* SINC irq disabled */ +#define MUSYCC_CCD_SUERIRQ_DISABLE 0x00000100 /* SUERR irq disabled */ +#define MUSYCC_CCD_FCS_XFER 0x00000200 /* Propagate FCS along with + * received data */ +#define MUSYCC_CCD_PROTO_SHIFT 12 /* Position index for protocol bit + * field */ +#define MUSYCC_CCD_TRANS 0 /* Protocol mode in bits 12-14 */ +#define MUSYCC_CCD_SS7 1 +#define MUSYCC_CCD_HDLC_FCS16 2 +#define MUSYCC_CCD_HDLC_FCS32 3 +#define MUSYCC_CCD_EOPIRQ_DISABLE 0x00008000 /* EOP irq disabled */ +#define MUSYCC_CCD_INVERT_DATA 0x00800000 /* Invert data */ +#define MUSYCC_CCD_MAX_LENGTH 10 /* Position index for max length bit + * field */ +#define MUSYCC_CCD_BUFFER_LENGTH 16 /* Position index for internal data + * buffer length */ +#define MUSYCC_CCD_BUFFER_LOC 24 /* Position index for internal data + * buffer starting location */ + +/**************************************************************************** + * Interrupt Descriptor Information */ + +#define INT_EMPTY_ENTRY 0xfeedface +#define INT_EMPTY_ENTRY2 0xdeadface + +/**************************************************************************** + * Interrupt Status Descriptor + * + * NOTE: One must first fetch the value of the interrupt status descriptor + * into a local variable, then pass that value into the read macros. This + * is required to avoid race conditions. + ***/ + +#define INTRPTS_NEXTINT_M 0x7FFF0000 +#define INTRPTS_NEXTINT_S 16 +#define INTRPTS_NEXTINT(x) ((x & INTRPTS_NEXTINT_M) >> INTRPTS_NEXTINT_S) + +#define INTRPTS_INTFULL_M 0x00008000 +#define INTRPTS_INTFULL_S 15 +#define INTRPTS_INTFULL(x) ((x & INTRPTS_INTFULL_M) >> INTRPTS_INTFULL_S) + +#define INTRPTS_INTCNT_M 0x00007FFF +#define INTRPTS_INTCNT_S 0 +#define INTRPTS_INTCNT(x) ((x & INTRPTS_INTCNT_M) >> INTRPTS_INTCNT_S) + + +/**************************************************************************** + * Interrupt Descriptor + ***/ + +#define INTRPT_DIR_M 0x80000000 +#define INTRPT_DIR_S 31 +#define INTRPT_DIR(x) ((x & INTRPT_DIR_M) >> INTRPT_DIR_S) + +#define INTRPT_GRP_M 0x60000000 +#define INTRPT_GRP_MSB_M 0x00004000 +#define INTRPT_GRP_S 29 +#define INTRPT_GRP_MSB_S 12 +#define INTRPT_GRP(x) (((x & INTRPT_GRP_M) >> INTRPT_GRP_S) | \ + ((x & INTRPT_GRP_MSB_M) >> INTRPT_GRP_MSB_S)) + +#define INTRPT_CH_M 0x1F000000 +#define INTRPT_CH_S 24 +#define INTRPT_CH(x) ((x & INTRPT_CH_M) >> INTRPT_CH_S) + +#define INTRPT_EVENT_M 0x00F00000 +#define INTRPT_EVENT_S 20 +#define INTRPT_EVENT(x) ((x & INTRPT_EVENT_M) >> INTRPT_EVENT_S) + +#define INTRPT_ERROR_M 0x000F0000 +#define INTRPT_ERROR_S 16 +#define INTRPT_ERROR(x) ((x & INTRPT_ERROR_M) >> INTRPT_ERROR_S) + +#define INTRPT_ILOST_M 0x00008000 +#define INTRPT_ILOST_S 15 +#define INTRPT_ILOST(x) ((x & INTRPT_ILOST_M) >> INTRPT_ILOST_S) + +#define INTRPT_PERR_M 0x00004000 +#define INTRPT_PERR_S 14 +#define INTRPT_PERR(x) ((x & INTRPT_PERR_M) >> INTRPT_PERR_S) + +#define INTRPT_BLEN_M 0x00003FFF +#define INTRPT_BLEN_S 0 +#define INTRPT_BLEN(x) ((x & INTRPT_BLEN_M) >> INTRPT_BLEN_S) + + +/* Buffer Descriptor bit macros */ +#define OWNER_BIT 0x80000000 /* Set for MUSYCC owner on xmit, host + * owner on receive */ +#define HOST_TX_OWNED 0x00000000 /* Host owns descriptor */ +#define MUSYCC_TX_OWNED 0x80000000 /* MUSYCC owns descriptor */ +#define HOST_RX_OWNED 0x80000000 /* Host owns descriptor */ +#define MUSYCC_RX_OWNED 0x00000000 /* MUSYCC owns descriptor */ + +#define POLL_DISABLED 0x40000000 /* MUSYCC not allowed to poll buffer + * for ownership */ +#define EOMIRQ_ENABLE 0x20000000 /* This buffer contains the end of + * the message */ +#define EOBIRQ_ENABLE 0x10000000 /* EOB irq enabled */ +#define PADFILL_ENABLE 0x01000000 /* Enable padfill */ +#define REPEAT_BIT 0x00008000 /* Bit on for FISU descriptor */ +#define LENGTH_MASK 0X3fff /* This part of status descriptor is + * length */ +#define IDLE_CODE 25 /* Position index for idle code (2 + * bits) */ +#define EXTRA_FLAGS 16 /* Position index for minimum flags + * between messages (8 bits) */ +#define IDLE_CODE_MASK 0x03 /* Gets rid of garbage before the + * pattern is OR'd in */ +#define EXTRA_FLAGS_MASK 0xff /* Gets rid of garbage before the + * pattern is OR'd in */ +#define PCI_PERMUTED_OWNER_BIT 0x00000080 /* For flipping the bit on + * the polled mode descriptor */ + +/* Service Request Descriptor bit macros */ +#define SREQ 8 /* Position index for service request bit + * field */ +#define SR_NOOP (0<<(SREQ)) /* No Operation. Generates SACK */ +#define SR_CHIP_RESET (1<<(SREQ)) /* Soft chip reset */ +#define SR_GROUP_RESET (2<<(SREQ)) /* Group reset */ +#define SR_GLOBAL_INIT (4<<(SREQ)) /* Global init: read global + * config deswc and interrupt + * queue desc */ +#define SR_GROUP_INIT (5<<(SREQ)) /* Group init: read Timeslot + * and Subchannel maps, + * Channel Config, */ + /* + * Group Config, Memory Protect, Message Length, and Port Config + * Descriptors + */ +#define SR_CHANNEL_ACTIVATE (8<<(SREQ)) /* Init channel, read Head + * Pointer, process first + * Message Descriptor */ +#define SR_GCHANNEL_MASK 0x001F /* channel portion (gchan) */ +#define SR_CHANNEL_DEACTIVATE (9<<(SREQ)) /* Stop channel processing */ +#define SR_JUMP (10<<(SREQ)) /* a: Process new Message + * List */ +#define SR_CHANNEL_CONFIG (11<<(SREQ)) /* b: Read channel + * Configuration Descriptor */ +#define SR_GLOBAL_CONFIG (16<<(SREQ)) /* 10: Read Global + * Configuration Descriptor */ +#define SR_INTERRUPT_Q (17<<(SREQ)) /* 11: Read Interrupt Queue + * Descriptor */ +#define SR_GROUP_CONFIG (18<<(SREQ)) /* 12: Read Group + * Configuration Descriptor */ +#define SR_MEMORY_PROTECT (19<<(SREQ)) /* 13: Read Memory Protection + * Descriptor */ +#define SR_MESSAGE_LENGTH (20<<(SREQ)) /* 14: Read Message Length + * Descriptor */ +#define SR_PORT_CONFIG (21<<(SREQ)) /* 15: Read Port + * Configuration Descriptor */ +#define SR_TIMESLOT_MAP (24<<(SREQ)) /* 18: Read Timeslot Map */ +#define SR_SUBCHANNEL_MAP (25<<(SREQ)) /* 19: Read Subchannel Map */ +#define SR_CHAN_CONFIG_TABLE (26<<(SREQ)) /* 20: Read Channel + * Configuration Table for + * the group */ +#define SR_TX_DIRECTION 0x00000020 /* Transmit direction bit. + * Bit off indicates receive + * direction */ +#define SR_RX_DIRECTION 0x00000000 + +/* Interrupt Descriptor bit macros */ +#define GROUP10 29 /* Position index for the 2 LS group + * bits */ +#define CHANNEL 24 /* Position index for channel bits */ +#define INT_IQD_TX 0x80000000 +#define INT_IQD_GRP 0x60000000 +#define INT_IQD_CHAN 0x1f000000 +#define INT_IQD_EVENT 0x00f00000 +#define INT_IQD_ERROR 0x000f0000 +#define INT_IQD_ILOST 0x00008000 +#define INT_IQD_PERR 0x00004000 +#define INT_IQD_BLEN 0x00003fff + +/* Interrupt Descriptor Events */ +#define EVE_EVENT 20 /* Position index for event bits */ +#define EVE_NONE 0 /* No event to report in this + * interrupt */ +#define EVE_SACK 1 /* Service Request acknowledge */ +#define EVE_EOB 2 /* End of Buffer */ +#define EVE_EOM 3 /* End of Message */ +#define EVE_EOP 4 /* End of Padfill */ +#define EVE_CHABT 5 /* Change to Abort Code */ +#define EVE_CHIC 6 /* Change to Idle Code */ +#define EVE_FREC 7 /* Frame Recovery */ +#define EVE_SINC 8 /* MTP2 SUERM Increment */ +#define EVE_SDEC 9 /* MTP2 SUERM Decrement */ +#define EVE_SFILT 10 /* MTP2 SUERM Filtered Message */ +/* Interrupt Descriptor Errors */ +#define ERR_ERRORS 16 /* Position index for error bits */ +#define ERR_BUF 1 /* Buffer Error */ +#define ERR_COFA 2 /* Change of Frame Alignment Error */ +#define ERR_ONR 3 /* Owner Bit Error */ +#define ERR_PROT 4 /* Memory Protection Error */ +#define ERR_OOF 8 /* Out of Frame Error */ +#define ERR_FCS 9 /* FCS Error */ +#define ERR_ALIGN 10 /* Octet Alignment Error */ +#define ERR_ABT 11 /* Abort Termination */ +#define ERR_LNG 12 /* Long Message Error */ +#define ERR_SHT 13 /* Short Message Error */ +#define ERR_SUERR 14 /* SUERM threshold exceeded */ +#define ERR_PERR 15 /* PCI Parity Error */ +/* Other Stuff */ +#define TRANSMIT_DIRECTION 0x80000000 /* Transmit direction bit. Bit off + * indicates receive direction */ +#define ILOST 0x00008000 /* Interrupt Lost */ +#define GROUPMSB 0x00004000 /* Group number MSB */ +#define SACK_IMAGE 0x00100000 /* Used in IRQ for semaphore test */ +#define INITIAL_STATUS 0x10000 /* IRQ status should be this after + * reset */ + +/* This must be defined on an entire channel group (Port) basis */ +#define SUERM_THRESHOLD 0x1f + +#undef VINT32 +#undef VINT8 + +#endif /*** _INC_MUSYCC_H_ ***/ + +/*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/pmc93x6_eeprom.c b/drivers/staging/cxt1e1/pmc93x6_eeprom.c new file mode 100644 index 00000000000..ba588f1b211 --- /dev/null +++ b/drivers/staging/cxt1e1/pmc93x6_eeprom.c @@ -0,0 +1,532 @@ +/* pmc93x6_eeprom.c - PMC's 93LC46 EEPROM Device + * + * The 93LC46 is a low-power, serial Electrically Erasable and + * Programmable Read Only Memory organized as 128 8-bit bytes. + * + * Accesses to the 93LC46 are done in a bit serial stream, organized + * in a 3 wire format. Writes are internally timed by the device + * (the In data bit is pulled low until the write is complete and + * then is pulled high) and take about 6 milliseconds. + * + * Copyright (C) 2003-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/types.h> +#include "pmcc4_sysdep.h" +#include "sbecom_inline_linux.h" +#include "pmcc4.h" +#include "sbe_promformat.h" +#include "pmc93x6_eeprom.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/*------------------------------------------------------------------------ + * EEPROM address definitions + *------------------------------------------------------------------------ + * + * The offset in the definitions below allows the test to skip over + * areas of the EEPROM that other programs (such a VxWorks) are + * using. + */ + +#define EE_MFG (long)0 /* Index to manufacturing record */ +#define EE_FIRST 0x28 /* Index to start testing at */ +#define EE_LIMIT 128 /* Index to end testing at */ + +/* Bit Ordering for Instructions + * + * A0, A1, A2, A3, A4, A5, A6, OP0, OP1, SB (lsb, or 1st bit out) + * + */ + +#define EPROM_EWEN 0x0019 /* Erase/Write enable (reversed) */ +#define EPROM_EWDS 0x0001 /* Erase/Write disable (reversed) */ +#define EPROM_READ 0x0003 /* Read (reversed) */ +#define EPROM_WRITE 0x0005 /* Write (reversed) */ +#define EPROM_ERASE 0x0007 /* Erase (reversed) */ +#define EPROM_ERAL 0x0009 /* Erase All (reversed) */ +#define EPROM_WRAL 0x0011 /* Write All (reversed) */ + +#define EPROM_ADR_SZ 7 /* Number of bits in offset address */ +#define EPROM_OP_SZ 3 /* Number of bits in command */ +#define SIZE_ADDR_OP (EPROM_ADR_SZ + EPROM_OP_SZ) +#define LC46A_MAX_OPS 10 /* Number of bits in Instruction */ +#define NUM_OF_BITS 8 /* Number of bits in data */ + +/* EEPROM signal bits */ +#define EPROM_ACTIVE_OUT_BIT 0x0001 /* Out data bit */ +#define EPROM_ACTIVE_IN_BIT 0x0002 /* In data bit */ +#define ACTIVE_IN_BIT_SHIFT 0x0001 /* Shift In data bit to LSB */ +#define EPROM_ENCS 0x0004 /* Set EEPROM CS during operation */ + +/*------------------------------------------------------------------------ + * The ByteReverse table is used to reverses the 8 bits within a byte + *------------------------------------------------------------------------ + */ + +static unsigned char ByteReverse[256]; +static int ByteReverseBuilt = FALSE; + +/*------------------------------------------------------------------------ + * mfg_template - initial serial EEPROM data structure + *------------------------------------------------------------------------ + */ + +static u8 mfg_template[sizeof(FLD_TYPE2)] = { + PROM_FORMAT_TYPE2, /* type; */ + 0x00, 0x1A, /* length[2]; */ + 0x00, 0x00, 0x00, 0x00, /* Crc32[4]; */ + 0x11, 0x76, /* Id[2]; */ + 0x07, 0x05, /* SubId[2] E1; */ + 0x00, 0xA0, 0xD6, 0x00, 0x00, 0x00, /* Serial[6]; */ + 0x00, 0x00, 0x00, 0x00, /* CreateTime[4]; */ + 0x00, 0x00, 0x00, 0x00, /* HeatRunTime[4]; */ + 0x00, 0x00, 0x00, 0x00, /* HeatRunIterations[4]; */ + 0x00, 0x00, 0x00, 0x00, /* HeatRunErrors[4]; */ +}; + +/*------------------------------------------------------------------------ + * BuildByteReverse - build the 8-bit reverse table + *------------------------------------------------------------------------ + * + * The 'ByteReverse' table reverses the 8 bits within a byte + * (the MSB becomes the LSB etc.). + */ + +static void BuildByteReverse(void) +{ + /* Used to build by powers to 2 */ + long half; + int i; + + ByteReverse[0] = 0; + + for (half = 1; half < sizeof(ByteReverse); half <<= 1) + for (i = 0; i < half; i++) + ByteReverse[half + i] = + (char)(ByteReverse[i] | (0x80 / half)); + + ByteReverseBuilt = TRUE; +} + +/*------------------------------------------------------------------------ + * eeprom_delay - small delay for EEPROM timing + *------------------------------------------------------------------------ + */ + +static void eeprom_delay(void) +{ + int timeout; + + for (timeout = 20; timeout; --timeout) + OS_uwait_dummy(); +} + +/*------------------------------------------------------------------------ + * eeprom_put_byte - Send a byte to the EEPROM serially + *------------------------------------------------------------------------ + * + * Given the PCI address and the data, this routine serially sends + * the data to the EEPROM. + */ + +static void eeprom_put_byte(long addr, long data, int count) +{ + u_int32_t output; + + while (--count >= 0) { + /* Get next data bit */ + output = (data & EPROM_ACTIVE_OUT_BIT) ? 1 : 0; + /* Add Chip Select */ + output |= EPROM_ENCS; + data >>= 1; + + eeprom_delay(); + /* Output it */ + pci_write_32((u_int32_t *) addr, output); + } +} + +/*------------------------------------------------------------------------ + * eeprom_get_byte - Receive a byte from the EEPROM serially + *------------------------------------------------------------------------ + * + * Given the PCI address, this routine serially fetches the data + * from the EEPROM. + */ + +static u_int32_t eeprom_get_byte(long addr) +{ + u_int32_t input; + u_int32_t data; + int count; + +/* Start the Reading of DATA + * + * The first read is a dummy as the data is latched in the + * EPLD and read on the next read access to the EEPROM. + */ + + input = pci_read_32((u_int32_t *) addr); + + data = 0; + count = NUM_OF_BITS; + while (--count >= 0) { + eeprom_delay(); + input = pci_read_32((u_int32_t *) addr); + + /* Shift data over */ + data <<= 1; + data |= (input & EPROM_ACTIVE_IN_BIT) ? 1 : 0; + + } + + return data; +} + +/*------------------------------------------------------------------------ + * disable_pmc_eeprom - Disable writes to the EEPROM + *------------------------------------------------------------------------ + * + * Issue the EEPROM command to disable writes. + */ + +static void disable_pmc_eeprom(long addr) +{ + eeprom_put_byte(addr, EPROM_EWDS, SIZE_ADDR_OP); + + /* this removes Chip Select from EEPROM */ + pci_write_32((u_int32_t *) addr, 0); +} + +/*------------------------------------------------------------------------ + * enable_pmc_eeprom - Enable writes to the EEPROM + *------------------------------------------------------------------------ + * + * Issue the EEPROM command to enable writes. + */ + +static void enable_pmc_eeprom(long addr) +{ + eeprom_put_byte(addr, EPROM_EWEN, SIZE_ADDR_OP); + + /* this removes Chip Select from EEPROM */ + pci_write_32((u_int32_t *) addr, 0); +} + +/*------------------------------------------------------------------------ + * pmc_eeprom_read - EEPROM location read + *------------------------------------------------------------------------ + * + * Given a EEPROM PCI address and location offset, this routine returns + * the contents of the specified location to the calling routine. + */ + +static u_int32_t pmc_eeprom_read(long addr, long mem_offset) +{ + /* Data from chip */ + u_int32_t data; + + if (!ByteReverseBuilt) + BuildByteReverse(); + + /* Reverse address */ + mem_offset = ByteReverse[0x7F & mem_offset]; + + /* + * NOTE: The max offset address is 128 or half the reversal table. So + * the LSB is always zero and counts as a built in shift of one bit. + * So even though we need to shift 3 bits to make room for the command, + * we only need to shift twice more because of the built in shift. + */ + + /* Shift for command */ + mem_offset <<= 2; + /* Add command */ + mem_offset |= EPROM_READ; + + /* Output chip address */ + eeprom_put_byte(addr, mem_offset, SIZE_ADDR_OP); + + /* Read chip data */ + data = eeprom_get_byte(addr); + + /* Remove Chip Select from EEPROM */ + pci_write_32((u_int32_t *) addr, 0); + + return (data & 0x000000FF); +} + +/*------------------------------------------------------------------------ + * pmc_eeprom_write - EEPROM location write + *------------------------------------------------------------------------ + * + * Given a EEPROM PCI address, location offset and value, this + * routine writes the value to the specified location. + * + * Note: it is up to the caller to determine if the write + * operation succeeded. + */ + +static int pmc_eeprom_write(long addr, long mem_offset, u_int32_t data) +{ + u_int32_t temp; + int count; + + if (!ByteReverseBuilt) + BuildByteReverse(); + + /* Reverse address */ + mem_offset = ByteReverse[0x7F & mem_offset]; + + /* + * NOTE: The max offset address is 128 or half the reversal table. So + * the LSB is always zero and counts as a built in shift of one bit. + * So even though we need to shift 3 bits to make room for the command, + * we only need to shift twice more because of the built in shift. + */ + + /* Shift for command */ + mem_offset <<= 2; + /* Add command */ + mem_offset |= EPROM_WRITE; + + /* Output chip address */ + eeprom_put_byte(addr, mem_offset, SIZE_ADDR_OP); + + /* Reverse data */ + data = ByteReverse[0xFF & data]; + /* Output chip data */ + eeprom_put_byte(addr, data, NUM_OF_BITS); + + /* Remove Chip Select from EEPROM */ + pci_write_32((u_int32_t *) addr, 0); + +/* + * Must see Data In at a low state before completing this transaction. + * + * Afterwards, the data bit will return to a high state, ~6 ms, terminating + * the operation. + */ + /* Re-enable Chip Select */ + pci_write_32((u_int32_t *) addr, EPROM_ENCS); + /* discard first read */ + temp = pci_read_32((u_int32_t *) addr); + temp = pci_read_32((u_int32_t *) addr); + if (temp & EPROM_ACTIVE_IN_BIT) { + temp = pci_read_32((u_int32_t *) addr); + if (temp & EPROM_ACTIVE_IN_BIT) { + /* Remove Chip Select from EEPROM */ + pci_write_32((u_int32_t *) addr, 0); + return 1; + } + } + count = 1000; + while (count--) { + for (temp = 0; temp < 0x10; temp++) + OS_uwait_dummy(); + + if (pci_read_32((u_int32_t *) addr) & EPROM_ACTIVE_IN_BIT) + break; + } + + if (count == -1) + return 2; + + return 0; +} + +/*------------------------------------------------------------------------ + * pmcGetBuffValue - read the specified value from buffer + *------------------------------------------------------------------------ + */ + +static long pmcGetBuffValue(char *ptr, int size) +{ + long value = 0; + int index; + + for (index = 0; index < size; ++index) { + value <<= 8; + value |= ptr[index] & 0xFF; + } + + return value; +} + +/*------------------------------------------------------------------------ + * pmcSetBuffValue - save the specified value to buffer + *------------------------------------------------------------------------ + */ + +static void pmcSetBuffValue(char *ptr, long value, int size) +{ + int index = size; + + while (--index >= 0) { + ptr[index] = (char)(value & 0xFF); + value >>= 8; + } +} + +/*------------------------------------------------------------------------ + * pmc_eeprom_read_buffer - read EEPROM data into specified buffer + *------------------------------------------------------------------------ + */ + +void +pmc_eeprom_read_buffer(long addr, long mem_offset, char *dest_ptr, int size) +{ + while (--size >= 0) + *dest_ptr++ = (char)pmc_eeprom_read(addr, mem_offset++); +} + +/*------------------------------------------------------------------------ + * pmc_eeprom_write_buffer - write EEPROM data from specified buffer + *------------------------------------------------------------------------ + */ + +void +pmc_eeprom_write_buffer(long addr, long mem_offset, char *dest_ptr, int size) +{ + enable_pmc_eeprom(addr); + + while (--size >= 0) + pmc_eeprom_write(addr, mem_offset++, *dest_ptr++); + + disable_pmc_eeprom(addr); +} + +/*------------------------------------------------------------------------ + * pmcCalcCrc - calculate the CRC for the serial EEPROM structure + *------------------------------------------------------------------------ + */ + +static u_int32_t pmcCalcCrc_T01(void *bufp) +{ + FLD_TYPE2 *buf = bufp; + /* CRC of the structure */ + u_int32_t crc; + + /* Calc CRC for type and length fields */ + sbeCrc((u_int8_t *) &buf->type, + (u_int32_t) STRUCT_OFFSET(FLD_TYPE1, Crc32), + (u_int32_t) 0, (u_int32_t *) &crc); + +#ifdef EEPROM_TYPE_DEBUG + /* RLD DEBUG */ + pr_info("sbeCrc: crc 1 calculated as %08x\n", crc); +#endif + return ~crc; +} + +static u_int32_t pmcCalcCrc_T02(void *bufp) +{ + FLD_TYPE2 *buf = bufp; + /* CRC of the structure */ + u_int32_t crc; + + /* Calc CRC for type and length fields */ + sbeCrc((u_int8_t *) &buf->type, + (u_int32_t) STRUCT_OFFSET(FLD_TYPE2, Crc32), + (u_int32_t) 0, (u_int32_t *) &crc); + + /* Calc CRC for remaining fields */ + sbeCrc((u_int8_t *) &buf->Id[0], + (u_int32_t) (sizeof(FLD_TYPE2) - STRUCT_OFFSET(FLD_TYPE2, Id)), + (u_int32_t) crc, (u_int32_t *) &crc); + +#ifdef EEPROM_TYPE_DEBUG + /* RLD DEBUG */ + pr_info("sbeCrc: crc 2 calculated as %08x\n", crc); +#endif + return crc; +} + +/*------------------------------------------------------------------------ + * pmc_init_seeprom - initialize the serial EEPROM structure + *------------------------------------------------------------------------ + * + * At the front of the serial EEPROM there is a record that contains + * manufacturing information. If the info does not already exist, it + * is created. The only field modifiable by the operator is the + * serial number field. + */ + +void pmc_init_seeprom(u_int32_t addr, u_int32_t serialNum) +{ + /* Memory image of structure */ + PROMFORMAT buffer; + /* CRC of structure */ + u_int32_t crc; + time_t createTime; + + createTime = get_seconds(); + + /* use template data */ + memcpy(&buffer.fldType2, mfg_template, sizeof(buffer.fldType2)); + + /* Update serial number field in buffer */ + pmcSetBuffValue(&buffer.fldType2.Serial[3], serialNum, 3); + + /* Update create time field in buffer */ + pmcSetBuffValue(&buffer.fldType2.CreateTime[0], createTime, 4); + + /* Update CRC field in buffer */ + crc = pmcCalcCrc_T02(&buffer); + pmcSetBuffValue(&buffer.fldType2.Crc32[0], crc, 4); + +#ifdef DEBUG + for (i = 0; i < sizeof(FLD_TYPE2); ++i) + pr_info("[%02X] = %02X\n", i, buffer.bytes[i] & 0xFF); +#endif + + /* Write structure to serial EEPROM */ + pmc_eeprom_write_buffer(addr, EE_MFG, (char *)&buffer, + sizeof(FLD_TYPE2)); +} + +char pmc_verify_cksum(void *bufp) +{ + FLD_TYPE1 *buf1 = bufp; + FLD_TYPE2 *buf2 = bufp; + /* CRC read from EEPROM */ + u_int32_t crc1, crc2; + + /* Retrieve contents of CRC field */ + crc1 = pmcGetBuffValue(&buf1->Crc32[0], sizeof(buf1->Crc32)); +#ifdef EEPROM_TYPE_DEBUG + /* RLD DEBUG */ + pr_info("EEPROM: chksum 1 reads as %08x\n", crc1); +#endif + if ((buf1->type == PROM_FORMAT_TYPE1) && + (pmcCalcCrc_T01((void *)buf1) == crc1)) + return PROM_FORMAT_TYPE1; /* checksum type 1 verified */ + + crc2 = pmcGetBuffValue(&buf2->Crc32[0], sizeof(buf2->Crc32)); +#ifdef EEPROM_TYPE_DEBUG + /* RLD DEBUG */ + pr_info("EEPROM: chksum 2 reads as %08x\n", crc2); +#endif + if ((buf2->type == PROM_FORMAT_TYPE2) && + (pmcCalcCrc_T02((void *)buf2) == crc2)) + return PROM_FORMAT_TYPE2; /* checksum type 2 verified */ + + /* failed to validate */ + return PROM_FORMAT_Unk; +} diff --git a/drivers/staging/cxt1e1/pmc93x6_eeprom.h b/drivers/staging/cxt1e1/pmc93x6_eeprom.h new file mode 100644 index 00000000000..96c48cb8326 --- /dev/null +++ b/drivers/staging/cxt1e1/pmc93x6_eeprom.h @@ -0,0 +1,39 @@ +#ifndef _INC_PMC93X6_EEPROM_H_ +#define _INC_PMC93X6_EEPROM_H_ + +/*----------------------------------------------------------------------------- + * pmc93x6_eeprom.h - + * + * Copyright (C) 2002-2004 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + *----------------------------------------------------------------------------- + */ + +#include <linux/types.h> + +#ifdef __KERNEL__ + +#include "pmcc4_private.h" + +void pmc_eeprom_read_buffer (long, long, char *, int); +void pmc_eeprom_write_buffer (long, long, char *, int); +void pmc_init_seeprom (u_int32_t, u_int32_t); +char pmc_verify_cksum (void *); + +#endif /*** __KERNEL__ ***/ + +#endif + +/*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/pmcc4.h b/drivers/staging/cxt1e1/pmcc4.h new file mode 100644 index 00000000000..b4b5e5ad791 --- /dev/null +++ b/drivers/staging/cxt1e1/pmcc4.h @@ -0,0 +1,108 @@ +#ifndef _INC_PMCC4_H_ +#define _INC_PMCC4_H_ + +/*----------------------------------------------------------------------------- + * pmcc4.h - + * + * Copyright (C) 2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + *----------------------------------------------------------------------------- + */ + +#include <linux/types.h> + +typedef int status_t; + +#define SBE_DRVR_FAIL 0 +#define SBE_DRVR_SUCCESS 1 + +/********************/ +/* PMCC4 memory Map */ +/********************/ + +#define COMET_OFFSET(x) (0x80000+(x)*0x10000) +#define EEPROM_OFFSET 0xC0000 +#define CPLD_OFFSET 0xD0000 + + struct pmcc4_timeslot_param + { + u_int8_t card; /* the card number */ + u_int8_t port; /* the port number */ + u_int8_t _reserved1; + u_int8_t _reserved2; + + /* + * each byte in bitmask below represents one timeslot (bitmask[0] is + * for timeslot 0 and so on), each bit in the byte selects timeslot + * bits for this channel (0xff - whole timeslot, 0x7f - 56kbps mode) + */ + u_int8_t bitmask[32]; + }; + + struct c4_musycc_param + { + u_int8_t RWportnum; + u_int16_t offset; + u_int32_t value; + }; + +/*Alarm values */ +#define sbeE1RMAI 0x100 +#define sbeYelAlm 0x04 +#define sbeRedAlm 0x02 +#define sbeAISAlm 0x01 + +#define sbeE1errSMF 0x02 +#define sbeE1CRC 0x01 + +#ifdef __KERNEL__ + +/* + * Device Driver interface, routines are for internal use only. + */ + +#include "pmcc4_private.h" + +char *get_hdlc_name (hdlc_device *); + +/* + * external interface + */ + +void c4_cleanup (void); +status_t c4_chan_up (ci_t *, int channum); +status_t c4_del_chan_stats (int channum); +status_t c4_del_chan (int channum); +status_t c4_get_iidinfo (ci_t *ci, struct sbe_iid_info *iip); +int c4_is_chan_up (int channum); + +void *getuserbychan (int channum); +void pci_flush_write (ci_t *ci); +void sbecom_set_loglevel (int debuglevel); +char *sbeid_get_bdname (ci_t *ci); +void sbeid_set_bdtype (ci_t *ci); +void sbeid_set_hdwbid (ci_t *ci); +u_int32_t sbeCrc (u_int8_t *, u_int32_t, u_int32_t, u_int32_t *); + +void VMETRO_TRIGGER (ci_t *, int); /* Note: int = 0(default) + * thru 15 */ + +#if defined (SBE_ISR_TASKLET) +void musycc_intr_bh_tasklet (ci_t *); + +#endif + +#endif /*** __KERNEL __ ***/ +#endif /* _INC_PMCC4_H_ */ diff --git a/drivers/staging/cxt1e1/pmcc4_cpld.h b/drivers/staging/cxt1e1/pmcc4_cpld.h new file mode 100644 index 00000000000..a51209bc527 --- /dev/null +++ b/drivers/staging/cxt1e1/pmcc4_cpld.h @@ -0,0 +1,91 @@ +#ifndef _INC_PMCC4_CPLD_H_ +#define _INC_PMCC4_CPLD_H_ + +/*----------------------------------------------------------------------------- + * pmcc4_cpld.h - + * + * Copyright (C) 2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + *----------------------------------------------------------------------------- + */ + +#include <linux/types.h> + +/********************************/ +/* iSPLD control chip registers */ +/********************************/ + +#if 0 +#define CPLD_MCSR 0x0 +#define CPLD_MCLK 0x1 +#define CPLD_LEDS 0x2 +#define CPLD_INTR 0x3 +#endif + + struct c4_cpld + { + volatile u_int32_t mcsr;/* r/w: Master Clock Source Register */ + volatile u_int32_t mclk;/* r/w: Master Clock Register */ + volatile u_int32_t leds;/* r/w: LED Register */ + volatile u_int32_t intr;/* r: Interrupt Register */ + }; + + typedef struct c4_cpld c4cpld_t; + +/* mcsr note: sourcing COMET must be initialized to Master Mode */ +#define PMCC4_CPLD_MCSR_IND 0 /* ports used individual BP Clk as + * source, no slaves */ +#define PMCC4_CPLD_MCSR_CMT_1 1 /* COMET 1 BP Clk is source, 2,3,4 + * are Clk slaves */ +#define PMCC4_CPLD_MCSR_CMT_2 2 /* COMET 2 BP Clk is source, 1,3,4 + * are Clk slaves */ +#define PMCC4_CPLD_MCSR_CMT_3 3 /* COMET 3 BP Clk is source, 1,2,4 + * are Clk slaves */ +#define PMCC4_CPLD_MCSR_CMT_4 4 /* COMET 4 BP Clk is source, 1,2,3 + * are Clk slaves */ + +#define PMCC4_CPLD_MCLK_MASK 0x0f +#define PMCC4_CPLD_MCLK_P1 0x1 +#define PMCC4_CPLD_MCLK_P2 0x2 +#define PMCC4_CPLD_MCLK_P3 0x4 +#define PMCC4_CPLD_MCLK_P4 0x8 +#define PMCC4_CPLD_MCLK_T1 0x00 +#define PMCC4_CPLD_MCLK_P1_E1 0x01 +#define PMCC4_CPLD_MCLK_P2_E1 0x02 +#define PMCC4_CPLD_MCLK_P3_E1 0x04 +#define PMCC4_CPLD_MCLK_P4_E1 0x08 + +#define PMCC4_CPLD_LED_OFF 0 +#define PMCC4_CPLD_LED_ON 1 +#define PMCC4_CPLD_LED_GP0 0x01 /* port 0, green */ +#define PMCC4_CPLD_LED_YP0 0x02 /* port 0, yellow */ +#define PMCC4_CPLD_LED_GP1 0x04 /* port 1, green */ +#define PMCC4_CPLD_LED_YP1 0x08 /* port 1, yellow */ +#define PMCC4_CPLD_LED_GP2 0x10 /* port 2, green */ +#define PMCC4_CPLD_LED_YP2 0x20 /* port 2, yellow */ +#define PMCC4_CPLD_LED_GP3 0x40 /* port 3, green */ +#define PMCC4_CPLD_LED_YP3 0x80 /* port 3, yellow */ +#define PMCC4_CPLD_LED_GREEN (PMCC4_CPLD_LED_GP0 | PMCC4_CPLD_LED_GP1 | \ + PMCC4_CPLD_LED_GP2 | PMCC4_CPLD_LED_GP3 ) +#define PMCC4_CPLD_LED_YELLOW (PMCC4_CPLD_LED_YP0 | PMCC4_CPLD_LED_YP1 | \ + PMCC4_CPLD_LED_YP2 | PMCC4_CPLD_LED_YP3) + +#define PMCC4_CPLD_INTR_MASK 0x0f +#define PMCC4_CPLD_INTR_CMT_1 0x01 +#define PMCC4_CPLD_INTR_CMT_2 0x02 +#define PMCC4_CPLD_INTR_CMT_3 0x04 +#define PMCC4_CPLD_INTR_CMT_4 0x08 + +#endif /* _INC_PMCC4_CPLD_H_ */ diff --git a/drivers/staging/cxt1e1/pmcc4_defs.h b/drivers/staging/cxt1e1/pmcc4_defs.h new file mode 100644 index 00000000000..83ceae4324b --- /dev/null +++ b/drivers/staging/cxt1e1/pmcc4_defs.h @@ -0,0 +1,68 @@ +#ifndef _INC_PMCC4_DEFS_H_ +#define _INC_PMCC4_DEFS_H_ + +/*----------------------------------------------------------------------------- + * c4_defs.h - + * + * Implementation elements of the wanPMC-C4T1E1 device driver + * + * Copyright (C) 2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + *----------------------------------------------------------------------------- + */ + + +#define MAX_BOARDS 8 +#define MAX_CHANS_USED 128 + +#ifdef SBE_PMCC4_ENABLE +#define MUSYCC_NPORTS 4 /* CN8474 */ +#endif +#ifdef SBE_WAN256T3_ENABLE +#define MUSYCC_NPORTS 8 /* CN8478 */ +#endif +#define MUSYCC_NCHANS 32 /* actually, chans per port */ + +#define MUSYCC_NIQD 0x1000 /* power of 2 */ +#define MUSYCC_MRU 2048 /* default */ +#define MUSYCC_MTU 2048 /* default */ +#define MUSYCC_TXDESC_MIN 10 /* HDLC mode default */ +#define MUSYCC_RXDESC_MIN 18 /* HDLC mode default */ +#define MUSYCC_TXDESC_TRANS 4 /* Transparent mode minimum # of TX descriptors */ +#define MUSYCC_RXDESC_TRANS 12 /* Transparent mode minimum # of RX descriptors */ + +#define MAX_DEFAULT_IFQLEN 32 /* network qlen */ + + +#define SBE_IFACETMPL "pmcc4-%d" +#ifdef IFNAMSIZ +#define SBE_IFACETMPL_SIZE IFNAMSIZ +#else +#define SBE_IFACETMPL_SIZE 16 +#endif + +/* we want the PMCC4 watchdog to fire off every 250ms */ +#define WATCHDOG_TIMEOUT 250000 + +/* if we restart the watchdog every 250ms, then we'll time out + * an additional 300ms later */ +#define WATCHDOG_UTIMEOUT (WATCHDOG_TIMEOUT+300000) + +#if !defined(SBE_ISR_TASKLET) && !defined(SBE_ISR_IMMEDIATE) && !defined(SBE_ISR_INLINE) +#define SBE_ISR_TASKLET +#endif + +#endif /*** _INC_PMCC4_DEFS_H_ ***/ + diff --git a/drivers/staging/cxt1e1/pmcc4_drv.c b/drivers/staging/cxt1e1/pmcc4_drv.c new file mode 100644 index 00000000000..76bebdd18b3 --- /dev/null +++ b/drivers/staging/cxt1e1/pmcc4_drv.c @@ -0,0 +1,1613 @@ +/*----------------------------------------------------------------------------- + * pmcc4_drv.c - + * + * Copyright (C) 2007 One Stop Systems, Inc. + * Copyright (C) 2002-2006 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@onestopsystems.com + * One Stop Systems, Inc. Escondido, California U.S.A. + *----------------------------------------------------------------------------- + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/types.h> +#include "pmcc4_sysdep.h" +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/sched.h> /* include for timer */ +#include <linux/timer.h> /* include for timer */ +#include <linux/hdlc.h> +#include <linux/io.h> + +#include "sbecom_inline_linux.h" +#include "libsbew.h" +#include "pmcc4_private.h" +#include "pmcc4.h" +#include "pmcc4_ioctls.h" +#include "musycc.h" +#include "comet.h" +#include "sbe_bid.h" + +#define KERN_WARN KERN_WARNING + +/* forward references */ +status_t c4_wk_chan_init (mpi_t *, mch_t *); +void c4_wq_port_cleanup (mpi_t *); +status_t c4_wq_port_init (mpi_t *); + +int c4_loop_port (ci_t *, int, u_int8_t); +status_t c4_set_port (ci_t *, int); +status_t musycc_chan_down (ci_t *, int); + +u_int32_t musycc_chan_proto (int); +status_t musycc_dump_ring (ci_t *, unsigned int); +status_t __init musycc_init (ci_t *); +void musycc_init_mdt (mpi_t *); +void musycc_serv_req (mpi_t *, u_int32_t); +void musycc_update_timeslots (mpi_t *); + +extern void musycc_update_tx_thp (mch_t *); +extern int cxt1e1_log_level; +extern int cxt1e1_max_mru; +extern int cxt1e1_max_mtu; +extern int max_rxdesc_used, max_rxdesc_default; +extern int max_txdesc_used, max_txdesc_default; + +#if defined (__powerpc__) +extern void *memset (void *s, int c, size_t n); + +#endif + +int drvr_state = SBE_DRVR_INIT; +ci_t *c4_list = NULL; +ci_t *CI; /* dummy pointer to board ZEROE's data - + * DEBUG USAGE */ + + +void +sbecom_set_loglevel (int d) +{ + /* + * The code within the following -if- clause is a backdoor debug facility + * which can be used to display the state of a board's channel. + */ + if (d > LOG_DEBUG) + { + unsigned int channum = d - (LOG_DEBUG + 1); /* convert to ZERO + * relativity */ + + (void) musycc_dump_ring ((ci_t *) CI, channum); /* CI implies support + * for card 0 only */ + } else + { + if (cxt1e1_log_level != d) + { + pr_info("log level changed from %d to %d\n", cxt1e1_log_level, d); + cxt1e1_log_level = d; /* set new */ + } else + pr_info("log level is %d\n", cxt1e1_log_level); + } +} + + +mch_t * +c4_find_chan (int channum) +{ + ci_t *ci; + mch_t *ch; + int portnum, gchan; + + for (ci = c4_list; ci; ci = ci->next) + for (portnum = 0; portnum < ci->max_port; portnum++) + for (gchan = 0; gchan < MUSYCC_NCHANS; gchan++) + { + ch = ci->port[portnum].chan[gchan]; + if (ch) { + if ((ch->state != UNASSIGNED) && + (ch->channum == channum)) + return ch; + } + } + return NULL; +} + +/*** + * Check port state and set LED states using watchdog or ioctl... + * also check for in-band SF loopback commands (& cause results if they are there) + * + * Alarm function depends on comet bits indicating change in + * link status (linkMask) to keep the link status indication straight. + * + * Indications are only LED and system log -- except when ioctl is invoked. + * + * "alarmed" record (a.k.a. copyVal, in some cases below) decodes as: + * + * RMAI (E1 only) 0x100 + * alarm LED on 0x80 + * link LED on 0x40 + * link returned 0x20 (link was down, now it's back and 'port get' hasn't run) + * change in LED 0x10 (update LED register because value has changed) + * link is down 0x08 + * YelAlm(RAI) 0x04 + * RedAlm 0x02 + * AIS(blue)Alm 0x01 + * + * note "link has returned" indication is reset on read + * (e.g. by use of the c4_control port get command) + */ + +#define sbeLinkMask 0x41 /* change in signal status (lost/recovered) + + * state */ +#define sbeLinkChange 0x40 +#define sbeLinkDown 0x01 +#define sbeAlarmsMask 0x07 /* red / yellow / blue alarm conditions */ +#define sbeE1AlarmsMask 0x107 /* alarm conditions */ + +#define COMET_LBCMD_READ 0x80 /* read only (do not set, return read value) */ + +void +checkPorts (ci_t *ci) +{ +#ifndef CONFIG_SBE_PMCC4_NCOMM + /* + * PORT POINT - NCOMM needs to avoid this code since the polling of + * alarms conflicts with NCOMM's interrupt servicing implementation. + */ + + struct s_comet_reg *comet; + volatile u_int32_t value; + u_int32_t copyVal, LEDval; + + u_int8_t portnum; + + LEDval = 0; + for (portnum = 0; portnum < ci->max_port; portnum++) + { + copyVal = 0x12f & (ci->alarmed[portnum]); /* port's alarm record */ + comet = ci->port[portnum].cometbase; + value = pci_read_32 ((u_int32_t *) &comet->cdrc_ists) & sbeLinkMask; /* link loss reg */ + + if (value & sbeLinkChange) /* is there a change in the link stuff */ + { + /* if there's been a change (above) and yet it's the same (below) */ + if (!(((copyVal >> 3) & sbeLinkDown) ^ (value & sbeLinkDown))) + { + if (value & sbeLinkDown) + pr_warning("%s: Port %d momentarily recovered.\n", + ci->devname, portnum); + else + pr_warning("%s: Warning: Port %d link was briefly down.\n", + ci->devname, portnum); + } else if (value & sbeLinkDown) + pr_warning("%s: Warning: Port %d link is down.\n", + ci->devname, portnum); + else + { + pr_warning("%s: Port %d link has recovered.\n", + ci->devname, portnum); + copyVal |= 0x20; /* record link transition to up */ + } + copyVal |= 0x10; /* change (link) --> update LEDs */ + } + copyVal &= 0x137; /* clear LED & link old history bits & + * save others */ + if (value & sbeLinkDown) + copyVal |= 0x08; /* record link status (now) */ + else + { /* if link is up, do this */ + copyVal |= 0x40; /* LED indicate link is up */ + /* Alarm things & the like ... first if E1, then if T1 */ + if (IS_FRAME_ANY_E1 (ci->port[portnum].p.port_mode)) + { + /* + * first check Codeword (SaX) changes & CRC and + * sub-multi-frame errors + */ + /* + * note these errors are printed every time they are detected + * vs. alarms + */ + value = pci_read_32 ((u_int32_t *) &comet->e1_frmr_nat_ists); /* codeword */ + if (value & 0x1f) + { /* if errors (crc or smf only) */ + if (value & 0x10) + pr_warning("%s: E1 Port %d Codeword Sa4 change detected.\n", + ci->devname, portnum); + if (value & 0x08) + pr_warning("%s: E1 Port %d Codeword Sa5 change detected.\n", + ci->devname, portnum); + if (value & 0x04) + pr_warning("%s: E1 Port %d Codeword Sa6 change detected.\n", + ci->devname, portnum); + if (value & 0x02) + pr_warning("%s: E1 Port %d Codeword Sa7 change detected.\n", + ci->devname, portnum); + if (value & 0x01) + pr_warning("%s: E1 Port %d Codeword Sa8 change detected.\n", + ci->devname, portnum); + } + value = pci_read_32 ((u_int32_t *) &comet->e1_frmr_mists); /* crc & smf */ + if (value & 0x3) + { /* if errors (crc or smf only) */ + if (value & sbeE1CRC) + pr_warning("%s: E1 Port %d CRC-4 error(s) detected.\n", + ci->devname, portnum); + if (value & sbeE1errSMF) /* error in sub-multiframe */ + pr_warning("%s: E1 Port %d received errored SMF.\n", + ci->devname, portnum); + } + value = pci_read_32 ((u_int32_t *) &comet->e1_frmr_masts) & 0xcc; /* alarms */ + /* + * pack alarms together (bitmiser), and construct similar to + * T1 + */ + /* RAI,RMAI,.,.,LOF,AIS,.,. ==> RMAI,.,.,.,.,.,RAI,LOF,AIS */ + /* see 0x97 */ + value = (value >> 2); + if (value & 0x30) + { + if (value & 0x20) + value |= 0x40; /* RAI */ + if (value & 0x10) + value |= 0x100; /* RMAI */ + value &= ~0x30; + } /* finished packing alarm in handy order */ + if (value != (copyVal & sbeE1AlarmsMask)) + { /* if alarms changed */ + copyVal |= 0x10;/* change LED status */ + if ((copyVal & sbeRedAlm) && !(value & sbeRedAlm)) + { + copyVal &= ~sbeRedAlm; + pr_warning("%s: E1 Port %d LOF alarm ended.\n", + ci->devname, portnum); + } else if (!(copyVal & sbeRedAlm) && (value & sbeRedAlm)) + { + copyVal |= sbeRedAlm; + pr_warning("%s: E1 Warning: Port %d LOF alarm.\n", + ci->devname, portnum); + } else if ((copyVal & sbeYelAlm) && !(value & sbeYelAlm)) + { + copyVal &= ~sbeYelAlm; + pr_warning("%s: E1 Port %d RAI alarm ended.\n", + ci->devname, portnum); + } else if (!(copyVal & sbeYelAlm) && (value & sbeYelAlm)) + { + copyVal |= sbeYelAlm; + pr_warning("%s: E1 Warning: Port %d RAI alarm.\n", + ci->devname, portnum); + } else if ((copyVal & sbeE1RMAI) && !(value & sbeE1RMAI)) + { + copyVal &= ~sbeE1RMAI; + pr_warning("%s: E1 Port %d RMAI alarm ended.\n", + ci->devname, portnum); + } else if (!(copyVal & sbeE1RMAI) && (value & sbeE1RMAI)) + { + copyVal |= sbeE1RMAI; + pr_warning("%s: E1 Warning: Port %d RMAI alarm.\n", + ci->devname, portnum); + } else if ((copyVal & sbeAISAlm) && !(value & sbeAISAlm)) + { + copyVal &= ~sbeAISAlm; + pr_warning("%s: E1 Port %d AIS alarm ended.\n", + ci->devname, portnum); + } else if (!(copyVal & sbeAISAlm) && (value & sbeAISAlm)) + { + copyVal |= sbeAISAlm; + pr_warning("%s: E1 Warning: Port %d AIS alarm.\n", + ci->devname, portnum); + } + } + /* end of E1 alarm code */ + } else + { /* if a T1 mode */ + value = pci_read_32 ((u_int32_t *) &comet->t1_almi_ists); /* alarms */ + value &= sbeAlarmsMask; + if (value != (copyVal & sbeAlarmsMask)) + { /* if alarms changed */ + copyVal |= 0x10;/* change LED status */ + if ((copyVal & sbeRedAlm) && !(value & sbeRedAlm)) + { + copyVal &= ~sbeRedAlm; + pr_warning("%s: Port %d red alarm ended.\n", + ci->devname, portnum); + } else if (!(copyVal & sbeRedAlm) && (value & sbeRedAlm)) + { + copyVal |= sbeRedAlm; + pr_warning("%s: Warning: Port %d red alarm.\n", + ci->devname, portnum); + } else if ((copyVal & sbeYelAlm) && !(value & sbeYelAlm)) + { + copyVal &= ~sbeYelAlm; + pr_warning("%s: Port %d yellow (RAI) alarm ended.\n", + ci->devname, portnum); + } else if (!(copyVal & sbeYelAlm) && (value & sbeYelAlm)) + { + copyVal |= sbeYelAlm; + pr_warning("%s: Warning: Port %d yellow (RAI) alarm.\n", + ci->devname, portnum); + } else if ((copyVal & sbeAISAlm) && !(value & sbeAISAlm)) + { + copyVal &= ~sbeAISAlm; + pr_warning("%s: Port %d blue (AIS) alarm ended.\n", + ci->devname, portnum); + } else if (!(copyVal & sbeAISAlm) && (value & sbeAISAlm)) + { + copyVal |= sbeAISAlm; + pr_warning("%s: Warning: Port %d blue (AIS) alarm.\n", + ci->devname, portnum); + } + } + } /* end T1 mode alarm checks */ + } + if (copyVal & sbeAlarmsMask) + copyVal |= 0x80; /* if alarm turn yel LED on */ + if (copyVal & 0x10) + LEDval |= 0x100; /* tag if LED values have changed */ + LEDval |= ((copyVal & 0xc0) >> (6 - (portnum * 2))); + + ci->alarmed[portnum] &= 0xfffff000; /* out with the old (it's fff + * ... foo) */ + ci->alarmed[portnum] |= (copyVal); /* in with the new */ + + /* + * enough with the alarms and LED's, now let's check for loopback + * requests + */ + + if (IS_FRAME_ANY_T1 (ci->port[portnum].p.port_mode)) + { /* if a T1 mode */ + /* + * begin in-band (SF) loopback code detection -- start by reading + * command + */ + value = pci_read_32 ((u_int32_t *) &comet->ibcd_ies); /* detect reg. */ + value &= 0x3; /* trim to handy bits */ + if (value & 0x2) + { /* activate loopback (sets for deactivate + * code length) */ + copyVal = c4_loop_port (ci, portnum, COMET_LBCMD_READ); /* read line loopback + * mode */ + if (copyVal != COMET_MDIAG_LINELB) /* don't do it again if + * already in that mode */ + c4_loop_port (ci, portnum, COMET_MDIAG_LINELB); /* put port in line + * loopback mode */ + } + if (value & 0x1) + { /* deactivate loopback (sets for activate + * code length) */ + copyVal = c4_loop_port (ci, portnum, COMET_LBCMD_READ); /* read line loopback + * mode */ + if (copyVal != COMET_MDIAG_LBOFF) /* don't do it again if + * already in that mode */ + c4_loop_port (ci, portnum, COMET_MDIAG_LBOFF); /* take port out of any + * loopback mode */ + } + } + if (IS_FRAME_ANY_T1ESF (ci->port[portnum].p.port_mode)) + { /* if a T1 ESF mode */ + /* begin ESF loopback code */ + value = pci_read_32 ((u_int32_t *) &comet->t1_rboc_sts) & 0x3f; /* read command */ + if (value == 0x07) + c4_loop_port (ci, portnum, COMET_MDIAG_LINELB); /* put port in line + * loopback mode */ + if (value == 0x0a) + c4_loop_port (ci, portnum, COMET_MDIAG_PAYLB); /* put port in payload + * loopbk mode */ + if ((value == 0x1c) || (value == 0x19) || (value == 0x12)) + c4_loop_port (ci, portnum, COMET_MDIAG_LBOFF); /* take port out of any + * loopbk mode */ + if (cxt1e1_log_level >= LOG_DEBUG) + if (value != 0x3f) + pr_warning("%s: BOC value = %x on Port %d\n", + ci->devname, value, portnum); + /* end ESF loopback code */ + } + } + + /* if something is new, update LED's */ + if (LEDval & 0x100) + pci_write_32 ((u_int32_t *) &ci->cpldbase->leds, LEDval & 0xff); +#endif /*** CONFIG_SBE_PMCC4_NCOMM ***/ +} + + +static void +c4_watchdog (ci_t *ci) +{ + if (drvr_state != SBE_DRVR_AVAILABLE) + { + if (cxt1e1_log_level >= LOG_MONITOR) + pr_info("drvr not available (%x)\n", drvr_state); + return; + } + ci->wdcount++; + checkPorts (ci); + ci->wd_notify = 0; +} + + +void +c4_cleanup (void) +{ + ci_t *ci, *next; + mpi_t *pi; + int portnum, j; + + ci = c4_list; + while (ci) + { + next = ci->next; /* protect <next> from upcoming <free> */ + pci_write_32 ((u_int32_t *) &ci->cpldbase->leds, PMCC4_CPLD_LED_OFF); + for (portnum = 0; portnum < ci->max_port; portnum++) + { + pi = &ci->port[portnum]; + c4_wq_port_cleanup (pi); + for (j = 0; j < MUSYCC_NCHANS; j++) + { + if (pi->chan[j]) + kfree(pi->chan[j]); /* free mch_t struct */ + } + kfree(pi->regram_saved); + } + kfree(ci->iqd_p_saved); + kfree(ci); + ci = next; /* cleanup next board, if any */ + } +} + + +/* + * This function issues a write to all comet chips and expects the same data + * to be returned from the subsequent read. This determines the board build + * to be a 1-port, 2-port, or 4-port build. The value returned represents a + * bit-mask of the found ports. Only certain configurations are considered + * VALID or LEGAL builds. + */ + +int +c4_get_portcfg (ci_t *ci) +{ + struct s_comet_reg *comet; + int portnum, mask; + u_int32_t wdata, rdata; + + wdata = COMET_MDIAG_LBOFF; /* take port out of any loopback mode */ + + mask = 0; + for (portnum = 0; portnum < MUSYCC_NPORTS; portnum++) + { + comet = ci->port[portnum].cometbase; + pci_write_32 ((u_int32_t *) &comet->mdiag, wdata); + rdata = pci_read_32 ((u_int32_t *) &comet->mdiag) & COMET_MDIAG_LBMASK; + if (wdata == rdata) + mask |= 1 << portnum; + } + return mask; +} + + +/* nothing herein should generate interrupts */ + +status_t __init +c4_init (ci_t *ci, u_char *func0, u_char *func1) +{ + mpi_t *pi; + mch_t *ch; + static u_int32_t count = 0; + int portnum, j; + + ci->state = C_INIT; + ci->brdno = count++; + ci->intlog.this_status_new = 0; + atomic_set (&ci->bh_pending, 0); + + ci->reg = (struct musycc_globalr *) func0; + ci->eeprombase = (u_int32_t *) (func1 + EEPROM_OFFSET); + ci->cpldbase = (c4cpld_t *) ((u_int32_t *) (func1 + ISPLD_OFFSET)); + + /*** PORT POINT - the following is the first access of any type to the hardware ***/ +#ifdef CONFIG_SBE_PMCC4_NCOMM + /* NCOMM driver uses INTB interrupt to monitor CPLD register */ + pci_write_32 ((u_int32_t *) &ci->reg->glcd, GCD_MAGIC); +#else + /* standard driver POLLS for INTB via CPLD register */ + pci_write_32 ((u_int32_t *) &ci->reg->glcd, GCD_MAGIC | MUSYCC_GCD_INTB_DISABLE); +#endif + + { + int pmsk; + + /* need comet addresses available for determination of hardware build */ + for (portnum = 0; portnum < MUSYCC_NPORTS; portnum++) + { + pi = &ci->port[portnum]; + pi->cometbase = (struct s_comet_reg *) ((u_int32_t *) (func1 + COMET_OFFSET (portnum))); + pi->reg = (struct musycc_globalr *) ((u_char *) ci->reg + (portnum * 0x800)); + pi->portnum = portnum; + pi->p.portnum = portnum; + pi->openchans = 0; +#ifdef SBE_MAP_DEBUG + pr_info("Comet-%d: addr = %p\n", portnum, pi->cometbase); +#endif + } + pmsk = c4_get_portcfg (ci); + switch (pmsk) + { + case 0x1: + ci->max_port = 1; + break; + case 0x3: + ci->max_port = 2; + break; +#if 0 + case 0x7: /* not built, but could be... */ + ci->max_port = 3; + break; +#endif + case 0xf: + ci->max_port = 4; + break; + default: + ci->max_port = 0; + pr_warning("%s: illegal port configuration (%x)\n", + ci->devname, pmsk); + return SBE_DRVR_FAIL; + } +#ifdef SBE_MAP_DEBUG + pr_info(">> %s: c4_get_build - pmsk %x max_port %x\n", + ci->devname, pmsk, ci->max_port); +#endif + } + + for (portnum = 0; portnum < ci->max_port; portnum++) + { + pi = &ci->port[portnum]; + pi->up = ci; + pi->sr_last = 0xffffffff; + pi->p.port_mode = CFG_FRAME_SF; /* T1 B8ZS, the default */ + pi->p.portP = (CFG_CLK_PORT_EXTERNAL | CFG_LBO_LH0); /* T1 defaults */ + + OS_sem_init (&pi->sr_sem_busy, SEM_AVAILABLE); + OS_sem_init (&pi->sr_sem_wait, SEM_TAKEN); + + for (j = 0; j < 32; j++) + { + pi->fifomap[j] = -1; + pi->tsm[j] = 0; /* no assignments, all available */ + } + + /* allocate channel structures for this port */ + for (j = 0; j < MUSYCC_NCHANS; j++) + { + ch = kzalloc(sizeof(mch_t), GFP_KERNEL | GFP_DMA); + if (ch) + { + pi->chan[j] = ch; + ch->state = UNASSIGNED; + ch->up = pi; + ch->gchan = (-1); /* channel assignment not yet known */ + ch->channum = (-1); /* channel assignment not yet known */ + ch->p.card = ci->brdno; + ch->p.port = portnum; + ch->p.channum = (-1); /* channel assignment not yet known */ + ch->p.mode_56k = 0; /* default is 64kbps mode */ + } else + { + pr_warning("failed mch_t malloc, port %d channel %d size %u.\n", + portnum, j, (unsigned int) sizeof (mch_t)); + break; + } + } + } + + + { + /* + * Set LEDs through their paces to supply visual proof that LEDs are + * functional and not burnt out nor broken. + * + * YELLOW + GREEN -> OFF. + */ + + pci_write_32 ((u_int32_t *) &ci->cpldbase->leds, + PMCC4_CPLD_LED_GREEN | PMCC4_CPLD_LED_YELLOW); + OS_uwait (750000, "leds"); + pci_write_32 ((u_int32_t *) &ci->cpldbase->leds, PMCC4_CPLD_LED_OFF); + } + + OS_init_watchdog (&ci->wd, (void (*) (void *)) c4_watchdog, ci, WATCHDOG_TIMEOUT); + return SBE_DRVR_SUCCESS; +} + + +/* better be fully setup to handle interrupts when you call this */ + +status_t __init +c4_init2 (ci_t *ci) +{ + status_t ret; + + /* PORT POINT: this routine generates first interrupt */ + ret = musycc_init(ci); + if (ret != SBE_DRVR_SUCCESS) + return ret; + +#if 0 + ci->p.framing_type = FRAMING_CBP; + ci->p.h110enable = 1; +#if 0 + ci->p.hypersize = 0; +#else + hyperdummy = 0; +#endif + ci->p.clock = 0; /* Use internal clocking until set to + * external */ + c4_card_set_params (ci, &ci->p); +#endif + OS_start_watchdog (&ci->wd); + return SBE_DRVR_SUCCESS; +} + + +/* This function sets the loopback mode (or clears it, as the case may be). */ + +int +c4_loop_port (ci_t *ci, int portnum, u_int8_t cmd) +{ + struct s_comet_reg *comet; + volatile u_int32_t loopValue; + + comet = ci->port[portnum].cometbase; + loopValue = pci_read_32 ((u_int32_t *) &comet->mdiag) & COMET_MDIAG_LBMASK; + + if (cmd & COMET_LBCMD_READ) + return loopValue; /* return the read value */ + + if (loopValue != cmd) + { + switch (cmd) + { + case COMET_MDIAG_LINELB: + /* set(SF)loopback down (turn off) code length to 6 bits */ + pci_write_32 ((u_int32_t *) &comet->ibcd_cfg, 0x05); + break; + case COMET_MDIAG_LBOFF: + /* set (SF) loopback up (turn on) code length to 5 bits */ + pci_write_32 ((u_int32_t *) &comet->ibcd_cfg, 0x00); + break; + } + + pci_write_32 ((u_int32_t *) &comet->mdiag, cmd); + if (cxt1e1_log_level >= LOG_WARN) + pr_info("%s: loopback mode changed to %2x from %2x on Port %d\n", + ci->devname, cmd, loopValue, portnum); + loopValue = pci_read_32 ((u_int32_t *) &comet->mdiag) & COMET_MDIAG_LBMASK; + if (loopValue != cmd) + { + if (cxt1e1_log_level >= LOG_ERROR) + pr_info("%s: write to loop register failed, unknown state for Port %d\n", + ci->devname, portnum); + } + } else + { + if (cxt1e1_log_level >= LOG_WARN) + pr_info("%s: loopback already in that mode (%2x)\n", + ci->devname, loopValue); + } + return 0; +} + + +/* c4_frame_rw: read or write the comet register specified + * (modifies use of port_param to non-standard use of struct) + * Specifically: + * pp.portnum (one guess) + * pp.port_mode offset of register + * pp.portP write (or not, i.e. read) + * pp.portStatus write value + * BTW: + * pp.portStatus also used to return read value + * pp.portP also used during write, to return old reg value + */ + +status_t +c4_frame_rw (ci_t *ci, struct sbecom_port_param *pp) +{ + struct s_comet_reg *comet; + volatile u_int32_t data; + + if (pp->portnum >= ci->max_port)/* sanity check */ + return -ENXIO; + + comet = ci->port[pp->portnum].cometbase; + data = pci_read_32 ((u_int32_t *) comet + pp->port_mode) & 0xff; + + if (pp->portP) + { /* control says this is a register + * _write_ */ + if (pp->portStatus == data) + pr_info("%s: Port %d already that value! Writing again anyhow.\n", + ci->devname, pp->portnum); + pp->portP = (u_int8_t) data; + pci_write_32 ((u_int32_t *) comet + pp->port_mode, + pp->portStatus); + data = pci_read_32 ((u_int32_t *) comet + pp->port_mode) & 0xff; + } + pp->portStatus = (u_int8_t) data; + return 0; +} + + +/* c4_pld_rw: read or write the pld register specified + * (modifies use of port_param to non-standard use of struct) + * Specifically: + * pp.port_mode offset of register + * pp.portP write (or not, i.e. read) + * pp.portStatus write value + * BTW: + * pp.portStatus also used to return read value + * pp.portP also used during write, to return old reg value + */ + +status_t +c4_pld_rw (ci_t *ci, struct sbecom_port_param *pp) +{ + volatile u_int32_t *regaddr; + volatile u_int32_t data; + int regnum = pp->port_mode; + + regaddr = (u_int32_t *) ci->cpldbase + regnum; + data = pci_read_32 ((u_int32_t *) regaddr) & 0xff; + + if (pp->portP) + { /* control says this is a register + * _write_ */ + pp->portP = (u_int8_t) data; + pci_write_32 ((u_int32_t *) regaddr, pp->portStatus); + data = pci_read_32 ((u_int32_t *) regaddr) & 0xff; + } + pp->portStatus = (u_int8_t) data; + return 0; +} + +/* c4_musycc_rw: read or write the musycc register specified + * (modifies use of port_param to non-standard use of struct) + * Specifically: + * mcp.RWportnum port number and write indication bit (0x80) + * mcp.offset offset of register + * mcp.value write value going in and read value returning + */ + +/* PORT POINT: TX Subchannel Map registers are write-only + * areas within the MUSYCC and always return FF */ +/* PORT POINT: regram and reg structures are minorly different and <offset> ioctl + * settings are aligned with the <reg> struct musycc_globalr{} usage. + * Also, regram is separately allocated shared memory, allocated for each port. + * PORT POINT: access offsets of 0x6000 for Msg Cfg Desc Tbl are for 4-port MUSYCC + * only. (An 8-port MUSYCC has 0x16000 offsets for accessing its upper 4 tables.) + */ + +status_t +c4_musycc_rw (ci_t *ci, struct c4_musycc_param *mcp) +{ + mpi_t *pi; + volatile u_int32_t *dph; /* hardware implemented register */ + u_int32_t *dpr = NULL; /* RAM image of registers for group command + * usage */ + int offset = mcp->offset % 0x800; /* group relative address + * offset, mcp->portnum is + * not used */ + int portnum, ramread = 0; + volatile u_int32_t data; + + /* + * Sanity check hardware accessibility. The 0x6000 portion handles port + * numbers associated with Msg Descr Tbl decoding. + */ + portnum = (mcp->offset % 0x6000) / 0x800; + if (portnum >= ci->max_port) + return -ENXIO; + pi = &ci->port[portnum]; + if (mcp->offset >= 0x6000) + offset += 0x6000; /* put back in MsgCfgDesc address offset */ + dph = (u_int32_t *) ((u_long) pi->reg + offset); + + /* read of TX are from RAM image, since hardware returns FF */ + dpr = (u_int32_t *) ((u_long) pi->regram + offset); + if (mcp->offset < 0x6000) /* non MsgDesc Tbl accesses might require + * RAM access */ + { + if (offset >= 0x200 && offset < 0x380) + ramread = 1; + if (offset >= 0x10 && offset < 0x200) + ramread = 1; + } + /* read register from RAM or hardware, depending... */ + if (ramread) + { + data = *dpr; + //pr_info("c4_musycc_rw: RAM addr %p read data %x (portno %x offset %x RAM ramread %x)\n", dpr, data, portnum, offset, ramread); /* RLD DEBUG */ + } else + { + data = pci_read_32 ((u_int32_t *) dph); + //pr_info("c4_musycc_rw: REG addr %p read data %x (portno %x offset %x RAM ramread %x)\n", dph, data, portnum, offset, ramread); /* RLD DEBUG */ + } + + + if (mcp->RWportnum & 0x80) + { /* control says this is a register + * _write_ */ + if (mcp->value == data) + pr_info("%s: musycc grp%d already that value! writing again anyhow.\n", + ci->devname, (mcp->RWportnum & 0x7)); + /* write register RAM */ + if (ramread) + *dpr = mcp->value; + /* write hardware register */ + pci_write_32 ((u_int32_t *) dph, mcp->value); + } + mcp->value = data; /* return the read value (or the 'old + * value', if is write) */ + return 0; +} + +status_t +c4_get_port (ci_t *ci, int portnum) +{ + if (portnum >= ci->max_port) /* sanity check */ + return -ENXIO; + + SD_SEM_TAKE (&ci->sem_wdbusy, "_wd_"); /* only 1 thru here, per + * board */ + checkPorts (ci); + ci->port[portnum].p.portStatus = (u_int8_t) ci->alarmed[portnum]; + ci->alarmed[portnum] &= 0xdf; + SD_SEM_GIVE (&ci->sem_wdbusy); /* release per-board hold */ + return 0; +} + +status_t +c4_set_port (ci_t *ci, int portnum) +{ + mpi_t *pi; + struct sbecom_port_param *pp; + int e1mode; + u_int8_t clck; + int i; + + if (portnum >= ci->max_port) /* sanity check */ + return -ENXIO; + + pi = &ci->port[portnum]; + pp = &ci->port[portnum].p; + e1mode = IS_FRAME_ANY_E1 (pp->port_mode); + if (cxt1e1_log_level >= LOG_MONITOR2) + { + pr_info("%s: c4_set_port[%d]: entered, e1mode = %x, openchans %d.\n", + ci->devname, + portnum, e1mode, pi->openchans); + } + if (pi->openchans) + return -EBUSY; /* group needs initialization only for + * first channel of a group */ + + { + status_t ret; + + ret = c4_wq_port_init(pi); + if (ret) /* create/init workqueue_struct */ + return ret; + } + + init_comet (ci, pi->cometbase, pp->port_mode, 1 /* clockmaster == true */ , pp->portP); + clck = pci_read_32 ((u_int32_t *) &ci->cpldbase->mclk) & PMCC4_CPLD_MCLK_MASK; + if (e1mode) + clck |= 1 << portnum; + else + clck &= 0xf ^ (1 << portnum); + + pci_write_32 ((u_int32_t *) &ci->cpldbase->mclk, clck); + pci_write_32 ((u_int32_t *) &ci->cpldbase->mcsr, PMCC4_CPLD_MCSR_IND); + pci_write_32 ((u_int32_t *) &pi->reg->gbp, OS_vtophys (pi->regram)); + + /*********************************************************************/ + /* ERRATA: If transparent mode is used, do not set OOFMP_DISABLE bit */ + /*********************************************************************/ + + pi->regram->grcd = + __constant_cpu_to_le32 (MUSYCC_GRCD_RX_ENABLE | + MUSYCC_GRCD_TX_ENABLE | + MUSYCC_GRCD_OOFMP_DISABLE | + MUSYCC_GRCD_SF_ALIGN | /* per MUSYCC ERRATA, + * for T1 * fix */ + MUSYCC_GRCD_COFAIRQ_DISABLE | + MUSYCC_GRCD_MC_ENABLE | + (MUSYCC_GRCD_POLLTH_32 << MUSYCC_GRCD_POLLTH_SHIFT)); + + pi->regram->pcd = + __constant_cpu_to_le32 ((e1mode ? 1 : 0) | + MUSYCC_PCD_TXSYNC_RISING | + MUSYCC_PCD_RXSYNC_RISING | + MUSYCC_PCD_RXDATA_RISING); + + /* Message length descriptor */ + pi->regram->mld = __constant_cpu_to_le32 (cxt1e1_max_mru | (cxt1e1_max_mru << 16)); + + /* tsm algorithm */ + for (i = 0; i < 32; i++) + { + + /*** ASSIGNMENT NOTES: ***/ + /*** Group's channel ZERO unavailable if E1. ***/ + /*** Group's channel 16 unavailable if E1 CAS. ***/ + /*** Group's channels 24-31 unavailable if T1. ***/ + + if (((i == 0) && e1mode) || + ((i == 16) && ((pp->port_mode == CFG_FRAME_E1CRC_CAS) || (pp->port_mode == CFG_FRAME_E1CRC_CAS_AMI))) + || ((i > 23) && (!e1mode))) + { + pi->tsm[i] = 0xff; /* make tslot unavailable for this mode */ + } else + { + pi->tsm[i] = 0x00; /* make tslot available for assignment */ + } + } + for (i = 0; i < MUSYCC_NCHANS; i++) + { + pi->regram->ttsm[i] = 0; + pi->regram->rtsm[i] = 0; + } + FLUSH_MEM_WRITE (); + musycc_serv_req (pi, SR_GROUP_INIT | SR_RX_DIRECTION); + musycc_serv_req (pi, SR_GROUP_INIT | SR_TX_DIRECTION); + + musycc_init_mdt (pi); + + pi->group_is_set = 1; + pi->p = *pp; + return 0; +} + + +unsigned int max_int = 0; + +status_t +c4_new_chan (ci_t *ci, int portnum, int channum, void *user) +{ + mpi_t *pi; + mch_t *ch; + int gchan; + + if (c4_find_chan (channum)) /* a new channel shouldn't already exist */ + return -EEXIST; + + if (portnum >= ci->max_port) /* sanity check */ + return -ENXIO; + + pi = &(ci->port[portnum]); + /* find any available channel within this port */ + for (gchan = 0; gchan < MUSYCC_NCHANS; gchan++) + { + ch = pi->chan[gchan]; + if (ch && ch->state == UNASSIGNED) /* no assignment is good! */ + break; + } + if (gchan == MUSYCC_NCHANS) /* exhausted table, all were assigned */ + return -ENFILE; + + ch->up = pi; + + /* NOTE: mch_t already cleared during OS_kmalloc() */ + ch->state = DOWN; + ch->user = user; + ch->gchan = gchan; + ch->channum = channum; /* mark our channel assignment */ + ch->p.channum = channum; +#if 1 + ch->p.card = ci->brdno; + ch->p.port = portnum; +#endif + ch->p.chan_mode = CFG_CH_PROTO_HDLC_FCS16; + ch->p.idlecode = CFG_CH_FLAG_7E; + ch->p.pad_fill_count = 2; + spin_lock_init (&ch->ch_rxlock); + spin_lock_init (&ch->ch_txlock); + + { + status_t ret; + + ret = c4_wk_chan_init(pi, ch); + if (ret) + return ret; + } + + /* save off interface assignments which bound a board */ + if (!ci->first_if) /* first channel registered is assumed to + * be the lowest channel */ + { + ci->first_if = ci->last_if = user; + ci->first_channum = ci->last_channum = channum; + } else + { + ci->last_if = user; + if (ci->last_channum < channum) /* higher number channel found */ + ci->last_channum = channum; + } + return 0; +} + +status_t +c4_del_chan (int channum) +{ + mch_t *ch; + + ch = c4_find_chan(channum); + if (!ch) + return -ENOENT; + + if (ch->state == UP) + musycc_chan_down ((ci_t *) 0, channum); + ch->state = UNASSIGNED; + ch->gchan = (-1); + ch->channum = (-1); + ch->p.channum = (-1); + return 0; +} + +status_t +c4_del_chan_stats (int channum) +{ + mch_t *ch; + + ch = c4_find_chan(channum); + if (!ch) + return -ENOENT; + + memset (&ch->s, 0, sizeof (struct sbecom_chan_stats)); + return 0; +} + + +status_t +c4_set_chan (int channum, struct sbecom_chan_param *p) +{ + mch_t *ch; + int i, x = 0; + + ch = c4_find_chan(channum); + if (!ch) + return -ENOENT; + +#if 1 + if (ch->p.card != p->card || + ch->p.port != p->port || + ch->p.channum != p->channum) + return -EINVAL; +#endif + + if (!(ch->up->group_is_set)) + { + return -EIO; /* out of order, SET_PORT command + * required prior to first group's + * SET_CHAN command */ + } + /* + * Check for change of parameter settings in order to invoke closing of + * channel prior to hardware poking. + */ + + if (ch->p.status != p->status || ch->p.chan_mode != p->chan_mode || + ch->p.data_inv != p->data_inv || ch->p.intr_mask != p->intr_mask || + ch->txd_free < ch->txd_num) /* to clear out queued messages */ + x = 1; /* we have a change requested */ + for (i = 0; i < 32; i++) /* check for timeslot mapping changes */ + if (ch->p.bitmask[i] != p->bitmask[i]) + x = 1; /* we have a change requested */ + ch->p = *p; + if (x && (ch->state == UP)) /* if change request and channel is + * open... */ + { + status_t ret; + + ret = musycc_chan_down((ci_t *)0, channum); + if (ret) + return ret; + ret = c4_chan_up(ch->up->up, channum); + if (ret) + return ret; + sd_enable_xmit (ch->user); /* re-enable to catch flow controlled + * channel */ + } + return 0; +} + + +status_t +c4_get_chan (int channum, struct sbecom_chan_param *p) +{ + mch_t *ch; + + ch = c4_find_chan(channum); + if (!ch) + return -ENOENT; + + *p = ch->p; + return 0; +} + +status_t +c4_get_chan_stats (int channum, struct sbecom_chan_stats *p) +{ + mch_t *ch; + + ch = c4_find_chan(channum); + if (!ch) + return -ENOENT; + + *p = ch->s; + p->tx_pending = atomic_read (&ch->tx_pending); + return 0; +} + +static int +c4_fifo_alloc (mpi_t *pi, int chan, int *len) +{ + int i, l = 0, start = 0, max = 0, maxstart = 0; + + for (i = 0; i < 32; i++) + { + if (pi->fifomap[i] != -1) + { + l = 0; + start = i + 1; + continue; + } + ++l; + if (l > max) + { + max = l; + maxstart = start; + } + if (max == *len) + break; + } + if (max != *len) + { + if (cxt1e1_log_level >= LOG_WARN) + pr_info("%s: wanted to allocate %d fifo space, but got only %d\n", + pi->up->devname, *len, max); + *len = max; + } + if (cxt1e1_log_level >= LOG_DEBUG) + pr_info("%s: allocated %d fifo at %d for channel %d/%d\n", + pi->up->devname, max, start, chan, pi->p.portnum); + for (i = maxstart; i < (maxstart + max); i++) + pi->fifomap[i] = chan; + return start; +} + +void +c4_fifo_free (mpi_t *pi, int chan) +{ + int i; + + if (cxt1e1_log_level >= LOG_DEBUG) + pr_info("%s: deallocated fifo for channel %d/%d\n", + pi->up->devname, chan, pi->p.portnum); + for (i = 0; i < 32; i++) + if (pi->fifomap[i] == chan) + pi->fifomap[i] = -1; +} + + +status_t +c4_chan_up (ci_t *ci, int channum) +{ + mpi_t *pi; + mch_t *ch; + struct mbuf *m; + struct mdesc *md; + int nts, nbuf, txnum, rxnum; + int addr, i, j, gchan; + u_int32_t tmp; /* for optimizing conversion across BE + * platform */ + + ch = c4_find_chan(channum); + if (!ch) + return -ENOENT; + + if (ch->state == UP) + { + if (cxt1e1_log_level >= LOG_MONITOR) + pr_info("%s: channel already UP, graceful early exit\n", + ci->devname); + return 0; + } + pi = ch->up; + gchan = ch->gchan; + /* find nts ('number of timeslots') */ + nts = 0; + for (i = 0; i < 32; i++) + { + if (ch->p.bitmask[i] & pi->tsm[i]) + { + if (1 || cxt1e1_log_level >= LOG_WARN) + { + pr_info("%s: c4_chan_up[%d] EINVAL (attempt to cfg in-use or unavailable TimeSlot[%d])\n", + ci->devname, channum, i); + pr_info("+ ask4 %x, currently %x\n", + ch->p.bitmask[i], pi->tsm[i]); + } + return -EINVAL; + } + for (j = 0; j < 8; j++) + if (ch->p.bitmask[i] & (1 << j)) + nts++; + } + + nbuf = nts / 8 ? nts / 8 : 1; + if (!nbuf) + { + /* if( cxt1e1_log_level >= LOG_WARN) */ + pr_info("%s: c4_chan_up[%d] ENOBUFS (no TimeSlots assigned)\n", + ci->devname, channum); + return -ENOBUFS; /* this should not happen */ + } + addr = c4_fifo_alloc (pi, gchan, &nbuf); + ch->state = UP; + + /* Setup the Time Slot Map */ + musycc_update_timeslots (pi); + + /* ch->tx_limit = nts; */ + ch->s.tx_pending = 0; + + /* Set Channel Configuration Descriptors */ + { + u_int32_t ccd; + + ccd = musycc_chan_proto (ch->p.chan_mode) << MUSYCC_CCD_PROTO_SHIFT; + if ((ch->p.chan_mode == CFG_CH_PROTO_ISLP_MODE) || + (ch->p.chan_mode == CFG_CH_PROTO_TRANS)) + { + ccd |= MUSYCC_CCD_FCS_XFER; /* Non FSC Mode */ + } + ccd |= 2 << MUSYCC_CCD_MAX_LENGTH; /* Select second MTU */ + ccd |= ch->p.intr_mask; + ccd |= addr << MUSYCC_CCD_BUFFER_LOC; + if (ch->p.chan_mode == CFG_CH_PROTO_TRANS) + ccd |= (nbuf) << MUSYCC_CCD_BUFFER_LENGTH; + else + ccd |= (nbuf - 1) << MUSYCC_CCD_BUFFER_LENGTH; + + if (ch->p.data_inv & CFG_CH_DINV_TX) + ccd |= MUSYCC_CCD_INVERT_DATA; /* Invert data */ + pi->regram->tcct[gchan] = cpu_to_le32 (ccd); + + if (ch->p.data_inv & CFG_CH_DINV_RX) + ccd |= MUSYCC_CCD_INVERT_DATA; /* Invert data */ + else + ccd &= ~MUSYCC_CCD_INVERT_DATA; /* take away data inversion */ + pi->regram->rcct[gchan] = cpu_to_le32 (ccd); + FLUSH_MEM_WRITE (); + } + + /* Reread the Channel Configuration Descriptor for this channel */ + musycc_serv_req (pi, SR_CHANNEL_CONFIG | SR_RX_DIRECTION | gchan); + musycc_serv_req (pi, SR_CHANNEL_CONFIG | SR_TX_DIRECTION | gchan); + + /* + * Figure out how many buffers we want. If the customer has changed from + * the defaults, then use the changed values. Otherwise, use Transparent + * mode's specific minimum default settings. + */ + if (ch->p.chan_mode == CFG_CH_PROTO_TRANS) + { + if (max_rxdesc_used == max_rxdesc_default) /* use default setting */ + max_rxdesc_used = MUSYCC_RXDESC_TRANS; + if (max_txdesc_used == max_txdesc_default) /* use default setting */ + max_txdesc_used = MUSYCC_TXDESC_TRANS; + } + /* + * Increase counts when hyperchanneling, since this implies an increase + * in throughput per channel + */ + rxnum = max_rxdesc_used + (nts / 4); + txnum = max_txdesc_used + (nts / 4); + +#if 0 + /* DEBUG INFO */ + if (cxt1e1_log_level >= LOG_MONITOR) + pr_info("%s: mode %x rxnum %d (rxused %d def %d) txnum %d (txused %d def %d)\n", + ci->devname, ch->p.chan_mode, + rxnum, max_rxdesc_used, max_rxdesc_default, + txnum, max_txdesc_used, max_txdesc_default); +#endif + + ch->rxd_num = rxnum; + ch->txd_num = txnum; + ch->rxix_irq_srv = 0; + + ch->mdr = kzalloc(sizeof(struct mdesc) * rxnum, GFP_KERNEL | GFP_DMA); + ch->mdt = kzalloc(sizeof(struct mdesc) * txnum, GFP_KERNEL | GFP_DMA); + if (ch->p.chan_mode == CFG_CH_PROTO_TRANS) + tmp = __constant_cpu_to_le32 (cxt1e1_max_mru | EOBIRQ_ENABLE); + else + tmp = __constant_cpu_to_le32 (cxt1e1_max_mru); + + for (i = 0, md = ch->mdr; i < rxnum; i++, md++) + { + if (i == (rxnum - 1)) + { + md->snext = &ch->mdr[0];/* wrapness */ + } else + { + md->snext = &ch->mdr[i + 1]; + } + md->next = cpu_to_le32 (OS_vtophys (md->snext)); + + m = OS_mem_token_alloc(cxt1e1_max_mru); + if (!m) { + if (cxt1e1_log_level >= LOG_MONITOR) + pr_info( + "%s: c4_chan_up[%d] - token alloc failure, size = %d.\n", + ci->devname, channum, cxt1e1_max_mru); + goto errfree; + } + md->mem_token = m; + md->data = cpu_to_le32 (OS_vtophys (OS_mem_token_data (m))); + md->status = tmp | MUSYCC_RX_OWNED; /* MUSYCC owns RX descriptor ** + * CODING NOTE: + * MUSYCC_RX_OWNED = 0 so no + * need to byteSwap */ + } + + for (i = 0, md = ch->mdt; i < txnum; i++, md++) + { + md->status = HOST_TX_OWNED; /* Host owns TX descriptor ** CODING + * NOTE: HOST_TX_OWNED = 0 so no need to + * byteSwap */ + md->mem_token = NULL; + md->data = 0; + if (i == (txnum - 1)) + { + md->snext = &ch->mdt[0];/* wrapness */ + } else + { + md->snext = &ch->mdt[i + 1]; + } + md->next = cpu_to_le32 (OS_vtophys (md->snext)); + } + ch->txd_irq_srv = ch->txd_usr_add = &ch->mdt[0]; + ch->txd_free = txnum; + ch->tx_full = 0; + ch->txd_required = 0; + + /* Configure it into the chip */ + tmp = cpu_to_le32 (OS_vtophys (&ch->mdt[0])); + pi->regram->thp[gchan] = tmp; + pi->regram->tmp[gchan] = tmp; + + tmp = cpu_to_le32 (OS_vtophys (&ch->mdr[0])); + pi->regram->rhp[gchan] = tmp; + pi->regram->rmp[gchan] = tmp; + + /* Activate the Channel */ + FLUSH_MEM_WRITE (); + if (ch->p.status & RX_ENABLED) + { +#ifdef RLD_TRANS_DEBUG + pr_info("++ c4_chan_up() CHAN RX ACTIVATE: chan %d\n", ch->channum); +#endif + ch->ch_start_rx = 0; /* we are restarting RX... */ + musycc_serv_req (pi, SR_CHANNEL_ACTIVATE | SR_RX_DIRECTION | gchan); + } + if (ch->p.status & TX_ENABLED) + { +#ifdef RLD_TRANS_DEBUG + pr_info("++ c4_chan_up() CHAN TX ACTIVATE: chan %d <delayed>\n", ch->channum); +#endif + ch->ch_start_tx = CH_START_TX_1ST; /* we are delaying start + * until receipt from user of + * first packet to transmit. */ + } + ch->status = ch->p.status; + pi->openchans++; + return 0; + +errfree: + while (i > 0) + { + /* Don't leak all the previously allocated mbufs in this loop */ + i--; + OS_mem_token_free (ch->mdr[i].mem_token); + } + kfree(ch->mdt); + ch->mdt = NULL; + ch->txd_num = 0; + kfree(ch->mdr); + ch->mdr = NULL; + ch->rxd_num = 0; + ch->state = DOWN; + return -ENOBUFS; +} + +/* stop the hardware from servicing & interrupting */ + +void +c4_stopwd (ci_t *ci) +{ + OS_stop_watchdog (&ci->wd); + SD_SEM_TAKE (&ci->sem_wdbusy, "_stop_"); /* ensure WD not running */ + SD_SEM_GIVE (&ci->sem_wdbusy); +} + + +void +sbecom_get_brdinfo (ci_t *ci, struct sbe_brd_info *bip, u_int8_t *bsn) +{ + char *np; + u_int32_t sn = 0; + int i; + + bip->brdno = ci->brdno; /* our board number */ + bip->brd_id = ci->brd_id; + bip->brd_hdw_id = ci->hdw_bid; + bip->brd_chan_cnt = MUSYCC_NCHANS *ci->max_port; /* number of channels + * being used */ + bip->brd_port_cnt = ci->max_port; /* number of ports being used */ + bip->brd_pci_speed = BINFO_PCI_SPEED_unk; /* PCI speed not yet + * determinable */ + + if (ci->first_if) + { + { + struct net_device *dev; + + dev = (struct net_device *) ci->first_if; + np = (char *) dev->name; + } + strncpy (bip->first_iname, np, CHNM_STRLEN - 1); + } else + strcpy (bip->first_iname, "<NULL>"); + if (ci->last_if) + { + { + struct net_device *dev; + + dev = (struct net_device *) ci->last_if; + np = (char *) dev->name; + } + strncpy (bip->last_iname, np, CHNM_STRLEN - 1); + } else + strcpy (bip->last_iname, "<NULL>"); + + if (bsn) + { + for (i = 0; i < 3; i++) + { + bip->brd_mac_addr[i] = *bsn++; + } + for (; i < 6; i++) + { + bip->brd_mac_addr[i] = *bsn; + sn = (sn << 8) | *bsn++; + } + } else + { + for (i = 0; i < 6; i++) + bip->brd_mac_addr[i] = 0; + } + bip->brd_sn = sn; +} + + +status_t +c4_get_iidinfo (ci_t *ci, struct sbe_iid_info *iip) +{ + struct net_device *dev; + char *np; + + dev = getuserbychan(iip->channum); + if (!dev) + return -ENOENT; + + np = dev->name; + strncpy (iip->iname, np, CHNM_STRLEN - 1); + iip->iname[CHNM_STRLEN - 1] = '\0'; + return 0; +} + + +#ifdef CONFIG_SBE_PMCC4_NCOMM +void (*nciInterrupt[MAX_BOARDS][4]) (void); +extern void wanpmcC4T1E1_hookInterrupt (int cardID, int deviceID, void *handler); + +void +wanpmcC4T1E1_hookInterrupt (int cardID, int deviceID, void *handler) +{ + if (cardID < MAX_BOARDS) /* sanity check */ + nciInterrupt[cardID][deviceID] = handler; +} + +irqreturn_t +c4_ebus_intr_th_handler (void *devp) +{ + ci_t *ci = (ci_t *) devp; + volatile u_int32_t ists; + int handled = 0; + int brdno; + + /* which COMET caused the interrupt */ + brdno = ci->brdno; + ists = pci_read_32 ((u_int32_t *) &ci->cpldbase->intr); + if (ists & PMCC4_CPLD_INTR_CMT_1) + { + handled = 0x1; + if (nciInterrupt[brdno][0] != NULL) + (*nciInterrupt[brdno][0]) (); + } + if (ists & PMCC4_CPLD_INTR_CMT_2) + { + handled |= 0x2; + if (nciInterrupt[brdno][1] != NULL) + (*nciInterrupt[brdno][1]) (); + } + if (ists & PMCC4_CPLD_INTR_CMT_3) + { + handled |= 0x4; + if (nciInterrupt[brdno][2] != NULL) + (*nciInterrupt[brdno][2]) (); + } + if (ists & PMCC4_CPLD_INTR_CMT_4) + { + handled |= 0x8; + if (nciInterrupt[brdno][3] != NULL) + (*nciInterrupt[brdno][3]) (); + } +#if 0 + /*** Test code just de-implements the asserted interrupt. Alternate + vendor will supply COMET interrupt handling code herein or such. + ***/ + pci_write_32 ((u_int32_t *) &ci->reg->glcd, GCD_MAGIC | MUSYCC_GCD_INTB_DISABLE); +#endif + + return IRQ_RETVAL (handled); +} + + +unsigned long +wanpmcC4T1E1_getBaseAddress (int cardID, int deviceID) +{ + ci_t *ci; + unsigned long base = 0; + + ci = c4_list; + while (ci) + { + if (ci->brdno == cardID) /* found valid device */ + { + if (deviceID < ci->max_port) /* comet is supported */ + base = ((unsigned long) ci->port[deviceID].cometbase); + break; + } + ci = ci->next; /* next board, if any */ + } + return base; +} + +#endif /*** CONFIG_SBE_PMCC4_NCOMM ***/ + + +/*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/pmcc4_ioctls.h b/drivers/staging/cxt1e1/pmcc4_ioctls.h new file mode 100644 index 00000000000..56a1ee39be1 --- /dev/null +++ b/drivers/staging/cxt1e1/pmcc4_ioctls.h @@ -0,0 +1,65 @@ +#ifndef _INC_PMCC4_IOCTLS_H_ +#define _INC_PMCC4_IOCTLS_H_ + +/*----------------------------------------------------------------------------- + * pmcc4_ioctls.h - + * + * Copyright (C) 2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + *----------------------------------------------------------------------------- + */ + +#include "sbew_ioc.h" + +enum +{ + // C4_GET_PORT = 0, + // C4_SET_PORT, + // C4_GET_CHAN, + // C4_SET_CHAN, + C4_DEL_CHAN = 0, + // C4_CREATE_CHAN, + // C4_GET_CHAN_STATS, + // C4_RESET, + // C4_DEBUG, + C4_RESET_STATS, + C4_LOOP_PORT, + C4_RW_FRMR, + C4_RW_MSYC, + C4_RW_PLD +}; + +#define C4_GET_PORT SBE_IOC_PORT_GET +#define C4_SET_PORT SBE_IOC_PORT_SET +#define C4_GET_CHAN SBE_IOC_CHAN_GET +#define C4_SET_CHAN SBE_IOC_CHAN_SET +// #define C4_DEL_CHAN XXX +#define C4_CREATE_CHAN SBE_IOC_CHAN_NEW +#define C4_GET_CHAN_STATS SBE_IOC_CHAN_GET_STAT +#define C4_RESET SBE_IOC_RESET_DEV +#define C4_DEBUG SBE_IOC_LOGLEVEL +// #define C4_RESET_STATS XXX +// #define C4_LOOP_PORT XXX +// #define C4_RW_FRMR XXX +// #define C4_RW_MSYC XXX +// #define C4_RW_PLD XXX + +struct c4_chan_stats_wrap +{ + int channum; + struct sbecom_chan_stats stats; +}; + +#endif /* _INC_PMCC4_IOCTLS_H_ */ diff --git a/drivers/staging/cxt1e1/pmcc4_private.h b/drivers/staging/cxt1e1/pmcc4_private.h new file mode 100644 index 00000000000..451f12f5b04 --- /dev/null +++ b/drivers/staging/cxt1e1/pmcc4_private.h @@ -0,0 +1,295 @@ +#ifndef _INC_PMCC4_PRIVATE_H_ +#define _INC_PMCC4_PRIVATE_H_ + +/*----------------------------------------------------------------------------- + * pmcc4_private.h - + * + * Copyright (C) 2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/semaphore.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> /* support for tasklets */ +#include <linux/timer.h> /* support for timer */ +#include <linux/workqueue.h> +#include <linux/hdlc.h> + +#include "libsbew.h" +#include "pmcc4_defs.h" +#include "pmcc4_cpld.h" +#include "musycc.h" +#include "sbe_promformat.h" +#include "comet.h" + + +/* driver state */ +#define SBE_DRVR_INIT 0x0 +#define SBE_DRVR_AVAILABLE 0x69734F4E +#define SBE_DRVR_DOWN 0x1 + +/****************************************************************************** + * MUSYCC Message Descriptor - coupled to hardware implementation, the first + * three u_int32 must not be reordered. + */ + +struct mdesc +{ + volatile u_int32_t status; /* Buffer Descriptor */ + u_int32_t data; /* Data Pointer */ + u_int32_t next; /* MUSYCC view of Next Pointer */ + void *mem_token; /* Data */ + struct mdesc *snext; +}; + + +/************************************************************************* + * Private driver data structures, internal use only. + */ + +struct c4_chan_info +{ + int gchan; /* channel number within group/port 0-31 */ + int channum; /* absolute channel number 0-128 */ + u_int8_t status; +#define TX_RECOVERY_MASK 0x0f +#define TX_ONR_RECOVERY 0x01 +#define TX_BUFF_RECOVERY 0x02 +#define RX_RECOVERY_MASK 0xf0 +#define RX_ONR_RECOVERY 0x10 + + unsigned char ch_start_rx; +#define CH_START_RX_NOW 1 +#define CH_START_RX_ONR 2 +#define CH_START_RX_BUF 3 + + unsigned char ch_start_tx; +#define CH_START_TX_1ST 1 +#define CH_START_TX_ONR 2 +#define CH_START_TX_BUF 3 + + char tx_full; /* boolean */ + short txd_free; /* count of TX Desc available */ + short txd_required; /* count of TX Desc needed by mesg */ + unsigned short rxd_num; /* must support range up to 2000 */ + unsigned short txd_num; /* must support range up to 1000 */ + int rxix_irq_srv; + + enum + { + UNASSIGNED, /* AVAILABLE, NOTINUSE */ + DOWN, /* ASSIGNED, NOTINUSE */ + UP /* ASSIGNED and INUSE */ + } state; + + struct c4_port_info *up; + void *user; + + struct work_struct ch_work; + struct mdesc *mdt; + struct mdesc *mdr; + struct mdesc *txd_irq_srv; + struct mdesc *txd_usr_add; + +#if 0 + /* + * FUTURE CODE MIGHT SEPARATE TIMESLOT MAP SETUPS INTO SINGLE IOCTL and + * REMOVE MAPS FROM CHANNEL PARAMETER STRUCTURE + */ + /* + * each byte in bitmask below represents one timeslot (bitmask[0] is for + * timeslot 0 and so on), each bit in the byte selects timeslot bits for + * this channel (0xff - whole timeslot, 0x7f - 56kbps mode) + */ + + u_int8_t ts_bitmask[32]; +#endif + spinlock_t ch_rxlock; + spinlock_t ch_txlock; + atomic_t tx_pending; + + struct sbecom_chan_stats s; + struct sbecom_chan_param p; +}; +typedef struct c4_chan_info mch_t; + +struct c4_port_info +{ + + struct musycc_globalr *reg; + struct musycc_groupr *regram; + void *regram_saved; /* Original malloc value may have non-2KB + * boundary. Need to save for use when + * freeing. */ + struct s_comet_reg *cometbase; + struct sbe_card_info *up; + + /* + * The workqueue is used for TX restart of ONR'd channels when in + * Transparent mode. + */ + + struct workqueue_struct *wq_port; /* chan restart work queue */ + struct semaphore sr_sem_busy; /* service request exclusion + * semaphore */ + struct semaphore sr_sem_wait; /* service request handshake + * semaphore */ + u_int32_t sr_last; + short openchans; + char portnum; + char group_is_set; /* GROUP_INIT command issued to MUSYCC, + * otherwise SET_CHAN Ioctl fails */ + + mch_t *chan[MUSYCC_NCHANS]; + struct sbecom_port_param p; + + /* + * The MUSYCC timeslot mappings are maintained within the driver and are + * modified and reloaded as each of a group's channels are configured. + */ + u_int8_t tsm[32]; /* tsm (time slot map) */ + int fifomap[32]; +}; +typedef struct c4_port_info mpi_t; + + +#define COMET_OFFSET(x) (0x80000+(x)*0x10000) +#define EEPROM_OFFSET 0xC0000 +#define ISPLD_OFFSET 0xD0000 + +/* iSPLD control chip registers */ +#define ISPLD_MCSR 0x0 +#define ISPLD_MCLK 0x1 +#define ISPLD_LEDS 0x2 +#define ISPLD_INTR 0x3 +#define ISPLD_MAX 0x3 + +struct sbe_card_info +{ + struct musycc_globalr *reg; + struct musycc_groupr *regram; + u_int32_t *iqd_p; /* pointer to dword aligned interrupt queue + * descriptors */ + void *iqd_p_saved; /* Original malloc value may have non-dword + * aligned boundary. Need to save for use + * when freeing. */ + unsigned int iqp_headx, iqp_tailx; + + struct semaphore sem_wdbusy;/* watchdog exclusion semaphore */ + struct watchdog wd; /* statically allocated watchdog structure */ + atomic_t bh_pending; /* bh queued, but not yet running */ + u_int32_t brd_id; /* unique PCI ID */ + u_int16_t hdw_bid; /* on/board hardware ID */ + unsigned short wdcount; + unsigned char max_port; + unsigned char brdno; /* our board number */ + unsigned char wd_notify; +#define WD_NOTIFY_1TX 1 +#define WD_NOTIFY_BUF 2 +#define WD_NOTIFY_ONR 4 + enum /* state as regards interrupt processing */ + { + C_INIT, /* of-board-address not configured or are in + * process of being removed, don't access + * hardware */ + C_IDLE, /* off-board-addresses are configured, but + * don't service interrupts, just clear them + * from hardware */ + C_RUNNING /* life is good, service away */ + } state; + + struct sbe_card_info *next; + u_int32_t *eeprombase; /* mapped address of board's EEPROM */ + c4cpld_t *cpldbase; /* mapped address of board's CPLD hardware */ + void *hdw_info; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *dir_dev; +#endif + + /* saved off interface assignments which bound a board */ + hdlc_device *first_if; + hdlc_device *last_if; + short first_channum, last_channum; + + struct intlog + { + u_int32_t this_status_new; + u_int32_t last_status_new; + u_int32_t drvr_intr_thcount; + u_int32_t drvr_intr_bhcount; + u_int32_t drvr_int_failure; + } intlog; + + mpi_t port[MUSYCC_NPORTS]; + char devname[SBE_IFACETMPL_SIZE + 1]; + atomic_t tx_pending; + u_int32_t alarmed[4]; /* dpm211 */ + +#if defined(SBE_ISR_TASKLET) + struct tasklet_struct ci_musycc_isr_tasklet; +#elif defined(SBE_ISR_IMMEDIATE) + struct tq_struct ci_musycc_isr_tq; +#endif +}; +typedef struct sbe_card_info ci_t; + +struct s_hdw_info +{ + u_int8_t pci_busno; + u_int8_t pci_slot; + u_int8_t pci_pin[2]; + u_int8_t revid[2]; + u_int8_t mfg_info_sts; +#define EEPROM_OK 0x00 +#define EEPROM_CRCERR 0x01 + char promfmt; /* prom type, from sbe_promformat.h */ + + char devname[SBE_IFACETMPL_SIZE]; + struct pci_bus *bus; + struct net_device *ndev; + struct pci_dev *pdev[2]; + + unsigned long addr[2]; + void __iomem *addr_mapped[2]; + unsigned long len[2]; + + union + { + char data[128]; + FLD_TYPE1 pft1; /* prom field, type #1 */ + FLD_TYPE2 pft2; /* prom field, type #2 */ + } mfg_info; +}; +typedef struct s_hdw_info hdw_info_t; + +/*****************************************************************/ + +struct c4_priv +{ + int channum; + struct sbe_card_info *ci; +}; + + +/*****************************************************************/ + +extern ci_t *c4_list; + +mch_t *c4_find_chan (int); +int c4_set_chan (int channum, struct sbecom_chan_param *); +int c4_get_chan (int channum, struct sbecom_chan_param *); +int c4_get_chan_stats (int channum, struct sbecom_chan_stats *); + +#endif /* _INC_PMCC4_PRIVATE_H_ */ diff --git a/drivers/staging/cxt1e1/pmcc4_sysdep.h b/drivers/staging/cxt1e1/pmcc4_sysdep.h new file mode 100644 index 00000000000..2916c2cb13f --- /dev/null +++ b/drivers/staging/cxt1e1/pmcc4_sysdep.h @@ -0,0 +1,63 @@ +#ifndef _INC_PMCC4_SYSDEP_H_ +#define _INC_PMCC4_SYSDEP_H_ + +/*----------------------------------------------------------------------------- + * pmcc4_sysdep.h - + * + * Copyright (C) 2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* reduce multiple autoconf entries to a single definition */ + +#ifdef CONFIG_SBE_PMCC4_HDLC_V7_MODULE +#undef CONFIG_SBE_PMCC4_HDLC_V7 +#define CONFIG_SBE_PMCC4_HDLC_V7 1 +#endif + +#ifdef CONFIG_SBE_PMCC4_NCOMM_MODULE +#undef CONFIG_SBE_PMCC4_NCOMM +#define CONFIG_SBE_PMCC4_NCOMM 1 +#endif + + +/* FLUSH MACROS - if using ioremap_nocache(), then these can be NOOPS, + * otherwise a memory barrier needs to be inserted. + */ + +#define FLUSH_PCI_READ() rmb() +#define FLUSH_PCI_WRITE() wmb() +#define FLUSH_MEM_READ() rmb() +#define FLUSH_MEM_WRITE() wmb() + + +/* + * System dependent callbacks routines, not inlined... + * For inlined system dependent routines, see include/sbecom_inlinux_linux.h + */ + +/* + * passes received memory token back to the system, <user> is parameter from + * sd_new_chan() used to create the channel which the data arrived on + */ + +void sd_recv_consume(void *token, size_t len, void *user); + +void sd_disable_xmit (void *user); +void sd_enable_xmit (void *user); +int sd_line_is_ok (void *user); +void sd_line_is_up (void *user); +void sd_line_is_down (void *user); +int sd_queue_stopped (void *user); + +#endif /*** _INC_PMCC4_SYSDEP_H_ ***/ +extern int cxt1e1_log_level; diff --git a/drivers/staging/cxt1e1/sbe_bid.h b/drivers/staging/cxt1e1/sbe_bid.h new file mode 100644 index 00000000000..abc2e55f62f --- /dev/null +++ b/drivers/staging/cxt1e1/sbe_bid.h @@ -0,0 +1,47 @@ +#ifndef _INC_SBEBID_H_ +#define _INC_SBEBID_H_ + +/*----------------------------------------------------------------------------- + * sbe_bid.h - + * + * Copyright (C) 2004-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + * + *----------------------------------------------------------------------------- + */ + +#define SBE_BID_REG 0x00000000 /* Board ID Register */ + +#define SBE_BID_256T3_E1 0x46 /* SBE wanPTMC-256T3 (E1 Version) */ +#define SBE_BID_256T3_T1 0x42 /* SBE wanPTMC-256T3 (T1 Version) */ +#define SBE_BID_2T3E3 0x43 /* SBE wanPMC-2T3E3 */ +#define SBE_BID_C1T3 0x45 /* SBE wanPMC-C1T3 */ +#define SBE_BID_C24TE1 0x47 /* SBE wanPTMC-C24TE1 */ +#define SBE_BID_C24TE1_RTM_24 0x48 /* C24TE1 RTM (24 Port) */ +#define SBE_BID_C24TE1_RTM_12 0x49 /* C24TE1 RTM (12 Port) */ +#define SBE_BID_C24TE1_RTM_12DSU 0x4A /* C24TE1 RTM (12 Port/DSU) */ +#define SBE_BID_C24TE1_RTM_T3 0x4B /* C24TE1 RTM (T3) */ +#define SBE_BID_C4T1E1 0x41 /* SBE wanPTMC-C4T1E1 */ +#define SBE_BID_HC4T1E1 0x44 /* SBE wanADAPT-HC4T1E1 */ + +/* bogus temporary usage values */ +#define SBE_BID_PMC_C4T1E1 0xC4 /* SBE wanPMC-C4T1E1 (4 Port) */ +#define SBE_BID_PMC_C2T1E1 0xC2 /* SBE wanPMC-C2T1E1 (2 Port) */ +#define SBE_BID_PMC_C1T1E1 0xC1 /* SBE wanPMC-C1T1E1 (1 Port) */ +#define SBE_BID_PCI_C4T1E1 0x04 /* SBE wanPCI-C4T1E1 (4 Port) */ +#define SBE_BID_PCI_C2T1E1 0x02 /* SBE wanPCI-C2T1E1 (2 Port) */ +#define SBE_BID_PCI_C1T1E1 0x01 /* SBE wanPCI-C1T1E1 (1 Port) */ + +#endif /*** _INC_SBEBID_H_ ***/ diff --git a/drivers/staging/cxt1e1/sbe_promformat.h b/drivers/staging/cxt1e1/sbe_promformat.h new file mode 100644 index 00000000000..aad411d185f --- /dev/null +++ b/drivers/staging/cxt1e1/sbe_promformat.h @@ -0,0 +1,130 @@ +#ifndef _INC_SBE_PROMFORMAT_H_ +#define _INC_SBE_PROMFORMAT_H_ + +/*----------------------------------------------------------------------------- + * sbe_promformat.h - Contents of seeprom used by dvt and manufacturing tests + * + * Copyright (C) 2002-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + * + *----------------------------------------------------------------------------- + */ + + +/*** + * PMCC4 SAMPLE EEPROM IMAGE + * + * eeprom[00]: 01 11 76 07 01 00 a0 d6 + * eeprom[08]: 22 34 56 3e 5b c1 1c 3e + * eeprom[16]: 5b e1 b6 00 00 00 01 00 + * eeprom[24]: 00 08 46 d3 7b 5e a8 fb + * eeprom[32]: f7 ef df bf 7f 55 00 01 + * eeprom[40]: 02 04 08 10 20 40 80 ff + * eeprom[48]: fe fd fb f7 ef df bf 7f + * + ***/ + + +/*------------------------------------------------------------------------ + * Type 1 Format + * byte: + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 + * ------------------------------------------------------------------------- + * 01 11 76 SS SS 00 0A D6 <SERIAL NUM> <Create TIME> <Heatrun TIME> + * SBE SUB SERIAL # (BCD) (time_t) (time_t) + * ID VENDOR (format) (format) + * + * 19 20 21 22 23 24 25 26 + * Heat Run Heat Run + * Iterations Errors + *------------------------------------------------------------------------ + * + * + * + * Type 2 Format - Added length, CRC in fixed position + * byte: + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + * ------------------------------------------------------------------------- + * 02 00 1A CC CC CC CC 11 76 07 03 00 0A D6 <SERIAL NUM> + * Payload SBE Crc32 SUB System System SERIAL/MAC + * Length VENDOR ID ID + * + * 17 18 19 20 21 22 23 24 25 26 27 28 29 39 31 32 + * -------------------------------------------------------------------------- + * <Create TIME> <Heatrun TIME> Heat Run Heat Run + * (time_t) (time_t) Iterations Errors + * + */ + +#define STRUCT_OFFSET(type, symbol) ((long)&(((type *)0)->symbol)) + +/*------------------------------------------------------------------------ + * Historically different Prom format types. + * + * For diagnostic and failure purposes, do not create a type 0x00 or a + * type 0xff + *------------------------------------------------------------------------ + */ +#define PROM_FORMAT_Unk (-1) +#define PROM_FORMAT_TYPE1 1 +#define PROM_FORMAT_TYPE2 2 + + +/****** bit fields for a type 1 formatted seeprom **************************/ + typedef struct + { + char type; /* 0x00 */ + char Id[2]; /* 0x01-0x02 */ + char SubId[2]; /* 0x03-0x04 */ + char Serial[6]; /* 0x05-0x0a */ + char CreateTime[4]; /* 0x0b-0x0e */ + char HeatRunTime[4]; /* 0x0f-0x12 */ + char HeatRunIterations[4]; /* 0x13-0x16 */ + char HeatRunErrors[4]; /* 0x17-0x1a */ + char Crc32[4]; /* 0x1b-0x1e */ + } FLD_TYPE1; + + +/****** bit fields for a type 2 formatted seeprom **************************/ + typedef struct + { + char type; /* 0x00 */ + char length[2]; /* 0x01-0x02 */ + char Crc32[4]; /* 0x03-0x06 */ + char Id[2]; /* 0x07-0x08 */ + char SubId[2]; /* 0x09-0x0a */ + char Serial[6]; /* 0x0b-0x10 */ + char CreateTime[4]; /* 0x11-0x14 */ + char HeatRunTime[4]; /* 0x15-0x18 */ + char HeatRunIterations[4]; /* 0x19-0x1c */ + char HeatRunErrors[4]; /* 0x1d-0x20 */ + } FLD_TYPE2; + + + +/***** this union allows us to access the seeprom as an array of bytes ***/ +/***** or as individual fields ***/ + +#define SBE_EEPROM_SIZE 128 +#define SBE_MFG_INFO_SIZE sizeof(FLD_TYPE2) + + typedef union + { + char bytes[128]; + FLD_TYPE1 fldType1; + FLD_TYPE2 fldType2; + } PROMFORMAT; + +#endif /*** _INC_SBE_PROMFORMAT_H_ ***/ diff --git a/drivers/staging/cxt1e1/sbecom_inline_linux.h b/drivers/staging/cxt1e1/sbecom_inline_linux.h new file mode 100644 index 00000000000..f5835c29ef3 --- /dev/null +++ b/drivers/staging/cxt1e1/sbecom_inline_linux.h @@ -0,0 +1,193 @@ +#ifndef _INC_SBECOM_INLNX_H_ +#define _INC_SBECOM_INLNX_H_ + +/*----------------------------------------------------------------------------- + * sbecom_inline_linux.h - SBE common Linux inlined routines + * + * Copyright (C) 2007 One Stop Systems, Inc. + * Copyright (C) 2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@onestopsystems.com + * One Stop Systems, Inc. Escondido, California U.S.A. + *----------------------------------------------------------------------------- + */ + + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> /* resolves kmalloc references */ +#include <linux/skbuff.h> /* resolves skb references */ +#include <linux/netdevice.h> /* resolves dev_kree_skb_any */ +#include <asm/byteorder.h> /* resolves cpu_to_le32 */ + +/* forward reference */ +u_int32_t pci_read_32 (u_int32_t *p); +void pci_write_32 (u_int32_t *p, u_int32_t v); + + +/* + * system dependent callbacks + */ + +/****************/ +/* memory token */ +/****************/ + +static inline void * +OS_mem_token_alloc (size_t size) +{ + struct sk_buff *skb; + + skb = dev_alloc_skb (size); + if (!skb) + { + //pr_warning("no mem in OS_mem_token_alloc !\n"); + return NULL; + } + return skb; +} + + +static inline void +OS_mem_token_free (void *token) +{ + dev_kfree_skb_any (token); +} + + +static inline void +OS_mem_token_free_irq (void *token) +{ + dev_kfree_skb_irq (token); +} + + +static inline void * +OS_mem_token_data (void *token) +{ + return ((struct sk_buff *) token)->data; +} + + +static inline void * +OS_mem_token_next (void *token) +{ + return NULL; +} + + +static inline int +OS_mem_token_len (void *token) +{ + return ((struct sk_buff *) token)->len; +} + + +static inline int +OS_mem_token_tlen (void *token) +{ + return ((struct sk_buff *) token)->len; +} + + +/***************************************/ +/* virtual to physical addr conversion */ +/***************************************/ + +static inline u_long +OS_phystov (void *addr) +{ + return (u_long) __va (addr); +} + + +static inline u_long +OS_vtophys (void *addr) +{ + return __pa (addr); +} + + +/**********/ +/* semops */ +/**********/ + +void OS_sem_init (void *, int); + + +static inline void +OS_sem_free (void *sem) +{ + /* + * NOOP - since semaphores structures predeclared w/in structures, no + * longer malloc'd + */ +} + +#define SD_SEM_TAKE(sem,desc) down(sem) +#define SD_SEM_GIVE(sem) up(sem) +#define SEM_AVAILABLE 1 +#define SEM_TAKEN 0 + + +/**********************/ +/* watchdog functions */ +/**********************/ + +struct watchdog +{ + struct timer_list h; + struct work_struct work; + void *softc; + void (*func) (void *softc); + int ticks; + int init_tq; +}; + + +static inline int +OS_start_watchdog (struct watchdog *wd) +{ + wd->h.expires = jiffies + wd->ticks; + add_timer (&wd->h); + return 0; +} + + +static inline int +OS_stop_watchdog (struct watchdog *wd) +{ + del_timer_sync (&wd->h); + return 0; +} + + +static inline int +OS_free_watchdog (struct watchdog *wd) +{ + OS_stop_watchdog (wd); + kfree(wd); + return 0; +} + + +/* sleep in microseconds */ +void OS_uwait (int usec, char *description); +void OS_uwait_dummy (void); + + +/* watchdog functions */ +int OS_init_watchdog(struct watchdog *wdp, void (*f) (void *), void *ci, int usec); + + +#endif /*** _INC_SBECOM_INLNX_H_ ***/ diff --git a/drivers/staging/cxt1e1/sbecrc.c b/drivers/staging/cxt1e1/sbecrc.c new file mode 100644 index 00000000000..a51780f6048 --- /dev/null +++ b/drivers/staging/cxt1e1/sbecrc.c @@ -0,0 +1,133 @@ +/* Based on "File Verification Using CRC" by Mark R. Nelson in Dr. Dobbs' + * Journal, May 1992, pp. 64-67. This algorithm generates the same CRC + * values as ZMODEM and PKZIP + * + * Copyright (C) 2002-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/types.h> +#include "pmcc4_sysdep.h" +#include "sbecom_inline_linux.h" +#include "sbe_promformat.h" + +/* defines */ +#define CRC32_POLYNOMIAL 0xEDB88320L +#define CRC_TABLE_ENTRIES 256 + + + +static u_int32_t crcTableInit; + +#ifdef STATIC_CRC_TABLE +static u_int32_t CRCTable[CRC_TABLE_ENTRIES]; + +#endif + + +/*************************************************************************** +* +* genCrcTable - fills in CRCTable, as used by sbeCrc() +* +* RETURNS: N/A +* +* ERRNO: N/A +***************************************************************************/ + +static void +genCrcTable(u_int32_t *CRCTable) +{ + int ii, jj; + u_int32_t crc; + + for (ii = 0; ii < CRC_TABLE_ENTRIES; ii++) { + crc = ii; + for (jj = 8; jj > 0; jj--) { + if (crc & 1) + crc = (crc >> 1) ^ CRC32_POLYNOMIAL; + else + crc >>= 1; + } + CRCTable[ii] = crc; + } + + crcTableInit++; +} + + +/*************************************************************************** +* +* sbeCrc - generates a CRC on a given buffer, and initial CRC +* +* This routine calculates the CRC for a buffer of data using the +* table lookup method. It accepts an original value for the crc, +* and returns the updated value. This permits "catenation" of +* discontiguous buffers. An original value of 0 for the "first" +* buffer is the norm. +* +* Based on "File Verification Using CRC" by Mark R. Nelson in Dr. Dobb's +* Journal, May 1992, pp. 64-67. This algorithm generates the same CRC +* values as ZMODEM and PKZIP. +* +* RETURNS: calculated crc of block +* +*/ + +void +sbeCrc(u_int8_t *buffer, /* data buffer to crc */ + u_int32_t count, /* length of block in bytes */ + u_int32_t initialCrc, /* starting CRC */ + u_int32_t *result) +{ + u_int32_t *tbl = NULL; + u_int32_t temp1, temp2, crc; + + /* + * if table not yet created, do so. Don't care about "extra" time + * checking this every time sbeCrc() is called, since CRC calculations + * are already time consuming + */ + if (!crcTableInit) { +#ifdef STATIC_CRC_TABLE + tbl = &CRCTable; + genCrcTable(tbl); +#else + tbl = kzalloc(CRC_TABLE_ENTRIES * sizeof(u_int32_t), + GFP_KERNEL); + if (!tbl) { + *result = 0; /* dummy up return value due to malloc + * failure */ + return; + } + genCrcTable(tbl); +#endif + } + /* inverting bits makes ZMODEM & PKZIP compatible */ + crc = initialCrc ^ 0xFFFFFFFFL; + + while (count-- != 0) { + temp1 = (crc >> 8) & 0x00FFFFFFL; + temp2 = tbl[((int) crc ^ *buffer++) & 0xff]; + crc = temp1 ^ temp2; + } + + crc ^= 0xFFFFFFFFL; + + *result = crc; + +#ifndef STATIC_CRC_TABLE + crcTableInit = 0; + kfree(tbl); +#endif +} + +/*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/sbeid.c b/drivers/staging/cxt1e1/sbeid.c new file mode 100644 index 00000000000..97c5c6e7e29 --- /dev/null +++ b/drivers/staging/cxt1e1/sbeid.c @@ -0,0 +1,205 @@ +/* Copyright (C) 2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/types.h> +#include "pmcc4_sysdep.h" +#include "sbecom_inline_linux.h" +#include "libsbew.h" +#include "pmcc4_private.h" +#include "pmcc4.h" +#include "sbe_bid.h" + +char * +sbeid_get_bdname(ci_t *ci) +{ + char *np = NULL; + + switch (ci->brd_id) { + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_256T3_E1): + np = "wanPTMC-256T3 <E1>"; + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_256T3_T1): + np = "wanPTMC-256T3 <T1>"; + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C4T1E1): + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C4T1E1_L): + np = "wanPMC-C4T1E1"; + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C2T1E1): + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C2T1E1_L): + np = "wanPMC-C2T1E1"; + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T1E1): + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T1E1_L): + np = "wanPMC-C1T1E1"; + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C4T1E1): + np = "wanPCI-C4T1E1"; + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C2T1E1): + np = "wanPCI-C2T1E1"; + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C1T1E1): + np = "wanPCI-C1T1E1"; + break; + default: + /*** np = "<unknown>"; ***/ + np = "wanPCI-CxT1E1"; + break; + } + + return np; +} + + +/* given the presetting of brd_id, set the corresponding hdw_id */ + +void +sbeid_set_hdwbid(ci_t *ci) +{ + /* + * set SBE's unique hardware identification (for legacy boards might not + * have this register implemented) + */ + + switch (ci->brd_id) { + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_256T3_E1): + ci->hdw_bid = SBE_BID_256T3_E1; /* 0x46 - SBE wanPTMC-256T3 (E1 + * Version) */ + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_256T3_T1): + ci->hdw_bid = SBE_BID_256T3_T1; /* 0x42 - SBE wanPTMC-256T3 (T1 + * Version) */ + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C4T1E1): + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C4T1E1_L): + /* + * This Board ID is a generic identification. Use the found number + * of ports to further define this hardware. + */ + switch (ci->max_port) { + default: /* shouldn't need a default, but have one + * anyway */ + case 4: + ci->hdw_bid = SBE_BID_PMC_C4T1E1; /* 0xC4 - SBE wanPMC-C4T1E1 */ + break; + case 2: + ci->hdw_bid = SBE_BID_PMC_C2T1E1; /* 0xC2 - SBE wanPMC-C2T1E1 */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C2T1E1); + break; + case 1: + ci->hdw_bid = SBE_BID_PMC_C1T1E1; /* 0xC1 - SBE wanPMC-C1T1E1 */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T1E1); + break; + } + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C2T1E1): + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C2T1E1_L): + ci->hdw_bid = SBE_BID_PMC_C2T1E1; /* 0xC2 - SBE wanPMC-C2T1E1 */ + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T1E1): + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T1E1_L): + ci->hdw_bid = SBE_BID_PMC_C1T1E1; /* 0xC1 - SBE wanPMC-C1T1E1 */ + break; +#ifdef SBE_PMCC4_ENABLE + /* + * This case is entered as a result of the inability to obtain the + * <bid> from the board's EEPROM. Assume a PCI board and set + * <hdsbid> according to the number ofr found ports. + */ + case 0: + /* start by assuming 4-port for ZERO casing */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C4T1E1); + /* drop thru to set hdw_bid and alternate PCI CxT1E1 settings */ +#endif + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C4T1E1): + /* + * This Board ID is a generic identification. Use the number of + * found ports to further define this hardware. + */ + switch (ci->max_port) { + default: /* shouldn't need a default, but have one + * anyway */ + case 4: + ci->hdw_bid = SBE_BID_PCI_C4T1E1; /* 0x04 - SBE wanPCI-C4T1E1 */ + break; + case 2: + ci->hdw_bid = SBE_BID_PCI_C2T1E1; /* 0x02 - SBE wanPCI-C2T1E1 */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C2T1E1); + break; + case 1: + ci->hdw_bid = SBE_BID_PCI_C1T1E1; /* 0x01 - SBE wanPCI-C1T1E1 */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C1T1E1); + break; + } + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C2T1E1): + ci->hdw_bid = SBE_BID_PCI_C2T1E1; /* 0x02 - SBE wanPCI-C2T1E1 */ + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C1T1E1): + ci->hdw_bid = SBE_BID_PCI_C1T1E1; /* 0x01 - SBE wanPCI-C1T1E1 */ + break; + default: + /*** bid = "<unknown>"; ***/ + ci->hdw_bid = SBE_BID_PMC_C4T1E1; /* 0x41 - SBE wanPTMC-C4T1E1 */ + break; + } +} + +/* given the presetting of hdw_bid, set the corresponding brd_id */ + +void +sbeid_set_bdtype(ci_t *ci) +{ + /* set SBE's unique PCI VENDOR/DEVID */ + switch (ci->hdw_bid) { + case SBE_BID_C1T3: /* SBE wanPMC-C1T3 */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T3); + break; + case SBE_BID_C24TE1: /* SBE wanPTMC-C24TE1 */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_C24TE1); + break; + case SBE_BID_256T3_E1: /* SBE wanPTMC-256T3 E1 Version */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_256T3_E1); + break; + case SBE_BID_256T3_T1: /* SBE wanPTMC-256T3 T1 Version */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_256T3_T1); + break; + case SBE_BID_PMC_C4T1E1: /* 0xC4 - SBE wanPMC-C4T1E1 */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C4T1E1); + break; + case SBE_BID_PMC_C2T1E1: /* 0xC2 - SBE wanPMC-C2T1E1 */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C2T1E1); + break; + case SBE_BID_PMC_C1T1E1: /* 0xC1 - SBE wanPMC-C1T1E1 */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T1E1); + break; + case SBE_BID_PCI_C4T1E1: /* 0x04 - SBE wanPCI-C4T1E1 */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C4T1E1); + break; + case SBE_BID_PCI_C2T1E1: /* 0x02 - SBE wanPCI-C2T1E1 */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C2T1E1); + break; + case SBE_BID_PCI_C1T1E1: /* 0x01 - SBE wanPCI-C1T1E1 */ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C1T1E1); + break; + + default: + /*** hdw_bid = "<unknown>"; ***/ + ci->brd_id = SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C4T1E1); + break; + } +} + + +/*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/sbeproc.c b/drivers/staging/cxt1e1/sbeproc.c new file mode 100644 index 00000000000..1c2e52e8b5f --- /dev/null +++ b/drivers/staging/cxt1e1/sbeproc.c @@ -0,0 +1,219 @@ +/* Copyright (C) 2004-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/sched.h> +#include <asm/uaccess.h> +#include "pmcc4_sysdep.h" +#include "sbecom_inline_linux.h" +#include "pmcc4_private.h" +#include "sbeproc.h" + +extern void sbecom_get_brdinfo(ci_t *, struct sbe_brd_info *, u_int8_t *); +extern struct s_hdw_info hdw_info[MAX_BOARDS]; + +void sbecom_proc_brd_cleanup(ci_t *ci) +{ + if (ci->dir_dev) { + char dir[7 + SBE_IFACETMPL_SIZE + 1]; + snprintf(dir, sizeof(dir), "driver/%s", ci->devname); + remove_proc_entry("info", ci->dir_dev); + remove_proc_entry(dir, NULL); + ci->dir_dev = NULL; + } +} + +static void sbecom_proc_get_brdinfo(ci_t *ci, struct sbe_brd_info *bip) +{ + hdw_info_t *hi = &hdw_info[ci->brdno]; + u_int8_t *bsn = NULL; + + switch (hi->promfmt) + { + case PROM_FORMAT_TYPE1: + bsn = (u_int8_t *) hi->mfg_info.pft1.Serial; + break; + case PROM_FORMAT_TYPE2: + bsn = (u_int8_t *) hi->mfg_info.pft2.Serial; + break; + } + + sbecom_get_brdinfo (ci, bip, bsn); + + pr_devel(">> sbecom_get_brdinfo: returned, first_if %p <%s> last_if %p <%s>\n", + bip->first_iname, bip->first_iname, + bip->last_iname, bip->last_iname); +} + +/* + * Describe the driver state through /proc + */ +static int sbecom_proc_get_sbe_info(struct seq_file *m, void *v) +{ + ci_t *ci = m->private; + char *spd; + struct sbe_brd_info *bip; + + bip = kzalloc(sizeof(struct sbe_brd_info), GFP_KERNEL | GFP_DMA); + if (!bip) + return -ENOMEM; + + pr_devel(">> sbecom_proc_get_sbe_info: entered\n"); + + sbecom_proc_get_brdinfo(ci, bip); + + seq_puts(m, "Board Type: "); + switch (bip->brd_id) { + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T3): + seq_puts(m, "wanPMC-C1T3"); + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_256T3_E1): + seq_puts(m, "wanPTMC-256T3 <E1>"); + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_256T3_T1): + seq_puts(m, "wanPTMC-256T3 <T1>"); + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPTMC_C24TE1): + seq_puts(m, "wanPTMC-C24TE1"); + break; + + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C4T1E1): + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C4T1E1_L): + seq_puts(m, "wanPMC-C4T1E1"); + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C2T1E1): + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C2T1E1_L): + seq_puts(m, "wanPMC-C2T1E1"); + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T1E1): + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPMC_C1T1E1_L): + seq_puts(m, "wanPMC-C1T1E1"); + break; + + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C4T1E1): + seq_puts(m, "wanPCI-C4T1E1"); + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C2T1E1): + seq_puts(m, "wanPCI-C2T1E1"); + break; + case SBE_BOARD_ID(PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_WANPCI_C1T1E1): + seq_puts(m, "wanPCI-C1T1E1"); + break; + + default: + seq_puts(m, "unknown"); + break; + } + + seq_printf(m, " [%08X]\n", bip->brd_id); + + seq_printf(m, "Board Number: %d\n", bip->brdno); + seq_printf(m, "Hardware ID: 0x%02X\n", ci->hdw_bid); + seq_printf(m, "Board SN: %06X\n", bip->brd_sn); + seq_printf(m, "Board MAC: %pMF\n", bip->brd_mac_addr); + seq_printf(m, "Ports: %d\n", ci->max_port); + seq_printf(m, "Channels: %d\n", bip->brd_chan_cnt); +#if 1 + seq_printf(m, "Interface: %s -> %s\n", + bip->first_iname, bip->last_iname); +#else + seq_printf(m, "Interface: <not available> 1st %p lst %p\n", + bip->first_iname, bip->last_iname); +#endif + + switch (bip->brd_pci_speed) { + case BINFO_PCI_SPEED_33: + spd = "33Mhz"; + break; + case BINFO_PCI_SPEED_66: + spd = "66Mhz"; + break; + default: + spd = "<not available>"; + break; + } + seq_printf(m, "PCI Bus Speed: %s\n", spd); + +#ifdef SBE_PMCC4_ENABLE + { + extern int cxt1e1_max_mru; +#if 0 + extern int max_chans_used; + extern int cxt1e1_max_mtu; +#endif + extern int max_rxdesc_used, max_txdesc_used; + + seq_printf(m, "\ncxt1e1_max_mru: %d\n", cxt1e1_max_mru); +#if 0 + seq_printf(m, "\nmax_chans_used: %d\n", max_chans_used); + seq_printf(m, "cxt1e1_max_mtu: %d\n", cxt1e1_max_mtu); +#endif + seq_printf(m, "max_rxdesc_used: %d\n", max_rxdesc_used); + seq_printf(m, "max_txdesc_used: %d\n", max_txdesc_used); + } +#endif + + kfree(bip); + + pr_devel(">> proc_fs: finished\n"); + return 0; +} + +/* + * seq_file wrappers for procfile show routines. + */ +static int sbecom_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, sbecom_proc_get_sbe_info, PDE_DATA(inode)); +} + +static const struct file_operations sbecom_proc_fops = { + .open = sbecom_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* + * Initialize the /proc subsystem for the specific SBE driver + */ +int __init sbecom_proc_brd_init(ci_t *ci) +{ + char dir[7 + SBE_IFACETMPL_SIZE + 1]; + + snprintf(dir, sizeof(dir), "driver/%s", ci->devname); + ci->dir_dev = proc_mkdir(dir, NULL); + if (!ci->dir_dev) { + pr_err("Unable to create directory /proc/driver/%s\n", ci->devname); + goto fail; + } + + if (!proc_create_data("info", S_IFREG | S_IRUGO, ci->dir_dev, + &sbecom_proc_fops, ci)) { + pr_err("Unable to create entry /proc/driver/%s/info\n", ci->devname); + goto fail; + } + return 0; + +fail: + sbecom_proc_brd_cleanup(ci); + return 1; +} diff --git a/drivers/staging/cxt1e1/sbeproc.h b/drivers/staging/cxt1e1/sbeproc.h new file mode 100644 index 00000000000..37285df359c --- /dev/null +++ b/drivers/staging/cxt1e1/sbeproc.h @@ -0,0 +1,42 @@ +#ifndef _INC_SBEPROC_H_ +#define _INC_SBEPROC_H_ + +/*----------------------------------------------------------------------------- + * sbeproc.h - + * + * Copyright (C) 2004-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + *----------------------------------------------------------------------------- + */ + + +#ifdef CONFIG_PROC_FS +void sbecom_proc_brd_cleanup (ci_t *); +int __init sbecom_proc_brd_init (ci_t *); + +#else + +static inline void sbecom_proc_brd_cleanup(ci_t *ci) +{ +} + +static inline int __init sbecom_proc_brd_init(ci_t *ci) +{ + return 0; +} + +#endif /*** CONFIG_PROC_FS ***/ + +#endif /*** _INC_SBEPROC_H_ ***/ diff --git a/drivers/staging/cxt1e1/sbew_ioc.h b/drivers/staging/cxt1e1/sbew_ioc.h new file mode 100644 index 00000000000..e1e5bfc9ad3 --- /dev/null +++ b/drivers/staging/cxt1e1/sbew_ioc.h @@ -0,0 +1,81 @@ +#ifndef _INC_SBEWIOC_H_ +#define _INC_SBEWIOC_H_ + +/*----------------------------------------------------------------------------- + * sbew_ioc.h - + * + * Copyright (C) 2002-2005 SBE, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For further information, contact via email: support@sbei.com + * SBE, Inc. San Ramon, California U.S.A. + * + *----------------------------------------------------------------------------- + */ + +#include <linux/ioctl.h> + +#define SBE_LOCKFILE "/tmp/.sbewan.LCK" + +#define SBE_IOC_COOKIE 0x19780926 +#define SBE_IOC_MAGIC ('s') + +/* IOW write - data has to go into driver from application */ +/* IOR read - data has to be returned to application from driver */ + +/* + * Note: for an IOWR Ioctl, the read and write data do not have to + * be the same size, but the entity declared within the IOC must be + * the larger of the two. + */ + +#define SBE_IOC_LOGLEVEL _IOW(SBE_IOC_MAGIC, 0x00, int) +#define SBE_IOC_CHAN_NEW _IOW(SBE_IOC_MAGIC, 0x01, int) /* unused */ +#define SBE_IOC_CHAN_UP _IOW(SBE_IOC_MAGIC, 0x02, int) /* unused */ +#define SBE_IOC_CHAN_DOWN _IOW(SBE_IOC_MAGIC, 0x03, int) /* unused */ +#define SBE_IOC_CHAN_GET _IOWR(SBE_IOC_MAGIC, 0x04, struct sbecom_chan_param) +#define SBE_IOC_CHAN_SET _IOW(SBE_IOC_MAGIC, 0x05, struct sbecom_chan_param) +#define SBE_IOC_CHAN_GET_STAT _IOWR(SBE_IOC_MAGIC, 0x06, struct sbecom_chan_stats) +#define SBE_IOC_CHAN_DEL_STAT _IOW(SBE_IOC_MAGIC, 0x07, int) +#define SBE_IOC_PORTS_ENABLE _IOW(SBE_IOC_MAGIC, 0x0A, int) +#define SBE_IOC_PORT_GET _IOWR(SBE_IOC_MAGIC, 0x0C, struct sbecom_port_param) +#define SBE_IOC_PORT_SET _IOW(SBE_IOC_MAGIC, 0x0D, struct sbecom_port_param) +#define SBE_IOC_READ_VEC _IOWR(SBE_IOC_MAGIC, 0x10, struct sbecom_wrt_vec) +#define SBE_IOC_WRITE_VEC _IOWR(SBE_IOC_MAGIC, 0x11, struct sbecom_wrt_vec) +#define SBE_IOC_GET_SN _IOR(SBE_IOC_MAGIC, 0x12, u_int32_t) +#define SBE_IOC_RESET_DEV _IOW(SBE_IOC_MAGIC, 0x13, int) +#define SBE_IOC_FRAMER_GET _IOWR(SBE_IOC_MAGIC, 0x14, struct sbecom_framer_param) +#define SBE_IOC_FRAMER_SET _IOW(SBE_IOC_MAGIC, 0x15, struct sbecom_framer_param) +#define SBE_IOC_CARD_GET _IOR(SBE_IOC_MAGIC, 0x20, struct sbecom_card_param) +#define SBE_IOC_CARD_SET _IOW(SBE_IOC_MAGIC, 0x21, struct sbecom_card_param) +#define SBE_IOC_CARD_GET_STAT _IOR(SBE_IOC_MAGIC, 0x22, struct temux_card_stats) +#define SBE_IOC_CARD_DEL_STAT _IO(SBE_IOC_MAGIC, 0x23) +#define SBE_IOC_CARD_CHAN_STAT _IOR(SBE_IOC_MAGIC, 0x24, struct sbecom_chan_stats) +#define SBE_IOC_CARD_BLINK _IOW(SBE_IOC_MAGIC, 0x30, int) +#define SBE_IOC_DRVINFO_GET _IOWR(SBE_IOC_MAGIC, 0x31, struct sbe_drv_info) +#define SBE_IOC_BRDINFO_GET _IOR(SBE_IOC_MAGIC, 0x32, struct sbe_brd_info) +#define SBE_IOC_IID_GET _IOWR(SBE_IOC_MAGIC, 0x33, struct sbe_iid_info) +#define SBE_IOC_BRDADDR_GET _IOWR(SBE_IOC_MAGIC, 0x34, struct sbe_brd_addr) + +#ifdef NOT_YET_COMMON +#define SBE_IOC_TSIOC_GET _IOWR(SBE_IOC_MAGIC, 0x16, struct wanc1t3_ts_param) +#define SBE_IOC_TSIOC_SET _IOW(SBE_IOC_MAGIC, 0x17, struct wanc1t3_ts_param) +#endif + +/* + * Restrict SBE_IOC_WRITE_VEC & READ_VEC to a single parameter pair, application + * then must issue multiple Ioctls for large blocks of contiguous data. + */ + +#define SBE_IOC_MAXVEC 1 + +#endif /*** _INC_SBEWIOC_H_ ***/ |
