Commit 14b596c9 authored by Kristina Martšenko's avatar Kristina Martšenko Committed by Greg Kroah-Hartman

staging: cxt1e1: remove driver

Remove the driver as it hasn't been cleaned up and it doesn't look like
anyone is going to work on it anymore. This can be reverted if someone
wants to work to fix the remaining issues the driver has.
Signed-off-by: default avatarKristina Martšenko <kristina.martsenko@gmail.com>
Cc: Bob Beers <bob.beers@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 19b1e769
......@@ -72,8 +72,6 @@ source "drivers/staging/sep/Kconfig"
source "drivers/staging/iio/Kconfig"
source "drivers/staging/cxt1e1/Kconfig"
source "drivers/staging/xgifb/Kconfig"
source "drivers/staging/tidspbridge/Kconfig"
......
......@@ -30,7 +30,6 @@ obj-$(CONFIG_VT6656) += vt6656/
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_CXT1E1) += cxt1e1/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_TIDSPBRIDGE) += tidspbridge/
obj-$(CONFIG_ACPI_QUICKSTART) += quickstart/
......
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.
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
/* 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 ***/
#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_ */
/*-----------------------------------------------------------------------------
* 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 ***/
#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_ */
/* 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 ***/
/* 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 ***/
#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_ ***/
/* 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 ***/
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_locked(mch_t *ch)
{
struct mdesc *m;
u_int32_t status;
int n;
#ifdef RLD_DUMP_BUFDATA
u_int32_t *dp;
int len = 0;
#endif
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");
return 0;
}
static int
musycc_dump_rxbuffer_ring(mch_t *ch)
{
unsigned long flags = 0;
int ret;
spin_lock_irqsave(&ch->ch_rxlock, flags);
ret = musycc_dump_rxbuffer_ring_locked(ch);
spin_unlock_irqrestore(&ch->ch_rxlock, flags);
return ret;
}
static int
musycc_dump_txbuffer_ring_locked(mch_t *ch)
{
struct mdesc *m;
u_int32_t status;
int n;
#ifdef RLD_DUMP_BUFDATA
u_int32_t *dp;
int len = 0;
#endif
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");
return 0;
}
static int
musycc_dump_txbuffer_ring(mch_t *ch)
{
unsigned long flags = 0;
int ret;
spin_lock_irqsave(&ch->ch_txlock, flags);
ret = musycc_dump_txbuffer_ring_locked(ch);
spin_unlock_irqrestore(&ch->ch_txlock, flags);
return ret;
}
/*
* 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);
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);
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); /* 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_locked(ch);
}
#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_locked(ch);
}
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_locked(ch);
}
#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_locked(ch);
#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 ***/
#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 ***/
/* 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;
}
#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 ***/
#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);
void 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_ */
#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_ */
#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_ ***/
/*-----------------------------------------------------------------------------
* 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 ***/
#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_ */
#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"
#include "sbecom_inline_linux.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_ */
#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;
#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_ ***/
#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_ ***/
#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_ ***/
/* 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.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 ***/
/* 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 ***/
/* 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;
}
#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_ ***/
#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_ ***/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment