📄 comx-hw-munich.c
字号:
/* * Hardware-level driver for the SliceCOM board for Linux kernels 2.4.X * * Current maintainer / latest changes: Pasztor Szilard <don@itc.hu> * * Original author: Bartok Istvan <bartoki@itc.hu> * Based on skeleton by Tivadar Szemethy <tiv@itc.hu> * * 0.51: * - port for 2.4.x * - clean up some code, make it more portable * - busted direct hardware access through mapped memory * - fix a possible race * - prevent procfs buffer overflow * * 0.50: * - support for the pcicom board, lots of rearrangements * - handle modem status lines * * 0.50a: * - fix for falc version 1.0 * * 0.50b: T&t * - fix for bad localbus */#define VERSION "0.51"#define VERSIONSTR "SliceCOM v" VERSION ", 2002/01/07\n"#include <linux/config.h>#include <linux/ctype.h>#include <linux/module.h>#include <linux/version.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/netdevice.h>#include <linux/proc_fs.h>#include <asm/delay.h>#include <asm/types.h>#include <asm/uaccess.h>#include <asm/io.h>#include <linux/ioport.h>#include <linux/pci.h>#include <linux/init.h>#define COMX_NEW#ifndef COMX_NEW#include "../include/comx.h"#include "../include/munich32x.h"#include "../include/falc-lh.h"#else#include "comx.h"#include "munich32x.h"#include "falc-lh.h"#endifMODULE_AUTHOR("Bartok Istvan <bartoki@itc.hu>, Gergely Madarasz <gorgo@itc.hu>, Szilard Pasztor <don@itc.hu>");MODULE_DESCRIPTION("Hardware-level driver for the SliceCOM and PciCOM (WelCOM) adapters");MODULE_LICENSE("GPL");/* * TODO: az ilyenek a comxhw.h -ban szoktak lenni, idovel menjenek majd oda: */#define FILENAME_BOARDNUM "boardnum" /* /proc/comx/comx0.1/boardnum */#define FILENAME_TIMESLOTS "timeslots" /* /proc/comx/comx0.1/timeslots */#define FILENAME_FRAMING "framing" /* /proc/comx/comx0.1/framing */#define FILENAME_LINECODE "linecode" /* /proc/comx/comx0.1/linecode */#define FILENAME_CLOCK_SOURCE "clock_source" /* /proc/comx/comx0.1/clock_source */#define FILENAME_LOOPBACK "loopback" /* /proc/comx/comx0.1/loopback */#define FILENAME_REG "reg" /* /proc/comx/comx0.1/reg */#define FILENAME_LBIREG "lbireg" /* /proc/comx/comx0.1/lbireg */#define SLICECOM_BOARDNUM_DEFAULT 0#define SLICECOM_FRAMING_CRC4 1#define SLICECOM_FRAMING_NO_CRC4 2#define SLICECOM_FRAMING_DEFAULT SLICECOM_FRAMING_CRC4#define SLICECOM_LINECODE_HDB3 1#define SLICECOM_LINECODE_AMI 2#define SLICECOM_LINECODE_DEFAULT SLICECOM_LINECODE_HDB3#define SLICECOM_CLOCK_SOURCE_LINE 1#define SLICECOM_CLOCK_SOURCE_INTERNAL 2#define SLICECOM_CLOCK_SOURCE_DEFAULT SLICECOM_CLOCK_SOURCE_LINE#define SLICECOM_LOOPBACK_NONE 1#define SLICECOM_LOOPBACK_LOCAL 2#define SLICECOM_LOOPBACK_REMOTE 3#define SLICECOM_LOOPBACK_DEFAULT SLICECOM_LOOPBACK_NONE#define MUNICH_VIRT(addr) (void *)(&bar1[addr])struct slicecom_stringtable{ char *name; int value;};/* A convention: keep "default" the last not NULL when reading from /proc, "error" is an indication that something went wrong, we have an undefined value */struct slicecom_stringtable slicecom_framings[] ={ {"crc4", SLICECOM_FRAMING_CRC4}, {"no-crc4", SLICECOM_FRAMING_NO_CRC4}, {"default", SLICECOM_FRAMING_DEFAULT}, {"error", 0}};struct slicecom_stringtable slicecom_linecodes[] ={ {"hdb3", SLICECOM_LINECODE_HDB3}, {"ami", SLICECOM_LINECODE_AMI}, {"default", SLICECOM_LINECODE_DEFAULT}, {"error", 0}};struct slicecom_stringtable slicecom_clock_sources[] ={ {"line", SLICECOM_CLOCK_SOURCE_LINE}, {"internal", SLICECOM_CLOCK_SOURCE_INTERNAL}, {"default", SLICECOM_CLOCK_SOURCE_DEFAULT}, {"error", 0}};struct slicecom_stringtable slicecom_loopbacks[] ={ {"none", SLICECOM_LOOPBACK_NONE}, {"local", SLICECOM_LOOPBACK_LOCAL}, {"remote", SLICECOM_LOOPBACK_REMOTE}, {"default", SLICECOM_LOOPBACK_DEFAULT}, {"error", 0}};/* * Some tunable values... * * Note: when tuning values which change the length of text in * /proc/comx/comx[n]/status, keep in mind that it must be shorter then * PAGESIZE ! */#define MAX_BOARDS 4 /* ezzel 4 kartya lehet a gepben: 0..3 */#define RX_DESC_MAX 8 /* Rx ring size, must be >= 4 */#define TX_DESC_MAX 4 /* Tx ring size, must be >= 2 */ /* a sokkal hosszabb Tx ring mar ronthatja a nem-FIFO packet */ /* schedulerek (fair queueing, stb.) hatekonysagat. */#define MAX_WORK 10 /* TOD: update the info max. ennyi-1 esemenyt dolgoz fel egy interrupt hivasnal *//* * These are tunable too, but don't touch them without fully understanding what is happening */#define UDELAY 20 /* We wait UDELAY usecs with disabled interrupts before and */ /* after each command to avoid writing into each other's */ /* ccb->action_spec. A _send_packet nem var, mert azt az */ /* _interrupt()-bol is meghivhatja a LINE_tx() *//* * Just to avoid warnings about implicit declarations: */static int MUNICH_close(struct net_device *dev);static struct comx_hardware slicecomhw;static struct comx_hardware pcicomhw;static unsigned long flags;static spinlock_t mister_lock = SPIN_LOCK_UNLOCKED;typedef volatile struct /* Time Slot Assignment */{ u32 rxfillmask:8, // ----------------------------+------+ // | | rxchannel:5, // ----------------------+---+ | | rti:1, // ---------------------+| | | | res2:2, // -------------------++|| | | | // |||| | | | txfillmask:8, // ----------+------+ |||| | | | // | | |||| | | | txchannel:5, // ----+---+ | | |||| | | | tti:1, // ---+| | | | |||| | | | res1:2; // -++|| | | | |||| | | | // 3 2 1 // 10987654 32109876 54321098 76543210} timeslot_spec_t;typedef volatile struct /* Receive Descriptor */{ u32 zero1:16, no:13, hi:1, hold:1, zero2:1; u32 next; u32 data; u32 zero3:8, status:8, bno:13, zero4:1, c:1, fe:1;} rx_desc_t;typedef volatile struct /* Transmit Descriptor */{ u32 fnum:11, csm:1, no13:1, zero1:2, v110:1, no:13, hi:1, hold:1, fe:1; u32 next; u32 data;} tx_desc_t;typedef volatile struct /* Channel Specification */{ u32 iftf:1, mode:2, fa:1, trv:2, crc:1, inv:1, cs:1, tflag:7, ra:1, ro:1, th:1, ta:1, to:1, ti:1, ri:1, nitbs:1, fit:1, fir:1, re:1, te:1, ch:1, ifc:1, sfe:1, fe2:1; u32 frda; u32 ftda; u32 itbs:6, zero1:26;} channel_spec_t;typedef volatile struct /* Configuration Control Block */{ u32 action_spec; u32 reserved1; u32 reserved2; timeslot_spec_t timeslot_spec[32]; channel_spec_t channel_spec[32]; u32 current_rx_desc[32]; u32 current_tx_desc[32]; u32 csa; /* Control Start Address. CSA = *CCBA; CCB = *CSA */ /* MUNICH does it like: CCB = *( *CCBA ) */} munich_ccb_t;typedef volatile struct /* Entry in the interrupt queue */{ u32 all;} munich_intq_t;#define MUNICH_INTQLEN 63 /* Rx/Tx Interrupt Queue Length (not the real len, but the TIQL/RIQL value) */#define MUNICH_INTQMAX ( 16*(MUNICH_INTQLEN+1) ) /* Rx/Tx/Periph Interrupt Queue size in munich_intq_t's */#define MUNICH_INTQSIZE ( 4*MUNICH_INTQMAX ) /* Rx/Tx/Periph Interrupt Queue size in bytes */#define MUNICH_PIQLEN 4 /* Peripheral Interrupt Queue Length. Unlike the RIQL/TIQL, */#define MUNICH_PIQMAX ( 4*MUNICH_PIQLEN ) /* PIQL register needs it like this */#define MUNICH_PIQSIZE ( 4*MUNICH_PIQMAX )typedef volatile u32 vol_u32; /* TOD: ezek megszunnek ha atirom readw()/writew()-re - k閟z */typedef volatile u8 vol_u8;typedef volatile struct /* counters of E1-errors and errored seconds, see rfc2495 */{ /* use here only unsigned ints, we depend on it when calculating the sum for the last N intervals */ unsigned line_code_violations, /* AMI: bipolar violations, HDB3: hdb3 violations */ path_code_violations, /* FAS errors and CRC4 errors */ e_bit_errors, /* E-Bit Errors (the remote side received from us with CRC4-error) */ slip_secs, /* number of seconds with (receive) Controlled Slip(s) */ fr_loss_secs, /* number of seconds an Out Of Frame defect was detected */ line_err_secs, /* number of seconds with one or more Line Code Violations */ degraded_mins, /* Degraded Minute - the estimated error rate is >1E-6, but <1E-3 */ errored_secs, /* Errored Second - at least one of these happened: - Path Code Violation - Out Of Frame defect - Slip - receiving AIS - not incremented during an Unavailable Second */ bursty_err_secs, /* Bursty Errored Second: (rfc2495 says it does not apply to E1) - Path Code Violations >1, but <320 - not a Severely Errored Second - no AIS - not incremented during an Unavailabla Second */ severely_err_secs, /* Severely Errored Second: - CRC4: >=832 Path COde Violations || >0 Out Of Frame defects - noCRC4: >=2048 Line Code Violations - not incremented during an Unavailable Second */ unavail_secs; /* number of Unavailable Seconds. Unavailable state is said after: - 10 contiguous Severely Errored Seconds - or RAI || AIS || LOF || LOS - (any) loopback has been set */ /* * we do not strictly comply to the rfc: we do not retroactively reduce errored_secs, * bursty_err_secs, severely_err_secs when 'unavailable state' is reached */} e1_stats_t;typedef volatile struct /* ezek board-adatok, nem lehetnek a slicecom_privdata -ban */{ int use_count; /* num. of interfaces using the board */ int irq; /* a kartya irq-ja. belemasoljuk a dev->irq -kba is, de csak hogy */ /* szebb legyen az ifconfig outputja */ /* ha != 0, az azt jelenti hogy az az irq most nekunk sikeresen */ /* le van foglalva */ struct pci_dev *pci; /* a kartya PCI strukturaja. NULL, ha nincs kartya */ u32 *bar1; /* pci->base_address[0] ioremap()-ed by munich_probe(), */ /* on x86 can be used both as a bus or virtual address. */ /* These are the Munich's registers */ u8 *lbi; /* pci->base_address[1] ioremap()-ed by munich_probe(), */ /* this is a 256-byte range, the start of the LBI on the board */ munich_ccb_t *ccb; /* virtual address of CCB */ munich_intq_t *tiq; /* Tx Interrupt Queue */ munich_intq_t *riq; /* Rx Interrupt Queue */ munich_intq_t *piq; /* Peripheral Interrupt Queue (FALC interrupts arrive here) */ int tiq_ptr, /* A 'current' helyek a tiq/riq/piq -ban. */ riq_ptr, /* amikor feldolgoztam az interruptokat, a legelso ures */ piq_ptr; /* interrupt_information szora mutatnak. */ struct net_device *twins[32]; /* MUNICH channel -> network interface assignment */ unsigned long lastcheck; /* When were the Rx rings last checked. Time in jiffies */ struct timer_list modemline_timer; char isx21; char lineup; char framing; /* a beallitasok tarolasa */ char linecode; char clock_source; char loopback; char devname[30]; /* what to show in /proc/interrupts */ unsigned histogram[MAX_WORK]; /* number of processed events in the interrupt loop */ unsigned stat_pri_races; /* number of special events, we try to handle them */ unsigned stat_pti_races; unsigned stat_pri_races_missed; /* when it can not be handled, because of MAX_WORK */ unsigned stat_pti_races_missed;#define SLICECOM_BOARD_INTERVALS_SIZE 97 e1_stats_t intervals[SLICECOM_BOARD_INTERVALS_SIZE]; /* E1 line statistics */ unsigned current_interval; /* pointer to the current interval */ unsigned elapsed_seconds; /* elapsed seconds from the start of the current interval */ unsigned ses_seconds; /* counter of contiguous Severely Errored Seconds */ unsigned is_unavailable; /* set to 1 after 10 contiguous Severely Errored Seconds */ unsigned no_ses_seconds; /* contiguous Severely Error -free seconds in unavail state */ unsigned deg_elapsed_seconds; /* for counting the 'Degraded Mins' */ unsigned deg_cumulated_errors; struct module *owner; /* pointer to our module to avoid module load races */} munich_board_t;struct slicecom_privdata{ int busy; /* transmitter busy - number of packets in the Tx ring */ int channel; /* Munich logical channel ('channel-group' in Cisco) */ unsigned boardnum; u32 timeslots; /* i-th bit means i-th timeslot is our */ int tx_ring_hist[TX_DESC_MAX]; /* histogram: number of packets in Tx ring when _send_packet is called */ tx_desc_t tx_desc[TX_DESC_MAX]; /* the ring of Tx descriptors */ u8 tx_data[TX_DESC_MAX][TXBUFFER_SIZE]; /* buffers for data to transmit */ int tx_desc_ptr; /* hanyadik descriptornal tartunk a beirassal */ /* ahol ez all, oda irtunk utoljara */ rx_desc_t rx_desc[RX_DESC_MAX]; /* the ring of Rx descriptors */ u8 rx_data[RX_DESC_MAX][RXBUFFER_SIZE]; /* buffers for received data */ int rx_desc_ptr; /* hanyadik descriptornal tartunk az olvasassal */ int rafutott;};static u32 reg, reg_ertek; /* why static: don't write stack trash into regs if strtoul() fails */static u32 lbireg;static u8 lbireg_ertek; /* why static: don't write stack trash into regs if strtoul() fails */static munich_board_t slicecom_boards[MAX_BOARDS];static munich_board_t pcicom_boards[MAX_BOARDS];/* * Reprogram Idle Channel Registers in the FALC - send special code in not used channels * Should be called from the open and close, when the timeslot assignment changes */void rework_idle_channels(struct net_device *dev){ struct comx_channel *ch = dev->priv; struct slicecom_privdata *hw = ch->HW_privdata; munich_board_t *board = slicecom_boards + hw->boardnum; munich_ccb_t *ccb = board->ccb; u8 *lbi = board->lbi; int i, j, tmp; spin_lock_irqsave(&mister_lock, flags); for (i = 0; i < 4; i++) { tmp = 0xFF; for (j = 0; j < 8; j++) if (ccb->timeslot_spec[8 * i + j].tti == 0) tmp ^= (0x80 >> j); writeb(tmp, lbi + 0x30 + i); } spin_unlock_irqrestore(&mister_lock, flags);}/* * Set PCM framing - /proc/comx/comx0/framing */void slicecom_set_framing(int boardnum, int value)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -