diff options
author | Hellmuth Michaelis <hm@FreeBSD.org> | 2001-01-11 14:35:45 +0000 |
---|---|---|
committer | Hellmuth Michaelis <hm@FreeBSD.org> | 2001-01-11 14:35:45 +0000 |
commit | 2fbe70cb49ea7d3bbccbc63a23af4c3b8a7b6283 (patch) | |
tree | c0230033ed9cab683cdcd3156fe570f8ea5e5749 /sys/i4b/layer1 | |
parent | 6624680fec5de8d24e68dcd3828e80ebf772bfd6 (diff) | |
download | src-2fbe70cb49ea7d3bbccbc63a23af4c3b8a7b6283.tar.gz src-2fbe70cb49ea7d3bbccbc63a23af4c3b8a7b6283.zip |
Add the ISDN itjc hardware driver. This driver supports the NETJet-S cards
from Traverse Technology and also the Teles PCI-TJ cards both based on the
chipset combination of the Siemens ISAC and the TJNet Tiger300/320 chips.
The itjc/i4b_hdlc.h file will hopefully soon be merged with the file
/usr/src/sys/i4b/layer1/i4b_hdlc.h.
Submitted by: Sergio de Souza Prallon <prallon@tmp.com.br>
Notes
Notes:
svn path=/head/; revision=70927
Diffstat (limited to 'sys/i4b/layer1')
-rw-r--r-- | sys/i4b/layer1/i4b_l1.h | 8 | ||||
-rw-r--r-- | sys/i4b/layer1/i4b_l1dmux.c | 23 | ||||
-rw-r--r-- | sys/i4b/layer1/itjc/i4b_hdlc.h | 412 | ||||
-rw-r--r-- | sys/i4b/layer1/itjc/i4b_itjc_ext.h | 59 | ||||
-rw-r--r-- | sys/i4b/layer1/itjc/i4b_itjc_isac.c | 552 | ||||
-rw-r--r-- | sys/i4b/layer1/itjc/i4b_itjc_l1.c | 243 | ||||
-rw-r--r-- | sys/i4b/layer1/itjc/i4b_itjc_l1fsm.c | 520 | ||||
-rw-r--r-- | sys/i4b/layer1/itjc/i4b_itjc_pci.c | 2134 |
8 files changed, 3942 insertions, 9 deletions
diff --git a/sys/i4b/layer1/i4b_l1.h b/sys/i4b/layer1/i4b_l1.h index 55d6860c4064..50360dbc1f1c 100644 --- a/sys/i4b/layer1/i4b_l1.h +++ b/sys/i4b/layer1/i4b_l1.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Hellmuth Michaelis. All rights reserved. + * Copyright (c) 2000, 2001 Hellmuth Michaelis. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,11 +27,9 @@ * i4b_l1.h - isdn4bsd layer 1 header file * --------------------------------------- * - * $Id: i4b_l1.h,v 1.15 2000/06/02 16:14:36 hm Exp $ - * * $FreeBSD$ * - * last edit-date: [Thu Oct 26 08:42:44 2000] + * last edit-date: [Wed Jan 10 16:42:27 2001] * *---------------------------------------------------------------------------*/ @@ -71,6 +69,7 @@ #define FLAG_ACER_P10 26 #define FLAG_TELEINT_NO_1 27 #define FLAG_CCD_HFCS_PCI 28 +#define FLAG_NETJET_S 29 #define SEC_DELAY 1000000 /* one second DELAY for DELAY*/ @@ -91,6 +90,7 @@ #define L0IHFCUNIT(u) ( (((L1DRVR_IHFC) << 8) & 0xff00) | ((u) & 0xff)) #define L0IFPNPUNIT(u) ( (((L1DRVR_IFPNP) << 8) & 0xff00) | ((u) & 0xff)) #define L0ICCHPUNIT(u) ( (((L1DRVR_ICCHP) << 8) & 0xff00) | ((u) & 0xff)) +#define L0ITJCUNIT(u) ( (((L1DRVR_ITJC) << 8) & 0xff00) | ((u) & 0xff)) /* jump table for the multiplex functions */ struct i4b_l1mux_func { diff --git a/sys/i4b/layer1/i4b_l1dmux.c b/sys/i4b/layer1/i4b_l1dmux.c index c65bb8c8e7a9..9df32b50c934 100644 --- a/sys/i4b/layer1/i4b_l1dmux.c +++ b/sys/i4b/layer1/i4b_l1dmux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Hellmuth Michaelis. All rights reserved. + * Copyright (c) 2000, 2001 Hellmuth Michaelis. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,11 +27,9 @@ * i4b_l1dmux.c - isdn4bsd layer 1 driver multiplexer * -------------------------------------------------- * - * $Id: i4b_l1dmux.c,v 1.12 2000/06/02 16:14:36 hm Exp $ - * * $FreeBSD$ * - * last edit-date: [Fri Jun 2 14:37:39 2000] + * last edit-date: [Wed Jan 10 16:43:24 2001] * *---------------------------------------------------------------------------*/ @@ -40,11 +38,11 @@ #include "ifpi.h" #include "ifpnp.h" #include "ihfc.h" +#include "itjc.h" #include <sys/param.h> #include <sys/systm.h> - #include <machine/i4b_debug.h> #include <machine/i4b_ioctl.h> #include <machine/i4b_trace.h> @@ -105,6 +103,10 @@ static int l1ihfcunittab[MAXL1UNITS]; static int l1ifpnpunittab[MAXL1UNITS]; #endif +#if NITJC > 0 +static int l1itjcunittab[MAXL1UNITS]; +#endif + static int numl1units = 0; static int l1drvunittab[MAXL1UNITS]; @@ -185,6 +187,11 @@ getl1tab(int drv) return(l1ifpnpunittab); break; #endif +#if NITJC > 0 + case L1DRVR_ITJC: + return(l1itjcunittab); + break; +#endif default: return(NULL); break; @@ -316,6 +323,12 @@ i4b_l1_mph_status_ind(int drv_unit, int status, int parm, struct i4b_l1mux_func #if NIHFC > 0 case L1DRVR_IHFC: printf("ihfc%d: passive stack unit %d\n", L0UNIT(drv_unit), numl1units); + break; +#endif +#if NITJC > 0 + case L1DRVR_ITJC: + printf("itjc%d: passive stack unit %d\n", L0UNIT(drv_unit), numl1units); + break; #endif } diff --git a/sys/i4b/layer1/itjc/i4b_hdlc.h b/sys/i4b/layer1/itjc/i4b_hdlc.h new file mode 100644 index 000000000000..ccc60caeebbf --- /dev/null +++ b/sys/i4b/layer1/itjc/i4b_hdlc.h @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2000 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_hdlc.h - software-HDLC header file + * -------------------------------------- + * + * $Id: i4b_hdlc.h,v 1.5 2000/08/28 07:41:19 hm Exp $ + * + * $FreeBSD$ + * + * last edit-date: [Thu Jan 11 11:31:01 2001] + * + * Please conform "ihfc/i4b_ihfc_drv.c" (ihfc_hdlc_Bxxxx) + * for correct usage! (-hp) + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_HDLC_H_ +#define _I4B_HDLC_H_ + +/*---------------------------------------------------------------------------* + * HDLC CRC table + * + * Usage: + * crc = (HDLC_FCS_TAB[(u_char)(crc ^ byte of data)] ^ (u_char)(crc >> 8)); + * + * For more information see RFC 1662 (p. 10) + *---------------------------------------------------------------------------*/ +static const u_short HDLC_FCS_TAB[256] = { 0x0000, + 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, + 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, + 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, + 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, + 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, + 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, + 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, + 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, + 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, + 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, + 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, + 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, + 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, + 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387, + 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, + 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, + 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, + 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, + 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, + 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, + 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, + 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, + 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, + 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, + 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, + 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, + 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, + 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, + 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, + 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, + 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, + 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +/*---------------------------------------------------------------------------* + * HDLC bit table + * ============== + * + * bits[0..3]: A value which tells how many set bits there are at the + * beginning of the byte. + * + * bits[4..7]: Special bytes like 0x7e, 0x7d, 0xfd ... are flagged here + * NOTE: Special bytes also means 'abort' bytes (7 or more + * continuous set bits) + * + * bits[8..11]: A copy of bits[0..3] but only incremented by one. + * NOTE: 0x7e has value '8' instead of '0'. Internal reasons. + * + * bits[12..15]: A value which tells how many set bits there are at the + * end of the byte. + * NOTE: 0xff has both '8' incoming and '8' outgoing bits. + * + *---------------------------------------------------------------------------*/ +static const u_short HDLC_BIT_TAB[256] = { 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0504, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0605, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0504, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0160, 0x0706, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0504, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0605, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0504, 0x0100, + 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100, + 0x0201, 0x0100, 0x0302, 0x01a0, 0x02a1, 0x0860, 0x0807, 0x1100, + 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1403, 0x1100, + 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1504, 0x1100, + 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1403, 0x1100, + 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1605, 0x1100, + 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1403, 0x1100, + 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1504, 0x1100, + 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1403, 0x1100, + 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1160, 0x1706, 0x2100, + 0x2201, 0x2100, 0x2302, 0x2100, 0x2201, 0x2100, 0x2403, 0x2100, + 0x2201, 0x2100, 0x2302, 0x2100, 0x2201, 0x2100, 0x2504, 0x2100, + 0x2201, 0x2100, 0x2302, 0x2100, 0x2201, 0x2100, 0x2403, 0x2100, + 0x2201, 0x2100, 0x2302, 0x2100, 0x2201, 0x2100, 0x2605, 0x3100, + 0x3201, 0x3100, 0x3302, 0x3100, 0x3201, 0x3100, 0x3403, 0x3100, + 0x3201, 0x3100, 0x3302, 0x3100, 0x3201, 0x3100, 0x3504, 0x4100, + 0x4201, 0x4100, 0x4302, 0x4100, 0x4201, 0x4100, 0x4403, 0x5100, + 0x5201, 0x5100, 0x5302, 0x6180, 0x6281, 0x7150, 0x8908 +}; + +/*---------------------------------------------------------------------------* + * HDLC_DECODE + * =========== + * + * u_char: flag, blevel + * u_short: crc, ib, tmp, tmp2, len + * + * next: 'continue' or 'goto xxx' + * + * cfr: complete frame + * nfr: new frame + * NOTE: must setup 'len' and 'dst', so that 'dst' may be written + * at most 'len' times. + * + * rab: abort + * rdd: read data (read byte is stored in 'tmp2') + * rdo: overflow + * + * d: dummy + * + * NOTE: setting flag to '0' and len to '0' => recover from rdu + * NOTE: bits[8 .. ] of tmp2 may be used to store custom data/flags + * NOTE: these variables have to be 'suspended' / 'resumed' somehow: + * flag, blevel, crc, ib, tmp, len + * NOTE: zero is default value for all variables. + * NOTE: each time 'dst' is written, 'len' is decreased by one. + *---------------------------------------------------------------------------*/ + +#define HDLC_DECODE(dst, len, tmp, tmp2, blevel, ib, crc, flag, rddcmd, nfrcmd, \ + cfrcmd, rabcmd, rdocmd, nextcmd, d) \ + \ + rddcmd; \ + \ + ib += HDLC_BIT_TAB[(u_char)tmp2]; \ + \ + if ((u_char)ib >= 5) \ + { \ + if (ib & 0x20) /* de-stuff (msb) */ \ + { \ + if ((u_char)tmp2 == 0x7e) goto j0##d; \ + tmp2 += tmp2 & 0x7f; \ + blevel--; \ + \ + if ((ib += 0x100) & 0xc) tmp2 |= 1; /* */ \ + } \ + \ + ib &= ~0xe0; \ + \ + if ((u_char)ib == 6) /* flag seq (lsb) */ \ + { \ + j0##d: if (flag >= 2) \ + { \ + len += (4 - flag) & 3; /* remove CRC bytes */ \ + crc ^= 0xf0b8; \ + cfrcmd; \ + len = 0; \ + } \ + \ + flag = 1; \ + \ + blevel = (ib >> 8) & 0xf; \ + tmp = ((u_char)tmp2) >> blevel; \ + blevel = 8 - blevel; \ + \ + ib >>= 12; \ + \ + nextcmd; \ + } \ + if ((u_char)ib >= 7) /* abort (msb & lsb) */ \ + { \ + if (flag >= 2) \ + { \ + rabcmd; \ + len = 0; \ + } \ + \ + flag = 0; \ + \ + ib >>= 12; \ + \ + nextcmd; \ + } \ + if ((u_char)ib == 5) /* de-stuff (lsb) */ \ + { \ + tmp2 = (tmp2 | (tmp2 + 1)) & ~0x1; \ + blevel--; \ + } \ + if (blevel > 7) /* EO - bits */ \ + { \ + tmp |= (u_char)tmp2 >> (8 - (blevel &= 7)); \ + \ + ib >>= 12; \ + \ + nextcmd; \ + } \ + } \ + \ + tmp |= (u_char)tmp2 << blevel; \ + \ + if (!len--) \ + { \ + len++; \ + \ + if (!flag++) { flag--; goto j5##d;} /* hunt mode */ \ + \ + switch (flag) \ + { case 2: /* new frame */ \ + nfrcmd; \ + crc = -1; \ + if (!len--) { len++; flag++; goto j4##d; } \ + goto j3##d; \ + case 3: /* CRC (lsb's) */ \ + case 4: /* CRC (msb's) */ \ + goto j4##d; \ + case 5: /* RDO */ \ + rdocmd; \ + flag = 0; \ + break; \ + } \ + } \ + else \ + { \ + j3##d: dst = (u_char)tmp; \ + j4##d: crc = (HDLC_FCS_TAB[(u_char)(tmp ^ crc)] ^ (u_char)(crc >> 8)); \ + } \ + \ + j5##d: ib >>= 12; \ + tmp >>= 8; \ + +/*------ end of HDLC_DECODE -------------------------------------------------*/ + + +/*---------------------------------------------------------------------------* + * HDLC_ENCODE + * =========== + * + * u_char: flag, src + * u_short: tmp2, blevel, ib, crc, len + * u_int: tmp + * + * gfr: This is the place where you free the last [mbuf] chain, and get + * the next one. If a mbuf is available the code should setup 'len' + * and 'src' so that 'src' may be read 'len' times. If no mbuf is + * available leave 'len' and 'src' untouched. + * + * nmb: If your implementation accept/use chained mbufs, this is the + * place where you update 'len' and 'src' to the next mbuf of + * the chain that makes up a frame. If no further mbuf is + * available leave 'len' and 'src' untouched. This is not the + * place where you free the mbuf. Leave the block empty if your + * implementation does not accept/use chained mbufs. + * + * wrd: write data (output = (u_char)tmp) + * + * d: dummy + * + * NOTE: setting flag to '-2' and len to '0' => abort bytes will be sent + * NOTE: these variables have to be 'suspended' / 'resumed' somehow: + * flag, blevel, crc, ib, tmp, len + * NOTE: zero is default value for all variables. + * NOTE: each time 'src' is read, 'len' is decreased by one. + * NOTE: neither cmd's should exit through 'goto' or 'break' statements. + *---------------------------------------------------------------------------*/ + +#define HDLC_ENCODE(src, len, tmp, tmp2, blevel, ib, crc, flag, gfrcmd, nmbcmd, wrdcmd, d) \ + \ + if (blevel >= 0x800) { blevel -= 0x800; goto j4##d; } \ + \ + if (!len--) \ + { \ + len++; \ + \ + switch(++flag) \ + { default: /* abort */ \ + tmp = blevel = 0; /* zero is default */ \ + tmp2 = 0xff; \ + goto j3##d; \ + case 1: /* 1st time FS */ \ + case 2: /* 2nd time FS */ \ + tmp2 = 0x7e; \ + goto j3##d; \ + case 3: \ + gfrcmd; /* get new frame */ \ + if (!len--) \ + { \ + len++; \ + flag--; /* don't proceed */ \ + tmp2 = 0x7e; \ + goto j3##d; /* final FS */ \ + } \ + else \ + { \ + crc = -1; \ + ib = 0; \ + goto j1##d; /* first byte */ \ + } \ + case 4: \ + nmbcmd; /* get next mbuf in chain */ \ + if (!len--) \ + { \ + len++; \ + crc ^= -1; \ + tmp2 = (u_char)crc; \ + goto j2##d; /* CRC (lsb's) */ \ + } \ + else \ + { \ + flag--; \ + goto j1##d; /* proceed with the frame */ \ + } \ + case 5: \ + tmp2 = (u_char)(crc >> 8); \ + flag = 1; \ + goto j2##d; /* CRC (msb's) */ \ + } \ + } \ + else \ + { j1##d : \ + tmp2 = (u_char)src; \ + crc =(HDLC_FCS_TAB[(u_char)(crc ^ tmp2)] ^ (u_char)(crc >> 8)); \ + j2##d: \ + \ + ib >>= 12; \ + ib += HDLC_BIT_TAB[(u_char)tmp2]; \ + \ + if ((u_char)ib >= 5) /* stuffing */ \ + { \ + blevel &= ~0xff; \ + \ + if (ib & 0xc0) /* bit stuff (msb) */ \ + { \ + tmp2 += tmp2 & (0xff * (ib & 0xc0)); \ + ib %= 0x5000; \ + blevel++; \ + } \ + \ + ib &= ~0xf0; \ + \ + if ((u_char)ib >= 5) /* bit stuff (lsb) */ \ + { \ + tmp2 += tmp2 & ~0x1f >> ((ib - (ib >> 8) + 1) \ + & 7); \ + blevel++; \ + \ + if ((u_char)ib >= 10) /* bit stuff (msb) */ \ + { \ + tmp2 += tmp2 & ~0x7ff >> ((ib - \ + (ib >> 8) + 1) & 7); \ + blevel++; \ + } \ + if (ib & 0x8000) /* bit walk */ \ + { \ + ib = ((u_char)ib % 5) << 12; \ + } \ + } \ + \ + tmp |= tmp2 << (u_char)(blevel >> 8); \ + blevel += (u_char)blevel << 8; \ + } \ + else /* no stuffing */ \ + { \ + j3##d:tmp |= tmp2 << (u_char)(blevel >> 8); \ + } \ + } \ + \ + j4##d: wrdcmd; \ + tmp >>= 8; \ + +/*------ end of HDLC_ENCODE -------------------------------------------------*/ + + +#endif /* _I4B_HDLC_H_ */ diff --git a/sys/i4b/layer1/itjc/i4b_itjc_ext.h b/sys/i4b/layer1/itjc/i4b_itjc_ext.h new file mode 100644 index 000000000000..72631e510d96 --- /dev/null +++ b/sys/i4b/layer1/itjc/i4b_itjc_ext.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2000, 2001 Sergio Prallon. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_itjc - NetJet PCI for split layers + * ------------------------------------------ + * + * $FreeBSD$ + * + * last edit-date: [Wed Jan 10 17:15:31 2001] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_ITJC_EXT_H_ +#define _I4B_ITJC_EXT_H_ + +#include <i4b/include/i4b_l3l4.h> + +void itjc_set_linktab(int unit, int channel, drvr_link_t * dlt); +isdn_link_t *itjc_ret_linktab(int unit, int channel); + +int itjc_ph_data_req(int unit, struct mbuf *m, int freeflag); +int itjc_ph_activate_req(int unit); +int itjc_mph_command_req(int unit, int command, void *parm); + +void itjc_isac_irq(struct l1_softc *sc, int ista); +void itjc_isac_l1_cmd(struct l1_softc *sc, int command); +int itjc_isac_init(struct l1_softc *sc); + +void itjc_recover(struct l1_softc *sc); +char * itjc_printstate(struct l1_softc *sc); +void itjc_next_state(struct l1_softc *sc, int event); + +#define ITJC_MAXUNIT 4 +extern struct l1_softc *itjc_scp[ITJC_MAXUNIT]; + +#endif /* _I4B_ITJC_EXT_H_ */ diff --git a/sys/i4b/layer1/itjc/i4b_itjc_isac.c b/sys/i4b/layer1/itjc/i4b_itjc_isac.c new file mode 100644 index 000000000000..d0d80c6e2653 --- /dev/null +++ b/sys/i4b/layer1/itjc/i4b_itjc_isac.c @@ -0,0 +1,552 @@ +/* + * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_itjc_isac.c - i4b NetJet-S ISAC handler + * -------------------------------------------- + * + * $FreeBSD$ + * + * last edit-date: [Wed Jan 10 17:15:54 2001] + * + *---------------------------------------------------------------------------*/ + +#include "itjc.h" +#include "pci.h" + +#if (NITJC > 0) + +#include "opt_i4b.h" + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> + +#include <machine/stdarg.h> +#include <machine/clock.h> + +#include <net/if.h> + +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> + +#include <i4b/layer1/i4b_l1.h> + +#include <i4b/layer1/isic/i4b_isic.h> +#include <i4b/layer1/isic/i4b_isac.h> + +#include <i4b/layer1/itjc/i4b_itjc_ext.h> + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_mbuf.h> + +static u_char itjc_isac_exir_hdlr(register struct l1_softc *sc, u_char exir); +static void itjc_isac_ind_hdlr(register struct l1_softc *sc, int ind); + +/*---------------------------------------------------------------------------* + * ISAC interrupt service routine + *---------------------------------------------------------------------------*/ +void +itjc_isac_irq(struct l1_softc *sc, int ista) +{ + register u_char c = 0; + NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista); + + if(ista & ISAC_ISTA_EXI) /* extended interrupt */ + { + c |= itjc_isac_exir_hdlr(sc, ISAC_READ(I_EXIR)); + } + + if(ista & ISAC_ISTA_RME) /* receive message end */ + { + register int rest; + u_char rsta; + + /* get rx status register */ + + rsta = ISAC_READ(I_RSTA); + + if((rsta & ISAC_RSTA_MASK) != 0x20) + { + int error = 0; + + if(!(rsta & ISAC_RSTA_CRC)) /* CRC error */ + { + error++; + NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit); + } + + if(rsta & ISAC_RSTA_RDO) /* ReceiveDataOverflow */ + { + error++; + NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit); + } + + if(rsta & ISAC_RSTA_RAB) /* ReceiveABorted */ + { + error++; + NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit); + } + + if(error == 0) + NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTA = 0x%02x!", sc->sc_unit, rsta); + + i4b_Dfreembuf(sc->sc_ibuf); + + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + ISAC_WRITE(I_CMDR, ISAC_CMDR_RMC|ISAC_CMDR_RRES); + ISACCMDRWRDELAY(); + + return; + } + + rest = (ISAC_READ(I_RBCL) & (ISAC_FIFO_LEN-1)); + + if(rest == 0) + rest = ISAC_FIFO_LEN; + + if(sc->sc_ibuf == NULL) + { + if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL) + sc->sc_ib = sc->sc_ibuf->m_data; + else + panic("itjc_isac_irq: RME, i4b_Dgetmbuf returns NULL!\n"); + sc->sc_ilen = 0; + } + + if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest)) + { + ISAC_RDFIFO(sc->sc_ib, rest); + sc->sc_ilen += rest; + + sc->sc_ibuf->m_pkthdr.len = + sc->sc_ibuf->m_len = sc->sc_ilen; + + if(sc->sc_trace & TRACE_D_RX) + { + i4b_trace_hdr_t hdr; + hdr.unit = L0ITJCUNIT(sc->sc_unit); + hdr.type = TRC_CH_D; + hdr.dir = FROM_NT; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data); + } + + c |= ISAC_CMDR_RMC; + + if(sc->sc_enabled && + (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)) + { + i4b_l1_ph_data_ind(L0ITJCUNIT(sc->sc_unit), sc->sc_ibuf); + } + else + { + i4b_Dfreembuf(sc->sc_ibuf); + } + } + else + { + NDBGL1(L1_I_ERR, "RME, input buffer overflow!"); + i4b_Dfreembuf(sc->sc_ibuf); + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + } + + if(ista & ISAC_ISTA_RPF) /* receive fifo full */ + { + if(sc->sc_ibuf == NULL) + { + if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL) + sc->sc_ib= sc->sc_ibuf->m_data; + else + panic("itjc_isac_irq: RPF, i4b_Dgetmbuf returns NULL!\n"); + sc->sc_ilen = 0; + } + + if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISAC_FIFO_LEN)) + { + ISAC_RDFIFO(sc->sc_ib, ISAC_FIFO_LEN); + sc->sc_ilen += ISAC_FIFO_LEN; + sc->sc_ib += ISAC_FIFO_LEN; + c |= ISAC_CMDR_RMC; + } + else + { + NDBGL1(L1_I_ERR, "RPF, input buffer overflow!"); + i4b_Dfreembuf(sc->sc_ibuf); + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + } + + if(ista & ISAC_ISTA_XPR) /* transmit fifo empty (XPR bit set) */ + { + if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL)) + { + sc->sc_freeflag = sc->sc_freeflag2; + sc->sc_obuf = sc->sc_obuf2; + sc->sc_op = sc->sc_obuf->m_data; + sc->sc_ol = sc->sc_obuf->m_len; + sc->sc_obuf2 = NULL; + } + + if(sc->sc_obuf) + { + ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISAC_FIFO_LEN)); + + if(sc->sc_ol > ISAC_FIFO_LEN) /* length > 32 ? */ + { + sc->sc_op += ISAC_FIFO_LEN; /* bufferptr+32 */ + sc->sc_ol -= ISAC_FIFO_LEN; /* length - 32 */ + c |= ISAC_CMDR_XTF; /* set XTF bit */ + } + else + { + if(sc->sc_freeflag) + { + i4b_Dfreembuf(sc->sc_obuf); + sc->sc_freeflag = 0; + } + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + + c |= ISAC_CMDR_XTF | ISAC_CMDR_XME; + } + } + else + { + sc->sc_state &= ~ISAC_TX_ACTIVE; + } + } + + if(ista & ISAC_ISTA_CISQ) /* channel status change CISQ */ + { + register u_char ci; + + /* get command/indication rx register*/ + + ci = ISAC_READ(I_CIRR); + + /* if S/Q IRQ, read SQC reg to clr SQC IRQ */ + + if(ci & ISAC_CIRR_SQC) + (void) ISAC_READ(I_SQRR); + + /* C/I code change IRQ (flag already cleared by CIRR read) */ + + if(ci & ISAC_CIRR_CIC0) + itjc_isac_ind_hdlr(sc, (ci >> 2) & 0xf); + } + + if(c) + { + ISAC_WRITE(I_CMDR, c); + ISACCMDRWRDELAY(); + } +} + +/*---------------------------------------------------------------------------* + * ISAC L1 Extended IRQ handler + *---------------------------------------------------------------------------*/ +static u_char +itjc_isac_exir_hdlr(register struct l1_softc *sc, u_char exir) +{ + u_char c = 0; + + if(exir & ISAC_EXIR_XMR) + { + NDBGL1(L1_I_ERR, "EXIRQ Tx Message Repeat"); + + c |= ISAC_CMDR_XRES; + } + + if(exir & ISAC_EXIR_XDU) + { + NDBGL1(L1_I_ERR, "EXIRQ Tx Data Underrun"); + + c |= ISAC_CMDR_XRES; + } + + if(exir & ISAC_EXIR_PCE) + { + NDBGL1(L1_I_ERR, "EXIRQ Protocol Error"); + } + + if(exir & ISAC_EXIR_RFO) + { + NDBGL1(L1_I_ERR, "EXIRQ Rx Frame Overflow"); + + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + + if(exir & ISAC_EXIR_SOV) + { + NDBGL1(L1_I_ERR, "EXIRQ Sync Xfer Overflow"); + } + + if(exir & ISAC_EXIR_MOS) + { + NDBGL1(L1_I_ERR, "EXIRQ Monitor Status"); + } + + if(exir & ISAC_EXIR_SAW) + { + /* cannot happen, STCR:TSF is set to 0 */ + + NDBGL1(L1_I_ERR, "EXIRQ Subscriber Awake"); + } + + if(exir & ISAC_EXIR_WOV) + { + /* cannot happen, STCR:TSF is set to 0 */ + + NDBGL1(L1_I_ERR, "EXIRQ Watchdog Timer Overflow"); + } + + return(c); +} + +/*---------------------------------------------------------------------------* + * ISAC L1 Indication handler + *---------------------------------------------------------------------------*/ +static void +itjc_isac_ind_hdlr(register struct l1_softc *sc, int ind) +{ + register int event; + + switch(ind) + { + case ISAC_CIRR_IAI8: + NDBGL1(L1_I_CICO, "rx AI8 in state %s", itjc_printstate(sc)); + itjc_isac_l1_cmd(sc, CMD_AR8); + event = EV_INFO48; + i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL); + break; + + case ISAC_CIRR_IAI10: + NDBGL1(L1_I_CICO, "rx AI10 in state %s", itjc_printstate(sc)); + itjc_isac_l1_cmd(sc, CMD_AR10); + event = EV_INFO410; + i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL); + break; + + case ISAC_CIRR_IRSY: + NDBGL1(L1_I_CICO, "rx RSY in state %s", itjc_printstate(sc)); + event = EV_RSY; + break; + + case ISAC_CIRR_IPU: + NDBGL1(L1_I_CICO, "rx PU in state %s", itjc_printstate(sc)); + event = EV_PU; + break; + + case ISAC_CIRR_IDR: + NDBGL1(L1_I_CICO, "rx DR in state %s", itjc_printstate(sc)); + itjc_isac_l1_cmd(sc, CMD_DIU); + event = EV_DR; + break; + + case ISAC_CIRR_IDID: + NDBGL1(L1_I_CICO, "rx DID in state %s", itjc_printstate(sc)); + event = EV_INFO0; + i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_L1STAT, LAYER_IDLE, NULL); + break; + + case ISAC_CIRR_IDIS: + NDBGL1(L1_I_CICO, "rx DIS in state %s", itjc_printstate(sc)); + event = EV_DIS; + break; + + case ISAC_CIRR_IEI: + NDBGL1(L1_I_CICO, "rx EI in state %s", itjc_printstate(sc)); + itjc_isac_l1_cmd(sc, CMD_DIU); + event = EV_EI; + break; + + case ISAC_CIRR_IARD: + NDBGL1(L1_I_CICO, "rx ARD in state %s", itjc_printstate(sc)); + event = EV_INFO2; + break; + + case ISAC_CIRR_ITI: + NDBGL1(L1_I_CICO, "rx TI in state %s", itjc_printstate(sc)); + event = EV_INFO0; + break; + + case ISAC_CIRR_IATI: + NDBGL1(L1_I_CICO, "rx ATI in state %s", itjc_printstate(sc)); + event = EV_INFO0; + break; + + case ISAC_CIRR_ISD: + NDBGL1(L1_I_CICO, "rx SD in state %s", itjc_printstate(sc)); + event = EV_INFO0; + break; + + default: + NDBGL1(L1_I_ERR, "UNKNOWN Indication 0x%x in state %s", ind, itjc_printstate(sc)); + event = EV_INFO0; + break; + } + itjc_next_state(sc, event); +} + +/*---------------------------------------------------------------------------* + * execute a layer 1 command + *---------------------------------------------------------------------------*/ +void +itjc_isac_l1_cmd(struct l1_softc *sc, int command) +{ + u_char cmd; + + if(command < 0 || command > CMD_ILL) + { + NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, itjc_printstate(sc)); + return; + } + + cmd = ISAC_CIX0_LOW; + + switch(command) + { + case CMD_TIM: + NDBGL1(L1_I_CICO, "tx TIM in state %s", itjc_printstate(sc)); + cmd |= (ISAC_CIXR_CTIM << 2); + break; + + case CMD_RS: + NDBGL1(L1_I_CICO, "tx RS in state %s", itjc_printstate(sc)); + cmd |= (ISAC_CIXR_CRS << 2); + break; + + case CMD_AR8: + NDBGL1(L1_I_CICO, "tx AR8 in state %s", itjc_printstate(sc)); + cmd |= (ISAC_CIXR_CAR8 << 2); + break; + + case CMD_AR10: + NDBGL1(L1_I_CICO, "tx AR10 in state %s", itjc_printstate(sc)); + cmd |= (ISAC_CIXR_CAR10 << 2); + break; + + case CMD_DIU: + NDBGL1(L1_I_CICO, "tx DIU in state %s", itjc_printstate(sc)); + cmd |= (ISAC_CIXR_CDIU << 2); + break; + } + ISAC_WRITE(I_CIXR, cmd); +} + +/*---------------------------------------------------------------------------* + * L1 ISAC initialization + *---------------------------------------------------------------------------*/ +int +itjc_isac_init(struct l1_softc *sc) +{ + ISAC_IMASK = 0xff; /* disable all irqs */ + + ISAC_WRITE(I_MASK, ISAC_IMASK); + + NDBGL1(L1_I_SETUP, "configuring for IOM-2 mode"); + + /* ADF2: Select mode IOM-2 */ + ISAC_WRITE(I_ADF2, ISAC_ADF2_IMS); + + /* SPCR: serial port control register: + * SPU - software power up = 0 + * SPM - timing mode 0 + * TLP - test loop = 0 + * C1C, C2C - B1 + C1 and B2 + IC2 monitoring + */ + ISAC_WRITE(I_SPCR, 0x00); + + /* SQXR: S/Q channel xmit register: + * IDC - IOM direction = 0 (master) + * CFS - Config Select = 0 (clock always active) + * CI1E - C/I channel 1 IRQ enable = 0 + * SQIE - S/Q IRQ enable = 0 + * SQX1-4 - Fa bits = 1 + */ + ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4); + + /* ADF1: additional feature reg 1: + * WTC - watchdog = 0 + * TEM - test mode = 0 + * PFS - pre-filter = 0 + * IOF - IOM i/f off = 0 + * ITF - interframe fill = idle + */ + ISAC_WRITE(I_ADF1, 0x00); + + /* STCR: sync transfer control reg: + * TSF - terminal secific functions = 0 + * TBA - TIC bus address = 7 + * STx/SCx = 0 + */ + ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0); + + /* MODE: Mode Register: + * MDSx - transparent mode 2 + * TMD - timer mode = external + * RAC - Receiver enabled + * DIMx - digital i/f mode + */ + ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0); + + /* enabled interrupts: + * =================== + * RME - receive message end + * RPF - receive pool full + * XPR - transmit pool ready + * CISQ - CI or S/Q channel change + * EXI - extended interrupt + */ + + ISAC_IMASK = ISAC_MASK_RSC | /* auto mode only */ + ISAC_MASK_TIN | /* timer irq */ + ISAC_MASK_SIN; /* sync xfer irq */ + + ISAC_WRITE(I_MASK, ISAC_IMASK); + + return(0); +} + +#endif /* NITJC > 0 */ diff --git a/sys/i4b/layer1/itjc/i4b_itjc_l1.c b/sys/i4b/layer1/itjc/i4b_itjc_l1.c new file mode 100644 index 000000000000..6952caf67c23 --- /dev/null +++ b/sys/i4b/layer1/itjc/i4b_itjc_l1.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_itjc_l1.c - NetJet-S layer 1 handler + * --------------------------------------------- + * + * $FreeBSD$ + * + * last edit-date: [Wed Jan 10 17:16:19 2001] + * + *---------------------------------------------------------------------------*/ + +#include "itjc.h" +#include "pci.h" + +#if (NITJC > 0) && (NPCI > 0) + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> + +#include <machine/stdarg.h> +#include <machine/clock.h> + +#include <net/if.h> + +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> + +#include <i4b/layer1/isic/i4b_isic.h> +#include <i4b/layer1/isic/i4b_isac.h> + +#include <i4b/layer1/itjc/i4b_itjc_ext.h> + +#include <i4b/layer1/i4b_l1.h> + +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +/*---------------------------------------------------------------------------* + * + * L2 -> L1: PH-DATA-REQUEST + * ========================= + * + * parms: + * unit physical interface unit number + * m mbuf containing L2 frame to be sent out + * freeflag MBUF_FREE: free mbuf here after having sent + * it out + * MBUF_DONTFREE: mbuf is freed by Layer 2 + * returns: + * ==0 fail, nothing sent out + * !=0 ok, frame sent out + * + *---------------------------------------------------------------------------*/ +int +itjc_ph_data_req(int unit, struct mbuf *m, int freeflag) +{ + u_char cmd; + int s; + struct l1_softc *sc = itjc_scp[unit]; + + NDBGL1(L1_PRIM, "PH-DATA-REQ, unit %d, freeflag=%d", unit, freeflag); + + if(m == NULL) /* failsafe */ + return (0); + + s = SPLI4B(); + + if(sc->sc_I430state == ST_F3) /* layer 1 not running ? */ + { + NDBGL1(L1_I_ERR, "still in state F3!"); + itjc_ph_activate_req(unit); + } + + if(sc->sc_state & ISAC_TX_ACTIVE) + { + if(sc->sc_obuf2 == NULL) + { + sc->sc_obuf2 = m; /* save mbuf ptr */ + + if(freeflag) + sc->sc_freeflag2 = 1; /* IRQ must mfree */ + else + sc->sc_freeflag2 = 0; /* IRQ must not mfree */ + + NDBGL1(L1_I_MSG, "using 2nd ISAC TX buffer, state = %s", itjc_printstate(sc)); + + if(sc->sc_trace & TRACE_D_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = L0ITJCUNIT(unit); + hdr.type = TRC_CH_D; + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); + } + splx(s); + return(1); + } + + NDBGL1(L1_I_ERR, "No Space in TX FIFO, state = %s", itjc_printstate(sc)); + + if(freeflag == MBUF_FREE) + i4b_Dfreembuf(m); + + splx(s); + return (0); + } + + if(sc->sc_trace & TRACE_D_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = L0ITJCUNIT(unit); + hdr.type = TRC_CH_D; + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); + } + + sc->sc_state |= ISAC_TX_ACTIVE; /* set transmitter busy flag */ + + NDBGL1(L1_I_MSG, "ISAC_TX_ACTIVE set"); + + sc->sc_freeflag = 0; /* IRQ must NOT mfree */ + + ISAC_WRFIFO(m->m_data, min(m->m_len, ISAC_FIFO_LEN)); /* output to TX fifo */ + + if(m->m_len > ISAC_FIFO_LEN) /* message > 32 bytes ? */ + { + sc->sc_obuf = m; /* save mbuf ptr */ + sc->sc_op = m->m_data + ISAC_FIFO_LEN; /* ptr for irq hdl */ + sc->sc_ol = m->m_len - ISAC_FIFO_LEN; /* length for irq hdl */ + + if(freeflag) + sc->sc_freeflag = 1; /* IRQ must mfree */ + + cmd = ISAC_CMDR_XTF; + } + else + { + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + + if(freeflag) + i4b_Dfreembuf(m); + + cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME; + } + + ISAC_WRITE(I_CMDR, cmd); + ISACCMDRWRDELAY(); + + splx(s); + + return(1); +} + +/*---------------------------------------------------------------------------* + * + * L2 -> L1: PH-ACTIVATE-REQUEST + * ============================= + * + * parms: + * unit physical interface unit number + * + * returns: + * ==0 + * !=0 + * + *---------------------------------------------------------------------------*/ +int +itjc_ph_activate_req(int unit) +{ + struct l1_softc *sc = itjc_scp[unit]; + NDBGL1(L1_PRIM, "PH-ACTIVATE-REQ, unit %d", unit); + itjc_next_state(sc, EV_PHAR); + return(0); +} + +/*---------------------------------------------------------------------------* + * command from the upper layers + *---------------------------------------------------------------------------*/ +int +itjc_mph_command_req(int unit, int command, void *parm) +{ + struct l1_softc *sc = itjc_scp[unit]; + + switch(command) + { + case CMR_DOPEN: /* daemon running */ + NDBGL1(L1_PRIM, "unit %d, command = CMR_DOPEN", unit); + sc->sc_enabled = 1; + break; + + case CMR_DCLOSE: /* daemon not running */ + NDBGL1(L1_PRIM, "unit %d, command = CMR_DCLOSE", unit); + sc->sc_enabled = 0; + break; + + case CMR_SETTRACE: + NDBGL1(L1_PRIM, "unit %d, command = CMR_SETTRACE, parm = %d", unit, (unsigned int)parm); + sc->sc_trace = (unsigned int)parm; + break; + + default: + NDBGL1(L1_ERROR, "ERROR, unknown command = %d, unit = %d, parm = %d", command, unit, (unsigned int)parm); + break; + } + + return(0); +} + +#endif /* NITJC > 0 */ diff --git a/sys/i4b/layer1/itjc/i4b_itjc_l1fsm.c b/sys/i4b/layer1/itjc/i4b_itjc_l1fsm.c new file mode 100644 index 000000000000..2bc902a3341e --- /dev/null +++ b/sys/i4b/layer1/itjc/i4b_itjc_l1fsm.c @@ -0,0 +1,520 @@ +/* + * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_itjc_l1fsm.c - NetJet-S layer 1 I.430 state machine + * ------------------------------------------------------------ + * + * $FreeBSD$ + * + * last edit-date: [Wed Jan 10 17:16:33 2001] + * + *---------------------------------------------------------------------------*/ + +#include "itjc.h" +#include "pci.h" + +#if (NITJC > 0) && (NPCI > 0) + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> + +#include <machine/stdarg.h> +#include <machine/clock.h> + +#include <net/if.h> + +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> + +#include <i4b/layer1/isic/i4b_isic.h> +#include <i4b/layer1/isic/i4b_isac.h> +#include <i4b/layer1/isic/i4b_hscx.h> + +#include <i4b/layer1/i4b_l1.h> + +#include <i4b/include/i4b_global.h> + +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer1/itjc/i4b_itjc_ext.h> + +#if DO_I4B_DEBUG +static char *state_text[N_STATES] = { + "F3 Deactivated", + "F4 Awaiting Signal", + "F5 Identifying Input", + "F6 Synchronized", + "F7 Activated", + "F8 Lost Framing", + "Illegal State" +}; + +static char *event_text[N_EVENTS] = { + "EV_PHAR PH_ACT_REQ", + "EV_T3 Timer 3 expired", + "EV_INFO0 INFO0 received", + "EV_RSY Level Detected", + "EV_INFO2 INFO2 received", + "EV_INFO48 INFO4 received", + "EV_INFO410 INFO4 received", + "EV_DR Deactivate Req", + "EV_PU Power UP", + "EV_DIS Disconnected", + "EV_EI Error Ind", + "Illegal Event" +}; +#endif + +/* Function prototypes */ + +static void timer3_expired (struct l1_softc *sc); +static void T3_start (struct l1_softc *sc); +static void T3_stop (struct l1_softc *sc); +static void F_T3ex (struct l1_softc *sc); +static void timer4_expired (struct l1_softc *sc); +static void T4_start (struct l1_softc *sc); +static void T4_stop (struct l1_softc *sc); +static void F_AI8 (struct l1_softc *sc); +static void F_AI10 (struct l1_softc *sc); +static void F_I01 (struct l1_softc *sc); +static void F_I02 (struct l1_softc *sc); +static void F_I03 (struct l1_softc *sc); +static void F_I2 (struct l1_softc *sc); +static void F_ill (struct l1_softc *sc); +static void F_NULL (struct l1_softc *sc); + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 expire function + *---------------------------------------------------------------------------*/ +static void +timer3_expired(struct l1_softc *sc) +{ + if(sc->sc_I430T3) + { + NDBGL1(L1_T_ERR, "state = %s", itjc_printstate(sc)); + sc->sc_I430T3 = 0; + + /* XXX try some recovery here XXX */ + + itjc_recover(sc); + + sc->sc_init_tries++; /* increment retry count */ + +/*XXX*/ if(sc->sc_init_tries > 4) + { + int s = SPLI4B(); + + sc->sc_init_tries = 0; + + if(sc->sc_obuf2 != NULL) + { + i4b_Dfreembuf(sc->sc_obuf2); + sc->sc_obuf2 = NULL; + } + if(sc->sc_obuf != NULL) + { + i4b_Dfreembuf(sc->sc_obuf); + sc->sc_obuf = NULL; + sc->sc_freeflag = 0; + sc->sc_op = NULL; + sc->sc_ol = 0; + } + + splx(s); + + i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_NOL1ACC, 0, NULL); + } + + itjc_next_state(sc, EV_T3); + } + else + { + NDBGL1(L1_T_ERR, "expired without starting it ...."); + } +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 start + *---------------------------------------------------------------------------*/ +static void +T3_start(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", itjc_printstate(sc)); + sc->sc_I430T3 = 1; + sc->sc_T3_callout = timeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, 2*hz); +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 stop + *---------------------------------------------------------------------------*/ +static void +T3_stop(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", itjc_printstate(sc)); + + sc->sc_init_tries = 0; /* init connect retry count */ + + if(sc->sc_I430T3) + { + sc->sc_I430T3 = 0; + untimeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, sc->sc_T3_callout); + } +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 expiry + *---------------------------------------------------------------------------*/ +static void +F_T3ex(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_T3ex executing"); + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_deactivate_ind(L0ITJCUNIT(sc->sc_unit)); +} + +/*---------------------------------------------------------------------------* + * Timer T4 expire function + *---------------------------------------------------------------------------*/ +static void +timer4_expired(struct l1_softc *sc) +{ + if(sc->sc_I430T4) + { + NDBGL1(L1_T_MSG, "state = %s", itjc_printstate(sc)); + sc->sc_I430T4 = 0; + i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_PDEACT, 0, NULL); + } + else + { + NDBGL1(L1_T_ERR, "expired without starting it ...."); + } +} + +/*---------------------------------------------------------------------------* + * Timer T4 start + *---------------------------------------------------------------------------*/ +static void +T4_start(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", itjc_printstate(sc)); + sc->sc_I430T4 = 1; + sc->sc_T4_callout = timeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, hz); +} + +/*---------------------------------------------------------------------------* + * Timer T4 stop + *---------------------------------------------------------------------------*/ +static void +T4_stop(struct l1_softc *sc) +{ + NDBGL1(L1_T_MSG, "state = %s", itjc_printstate(sc)); + + if(sc->sc_I430T4) + { + sc->sc_I430T4 = 0; + untimeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, sc->sc_T4_callout); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received AI8 + *---------------------------------------------------------------------------*/ +static void +F_AI8(struct l1_softc *sc) +{ + T4_stop(sc); + + NDBGL1(L1_F_MSG, "FSM function F_AI8 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_activate_ind(L0ITJCUNIT(sc->sc_unit)); + + T3_stop(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO4_8; + + hdr.unit = L0ITJCUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received AI10 + *---------------------------------------------------------------------------*/ +static void +F_AI10(struct l1_softc *sc) +{ + T4_stop(sc); + + NDBGL1(L1_F_MSG, "FSM function F_AI10 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_activate_ind(L0ITJCUNIT(sc->sc_unit)); + + T3_stop(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO4_10; + + hdr.unit = L0ITJCUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in states F3 .. F5 + *---------------------------------------------------------------------------*/ +static void +F_I01(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I01 executing"); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = L0ITJCUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in state F6 + *---------------------------------------------------------------------------*/ +static void +F_I02(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I02 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_deactivate_ind(L0ITJCUNIT(sc->sc_unit)); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = L0ITJCUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in state F7 or F8 + *---------------------------------------------------------------------------*/ +static void +F_I03(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I03 executing"); + + if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) + i4b_l1_ph_deactivate_ind(L0ITJCUNIT(sc->sc_unit)); + + T4_start(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = L0ITJCUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: activate request + *---------------------------------------------------------------------------*/ +static void +F_AR(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_AR executing"); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO1_8; + + hdr.unit = L0ITJCUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_TE; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } + + itjc_isac_l1_cmd(sc, CMD_AR8); + + T3_start(sc); +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO2 + *---------------------------------------------------------------------------*/ +static void +F_I2(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_I2 executing"); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO2; + + hdr.unit = L0ITJCUNIT(sc->sc_unit); + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, 1, &info); + } + +} + +/*---------------------------------------------------------------------------* + * illegal state default action + *---------------------------------------------------------------------------*/ +static void +F_ill(struct l1_softc *sc) +{ + NDBGL1(L1_F_ERR, "FSM function F_ill executing"); +} + +/*---------------------------------------------------------------------------* + * No action + *---------------------------------------------------------------------------*/ +static void +F_NULL(struct l1_softc *sc) +{ + NDBGL1(L1_F_MSG, "FSM function F_NULL executing"); +} + + +/*---------------------------------------------------------------------------* + * layer 1 state transition table + *---------------------------------------------------------------------------*/ +struct itjc_state_tab { + void (*func) (struct l1_softc *sc); /* function to execute */ + int newstate; /* next state */ +} itjc_state_tab[N_EVENTS][N_STATES] = { + +/* STATE: F3 F4 F5 F6 F7 F8 ILLEGAL STATE */ +/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* EV_PHAR x*/ {{F_AR, ST_F4}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_ill, ST_ILL}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_T3 x*/ {{F_NULL, ST_F3}, {F_T3ex, ST_F3}, {F_T3ex, ST_F3}, {F_T3ex, ST_F3}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_INFO0 */ {{F_I01, ST_F3}, {F_I01, ST_F4}, {F_I01, ST_F5}, {F_I02, ST_F3}, {F_I03, ST_F3}, {F_I03, ST_F3}, {F_ill, ST_ILL}}, +/* EV_RSY x*/ {{F_NULL, ST_F3}, {F_NULL, ST_F5}, {F_NULL, ST_F5}, {F_NULL, ST_F8}, {F_NULL, ST_F8}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_INFO2 */ {{F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_ill, ST_ILL}}, +/* EV_INFO48*/ {{F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_NULL, ST_F7}, {F_AI8, ST_F7}, {F_ill, ST_ILL}}, +/* EV_INFO41*/ {{F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_NULL, ST_F7}, {F_AI10, ST_F7}, {F_ill, ST_ILL}}, +/* EV_DR */ {{F_NULL, ST_F3}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_PU */ {{F_NULL, ST_F3}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_DIS */ {{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}, +/* EV_EI */ {{F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_ill, ST_ILL}}, +/* EV_ILL */ {{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}} +}; + +/*---------------------------------------------------------------------------* + * event handler + *---------------------------------------------------------------------------*/ +void +itjc_next_state(struct l1_softc *sc, int event) +{ + int currstate, newstate; + + if(event >= N_EVENTS) + panic("i4b_l1fsm.c: event >= N_EVENTS\n"); + + currstate = sc->sc_I430state; + + if(currstate >= N_STATES) + panic("i4b_l1fsm.c: currstate >= N_STATES\n"); + + newstate = itjc_state_tab[event][currstate].newstate; + + if(newstate >= N_STATES) + panic("i4b_l1fsm.c: newstate >= N_STATES\n"); + + NDBGL1(L1_F_MSG, "FSM event [%s]: [%s => %s]", event_text[event], + state_text[currstate], + state_text[newstate]); + + (*itjc_state_tab[event][currstate].func)(sc); + + if(newstate == ST_ILL) + { + newstate = ST_F3; + NDBGL1(L1_F_ERR, "FSM Illegal State ERROR, oldstate = %s, newstate = %s, event = %s!", + state_text[currstate], + state_text[newstate], + event_text[event]); + } + + sc->sc_I430state = newstate; +} + +#if DO_I4B_DEBUG +/*---------------------------------------------------------------------------* + * return pointer to current state description + *---------------------------------------------------------------------------*/ +char * +itjc_printstate(struct l1_softc *sc) +{ + return((char *) state_text[sc->sc_I430state]); +} +#endif + +#endif /* NITJC > 0 */ diff --git a/sys/i4b/layer1/itjc/i4b_itjc_pci.c b/sys/i4b/layer1/itjc/i4b_itjc_pci.c new file mode 100644 index 000000000000..28bea9074e5a --- /dev/null +++ b/sys/i4b/layer1/itjc/i4b_itjc_pci.c @@ -0,0 +1,2134 @@ +/* + * Copyright (c) 2000, 2001 Sergio Prallon. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_itjc_pci.c: NetJet-S hardware driver + * ---------------------------------------- + * + * $FreeBSD$ + * + * last edit-date: [Thu Jan 11 11:29:38 2001] + * + *---------------------------------------------------------------------------*/ + +#include "itjc.h" +#include "opt_i4b.h" +#include "pci.h" + +#if (NITJC > 0) + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#include <machine/clock.h> +#include <machine/bus_pio.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> +#include <sys/rman.h> + +#include <pci/pcireg.h> +#include <pci/pcivar.h> + +#include <sys/socket.h> +#include <net/if.h> + +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer1/i4b_l1.h> + +#include <i4b/layer1/itjc/i4b_hdlc.h> /* XXXXXXXXXXXXXXXXXXXXXXXX */ + +#include <i4b/layer1/isic/i4b_isic.h> +#include <i4b/layer1/isic/i4b_isac.h> + +#include <i4b/layer1/itjc/i4b_itjc_ext.h> + +#define PCI_TJNET_VID (0xe159) +#define PCI_TJ300_DID (0x0001) + + +/* + * Function prototypes + */ + +static int itjc_probe(device_t dev); +static int itjc_attach(device_t dev); +static void itjc_shutdown(device_t dev); +static void itjc_intr(void *xsc); +static int itjc_dma_start(struct l1_softc *sc); +static void itjc_dma_stop(struct l1_softc *sc); +static void itjc_isac_intr(struct l1_softc *sc); +static void itjc_init_linktab(struct l1_softc *sc); +static void itjc_bchannel_setup(int unit, int h_chan, int bprot, + int activate); +static void itjc_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp); + + +/* + * Shorter names to bus resource manager routines. + */ + +#define itjc_bus_setup(sc) \ + bus_space_handle_t h = \ + rman_get_bushandle((sc)->sc_resources.io_base[0]); \ + bus_space_tag_t t = \ + rman_get_bustag((sc)->sc_resources.io_base[0]); + +#define itjc_read_1(port) (bus_space_read_1(t, h, (port))) +#define itjc_read_4(port) (bus_space_read_4(t, h, (port))) +#define itjc_write_1(port, data) (bus_space_write_1(t, h, (port), (data))) +#define itjc_write_4(port, data) (bus_space_write_4(t, h, (port), (data))) +#define itjc_read_multi_1(port, buf, size) \ + (bus_space_read_multi_1(t, h, (port), (buf), (size))) +#define itjc_write_multi_1(port, buf, size) \ + (bus_space_write_multi_1(t, h, (port), (buf), (size))) + + +/*---------------------------------------------------------------------------* + * Glue data to register ourselves as a PCI device driver. + *---------------------------------------------------------------------------*/ + +static device_method_t itjc_pci_methods[] = +{ + /* Device interface */ + DEVMETHOD(device_probe, itjc_probe), + DEVMETHOD(device_attach, itjc_attach), + DEVMETHOD(device_shutdown, itjc_shutdown), + + /* bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + + { 0, 0 } +}; + +static driver_t itjc_pci_driver = +{ + "itjc", + itjc_pci_methods, + sizeof(struct l1_softc) +}; + +static devclass_t itjc_pci_devclass; + +DRIVER_MODULE(netjet, pci, itjc_pci_driver, itjc_pci_devclass, 0, 0); + +/* + * Jump table for multiplex routines. + */ + +struct i4b_l1mux_func itjc_l1mux_func = +{ + itjc_ret_linktab, + itjc_set_linktab, + itjc_mph_command_req, + itjc_ph_data_req, + itjc_ph_activate_req, +}; + +struct l1_softc *itjc_scp[ITJC_MAXUNIT]; + + +/*---------------------------------------------------------------------------* + * Tiger300/320 PCI ASIC registers. + *---------------------------------------------------------------------------*/ + +/* + * Register offsets from i/o base. + */ +enum tiger_regs +{ + TIGER_RESET_PIB_CL_TIME = 0x00, + TIGER_DMA_OPER = 0x01, + TIGER_AUX_PORT_CNTL = 0x02, + TIGER_AUX_PORT_DATA = 0x03, + TIGER_INT0_MASK = 0x04, + TIGER_INT1_MASK = 0x05, + TIGER_INT0_STATUS = 0x06, + TIGER_INT1_STATUS = 0x07, + TIGER_DMA_WR_START_ADDR = 0x08, + TIGER_DMA_WR_INT_ADDR = 0x0C, + TIGER_DMA_WR_END_ADDR = 0x10, + TIGER_DMA_WR_CURR_ADDR = 0x14, + TIGER_DMA_RD_START_ADDR = 0x18, + TIGER_DMA_RD_INT_ADDR = 0x1C, + TIGER_DMA_RD_END_ADDR = 0x20, + TIGER_DMA_RD_CURR_ADDR = 0x24, + TIGER_PULSE_COUNTER = 0x28, +}; + +/* + * Bits on the above registers. + */ + +enum tiger_reg_bits +{ +/* Reset and PIB Cycle Timing */ + + TIGER_DMA_OP_MODE_MASK = 0x80, + TIGER_SELF_ADDR_DMA = 0x00, /* Wrap around ending addr */ + TIGER_NORMAL_DMA = 0x80, /* Stop at ending addr */ + + TIGER_DMA_INT_MODE_MASK = 0x40, + TIGER_DONT_LATCH_DMA_INT= 0x00, /* Bits on int0 status will be + set only while curr addr + equals int or end addr */ + TIGER_LATCH_DMA_INT = 0x40, /* Bits on int0 status remain + set until cleared by CPU */ + + TIGER_PIB_CYCLE_TIMING_MASK = 0x30, + TIGER_PIB_3_CYCLES = 0x00, + TIGER_PIB_5_CYCLES = 0x01, + TIGER_PIB_12_CYCLES = 0x10, + + TIGER_RESET_MASK = 0x0F, + TIGER_RESET_PULSE_COUNT = 0x08, + TIGER_RESET_SERIAL_PORT = 0x04, + TIGER_RESET_DMA_LOGIC = 0x02, + TIGER_RESET_EXTERNAL = 0x01, + TIGER_RESET_ALL = 0x0F, + +/* DMA Operation */ + TIGER_DMA_RESTART_MASK = 0x02, + TIGER_HOLD_DMA = 0x00, + TIGER_RESTART_DMA = 0x00, + + TIGER_DMA_ENABLE_MASK = 0x01, + TIGER_ENABLE_DMA = 0x01, + TIGER_DISABLE_DMA = 0x00, + +/* AUX Port Control & Data plus Interrupt 1 Mask & Status */ + TIGER_AUX_7_MASK = 0x80, + TIGER_AUX_6_MASK = 0x40, + TIGER_AUX_5_MASK = 0x20, + TIGER_AUX_4_MASK = 0x10, + TIGER_ISAC_INT_MASK = 0x10, + TIGER_AUX_3_MASK = 0x08, + TIGER_AUX_2_MASK = 0x04, + TIGER_AUX_1_MASK = 0x02, + TIGER_AUX_0_MASK = 0x01, + +/* AUX Port Control */ + TIGER_AUX_7_IS_INPUT = 0x00, + TIGER_AUX_7_IS_OUTPUT = 0x80, + TIGER_AUX_6_IS_INPUT = 0x00, + TIGER_AUX_6_IS_OUTPUT = 0x40, + TIGER_AUX_5_IS_INPUT = 0x00, + TIGER_AUX_5_IS_OUTPUT = 0x20, + TIGER_AUX_4_IS_INPUT = 0x00, + TIGER_AUX_4_IS_OUTPUT = 0x10, + TIGER_AUX_3_IS_INPUT = 0x00, + TIGER_AUX_3_IS_OUTPUT = 0x80, + TIGER_AUX_2_IS_INPUT = 0x00, + TIGER_AUX_2_IS_OUTPUT = 0x40, + TIGER_AUX_1_IS_INPUT = 0x00, + TIGER_AUX_1_IS_OUTPUT = 0x20, + TIGER_AUX_0_IS_INPUT = 0x00, + TIGER_AUX_0_IS_OUTPUT = 0x10, + TIGER_AUX_NJ_DEFAULT = 0xEF, /* All but ISAC int is output */ + +/* Interrupt 0 Mask & Status */ + TIGER_PCI_TARGET_ABORT_INT_MASK = 0x20, + TIGER_NO_TGT_ABORT_INT = 0x00, + TIGER_TARGET_ABORT_INT = 0x20, + TIGER_PCI_MASTER_ABORT_INT_MASK = 0x10, + TIGER_NO_MST_ABORT_INT = 0x00, + TIGER_MASTER_ABORT_INT = 0x10, + TIGER_DMA_RD_END_INT_MASK = 0x08, + TIGER_NO_RD_END_INT = 0x00, + TIGER_RD_END_INT = 0x08, + TIGER_DMA_RD_INT_INT_MASK = 0x04, + TIGER_NO_RD_INT_INT = 0x00, + TIGER_RD_INT_INT = 0x04, + TIGER_DMA_WR_END_INT_MASK = 0x02, + TIGER_NO_WR_END_INT = 0x00, + TIGER_WR_END_INT = 0x02, + TIGER_DMA_WR_INT_INT_MASK = 0x01, + TIGER_NO_WR_INT_INT = 0x00, + TIGER_WR_INT_INT = 0x01, + +/* Interrupt 1 Mask & Status */ + TIGER_NO_AUX_7_INT = 0x00, + TIGER_AUX_7_INT = 0x80, + TIGER_NO_AUX_6_INT = 0x00, + TIGER_AUX_6_INT = 0x40, + TIGER_NO_AUX_5_INT = 0x00, + TIGER_AUX_5_INT = 0x20, + TIGER_NO_AUX_4_INT = 0x00, + TIGER_AUX_4_INT = 0x10, + TIGER_NO_ISAC_INT = 0x00, + TIGER_ISAC_INT = 0x10, + TIGER_NO_AUX_3_INT = 0x00, + TIGER_AUX_3_INT = 0x08, + TIGER_NO_AUX_2_INT = 0x00, + TIGER_AUX_2_INT = 0x04, + TIGER_NO_AUX_1_INT = 0x00, + TIGER_AUX_1_INT = 0x02, + TIGER_NO_AUX_0_INT = 0x00, + TIGER_AUX_0_INT = 0x01 +}; + +/* + * Peripheral Interface Bus definitions. This is an ISA like bus + * created by the Tiger ASIC to keep ISA chips like the ISAC happy + * on a PCI environment. + * + * Since the PIB only supplies 4 addressing lines, the 2 higher bits + * (A4 & A5) of the ISAC register addresses are wired on the 2 lower + * AUX lines. Another restriction is that all I/O to the PIB (8bit + * wide) is mapped on the PCI side as 32bit data. So the PCI address + * of a given ISAC register has to be multiplied by 4 before being + * added to the PIB base offset. + */ +enum tiger_pib_regs_defs +{ + /* Offset from the I/O base to the ISAC registers. */ + PIB_OFFSET = 0xC0, + PIB_LO_ADDR_MASK = 0x0F, + PIB_HI_ADDR_MASK = 0x30, + PIB_LO_ADDR_SHIFT = 2, /* Align on dword boundary */ + PIB_HI_ADDR_SHIFT = 4 /* Right shift to AUX_1 & AUX_0 */ +}; + + +#define itjc_set_pib_addr_msb(a) \ +( \ + itjc_write_1(TIGER_AUX_PORT_DATA, \ + ((a) & PIB_HI_ADDR_MASK) >> PIB_HI_ADDR_SHIFT) \ +) + +#define itjc_pib_2_pci(a) \ +( \ + (((a) & PIB_LO_ADDR_MASK) << PIB_LO_ADDR_SHIFT) + PIB_OFFSET \ +) + +#define itjc_get_dma_offset(ctx,reg) \ +( \ + (u_int16_t)((bus_addr_t)itjc_read_4((reg)) - (ctx)->bus_addr) \ +) + + +/* + * IOM-2 serial channel 0 DMA data ring buffers. + * + * The Tiger300/320 ASIC do not nothing more than transfer via DMA the + * first 32 bits of every IOM-2 frame on the serial interface to the + * ISAC. So we have no framing/deframing facilities like we would have + * with an HSCX, having to do the job with CPU cycles. On the plus side + * we are able to specify large rings which can limit the occurrence of + * over/underruns. + */ + +enum +{ + ITJC_RING_SLOT_WORDS = 64, + ITJC_RING_WORDS = 3 * ITJC_RING_SLOT_WORDS, + ITJC_RING_SLOT_BYTES = 4 * ITJC_RING_SLOT_WORDS, + ITJC_RING_BYTES = 4 * ITJC_RING_WORDS, + ITJC_DMA_POOL_WORDS = 2 * ITJC_RING_WORDS, + ITJC_DMA_POOL_BYTES = 4 * ITJC_DMA_POOL_WORDS +}; + +#define itjc_ring_add(x, d) (((x) + 4 * (d)) % ITJC_RING_BYTES) +#define itjc_ring_sub(x, d) (((x) + ITJC_RING_BYTES - 4 * (d)) \ + % ITJC_RING_BYTES) + + +enum +{ + TIGER_CH_A = 0, + TIGER_CH_B = 1, + + HSCX_CH_A = 0, /* For compatibility reasons. */ + HSCX_CH_B = 1, +}; + +enum +{ + ITJC_TEL_SILENCE_BYTE = 0x00, + ITJC_HDLC_FLAG_BYTE = 0x7E, + ITJC_HDLC_ABORT_BYTE = 0xFF +}; + +/* + * Hardware DMA control block (one per card). + */ +typedef enum +{ + ITJC_DS_LOAD_FAILED = -1, + ITJC_DS_FREE = 0, + ITJC_DS_LOADING, + ITJC_DS_STOPPED, + ITJC_DS_RUNNING +} + dma_state_t; + +typedef struct +{ + dma_state_t state; + u_int8_t *pool; + bus_addr_t bus_addr; + bus_dma_tag_t tag; + bus_dmamap_t map; + int error; +} + dma_context_t; + +dma_context_t + dma_context [ ITJC_MAXUNIT ]; + +/* + * B-channel DMA control blocks (4 per card -- 1 RX & 1 TX per channel). + */ +typedef enum +{ + ITJC_RS_IDLE = 0, + ITJC_RS_ACTIVE +} + dma_rx_state_t; + +typedef enum +{ + ITJC_TS_IDLE = 0, + ITJC_TS_ACTIVE, + ITJC_TS_AFTER_XDU +} + dma_tx_state_t; + +typedef struct +{ + u_int8_t *ring; + bus_addr_t bus_addr; + u_int16_t next_read; + u_int16_t hdlc_len; + u_int16_t hdlc_tmp; + u_int16_t hdlc_crc; + u_int16_t hdlc_ib; + u_int8_t hdlc_blevel; + u_int8_t hdlc_flag; + dma_rx_state_t state; +} + dma_rx_context_t; + +typedef struct +{ + u_int8_t *ring; + bus_addr_t bus_addr; + u_int16_t next_write; + u_int32_t hdlc_tmp; + u_int16_t hdlc_blevel; + u_int16_t hdlc_crc; + u_int16_t hdlc_ib; + u_int16_t next_frame; + u_int16_t filled; + u_int8_t hdlc_flag; + dma_tx_state_t state; +} + dma_tx_context_t; + +dma_rx_context_t + dma_rx_context [ ITJC_MAXUNIT ] [ 2 ]; + +dma_tx_context_t + dma_tx_context [ ITJC_MAXUNIT ] [ 2 ]; + +/* + * Used by the mbuf handling functions. + */ +typedef enum +{ + ITJC_MB_CURR = 0, + ITJC_MB_NEXT = 1, + ITJC_MB_NEW = 2 +} + which_mb_t; + + +/*---------------------------------------------------------------------------* + * itjc_map_callback - get DMA bus address from resource mgr. + *---------------------------------------------------------------------------*/ +static void +itjc_map_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + dma_context_t *ctx = (dma_context_t *)arg; + + if (error) + { + ctx->error = error; + ctx->state = ITJC_DS_LOAD_FAILED; + return; + } + + ctx->bus_addr = segs->ds_addr; + ctx->state = ITJC_DS_STOPPED; +} + + +/*---------------------------------------------------------------------------* + * itjc_dma_start - Complete DMA setup & start the Tiger DMA engine. + *---------------------------------------------------------------------------*/ +static int +itjc_dma_start(struct l1_softc *sc) +{ + int unit = sc->sc_unit; + dma_context_t *ctx = &dma_context[unit]; + dma_rx_context_t *rxc = &dma_rx_context[unit][0]; + dma_tx_context_t *txc = &dma_tx_context[unit][0]; + bus_addr_t ba; + u_int8_t i; + u_int32_t *pool_end, + *ip; + + itjc_bus_setup(sc); + + /* See if it is already running. */ + + if (ctx->state == ITJC_DS_RUNNING) + return 0; + + if (ctx->state == ITJC_DS_LOAD_FAILED) + { + NDBGL1(L1_ERROR, "itjc%d: dma_start: DMA map loading " + "failed (error=%d).\n", unit, ctx->error); + return 1; + } + + if (ctx->state != ITJC_DS_STOPPED) + { + NDBGL1(L1_ERROR, "itjc%d: dma_start: Unexpected DMA " + "state (%d).\n", unit, ctx->state); + return 1; + } + + /* + * Initialize the DMA control structures (hardware & B-channel). + */ + ba = ctx->bus_addr; + + txc->ring = ctx->pool + TIGER_CH_A; + rxc->ring = ctx->pool + TIGER_CH_A + ITJC_RING_BYTES; + + txc->bus_addr = ba; + rxc->bus_addr = ba + ITJC_RING_BYTES; + + ++rxc; ++txc; + + txc->ring = ctx->pool + TIGER_CH_B; + rxc->ring = ctx->pool + TIGER_CH_B + ITJC_RING_BYTES; + + txc->bus_addr = ba; + rxc->bus_addr = ba + ITJC_RING_BYTES; + + /* + * Fill the DMA ring buffers with IOM-2 channel 0 frames made of + * idle/abort sequences for the B & D channels and NOP for IOM-2 + * cmd/ind, monitor handshake & data. + */ + pool_end = (u_int32_t *)ctx->pool + ITJC_DMA_POOL_WORDS; + for (ip = (u_int32_t *)ctx->pool; ip < pool_end; ++ip) + *ip = 0xFFFFFFFF; + + /* + * Program the Tiger DMA gears. + */ + + itjc_write_4(TIGER_DMA_WR_START_ADDR, ba); + itjc_write_4(TIGER_DMA_WR_INT_ADDR, ba + ITJC_RING_SLOT_BYTES - 4); + itjc_write_4(TIGER_DMA_WR_END_ADDR, ba + ITJC_RING_BYTES - 4); + + ba += ITJC_RING_BYTES; + + itjc_write_4(TIGER_DMA_RD_START_ADDR, ba); + itjc_write_4(TIGER_DMA_RD_INT_ADDR, ba + ITJC_RING_SLOT_BYTES * 2 - 4); + itjc_write_4(TIGER_DMA_RD_END_ADDR, ba + ITJC_RING_BYTES - 4); + + itjc_write_1(TIGER_INT0_MASK, + TIGER_WR_END_INT | TIGER_WR_INT_INT | TIGER_RD_INT_INT); + + itjc_write_1(TIGER_DMA_OPER, TIGER_ENABLE_DMA); + + /* + * See if it really started. + */ + ba = itjc_read_4(TIGER_DMA_RD_CURR_ADDR); + for (i = 0; i < 10; ++i) + { + DELAY(SEC_DELAY/1000); + if (ba != itjc_read_4(TIGER_DMA_RD_CURR_ADDR)) + { + ctx->state = ITJC_DS_RUNNING; + return 0; + } + } + + NDBGL1(L1_ERROR, "itjc%d: dma_start: DMA start failed.\n ", unit); + return 1; +} + + +/*---------------------------------------------------------------------------* + * itjc_dma_stop - Stop the Tiger DMA engine. + *---------------------------------------------------------------------------*/ +void +itjc_dma_stop(struct l1_softc *sc) +{ + dma_context_t *ctx = &dma_context[sc->sc_unit]; + + itjc_bus_setup(sc); + + /* Only stop the DMA if it is running. */ + + if (ctx->state != ITJC_DS_RUNNING) + return; + + itjc_write_1(TIGER_DMA_OPER, TIGER_DISABLE_DMA); + DELAY(SEC_DELAY/1000); + + ctx->state = ITJC_DS_STOPPED; +} + + +/*---------------------------------------------------------------------------* + * itjc_bchannel_dma_setup - The DMA side of itjc_bchannel_setup. + *---------------------------------------------------------------------------*/ +static void +itjc_bchannel_dma_setup(struct l1_softc *sc, int h_chan, int activate) +{ + dma_rx_context_t *rxc = &dma_rx_context[sc->sc_unit][h_chan]; + dma_tx_context_t *txc = &dma_tx_context[sc->sc_unit][h_chan]; + + l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + + u_int8_t fill_byte, + *ring_end, + *cp; + + int s = SPLI4B(); + + itjc_bus_setup(sc); + + if (activate) + { + /* + * Get the DMA engine going if it's not running already. + */ + itjc_dma_start(sc); + + rxc->hdlc_len = rxc->hdlc_tmp = rxc->hdlc_crc = 0; + rxc->hdlc_ib = rxc->hdlc_blevel = rxc->hdlc_flag = 0; + + txc->hdlc_tmp = txc->hdlc_blevel = txc->hdlc_crc = 0; + txc->hdlc_ib = 0; + txc->hdlc_flag = 2; + txc->filled = 0; + + if (chan->bprot == BPROT_NONE) + fill_byte = ITJC_TEL_SILENCE_BYTE; + else + fill_byte = ITJC_HDLC_ABORT_BYTE; + + ring_end = rxc->ring + ITJC_RING_BYTES; + for (cp = rxc->ring; cp < ring_end; cp += 4) + *cp = fill_byte; + + ring_end = txc->ring + ITJC_RING_BYTES; + for (cp = txc->ring; cp < ring_end; cp += 4) + *cp = fill_byte; + + rxc->next_read = + itjc_get_dma_offset(rxc, TIGER_DMA_RD_CURR_ADDR); + + txc->next_frame = txc->next_write = + itjc_get_dma_offset(txc, TIGER_DMA_WR_CURR_ADDR); + + rxc->state = ITJC_RS_ACTIVE; + txc->state = ITJC_TS_AFTER_XDU; + } + else + { + dma_rx_context_t *rxc2; + + txc->state = ITJC_TS_IDLE; + rxc->state = ITJC_RS_IDLE; + + rxc2 = &dma_rx_context[sc->sc_unit][0]; + + if (rxc2->state == ITJC_RS_IDLE + && rxc2[1].state == ITJC_RS_IDLE) + itjc_dma_stop(sc); + } + + splx(s); +} + + +/*---------------------------------------------------------------------------* + * Mbuf & if_queues management routines. + *---------------------------------------------------------------------------*/ + +static u_int8_t * +itjc_get_rx_mbuf(l1_bchan_state_t *chan, u_int8_t **dst_end_p, +which_mb_t which) +{ + struct mbuf *mbuf = chan->in_mbuf; + + if (mbuf == NULL && which == ITJC_MB_NEW) + { + if ((mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL) + panic("itjc_get_rx_mbuf: cannot allocate mbuf!"); + + chan->in_mbuf = mbuf; + chan->in_cbptr = (u_int8_t *)mbuf->m_data; + chan->in_len = 0; + } + + if (dst_end_p != NULL) + { + if (mbuf != NULL) + *dst_end_p = (u_int8_t *)(mbuf->m_data) + + BCH_MAX_DATALEN; + else + *dst_end_p = NULL; + } + + return chan->in_cbptr; +} + + +static void +itjc_save_rx_mbuf(l1_bchan_state_t *chan, u_int8_t * dst) +{ + struct mbuf *mbuf = chan->in_mbuf; + + if (dst != NULL && mbuf != NULL) + { + chan->in_cbptr = dst; + chan->in_len = dst - (u_int8_t *)mbuf->m_data; + } + else if (dst == NULL && mbuf == NULL) + { + chan->in_cbptr = NULL; + chan->in_len = 0; + } + else + panic("itjc_save_rx_mbuf: stale pointer dst=%p mbuf=%p " + "in_cbptr=%p in_len=%d", dst, mbuf, + chan->in_cbptr, chan->in_len); +} + + +static void +itjc_free_rx_mbuf(l1_bchan_state_t *chan) +{ + struct mbuf *mbuf = chan->in_mbuf; + + if (mbuf != NULL) + i4b_Bfreembuf(mbuf); + + chan->in_mbuf = NULL; + chan->in_cbptr = NULL; + chan->in_len = 0; +} + + +static void +itjc_put_rx_mbuf(struct l1_softc *sc, l1_bchan_state_t *chan, u_int16_t len) +{ + i4b_trace_hdr_t hdr; + struct mbuf *mbuf = chan->in_mbuf; + u_int8_t *data = mbuf->m_data; + int activity = 1; + + mbuf->m_pkthdr.len = mbuf->m_len = len; + + if (sc->sc_trace & TRACE_B_RX) + { + hdr.unit = L0ITJCUNIT(sc->sc_unit); + hdr.type = (chan->channel == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_NT; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, len, data); + } + + if (chan->bprot == BPROT_NONE) + { + activity = ! i4b_l1_bchan_tel_silence(data, len); + + /* move rx'd data to rx queue */ + + if (! _IF_QFULL(&chan->rx_queue)) + { + IF_ENQUEUE(&chan->rx_queue, mbuf); + } + else + { + i4b_Bfreembuf(mbuf); + len = 0; + } + } + + if (len != 0) + { + chan->rxcount += len; + + (*chan->isic_drvr_linktab->bch_rx_data_ready) + (chan->isic_drvr_linktab->unit); + } + + if (activity) + (*chan->isic_drvr_linktab->bch_activity) + (chan->isic_drvr_linktab->unit, ACT_RX); + + chan->in_mbuf = NULL; + chan->in_cbptr = NULL; + chan->in_len = 0; +} + + +#define itjc_free_tx_mbufs(chan) \ +{ \ + i4b_Bfreembuf((chan)->out_mbuf_head); \ + (chan)->out_mbuf_cur = (chan)->out_mbuf_head = NULL; \ + (chan)->out_mbuf_cur_ptr = NULL; \ + (chan)->out_mbuf_cur_len = 0; \ +} + + +static u_int16_t +itjc_get_tx_mbuf(struct l1_softc *sc, l1_bchan_state_t *chan, + u_int8_t **src_p, which_mb_t which) +{ + i4b_trace_hdr_t hdr; + struct mbuf *mbuf = chan->out_mbuf_cur; + u_int8_t activity = 1; + u_int16_t len; + void *data; + + switch (which) + { + case ITJC_MB_CURR: + if (mbuf != NULL) + { + *src_p = chan->out_mbuf_cur_ptr; + return chan->out_mbuf_cur_len; + } + + break; + + case ITJC_MB_NEXT: + if (mbuf != NULL) + { + chan->txcount += mbuf->m_len; + + mbuf = mbuf->m_next; + + if (mbuf != NULL) + goto new_mbuf; + } + + chan->out_mbuf_cur_ptr = *src_p = NULL; + chan->out_mbuf_cur_len = 0; + + if (chan->out_mbuf_head != NULL) + { + i4b_Bfreembuf(chan->out_mbuf_head); + chan->out_mbuf_head = NULL; + } + + return 0; + + case ITJC_MB_NEW: + if (mbuf != NULL) + chan->txcount += mbuf->m_len; + } + + if (chan->out_mbuf_head != NULL) + i4b_Bfreembuf(chan->out_mbuf_head); + + IF_DEQUEUE(&chan->tx_queue, mbuf); + + if (mbuf == NULL) + { + chan->out_mbuf_cur = chan->out_mbuf_head = NULL; + chan->out_mbuf_cur_ptr = *src_p = NULL; + chan->out_mbuf_cur_len = 0; + + chan->state &= ~(HSCX_TX_ACTIVE); + + (*chan->isic_drvr_linktab->bch_tx_queue_empty) + (chan->isic_drvr_linktab->unit); + + return 0; + } + + chan->out_mbuf_head = mbuf; + +new_mbuf: + chan->out_mbuf_cur = mbuf; + chan->out_mbuf_cur_ptr = data = mbuf->m_data; + chan->out_mbuf_cur_len = len = mbuf->m_len; + + chan->state |= HSCX_TX_ACTIVE; + + if (sc->sc_trace & TRACE_B_TX) + { + hdr.unit = L0ITJCUNIT(sc->sc_unit); + hdr.type = (chan->channel == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + i4b_l1_trace_ind(&hdr, len, data); + } + + if (chan->bprot == BPROT_NONE) + activity = ! i4b_l1_bchan_tel_silence(data, len); + + if (activity) + (*chan->isic_drvr_linktab->bch_activity) + (chan->isic_drvr_linktab->unit, ACT_TX); + + *src_p = data; + return len; +} + + +#define itjc_save_tx_mbuf(chan, src, dst) \ +( \ + (chan)->out_mbuf_cur != NULL ? \ + ( \ + (chan)->out_mbuf_cur_ptr = (src), \ + (chan)->out_mbuf_cur_len = (len) \ + ) \ + : \ + 0 \ +) + + +/*---------------------------------------------------------------------------* + * B-channel interrupt service routines. + *---------------------------------------------------------------------------*/ + +/* + * Since the Tiger ASIC doesn't produce a XMIT underflow indication, + * we need to deduce it ourselves. This is somewhat tricky because we + * are dealing with modulo m arithmetic. The idea here is to have a + * "XDU zone" ahead of the writing pointer sized 1/3 of total ring + * length (a ring slot). If the hardware DMA pointer is found there we + * consider that a XDU has occurred. To complete the scheme, we never + * let the ring have more than 2 slots of (unsent) data and adjust the + * interrupt registers to cause an interrupt at every slot. + */ +static u_int8_t +itjc_xdu(struct l1_softc *sc, l1_bchan_state_t *chan, dma_tx_context_t *ctx, +u_int16_t *dst_p, u_int16_t *dst_end_p, u_int8_t tx_restart) +{ + u_int8_t xdu; + + u_int16_t dst_end, + dst, + dma, + dma_l, + dma_h, + xdu_l, + xdu_h; + + itjc_bus_setup(sc); + + /* + * Since the hardware is running, be conservative and assume + * the pointer location has a `fuzy' error factor. + */ + dma = itjc_get_dma_offset(ctx, TIGER_DMA_WR_CURR_ADDR); + dma_l = dma; + dma_h = itjc_ring_add(dma, 1); + + dst_end = itjc_ring_sub(dma_l, ITJC_RING_SLOT_WORDS); + + if (ctx->state != ITJC_TS_ACTIVE) + { + xdu = (ctx->state == ITJC_TS_AFTER_XDU); + dst = itjc_ring_add(dma_h, 4); + goto done; + } + + /* + * Check for xmit underruns. + */ + xdu_l = dst = ctx->next_write; + xdu_h = itjc_ring_add(dst, ITJC_RING_SLOT_WORDS); + + if (xdu_l < xdu_h) + xdu = (xdu_l <= dma_l && dma_l < xdu_h) + || (xdu_l <= dma_h && dma_h < xdu_h); + else + xdu = (xdu_l <= dma_l || dma_l < xdu_h) + || (xdu_l <= dma_h || dma_h < xdu_h); + + if (xdu) + { + ctx->state = ITJC_TS_AFTER_XDU; + + dst = itjc_ring_add(dma_h, 4); + } + else if (tx_restart) + { + /* + * See if we still can restart from immediately + * after the last frame sent. It's a XDU test but + * using the real data end on the comparsions. We + * don't consider XDU an error here because we were + * just trying to avoid send a filling gap between + * frames. If it's already sent no harm is done. + */ + xdu_l = dst = ctx->next_frame; + xdu_h = itjc_ring_add(dst, ITJC_RING_SLOT_WORDS); + + if (xdu_l < xdu_h) + xdu = (xdu_l <= dma_l && dma_l < xdu_h) + || (xdu_l <= dma_h && dma_h < xdu_h); + else + xdu = (xdu_l <= dma_l || dma_l < xdu_h) + || (xdu_l <= dma_h || dma_h < xdu_h); + + if (xdu) + dst = itjc_ring_add(dma_h, 4); + + xdu = 0; + } + +done: + if (dst_p != NULL) + *dst_p = dst; + + if (dst_end_p != NULL) + *dst_end_p = dst_end; + + ctx->next_write = dst_end; + + return xdu; +} + + +#define itjc_rotate_hdlc_flag(blevel) \ + ((u_int8_t)(0x7E7E >> (8 - (u_int8_t)((blevel) >> 8)))) + + +static void +itjc_dma_rx_intr(struct l1_softc *sc, l1_bchan_state_t *chan, +dma_rx_context_t *ctx) +{ + u_int8_t *ring, + *dst, + *dst_end, + flag, + blevel; + + u_int16_t dma, + src, + tmp2, + tmp, + len, + crc, + ib; + + itjc_bus_setup(sc); + + + if (ctx->state == ITJC_RS_IDLE) + return; + + ring = ctx->ring; + dma = itjc_get_dma_offset(ctx, TIGER_DMA_RD_CURR_ADDR); + dma = itjc_ring_sub(dma, 1); + src = ctx->next_read; + + if (chan->bprot == BPROT_NONE) + { + dst = itjc_get_rx_mbuf(chan, &dst_end, ITJC_MB_CURR); + + while (src != dma) + { + if (dst == NULL) + dst = itjc_get_rx_mbuf(chan, &dst_end, + ITJC_MB_NEW); + + *dst++ = ring[src]; + src = itjc_ring_add(src, 1); + + if (dst >= dst_end) + { + itjc_put_rx_mbuf(sc, chan, BCH_MAX_DATALEN); + dst = dst_end = NULL; + } + } + ctx->next_read = src; + itjc_save_rx_mbuf(chan, dst); + return; + } + + blevel = ctx->hdlc_blevel; + flag = ctx->hdlc_flag; + len = ctx->hdlc_len; + tmp = ctx->hdlc_tmp; + crc = ctx->hdlc_crc; + ib = ctx->hdlc_ib; + + dst = itjc_get_rx_mbuf(chan, NULL, ITJC_MB_CURR); + + while (src != dma) + { + HDLC_DECODE(*dst++, len, tmp, tmp2, blevel, ib, crc, flag, + {/* rdd */ + tmp2 = ring[src]; + src = itjc_ring_add(src, 1); + }, + {/* nfr */ + if (dst != NULL) + panic("itjc_dma_rx_intr: nfrcmd with " + "valid current frame"); + + dst = itjc_get_rx_mbuf(chan, &dst_end, ITJC_MB_NEW); + len = dst_end - dst; + }, + {/* cfr */ + len = BCH_MAX_DATALEN - len; + + if ((!len) || (len > BCH_MAX_DATALEN)) + { + /* + * NOTE: frames without any data, only crc + * field, should be silently discared. + */ + NDBGL1(L1_S_MSG, "itjc_dma_rx_intr: " + "bad frame (len=%d, unit=%d)", + len, sc->sc_unit); + + itjc_free_rx_mbuf(chan); + + goto s0; + } + + if (crc) + { + NDBGL1(L1_S_ERR, + "CRC (crc=0x%04x, len=%d, unit=%d)", + crc, len, sc->sc_unit); + + itjc_free_rx_mbuf(chan); + + goto s0; + } + + itjc_put_rx_mbuf(sc, chan, len); + + s0: + dst = NULL; + len = 0; + }, + {/* rab */ + NDBGL1(L1_S_ERR, "Read Abort (unit=%d)", sc->sc_unit); + + itjc_free_rx_mbuf(chan); + dst = NULL; + len = 0; + }, + {/* rdo */ + NDBGL1(L1_S_ERR, "RDO (unit=%d) dma=%d src=%d", + sc->sc_unit, dma, src); + + itjc_free_rx_mbuf(chan); + dst = NULL; + len = 0; + }, + continue, + d); + } + + itjc_save_rx_mbuf(chan, dst); + + ctx->next_read = src; + ctx->hdlc_blevel= blevel; + ctx->hdlc_flag = flag; + ctx->hdlc_len = len; + ctx->hdlc_tmp = tmp; + ctx->hdlc_crc = crc; + ctx->hdlc_ib = ib; +} + + +/* + * The HDLC side of itjc_dma_tx_intr. We made a separate function + * to improve readability and (perhaps) help the compiler with + * register allocation. + */ +static void +itjc_hdlc_encode(struct l1_softc *sc, l1_bchan_state_t *chan, +dma_tx_context_t * ctx) +{ + u_int8_t *ring, + *src, + xdu, + flag, + flag_byte, + tx_restart; + + u_int16_t saved_len, + dst_end, + dst_end1, + dst, + filled, + blevel, + tmp2, + len, + crc, + ib; + + u_int32_t tmp; + + + saved_len = len = itjc_get_tx_mbuf(sc, chan, &src, ITJC_MB_CURR); + + filled = ctx->filled; + flag = ctx->hdlc_flag; + + if (src == NULL && flag == 2 && filled >= ITJC_RING_WORDS) + return; + + tx_restart = (flag == 2 && src != NULL); + xdu = itjc_xdu(sc, chan, ctx, &dst, &dst_end, tx_restart); + + ring = ctx->ring; + + ib = ctx->hdlc_ib; + crc = ctx->hdlc_crc; + tmp = ctx->hdlc_tmp; + blevel = ctx->hdlc_blevel; + + if (xdu) + { + if (flag != 2) + { + NDBGL1(L1_H_XFRERR, "XDU"); + ++chan->stat_XDU; + + /* + * Abort the current frame and + * prepare for a full restart. + */ + itjc_free_tx_mbufs(chan); + saved_len = len = filled = 0; + flag = (u_int8_t)-2; + } + else if (filled < ITJC_RING_SLOT_WORDS) + { + /* + * A little garbage may have been retransmitted. + * Send an abort before any new data. + */ + filled = 0; + flag = (u_int8_t)-2; + } + } + + if (flag != 3) + len = 0; + + while (dst != dst_end) + { + HDLC_ENCODE( + *src++, len, tmp, tmp2, blevel, ib, crc, flag, + {/* gfr */ + if ((len = saved_len) == 0) + len = itjc_get_tx_mbuf(sc, chan, &src, + ITJC_MB_NEW); + + if (len == 0) + { + ctx->next_frame = dst; + + flag_byte = itjc_rotate_hdlc_flag(blevel); + + for (dst_end1 = itjc_ring_sub(dst_end, 1); + dst != dst_end1; + dst = itjc_ring_add(dst, 1)) + { + ring[dst] = flag_byte; + ++filled; + } + } + else + filled = 0; + + ctx->state = ITJC_TS_ACTIVE; + }, + {/* nmb */ + saved_len = 0; + len = itjc_get_tx_mbuf(sc, chan, &src, ITJC_MB_NEXT); + }, + {/* wrd */ + ring[dst] = (u_int8_t)tmp; + dst = itjc_ring_add(dst, 1); + }, + d1); + } + + ctx->hdlc_blevel = blevel; + ctx->hdlc_flag = flag; + ctx->hdlc_tmp = tmp; + ctx->hdlc_crc = crc; + ctx->hdlc_ib = ib; + + ctx->filled = filled; + ctx->next_write = dst; + + itjc_save_tx_mbuf(chan, src, len); +} + + +static void +itjc_dma_tx_intr(struct l1_softc *sc, l1_bchan_state_t *chan, +dma_tx_context_t * ctx) +{ + u_int8_t *data_end, + *ring, + *src, + xdu; + + u_int16_t dst, + dst_end, + filled, + len; + + + if (ctx->state == ITJC_TS_IDLE) + goto done; + + if (chan->bprot != BPROT_NONE) + { + itjc_hdlc_encode(sc, chan, ctx); + goto done; + } + + ring = ctx->ring; + filled = ctx->filled; + + len = itjc_get_tx_mbuf(sc, chan, &src, ITJC_MB_CURR); + + if (len == 0 && filled >= ITJC_RING_WORDS) + goto done; + + xdu = itjc_xdu(sc, chan, ctx, &dst, &dst_end, len != 0); + + if (xdu && filled < ITJC_RING_WORDS) + { + NDBGL1(L1_H_XFRERR, "XDU"); + ++chan->stat_XDU; + filled = 0; + } + + if (len == 0) + goto fill_ring; + + ctx->state = ITJC_TS_ACTIVE; + + data_end = src + len; + while (dst != dst_end) + { + ring[dst] = *src++; --len; + + dst = itjc_ring_add(dst, 1); + + if (src >= data_end) + { + len = itjc_get_tx_mbuf(sc, chan, &src, ITJC_MB_NEXT); + if (len == 0) + len = itjc_get_tx_mbuf(sc, chan, + &src, ITJC_MB_NEW); + + if (len == 0) + { + data_end = NULL; + break; + } + data_end = src + len; + } + } + + itjc_save_tx_mbuf(chan, src, len); + + filled = 0; + +fill_ring: + ctx->next_frame = dst; + + for (; dst != dst_end; dst = itjc_ring_add(dst, 1)) + { + ring[dst] = ITJC_TEL_SILENCE_BYTE; + ++filled; + } + + ctx->next_write = dst; + ctx->filled = filled; + +done: +} + + +/*---------------------------------------------------------------------------* + * NetJet fifo read/write routines. + *---------------------------------------------------------------------------*/ + +static void +itjc_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + itjc_bus_setup(sc); + + if (what != ISIC_WHAT_ISAC) + panic("itjc_write_fifo: Trying to read from HSCX fifo.\n"); + + itjc_set_pib_addr_msb(0); + itjc_read_multi_1(PIB_OFFSET, buf, size); +} + + +static void +itjc_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size) +{ + itjc_bus_setup(sc); + + if (what != ISIC_WHAT_ISAC) + panic("itjc_write_fifo: Trying to write to HSCX fifo.\n"); + + itjc_set_pib_addr_msb(0); + itjc_write_multi_1(PIB_OFFSET, buf, size); +} + + +/*---------------------------------------------------------------------------* + * Read an ISAC register. + *---------------------------------------------------------------------------*/ +static u_int8_t +itjc_read_reg(struct l1_softc *sc, int what, bus_size_t offs) +{ + itjc_bus_setup(sc); + + if (what != ISIC_WHAT_ISAC) + { + panic("itjc_read_reg: what(%d) != ISIC_WHAT_ISAC\n", + what); + return 0; + } + + itjc_set_pib_addr_msb(offs); + return itjc_read_1(itjc_pib_2_pci(offs)); +} + + +/*---------------------------------------------------------------------------* + * Write an ISAC register. + *---------------------------------------------------------------------------*/ +static void +itjc_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + itjc_bus_setup(sc); + + if (what != ISIC_WHAT_ISAC) + { + panic("itjc_write_reg: what(%d) != ISIC_WHAT_ISAC\n", + what); + return; + } + + itjc_set_pib_addr_msb(offs); + itjc_write_1(itjc_pib_2_pci(offs), data); +} + + +/*---------------------------------------------------------------------------* + * itjc_probe - probe for a card. + *---------------------------------------------------------------------------*/ +static int itjc_probe(device_t dev) +{ + u_int16_t vid = pci_get_vendor(dev), + did = pci_get_device(dev); + + if ((vid == PCI_TJNET_VID) && (did == PCI_TJ300_DID)) + { + device_set_desc(dev, "NetJet-S"); + return 0; + } + + return ENXIO; +} + + +/*---------------------------------------------------------------------------* + * itjc_attach - attach a (previously probed) card. + *---------------------------------------------------------------------------*/ +int +itjc_attach(device_t dev) +{ + bus_space_handle_t h; + bus_space_tag_t t; + + struct l1_softc *sc = device_get_softc(dev); + + u_int16_t vid = pci_get_vendor(dev), + did = pci_get_device(dev); + + int unit = device_get_unit(dev), + s = splimp(), + res_init_level = 0, + error = 0; + + void *ih = 0; + + dma_context_t *ctx = &dma_context[unit]; + + bzero(sc, sizeof(struct l1_softc)); + + /* Probably not really required. */ + if (unit > ITJC_MAXUNIT) + { + printf("itjc%d: Error, unit > ITJC_MAXUNIT!\n", unit); + splx(s); + return ENXIO; + } + + if (!(vid == PCI_TJNET_VID && did == PCI_TJ300_DID)) + { + printf("itjc%d: unknown device (%04X,%04X)!\n", unit, vid, did); + goto fail; + } + + itjc_scp[unit] = sc; + + sc->sc_resources.io_rid[0] = PCIR_MAPS+0; + sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, + &sc->sc_resources.io_rid[0], 0, ~0, 1, RF_ACTIVE); + + if (sc->sc_resources.io_base[0] == NULL) + { + printf("itjc%d: couldn't map IO port\n", unit); + error = ENXIO; + goto fail; + } + + h = rman_get_bushandle(sc->sc_resources.io_base[0]); + t = rman_get_bustag(sc->sc_resources.io_base[0]); + + ++res_init_level; + + /* Allocate interrupt. */ + sc->sc_resources.irq_rid = 0; + sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ, + &sc->sc_resources.irq_rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); + + if (sc->sc_resources.irq == NULL) + { + printf("itjc%d: couldn't map interrupt\n", unit); + error = ENXIO; + goto fail; + } + + ++res_init_level; + + error = bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, + itjc_intr, sc, &ih); + + if (error) + { + printf("itjc%d: couldn't set up irq handler\n", unit); + error = ENXIO; + goto fail; + } + + /* + * Reset the ASIC & the ISAC. + */ + itjc_write_1(TIGER_RESET_PIB_CL_TIME, TIGER_RESET_ALL); + + DELAY(SEC_DELAY/100); /* Give it 10 ms to reset ...*/ + + itjc_write_1(TIGER_RESET_PIB_CL_TIME, + TIGER_SELF_ADDR_DMA | TIGER_PIB_3_CYCLES); + + DELAY(SEC_DELAY/100); /* ... and more 10 to recover. */ + + /* + * First part of DMA initialization. Create & map the memory + * pool that will be used to bear the rx & tx ring buffers. + */ + ctx->state = ITJC_DS_LOADING; + + error = bus_dma_tag_create( + NULL, /* parent */ + 4, /* alignment*/ + 0, /* boundary*/ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr*/ + BUS_SPACE_MAXADDR, /* highaddr*/ + NULL, /* filter*/ + NULL, /* filterarg*/ + ITJC_DMA_POOL_BYTES, /* maxsize*/ + 1, /* nsegments*/ + ITJC_DMA_POOL_BYTES, /* maxsegsz*/ + BUS_DMA_ALLOCNOW | BUS_DMAMEM_NOSYNC, /* flags*/ + &ctx->tag); + + if (error) + { + printf("itjc%d: couldn't create bus DMA tag.\n", unit); + goto fail; + } + + ++res_init_level; + + error = bus_dmamem_alloc( + ctx->tag, /* DMA tag */ + (void **)&ctx->pool, /* KV addr of the allocated memory */ + BUS_DMA_NOWAIT | BUS_DMAMEM_NOSYNC, /* flags */ + &ctx->map); /* KV <-> PCI map */ + + if (error) + goto fail; + + /* + * Load the KV <-> PCI map so the device sees the same + * memory segment as pointed by pool. Note: since the + * load may happen assyncronously (completion indicated by + * the execution of the callback function) we have to + * delay the initialization of the DMA engine to a moment we + * actually have the proper bus addresses to feed the Tiger + * and our DMA control blocks. This will be done in + * itjc_bchannel_setup via a call to itjc_dma_start. + */ + bus_dmamap_load( + ctx->tag, /* DMA tag */ + ctx->map, /* DMA map */ + ctx->pool, /* KV addr of buffer */ + ITJC_DMA_POOL_BYTES, /* buffer size */ + itjc_map_callback, /* this receive the bus addr/error */ + ctx, /* callback aux arg */ + 0); /* flags */ + + ++res_init_level; + + /* + * Setup the AUX port so we can talk to the ISAC. + */ + itjc_write_1(TIGER_AUX_PORT_CNTL, TIGER_AUX_NJ_DEFAULT); + itjc_write_1(TIGER_INT1_MASK, TIGER_ISAC_INT); + + /* + * From now on, almost like a `normal' ISIC driver. + */ + + sc->sc_unit = unit; + + ISAC_BASE = (caddr_t)ISIC_WHAT_ISAC; + + HSCX_A_BASE = (caddr_t)ISIC_WHAT_HSCXA; + HSCX_B_BASE = (caddr_t)ISIC_WHAT_HSCXB; + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = itjc_read_reg; + sc->writereg = itjc_write_reg; + + sc->readfifo = itjc_read_fifo; + sc->writefifo = itjc_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_NETJET_S; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + /* set up some other miscellaneous things */ + sc->sc_ipac = 0; + sc->sc_bfifolen = 2 * ITJC_RING_SLOT_WORDS; + + printf("itjc%d: ISAC 2186 Version 1.1 (IOM-2)\n", unit); + + /* init the ISAC */ + itjc_isac_init(sc); + + /* init the "HSCX" */ + itjc_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + itjc_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* can't use the normal B-Channel stuff */ + itjc_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + +#if defined(__FreeBSD__) && __FreeBSD__ >=3 + callout_handle_init(&sc->sc_T3_callout); + callout_handle_init(&sc->sc_T4_callout); +#endif + + /* init higher protocol layers */ + + i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_ATTACH, + sc->sc_cardtyp, &itjc_l1mux_func); + + splx(s); + return 0; + + fail: + switch (res_init_level) + { + case 5: + bus_dmamap_unload(ctx->tag, ctx->map); + /* FALL TRHU */ + + case 4: + bus_dmamem_free(ctx->tag, ctx->pool, ctx->map); + bus_dmamap_destroy(ctx->tag, ctx->map); + /* FALL TRHU */ + + case 3: + bus_dma_tag_destroy(ctx->tag); + /* FALL TRHU */ + + case 2: + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_resources.irq); + /* FALL TRHU */ + + case 1: + bus_release_resource(dev, SYS_RES_IOPORT, PCIR_MAPS+0, + sc->sc_resources.io_base[0]); + /* FALL TRHU */ + + case 0: + } + + itjc_scp[unit] = NULL; + + splx(s); + return error; +} + + +/*---------------------------------------------------------------------------* + * itjc_intr - main interrupt service routine. + *---------------------------------------------------------------------------*/ +static void +itjc_intr(void *xsc) +{ + struct l1_softc *sc = xsc; + l1_bchan_state_t *chan = &sc->sc_chan[0]; + dma_context_t *dma = &dma_context[sc->sc_unit]; + dma_rx_context_t *rxc = &dma_rx_context[sc->sc_unit][0]; + dma_tx_context_t *txc = &dma_tx_context[sc->sc_unit][0]; + + itjc_bus_setup(sc); + + /* Honor interrupts from successfully configured cards only. */ + if (dma->state < ITJC_DS_STOPPED) + return; + + /* First, we check the ISAC... */ + if (! (itjc_read_1(TIGER_AUX_PORT_DATA) & TIGER_ISAC_INT_MASK)) + { + itjc_write_1(TIGER_INT1_STATUS, TIGER_ISAC_INT); + NDBGL1(L1_H_IRQ, "ISAC"); + itjc_isac_intr(sc); + } + + /* ... after what we always have a look at the DMA rings. */ + + NDBGL1(L1_H_IRQ, "Tiger"); + + itjc_read_1(TIGER_INT0_STATUS); + itjc_write_1(TIGER_INT0_STATUS, TIGER_TARGET_ABORT_INT + | TIGER_MASTER_ABORT_INT | TIGER_RD_END_INT + | TIGER_RD_INT_INT | TIGER_WR_END_INT | TIGER_WR_INT_INT); + + itjc_dma_rx_intr(sc, chan, rxc); + itjc_dma_tx_intr(sc, chan, txc); + + ++chan; ++rxc; ++txc; + + itjc_dma_rx_intr(sc, chan, rxc); + itjc_dma_tx_intr(sc, chan, txc); +} + + +/*---------------------------------------------------------------------------* + * itjc_bchannel_setup - (Re)initialize and start/stop a Bchannel. + *---------------------------------------------------------------------------*/ +static void +itjc_bchannel_setup(int unit, int h_chan, int bprot, int activate) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = itjc_scp[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + int s = SPLI4B(); + + NDBGL1(L1_BCHAN, "unit=%d, channel=%d, %s", + unit, h_chan, activate ? "activate" : "deactivate"); + + /* + * If we are deactivating the channel, we have to stop + * the DMA before we reset the channel control structures. + */ + if (! activate) + itjc_bchannel_dma_setup(sc, h_chan, activate); + + /* general part */ + + chan->state = HSCX_IDLE; + + chan->unit = sc->sc_unit; /* unit number */ + chan->channel = h_chan; /* B channel */ + chan->bprot = bprot; /* B channel protocol */ + + /* receiver part */ + + i4b_Bcleanifq(&chan->rx_queue); /* clean rx queue */ + + chan->rx_queue.ifq_maxlen = IFQ_MAXLEN; + + chan->rxcount = 0; /* reset rx counter */ + + i4b_Bfreembuf(chan->in_mbuf); /* clean rx mbuf */ + + chan->in_mbuf = NULL; /* reset mbuf ptr */ + chan->in_cbptr = NULL; /* reset mbuf curr ptr */ + chan->in_len = 0; /* reset mbuf data len */ + + /* transmitter part */ + + i4b_Bcleanifq(&chan->tx_queue); /* clean tx queue */ + + chan->tx_queue.ifq_maxlen = IFQ_MAXLEN; + + chan->txcount = 0; /* reset tx counter */ + + i4b_Bfreembuf(chan->out_mbuf_head); /* clean tx mbuf */ + + chan->out_mbuf_head = NULL; /* reset head mbuf ptr */ + chan->out_mbuf_cur = NULL; /* reset current mbuf ptr */ + chan->out_mbuf_cur_ptr = NULL; /* reset current mbuf data ptr */ + chan->out_mbuf_cur_len = 0; /* reset current mbuf data cnt */ + + /* + * Only setup & start the DMA after all other channel + * control structures are in place. + */ + if (activate) + itjc_bchannel_dma_setup(sc, h_chan, activate); + + splx(s); +} + + +/*---------------------------------------------------------------------------* + * itjc_bchannel_start - Signal us we have more data to send. + *---------------------------------------------------------------------------*/ +static void +itjc_bchannel_start(int unit, int h_chan) +{ +#if Buggy_code + /* + * I disabled this routine because it was causing crashes when + * this driver was used with the ISP (kernel SPPP) protocol driver. + * The scenario is reproductible: + * Use the -link1 (dial on demand) ifconfig option. + * Start an interactive TCP connection to somewhere. + * Wait until the PPP connection times out and is dropped. + * Try to send something on the TCP connection. + * The machine will print some garbage and halt or reboot + * (no panic messages). + * + * I've nailed down the problem to the fact that this routine + * was being called before the B channel had been setup again. + * + * For now, I don't have a good solution other than this one. + * But, don't despair. The impact of it is unnoticeable. + */ + +#ifdef __FreeBSD__ + struct l1_softc *sc = itjc_scp[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + + int s = SPLI4B(); + + dma_tx_context_t *txc = &dma_tx_context[unit][h_chan]; + + if (chan->state & HSCX_TX_ACTIVE) + { + splx(s); + return; + } + + itjc_dma_tx_intr(sc, chan, txc); + + splx(s); +#endif +} + + +/*---------------------------------------------------------------------------* + * itjc_shutdown - Stop the driver and reset the card. + *---------------------------------------------------------------------------*/ +static void +itjc_shutdown(device_t dev) +{ + struct l1_softc *sc = device_get_softc(dev); + + itjc_bus_setup(sc); + + /* + * Stop the DMA the nice and easy way. + */ + itjc_bchannel_setup(sc->sc_unit, 0, BPROT_NONE, 0); + itjc_bchannel_setup(sc->sc_unit, 1, BPROT_NONE, 0); + + /* + * Reset the card. + */ + itjc_write_1(TIGER_RESET_PIB_CL_TIME, TIGER_RESET_ALL); + + DELAY(SEC_DELAY/100); /* Give it 10 ms to reset ...*/ + + itjc_write_1(TIGER_RESET_PIB_CL_TIME, + TIGER_SELF_ADDR_DMA | TIGER_LATCH_DMA_INT | TIGER_PIB_3_CYCLES); + + DELAY(SEC_DELAY/100); /* ... and more 10 to recover */ +} + + +/*---------------------------------------------------------------------------* + * itjc_ret_linktab - Return the address of itjc drivers linktab. + *---------------------------------------------------------------------------*/ +isdn_link_t * +itjc_ret_linktab(int unit, int channel) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = itjc_scp[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[channel]; + + return(&chan->isic_isdn_linktab); +} + +/*---------------------------------------------------------------------------* + * itjc_set_linktab - Set the driver linktab in the b channel softc. + *---------------------------------------------------------------------------*/ +void +itjc_set_linktab(int unit, int channel, drvr_link_t *dlt) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = itjc_scp[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[channel]; + + chan->isic_drvr_linktab = dlt; +} + + +/*---------------------------------------------------------------------------* + * itjc_init_linktab - Initialize our local linktab. + *---------------------------------------------------------------------------*/ +static void +itjc_init_linktab(struct l1_softc *sc) +{ + l1_bchan_state_t *chan = &sc->sc_chan[HSCX_CH_A]; + isdn_link_t *lt = &chan->isic_isdn_linktab; + + /* make sure the hardware driver is known to layer 4 */ + /* avoid overwriting if already set */ + if (ctrl_types[CTRL_PASSIVE].set_linktab == NULL) + { + ctrl_types[CTRL_PASSIVE].set_linktab = itjc_set_linktab; + ctrl_types[CTRL_PASSIVE].get_linktab = itjc_ret_linktab; + } + + /* local setup */ + lt->unit = sc->sc_unit; + lt->channel = HSCX_CH_A; + lt->bch_config = itjc_bchannel_setup; + lt->bch_tx_start = itjc_bchannel_start; + lt->bch_stat = itjc_bchannel_stat; + lt->tx_queue = &chan->tx_queue; + + /* used by non-HDLC data transfers, i.e. telephony drivers */ + lt->rx_queue = &chan->rx_queue; + + /* used by HDLC data transfers, i.e. ipr and isp drivers */ + lt->rx_mbuf = &chan->in_mbuf; + + chan = &sc->sc_chan[HSCX_CH_B]; + lt = &chan->isic_isdn_linktab; + + lt->unit = sc->sc_unit; + lt->channel = HSCX_CH_B; + lt->bch_config = itjc_bchannel_setup; + lt->bch_tx_start = itjc_bchannel_start; + lt->bch_stat = itjc_bchannel_stat; + lt->tx_queue = &chan->tx_queue; + + /* used by non-HDLC data transfers, i.e. telephony drivers */ + lt->rx_queue = &chan->rx_queue; + + /* used by HDLC data transfers, i.e. ipr and isp drivers */ + lt->rx_mbuf = &chan->in_mbuf; +} + + +/*---------------------------------------------------------------------------* + * itjc_bchannel_stat - Collect link statistics for a given B channel. + *---------------------------------------------------------------------------*/ +static void +itjc_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp) +{ +#ifdef __FreeBSD__ + struct l1_softc *sc = itjc_scp[unit]; +#else + struct l1_softc *sc = isic_find_sc(unit); +#endif + l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; + int s; + + s = SPLI4B(); + + bsp->outbytes = chan->txcount; + bsp->inbytes = chan->rxcount; + + chan->txcount = 0; + chan->rxcount = 0; + + splx(s); +} + + +/*---------------------------------------------------------------------------* + * Netjet - ISAC interrupt routine. + *---------------------------------------------------------------------------*/ +static void +itjc_isac_intr(struct l1_softc *sc) +{ + register u_char irq_stat; + + do + { + /* get isac irq status */ + irq_stat = ISAC_READ(I_ISTA); + + if(irq_stat) + itjc_isac_irq(sc, irq_stat); /* isac handler */ + } + while(irq_stat); + + ISAC_WRITE(I_MASK, 0xff); + + DELAY(100); + + ISAC_WRITE(I_MASK, ISAC_IMASK); +} + + +/*---------------------------------------------------------------------------* + * itjc_recover - Try to recover from ISAC irq lockup. + *---------------------------------------------------------------------------*/ +void +itjc_recover(struct l1_softc *sc) +{ + u_char byte; + + /* get isac irq status */ + + byte = ISAC_READ(I_ISTA); + + NDBGL1(L1_ERROR, " ISAC: ISTA = 0x%x", byte); + + if(byte & ISAC_ISTA_EXI) + NDBGL1(L1_ERROR, " ISAC: EXIR = 0x%x", (u_char)ISAC_READ(I_EXIR)); + + if(byte & ISAC_ISTA_CISQ) + { + byte = ISAC_READ(I_CIRR); + + NDBGL1(L1_ERROR, " ISAC: CISQ = 0x%x", byte); + + if(byte & ISAC_CIRR_SQC) + NDBGL1(L1_ERROR, " ISAC: SQRR = 0x%x", (u_char)ISAC_READ(I_SQRR)); + } + + NDBGL1(L1_ERROR, " ISAC: IMASK = 0x%x", ISAC_IMASK); + + ISAC_WRITE(I_MASK, 0xff); + DELAY(100); + ISAC_WRITE(I_MASK, ISAC_IMASK); +} + +#endif /* NITJC > 0 */ |