Commit 14003981 authored by Szilárd Pásztor's avatar Szilárd Pásztor Committed by Jeff Garzik

Add new slicecom/munish WAN driver.

parent fa15f5ec
...@@ -24,6 +24,8 @@ HiCOMX (2x2Mbps intelligent board) ...@@ -24,6 +24,8 @@ HiCOMX (2x2Mbps intelligent board)
LoCOMX (1x512 kbps passive board) LoCOMX (1x512 kbps passive board)
MixCOM (1x512 or 2x512kbps passive board with a hardware watchdog an MixCOM (1x512 or 2x512kbps passive board with a hardware watchdog an
optional BRI interface and optional flashROM (1-32M)) optional BRI interface and optional flashROM (1-32M))
SliceCOM (1x2Mbps channelized E1 board)
PciCOM (X21)
At the moment of writing this document, the (Cisco)-HDLC, LAPB, SyncPPP and At the moment of writing this document, the (Cisco)-HDLC, LAPB, SyncPPP and
Frame Relay (DTE, rfc1294 IP encapsulation with partially implemented Q933a Frame Relay (DTE, rfc1294 IP encapsulation with partially implemented Q933a
...@@ -72,7 +74,7 @@ EXAMPLE ...@@ -72,7 +74,7 @@ EXAMPLE
To create the interface 'comx0' which is the first channel of a COMX card: To create the interface 'comx0' which is the first channel of a COMX card:
insmod comx insmod comx
# insmod comx-hw-comx ; insmod comx-proto-hdlc (these are usually # insmod comx-hw-comx ; insmod comx-proto-ppp (these are usually
autoloaded if you use the kernel module loader) autoloaded if you use the kernel module loader)
mkdir /proc/comx/comx0 mkdir /proc/comx/comx0
...@@ -141,47 +143,45 @@ THE MIXCOM DRIVER ...@@ -141,47 +143,45 @@ THE MIXCOM DRIVER
The MixCOM board doesn't require firmware, the driver communicates with The MixCOM board doesn't require firmware, the driver communicates with
it through I/O ports. You can have three of these cards in one machine. it through I/O ports. You can have three of these cards in one machine.
THE HDLC LINE PROTOCOL DRIVER THE SLICECOM DRIVER
There's only one configurable parameter with this protocol: the 'keepalive' The SliceCOM board doesn't require firmware. You can have 4 of these cards
value. You can set this in seconds or set to 'off'. Agree with the administrator in one machine. The driver doesn't (yet) support shared interrupts, so
of your peer router on this setting. The default is 10 (seconds). you will need a separate IRQ line for every board.
Read linux/Documentation/networking/slicecom.txt for help on configuring
this adapter.
EXAMPLE THE HDLC/PPP LINE PROTOCOL DRIVER
(setting up hw parameters, see above) The HDLC/SyncPPP line protocol driver uses the kernel's built-in syncppp
echo hdlc >/proc/comx/comx0/protocol driver (syncppp.o). You don't have to manually select syncppp.o when building
echo 10 >/proc/comx/comx0/keepalive <- not necessary, 10 is the default the kernel, the dependencies compile it in automatically.
ifconfig comx0 1.2.3.4 pointopoint 5.6.7.8 netmask 255.255.255.255
THE PPP LINE PROTOCOL DRIVER
To use this driver, you have to have ppp-2.3.4, and have a modified version of
pppd (this pppd will work as async pppd to, the modifiactions merely relax
some restricions in order to be able to use non-async lines too.
If configured, this driver can use Van Jacobson TCP header compression (you'll
need the slhc.o module for this).
Additionally to use this protocol, enable async ppp in your kernel config, and
create the comx device special files in /dev. They're character special files
with major 88, and their names must be the same as their network interface
counterparts (i.e /dev/comx0 with minor 0 corresponds interface comx0 and so
on).
EXAMPLE EXAMPLE
(setting up hw parameters, see above)
# using HDLC:
echo hdlc >/proc/comx/comx0/protocol
echo 10 >/proc/comx/comx0/keepalive <- not necessary, 10 is the default
ifconfig comx0 1.2.3.4 pointopoint 5.6.7.8 netmask 255.255.255.255
(setting up hw parameters, see above) (setting up hw parameters, see above)
# using PPP:
echo ppp >/proc/comx/comx0/protocol echo ppp >/proc/comx/comx0/protocol
ifconfig comx0 up ifconfig comx0 up
pppd comx0 1.2.3.4:5.6.7.8 persist <- with this option pppd won't exit ifconfig comx0 1.2.3.4 pointopoint 5.6.7.8 netmask 255.255.255.255
when the line goes down
THE LAPB LINE PROTOCOL DRIVER THE LAPB LINE PROTOCOL DRIVER
For this, you'll need to configure LAPB support (See 'LAPB Data Link Driver' in For this, you'll need to configure LAPB support (See 'LAPB Data Link Driver' in
'Network options' section) into your kernel (thanks to Jonathan Naylor for his 'Network options' section) into your kernel (thanks to Jonathan Naylor for his
excellent implementation). excellent implementation).
comxlapb.o provides the following files in the appropriate directory comx-proto-lapb.o provides the following files in the appropriate directory
(the default values in parens): t1 (5), t2 (1), n2 (20), mode (DTE, STD) and (the default values in parens): t1 (5), t2 (1), n2 (20), mode (DTE, STD) and
window (7). Agree with the administrator of your peer router on these window (7). Agree with the administrator of your peer router on these
settings (most people use defaults, but you have to know if you are DTE or settings (most people use defaults, but you have to know if you are DTE or
...@@ -221,7 +221,7 @@ FURTHER /proc FILES ...@@ -221,7 +221,7 @@ FURTHER /proc FILES
boardtype: boardtype:
Type of the hardware. Valid values are: Type of the hardware. Valid values are:
'comx', 'hicomx', 'locomx', 'cmx'. 'comx', 'hicomx', 'locomx', 'cmx', 'slicecom'.
protocol: protocol:
Data-link protocol on this channel. Can be: HDLC, LAPB, PPP, FRAD Data-link protocol on this channel. Can be: HDLC, LAPB, PPP, FRAD
......
SliceCOM adapter felhasznaloi dokumentacioja - 0.51 verziohoz
Bartk Istvn <bartoki@itc.hu>
Utolso modositas: Wed Aug 29 17:26:58 CEST 2001
-----------------------------------------------------------------
Hasznalata:
Forditas:
Code maturity level options
[*] Prompt for development and/or incomplete code/drivers
Network device support
Wan interfaces
<M> MultiGate (COMX) synchronous
<M> Support for MUNICH based boards: SliceCOM, PCICOM (NEW)
<M> Support for HDLC and syncPPP...
A modulok betoltese:
modprobe comx
modprobe comx-proto-ppp # a Cisco-HDLC es a SyncPPP protokollt is
# ez a modul adja
modprobe comx-hw-munich # a modul betoltodeskor azonnal jelent a
# syslogba a detektalt kartyakrol
Konfiguralas:
# Ezen az interfeszen Cisco-HDLC vonali protokoll fog futni
# Az interfeszhez rendelt idoszeletek: 1,2 (128 kbit/sec-es vonal)
# (a G.703 keretben az elso adatot vivo idoszelet az 1-es)
#
mkdir /proc/comx/comx0.1/
echo slicecom >/proc/comx/comx0.1/boardtype
echo hdlc >/proc/comx/comx0.1/protocol
echo 1 2 >/proc/comx/comx0.1/timeslots
# Ezen az interfeszen SyncPPP vonali protokoll fog futni
# Az interfeszhez rendelt idoszelet: 3 (64 kbit/sec-es vonal)
#
mkdir /proc/comx/comx0.2/
echo slicecom >/proc/comx/comx0.2/boardtype
echo ppp >/proc/comx/comx0.2/protocol
echo 3 >/proc/comx/comx0.2/timeslots
...
ifconfig comx0.1 up
ifconfig comx0.2 up
-----------------------------------------------------------------
A COMX driverek default 20 csomagnyi transmit queue-t rendelnek a halozati
interfeszekhez. WAN halozatokban ennel hosszabbat is szokas hasznalni
(20 es 100 kozott), hogy a vonal kihasznaltsaga nagy terheles eseten jobb
legyen (bar ezzel megno a varhato kesleltetes a csomagok sorban allasa miatt):
# ifconfig comx0 txqueuelen 50
Ezt a beallitasi lehetoseget csak az ujabb disztribuciok ifconfig parancsa
tamogatja (amik mar a 2.2 kernelekhez keszultek, mint a RedHat 6.1 vagy a
Debian 2.2).
A 2.1-es Debian disztribuciohoz a http://www.debian.org/~rcw/2.2/netbase/
cimrol toltheto le ujabb netbase csomag, ami mar ilyet tamogato ifconfig
parancsot tartalmaz. Bovebben a 2.2 kernel hasznalatarol Debian 2.1 alatt:
http://www.debian.org/releases/stable/running-kernel-2.2
-----------------------------------------------------------------
A kartya LED-jeinek jelentese:
piros - eg, ha Remote Alarm-ot kuld a tuloldal
zold - eg, ha a vett jelben megtalalja a keretszinkront
Reszletesebben:
piros: zold: jelentes:
- - nincs keretszinkron (nincs jel, vagy rossz a jel)
- eg "minden rendben"
eg eg a vetel OK, de a tuloldal Remote Alarm-ot kuld
eg - ez nincs ertelmezve, egyelore funkcio nelkul
-----------------------------------------------------------------
Reszletesebb leiras a hardver beallitasi lehetosegeirol:
Az altalanos,- es a protokoll-retegek beallitasi lehetosegeirol a 'comx.txt'
fajlban leirtak SliceCOM kartyanal is ervenyesek, itt csak a hardver-specifikus
beallitasi lehetosegek vannak osszefoglalva:
Konfiguralasi interfesz a /proc/comx/ alatt:
Minden timeslot-csoportnak kulon comx* interfeszt kell letrehozni mkdir-rel:
comx0, comx1, .. stb. Itt beallithato, hogy az adott interfesz hanyadik kartya
melyik timeslotja(i)bol alljon ossze. A Cisco-fele serial3:1 elnevezesek
(serial3:1 = a 3. kartyaban az 1-es idoszelet-csoport) Linuxon aliasing-ot
jelentenenek, ezert mi nem tudunk ilyen elnevezest hasznalni.
Tobb kartya eseten a comx0.1, comx0.2, ... vagy slice0.1, slice0.2 nevek
hasznalhatoak.
Tobb SliceCOM kartya is lehet egy gepben, de sajat interrupt kell mindegyiknek,
nem tud meg megosztott interruptot kezelni.
Az egesz kartyat erinto beallitasok:
Az ioport es irq beallitas nincs: amit a PCI BIOS kioszt a rendszernek,
azt hasznalja a driver.
comx0/boardnum - hanyadik SliceCOM kartya a gepben (a 'termeszetes' PCI
sorrendben ertve: ahogyan a /proc/pci-ban vagy az 'lspci'
kimeneteben megjelenik, altalaban az alaplapi PCI meghajto
aramkorokhoz kozelebb eso kartyak a kisebb sorszamuak)
Default: 0 (0-tol kezdodik a szamolas)
Bar a kovetkezoket csak egy-egy interfeszen allitjuk at, megis az egesz kartya
mukodeset egyszerre allitjak. A megkotes hogy csak UP-ban levo interfeszen
hasznalhatoak, azert van, mert kulonben nem vart eredmenyekre vezetne egy ilyen
paranccsorozat:
echo 0 >boardnum
echo internal >clock_source
echo 1 >boardnum
- Ez a 0-s board clock_source-at allitana at.
Ezek a beallitasok megmaradnak az osszes interfesz torlesekor, de torlodnek
a driver modul ki/betoltesekor.
comx0/clock_source - A Tx orajelforrasa, a Cisco-val hasonlatosra keszult.
Hasznalata:
papaya:# echo line >/proc/comx/comx0/clock_source
papaya:# echo internal >/proc/comx/comx0/clock_source
line - A Tx orajelet a vett adatfolyambol dekodolja, igyekszik
igazodni hozza. Ha nem lat orajelet az inputon, akkor
atall a sajat orajelgeneratorara.
internal - A Tx orajelet a sajat orajelgeneratora szolgaltatja.
Default: line
Normal osszeallitas eseten a tavkozlesi szolgaltato eszkoze
(pl. HDSL modem) adja az orajelet, ezert ez a default.
comx0/framing - A CRC4 ki/be kapcsolasa
A CRC4: 16 PCM keretet (A PCM keret az, amibe a 32 darab 64
kilobites csatorna van bemultiplexalva. Nem osszetevesztendo a HDLC
kerettel.) 2x8 -as csoportokra osztanak, es azokhoz 4-4 bites CRC-t
szamolnak. Elsosorban a vonal minosegenek a monitorozasara szolgal.
papaya:~# echo crc4 >/proc/comx/comx0/framing
papaya:~# echo no-crc4 >/proc/comx/comx0/framing
Default a 'crc4', a MATAV vonalak altalaban igy futnak. De ha nem
egyforma is a beallitas a vonal ket vegen, attol a forgalom altalaban
at tud menni.
comx0/linecode - A vonali kodolas beallitasa
papaya:~# echo hdb3 >/proc/comx/comx0/linecode
papaya:~# echo ami >/proc/comx/comx0/linecode
Default a 'hdb3', a MATAV vonalak igy futnak.
(az AMI kodolas igen ritka E1-es vonalaknal). Ha ez a beallitas nem
egyezik a vonal ket vegen, akkor elofordulhat hogy a keretszinkron
osszejon, de CRC4-hibak es a vonalakon atvitt adatokban is hibak
keletkeznek (amit a HDLC/SyncPPP szinten CRC-hibaval jelez)
comx0/reg - a kartya aramkoreinek, a MUNICH (reg) es a FALC (lbireg)
comx0/lbireg regisztereinek kozvetlen elerese. Hasznalata:
echo >reg 0x04 0x0 - a 4-es regiszterbe 0-t ir
echo >reg 0x104 - printk()-val kiirja a 4-es regiszter
tartalmat a syslogba.
WARNING: ezek csak a fejleszteshez keszultek, sok galibat
lehet veluk okozni!
comx0/loopback - A kartya G.703 jelenek a visszahurkolasara is van lehetoseg:
papaya:# echo none >/proc/comx/comx0/loopback
papaya:# echo local >/proc/comx/comx0/loopback
papaya:# echo remote >/proc/comx/comx0/loopback
none - nincs visszahurkolas, normal mukodes
local - a kartya a sajat maga altal adott jelet kapja vissza
remote - a kartya a kivulrol vett jelet adja kifele
Default: none
-----------------------------------------------------------------
Az interfeszhez (Cisco terminologiaban 'channel-group') kapcsolodo beallitasok:
comx0/timeslots - mely timeslotok (idoszeletek) tartoznak az adott interfeszhez.
papaya:~# cat /proc/comx/comx0/timeslots
1 3 4 5 6
papaya:~#
Egy timeslot megkeresese (hanyas interfeszbe tartozik nalunk):
papaya:~# grep ' 4' /proc/comx/comx*/timeslots
/proc/comx/comx0/timeslots:1 3 4 5 6
papaya:~#
Beallitasa:
papaya:~# echo '1 5 2 6 7 8' >/proc/comx/comx0/timeslots
A timeslotok sorrendje nem szamit, '1 3 2' ugyanaz mint az '1 2 3'.
Beallitashoz az adott interfesznek DOWN-ban kell lennie
(ifconfig comx0 down), de ugyanannak a kartyanak a tobbi interfesze
uzemelhet kozben.
Beallitaskor leellenorzi, hogy az uj timeslotok nem utkoznek-e egy
masik interfesz timeslotjaival. Ha utkoznek, akkor nem allitja at.
Mindig 10-es szamrendszerben tortenik a timeslotok ertelmezese, nehogy
a 08, 09 alaku felirast rosszul ertelmezze.
-----------------------------------------------------------------
Az interfeszek es a kartya allapotanak lekerdezese:
- A ' '-szel kezdodo sorok az eredeti kimenetet, a //-rel kezdodo sorok a
magyarazatot jelzik.
papaya:~$ cat /proc/comx/comx1/status
Interface administrative status is UP, modem status is UP, protocol is UP
Modem status changes: 0, Transmitter status is IDLE, tbusy: 0
Interface load (input): 978376 / 947808 / 951024 bits/s (5s/5m/15m)
(output): 978376 / 947848 / 951024 bits/s (5s/5m/15m)
Debug flags: none
RX errors: len: 22, overrun: 1, crc: 0, aborts: 0
buffer overrun: 0, pbuffer overrun: 0
TX errors: underrun: 0
Line keepalive (value: 10) status UP [0]
// Itt kezdodik a hardver-specifikus resz:
Controller status:
No alarms
// Alarm: hibajelzes:
//
// No alarms - minden rendben
//
// LOS - Loss Of Signal - nem erzekel jelet a bemeneten.
// AIS - Alarm Indication Signal - csak egymas utani 1-esek jonnek
// a bemeneten, a tuloldal igy is jelezheti hogy meghibasodott vagy
// nincs inicializalva.
// AUXP - Auxiliary Pattern Indication - 01010101.. sorozat jon a bemeneten.
// LFA - Loss of Frame Alignment - nincs keretszinkron
// RRA - Receive Remote Alarm - a tuloldal el, de hibat jelez.
// LMFA - Loss of CRC4 Multiframe Alignment - nincs CRC4-multikeret-szinkron
// NMF - No Multiframe alignment Found after 400 msec - ilyen alarm a no-crc4
// es crc4 keretezesek eseten nincs, lasd lentebb
//
// Egyeb lehetseges hibajelzesek:
//
// Transmit Line Short - a kartya ugy erzi hogy az adasi kimenete rovidre
// van zarva, ezert kikapcsolta az adast. (nem feltetlenul veszi eszre
// a kulso rovidzarat)
// A veteli oldal csomagjainak lancolt listai, debug celokra:
Rx ring:
rafutott: 0
lastcheck: 50845731, jiffies: 51314281
base: 017b1858
rx_desc_ptr: 0
rx_desc_ptr: 017b1858
hw_curr_ptr: 017b1858
06040000 017b1868 017b1898 c016ff00
06040000 017b1878 017b1e9c c016ff00
46040000 017b1888 017b24a0 c016ff00
06040000 017b1858 017b2aa4 c016ff00
// A kartyat hasznalo tobbi interfesz: a 0-s channel-group a comx1 interfesz,
// es az 1,2,...,16 timeslotok tartoznak hozza:
Interfaces using this board: (channel-group, interface, timeslots)
0 comx1: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 comx2: 17
2 comx3: 18
3 comx4: 19
4 comx5: 20
5 comx6: 21
6 comx7: 22
7 comx8: 23
8 comx9: 24
9 comx10: 25
10 comx11: 26
11 comx12: 27
12 comx13: 28
13 comx14: 29
14 comx15: 30
15 comx16: 31
// Hany esemenyt kezelt le a driver egy-egy hardver-interrupt kiszolgalasanal:
Interrupt work histogram:
hist[ 0]: 0 hist[ 1]: 2 hist[ 2]: 18574 hist[ 3]: 79
hist[ 4]: 14 hist[ 5]: 1 hist[ 6]: 0 hist[ 7]: 1
hist[ 8]: 0 hist[ 9]: 7
// Hany kikuldendo csomag volt mar a Tx-ringben amikor ujabb lett irva bele:
Tx ring histogram:
hist[ 0]: 2329 hist[ 1]: 0 hist[ 2]: 0 hist[ 3]: 0
// Az E1-interfesz hiba-szamlaloi, az rfc2495-nek megfeleloen:
// (kb. a Cisco routerek "show controllers e1" formatumaban: http://www.cisco.com/univercd/cc/td/doc/product/software/ios11/rbook/rinterfc.htm#xtocid25669126)
Data in current interval (91 seconds elapsed):
9516 Line Code Violations, 65 Path Code Violations, 2 E-Bit Errors
0 Slip Secs, 2 Fr Loss Secs, 2 Line Err Secs, 0 Degraded Mins
0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 11 Unavail Secs
Data in Interval 1 (15 minutes):
0 Line Code Violations, 0 Path Code Violations, 0 E-Bit Errors
0 Slip Secs, 0 Fr Loss Secs, 0 Line Err Secs, 0 Degraded Mins
0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 0 Unavail Secs
Data in last 4 intervals (1 hour):
0 Line Code Violations, 0 Path Code Violations, 0 E-Bit Errors
0 Slip Secs, 0 Fr Loss Secs, 0 Line Err Secs, 0 Degraded Mins
0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 0 Unavail Secs
Data in last 96 intervals (24 hours):
0 Line Code Violations, 0 Path Code Violations, 0 E-Bit Errors
0 Slip Secs, 0 Fr Loss Secs, 0 Line Err Secs, 0 Degraded Mins
0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 0 Unavail Secs
-----------------------------------------------------------------
Nehany kulonlegesebb beallitasi lehetoseg (idovel beepulhetnek majd a driverbe):
Ezekkel sok galibat lehet okozni, nagyon ovatosan kell oket hasznalni!
modified CRC-4, for improved interworking of CRC-4 and non-CRC-4
devices: (lasd page 107 es g706 Annex B)
lbireg[ 0x1b ] |= 0x08
lbireg[ 0x1c ] |= 0xc0
- ilyenkor ertelmezett az NMF - 'No Multiframe alignment Found after
400 msec' alarm.
FALC - a vonali meghajto IC
local loop - a sajat adasomat halljam vissza
remote loop - a kivulrol jovo adast adom vissza
Egy hibakeresesre hasznalhato dolog:
- 1-es timeslot local loop a FALC-ban: echo >lbireg 0x1d 0x21
- local loop kikapcsolasa: echo >lbireg 0x1d 0x00
SliceCOM adapter user's documentation - for the 0.51 driver version
Written by Bartók István <bartoki@itc.hu>
English translation: Lakatos György <gyuri@itc.hu>
Mon Dec 11 15:28:42 CET 2000
Last modified: Wed Aug 29 17:25:37 CEST 2001
-----------------------------------------------------------------
Usage:
Compiling the kernel:
Code maturity level options
[*] Prompt for development and/or incomplete code/drivers
Network device support
Wan interfaces
<M> MultiGate (COMX) synchronous
<M> Support for MUNICH based boards: SliceCOM, PCICOM (NEW)
<M> Support for HDLC and syncPPP...
Loading the modules:
modprobe comx
modprobe comx-proto-ppp # module for Cisco-HDLC and SyncPPP protocols
modprobe comx-hw-munich # the module logs information by the kernel
# about the detected boards
Configuring the board:
# This interface will use the Cisco-HDLC line protocol,
# the timeslices assigned are 1,2 (128 KiBit line speed)
# (the first data timeslice in the G.703 frame is no. 1)
#
mkdir /proc/comx/comx0.1/
echo slicecom >/proc/comx/comx0.1/boardtype
echo hdlc >/proc/comx/comx0.1/protocol
echo 1 2 >/proc/comx/comx0.1/timeslots
# This interface uses SyncPPP line protocol, the assigned
# is no. 3 (64 KiBit line speed)
#
mkdir /proc/comx/comx0.2/
echo slicecom >/proc/comx/comx0.2/boardtype
echo ppp >/proc/comx/comx0.2/protocol
echo 3 >/proc/comx/comx0.2/timeslots
...
ifconfig comx0.1 up
ifconfig comx0.2 up
-----------------------------------------------------------------
The COMX interfaces use a 10 packet transmit queue by default, however WAN
networks sometimes use bigger values (20 to 100), to utilize the line better
by large traffic (though the line delay increases because of more packets
join the queue).
# ifconfig comx0 txqueuelen 50
This option is only supported by the ifconfig command of the later
distributions, which came with 2.2 kernels, such as RedHat 6.1 or Debian 2.2.
You can download a newer netbase packet from
http://www.debian.org/~rcw/2.2/netbase/ for Debian 2.1, which has a new
ifconfig. You can get further information about using 2.2 kernel with
Debian 2.1 from http://www.debian.org/releases/stable/running-kernel-2.2
-----------------------------------------------------------------
The SliceCom LEDs:
red - on, if the interface is unconfigured, or it gets Remote Alarm-s
green - on, if the board finds frame-sync in the received signal
A bit more detailed:
red: green: meaning:
- - no frame-sync, no signal received, or signal SNAFU.
- on "Everything is OK"
on on Recepion is ok, but the remote end sends Remote Alarm
on - The interface is unconfigured
-----------------------------------------------------------------
A more detailed description of the hardware setting options:
The general and the protocol layer options described in the 'comx.txt' file
apply to the SliceCom as well, I only summarize the SliceCom hardware specific
settings below.
The '/proc/comx' configuring interface:
An interface directory should be created for every timeslot group with
'mkdir', e,g: 'comx0', 'comx1' etc. The timeslots can be assigned here to the
specific interface. The Cisco-like naming convention (serial3:1 - first
timeslot group of the 3rd. board) can't be used here, because these mean IP
aliasing in Linux.
You can give any meaningful name to keep the configuration clear;
e.g: 'comx0.1', 'comx0.2', 'comx1.1', comx1.2', if you have two boards
with two interfaces each.
Settings, which apply to the board:
Neither 'io' nor 'irq' settings required, the driver uses the resources
given by the PCI BIOS.
comx0/boardnum - board number of the SliceCom in the PC (using the 'natural'
PCI order) as listed in '/proc/pci' or the output of the
'lspci' command, generally the slots nearer to the motherboard
PCI driver chips have the lower numbers.
Default: 0 (the counting starts with 0)
Though the options below are to be set on a single interface, they apply to the
whole board. The restriction, to use them on 'UP' interfaces, is because the
command sequence below could lead to unpredicable results.
# echo 0 >boardnum
# echo internal >clock_source
# echo 1 >boardnum
The sequence would set the clock source of board 0.
These settings will persist after all the interfaces are cleared, but are
cleared when the driver module is unloaded and loaded again.
comx0/clock_source - source of the transmit clock
Usage:
# echo line >/proc/comx/comx0/clock_source
# echo internal >/proc/comx/comx0/clock_source
line - The Tx clock is being decoded if the input data stream,
if no clock seen on the input, then the board will use it's
own clock generator.
internal - The Tx clock is supplied by the builtin clock generator.
Default: line
Normally, the telecommunication company's end device (the HDSL
modem) provides the Tx clock, that's why 'line' is the default.
comx0/framing - Switching CRC4 off/on
CRC4: 16 PCM frames (The 32 64Kibit channels are multiplexed into a
PCM frame, nothing to do with HDLC frames) are divided into 2x8
groups, each group has a 4 bit CRC.
# echo crc4 >/proc/comx/comx0/framing
# echo no-crc4 >/proc/comx/comx0/framing
Default is 'crc4', the Hungarian MATAV lines behave like this.
The traffic generally passes if this setting on both ends don't match.
comx0/linecode - Setting the line coding
# echo hdb3 >/proc/comx/comx0/linecode
# echo ami >/proc/comx/comx0/linecode
Default a 'hdb3', MATAV lines use this.
(AMI coding is rarely used with E1 lines). Frame sync may occur, if
this setting doesn't match the other end's, but CRC4 and data errors
will come, which will result in CRC errors on HDLC/SyncPPP level.
comx0/reg - direct access to the board's MUNICH (reg) and FALC (lbireg)
comx0/lbireg circuit's registers
# echo >reg 0x04 0x0 - write 0 to register 4
# echo >reg 0x104 - write the contents of register 4 with
printk() to syslog
WARNING! These are only for development purposes, messing with this will
result much trouble!
comx0/loopback - Places a loop to the board's G.703 signals
# echo none >/proc/comx/comx0/loopback
# echo local >/proc/comx/comx0/loopback
# echo remote >/proc/comx/comx0/loopback
none - normal operation, no loop
local - the board receives it's own output
remote - the board sends the received data to the remote side
Default: none
-----------------------------------------------------------------
Interface (channel group in Cisco terms) settings:
comx0/timeslots - which timeslots belong to the given interface
Setting:
# echo '1 5 2 6 7 8' >/proc/comx/comx0/timeslots
# cat /proc/comx/comx0/timeslots
1 2 5 6 7 8
#
Finding a timeslot:
# grep ' 4' /proc/comx/comx*/timeslots
/proc/comx/comx0/timeslots:1 3 4 5 6
#
The timeslots can be in any order, '1 2 3' is the same as '1 3 2'.
The interface has to be DOWN during the setting ('ifconfig comx0
down'), but the other interfaces could operate normally.
The driver checks if the assigned timeslots are vacant, if not, then
the setting won't be applied.
The timeslot values are treated as decimal numbers, not to misunderstand
values of 08, 09 form.
-----------------------------------------------------------------
Checking the interface and board status:
- Lines beginning with ' ' (space) belong to the original output, the lines
which begin with '//' are the comments.
papaya:~$ cat /proc/comx/comx1/status
Interface administrative status is UP, modem status is UP, protocol is UP
Modem status changes: 0, Transmitter status is IDLE, tbusy: 0
Interface load (input): 978376 / 947808 / 951024 bits/s (5s/5m/15m)
(output): 978376 / 947848 / 951024 bits/s (5s/5m/15m)
Debug flags: none
RX errors: len: 22, overrun: 1, crc: 0, aborts: 0
buffer overrun: 0, pbuffer overrun: 0
TX errors: underrun: 0
Line keepalive (value: 10) status UP [0]
// The hardware specific part starts here:
Controller status:
No alarms
// Alarm:
//
// No alarms - Everything OK
//
// LOS - Loss Of Signal - No signal sensed on the input
// AIS - Alarm Indication Signal - The remot side sends '11111111'-s,
// it tells, that there's an error condition, or it's not
// initialised.
// AUXP - Auxiliary Pattern Indication - 01010101.. received.
// LFA - Loss of Frame Alignment - no frame sync received.
// RRA - Receive Remote Alarm - the remote end's OK, but singnals error cond.
// LMFA - Loss of CRC4 Multiframe Alignment - no CRC4 multiframe sync.
// NMF - No Multiframe alignment Found after 400 msec - no such alarm using
// no-crc4 or crc4 framing, see below.
//
// Other possible error messages:
//
// Transmit Line Short - the board felt, that it's output is short-circuited,
// so it switched the transmission off. (The board can't definitely tell,
// that it's output is short-circuited.)
// Chained list of the received packets, for debug purposes:
Rx ring:
rafutott: 0
lastcheck: 50845731, jiffies: 51314281
base: 017b1858
rx_desc_ptr: 0
rx_desc_ptr: 017b1858
hw_curr_ptr: 017b1858
06040000 017b1868 017b1898 c016ff00
06040000 017b1878 017b1e9c c016ff00
46040000 017b1888 017b24a0 c016ff00
06040000 017b1858 017b2aa4 c016ff00
// All the interfaces using the board: comx1, using the 1,2,...16 timeslots,
// comx2, using timeslot 17, etc.
Interfaces using this board: (channel-group, interface, timeslots)
0 comx1: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 comx2: 17
2 comx3: 18
3 comx4: 19
4 comx5: 20
5 comx6: 21
6 comx7: 22
7 comx8: 23
8 comx9: 24
9 comx10: 25
10 comx11: 26
11 comx12: 27
12 comx13: 28
13 comx14: 29
14 comx15: 30
15 comx16: 31
// The number of events handled by the driver during an interrupt cycle:
Interrupt work histogram:
hist[ 0]: 0 hist[ 1]: 2 hist[ 2]: 18574 hist[ 3]: 79
hist[ 4]: 14 hist[ 5]: 1 hist[ 6]: 0 hist[ 7]: 1
hist[ 8]: 0 hist[ 9]: 7
// The number of packets to send in the Tx ring, when a new one arrived:
Tx ring histogram:
hist[ 0]: 2329 hist[ 1]: 0 hist[ 2]: 0 hist[ 3]: 0
// The error counters of the E1 interface, according to the RFC2495,
// (similar to the Cisco "show controllers e1" command's output:
// http://www.cisco.com/univercd/cc/td/doc/product/software/ios11/rbook/rinterfc.htm#xtocid25669126)
Data in current interval (91 seconds elapsed):
9516 Line Code Violations, 65 Path Code Violations, 2 E-Bit Errors
0 Slip Secs, 2 Fr Loss Secs, 2 Line Err Secs, 0 Degraded Mins
0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 11 Unavail Secs
Data in Interval 1 (15 minutes):
0 Line Code Violations, 0 Path Code Violations, 0 E-Bit Errors
0 Slip Secs, 0 Fr Loss Secs, 0 Line Err Secs, 0 Degraded Mins
0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 0 Unavail Secs
Data in last 4 intervals (1 hour):
0 Line Code Violations, 0 Path Code Violations, 0 E-Bit Errors
0 Slip Secs, 0 Fr Loss Secs, 0 Line Err Secs, 0 Degraded Mins
0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 0 Unavail Secs
Data in last 96 intervals (24 hours):
0 Line Code Violations, 0 Path Code Violations, 0 E-Bit Errors
0 Slip Secs, 0 Fr Loss Secs, 0 Line Err Secs, 0 Degraded Mins
0 Errored Secs, 0 Bursty Err Secs, 0 Severely Err Secs, 0 Unavail Secs
-----------------------------------------------------------------
Some unique options, (may get into the driver later):
Treat them very carefully, these can cause much trouble!
modified CRC-4, for improved interworking of CRC-4 and non-CRC-4
devices: (see page 107 and g706 Annex B)
lbireg[ 0x1b ] |= 0x08
lbireg[ 0x1c ] |= 0xc0
- The NMF - 'No Multiframe alignment Found after 400 msec' alarm
comes into account.
FALC - the line driver chip.
local loop - I hear my transmission back.
remote loop - I echo the remote transmission back.
Something useful for finding errors:
- local loop for timeslot 1 in the FALC chip:
# echo >lbireg 0x1d 0x21
- Swithing the loop off:
# echo >lbireg 0x1d 0x00
...@@ -24,6 +24,7 @@ if [ "$CONFIG_WAN" = "y" ]; then ...@@ -24,6 +24,7 @@ if [ "$CONFIG_WAN" = "y" ]; then
dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX dep_tristate ' Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX
dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX dep_tristate ' Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX
dep_tristate ' Support for MixCOM board' CONFIG_COMX_HW_MIXCOM $CONFIG_COMX dep_tristate ' Support for MixCOM board' CONFIG_COMX_HW_MIXCOM $CONFIG_COMX
dep_tristate ' Support for MUNICH based boards: SliceCOM, PCICOM (WelCOM)' CONFIG_COMX_HW_MUNICH $CONFIG_COMX
dep_tristate ' Support for HDLC and syncPPP protocols on MultiGate boards' CONFIG_COMX_PROTO_PPP $CONFIG_COMX dep_tristate ' Support for HDLC and syncPPP protocols on MultiGate boards' CONFIG_COMX_PROTO_PPP $CONFIG_COMX
if [ "$CONFIG_LAPB" = "y" ]; then if [ "$CONFIG_LAPB" = "y" ]; then
dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_COMX dep_tristate ' Support for LAPB protocol on MultiGate boards' CONFIG_COMX_PROTO_LAPB $CONFIG_COMX
......
...@@ -34,6 +34,7 @@ obj-$(CONFIG_COMX) += comx.o ...@@ -34,6 +34,7 @@ obj-$(CONFIG_COMX) += comx.o
obj-$(CONFIG_COMX_HW_COMX) += comx-hw-comx.o obj-$(CONFIG_COMX_HW_COMX) += comx-hw-comx.o
obj-$(CONFIG_COMX_HW_LOCOMX) += z85230.o syncppp.o comx-hw-locomx.o obj-$(CONFIG_COMX_HW_LOCOMX) += z85230.o syncppp.o comx-hw-locomx.o
obj-$(CONFIG_COMX_HW_MIXCOM) += comx-hw-mixcom.o obj-$(CONFIG_COMX_HW_MIXCOM) += comx-hw-mixcom.o
obj-$(CONFIG_COMX_HW_MUNICH) += comx-hw-munich.o
obj-$(CONFIG_COMX_PROTO_PPP) += syncppp.o comx-proto-ppp.o obj-$(CONFIG_COMX_PROTO_PPP) += syncppp.o comx-proto-ppp.o
obj-$(CONFIG_COMX_PROTO_LAPB) += comx-proto-lapb.o obj-$(CONFIG_COMX_PROTO_LAPB) += comx-proto-lapb.o
obj-$(CONFIG_COMX_PROTO_FR) += comx-proto-fr.o obj-$(CONFIG_COMX_PROTO_FR) += comx-proto-fr.o
......
/*
* 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>
#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"
#endif
MODULE_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");
/*
* 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 - ksz */
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)
{
u8 *lbi = slicecom_boards[boardnum].lbi;
spin_lock_irqsave(&mister_lock, flags);
slicecom_boards[boardnum].framing = value;
switch (value)
{
case SLICECOM_FRAMING_CRC4:
writeb(readb(lbi + FMR1) | 8, lbi + FMR1);
writeb((readb(lbi + FMR2) & 0x3f) | 0x80, lbi + FMR2);
break;
case SLICECOM_FRAMING_NO_CRC4:
writeb(readb(lbi + FMR1) & 0xf7, lbi + FMR1);
writeb(readb(lbi + FMR2) & 0x3f, lbi + FMR2);
break;
default:
printk("slicecom: board %d: unhandled " FILENAME_FRAMING
" value %d\n", boardnum, value);
}
spin_unlock_irqrestore(&mister_lock, flags);
}
/*
* Set PCM linecode - /proc/comx/comx0/linecode
*/
void slicecom_set_linecode(int boardnum, int value)
{
u8 *lbi = slicecom_boards[boardnum].lbi;
spin_lock_irqsave(&mister_lock, flags);
slicecom_boards[boardnum].linecode = value;
switch (value)
{
case SLICECOM_LINECODE_HDB3:
writeb(readb(lbi + FMR0) | 0xf0, lbi + FMR0);
break;
case SLICECOM_LINECODE_AMI:
writeb((readb(lbi + FMR0) & 0x0f) | 0xa0, lbi + FMR0);
break;
default:
printk("slicecom: board %d: unhandled " FILENAME_LINECODE
" value %d\n", boardnum, value);
}
spin_unlock_irqrestore(&mister_lock, flags);
}
/*
* Set PCM clock source - /proc/comx/comx0/clock_source
*/
void slicecom_set_clock_source(int boardnum, int value)
{
u8 *lbi = slicecom_boards[boardnum].lbi;
spin_lock_irqsave(&mister_lock, flags);
slicecom_boards[boardnum].clock_source = value;
switch (value)
{
case SLICECOM_CLOCK_SOURCE_LINE:
writeb(readb(lbi + LIM0) & ~1, lbi + LIM0);
break;
case SLICECOM_CLOCK_SOURCE_INTERNAL:
writeb(readb(lbi + LIM0) | 1, lbi + LIM0);
break;
default:
printk("slicecom: board %d: unhandled " FILENAME_CLOCK_SOURCE
" value %d\n", boardnum, value);
}
spin_unlock_irqrestore(&mister_lock, flags);
}
/*
* Set loopbacks - /proc/comx/comx0/loopback
*/
void slicecom_set_loopback(int boardnum, int value)
{
u8 *lbi = slicecom_boards[boardnum].lbi;
spin_lock_irqsave(&mister_lock, flags);
slicecom_boards[boardnum].loopback = value;
switch (value)
{
case SLICECOM_LOOPBACK_NONE:
writeb(readb(lbi + LIM0) & ~2, lbi + LIM0); /* Local Loop OFF */
writeb(readb(lbi + LIM1) & ~2, lbi + LIM1); /* Remote Loop OFF */
break;
case SLICECOM_LOOPBACK_LOCAL:
writeb(readb(lbi + LIM1) & ~2, lbi + LIM1); /* Remote Loop OFF */
writeb(readb(lbi + LIM0) | 2, lbi + LIM0); /* Local Loop ON */
break;
case SLICECOM_LOOPBACK_REMOTE:
writeb(readb(lbi + LIM0) & ~2, lbi + LIM0); /* Local Loop OFF */
writeb(readb(lbi + LIM1) | 2, lbi + LIM1); /* Remote Loop ON */
break;
default:
printk("slicecom: board %d: unhandled " FILENAME_LOOPBACK
" value %d\n", boardnum, value);
}
spin_unlock_irqrestore(&mister_lock, flags);
}
/*
* Update E1 line status LEDs on the adapter
*/
void slicecom_update_leds(munich_board_t * board)
{
u32 *bar1 = board->bar1;
u8 *lbi = board->lbi;
u8 frs0;
u32 leds;
int i;
spin_lock_irqsave(&mister_lock, flags);
leds = 0;
frs0 = readb(lbi + FRS0); /* FRS0 bits described on page 137 */
if (!(frs0 & 0xa0))
{
leds |= 0x2000; /* Green LED: Input signal seems to be OK, no LOS, no LFA */
if (frs0 & 0x10)
leds |= 0x8000; /* Red LED: Receiving Remote Alarm */
}
writel(leds, MUNICH_VIRT(GPDATA));
if (leds == 0x2000 && !board->lineup)
{ /* line up */
board->lineup = 1;
for (i = 0; i < 32; i++)
{
if (board->twins[i] && (board->twins[i]->flags & IFF_RUNNING))
{
struct comx_channel *ch = board->twins[i]->priv;
if (!test_and_set_bit(0, &ch->lineup_pending))
{
ch->lineup_timer.function = comx_lineup_func;
ch->lineup_timer.data = (unsigned long)board->twins[i];
ch->lineup_timer.expires = jiffies + HZ * ch->lineup_delay;
add_timer(&ch->lineup_timer);
}
}
}
}
else if (leds != 0x2000 && board->lineup)
{ /* line down */
board->lineup = 0;
for (i = 0; i < 32; i++)
if (board->twins[i] && (board->twins[i]->flags & IFF_RUNNING))
{
struct comx_channel *ch = board->twins[i]->priv;
if (test_and_clear_bit(0, &ch->lineup_pending))
del_timer(&ch->lineup_timer);
else if (ch->line_status & LINE_UP)
{
ch->line_status &= ~LINE_UP;
if (ch->LINE_status)
ch->LINE_status(board->twins[i], ch->line_status);
}
}
}
spin_unlock_irqrestore(&mister_lock, flags);
}
/*
* This function gets called every second when the FALC issues the interrupt.
* Hardware counters contain error counts for last 1-second time interval.
* We add them to the global counters here.
* Read rfc2495 to understand this.
*/
void slicecom_update_line_counters(munich_board_t * board)
{
e1_stats_t *curr_int = &board->intervals[board->current_interval];
u8 *lbi = board->lbi;
unsigned framing_errors, code_violations, path_code_violations, crc4_errors,
e_bit_errors;
unsigned slip_detected, /* this one has logical value, not the number of slips! */
out_of_frame_defect, /* logical value */
ais_defect, /* logical value */
errored_sec, bursty_err_sec, severely_err_sec = 0, failure_sec;
u8 isr2, isr3, isr5, frs0;
spin_lock_irqsave(&mister_lock, flags);
isr2 = readb(lbi + ISR2); /* ISR0-5 described on page 156 */
isr3 = readb(lbi + ISR3);
isr5 = readb(lbi + ISR5);
frs0 = readb(lbi + FRS0); /* FRS0 described on page 137 */
/* Error Events: */
code_violations = readb(lbi + CVCL) + (readb(lbi + CVCH) << 8);
framing_errors = readb(lbi + FECL) + (readb(lbi + FECH) << 8);
crc4_errors = readb(lbi + CEC1L) + (readb(lbi + CEC1H) << 8);
e_bit_errors = readb(lbi + EBCL) + (readb(lbi + EBCH) << 8);
slip_detected = isr3 & (ISR3_RSN | ISR3_RSP);
path_code_violations = framing_errors + crc4_errors;
curr_int->line_code_violations += code_violations;
curr_int->path_code_violations += path_code_violations;
curr_int->e_bit_errors += e_bit_errors;
/* Performance Defects: */
/* there was an LFA in the last second, but maybe disappeared: */
out_of_frame_defect = (isr2 & ISR2_LFA) || (frs0 & FRS0_LFA);
/* there was an AIS in the last second, but maybe disappeared: */
ais_defect = (isr2 & ISR2_AIS) || (frs0 & FRS0_AIS);
/* Performance Parameters: */
if (out_of_frame_defect)
curr_int->fr_loss_secs++;
if (code_violations)
curr_int->line_err_secs++;
errored_sec = ((board->framing == SLICECOM_FRAMING_NO_CRC4) &&
(code_violations)) || path_code_violations ||
out_of_frame_defect || slip_detected || ais_defect;
bursty_err_sec = !out_of_frame_defect && !ais_defect &&
(path_code_violations > 1) && (path_code_violations < 320);
switch (board->framing)
{
case SLICECOM_FRAMING_CRC4:
severely_err_sec = out_of_frame_defect ||
(path_code_violations >= 832);
break;
case SLICECOM_FRAMING_NO_CRC4:
severely_err_sec = (code_violations >= 2048);
break;
}
/*
* failure_sec: true if there was a condition leading to a failure
* (and leading to unavailable state) in this second:
*/
failure_sec = (isr2 & ISR2_RA) || (frs0 & FRS0_RRA) /* Remote/Far End/Distant Alarm Failure */
|| ais_defect || out_of_frame_defect /* AIS or LOF Failure */
|| (isr2 & ISR2_LOS) || (frs0 & FRS0_LOS) /* Loss Of Signal Failure */
|| (board->loopback != SLICECOM_LOOPBACK_NONE); /* Loopback has been set */
if (board->is_unavailable)
{
if (severely_err_sec)
board->no_ses_seconds = 0;
else
board->no_ses_seconds++;
if ((board->no_ses_seconds >= 10) && !failure_sec)
{
board->is_unavailable = 0;
board->ses_seconds = 0;
board->no_ses_seconds = 0;
}
}
else
{
if (severely_err_sec)
board->ses_seconds++;
else
board->ses_seconds = 0;
if ((board->ses_seconds >= 10) || failure_sec)
{
board->is_unavailable = 1;
board->ses_seconds = 0;
board->no_ses_seconds = 0;
}
}
if (board->is_unavailable)
curr_int->unavail_secs++;
else
{
if (slip_detected)
curr_int->slip_secs++;
curr_int->errored_secs += errored_sec;
curr_int->bursty_err_secs += bursty_err_sec;
curr_int->severely_err_secs += severely_err_sec;
}
/* the RFC does not say clearly which errors to count here, we try to count bit errors */
if (!board->is_unavailable && !severely_err_sec)
{
board->deg_cumulated_errors += code_violations;
board->deg_elapsed_seconds++;
if (board->deg_elapsed_seconds >= 60)
{
if (board->deg_cumulated_errors >= 123)
curr_int->degraded_mins++;
board->deg_cumulated_errors = 0;
board->deg_elapsed_seconds = 0;
}
}
board->elapsed_seconds++;
if (board->elapsed_seconds >= 900)
{
board->current_interval =
(board->current_interval + 1) % SLICECOM_BOARD_INTERVALS_SIZE;
memset((void *)&board->intervals[board->current_interval], 0,
sizeof(e1_stats_t));
board->elapsed_seconds = 0;
}
spin_unlock_irqrestore(&mister_lock, flags);
}
static void pcicom_modemline(unsigned long b)
{
munich_board_t *board = (munich_board_t *) b;
struct net_device *dev = board->twins[0];
struct comx_channel *ch = dev->priv;
unsigned long regs;
regs = readl((void *)(&board->bar1[GPDATA]));
if ((ch->line_status & LINE_UP) && (regs & 0x0800))
{
ch->line_status &= ~LINE_UP;
board->lineup = 0;
if (ch->LINE_status)
{
ch->LINE_status(dev, ch->line_status);
}
}
if (!(ch->line_status & LINE_UP) && !(regs & 0x0800))
{
ch->line_status |= LINE_UP;
board->lineup = 1;
if (ch->LINE_status)
{
ch->LINE_status(dev, ch->line_status);
}
}
mod_timer((struct timer_list *)&board->modemline_timer, jiffies + HZ);
}
/*
* Is it possible to transmit ?
* Called (may be called) by the protocol layer
*/
static int MUNICH_txe(struct net_device *dev)
{
struct comx_channel *ch = dev->priv;
struct slicecom_privdata *hw = ch->HW_privdata;
return (hw->busy < TX_DESC_MAX - 1);
}
/*
* Hw probe function. Detects all the boards in the system,
* and fills up slicecom_boards[] and pcicom_boards[]
* Returns 0 on success.
* We do not disable interrupts!
*/
static int munich_probe(void)
{
struct pci_dev *pci;
int boardnum;
int slicecom_boardnum;
int pcicom_boardnum;
u32 *bar1;
u8 *lbi;
munich_board_t *board;
for (boardnum = 0; boardnum < MAX_BOARDS; boardnum++)
{
pcicom_boards[boardnum].pci = 0;
pcicom_boards[boardnum].bar1 = 0;
pcicom_boards[boardnum].lbi = 0;
slicecom_boards[boardnum].pci = 0;
slicecom_boards[boardnum].bar1 = 0;
slicecom_boards[boardnum].lbi = 0;
}
pci = NULL;
board = NULL;
slicecom_boardnum = 0;
pcicom_boardnum = 0;
for (boardnum = 0;
boardnum < MAX_BOARDS && (pci = pci_find_device(PCI_VENDOR_ID_SIEMENS,
PCI_DEVICE_ID_SIEMENS_MUNICH32X, pci)); boardnum++)
{
if (pci_enable_device(pci))
continue;
printk("munich_probe: munich chip found, IRQ %d\n", pci->irq);
#if (LINUX_VERSION_CODE < 0x02030d)
bar1 = ioremap_nocache(pci->base_address[0], 0x100);
lbi = ioremap_nocache(pci->base_address[1], 0x100);
#else
bar1 = ioremap_nocache(pci->resource[0].start, 0x100);
lbi = ioremap_nocache(pci->resource[1].start, 0x100);
#endif
if (bar1 && lbi)
{
pci_write_config_dword(pci, MUNICH_PCI_PCIRES, 0xe0000);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
pci_write_config_dword(pci, MUNICH_PCI_PCIRES, 0);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
/* check the type of the card */
writel(LREG0_MAGIC, MUNICH_VIRT(LREG0));
writel(LREG1_MAGIC, MUNICH_VIRT(LREG1));
writel(LREG2_MAGIC, MUNICH_VIRT(LREG2));
writel(LREG3_MAGIC, MUNICH_VIRT(LREG3));
writel(LREG4_MAGIC, MUNICH_VIRT(LREG4));
writel(LREG5_MAGIC, MUNICH_VIRT(LREG5));
writel(LCONF_MAGIC2,MUNICH_VIRT(LCONF)); /* enable the DMSM */
if ((readb(lbi + VSTR) == 0x13) || (readb(lbi + VSTR) == 0x10))
{
board = slicecom_boards + slicecom_boardnum;
sprintf((char *)board->devname, "slicecom%d",
slicecom_boardnum);
board->isx21 = 0;
slicecom_boardnum++;
}
else if ((readb(lbi + VSTR) == 0x6) || (readb(lbi + GIS) == 0x6))
{
board = pcicom_boards + pcicom_boardnum;
sprintf((char *)board->devname, "pcicom%d", pcicom_boardnum);
board->isx21 = 1;
pcicom_boardnum++;
}
if (board)
{
printk("munich_probe: %s board found\n", board->devname);
writel(LCONF_MAGIC1, MUNICH_VIRT(LCONF)); /* reset the DMSM */
board->pci = pci;
board->bar1 = bar1;
board->lbi = lbi;
board->framing = SLICECOM_FRAMING_DEFAULT;
board->linecode = SLICECOM_LINECODE_DEFAULT;
board->clock_source = SLICECOM_CLOCK_SOURCE_DEFAULT;
board->loopback = SLICECOM_LOOPBACK_DEFAULT;
SET_MODULE_OWNER(board);
}
else
{
printk("munich_probe: Board error, VSTR: %02X\n",
readb(lbi + VSTR));
iounmap((void *)bar1);
iounmap((void *)lbi);
}
}
else
{
printk("munich_probe: ioremap() failed, not enabling this board!\n");
/* .pci = NULL, so the MUNICH_open will not try to open it */
if (bar1) iounmap((void *)bar1);
if (lbi) iounmap((void *)lbi);
}
}
if (!pci && !boardnum)
{
printk("munich_probe: no PCI present!\n");
return -ENODEV;
}
if (pcicom_boardnum + slicecom_boardnum == 0)
{
printk
("munich_probe: Couldn't find any munich board: vendor:device %x:%x not found\n",
PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_MUNICH32X);
return -ENODEV;
}
/* Found some */
if (pcicom_boardnum)
printk("%d pcicom board(s) found.\n", pcicom_boardnum);
if (slicecom_boardnum)
printk("%d slicecom board(s) found.\n", slicecom_boardnum);
return 0;
}
/*
* Reset the hardware. Get called only from within this module if needed.
*/
#if 0
static int slicecom_reset(struct net_device *dev)
{
struct comx_channel *ch = dev->priv;
printk("slicecom_reset: resetting the hardware\n");
/* Begin to reset the hardware */
if (ch->HW_set_clock)
ch->HW_set_clock(dev);
/* And finish it */
return 0;
}
#endif
/*
* Transmit a packet.
* Called by the protocol layer
* Return values:
* FRAME_ACCEPTED: frame is being transmited, transmitter is busy
* FRAME_QUEUED: frame is being transmitted, there's more room in
* the transmitter for additional packet(s)
* FRAME_ERROR:
* FRAME_DROPPED: there was some error
*/
static int MUNICH_send_packet(struct net_device *dev, struct sk_buff *skb)
{
struct comx_channel *ch = (struct comx_channel *)dev->priv;
struct slicecom_privdata *hw = ch->HW_privdata;
/* Send it to the debug facility too if needed: */
if (ch->debug_flags & DEBUG_HW_TX)
comx_debug_bytes(dev, skb->data, skb->len, "MUNICH_send_packet");
/* If the line is inactive, don't accept: */
/* TODO: atgondolni hogy mi is legyen itt */
/* if (!(ch->line_status & LINE_UP)) return FRAME_DROPPED; */
/* More check, to be sure: */
if (skb->len > TXBUFFER_SIZE)
{
ch->stats.tx_errors++;
kfree_skb(skb);
return FRAME_ERROR;
}
/* Maybe you have to disable irq's while programming the hw: */
spin_lock_irqsave(&mister_lock, flags);
/* And more check: */
if (hw->busy >= TX_DESC_MAX - 1)
{
printk(KERN_ERR
"%s: Transmitter called while busy... dropping frame, busy = %d\n",
dev->name, hw->busy);
spin_unlock_irqrestore(&mister_lock, flags);
kfree_skb(skb);
return FRAME_DROPPED;
}
if (hw->busy >= 0)
hw->tx_ring_hist[hw->busy]++;
/* DELL: */
else
printk("slicecom: %s: FATAL: busy = %d\n", dev->name, hw->busy);
// /* DEL: */
// printk("slicecom: %s: _send_packet called, busy = %d\n", dev->name, hw->busy );
/* Packet can go, update stats: */
ch->stats.tx_packets++;
ch->stats.tx_bytes += skb->len;
/* Pass the packet to the HW: */
/* Step forward with the transmit descriptors: */
hw->tx_desc_ptr = (hw->tx_desc_ptr + 1) % TX_DESC_MAX;
memcpy(&(hw->tx_data[hw->tx_desc_ptr][0]), skb->data, skb->len);
hw->tx_desc[hw->tx_desc_ptr].no = skb->len;
/* We don't issue any command, just step with the HOLD bit */
hw->tx_desc[hw->tx_desc_ptr].hold = 1;
hw->tx_desc[(hw->tx_desc_ptr + TX_DESC_MAX - 1) % TX_DESC_MAX].hold = 0;
#ifdef COMX_NEW
dev_kfree_skb(skb);
#endif
/* csomag kerult a Tx ringbe: */
hw->busy++;
/* Report it: */
if (ch->debug_flags & DEBUG_HW_TX)
comx_debug(dev, "%s: MUNICH_send_packet was successful\n\n", dev->name);
if (hw->busy >= TX_DESC_MAX - 1)
{
spin_unlock_irqrestore(&mister_lock, flags);
return FRAME_ACCEPTED;
}
spin_unlock_irqrestore(&mister_lock, flags);
/* All done */
return FRAME_QUEUED;
}
/*
* Interrupt handler routine.
* Called by the Linux kernel.
* BEWARE! The interrupts are enabled on the call!
*/
static void MUNICH_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct sk_buff *skb;
int length;
int rx_status;
int work; /* hany esemenyt kezeltem mar le */
u32 *bar1;
u8 *lbi;
u32 stat, /* az esemenyek, amiket a ebben a loop korben le kell meg kezelni */
race_stat = 0, /* race eseten ebben uzenek magamnak hogy mit kell meg lekezelni */
ack; /* ezt fogom a vegen a STAT-ba irni, kiveszek belole 1-1 bitet ha */
/* az adott dolgot nem kell ack-olni mert volt vele munkam, es */
/* legjobb ha visszaterek ide megegyszer */
munich_intq_t int_info;
struct net_device *dev;
struct comx_channel *ch;
struct slicecom_privdata *hw;
munich_board_t *board = (munich_board_t *) dev_id;
int channel;
// , boardnum = (int)dev_id;
// board = munich_boards + boardnum;
bar1 = board->bar1;
lbi = board->lbi;
// Do not uncomment this under heavy load! :->
// printk("MUNICH_interrupt: masked STAT=0x%08x, tiq=0x%08x, riq=0x%08x, piq=0x%08x\n", stat, board->tiq[0].all, board->riq[0].all, board->piq[0].all );
for (work = 0; (stat = (race_stat | (readl(MUNICH_VIRT(STAT)) & ~STAT_NOT_HANDLED_BY_INTERRUPT))) && (work < MAX_WORK - 1); work++)
{
ack = stat & (STAT_PRI | STAT_PTI | STAT_LBII);
/* Handle the interrupt information in the Rx queue. We don't really trust */
/* info from this queue, because it can be overflowed, so later check */
/* every Rx ring for received packets. But there are some errors which can't */
/* be counted from the Rx rings, so we parse it. */
int_info = board->riq[board->riq_ptr];
if (int_info.all & 0xF0000000) /* ha ez nem 0, akkor itt interrupt_info van */
{
ack &= ~STAT_PRI; /* don't ack the interrupt, we had some work to do */
channel = PCM_INT_CHANNEL(int_info.all);
dev = board->twins[channel];
if (dev == NULL)
{
printk
("MUNICH_interrupt: got an Rx interrupt info for NULL device "
"%s.twins[%d], int_info = 0x%08x\n", board->devname,
channel, int_info.all);
goto go_for_next_interrupt;
}
ch = (struct comx_channel *)dev->priv;
hw = (struct slicecom_privdata *)ch->HW_privdata;
// printk("Rx STAT=0x%08x int_info=0x%08x rx_desc_ptr=%d rx_desc.status=0x%01x\n",
// stat, int_info.all, hw->rx_desc_ptr, hw->rx_desc[ hw->rx_desc_ptr ].status );
if (int_info.all & PCM_INT_HI)
printk("SliceCOM: %s: Host Initiated interrupt\n", dev->name);
if (int_info.all & PCM_INT_IFC)
printk("SliceCOM: %s: Idle/Flag Change\n", dev->name);
/* TOD: jo ez az Idle/Flag Change valamire? - azonnal latszik belole hogy mikor ad a masik oldal */
/* TOD: ilyen IT most nem is jon, mert ki van maszkolva az interrupt, biztosan kell ez? */
if (int_info.all & PCM_INT_FO)
/* Internal buffer (RB) overrun */
ch->stats.rx_over_errors++; /* TOD: Ez azt jelenti hogy a belso RB nem volt hozzaferheto, es ezert kihagyott valamit. De nem csak csomag lehetett, hanem esemeny, stb. is. lasd page 247. Ezzel a 'cat status'-hoz igazodok, de a netdevice.h szerint nem egyertelmu hogy ide ez kellene. Nem lehet hogy rx_missed ? */
/* DE: nem gotozok sehova, elvileg jo igy */
/* kesobb meg visszaterek az FO-ra, ha packet-FO volt. Keresd a "packet-FO"-t. */
if (int_info.all & PCM_INT_FI) /* frame received, but we do not trust the int_info queue */
if (int_info.all & PCM_INT_SF)
{ /* Short Frame: rovidebb mint a CRC */
/* "rovidebb mint CRC+2byte" vizsgalat a "CRC+2"-nel */
ch->stats.rx_length_errors++; /* TOD: noveljem? ne noveljem? */
goto go_for_next_interrupt;
}
go_for_next_interrupt: /* One step in the interrupt queue */
board->riq[board->riq_ptr].all = 0; /* megjelolom hogy itt meg nem jart a hw */
board->riq_ptr = (board->riq_ptr + 1) % MUNICH_INTQMAX;
}
/* Check every Rx ring for incomed packets: */
for (channel = 0; channel < 32; channel++)
{
dev = board->twins[channel];
if (dev != NULL)
{
ch = (struct comx_channel *)dev->priv;
hw = (struct slicecom_privdata *)ch->HW_privdata;
rx_status = hw->rx_desc[hw->rx_desc_ptr].status;
if (!(rx_status & 0x80)) /* mar jart itt a hardver */
{
ack &= ~STAT_PRI; /* Don't ack, we had some work */
/* Ez most egy kicsit zuros, mert itt mar nem latom az int_infot */
if (rx_status & RX_STATUS_ROF)
ch->stats.rx_over_errors++; /* TOD: 'cat status'-hoz igazodok */
if (rx_status & RX_STATUS_RA)
/* Abort received or issued on channel */
ch->stats.rx_frame_errors++; /* or HOLD bit in the descriptor */
/* TOD: 'cat status'-hoz igazodok */
if (rx_status & RX_STATUS_LFD)
{ /* Long Frame (longer then MFL in the MODE1) */
ch->stats.rx_length_errors++;
goto go_for_next_frame;
}
if (rx_status & RX_STATUS_NOB)
{ /* Not n*8 bits long frame - frame alignment */
ch->stats.rx_frame_errors++; /* ez viszont nem igazodik a 'cat status'-hoz */
goto go_for_next_frame;
}
if (rx_status & RX_STATUS_CRCO)
{ /* CRC error */
ch->stats.rx_crc_errors++;
goto go_for_next_frame;
}
if (rx_status & RX_STATUS_SF)
{ /* Short Frame: rovidebb mint CRC+2byte */
ch->stats.rx_errors++; /* The HW does not set PCI_INT_ERR bit for this one, see page 246 */
ch->stats.rx_length_errors++;
goto go_for_next_frame;
}
if (rx_status != 0)
{
printk("SliceCOM: %s: unhandled rx_status: 0x%02x\n",
dev->name, rx_status);
goto go_for_next_frame;
}
/* frame received without errors: */
length = hw->rx_desc[hw->rx_desc_ptr].bno;
ch->stats.rx_packets++; /* Count only 'good' packets */
ch->stats.rx_bytes += length;
/* Allocate a larger skb and reserve the heading for efficiency: */
if ((skb = dev_alloc_skb(length + 16)) == NULL)
{
ch->stats.rx_dropped++;
goto go_for_next_frame;
}
/* Do bookkeeping: */
skb_reserve(skb, 16);
skb_put(skb, length);
skb->dev = dev;
/* Now copy the data into the buffer: */
memcpy(skb->data, &(hw->rx_data[hw->rx_desc_ptr][0]), length);
/* DEL: UGLY HACK!!!! */
if (*((int *)skb->data) == 0x02000000 &&
*(((int *)skb->data) + 1) == 0x3580008f)
{
printk("%s: swapping hack\n", dev->name);
*((int *)skb->data) = 0x3580008f;
*(((int *)skb->data) + 1) = 0x02000000;
}
if (ch->debug_flags & DEBUG_HW_RX)
comx_debug_skb(dev, skb, "MUNICH_interrupt receiving");
/* Pass it to the protocol entity: */
ch->LINE_rx(dev, skb);
go_for_next_frame:
/* DEL: rafutott-e a HOLD bitre -detektalas */
{
if( ((rx_desc_t*)phys_to_virt(board->ccb->current_rx_desc[channel]))->hold
&& ((rx_desc_t*)phys_to_virt(board->ccb->current_rx_desc[channel]))->status != 0xff)
hw->rafutott++; /* rafutott: hanyszor volt olyan hogy a current descriptoron HOLD bit volt, es a hw mar befejezte az irast (azaz a hw rafutott a HOLD bitre) */
}
// if( jiffies % 2 ) /* DELL: okozzunk egy kis Rx ring slipet :) */
// {
/* Step forward with the receive descriptors: */
/* if you change this, change the copy of it below too! Search for: "RxSlip" */
hw->rx_desc[(hw->rx_desc_ptr + RX_DESC_MAX - 1) % RX_DESC_MAX].hold = 1;
hw->rx_desc[hw->rx_desc_ptr].status = 0xFF; /* megjelolom hogy itt meg nem jart a hw */
hw->rx_desc[(hw->rx_desc_ptr + RX_DESC_MAX - 2) % RX_DESC_MAX].hold = 0;
hw->rx_desc_ptr = (hw->rx_desc_ptr + 1) % RX_DESC_MAX;
// }
}
}
}
stat &= ~STAT_PRI;
// }
// if( stat & STAT_PTI ) /* TOD: primko megvalositas: mindig csak egy esemenyt dolgozok fel, */
/* es nem torlom a STAT-ot, ezert ujra visszajon ide a rendszer. Amikor */
/* jon interrupt, de nincs mit feldolgozni, akkor torlom a STAT-ot. */
/* 'needs a rewrite', de elso megoldasnak jo lesz */
// {
udelay(10000);
int_info = board->tiq[board->tiq_ptr];
if (int_info.all & 0xF0000000) /* ha ez nem 0, akkor itt interrupt_info van */
{
ack &= ~STAT_PTI; /* don't ack the interrupt, we had some work to do */
channel = PCM_INT_CHANNEL(int_info.all);
dev = board->twins[channel];
if (dev == NULL)
{
printk("MUNICH_interrupt: got a Tx interrupt for NULL device "
"%s.twins[%d], int_info = 0x%08x\n",
board->isx21 ? "pcicom" : "slicecom", channel, int_info.all);
goto go_for_next_tx_interrupt;
}
ch = (struct comx_channel *)dev->priv;
hw = (struct slicecom_privdata *)ch->HW_privdata;
// printk("Tx STAT=0x%08x int_info=0x%08x tiq_ptr=%d\n", stat, int_info.all, board->tiq_ptr );
if (int_info.all & PCM_INT_FE2)
{ /* "Tx available" */
/* do nothing */
}
else if (int_info.all & PCM_INT_FO)
{ /* Internal buffer (RB) overrun */
ch->stats.rx_over_errors++;
}
else
{
printk("slicecom: %s: unhandled Tx int_info: 0x%08x\n",
dev->name, int_info.all);
}
go_for_next_tx_interrupt:
board->tiq[board->tiq_ptr].all = 0;
board->tiq_ptr = (board->tiq_ptr + 1) % MUNICH_INTQMAX;
}
/* Check every Tx ring for incoming packets: */
for (channel = 0; channel < 32; channel++)
{
dev = board->twins[channel];
if (dev != NULL)
{
int newbusy;
ch = (struct comx_channel *)dev->priv;
hw = (struct slicecom_privdata *)ch->HW_privdata;
/* We dont trust the "Tx available" info from the TIQ, but check */
/* every ring if there is some free room */
if (ch->init_status && netif_running(dev))
{
newbusy = ( TX_DESC_MAX + (& hw->tx_desc[ hw->tx_desc_ptr ]) -
(tx_desc_t*)phys_to_virt(board->ccb->current_tx_desc[ hw->channel ]) ) % TX_DESC_MAX;
if(newbusy < 0)
{
printk("slicecom: %s: FATAL: fresly computed busy = %d, HW: 0x%p, SW: 0x%p\n",
dev->name, newbusy,
phys_to_virt(board->ccb->current_tx_desc[hw->channel]),
& hw->tx_desc[hw->tx_desc_ptr]);
}
/* Fogyott valami a Tx ringbol? */
if (newbusy < hw->busy)
{
// ack &= ~STAT_PTI; /* Don't ack, we had some work */
hw->busy = newbusy;
if (ch->LINE_tx)
ch->LINE_tx(dev); /* Report it to protocol driver */
}
else if (newbusy > hw->busy)
printk("slicecom: %s: newbusy > hw->busy, this should not happen!\n", dev->name);
}
}
}
stat &= ~STAT_PTI;
int_info = board->piq[board->piq_ptr];
if (int_info.all & 0xF0000000) /* ha ez nem 0, akkor itt interrupt_info van */
{
ack &= ~STAT_LBII; /* don't ack the interrupt, we had some work to do */
/* We do not really use (yet) the interrupt info from this queue, */
// printk("slicecom: %s: LBI Interrupt event: %08x\n", board->devname, int_info.all);
if (!board->isx21)
{
slicecom_update_leds(board);
slicecom_update_line_counters(board);
}
goto go_for_next_lbi_interrupt; /* To avoid warning about unused label */
go_for_next_lbi_interrupt: /* One step in the interrupt queue */
board->piq[board->piq_ptr].all = 0; /* megjelolom hogy itt meg nem jart a hw */
board->piq_ptr = (board->piq_ptr + 1) % MUNICH_PIQMAX;
}
stat &= ~STAT_LBII;
writel(ack, MUNICH_VIRT(STAT));
if (stat & STAT_TSPA)
{
// printk("slicecom: %s: PCM TSP Asynchronous\n", board->devname);
writel(STAT_TSPA, MUNICH_VIRT(STAT));
stat &= ~STAT_TSPA;
}
if (stat & STAT_RSPA)
{
// printk("slicecom: %s: PCM RSP Asynchronous\n", board->devname);
writel(STAT_RSPA, MUNICH_VIRT(STAT));
stat &= ~STAT_RSPA;
}
if (stat)
{
printk("MUNICH_interrupt: unhandled interrupt, STAT=0x%08x\n",
stat);
writel(stat, MUNICH_VIRT(STAT)); /* ha valamit megsem kezeltunk le, azert ack-ot kuldunk neki */
}
}
board->histogram[work]++;
/* We can miss these if we reach the MAX_WORK */
/* Count it to see how often it happens */
if (race_stat & STAT_PRI)
board->stat_pri_races_missed++;
if (race_stat & STAT_PTI)
board->stat_pti_races_missed++;
return;
}
void free_stuff(munich_board_t *board, struct comx_channel *ch)
{
/* Free CCB and the interrupt queues */
if (board->ccb) kfree((void *)board->ccb);
if (board->tiq) kfree((void *)board->tiq);
if (board->riq) kfree((void *)board->riq);
if (board->piq) kfree((void *)board->piq);
}
/*
* Hardware open routine.
* Called by comx (upper) layer when the user wants to bring up the interface
* with ifconfig.
* Initializes hardware, allocates resources etc.
* Returns 0 on OK, or standard error value on error.
*/
static int MUNICH_open(struct net_device *dev)
{
struct comx_channel *ch = dev->priv;
struct slicecom_privdata *hw = ch->HW_privdata;
struct proc_dir_entry *procfile = ch->procdir->subdir;
munich_board_t *board;
munich_ccb_t *ccb;
u32 *bar1;
u8 *lbi;
u32 stat;
unsigned long flags, jiffs;
int i, channel;
u32 timeslots = hw->timeslots;
board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
bar1 = board->bar1;
lbi = board->lbi;
/* TODO: a timeslotok ellenorzese kell majd ide .. hat, biztos? mar a write_proc-ban is
ellenorzom valamennyire.
if (!dev->io || !dev->irq) return -ENODEV;
*/
if (!board->pci)
{
printk("MUNICH_open: no %s board with boardnum = %d\n",
ch->hardware->name, hw->boardnum);
return -ENODEV;
}
spin_lock_irqsave(&mister_lock, flags);
/* lock the section to avoid race with multiple opens and make sure
that no interrupts get called while this lock is active */
if (board->use_count == 0) /* bring up the board if it was unused */
/* if fails, frees allocated resources and returns. */
/* TOD: is it safe? nem kellene resetelni a kartyat? */
{
printk("MUNICH_open: %s: bringing up board\n", board->devname);
/* Clean up the board's static struct if messed: */
for (i = 0; i < 32; i++)
board->twins[i] = NULL;
for (i = 0; i < MAX_WORK; i++)
board->histogram[i] = 0;
board->lineup = 0;
/* Allocate CCB: */
board->ccb = kmalloc(sizeof(munich_ccb_t), GFP_KERNEL);
if (board->ccb == NULL)
{
spin_unlock_irqrestore(&mister_lock, flags);
return -ENOMEM;
}
memset((void *)board->ccb, 0, sizeof(munich_ccb_t));
board->ccb->csa = virt_to_phys(board->ccb);
ccb = board->ccb;
for (i = 0; i < 32; i++)
{
ccb->timeslot_spec[i].tti = 1;
ccb->timeslot_spec[i].rti = 1;
}
/* Interrupt queues: */
board->tiq = kmalloc(MUNICH_INTQSIZE, GFP_KERNEL);
if (board->tiq == NULL)
{
spin_unlock_irqrestore(&mister_lock, flags);
free_stuff(board, ch);
return -ENOMEM;
}
memset((void *)board->tiq, 0, MUNICH_INTQSIZE);
board->riq = kmalloc(MUNICH_INTQSIZE, GFP_KERNEL);
if (board->riq == NULL)
{
spin_unlock_irqrestore(&mister_lock, flags);
free_stuff(board, ch);
return -ENOMEM;
}
memset((void *)board->riq, 0, MUNICH_INTQSIZE);
board->piq = kmalloc(MUNICH_PIQSIZE, GFP_KERNEL);
if (board->piq == NULL)
{
spin_unlock_irqrestore(&mister_lock, flags);
free_stuff(board, ch);
return -ENOMEM;
}
memset((void *)board->piq, 0, MUNICH_PIQSIZE);
board->tiq_ptr = 0;
board->riq_ptr = 0;
board->piq_ptr = 0;
/* Request irq: */
board->irq = 0;
/* (char*) cast to avoid warning about discarding volatile: */
if (request_irq(board->pci->irq, MUNICH_interrupt, 0,
(char *)board->devname, (void *)board))
{
printk("MUNICH_open: %s: unable to obtain irq %d\n", board->devname,
board->pci->irq);
/* TOD: free other resources (a sok malloc feljebb) */
spin_unlock_irqrestore(&mister_lock, flags);
free_stuff(board, ch);
return -EAGAIN;
}
board->irq = board->pci->irq; /* csak akkor legyen != 0, ha tenyleg le van foglalva nekunk */
/* Programming device: */
/* Reset the board like a power-on: */
/* TOD:
- It is not a real power-on: if a DMA transaction fails with master abort, the board
stays in half-dead state.
- It doesn't reset the FALC line driver */
pci_write_config_dword(board->pci, MUNICH_PCI_PCIRES, 0xe0000);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
pci_write_config_dword(board->pci, MUNICH_PCI_PCIRES, 0);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
writel(virt_to_phys(&ccb->csa), MUNICH_VIRT(CCBA));
writel(virt_to_phys( board->tiq ), MUNICH_VIRT(TIQBA));
writel(MUNICH_INTQLEN, MUNICH_VIRT(TIQL));
writel(virt_to_phys( board->riq ), MUNICH_VIRT(RIQBA));
writel(MUNICH_INTQLEN, MUNICH_VIRT(RIQL));
writel(virt_to_phys( board->piq ), MUNICH_VIRT(PIQBA));
writel(MUNICH_PIQLEN, MUNICH_VIRT(PIQL));
/* Put the magic values into the registers: */
writel(MODE1_MAGIC, MUNICH_VIRT(MODE1));
writel(MODE2_MAGIC, MUNICH_VIRT(MODE2));
writel(LREG0_MAGIC, MUNICH_VIRT(LREG0));
writel(LREG1_MAGIC, MUNICH_VIRT(LREG1));
writel(LREG2_MAGIC, MUNICH_VIRT(LREG2));
writel(LREG3_MAGIC, MUNICH_VIRT(LREG3));
writel(LREG4_MAGIC, MUNICH_VIRT(LREG4));
writel(LREG5_MAGIC, MUNICH_VIRT(LREG5));
writel(LCONF_MAGIC1, MUNICH_VIRT(LCONF)); /* reset the DMSM */
writel(LCONF_MAGIC2, MUNICH_VIRT(LCONF)); /* enable the DMSM */
writel(~0, MUNICH_VIRT(TXPOLL));
writel(board->isx21 ? 0x1400 : 0xa000, MUNICH_VIRT(GPDIR));
if (readl(MUNICH_VIRT(STAT))) writel(readl(MUNICH_VIRT(STAT)), MUNICH_VIRT(STAT));
ccb->action_spec = CCB_ACTIONSPEC_RES | CCB_ACTIONSPEC_IA;
writel(CMD_ARPCM, MUNICH_VIRT(CMD)); /* Start the PCM core reset */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
stat = 0; /* Wait for the action to complete max. 1 second */
jiffs = jiffies;
while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ))
{
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
}
if (stat & STAT_PCMF)
{
printk(KERN_ERR
"MUNICH_open: %s: Initial ARPCM failed. STAT=0x%08x\n",
board->devname, stat);
writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT));
free_irq(board->irq, (void *)board); /* TOD: free other resources too *//* maybe shut down hw? */
board->irq = 0;
spin_unlock_irqrestore(&mister_lock, flags);
free_stuff(board, ch);
return -EAGAIN;
}
else if (!(stat & STAT_PCMA))
{
printk(KERN_ERR
"MUNICH_open: %s: Initial ARPCM timeout. STAT=0x%08x\n",
board->devname, stat);
free_irq(board->irq, (void *)board); /* TOD: free other resources too *//* maybe shut off the hw? */
board->irq = 0;
spin_unlock_irqrestore(&mister_lock, flags);
free_stuff(board, ch);
return -EIO;
}
writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT)); /* Acknowledge */
if (board->isx21) writel(0, MUNICH_VIRT(GPDATA));
printk("MUNICH_open: %s: succesful HW-open took %ld jiffies\n",
board->devname, jiffies - jiffs);
/* Set up the FALC hanging on the Local Bus: */
if (!board->isx21)
{
writeb(0x0e, lbi + FMR1);
writeb(0, lbi + LIM0);
writeb(0xb0, lbi + LIM1); /* TODO: input threshold */
writeb(0xf7, lbi + XPM0);
writeb(0x02, lbi + XPM1);
writeb(0x00, lbi + XPM2);
writeb(0xf0, lbi + FMR0);
writeb(0x80, lbi + PCD);
writeb(0x80, lbi + PCR);
writeb(0x00, lbi + LIM2);
writeb(0x07, lbi + XC0);
writeb(0x3d, lbi + XC1);
writeb(0x05, lbi + RC0);
writeb(0x00, lbi + RC1);
writeb(0x83, lbi + FMR2);
writeb(0x9f, lbi + XSW);
writeb(0x0f, lbi + XSP);
writeb(0x00, lbi + TSWM);
writeb(0xe0, lbi + MODE);
writeb(0xff, lbi + IDLE); /* Idle Code to send in unused timeslots */
writeb(0x83, lbi + IPC); /* interrupt query line mode: Push/pull output, active high */
writeb(0xbf, lbi + IMR3); /* send an interrupt every second */
slicecom_set_framing(hw->boardnum, board->framing);
slicecom_set_linecode(hw->boardnum, board->linecode);
slicecom_set_clock_source(hw->boardnum, board->clock_source);
slicecom_set_loopback(hw->boardnum, board->loopback);
memset((void *)board->intervals, 0, sizeof(board->intervals));
board->current_interval = 0;
board->elapsed_seconds = 0;
board->ses_seconds = 0;
board->is_unavailable = 0;
board->no_ses_seconds = 0;
board->deg_elapsed_seconds = 0;
board->deg_cumulated_errors = 0;
}
/* Enable the interrupts last */
/* These interrupts will be enabled. We do not need the others. */
writel(readl(MUNICH_VIRT(IMASK)) & ~(STAT_PTI | STAT_PRI | STAT_LBII | STAT_TSPA | STAT_RSPA), MUNICH_VIRT(IMASK));
}
spin_unlock_irqrestore(&mister_lock, flags);
dev->irq = board->irq; /* hogy szep legyen az ifconfig outputja */
ccb = board->ccb; /* TOD: ez igy csunya egy kicsit hogy benn is meg kinn is beletoltom :( */
spin_lock_irqsave(&mister_lock, flags);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
/* Check if the selected timeslots aren't used already */
for (i = 0; i < 32; i++)
if (((1 << i) & timeslots) && ccb->timeslot_spec[i].tti == 0)
{
printk("MUNICH_open: %s: timeslot %d already used by %s\n",
dev->name, i, board->twins[ccb->timeslot_spec[i].txchannel]->name);
spin_unlock_irqrestore(&mister_lock, flags);
free_stuff(board, ch);
return -EBUSY; /* TOD: lehet hogy valami mas errno kellene? */
}
/* find a free channel: */
/* TODO: ugly, rewrite it */
for (channel = 0; channel <= 32; channel++)
{
if (channel == 32)
{ /* not found a free one */
printk
("MUNICH_open: %s: FATAL: can not find a free channel - this should not happen!\n",
dev->name);
spin_unlock_irqrestore(&mister_lock, flags);
free_stuff(board, ch);
return -ENODEV;
}
if (board->twins[channel] == NULL)
break; /* found the first free one */
}
board->lastcheck = jiffies; /* avoid checking uninitialized hardware channel */
/* Open the channel. If fails, calls MUNICH_close() to properly free resources and stop the HW */
hw->channel = channel;
board->twins[channel] = dev;
board->use_count++; /* meg nem nyitottuk meg a csatornat, de a twins-ben
mar elfoglaltunk egyet, es ha a _close-t akarjuk hivni, akkor ez kell. */
for (i = 0; i < 32; i++)
if ((1 << i) & timeslots)
{
ccb->timeslot_spec[i].tti = 0;
ccb->timeslot_spec[i].txchannel = channel;
ccb->timeslot_spec[i].txfillmask = ~0;
ccb->timeslot_spec[i].rti = 0;
ccb->timeslot_spec[i].rxchannel = channel;
ccb->timeslot_spec[i].rxfillmask = ~0;
}
if (!board->isx21) rework_idle_channels(dev);
memset((void *)&(hw->tx_desc), 0, TX_DESC_MAX * sizeof(tx_desc_t));
memset((void *)&(hw->rx_desc), 0, RX_DESC_MAX * sizeof(rx_desc_t));
for (i = 0; i < TX_DESC_MAX; i++)
{
hw->tx_desc[i].fe = 1;
hw->tx_desc[i].fnum = 2;
hw->tx_desc[i].data = virt_to_phys( & (hw->tx_data[i][0]) );
hw->tx_desc[i].next = virt_to_phys( & (hw->tx_desc[ (i+1) % TX_DESC_MAX ]) );
}
hw->tx_desc_ptr = 0; /* we will send an initial packet so it is correct: "oda irtunk utoljara" */
hw->busy = 0;
hw->tx_desc[hw->tx_desc_ptr].hold = 1;
hw->tx_desc[hw->tx_desc_ptr].no = 1; /* TOD: inkabb csak 0 hosszut kuldjunk ki az initkor? */
for (i = 0; i < RX_DESC_MAX; i++)
{
hw->rx_desc[i].no = RXBUFFER_SIZE;
hw->rx_desc[i].data = virt_to_phys(&(hw->rx_data[i][0]));
hw->rx_desc[i].next = virt_to_phys(&(hw->rx_desc[(i+1) % RX_DESC_MAX]));
hw->rx_desc[i].status = 0xFF;
}
hw->rx_desc_ptr = 0;
hw->rx_desc[(hw->rx_desc_ptr + RX_DESC_MAX - 2) % RX_DESC_MAX].hold = 1;
memset((void *)&ccb->channel_spec[channel], 0, sizeof(channel_spec_t));
ccb->channel_spec[channel].ti = 0; /* Transmit off */
ccb->channel_spec[channel].to = 1;
ccb->channel_spec[channel].ta = 0;
ccb->channel_spec[channel].th = 1; /* Transmit hold */
ccb->channel_spec[channel].ri = 0; /* Receive off */
ccb->channel_spec[channel].ro = 1;
ccb->channel_spec[channel].ra = 0;
ccb->channel_spec[channel].mode = 3; /* HDLC */
ccb->action_spec = CCB_ACTIONSPEC_IN | (channel << 8);
writel(CMD_ARPCM, MUNICH_VIRT(CMD));
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
spin_unlock_irqrestore(&mister_lock, flags);
stat = 0;
jiffs = jiffies;
while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ))
{
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
}
if (stat & STAT_PCMF)
{
printk(KERN_ERR "MUNICH_open: %s: %s channel %d off failed\n",
dev->name, board->devname, channel);
writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT));
MUNICH_close(dev);
return -EAGAIN;
}
else if (!(stat & STAT_PCMA))
{
printk(KERN_ERR "MUNICH_open: %s: %s channel %d off timeout\n",
dev->name, board->devname, channel);
MUNICH_close(dev);
return -EIO;
}
writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT));
// printk("MUNICH_open: %s: succesful channel off took %ld jiffies\n", board->devname, jiffies-jiffs);
spin_lock_irqsave(&mister_lock, flags);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
ccb->channel_spec[channel].ifc = 1; /* 1 .. 'Idle/Flag change' interrupt letiltva */
ccb->channel_spec[channel].fit = 1;
ccb->channel_spec[channel].nitbs = 1;
ccb->channel_spec[channel].itbs = 2;
/* TODOO: lehet hogy jo lenne igy, de utana kellene nezni hogy nem okoz-e fragmentaciot */
// ccb->channel_spec[channel].itbs = 2 * number_of_timeslots;
// printk("open: %s: number_of_timeslots: %d\n", dev->name, number_of_timeslots);
ccb->channel_spec[channel].mode = 3; /* HDLC */
ccb->channel_spec[channel].ftda = virt_to_phys(&(hw->tx_desc));
ccb->channel_spec[channel].frda = virt_to_phys(&(hw->rx_desc[0]));
ccb->channel_spec[channel].ti = 1; /* Transmit init */
ccb->channel_spec[channel].to = 0;
ccb->channel_spec[channel].ta = 1;
ccb->channel_spec[channel].th = 0;
ccb->channel_spec[channel].ri = 1; /* Receive init */
ccb->channel_spec[channel].ro = 0;
ccb->channel_spec[channel].ra = 1;
ccb->action_spec = CCB_ACTIONSPEC_ICO | (channel << 8);
writel(CMD_ARPCM, MUNICH_VIRT(CMD)); /* Start the channel init */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
spin_unlock_irqrestore(&mister_lock, flags);
stat = 0; /* Wait for the action to complete max. 1 second */
jiffs = jiffies;
while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ))
{
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
}
if (stat & STAT_PCMF)
{
printk(KERN_ERR "MUNICH_open: %s: channel open ARPCM failed\n",
board->devname);
writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT));
MUNICH_close(dev);
return -EAGAIN;
}
else if (!(stat & STAT_PCMA))
{
printk(KERN_ERR "MUNICH_open: %s: channel open ARPCM timeout\n",
board->devname);
MUNICH_close(dev);
return -EIO;
}
writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT));
// printk("MUNICH_open: %s: succesful channel open took %ld jiffies\n", board->devname, jiffies-jiffs);
spin_lock_irqsave(&mister_lock, flags);
ccb->channel_spec[channel].nitbs = 0; /* once ITBS defined, these must be 0 */
ccb->channel_spec[channel].itbs = 0;
if (board->isx21)
{
board->modemline_timer.data = (unsigned int)board;
board->modemline_timer.function = pcicom_modemline;
board->modemline_timer.expires = jiffies + HZ;
add_timer((struct timer_list *)&board->modemline_timer);
}
/* It is done. Declare that we're open: */
hw->busy = 0; /* It may be 1 if the frame at Tx init already ended, but it is not */
/* a real problem: we compute hw->busy on every interrupt */
hw->rafutott = 0;
ch->init_status |= HW_OPEN;
/* Initialize line state: */
if (board->lineup)
ch->line_status |= LINE_UP;
else
ch->line_status &= ~LINE_UP;
/* Remove w attribute from /proc files associated to hw parameters:
no write when the device is open */
for (; procfile; procfile = procfile->next)
if (strcmp(procfile->name, FILENAME_BOARDNUM) == 0 ||
strcmp(procfile->name, FILENAME_TIMESLOTS) == 0)
procfile->mode = S_IFREG | 0444;
spin_unlock_irqrestore(&mister_lock, flags);
return 0;
}
/*
* Hardware close routine.
* Called by comx (upper) layer when the user wants to bring down the interface
* with ifconfig.
* We also call it from MUNICH_open, if the open fails.
* Brings down hardware, frees resources, stops receiver
* Returns 0 on OK, or standard error value on error.
*/
static int MUNICH_close(struct net_device *dev)
{
struct comx_channel *ch = dev->priv;
struct slicecom_privdata *hw = ch->HW_privdata;
struct proc_dir_entry *procfile = ch->procdir->subdir;
munich_board_t *board;
munich_ccb_t *ccb;
u32 *bar1;
u32 timeslots = hw->timeslots;
int stat, i, channel = hw->channel;
unsigned long jiffs;
board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
ccb = board->ccb;
bar1 = board->bar1;
if (board->isx21)
del_timer((struct timer_list *)&board->modemline_timer);
spin_lock_irqsave(&mister_lock, flags);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
/* Disable receiver for the channel: */
for (i = 0; i < 32; i++)
if ((1 << i) & timeslots)
{
ccb->timeslot_spec[i].tti = 1;
ccb->timeslot_spec[i].txfillmask = 0; /* just to be double-sure :) */
ccb->timeslot_spec[i].rti = 1;
ccb->timeslot_spec[i].rxfillmask = 0;
}
if (!board->isx21) rework_idle_channels(dev);
ccb->channel_spec[channel].ti = 0; /* Receive off, Transmit off */
ccb->channel_spec[channel].to = 1;
ccb->channel_spec[channel].ta = 0;
ccb->channel_spec[channel].th = 1;
ccb->channel_spec[channel].ri = 0;
ccb->channel_spec[channel].ro = 1;
ccb->channel_spec[channel].ra = 0;
board->twins[channel] = NULL;
ccb->action_spec = CCB_ACTIONSPEC_IN | (channel << 8);
writel(CMD_ARPCM, MUNICH_VIRT(CMD));
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
spin_unlock_irqrestore(&mister_lock, flags);
stat = 0;
jiffs = jiffies;
while (!((stat = readl(MUNICH_VIRT(STAT))) & (STAT_PCMA | STAT_PCMF)) && time_before(jiffies, jiffs + HZ))
{
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
}
if (stat & STAT_PCMF)
{
printk(KERN_ERR
"MUNICH_close: %s: FATAL: channel off ARPCM failed, not closing!\n",
dev->name);
writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMF, MUNICH_VIRT(STAT));
/* If we return success, the privdata (and the descriptor list) will be freed */
return -EIO;
}
else if (!(stat & STAT_PCMA))
printk(KERN_ERR "MUNICH_close: %s: channel off ARPCM timeout\n",
board->devname);
writel(readl(MUNICH_VIRT(STAT)) & STAT_PCMA, MUNICH_VIRT(STAT));
// printk("MUNICH_close: %s: channel off took %ld jiffies\n", board->devname, jiffies-jiffs);
spin_lock_irqsave(&mister_lock, flags);
board->use_count--;
if (!board->use_count) /* we were the last user of the board */
{
printk("MUNICH_close: bringing down board %s\n", board->devname);
/* program down the board: */
writel(0x0000FF7F, MUNICH_VIRT(IMASK)); /* do not send any interrupts */
writel(0, MUNICH_VIRT(CMD)); /* stop the timer if someone started it */
writel(~0U, MUNICH_VIRT(STAT)); /* if an interrupt came between the cli()-sti(), quiet it */
if (ch->hardware == &pcicomhw)
writel(0x1400, MUNICH_VIRT(GPDATA));
/* Put the board into 'reset' state: */
pci_write_config_dword(board->pci, MUNICH_PCI_PCIRES, 0xe0000);
/* Free irq and other resources: */
if (board->irq)
free_irq(board->irq, (void *)board); /* Ha nem inicializalta magat, akkor meg nincs irq */
board->irq = 0;
free_stuff(board, ch);
}
/* Enable setting of hw parameters */
for (; procfile; procfile = procfile->next)
if (strcmp(procfile->name, FILENAME_BOARDNUM) == 0 ||
strcmp(procfile->name, FILENAME_TIMESLOTS) == 0)
procfile->mode = S_IFREG | 0644;
/* We're not open anymore */
ch->init_status &= ~HW_OPEN;
spin_unlock_irqrestore(&mister_lock, flags);
return 0;
}
/*
* Give (textual) status information.
* The text it returns will be a part of what appears when the user does a
* cat /proc/comx/comx[n]/status
* Don't write more than PAGESIZE.
* Return value: number of bytes written (length of the string, incl. 0)
*/
static int MUNICH_minden(struct net_device *dev, char *page)
{
struct comx_channel *ch = dev->priv;
struct slicecom_privdata *hw = ch->HW_privdata;
munich_board_t *board;
struct net_device *devp;
u8 *lbi;
e1_stats_t *curr_int, *prev_int;
e1_stats_t last4, last96; /* sum of last 4, resp. last 96 intervals */
unsigned *sump, /* running pointer for the sum data */
*p; /* running pointer for the interval data */
int len = 0;
u8 frs0, frs1;
u8 fmr2;
int i, j;
u32 timeslots;
board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
lbi = board->lbi;
curr_int = &board->intervals[board->current_interval];
prev_int =
&board->
intervals[(board->current_interval + SLICECOM_BOARD_INTERVALS_SIZE -
1) % SLICECOM_BOARD_INTERVALS_SIZE];
if (!board->isx21)
{
frs0 = readb(lbi + FRS0);
fmr2 = readb(lbi + FMR2);
len += snprintf(page + len, PAGE_SIZE - len, "Controller status:\n");
if (frs0 == 0)
len += snprintf(page + len, PAGE_SIZE - len, "\tNo alarms\n");
else
{
if (frs0 & FRS0_LOS)
len += snprintf(page + len, PAGE_SIZE - len, "\tLoss Of Signal\n");
else
{
if (frs0 & FRS0_AIS)
len += snprintf(page + len, PAGE_SIZE - len,
"\tAlarm Indication Signal\n");
else
{
if (frs0 & FRS0_AUXP)
len += snprintf(page + len, PAGE_SIZE - len,
"\tAuxiliary Pattern Indication\n");
if (frs0 & FRS0_LFA)
len += snprintf(page + len, PAGE_SIZE - len,
"\tLoss of Frame Alignment\n");
else
{
if (frs0 & FRS0_RRA)
len += snprintf(page + len, PAGE_SIZE - len,
"\tReceive Remote Alarm\n");
/* You can't set this framing with the /proc interface, but it */
/* may be good to have here this alarm if you set it by hand: */
if ((board->framing == SLICECOM_FRAMING_CRC4) &&
(frs0 & FRS0_LMFA))
len += snprintf(page + len, PAGE_SIZE - len,
"\tLoss of CRC4 Multiframe Alignment\n");
if (((fmr2 & 0xc0) == 0xc0) && (frs0 & FRS0_NMF))
len += snprintf(page + len, PAGE_SIZE - len,
"\tNo CRC4 Multiframe alignment Found after 400 msec\n");
}
}
}
}
frs1 = readb(lbi + FRS1);
if (FRS1_XLS & frs1)
len += snprintf(page + len, PAGE_SIZE - len,
"\tTransmit Line Short\n");
/* debug Rx ring: DEL: - vagy meghagyni, de akkor legyen kicsit altalanosabb */
}
len += snprintf(page + len, PAGE_SIZE - len, "Rx ring:\n");
len += snprintf(page + len, PAGE_SIZE - len, "\trafutott: %d\n", hw->rafutott);
len += snprintf(page + len, PAGE_SIZE - len,
"\tlastcheck: %ld, jiffies: %ld\n", board->lastcheck, jiffies);
len += snprintf(page + len, PAGE_SIZE - len, "\tbase: %08x\n",
(u32) virt_to_phys(&hw->rx_desc[0]));
len += snprintf(page + len, PAGE_SIZE - len, "\trx_desc_ptr: %d\n",
hw->rx_desc_ptr);
len += snprintf(page + len, PAGE_SIZE - len, "\trx_desc_ptr: %08x\n",
(u32) virt_to_phys(&hw->rx_desc[hw->rx_desc_ptr]));
len += snprintf(page + len, PAGE_SIZE - len, "\thw_curr_ptr: %08x\n",
board->ccb->current_rx_desc[hw->channel]);
for (i = 0; i < RX_DESC_MAX; i++)
len += snprintf(page + len, PAGE_SIZE - len, "\t%08x %08x %08x %08x\n",
*((u32 *) & hw->rx_desc[i] + 0),
*((u32 *) & hw->rx_desc[i] + 1),
*((u32 *) & hw->rx_desc[i] + 2),
*((u32 *) & hw->rx_desc[i] + 3));
if (!board->isx21)
{
len += snprintf(page + len, PAGE_SIZE - len,
"Interfaces using this board: (channel-group, interface, timeslots)\n");
for (i = 0; i < 32; i++)
{
devp = board->twins[i];
if (devp != NULL)
{
timeslots =
((struct slicecom_privdata *)((struct comx_channel *)devp->
priv)->HW_privdata)->
timeslots;
len += snprintf(page + len, PAGE_SIZE - len, "\t%2d %s: ", i,
devp->name);
for (j = 0; j < 32; j++)
if ((1 << j) & timeslots)
len += snprintf(page + len, PAGE_SIZE - len, "%d ", j);
len += snprintf(page + len, PAGE_SIZE - len, "\n");
}
}
}
len += snprintf(page + len, PAGE_SIZE - len, "Interrupt work histogram:\n");
for (i = 0; i < MAX_WORK; i++)
len += snprintf(page + len, PAGE_SIZE - len, "hist[%2d]: %8u%c", i,
board->histogram[i], (i &&
((i + 1) % 4 == 0 ||
i == MAX_WORK - 1)) ? '\n' : ' ');
len += snprintf(page + len, PAGE_SIZE - len, "Tx ring histogram:\n");
for (i = 0; i < TX_DESC_MAX; i++)
len += snprintf(page + len, PAGE_SIZE - len, "hist[%2d]: %8u%c", i,
hw->tx_ring_hist[i], (i &&
((i + 1) % 4 == 0 ||
i ==
TX_DESC_MAX - 1)) ? '\n' : ' ');
if (!board->isx21)
{
memset((void *)&last4, 0, sizeof(last4));
memset((void *)&last96, 0, sizeof(last96));
/* Calculate the sum of last 4 intervals: */
for (i = 1; i <= 4; i++)
{
p = (unsigned *)&board->intervals[(board->current_interval +
SLICECOM_BOARD_INTERVALS_SIZE -
i) % SLICECOM_BOARD_INTERVALS_SIZE];
sump = (unsigned *)&last4;
for (j = 0; j < (sizeof(e1_stats_t) / sizeof(unsigned)); j++)
sump[j] += p[j];
}
/* Calculate the sum of last 96 intervals: */
for (i = 1; i <= 96; i++)
{
p = (unsigned *)&board->intervals[(board->current_interval +
SLICECOM_BOARD_INTERVALS_SIZE -
i) % SLICECOM_BOARD_INTERVALS_SIZE];
sump = (unsigned *)&last96;
for (j = 0; j < (sizeof(e1_stats_t) / sizeof(unsigned)); j++)
sump[j] += p[j];
}
len += snprintf(page + len, PAGE_SIZE - len,
"Data in current interval (%d seconds elapsed):\n",
board->elapsed_seconds);
len += snprintf(page + len, PAGE_SIZE - len,
" %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n",
curr_int->line_code_violations,
curr_int->path_code_violations, curr_int->e_bit_errors);
len += snprintf(page + len, PAGE_SIZE - len,
" %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n",
curr_int->slip_secs, curr_int->fr_loss_secs,
curr_int->line_err_secs, curr_int->degraded_mins);
len += snprintf(page + len, PAGE_SIZE - len,
" %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n",
curr_int->errored_secs, curr_int->bursty_err_secs,
curr_int->severely_err_secs, curr_int->unavail_secs);
len += snprintf(page + len, PAGE_SIZE - len,
"Data in Interval 1 (15 minutes):\n");
len += snprintf(page + len, PAGE_SIZE - len,
" %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n",
prev_int->line_code_violations,
prev_int->path_code_violations, prev_int->e_bit_errors);
len += snprintf(page + len, PAGE_SIZE - len,
" %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n",
prev_int->slip_secs, prev_int->fr_loss_secs,
prev_int->line_err_secs, prev_int->degraded_mins);
len += snprintf(page + len, PAGE_SIZE - len,
" %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n",
prev_int->errored_secs, prev_int->bursty_err_secs,
prev_int->severely_err_secs, prev_int->unavail_secs);
len += snprintf(page + len, PAGE_SIZE - len,
"Data in last 4 intervals (1 hour):\n");
len += snprintf(page + len, PAGE_SIZE - len,
" %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n",
last4.line_code_violations, last4.path_code_violations,
last4.e_bit_errors);
len += snprintf(page + len, PAGE_SIZE - len,
" %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n",
last4.slip_secs, last4.fr_loss_secs, last4.line_err_secs,
last4.degraded_mins);
len += snprintf(page + len, PAGE_SIZE - len,
" %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n",
last4.errored_secs, last4.bursty_err_secs,
last4.severely_err_secs, last4.unavail_secs);
len += snprintf(page + len, PAGE_SIZE - len,
"Data in last 96 intervals (24 hours):\n");
len += snprintf(page + len, PAGE_SIZE - len,
" %d Line Code Violations, %d Path Code Violations, %d E-Bit Errors\n",
last96.line_code_violations, last96.path_code_violations,
last96.e_bit_errors);
len += snprintf(page + len, PAGE_SIZE - len,
" %d Slip Secs, %d Fr Loss Secs, %d Line Err Secs, %d Degraded Mins\n",
last96.slip_secs, last96.fr_loss_secs,
last96.line_err_secs, last96.degraded_mins);
len += snprintf(page + len, PAGE_SIZE - len,
" %d Errored Secs, %d Bursty Err Secs, %d Severely Err Secs, %d Unavail Secs\n",
last96.errored_secs, last96.bursty_err_secs,
last96.severely_err_secs, last96.unavail_secs);
}
// len +=snprintf( page + len, PAGE_SIZE - len, "Special events:\n" );
// len +=snprintf( page + len, PAGE_SIZE - len, "\tstat_pri/missed: %u / %u\n", board->stat_pri_races, board->stat_pri_races_missed );
// len +=snprintf( page + len, PAGE_SIZE - len, "\tstat_pti/missed: %u / %u\n", board->stat_pti_races, board->stat_pti_races_missed );
return len;
}
/*
* Memory dump function. Not used currently.
*/
static int BOARD_dump(struct net_device *dev)
{
printk
("BOARD_dump() requested. It is unimplemented, it should not be called\n");
return (-1);
}
/*
* /proc file read function for the files registered by this module.
* This function is called by the procfs implementation when a user
* wants to read from a file registered by this module.
* page is the workspace, start should point to the real start of data,
* off is the file offset, data points to the file's proc_dir_entry
* structure.
* Returns the number of bytes copied to the request buffer.
*/
static int munich_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
struct proc_dir_entry *file = (struct proc_dir_entry *)data;
struct net_device *dev = file->parent->data;
struct comx_channel *ch = dev->priv;
struct slicecom_privdata *hw = ch->HW_privdata;
munich_board_t *board;
int len = 0, i;
u32 timeslots = hw->timeslots;
board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
if (!strcmp(file->name, FILENAME_BOARDNUM))
len = sprintf(page, "%d\n", hw->boardnum);
else if (!strcmp(file->name, FILENAME_TIMESLOTS))
{
for (i = 0; i < 32; i++)
if ((1 << i) & timeslots)
len += snprintf(page + len, PAGE_SIZE - len, "%d ", i);
len += snprintf(page + len, PAGE_SIZE - len, "\n");
}
else if (!strcmp(file->name, FILENAME_FRAMING))
{
i = 0;
while (slicecom_framings[i].value &&
slicecom_framings[i].value != board->framing)
i++;
len += snprintf(page + len, PAGE_SIZE - len, "%s\n",
slicecom_framings[i].name);
}
else if (!strcmp(file->name, FILENAME_LINECODE))
{
i = 0;
while (slicecom_linecodes[i].value &&
slicecom_linecodes[i].value != board->linecode)
i++;
len += snprintf(page + len, PAGE_SIZE - len, "%s\n",
slicecom_linecodes[i].name);
}
else if (!strcmp(file->name, FILENAME_CLOCK_SOURCE))
{
i = 0;
while (slicecom_clock_sources[i].value &&
slicecom_clock_sources[i].value != board->clock_source)
i++;
len +=
snprintf(page + len, PAGE_SIZE - len, "%s\n",
slicecom_clock_sources[i].name);
}
else if (!strcmp(file->name, FILENAME_LOOPBACK))
{
i = 0;
while (slicecom_loopbacks[i].value &&
slicecom_loopbacks[i].value != board->loopback)
i++;
len += snprintf(page + len, PAGE_SIZE - len, "%s\n",
slicecom_loopbacks[i].name);
}
/* We set permissions to write-only for REG and LBIREG, but root can read them anyway: */
else if (!strcmp(file->name, FILENAME_REG))
{
len += snprintf(page + len, PAGE_SIZE - len,
"%s: " FILENAME_REG ": write-only file\n", dev->name);
}
else if (!strcmp(file->name, FILENAME_LBIREG))
{
len += snprintf(page + len, PAGE_SIZE - len,
"%s: " FILENAME_LBIREG ": write-only file\n", dev->name);
}
else
{
printk("slicecom_read_proc: internal error, filename %s\n", file->name);
return -EBADF;
}
/* file handling administration: count eof status, offset, start address
and count: */
if (off >= len)
{
*eof = 1;
return 0;
}
*start = page + off;
if (count >= len - off)
*eof = 1;
return min((off_t) count, (off_t) len - off);
}
/*
* Write function for /proc files registered by us.
* See the comment on read function above.
* Beware! buffer is in userspace!!!
* Returns the number of bytes written
*/
static int munich_write_proc(struct file *file, const char *buffer,
u_long count, void *data)
{
struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
struct net_device *dev = (struct net_device *)entry->parent->data;
struct comx_channel *ch = dev->priv;
struct slicecom_privdata *hw = ch->HW_privdata;
munich_board_t *board;
unsigned long ts, tmp_boardnum;
u32 tmp_timeslots = 0;
char *page, *p;
int i;
board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
/* Paranoia checking: */
if (file->f_dentry->d_inode->i_ino != entry->low_ino)
{
printk(KERN_ERR "munich_write_proc: file <-> data internal error\n");
return -EIO;
}
/* Request tmp buffer */
if (!(page = (char *)__get_free_page(GFP_KERNEL)))
return -ENOMEM;
/* Copy user data and cut trailing \n */
copy_from_user(page, buffer, count = min(count, PAGE_SIZE));
if (*(page + count - 1) == '\n')
*(page + count - 1) = 0;
*(page + PAGE_SIZE - 1) = 0;
if (!strcmp(entry->name, FILENAME_BOARDNUM))
{
tmp_boardnum = simple_strtoul(page, NULL, 0);
if (0 <= tmp_boardnum && tmp_boardnum < MAX_BOARDS)
hw->boardnum = tmp_boardnum;
else
{
printk("%s: " FILENAME_BOARDNUM " range is 0...%d\n", dev->name,
MAX_BOARDS - 1);
free_page((unsigned long)page);
return -EINVAL;
}
}
else if (!strcmp(entry->name, FILENAME_TIMESLOTS))
{
p = page;
while (*p)
{
if (isspace(*p))
p++;
else
{
ts = simple_strtoul(p, &p, 10); /* base = 10: Don't read 09 as an octal number */
/* ts = 0 ha nem tudta beolvasni a stringet, erre egy kicsit epitek itt: */
if (0 <= ts && ts < 32)
{
tmp_timeslots |= (1 << ts);
}
else
{
printk("%s: " FILENAME_TIMESLOTS " range is 1...31\n",
dev->name);
free_page((unsigned long)page);
return -EINVAL;
}
}
}
hw->timeslots = tmp_timeslots;
}
else if (!strcmp(entry->name, FILENAME_FRAMING))
{
i = 0;
while (slicecom_framings[i].value &&
strncmp(slicecom_framings[i].name, page,
strlen(slicecom_framings[i].name)))
i++;
if (!slicecom_framings[i].value)
{
printk("slicecom: %s: Invalid " FILENAME_FRAMING " '%s'\n",
dev->name, page);
free_page((unsigned long)page);
return -EINVAL;
}
else
{ /*
* If somebody says:
* echo >boardnum 0
* echo >framing no-crc4
* echo >boardnum 1
* - when the framing was set, hw->boardnum was 0, so it would set the framing for board 0
* Workaround: allow to set it only if interface is administrative UP
*/
if (netif_running(dev))
slicecom_set_framing(hw->boardnum, slicecom_framings[i].value);
else
{
printk("%s: " FILENAME_FRAMING
" can not be set while the interface is DOWN\n",
dev->name);
free_page((unsigned long)page);
return -EINVAL;
}
}
}
else if (!strcmp(entry->name, FILENAME_LINECODE))
{
i = 0;
while (slicecom_linecodes[i].value &&
strncmp(slicecom_linecodes[i].name, page,
strlen(slicecom_linecodes[i].name)))
i++;
if (!slicecom_linecodes[i].value)
{
printk("slicecom: %s: Invalid " FILENAME_LINECODE " '%s'\n",
dev->name, page);
free_page((unsigned long)page);
return -EINVAL;
}
else
{ /*
* Allow to set it only if interface is administrative UP,
* for the same reason as FILENAME_FRAMING
*/
if (netif_running(dev))
slicecom_set_linecode(hw->boardnum,
slicecom_linecodes[i].value);
else
{
printk("%s: " FILENAME_LINECODE
" can not be set while the interface is DOWN\n",
dev->name);
free_page((unsigned long)page);
return -EINVAL;
}
}
}
else if (!strcmp(entry->name, FILENAME_CLOCK_SOURCE))
{
i = 0;
while (slicecom_clock_sources[i].value &&
strncmp(slicecom_clock_sources[i].name, page,
strlen(slicecom_clock_sources[i].name)))
i++;
if (!slicecom_clock_sources[i].value)
{
printk("%s: Invalid " FILENAME_CLOCK_SOURCE " '%s'\n", dev->name,
page);
free_page((unsigned long)page);
return -EINVAL;
}
else
{ /*
* Allow to set it only if interface is administrative UP,
* for the same reason as FILENAME_FRAMING
*/
if (netif_running(dev))
slicecom_set_clock_source(hw->boardnum,
slicecom_clock_sources[i].value);
else
{
printk("%s: " FILENAME_CLOCK_SOURCE
" can not be set while the interface is DOWN\n",
dev->name);
free_page((unsigned long)page);
return -EINVAL;
}
}
}
else if (!strcmp(entry->name, FILENAME_LOOPBACK))
{
i = 0;
while (slicecom_loopbacks[i].value &&
strncmp(slicecom_loopbacks[i].name, page,
strlen(slicecom_loopbacks[i].name)))
i++;
if (!slicecom_loopbacks[i].value)
{
printk("%s: Invalid " FILENAME_LOOPBACK " '%s'\n", dev->name, page);
free_page((unsigned long)page);
return -EINVAL;
}
else
{ /*
* Allow to set it only if interface is administrative UP,
* for the same reason as FILENAME_FRAMING
*/
if (netif_running(dev))
slicecom_set_loopback(hw->boardnum,
slicecom_loopbacks[i].value);
else
{
printk("%s: " FILENAME_LOOPBACK
" can not be set while the interface is DOWN\n",
dev->name);
free_page((unsigned long)page);
return -EINVAL;
}
}
}
else if (!strcmp(entry->name, FILENAME_REG))
{ /* DEL: 'reg' csak tmp */
char *p;
u32 *bar1 = board->bar1;
reg = simple_strtoul(page, &p, 0);
reg_ertek = simple_strtoul(p + 1, NULL, 0);
if (reg < 0x100)
{
printk("reg(0x%02x) := 0x%08x jiff: %lu\n", reg, reg_ertek, jiffies);
writel(reg_ertek, MUNICH_VIRT(reg >> 2));
}
else
{
printk("reg(0x%02x) is 0x%08x jiff: %lu\n", reg - 0x100,
readl(MUNICH_VIRT((reg - 0x100) >> 2)), jiffies);
}
}
else if (!strcmp(entry->name, FILENAME_LBIREG))
{ /* DEL: 'lbireg' csak tmp */
char *p;
u8 *lbi = board->lbi;
lbireg = simple_strtoul(page, &p, 0);
lbireg_ertek = simple_strtoul(p + 1, NULL, 0);
if (lbireg < 0x100)
{
printk("lbireg(0x%02x) := 0x%02x jiff: %lu\n", lbireg,
lbireg_ertek, jiffies);
writeb(lbireg_ertek, lbi + lbireg);
}
else
printk("lbireg(0x%02x) is 0x%02x jiff: %lu\n", lbireg - 0x100,
readb(lbi + lbireg - 0x100), jiffies);
}
else
{
printk(KERN_ERR "munich_write_proc: internal error, filename %s\n",
entry->name);
free_page((unsigned long)page);
return -EBADF;
}
/* Don't forget to free the workspace */
free_page((unsigned long)page);
return count;
}
/*
* Boardtype init function.
* Called by the comx (upper) layer, when you set boardtype.
* Allocates resources associated to using munich board for this device,
* initializes ch_struct pointers etc.
* Returns 0 on success and standard error codes on error.
*/
static int init_escape(struct comx_channel *ch)
{
kfree(ch->HW_privdata);
return -EIO;
}
static int BOARD_init(struct net_device *dev)
{
struct comx_channel *ch = (struct comx_channel *)dev->priv;
struct slicecom_privdata *hw;
struct proc_dir_entry *new_file;
/* Alloc data for private structure */
if ((ch->HW_privdata =
kmalloc(sizeof(struct slicecom_privdata), GFP_KERNEL)) == NULL)
return -ENOMEM;
memset(hw = ch->HW_privdata, 0, sizeof(struct slicecom_privdata));
/* Register /proc files */
if ((new_file = create_proc_entry(FILENAME_BOARDNUM, S_IFREG | 0644,
ch->procdir)) == NULL)
return init_escape(ch);
new_file->data = (void *)new_file;
new_file->read_proc = &munich_read_proc;
new_file->write_proc = &munich_write_proc;
// new_file->proc_iops = &comx_normal_inode_ops;
new_file->nlink = 1;
if (ch->hardware == &slicecomhw)
{
if ((new_file = create_proc_entry(FILENAME_TIMESLOTS, S_IFREG | 0644,
ch->procdir)) == NULL)
return init_escape(ch);
new_file->data = (void *)new_file;
new_file->read_proc = &munich_read_proc;
new_file->write_proc = &munich_write_proc;
// new_file->proc_iops = &comx_normal_inode_ops;
new_file->nlink = 1;
if ((new_file = create_proc_entry(FILENAME_FRAMING, S_IFREG | 0644,
ch->procdir)) == NULL)
return init_escape(ch);
new_file->data = (void *)new_file;
new_file->read_proc = &munich_read_proc;
new_file->write_proc = &munich_write_proc;
// new_file->proc_iops = &comx_normal_inode_ops;
new_file->nlink = 1;
if ((new_file = create_proc_entry(FILENAME_LINECODE, S_IFREG | 0644,
ch->procdir)) == NULL)
return init_escape(ch);
new_file->data = (void *)new_file;
new_file->read_proc = &munich_read_proc;
new_file->write_proc = &munich_write_proc;
// new_file->proc_iops = &comx_normal_inode_ops;
new_file->nlink = 1;
if ((new_file = create_proc_entry(FILENAME_CLOCK_SOURCE, S_IFREG | 0644,
ch->procdir)) == NULL)
return init_escape(ch);
new_file->data = (void *)new_file;
new_file->read_proc = &munich_read_proc;
new_file->write_proc = &munich_write_proc;
// new_file->proc_iops = &comx_normal_inode_ops;
new_file->nlink = 1;
if ((new_file = create_proc_entry(FILENAME_LOOPBACK, S_IFREG | 0644,
ch->procdir)) == NULL)
return init_escape(ch);
new_file->data = (void *)new_file;
new_file->read_proc = &munich_read_proc;
new_file->write_proc = &munich_write_proc;
// new_file->proc_iops = &comx_normal_inode_ops;
new_file->nlink = 1;
}
/* DEL: ez itt csak fejlesztesi celokra!! */
if ((new_file = create_proc_entry(FILENAME_REG, S_IFREG | 0200, ch->procdir)) == NULL)
return init_escape(ch);
new_file->data = (void *)new_file;
new_file->read_proc = &munich_read_proc;
new_file->write_proc = &munich_write_proc;
// new_file->proc_iops = &comx_normal_inode_ops;
new_file->nlink = 1;
/* DEL: ez itt csak fejlesztesi celokra!! */
if ((new_file = create_proc_entry(FILENAME_LBIREG, S_IFREG | 0200,
ch->procdir)) == NULL)
return init_escape(ch);
new_file->data = (void *)new_file;
new_file->read_proc = &munich_read_proc;
new_file->write_proc = &munich_write_proc;
// new_file->proc_iops = &comx_normal_inode_ops;
new_file->nlink = 1;
/* Fill in ch_struct hw specific pointers: */
ch->HW_txe = MUNICH_txe;
ch->HW_open = MUNICH_open;
ch->HW_close = MUNICH_close;
ch->HW_send_packet = MUNICH_send_packet;
#ifndef COMX_NEW
ch->HW_minden = MUNICH_minden;
#else
ch->HW_statistics = MUNICH_minden;
#endif
hw->boardnum = SLICECOM_BOARDNUM_DEFAULT;
hw->timeslots = ch->hardware == &pcicomhw ? 0xffffffff : 2;
/* O.K. Count one more user on this module */
MOD_INC_USE_COUNT;
return 0;
}
/*
* Boardtype exit function.
* Called by the comx (upper) layer, when you clear boardtype from munich.
* Frees resources associated to using munich board for this device,
* resets ch_struct pointers etc.
*/
static int BOARD_exit(struct net_device *dev)
{
struct comx_channel *ch = (struct comx_channel *)dev->priv;
struct slicecom_privdata *hw = ch->HW_privdata;
// munich_board_t *board;
/* Free private data area */
// board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
kfree(ch->HW_privdata);
/* Remove /proc files */
remove_proc_entry(FILENAME_BOARDNUM, ch->procdir);
if (ch->hardware == &slicecomhw)
{
remove_proc_entry(FILENAME_TIMESLOTS, ch->procdir);
remove_proc_entry(FILENAME_FRAMING, ch->procdir);
remove_proc_entry(FILENAME_LINECODE, ch->procdir);
remove_proc_entry(FILENAME_CLOCK_SOURCE, ch->procdir);
remove_proc_entry(FILENAME_LOOPBACK, ch->procdir);
}
remove_proc_entry(FILENAME_REG, ch->procdir);
remove_proc_entry(FILENAME_LBIREG, ch->procdir);
/* Minus one user for the module accounting */
MOD_DEC_USE_COUNT;
return 0;
}
static struct comx_hardware slicecomhw =
{
"slicecom",
#ifdef COMX_NEW
VERSION,
#endif
BOARD_init,
BOARD_exit,
BOARD_dump,
NULL
};
static struct comx_hardware pcicomhw =
{
"pcicom",
#ifdef COMX_NEW
VERSION,
#endif
BOARD_init,
BOARD_exit,
BOARD_dump,
NULL
};
/* Module management */
int __init init_mister(void)
{
printk(VERSIONSTR);
comx_register_hardware(&slicecomhw);
comx_register_hardware(&pcicomhw);
return munich_probe();
}
static void __exit cleanup_mister(void)
{
int i;
comx_unregister_hardware("slicecom");
comx_unregister_hardware("pcicom");
for (i = 0; i < MAX_BOARDS; i++)
{
if (slicecom_boards[i].bar1)
iounmap((void *)slicecom_boards[i].bar1);
if (slicecom_boards[i].lbi)
iounmap((void *)slicecom_boards[i].lbi);
if (pcicom_boards[i].bar1)
iounmap((void *)pcicom_boards[i].bar1);
if (pcicom_boards[i].lbi)
iounmap((void *)pcicom_boards[i].lbi);
}
}
module_init(init_mister);
module_exit(cleanup_mister);
/* /*
* Device driver framework for the COMX line of synchronous serial boards * Device driver framework for the COMX line of synchronous serial boards
* *
* for Linux kernel 2.2.X * for Linux kernel 2.2.X / 2.4.X
* *
* Original authors: Arpad Bakay <bakay.arpad@synergon.hu>, * Original authors: Arpad Bakay <bakay.arpad@synergon.hu>,
* Peter Bajan <bajan.peter@synergon.hu>, * Peter Bajan <bajan.peter@synergon.hu>,
......
/*
* Defines for comx-hw-slicecom.c - FALC-LH specific
*
* Author: Bartok Istvan <bartoki@itc.hu>
* Last modified: Mon Feb 7 20:00:38 CET 2000
*
* :set tabstop=6
*/
/*
* Control register offsets on the LBI (page 90)
* use it like:
* lbi[ MODE ] = 0x34;
*/
#define MODE 0x03
#define IPC 0x08
#define IMR0 0x14 /* Interrupt Mask Register 0 */
#define IMR1 0x15
#define IMR2 0x16
#define IMR3 0x17
#define IMR4 0x18
#define IMR5 0x19
#define FMR0 0x1a /* Framer Mode Register 0 */
#define FMR1 0x1b
#define FMR2 0x1c
#define XSW 0x1e
#define XSP 0x1f
#define XC0 0x20
#define XC1 0x21
#define RC0 0x22
#define RC1 0x23
#define XPM0 0x24
#define XPM1 0x25
#define XPM2 0x26
#define TSWM 0x27
#define IDLE 0x29 /* Idle Code */
#define LIM0 0x34
#define LIM1 0x35
#define PCD 0x36
#define PCR 0x37
#define LIM2 0x38
/*
* Status registers on the LBI (page 134)
* these are read-only, use it like:
* if( lbi[ FRS0 ] ) ...
*/
#define FRS0 0x4c /* Framer Receive Status register 0 */
#define FRS1 0x4d /* Framer Receive Status register 1 */
#define FECL 0x50 /* Framing Error Counter low byte */ /* Counts FAS word receive errors */
#define FECH 0x51 /* high byte */
#define CVCL 0x52 /* Code Violation Counter low byte */ /* Counts bipolar and HDB3 code violations */
#define CVCH 0x53 /* high byte */
#define CEC1L 0x54 /* CRC4 Error Counter 1 low byte */ /* Counts CRC4 errors in the incoming stream */
#define CEC1H 0x55 /* high byte */
#define EBCL 0x56 /* E Bit error Counter low byte */ /* E-bits: the remote end sends them, when */
#define EBCH 0x57 /* high byte */ /* it detected a CRC4-error */
#define ISR0 0x68 /* Interrupt Status Register 0 */
#define ISR1 0x69 /* Interrupt Status Register 1 */
#define ISR2 0x6a /* Interrupt Status Register 2 */
#define ISR3 0x6b /* Interrupt Status Register 3 */
#define ISR5 0x6c /* Interrupt Status Register 5 */
#define GIS 0x6e /* Global Interrupt Status Register */
#define VSTR 0x6f /* version information */
/*
* Bit fields
*/
#define FRS0_LOS (1 << 7)
#define FRS0_AIS (1 << 6)
#define FRS0_LFA (1 << 5)
#define FRS0_RRA (1 << 4)
#define FRS0_AUXP (1 << 3)
#define FRS0_NMF (1 << 2)
#define FRS0_LMFA (1 << 1)
#define FRS1_XLS (1 << 1)
#define FRS1_XLO (1)
#define ISR2_FAR (1 << 7)
#define ISR2_LFA (1 << 6)
#define ISR2_MFAR (1 << 5)
#define ISR2_T400MS (1 << 4)
#define ISR2_AIS (1 << 3)
#define ISR2_LOS (1 << 2)
#define ISR2_RAR (1 << 1)
#define ISR2_RA (1)
#define ISR3_ES (1 << 7)
#define ISR3_SEC (1 << 6)
#define ISR3_LMFA16 (1 << 5)
#define ISR3_AIS16 (1 << 4)
#define ISR3_RA16 (1 << 3)
#define ISR3_API (1 << 2)
#define ISR3_RSN (1 << 1)
#define ISR3_RSP (1)
#define ISR5_XSP (1 << 7)
#define ISR5_XSN (1 << 6)
/*
* Defines for comx-hw-slicecom.c - MUNICH32X specific
*
* Author: Bartok Istvan <bartoki@itc.hu>
* Last modified: Tue Jan 11 14:27:36 CET 2000
*
* :set tabstop=6
*/
#define TXBUFFER_SIZE 1536 /* Max mennyit tud a kartya hardver atvenni */
#define RXBUFFER_SIZE (TXBUFFER_SIZE+4) /* For Rx reasons it must be a multiple of 4, and =>4 (page 265) */
/* +4 .. see page 265, bit FE */
/* TOD: a MODE1-be nem is ezt teszem, hanem a TXBUFFER-t, lehet hogy nem is kell? */
//#define PCI_VENDOR_ID_SIEMENS 0x110a
#define PCI_DEVICE_ID_SIEMENS_MUNICH32X 0x2101
/*
* PCI config space registers (page 120)
*/
#define MUNICH_PCI_PCIRES 0x4c /* 0xe0000 resets the chip */
/*
* MUNICH slave register offsets relative to base_address[0] (PCI BAR1) (page 181):
* offsets are in bytes, registers are u32's, so we need a >>2 for indexing
* the int[] by byte offsets. Use it like:
*
* bar1[ STAT ] = ~0L; or
* x = bar1[ STAT ];
*/
#define CONF (0x00 >> 2)
#define CMD (0x04 >> 2)
#define STAT (0x08 >> 2)
#define STACK (0x08 >> 2)
#define IMASK (0x0c >> 2)
#define PIQBA (0x14 >> 2)
#define PIQL (0x18 >> 2)
#define MODE1 (0x20 >> 2)
#define MODE2 (0x24 >> 2)
#define CCBA (0x28 >> 2)
#define TXPOLL (0x2c >> 2)
#define TIQBA (0x30 >> 2)
#define TIQL (0x34 >> 2)
#define RIQBA (0x38 >> 2)
#define RIQL (0x3c >> 2)
#define LCONF (0x40 >> 2) /* LBI Configuration Register */
#define LCCBA (0x44 >> 2) /* LBI Configuration Control Block */ /* DE: lehet hogy nem is kell? */
#define LTIQBA (0x50 >> 2) /* DE: lehet hogy nem is kell? page 210: LBI DMA Controller intq - nem hasznalunk DMA-t.. */
#define LTIQL (0x54 >> 2) /* DE: lehet hogy nem is kell? */
#define LRIQBA (0x58 >> 2) /* DE: lehet hogy nem is kell? */
#define LRIQL (0x5c >> 2) /* DE: lehet hogy nem is kell? */
#define LREG0 (0x60 >> 2) /* LBI Indirect External Configuration register 0 */
#define LREG1 (0x64 >> 2)
#define LREG2 (0x68 >> 2)
#define LREG3 (0x6c >> 2)
#define LREG4 (0x70 >> 2)
#define LREG5 (0x74 >> 2)
#define LREG6 (0x78 >> 2) /* LBI Indirect External Configuration register 6 */
#define LSTAT (0x7c >> 2) /* LBI Status Register */
#define GPDIR (0x80 >> 2) /* General Purpose Bus DIRection - 0..input, 1..output */
#define GPDATA (0x84 >> 2) /* General Purpose Bus DATA */
/*
* MUNICH commands: (they go into register CMD)
*/
#define CMD_ARPCM 0x01 /* Action Request Serial PCM Core */
#define CMD_ARLBI 0x02 /* Action Request LBI */
/*
* MUNICH event bits in the STAT, STACK, IMASK registers (page 188,189)
*/
#define STAT_PTI (1 << 15)
#define STAT_PRI (1 << 14)
#define STAT_LTI (1 << 13)
#define STAT_LRI (1 << 12)
#define STAT_IOMI (1 << 11)
#define STAT_SSCI (1 << 10)
#define STAT_LBII (1 << 9)
#define STAT_MBI (1 << 8)
#define STAT_TI (1 << 6)
#define STAT_TSPA (1 << 5)
#define STAT_RSPA (1 << 4)
#define STAT_LBIF (1 << 3)
#define STAT_LBIA (1 << 2)
#define STAT_PCMF (1 << 1)
#define STAT_PCMA (1)
/*
* We do not handle these (and do not touch their STAT bits) in the interrupt loop
*/
#define STAT_NOT_HANDLED_BY_INTERRUPT (STAT_PCMF | STAT_PCMA)
/*
* MUNICH MODE1/MODE2 slave register fields (page 193,196)
* these are not all masks, MODE1_XX_YY are my magic values!
*/
#define MODE1_PCM_E1 (1 << 31) /* E1, 2.048 Mbit/sec */
#define MODE1_TBS_4 (1 << 24) /* TBS = 4 .. no Tx bit shift */
#define MODE1_RBS_4 (1 << 18) /* RBS = 4 .. no Rx bit shift */
#define MODE1_REN (1 << 15) /* Rx Enable */
#define MODE1_MFL_MY TXBUFFER_SIZE /* Maximum Frame Length */
#define MODE1_MAGIC (MODE1_PCM_E1 | MODE1_TBS_4 | MODE1_RBS_4 | MODE1_REN | MODE1_MFL_MY)
#define MODE2_HPOLL (1 << 8) /* Hold Poll */
#define MODE2_SPOLL (1 << 7) /* Slow Poll */
#define MODE2_TSF (1) /* real magic - discovered by probing :) */
// #define MODE2_MAGIC (MODE2_TSF)
#define MODE2_MAGIC (MODE2_SPOLL | MODE2_TSF)
/*
* LCONF bits (page 205)
* these are not all masks, LCONF_XX_YY are my magic values!
*/
#define LCONF_IPA (1 << 31) /* Interrupt Pass. Use 1 for FALC54 */
#define LCONF_DCA (1 << 30) /* Disregard the int's for Channel A - DMSM does not try to handle them */
#define LCONF_DCB (1 << 29) /* Disregard the int's for Channel B */
#define LCONF_EBCRES (1 << 22) /* Reset LBI External Bus Controller, 0..reset, 1..normal operation */
#define LCONF_LBIRES (1 << 21) /* Reset LBI DMSM, 0..reset, 1..normal operation */
#define LCONF_BTYP_16DEMUX (1 << 7) /* 16-bit demultiplexed bus */
#define LCONF_ABM (1 << 4) /* Arbitration Master */
/* writing LCONF_MAGIC1 followed by a LCONF_MAGIC2 into LCONF resets the EBC and DMSM: */
#define LCONF_MAGIC1 (LCONF_BTYP_16DEMUX | LCONF_ABM | LCONF_IPA | LCONF_DCA | LCONF_DCB)
#define LCONF_MAGIC2 (LCONF_MAGIC1 | LCONF_EBCRES | LCONF_LBIRES)
/*
* LREGx magic values if a FALC54 is on the LBI (page 217)
*/
#define LREG0_MAGIC 0x00000264
#define LREG1_MAGIC 0x6e6a6b66
#define LREG2_MAGIC 0x00000264
#define LREG3_MAGIC 0x6e686966
#define LREG4_MAGIC 0x00000000
#define LREG5_MAGIC ( (7<<27) | (3<<24) | (1<<21) | (7<<3) | (2<<9) )
/*
* PCM Action Specification fields (munich_ccb_t.action_spec)
*/
#define CCB_ACTIONSPEC_IN (1 << 15) /* init */
#define CCB_ACTIONSPEC_ICO (1 << 14) /* init only this channel */
#define CCB_ACTIONSPEC_RES (1 << 6) /* reset all channels */
#define CCB_ACTIONSPEC_LOC (1 << 5)
#define CCB_ACTIONSPEC_LOOP (1 << 4)
#define CCB_ACTIONSPEC_LOOPI (1 << 3)
#define CCB_ACTIONSPEC_IA (1 << 2)
/*
* Interrupt Information bits in the TIQ, RIQ
*/
#define PCM_INT_HI (1 << 12)
#define PCM_INT_FI (1 << 11)
#define PCM_INT_IFC (1 << 10)
#define PCM_INT_SF (1 << 9)
#define PCM_INT_ERR (1 << 8)
#define PCM_INT_FO (1 << 7)
#define PCM_INT_FE2 (1 << 6)
#define PCM_INT_CHANNEL( info ) (info & 0x1F)
/*
* Rx status info in the rx_desc_t.status
*/
#define RX_STATUS_SF (1 << 6)
#define RX_STATUS_LOSS (1 << 5)
#define RX_STATUS_CRCO (1 << 4)
#define RX_STATUS_NOB (1 << 3)
#define RX_STATUS_LFD (1 << 2)
#define RX_STATUS_RA (1 << 1)
#define RX_STATUS_ROF 1
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