This is a driver for IDT77252 based ATM interfaces. It has been tested

with a ProATM-155 and an IDT evaluation board and should also work
with a ProATM-25 (it seems to work at least, I cannot really measure
what the card emits). The driver has been tested on i386 and sparc64,
but should work an other archs also. It supports UBR, CBR, ABR and VBR;
AAL0, AAL5 and AALraw. As an additional feature VCI/VPI 0/0 can be
opened for receiving in AALraw mode and receives all cells not claimed
by other open VCs (even cells with invalid GFC, VPI and VCI fields and
OAM cells).

Thanks to Christian Bucari from ProSum for lending two cards and answering
my questions.
This commit is contained in:
harti 2003-07-15 11:57:24 +00:00
parent 44a5a05269
commit 0d78becf4a
15 changed files with 14948 additions and 0 deletions

View File

@ -1683,6 +1683,9 @@ options MSIZE=512 # mbuf size in bytes
#
# The `fatm' device provides support for Fore PCA200E ATM PCI cards.
#
# The `patm' device provides support for IDT77252 based cards like
# ProSum's ProATM-155 and ProATM-25 and IDT's evaluation boards.
#
# atm device provides generic atm functions and is required for
# atm devices.
# NATM enables the netnatm protocol family that can be used to
@ -1699,6 +1702,7 @@ device atm
device en
device fatm #Fore PCA200E
device hatm #Fore/Marconi HE155/622
device patm #IDT77252 cards (ProATM and IDT)
device utopia #ATM PHY driver
options NATM #native ATM

View File

@ -539,6 +539,13 @@ dev/musycc/musycc.c optional musycc
dev/nge/if_nge.c optional nge
dev/null/null.c standard
dev/nmdm/nmdm.c optional nmdm
dev/patm/if_patm.c optional patm pci
dev/patm/if_patm_intr.c optional patm pci
dev/patm/if_patm_ioctl.c optional patm pci
dev/patm/if_patm_rx.c optional patm pci
dev/patm/if_patm_tx.c optional patm pci
dev/patm/if_patm_attach.c optional patm pci
dev/patm/if_patm_rtables.c optional patm pci
dev/pccard/card_if.m standard
dev/pccard/pccard.c optional pccard
dev/pccard/pccard_cis.c optional pccard

View File

@ -0,0 +1,14 @@
# $FreeBSD$
#
# This program is used to generate the if_patm_rtables.c file
# for the idt77252 driver. It is not installed.
#
PROG=genrtab
WARNS=5
NOMAN=true
LDADD=-lm
install:
.include <bsd.prog.mk>

View File

@ -0,0 +1,458 @@
/*
* Copyright (c) 2003
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
* 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.
*
* Author: Hartmut Brandt <harti@freebsd.org>
*
* This program is used to generate the different rate tables for the IDT77252
* driver. The generated tables are slightly different from those in the
* IDT manual.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <ieeefp.h>
/* verbosity flag */
static int verbose;
/* number of table entries */
static const u_int tsize = 256;
/* number of rate difference tables to create */
static const u_int ndtables = 16;
/* cell rate offset for log 0 */
static const double offset = 10.0;
/*
* Make an internal form of the interval and be sure to round down.
*/
static u_int
d2interval(double d)
{
fp_rnd_t r;
u_int s, id;
r = fpsetround(FP_RZ);
id = (u_int)rint(32 * d);
fpsetround(r);
s = 0;
while (id >= 32 * 32) {
s++;
id >>= 1;
}
return ((s << 10) | (id));
}
/*
* Convert an internal interval back to a real one.
*/
static double
interval2d(u_int id)
{
return ((1 << ((id >> 10) & 0xf)) * ((id & 0x3ff) / 32.0));
}
/*
* Convert double to ATM-Forum format. Make sure to round up.
*/
static u_int
cps2atmf(double cps)
{
fp_rnd_t r;
u_int s, id;
if (cps < 1.0)
return (0);
s = 0;
while (cps >= 2.0) {
s++;
cps /= 2;
}
r = fpsetround(FP_RP);
id = (u_int)rint(512 * cps);
fpsetround(r);
return ((1 << 14) | (s << 9) | (id & 0x1ff));
}
/*
* Convert ATM forum format to double
*/
static double
atmf2cps(u_int atmf)
{
return (((atmf >> 14) & 1) * (1 << ((atmf >> 9) & 0x1f)) *
((512 + (atmf & 0x1ff)) / 512.0));
}
/*
* A cell rate to the logarithmic one
*/
static double
cps2log(u_int alink, double lg)
{
if (lg <= offset)
return (0);
if (lg >= alink)
return (tsize - 1);
return ((tsize - 1) * (1 - log(alink / lg) / log(alink / offset)));
}
/*
* Convert log to cell rate
*/
static double
log2cps(u_int alink, u_int lg)
{
return (alink / pow(alink / offset,
(double)(tsize - lg - 1) / (tsize - 1)));
}
/*
* Convert a double to an internal scaled double
*/
static u_int
d2ifp(double fp)
{
fp_rnd_t r;
u_int s, ifp;
fp *= (1 << 16);
r = fpsetround(FP_RN);
ifp = (u_int)rint(fp);
fpsetround(r);
s = 0;
while (ifp >= 1024) {
s++;
ifp >>= 1;
}
return ((s << 10) | (ifp));
}
/*
* Convert internal scaled float to double
*/
static double
ifp2d(u_int p)
{
return ((p & 0x3ff) * (1 << ((p >> 10) & 0xf)) / 65536.0);
}
/*
* Generate log to rate conversion table
*/
static void
gen_log2rate(u_int alink)
{
u_int i, iinterval, atmf, n, nrm;
double rate, interval, xinterval, cps, xcps;
for (i = 0; i < 256; i++) {
/* get the desired rate */
rate = alink / pow(alink / offset,
(double)(tsize - i - 1) / (tsize - 1));
/* convert this to an interval */
interval = alink / rate;
/* make the internal form of this interval, be sure to
* round down */
iinterval = d2interval(interval);
/* now convert back */
xinterval = interval2d(iinterval);
/* make a cps from this interval */
cps = alink / xinterval;
/* convert this to its ATM forum format */
atmf = cps2atmf(cps);
/* and back */
xcps = atmf2cps(atmf);
/* decide on NRM */
if (xcps < 40.0) {
nrm = 0;
n = 3;
} else if (xcps < 80.0) {
nrm = 1;
n = 4;
} else if (xcps < 160.0) {
nrm = 2;
n = 8;
} else if (xcps < 320.0) {
nrm = 3;
n = 16;
} else {
nrm = 4;
n = 32;
}
/* print */
if (verbose)
printf(" 0x%08x, /* %03u: cps=%f nrm=%u int=%f */\n",
(atmf << 17) | (nrm << 14) | iinterval, i,
xcps, n, xinterval);
else
printf("0x%08x,\n", (atmf << 17) | (nrm << 14) |
iinterval);
}
}
/*
* Generate rate to log conversion table
*/
static void
gen_rate2log(u_int alink)
{
u_int i, atmf, val, ilcr;
double cps, lcr;
fp_rnd_t r;
val = 0;
for (i = 0; i < 512; i++) {
/* make ATM Forum CPS from index */
atmf = (((i & 0x1f0) >> 4) << 9) |
((i & 0xf) << 5) | (1 << 14);
/* make cps */
cps = atmf2cps(atmf);
/* convert to log */
lcr = cps2log(alink, cps);
r = fpsetround(FP_RN);
ilcr = (u_int)rint(lcr);
fpsetround(r);
/* put together */
val |= ilcr << (8 * (i % 4));
/* print */
if (i % 4 == 3) {
if (verbose)
printf(" 0x%08x,\t", val);
else
printf("0x%08x,\n", val);
val = 0;
} else if (verbose)
printf("\t\t");
if (verbose)
printf("/* %03u: %f -> %f */\n", i,
cps, log2cps(alink, ilcr));
}
}
/*
* Generate one entry into the global table
*/
static void
gen_glob_entry(u_int alink, u_int fill, u_int ci, u_int ni)
{
if (verbose)
printf(" 0x%08x, /* %2u/32 %8.6f, %6u, ci=%u, ni=%u */\n",
cps2atmf(alink * fill / 32.0) | (ci << 17) | (ni << 16),
fill, fill / 32.0, alink * fill / 32, ci, ni);
else
printf("0x%08x,\n",
cps2atmf(alink * fill / 32.0) | (ci << 17) | (ni << 16));
}
/*
* Generate global parameter table
*/
static void
gen_glob(u_int alink)
{
u_int i;
gen_glob_entry(alink, 32, 0, 0);
gen_glob_entry(alink, 16, 0, 0);
gen_glob_entry(alink, 8, 0, 1);
gen_glob_entry(alink, 4, 0, 1);
gen_glob_entry(alink, 2, 1, 1);
gen_glob_entry(alink, 1, 1, 1);
gen_glob_entry(alink, 0, 1, 1);
gen_glob_entry(alink, 0, 1, 1);
for (i = 0; i < tsize/2 - 8; i++) {
if (i % 16 == 0)
printf(" ");
printf(" 0,");
if (i % 16 == 15)
printf("\n");
}
printf("\n");
}
/*
* Generate additive rate increase tables
*/
static void
gen_air(u_int alink)
{
u_int t, i;
double diff; /* cell rate to increase by */
double cps;
double add;
u_int val, a;
for (t = 0; t < ndtables; t++) {
diff = (double)alink / (1 << t);
printf("/* AIR %u: diff=%f */\n", t, diff);
val = 0;
for (i = 0; i < tsize; i++) {
cps = log2cps(alink, i);
cps += diff;
if (cps > alink)
cps = alink;
add = cps2log(alink, cps) - i;
a = d2ifp(add);
if (i % 2) {
val |= a << 16;
if (verbose)
printf(" 0x%08x,\t", val);
else
printf("0x%08x,\n", val);
} else {
val = a;
if (verbose)
printf("\t\t");
}
if (verbose)
printf("/* %3u: %f */\n", i, ifp2d(add));
}
}
}
/*
* Generate rate decrease table
*/
static void
gen_rdf(u_int alink)
{
double d;
u_int t, i, f, val, diff;
for (t = 0; t < ndtables; t++) {
/* compute the log index difference */
if (t == 0) {
d = tsize - 1;
} else {
f = 1 << t;
d = (tsize - 1) / log(alink / offset);
d *= log((double)f / (f - 1));
}
printf(" /* RDF %u: 1/%u: %f */\n", t, 1 << t, d);
val = 0;
for (i = 0; i < tsize; i++) {
if (i < d)
diff = d2ifp(i);
else
diff = d2ifp(d);
if (i % 2) {
val |= diff << 16;
if (verbose)
printf(" 0x%08x,\t", val);
else
printf("0x%08x,\n", val);
} else {
val = diff;
if (verbose)
printf("\t\t");
}
if (verbose)
printf("/* %3u: %f */\n", i, ifp2d(diff));
}
}
}
/*
* Create all the tables for a given link cell rate and link bit rate.
* The link bit rate is only used to name the table.
*/
static void
gen_tables(u_int alink, u_int mbps)
{
printf("\n");
printf("/*\n");
printf(" * Tables for %ucps and %uMbps\n", alink, mbps);
printf(" */\n");
printf("const uint32_t patm_rtables%u[128 * (4 + 2 * %u)] = {\n",
mbps, ndtables);
gen_log2rate(alink);
gen_rate2log(alink);
gen_glob(alink);
gen_air(alink);
gen_rdf(alink);
printf("};\n");
}
int
main(int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, "v")) != -1)
switch (opt) {
case 'v':
verbose = 1;
break;
}
printf("/*\n");
printf(" * This file was generated by `%s'\n", argv[0]);
printf(" */\n");
printf("\n");
printf("#include <sys/cdefs.h>\n");
printf("__FBSDID(\"$FreeBSD$\");\n");
printf("\n");
printf("#include <sys/types.h>\n");
printf("\n");
printf("const u_int patm_rtables_size = 128 * (4 + 2 * %u);\n",
ndtables);
printf("const u_int patm_rtables_ntab = %u;\n", ndtables);
gen_tables(352768, 155);
gen_tables( 59259, 25);
return (0);
}

476
sys/dev/patm/idt77252reg.h Normal file
View File

@ -0,0 +1,476 @@
/*
* Copyright (c) 2003
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
* 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.
*
* Author: Hartmut Brandt <harti@freebsd.org>
*
* $FreeBSD$
*
* Register definitions for the IDT77252 chip.
*/
#define PCI_VENDOR_IDT 0x111D
#define PCI_DEVICE_IDT77252 3
#define PCI_DEVICE_IDT77v252 4
#define PCI_DEVICE_IDT77v222 5
#define IDT_PCI_REG_MEMBASE 0x14
#define IDT_NOR_D0 0x00 /* R/W Data register 0 */
#define IDT_NOR_D1 0x04 /* R/W Data register 1 */
#define IDT_NOR_D2 0x08 /* R/W Data register 2 */
#define IDT_NOR_D3 0x0C /* R/W Data register 3 */
#define IDT_NOR_CMD 0x10 /* R/W Command */
#define IDT_NOR_CFG 0x14 /* R/W Configuration */
#define IDT_NOR_STAT 0x18 /* R/W Status */
#define IDT_NOR_RSQB 0x1C /* R/W Receive status queue base */
#define IDT_NOR_RSQT 0x20 /* R Receive status queue tail */
#define IDT_NOR_RSQH 0x24 /* R/W Receive status queue tail */
#define IDT_NOR_CDC 0x28 /* R/W Cell drop counter */
#define IDT_NOR_VPEC 0x2C /* R/W VPI/VCI Lookup error counter */
#define IDT_NOR_ICC 0x30 /* R/W Invalid cell counter */
#define IDT_NOR_RAWCT 0x34 /* R Raw cell tail */
#define IDT_NOR_TMR 0x38 /* R Timer */
#define IDT_NOR_TSTB 0x3C /* R/W Transmit schedule table base */
#define IDT_NOR_TSQB 0x40 /* R/W Transmit Status queue base */
#define IDT_NOR_TSQT 0x44 /* R/W Transmit Status queue tail */
#define IDT_NOR_TSQH 0x48 /* R/W Transmit Status queue head */
#define IDT_NOR_GP 0x4C /* R/W General purpose */
#define IDT_NOR_VPM 0x50 /* R/W VPI/VCI mask */
#define IDT_NOR_RXFD 0x54 /* R/W Receive FIFO descriptor */
#define IDT_NOR_RXFT 0x58 /* R/W Receive FIFO tail */
#define IDT_NOR_RXFH 0x5C /* R/W Receive FIFO head */
#define IDT_NOR_RAWHND 0x60 /* R/W Raw cell handle */
#define IDT_NOR_RXSTAT 0x64 /* R Receive connection state */
#define IDT_NOR_ABRSTD 0x68 /* R/W ABR & VBR Schedule table descriptor */
#define IDT_NOR_ABRRQ 0x6C /* R/W ABR Ready queue pointer */
#define IDT_NOR_VBRRQ 0x70 /* R/W VBR Ready queue pointer */
#define IDT_NOR_RTBL 0x74 /* R/W Rate table descriptor */
#define IDT_NOR_MXDFCT 0x78 /* R/W Maximum deficit counter */
#define IDT_NOR_TXSTAT 0x7C /* R/W Transmit connection state */
#define IDT_NOR_TCMDQ 0x80 /* W Transmit command queue */
#define IDT_NOR_IRCP 0x84 /* R/W Inactive receive connection pointer */
#define IDT_NOR_FBQP0 0x88 /* R/W Free buffer queue 0 pointer */
#define IDT_NOR_FBQP1 0x8C /* R/W Free buffer queue 1 pointer */
#define IDT_NOR_FBQP2 0x90 /* R/W Free buffer queue 2 pointer */
#define IDT_NOR_FBQP3 0x94 /* R/W Free buffer queue 3 pointer */
#define IDT_NOR_FBQS0 0x98 /* R/W Free buffer queue 0 size */
#define IDT_NOR_FBQS1 0x9C /* R/W Free buffer queue 1 size */
#define IDT_NOR_FBQS2 0xA0 /* R/W Free buffer queue 2 size */
#define IDT_NOR_FBQS3 0xA4 /* R/W Free buffer queue 3 size */
#define IDT_NOR_FBQWP0 0xA8 /* R/W Free buffer queue 0 write pointer */
#define IDT_NOR_FBQWP1 0xAC /* R/W Free buffer queue 1 write pointer */
#define IDT_NOR_FBQWP2 0xB0 /* R/W Free buffer queue 2 write pointer */
#define IDT_NOR_FBQWP3 0xB4 /* R/W Free buffer queue 3 write pointer */
#define IDT_NOR_NOW 0xB8 /* R Current transmit schedule table addr */
#define IDT_NOR_DNOW 0xBC /* R Dynamic Now register */
#define IDT_NOR_END 0xC0
/*
* Command (IDT_NOR_CMD)
*/
#define IDT_CMD_NOP 0x00000000 /* No operation */
#define IDT_CMD_OPCL 0x20000000 /* Open/Close connection */
#define IDT_CMD_WSRAM 0x40000000 /* Write SRAM */
#define IDT_CMD_RSRAM 0x50000000 /* Read SRAM */
#define IDT_CMD_WFBQ 0x60000000 /* Write free buffer queue */
#define IDT_CMD_RUTIL 0x80000000 /* Read utility bus */
#define IDT_CMD_WUTIL 0x90000000 /* Write utility bus */
#define IDT_MKCMD_OPEN(VC) (IDT_CMD_OPCL | (1 << 19) | ((V) << 4))
#define IDT_MKCMD_CLOSE(VC) (IDT_CMD_OPCL | (0 << 19) | ((V) << 4))
#define IDT_MKCMD_WSRAM(A, S) (IDT_CMD_WSRAM | ((A) << 2) | (S))
#define IDT_MKCMD_RSRAM(A) (IDT_CMD_RSRAM | ((A) << 2))
#define IDT_MKCMD_WFBQ(Q) (IDT_CMD_WFBQ | (Q))
#define IDT_MKCMD_RUTIL(S0, S1, A) \
(IDT_CMD_RUTIL | ((S1) << 9) | ((S0) << 8) | (A))
#define IDT_MKCMD_WUTIL(S0, S1, A) \
(IDT_CMD_WUTIL | ((S1) << 9) | ((S0) << 8) | (A))
/*
* Configuration register (CFG)
*/
#define IDT_CFG_SWRST 0x80000000 /* software reset */
#define IDT_CFG_LOOP 0x40000000 /* internal loopback enable */
#define IDT_CFG_RXPTH 0x20000000 /* receive path enable */
#define IDT_CFG_IDLECLP 0x10000000 /* set CLP in null cells */
#define IDT_CFG_TXFIFO9 0x00000000 /* Tx FIFO 9 cells */
#define IDT_CFG_TXFIFO1 0x04000000 /* Tx FIFO 1 cells */
#define IDT_CFG_TXFIFO2 0x08000000 /* Tx FIFO 2 cells */
#define IDT_CFG_TXFIFO4 0x0C000000 /* Tx FIFO 4 cells */
#define IDT_CFG_NOIDLE 0x02000000 /* don't send idle cells */
#define IDT_CFG_RXQ128 0x00000000 /* Rx Status Queue 128 entries */
#define IDT_CFG_RXQ256 0x00400000 /* Rx Status Queue 256 entries */
#define IDT_CFG_RXQ512 0x00800000 /* Rx Status Queue 512 entries */
#define IDT_CFG_ICAPT 0x00200000 /* Invalid cell accept */
#define IDT_CFG_IGGFC 0x00100000 /* Ignore GFC field */
#define IDT_CFG_VP0 0x00000000 /* 0 VPI bits */
#define IDT_CFG_VP1 0x00040000 /* 1 VPI bit */
#define IDT_CFG_VP2 0x00080000 /* 2 VPI bits */
#define IDT_CFG_VP8 0x000C0000 /* 8 VPI bits */
#define IDT_CFG_CTS1K 0x00000000 /* Rx Connection table 1024 entries */
#define IDT_CFG_CTS4K 0x00010000 /* Rx Connection table 4096 entries */
#define IDT_CFG_CTS16K 0x00020000 /* Rx Connection table 16384 entries */
#define IDT_CFG_CTS512 0x00030000 /* Rx Connection table 512 entries */
#define IDT_CFG_VPECA 0x00008000 /* VPI/VCI error cell accept */
#define IDT_CFG_RXINONE 0x00000000 /* No interrupt on receive */
#define IDT_CFG_RXIIMM 0x00001000 /* immediate interrupt */
#define IDT_CFG_RXI28 0x00002000 /* every 0x2800 clocks */
#define IDT_CFG_RXI4F 0x00003000 /* every 0x4F00 clocks */
#define IDT_CFG_RXI74 0x00004000 /* every 0x7400 clocks */
#define IDT_CFG_RAWIE 0x00000800 /* raw cell queue interrupt enable */
#define IDT_CFG_RQFIE 0x00000400 /* Rx status queue almost full IE */
#define IDT_CFG_CACHE 0x00000100 /* begin DMA on cache line */
#define IDT_CFG_TIMOIE 0x00000080 /* timer roll over interrupt enable */
#define IDT_CFG_FBIE 0x00000040 /* free buffer queue interrupt enable */
#define IDT_CFG_TXENB 0x00000020 /* Tx enable */
#define IDT_CFG_TXINT 0x00000010 /* Tx status interrupt enable */
#define IDT_CFG_TXUIE 0x00000008 /* Tx underrun interrupt enable */
#define IDT_CFG_UMODE 0x00000004 /* utopia byte mode */
#define IDT_CFG_TXSFI 0x00000002 /* Tx status full interrupt enable */
#define IDT_CFG_PHYIE 0x00000001 /* PHY interrupt enable */
/*
* Status register (STAT)
*/
#define IDT_STAT_FRAC3(S) (((S) >> 28) & 0xf) /* FBQ3 valid */
#define IDT_STAT_FRAC2(S) (((S) >> 24) & 0xf) /* FBQ2 valid */
#define IDT_STAT_FRAC1(S) (((S) >> 20) & 0xf) /* FBQ1 valid */
#define IDT_STAT_FRAC0(S) (((S) >> 16) & 0xf) /* FBQ0 valid */
#define IDT_STAT_TSIF 0x00008000 /* Tx status indicator flag */
#define IDT_STAT_TXICP 0x00004000 /* Tx incomplete PDU */
#define IDT_STAT_TSQF 0x00001000 /* Tx status queue full */
#define IDT_STAT_TMROF 0x00000800 /* Timer overflow */
#define IDT_STAT_PHYI 0x00000400 /* PHY interrupt */
#define IDT_STAT_CMDBZ 0x00000200 /* command busy */
#define IDT_STAT_FBQ3A 0x00000100 /* FBQ 3 attention flag */
#define IDT_STAT_FBQ2A 0x00000080 /* FBQ 2 attention flag */
#define IDT_STAT_RSQF 0x00000040 /* Rx status queue full */
#define IDT_STAT_EPDU 0x00000020 /* end of CS-PDU */
#define IDT_STAT_RAWCF 0x00000010 /* raw cell flag */
#define IDT_STAT_FBQ1A 0x00000008 /* FBQ 1 attention flag */
#define IDT_STAT_FBQ0A 0x00000004 /* FBQ 0 attention flag */
#define IDT_STAT_RSQAF 0x00000002 /* Rx status queue almost full */
/*
* Cell drop count (CDC)
*/
#define IDT_CDC_RMID 0x00400000 /* RM cell ID error */
#define IDT_CDC_CTE 0x00200000 /* Rx connection table error */
#define IDT_CDC_NFB 0x00100000 /* No free buffers */
#define IDT_CDC_OAMCRC 0x00080000 /* bad OAM CRC */
#define IDT_CDC_RMCRC 0x00040000 /* bad RM CRC */
#define IDT_CDC_RMFIFO 0x00020000 /* RM FIFO full */
#define IDT_CDC_RXFIFO 0x00010000 /* Rx FIFO full */
#define IDT_CDC(S) ((S) & 0xffff) /* cell drop counter */
/*
* VPI/VCI lookup error count (VPEC)
*/
#define IDT_VPEC(S) ((S) & 0xffff)
/*
* Invalid cell count (ICC)
*/
#define IDT_ICC(S) ((S) & 0xffff)
/*
* General purpose register
*/
#define IDT_GP_TXNCC(S) (((S) >> 24) & 0xff) /* Tx negative cell count */
#define IDT_GP_EEDI 0x00010000 /* EEPROM data in */
#define IDT_GP_BIGE 0x00008000 /* big endian enable */
#define IDT_GP_RM 0x00000000 /* process RM cells */
#define IDT_GP_RM_TEE 0x00002000 /* process RM cells and put in RawQ */
#define IDT_GP_RM_RAW 0x00006000 /* put RM cells in RawQ */
#define IDT_GP_DLOOP 0x00001000 /* double loopback */
#define IDT_GP_PCIPAR 0x00000010 /* force PCI parity error */
#define IDT_GP_PCIPERR 0x00000020 /* force PERR */
#define IDT_GP_PCISERR 0x00000040 /* force SERR */
#define IDT_GP_PHY_RST 0x00000008 /* PHY reset */
#define IDT_GP_EESCLK 0x00000004 /* EEPROM clock */
#define IDT_GP_EECS 0x00000002 /* EEPROM chip select */
#define IDT_GP_EEDO 0x00000001 /* EEPROM data out */
/*
* Receive FIFO descriptor register (RXFD)
*/
#define IDT_RXFD(A, S) (((S) << 24) | ((A) << 2))
#define IDT_RXFDS(V) (((V) >> 24) & 0xf)
#define IDT_RXFDA(V) (((V) & 0x1ffffc) >> 2)
/*
* ABR & VBR schedule table descriptor register
*/
#define IDT_ABRSTD(A, S) (((S) << 24) | ((A) << 2))
#define IDT_ABRSTDS(V) (((V) >> 24) & 0x7)
#define IDT_ABRSTDA(V) (((V) & 0x1ffffc) >> 2)
/*
* ABR/VBR ready queue register
*/
#define IDT_ABRRQH(V) (((V) >> 16) & 0x3fff)
#define IDT_ABRRQT(V) (((V) >> 0) & 0x3fff)
#define IDT_VBRRQH(V) (((V) >> 16) & 0x3fff)
#define IDT_VBRRQT(V) (((V) >> 0) & 0x3fff)
/*
* Maximum deficit limit register
*/
#define IDT_MDFCT_LCI 0x00020000 /* local congestion indicator enable */
#define IDT_MDFCT_LNI 0x00010000 /* local no incread enable */
/*
* Transmit command queue register
*/
#define IDT_TCMDQ_NOP() ((0x0 << 24)) /* no operation */
#define IDT_TCMDQ_START(C) ((0x1 << 24) | (C)) /* start connection */
#define IDT_TCMDQ_ULACR(C, L) ((0x2 << 24) | (C) | ((L) << 16))
/* update LACR */
#define IDT_TCMDQ_SLACR(C, L) ((0x3 << 24) | (C) | ((L) << 16))
/* start and update LACR */
#define IDT_TCMDQ_UIER(C, L) ((0x4 << 24) | (C) | ((L) << 16))
/* update Int ER */
#define IDT_TCMDQ_HALT(C) ((0x5 << 24) | (C)) /* halt connection */
/*
* Free buffer queue size registers
*/
#define IDT_FBQS(T, N, C, S) (((T) << 28) | ((N) << 24) | ((C) << 20) | (S))
/*
* Receive status queue
*/
struct idt_rsqe {
uint32_t cid; /* VPI/VCI */
uint32_t handle; /* buffer handle */
uint32_t crc; /* AAL-5 CRC */
uint32_t stat; /* div. flags */
};
#define IDT_RSQE_SIZE 16 /* bytes */
#define IDT_RSQE_VPI(CID) (((CID) >> 16) & 0xff)
#define IDT_RSQE_VCI(CID) ((CID) & 0xffff)
#define IDT_RSQE_TYPE(S) (((S) >> 30) & 0x3)
#define IDT_RSQE_DATA 0x2
#define IDT_RSQE_IDLE 0x3
#define IDT_RSQE_VALID 0x80000000
#define IDT_RSQE_POOL(S) (((S) >> 16) & 0x3)
#define IDT_RSQE_BUF 0x8000
#define IDT_RSQE_NZGFC 0x4000
#define IDT_RSQE_EPDU 0x2000
#define IDT_RSQE_CBUF 0x1000
#define IDT_RSQE_EFCIE 0x0800
#define IDT_RSQE_CLP 0x0400
#define IDT_RSQE_CRC 0x0200
#define IDT_RSQE_CNT(S) ((S) & 0x1ff)
#define IDT_RSQH(R) (((R) & 0x1ffc) >> 2)
#define IDT_RSQT(R) (((R) & 0x1ffc) >> 2)
/*
* Transmit status queue
*/
#define IDT_TSQ_SIZE 1024 /* no. of entries */
#define IDT_TSQE_SIZE 8 /* bytes */
#define IDT_TSQE_SHIFT 3
struct idt_tsqe {
uint32_t stat;
uint32_t stamp;
};
#define IDT_TSQE_EMPTY 0x80000000
#define IDT_TSQE_TYPE(E) (((E) >> 29) & 0x3)
#define IDT_TSQE_TIMER 0x0
#define IDT_TSQE_TSR 0x1
#define IDT_TSQE_IDLE 0x2
#define IDT_TSQE_TBD 0x3
#define IDT_TSQE_TAG(E) (((E) >> 24) & 0x1f)
#define IDT_TSQE_HALTED 0x10
#define IDT_TSQE_STAMP(E) ((E) & 0xffffff)
#define IDT_TSQE_TAG_SPACE 32
/*
* Raw cell handle
*/
struct idt_rawhnd {
uint32_t tail;
uint32_t handle;
};
#define IDT_RAWHND_SIZE 8
/*
* TST
*/
#define IDT_TST_NULL (0 << 29) /* transmit NULL cell */
#define IDT_TST_CBR (1 << 29) /* transmit CBR cell */
#define IDT_TST_VBR (2 << 29) /* transmit [AVU]BR cell */
#define IDT_TST_BR (3 << 29) /* branch */
#define IDT_TST_MASK 0x7ffff
/*
* Free buffer queue
*/
#define IDT_FBQ_SIZE 512 /* entries */
/*
* Receive connection table
*/
#define IDT_RCT_FBP2 0x00400000 /* use FBQ 2 */
#define IDT_RCT_OPEN 0x00080000 /* connection open */
#define IDT_RCT_AAL0 0x00000000 /* AAL 0 */
#define IDT_RCT_AAL34 0x00010000 /* AAL 3/4 */
#define IDT_RCT_AAL5 0x00020000 /* AAL 5 */
#define IDT_RCT_AALRAW 0x00030000 /* raw cells */
#define IDT_RCT_AALOAM 0x00040000 /* OAM cells */
#define IDT_RCT_RCI 0x00008000 /* raw cell interrupt enable */
#define IDT_RCT_IACT_CNT_MASK 0x1c000000
#define IDT_RCT_IACT_CNT_SHIFT 26
#define IDT_RCT_ENTRY_SIZE 4 /* words */
/*
* Transmit connection table
*/
#define IDT_TCT_CBR 0x00000000
#define IDT_TCT_VBR 0x40000000
#define IDT_TCT_ABR 0x80000000
#define IDT_TCT_UBR 0x00000000
#define IDT_TCT_UBR_FLG 0x80000000 /* word8 flag */
#define IDT_TCT_HALT 0x80000000 /* connection halted */
#define IDT_TCT_IDLE 0x40000000 /* connection idle */
#define IDT_TCT_TSIF 0x00004000
#define IDT_TCT_MAXIDLE 0x7f000000
#define IDT_TCT_MBS_SHIFT 16
#define IDT_TCT_CRM_SHIFT 29
#define IDT_TCT_NAGE_SHIFT 21
#define IDT_TCT_LMCR_SHIFT 24
#define IDT_TCT_CDF_SHIFT 20
#define IDT_TCT_RDF_SHIFT 14
#define IDT_TCT_AIR_SHIFT 8
#define IDT_TCT_ACRI_SHIFT 16
/*
* Segmentation channel queue
*/
#define IDT_SCQ_SIZE 64 /* number of entries */
struct idt_tbd {
uint32_t flags;
uint32_t addr;
uint32_t aal5;
uint32_t hdr;
};
#define IDT_TBD_SIZE 16 /* bytes */
#define IDT_TBD_SHIFT 4
#define IDT_TBD_TSR 0x80000000 /* TSR entry */
#define IDT_TBD_EPDU 0x40000000 /* end of AAL PDU */
#define IDT_TBD_TSIF 0x20000000 /* generate status */
#define IDT_TBD_AAL0 0x00000000 /* AAL0 */
#define IDT_TBD_AAL34 0x04000000 /* AAL3/4 */
#define IDT_TBD_AAL5 0x08000000 /* AAL5 */
#define IDT_TBD_AALOAM 0x10000000 /* OAM cells */
#define IDT_TBD_GTSI 0x02000000 /* generate transmit status entry */
#define IDT_TBD_TAG_SHIFT 20
#define IDT_TBD_HDR(VPI, VCI, PTI, CLP) \
(((VPI) << 20) | ((VCI) << 4) | ((PTI) << 1) | (CLP))
#define IDT_TBD_VPI(H) (((H) >> 20) & 0xff)
#define IDT_TBD_VCI(H) (((H) >> 4) & 0xffff)
/*
* Segmentation channel descriptor
*/
#define IDT_SCD_SIZE 12 /* words */
/*
* Memory map for the different RAM sizes
*
* 16k 32k 128k 512k
*
* TxCT 0x00000/4k 0x00000/8x 0x00000/32k 0x00000/128k
* RxCT 0x01000/2k 0x02000/4k 0x08000/16k 0x20000/64k
* FBQ0 0x01800/1k 0x03000/1k 0x0c000/1k 0x30000/1k
* FBQ1 0x01c00/1k 0x03400/1k 0x0c400/1k 0x30400/1k
* FBQ2 0x02000/1k 0x03800/1k 0x0c800/1k 0x30800/1k
* FBQ3 - - - -
* RT 0x02400/4.5k 0x03c00/4.5k 0x0cc00/4.5k 0x30c00/4.5k
* SCD 0x03600/597 0x04e00/1621 0x0de00/9358 0x31e00/43036
* TST 0x06000/2x2k 0x0c000/2x4k 0x37000/2x8k 0xef000/2x16k
* ABR ST 0x07000/2x1k 0x0e000/2x2k 0x3b000/2x8k 0xf7000/2x16k
* RxFIFO 0x07800/2k 0x0f000/4k 0x3f000/4k 0xff000/4k
* End 0x08000 0x10000 0x40000 0x100000
*/
struct idt_mmap {
u_int sram; /* K SRAM */
u_int max_conn; /* connections */
u_int vcbits; /* VPI + VCI bits */
u_int rxtab; /* CFG word for CNTBL field */
u_int rct; /* RCT base */
u_int rtables; /* rate table address */
u_int scd_base; /* SCD area base address */
u_int scd_num; /* number of SCDs */
u_int tst1base; /* base address of TST 1 */
u_int tst_size; /* TST size in words */
u_int abrstd_addr; /* schedule table address */
u_int abrstd_size; /* schedule table size */
u_int abrstd_code; /* schedule table size */
u_int rxfifo_addr; /* address */
u_int rxfifo_size; /* in words */
u_int rxfifo_code; /* size */
};
#define IDT_MMAP { \
{ /* 16k x 32, 512 connections */ \
16, 512, 9, IDT_CFG_CTS512, /* RAM, connections, VC bits */ \
0x01000, /* RCT base */ \
0x02400, /* rate table address */ \
0x03600, 597, /* SCD base and num */ \
0x06000, 2048, /* TST/words, base */ \
0x07000, 2048, 0x1, /* ABR schedule table */ \
0x07800, 2048, 0x2 /* RxFIFO size in words */ \
}, \
{ /* 32k x 32, 1024 connections */ \
32, 1024, 10, IDT_CFG_CTS1K, /* RAM, connections, VC bits */ \
0x02000, /* RCT base */ \
0x03c00, /* rate table address */ \
0x04e00, 1621, /* SCD base and num */ \
0x0c000, 4096, /* TST/words, base */ \
0x0e000, 4096, 0x2, /* ABR schedule table */ \
0x0f000, 4096, 0x3 /* RxFIFO size in words */ \
}, \
{ /* 128k x 32, 4096 connections */ \
128, 4096, 12, IDT_CFG_CTS4K, /* RAM, connections, VC bits */ \
0x08000, /* RCT base */ \
0x0cc00, /* rate table address */ \
0x0de00, 9358, /* SCD base and num */ \
0x37000, 8192, /* TST/words, base */ \
0x3b000, 16384, 0x4, /* ABR schedule table */ \
0x3f000, 4096, 0x3 /* RxFIFO size in words */ \
}, \
{ /* 512k x 32, 512 connections */ \
512, 16384, 14, IDT_CFG_CTS16K, /* RAM, connections, VC bits */\
0x20000, /* RCT base */ \
0x30c00, /* rate table address */ \
0x31e00, 43036, /* SCD base and num */ \
0xef000, 16384, /* TST/words, base */ \
0xf7000, 16384, 0x5, /* ABR schedule table */ \
0xff000, 4096, 0x3 /* RxFIFO size in words */ \
}, \
}

499
sys/dev/patm/if_patm.c Normal file
View File

@ -0,0 +1,499 @@
/*
* Copyright (c) 2003
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
* 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.
*
* Author: Hartmut Brandt <harti@freebsd.org>
*
* Driver for IDT77252 based cards like ProSum's.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_inet.h"
#include "opt_natm.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/errno.h>
#include <sys/conf.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
#include <sys/queue.h>
#include <sys/condvar.h>
#include <sys/endian.h>
#include <vm/uma.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_atm.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/if_atm.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <sys/mbpool.h>
#include <dev/utopia/utopia.h>
#include <dev/patm/idt77252reg.h>
#include <dev/patm/if_patmvar.h>
static void patm_tst_init(struct patm_softc *sc);
static void patm_scd_init(struct patm_softc *sc);
/*
* Start the card. This assumes the mutex to be held
*/
void
patm_initialize(struct patm_softc *sc)
{
uint32_t cfg;
u_int i;
patm_debug(sc, ATTACH, "configuring...");
/* clear SRAM */
for (i = 0; i < sc->mmap->sram * 1024; i += 4)
patm_sram_write4(sc, i, 0, 0, 0, 0);
patm_scd_init(sc);
/* configuration register. Setting NOIDLE makes the timing wrong! */
cfg = IDT_CFG_TXFIFO9 | IDT_CFG_RXQ512 | PATM_CFG_VPI |
/* IDT_CFG_NOIDLE | */ sc->mmap->rxtab;
if (!(sc->flags & PATM_UNASS))
cfg |= IDT_CFG_IDLECLP;
patm_nor_write(sc, IDT_NOR_CFG, cfg);
/* clean all the status queues and the Raw handle */
memset(sc->tsq, 0, sc->sq_size);
/* initialize RSQ */
patm_debug(sc, ATTACH, "RSQ %llx", (unsigned long long)sc->rsq_phy);
patm_nor_write(sc, IDT_NOR_RSQB, sc->rsq_phy);
patm_nor_write(sc, IDT_NOR_RSQT, sc->rsq_phy);
patm_nor_write(sc, IDT_NOR_RSQH, 0);
sc->rsq_last = PATM_RSQ_SIZE - 1;
/* initialize TSTB */
patm_nor_write(sc, IDT_NOR_TSTB, sc->mmap->tst1base << 2);
patm_tst_init(sc);
/* initialize TSQ */
for (i = 0; i < IDT_TSQ_SIZE; i++)
sc->tsq[i].stamp = htole32(IDT_TSQE_EMPTY);
patm_nor_write(sc, IDT_NOR_TSQB, sc->tsq_phy);
patm_nor_write(sc, IDT_NOR_TSQH, 0);
patm_nor_write(sc, IDT_NOR_TSQT, 0);
sc->tsq_next = sc->tsq;
/* GP */
#if BYTE_ORDER == BIG_ENDIAN && 0
patm_nor_write(sc, IDT_NOR_GP, IDT_GP_BIGE);
#else
patm_nor_write(sc, IDT_NOR_GP, 0);
#endif
/* VPM */
patm_nor_write(sc, IDT_NOR_VPM, 0);
/* RxFIFO */
patm_nor_write(sc, IDT_NOR_RXFD,
IDT_RXFD(sc->mmap->rxfifo_addr, sc->mmap->rxfifo_code));
patm_nor_write(sc, IDT_NOR_RXFT, 0);
patm_nor_write(sc, IDT_NOR_RXFH, 0);
/* RAWHND */
patm_debug(sc, ATTACH, "RWH %llx",
(unsigned long long)sc->rawhnd_phy);
patm_nor_write(sc, IDT_NOR_RAWHND, sc->rawhnd_phy);
/* ABRSTD */
patm_nor_write(sc, IDT_NOR_ABRSTD,
IDT_ABRSTD(sc->mmap->abrstd_addr, sc->mmap->abrstd_code));
for (i = 0; i < sc->mmap->abrstd_size; i++)
patm_sram_write(sc, sc->mmap->abrstd_addr + i, 0);
patm_nor_write(sc, IDT_NOR_ABRRQ, 0);
patm_nor_write(sc, IDT_NOR_VBRRQ, 0);
/* rate tables */
if (sc->flags & PATM_25M) {
for (i = 0; i < patm_rtables_size; i++)
patm_sram_write(sc, sc->mmap->rtables + i,
patm_rtables25[i]);
} else {
for (i = 0; i < patm_rtables_size; i++)
patm_sram_write(sc, sc->mmap->rtables + i,
patm_rtables155[i]);
}
patm_nor_write(sc, IDT_NOR_RTBL, sc->mmap->rtables << 2);
/* Maximum deficit */
patm_nor_write(sc, IDT_NOR_MXDFCT, 32 | IDT_MDFCT_LCI | IDT_MDFCT_LNI);
/* Free buffer queues */
patm_nor_write(sc, IDT_NOR_FBQP0, 0);
patm_nor_write(sc, IDT_NOR_FBQP1, 0);
patm_nor_write(sc, IDT_NOR_FBQP2, 0);
patm_nor_write(sc, IDT_NOR_FBQP3, 0);
patm_nor_write(sc, IDT_NOR_FBQWP0, 0);
patm_nor_write(sc, IDT_NOR_FBQWP1, 0);
patm_nor_write(sc, IDT_NOR_FBQWP2, 0);
patm_nor_write(sc, IDT_NOR_FBQWP3, 0);
patm_nor_write(sc, IDT_NOR_FBQS0,
(SMBUF_THRESHOLD << 28) |
(SMBUF_NI_THRESH << 24) |
(SMBUF_CI_THRESH << 20) |
SMBUF_CELLS);
patm_nor_write(sc, IDT_NOR_FBQS1,
(LMBUF_THRESHOLD << 28) |
(LMBUF_NI_THRESH << 24) |
(LMBUF_CI_THRESH << 20) |
LMBUF_CELLS);
patm_nor_write(sc, IDT_NOR_FBQS2,
(VMBUF_THRESHOLD << 28) | VMBUF_CELLS);
patm_nor_write(sc, IDT_NOR_FBQS3, 0);
/* make SCD0 for UBR0 */
if ((sc->scd0 = patm_scd_alloc(sc)) == NULL) {
patm_printf(sc, "cannot create UBR0 SCD\n");
patm_reset(sc);
return;
}
sc->scd0->q.ifq_maxlen = PATM_DLFT_MAXQ;
patm_scd_setup(sc, sc->scd0);
patm_tct_setup(sc, sc->scd0, NULL);
patm_debug(sc, ATTACH, "go...");
sc->utopia.flags &= ~UTP_FL_POLL_CARRIER;
sc->ifatm.ifnet.if_flags |= IFF_RUNNING;
/* enable interrupts, Tx and Rx paths */
cfg |= IDT_CFG_RXPTH | IDT_CFG_RXIIMM | IDT_CFG_RAWIE | IDT_CFG_RQFIE |
IDT_CFG_TIMOIE | IDT_CFG_FBIE | IDT_CFG_TXENB | IDT_CFG_TXINT |
IDT_CFG_TXUIE | IDT_CFG_TXSFI | IDT_CFG_PHYIE;
patm_nor_write(sc, IDT_NOR_CFG, cfg);
}
/*
* External callable start function
*/
void
patm_init(void *p)
{
struct patm_softc *sc = p;
mtx_lock(&sc->mtx);
patm_stop(sc);
patm_initialize(sc);
mtx_unlock(&sc->mtx);
}
/*
* Stop the interface
*/
void
patm_stop(struct patm_softc *sc)
{
u_int i;
struct mbuf *m;
struct patm_txmap *map;
struct patm_scd *scd;
sc->ifatm.ifnet.if_flags &= ~IFF_RUNNING;
sc->utopia.flags |= UTP_FL_POLL_CARRIER;
patm_reset(sc);
mtx_lock(&sc->tst_lock);
i = sc->tst_state;
sc->tst_state = 0;
callout_stop(&sc->tst_callout);
mtx_unlock(&sc->tst_lock);
if (i != 0) {
/* this means we are just entering or leaving the timeout.
* wait a little bit. Doing this correctly would be more
* involved */
DELAY(1000);
}
/*
* Give any waiters on closing a VCC a chance. They will stop
* to wait if they see that IFF_RUNNING disappeared.
*/
while (!(cv_waitq_empty(&sc->vcc_cv))) {
cv_broadcast(&sc->vcc_cv);
DELAY(100);
}
/* free large buffers */
patm_debug(sc, ATTACH, "freeing large buffers...");
for (i = 0; i < sc->lbuf_max; i++)
if (sc->lbufs[i].m != NULL)
patm_lbuf_free(sc, &sc->lbufs[i]);
/* free small buffers that are on the card */
patm_debug(sc, ATTACH, "freeing small buffers...");
mbp_card_free(sc->sbuf_pool);
/* free aal0 buffers that are on the card */
patm_debug(sc, ATTACH, "freeing aal0 buffers...");
mbp_card_free(sc->vbuf_pool);
/* freeing partial receive chains and reset vcc state */
for (i = 0; i < sc->mmap->max_conn; i++) {
if (sc->vccs[i] != NULL) {
if (sc->vccs[i]->chain != NULL)
m_freem(sc->vccs[i]->chain);
if (sc->vccs[i]->vcc.flags & ATMIO_FLAG_NG) {
uma_zfree(sc->vcc_zone, sc->vccs[i]);
sc->vccs[i] = NULL;
} else {
/* keep HARP and NG */
sc->vccs[i]->chain = NULL;
sc->vccs[i]->last = NULL;
sc->vccs[i]->vflags = 0;
}
}
}
/* stop all active SCDs */
while ((scd = LIST_FIRST(&sc->scd_list)) != NULL) {
/* free queue packets */
for (;;) {
_IF_DEQUEUE(&scd->q, m);
if (m == NULL)
break;
m_freem(m);
}
/* free transmitting packets */
for (i = 0; i < IDT_TSQE_TAG_SPACE; i++) {
if ((m = scd->on_card[i]) != NULL) {
scd->on_card[i] = 0;
map = m->m_pkthdr.header;
bus_dmamap_unload(sc->tx_tag, map->map);
SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link);
m_freem(m);
}
}
patm_scd_free(sc, scd);
}
sc->scd0 = NULL;
sc->flags &= ~PATM_CLR;
/* reset raw cell queue */
sc->rawh = NULL;
}
/*
* Stop the card and reset it
*/
void
patm_reset(struct patm_softc *sc)
{
patm_debug(sc, ATTACH, "resetting...");
patm_nor_write(sc, IDT_NOR_CFG, IDT_CFG_SWRST);
DELAY(200);
patm_nor_write(sc, IDT_NOR_CFG, 0);
DELAY(200);
patm_nor_write(sc, IDT_NOR_RSQH, 0);
patm_nor_write(sc, IDT_NOR_TSQH, 0);
patm_nor_write(sc, IDT_NOR_GP, IDT_GP_PHY_RST);
DELAY(50);
patm_nor_write(sc, IDT_NOR_GP, IDT_GP_EEDO | IDT_GP_EECS);
DELAY(50);
}
/*
* Initialize the soft TST to contain only ABR scheduling and
* write it to SRAM
*/
static void
patm_tst_init(struct patm_softc *sc)
{
u_int i;
u_int base, idle;
base = sc->mmap->tst1base;
idle = sc->mmap->tst1base + sc->mmap->tst_size;
/* soft */
for (i = 0; i < sc->mmap->tst_size - 1; i++)
sc->tst_soft[i] = IDT_TST_VBR;
sc->tst_state = 0;
sc->tst_jump[0] = base + sc->mmap->tst_size - 1;
sc->tst_jump[1] = idle + sc->mmap->tst_size - 1;
sc->tst_base[0] = base;
sc->tst_base[1] = idle;
/* TST1 */
for (i = 0; i < sc->mmap->tst_size - 1; i++)
patm_sram_write(sc, base + i, IDT_TST_VBR);
patm_sram_write(sc, sc->tst_jump[0], IDT_TST_BR | (base << 2));
/* TST2 */
for (i = 0; i < sc->mmap->tst_size - 1; i++)
patm_sram_write(sc, idle + i, IDT_TST_VBR);
patm_sram_write(sc, sc->tst_jump[1], IDT_TST_BR | (idle << 2));
sc->tst_free = sc->mmap->tst_size - 1;
sc->tst_reserve = sc->tst_free * PATM_TST_RESERVE / 100;
sc->bwrem = sc->ifatm.mib.pcr;
}
/*
* Initialize the SCDs. This is done by building a list of all free
* SCDs in SRAM. The first word of each potential SCD is used as a
* link to the next free SCD. The list is rooted in softc.
*/
static void
patm_scd_init(struct patm_softc *sc)
{
u_int s; /* SRAM address of current SCD */
sc->scd_free = 0;
for (s = sc->mmap->scd_base; s + 12 <= sc->mmap->tst1base; s += 12) {
patm_sram_write(sc, s, sc->scd_free);
sc->scd_free = s;
}
}
/*
* allocate an SCQ
*/
struct patm_scd *
patm_scd_alloc(struct patm_softc *sc)
{
u_int sram, next; /* SRAM address of this and next SCD */
int error;
void *p;
struct patm_scd *scd;
bus_dmamap_t map;
bus_addr_t phy;
/* get an SCD from the free list */
if ((sram = sc->scd_free) == 0)
return (NULL);
next = patm_sram_read(sc, sram);
/* allocate memory for the queue and our host stuff */
error = bus_dmamem_alloc(sc->scd_tag, &p, BUS_DMA_NOWAIT, &map);
if (error != 0)
return (NULL);
phy = 0x3ff;
error = bus_dmamap_load(sc->scd_tag, map, p, sizeof(scd->scq),
patm_load_callback, &phy, BUS_DMA_NOWAIT);
if (error != 0) {
bus_dmamem_free(sc->scd_tag, p, map);
return (NULL);
}
KASSERT((phy & 0x1ff) == 0, ("SCD not aligned %lx", (u_long)phy));
scd = p;
bzero(scd, sizeof(*scd));
scd->sram = sram;
scd->phy = phy;
scd->map = map;
scd->space = IDT_SCQ_SIZE;
scd->last_tag = IDT_TSQE_TAG_SPACE - 1;
scd->q.ifq_maxlen = PATM_TX_IFQLEN;
/* remove the scd from the free list */
sc->scd_free = next;
LIST_INSERT_HEAD(&sc->scd_list, scd, link);
return (scd);
}
/*
* Free an SCD
*/
void
patm_scd_free(struct patm_softc *sc, struct patm_scd *scd)
{
LIST_REMOVE(scd, link);
/* clear SCD and insert link word */
patm_sram_write4(sc, scd->sram, sc->scd_free, 0, 0, 0);
patm_sram_write4(sc, scd->sram, 0, 0, 0, 0);
patm_sram_write4(sc, scd->sram, 0, 0, 0, 0);
/* put on free list */
sc->scd_free = scd->sram;
/* free memory */
bus_dmamap_unload(sc->scd_tag, scd->map);
bus_dmamem_free(sc->scd_tag, scd, scd->map);
}
/*
* DMA loading helper function. This function handles the loading of
* all one segment DMA maps. The argument is a pointer to a bus_addr_t
* which must contain the desired alignment of the address as a bitmap.
*/
void
patm_load_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
{
bus_addr_t *phy = arg;
if (error)
return;
KASSERT(nsegs == 1,
("too many segments for DMA: %d", nsegs));
KASSERT(segs[0].ds_addr <= 0xffffffffUL,
("phys addr too large %lx", (u_long)segs[0].ds_addr));
KASSERT((segs[0].ds_addr & *phy) == 0,
("bad alignment %lx:%lx", (u_long)segs[0].ds_addr, (u_long)*phy));
*phy = segs[0].ds_addr;
}

File diff suppressed because it is too large Load Diff

552
sys/dev/patm/if_patm_intr.c Normal file
View File

@ -0,0 +1,552 @@
/*
* Copyright (c) 2003
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
* 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.
*
* Author: Hartmut Brandt <harti@freebsd.org>
*
* Driver for IDT77252 based cards like ProSum's.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_inet.h"
#include "opt_natm.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/errno.h>
#include <sys/conf.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
#include <sys/queue.h>
#include <sys/condvar.h>
#include <sys/endian.h>
#include <vm/uma.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_atm.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/if_atm.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <sys/mbpool.h>
#include <dev/utopia/utopia.h>
#include <dev/patm/idt77252reg.h>
#include <dev/patm/if_patmvar.h>
static void patm_feed_sbufs(struct patm_softc *sc);
static void patm_feed_lbufs(struct patm_softc *sc);
static void patm_feed_vbufs(struct patm_softc *sc);
static void patm_intr_tsif(struct patm_softc *sc);
static void patm_intr_raw(struct patm_softc *sc);
#ifdef PATM_DEBUG
static int patm_mbuf_cnt(u_int unit) __unused;
#endif
/*
* Write free buf Q
*/
static __inline void
patm_fbq_write(struct patm_softc *sc, u_int queue, uint32_t h0,
uint32_t p0, uint32_t h1, uint32_t p1)
{
patm_debug(sc, FREEQ, "supplying(%u,%#x,%#x,%#x,%#x)",
queue, h0, p0, h1, p1);
patm_nor_write(sc, IDT_NOR_D0, h0);
patm_nor_write(sc, IDT_NOR_D1, p0);
patm_nor_write(sc, IDT_NOR_D2, h1);
patm_nor_write(sc, IDT_NOR_D3, p1);
patm_cmd_exec(sc, IDT_CMD_WFBQ | queue);
}
/*
* Interrupt
*/
void
patm_intr(void *p)
{
struct patm_softc *sc = p;
uint32_t stat, cfg;
u_int cnt;
const uint32_t ints = IDT_STAT_TSIF | IDT_STAT_TXICP | IDT_STAT_TSQF |
IDT_STAT_TMROF | IDT_STAT_PHYI | IDT_STAT_RSQF | IDT_STAT_EPDU |
IDT_STAT_RAWCF | IDT_STAT_RSQAF;
const uint32_t fbqa = IDT_STAT_FBQ3A | IDT_STAT_FBQ2A |
IDT_STAT_FBQ1A | IDT_STAT_FBQ0A;
mtx_lock(&sc->mtx);
stat = patm_nor_read(sc, IDT_NOR_STAT);
patm_nor_write(sc, IDT_NOR_STAT, stat & (ints | fbqa));
if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) {
/* if we are stopped ack all interrupts and handle PHYI */
if (stat & IDT_STAT_PHYI) {
patm_debug(sc, INTR, "PHYI (stopped)");
utopia_intr(&sc->utopia);
}
mtx_unlock(&sc->mtx);
return;
}
patm_debug(sc, INTR, "stat=%08x", stat);
/*
* If the buffer queues are empty try to fill them. If this fails
* disable the interrupt. Otherwise enable the interrupt.
*/
if (stat & fbqa) {
cfg = patm_nor_read(sc, IDT_NOR_CFG);
if (stat & IDT_STAT_FBQ0A)
patm_feed_sbufs(sc);
if (stat & IDT_STAT_FBQ1A)
patm_feed_lbufs(sc);
if (stat & IDT_STAT_FBQ2A) {
/*
* Workaround for missing interrupt on AAL0. Check the
* receive status queue if the FBQ2 is not full.
*/
patm_intr_rsq(sc);
patm_feed_vbufs(sc);
}
if ((patm_nor_read(sc, IDT_NOR_STAT) & fbqa) &&
(cfg & IDT_CFG_FBIE)) {
/* failed */
patm_nor_write(sc, IDT_NOR_CFG, cfg & ~IDT_CFG_FBIE);
patm_printf(sc, "out of buffers -- intr disabled\n");
} else if (!(cfg & IDT_CFG_FBIE)) {
patm_printf(sc, "bufQ intr re-enabled\n");
patm_nor_write(sc, IDT_NOR_CFG, cfg | IDT_CFG_FBIE);
}
patm_nor_write(sc, IDT_NOR_STAT, fbqa);
}
cnt = 0;
while ((stat & ints) != 0) {
if (++cnt == 200) {
patm_printf(sc, "%s: excessive interrupts\n", __func__);
patm_stop(sc);
break;
}
if (stat & IDT_STAT_TSIF) {
patm_debug(sc, INTR, "TSIF");
patm_intr_tsif(sc);
}
if (stat & IDT_STAT_TXICP) {
patm_printf(sc, "incomplete PDU transmitted\n");
}
if (stat & IDT_STAT_TSQF) {
patm_printf(sc, "TSQF\n");
patm_intr_tsif(sc);
}
if (stat & IDT_STAT_TMROF) {
patm_debug(sc, INTR, "TMROF");
patm_intr_tsif(sc);
}
if (stat & IDT_STAT_PHYI) {
patm_debug(sc, INTR, "PHYI");
utopia_intr(&sc->utopia);
}
if (stat & IDT_STAT_RSQF) {
patm_printf(sc, "RSQF\n");
patm_intr_rsq(sc);
}
if (stat & IDT_STAT_EPDU) {
patm_debug(sc, INTR, "EPDU");
patm_intr_rsq(sc);
}
if (stat & IDT_STAT_RAWCF) {
patm_debug(sc, INTR, "RAWCF");
patm_intr_raw(sc);
}
if (stat & IDT_STAT_RSQAF) {
patm_debug(sc, INTR, "RSQAF");
patm_intr_rsq(sc);
} else if (IDT_STAT_FRAC2(stat) != 0xf) {
/*
* Workaround for missing interrupt on AAL0. Check the
* receive status queue if the FBQ2 is not full.
*/
patm_intr_rsq(sc);
}
stat = patm_nor_read(sc, IDT_NOR_STAT);
patm_nor_write(sc, IDT_NOR_STAT, ints & stat);
patm_debug(sc, INTR, "stat=%08x", stat);
}
mtx_unlock(&sc->mtx);
patm_debug(sc, INTR, "... exit");
}
/*
* Compute the amount of buffers to feed into a given free buffer queue
*
* Feeding buffers is actually not so easy as it seems. We cannot use the
* fraction fields in the status registers, because they round down, i.e.
* if we have 34 buffers in the queue, it will show 1. If we now feed
* 512 - 1 * 32 buffers, we loose two buffers. The only reliable way to know
* how many buffers are in the queue are the FBQP registers.
*/
static u_int
patm_feed_cnt(struct patm_softc *sc, u_int q)
{
u_int w, r, reg;
u_int feed;
int free;
/* get the FBQ read and write pointers */
reg = patm_nor_read(sc, IDT_NOR_FBQP0 + 4 * q);
r = (reg & 0x7ff) >> 1;
w = ((reg >> 16) & 0x7ff) >> 1;
/* compute amount of free buffers */
if ((free = w - r) < 0)
free += 0x400;
KASSERT(free <= 512, ("bad FBQP 0x%x", reg));
feed = 512 - free;
/* can only feed pairs of buffers */
feed &= ~1;
if (feed > 0)
feed -= 2;
patm_debug(sc, FREEQ, "feeding %u buffers into queue %u", feed, q);
return (feed);
}
/*
* Feed small buffers into buffer queue 0
*
*/
static void
patm_feed_sbufs(struct patm_softc *sc)
{
u_int feed;
bus_addr_t p0, p1;
void *v0, *v1;
uint32_t h0, h1;
feed = patm_feed_cnt(sc, 0);
while (feed > 0) {
if ((v0 = mbp_alloc(sc->sbuf_pool, &p0, &h0)) == NULL)
break;
if ((v1 = mbp_alloc(sc->sbuf_pool, &p1, &h1)) == NULL) {
mbp_free(sc->sbuf_pool, v0);
break;
}
patm_fbq_write(sc, 0,
h0 | MBUF_SHANDLE, (p0 + SMBUF_OFFSET),
h1 | MBUF_SHANDLE, (p1 + SMBUF_OFFSET));
feed -= 2;
}
}
/*
* Feed small buffers into buffer queue 0
*/
static void
patm_feed_vbufs(struct patm_softc *sc)
{
u_int feed;
bus_addr_t p0, p1;
void *v0, *v1;
uint32_t h0, h1;
feed = patm_feed_cnt(sc, 2);
while (feed > 0) {
if ((v0 = mbp_alloc(sc->vbuf_pool, &p0, &h0)) == NULL)
break;
if ((v1 = mbp_alloc(sc->vbuf_pool, &p1, &h1)) == NULL) {
mbp_free(sc->vbuf_pool, v0);
break;
}
patm_fbq_write(sc, 2,
h0 | MBUF_VHANDLE, (p0 + VMBUF_OFFSET),
h1 | MBUF_VHANDLE, (p1 + VMBUF_OFFSET));
feed -= 2;
}
}
/*
* Allocate a large buffer
*/
static struct lmbuf *
patm_lmbuf_alloc(struct patm_softc *sc)
{
int error;
struct mbuf *m;
struct lmbuf *b;
m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
if (m == NULL)
return (NULL);
m->m_data += LMBUF_OFFSET;
if ((b = SLIST_FIRST(&sc->lbuf_free_list)) == NULL) {
m_freem(m);
return (NULL);
}
b->phy = 0; /* alignment */
error = bus_dmamap_load(sc->lbuf_tag, b->map, m->m_data, LMBUF_SIZE,
patm_load_callback, &b->phy, BUS_DMA_NOWAIT);
if (error) {
patm_printf(sc, "%s -- bus_dmamap_load: %d\n", __func__, error);
m_free(m);
return (NULL);
}
SLIST_REMOVE_HEAD(&sc->lbuf_free_list, link);
b->m = m;
return (b);
}
/*
* Feed large buffers into buffer queue 1
*/
static void
patm_feed_lbufs(struct patm_softc *sc)
{
u_int feed;
struct lmbuf *b0, *b1;
feed = patm_feed_cnt(sc, 1);
while (feed > 0) {
if ((b0 = patm_lmbuf_alloc(sc)) == NULL)
break;
if ((b1 = patm_lmbuf_alloc(sc)) == NULL) {
patm_lbuf_free(sc, b0);
break;
}
patm_fbq_write(sc, 1,
LMBUF_HANDLE | b0->handle, b0->phy,
LMBUF_HANDLE | b1->handle, b1->phy);
feed -= 2;
}
}
/*
* Handle transmit status interrupt
*/
static void
patm_intr_tsif(struct patm_softc *sc)
{
struct idt_tsqe *tsqe = sc->tsq_next;;
struct idt_tsqe *prev = NULL;
uint32_t stamp;
stamp = le32toh(tsqe->stamp);
if (stamp & IDT_TSQE_EMPTY)
return;
do {
switch (IDT_TSQE_TYPE(stamp)) {
case IDT_TSQE_TBD:
patm_tx(sc, stamp, le32toh(tsqe->stat));
break;
case IDT_TSQE_IDLE:
patm_tx_idle(sc, le32toh(tsqe->stat));
break;
}
/* recycle */
tsqe->stat = 0;
tsqe->stamp = htole32(IDT_TSQE_EMPTY);
/* save pointer to this entry and advance */
prev = tsqe;
if (++tsqe == &sc->tsq[IDT_TSQ_SIZE])
tsqe = &sc->tsq[0];
stamp = le32toh(tsqe->stamp);
} while (!(stamp & IDT_TSQE_EMPTY));
sc->tsq_next = tsqe;
patm_nor_write(sc, IDT_NOR_TSQH, ((prev - sc->tsq) << IDT_TSQE_SHIFT));
}
/*
* Handle receive interrupt
*/
void
patm_intr_rsq(struct patm_softc *sc)
{
struct idt_rsqe *rsqe;
u_int stat;
if (sc->rsq_last + 1 == PATM_RSQ_SIZE)
rsqe = &sc->rsq[0];
else
rsqe = &sc->rsq[sc->rsq_last + 1];
stat = le32toh(rsqe->stat);
if (!(stat & IDT_RSQE_VALID))
return;
while (stat & IDT_RSQE_VALID) {
patm_rx(sc, rsqe);
/* recycle RSQE */
rsqe->cid = 0;
rsqe->handle = 0;
rsqe->crc = 0;
rsqe->stat = 0;
/* save pointer to this entry and advance */
if (++sc->rsq_last == PATM_RSQ_SIZE)
sc->rsq_last = 0;
if (++rsqe == &sc->rsq[PATM_RSQ_SIZE])
rsqe = sc->rsq;
stat = le32toh(rsqe->stat);
}
patm_nor_write(sc, IDT_NOR_RSQH, sc->rsq_phy | (sc->rsq_last << 2));
patm_feed_sbufs(sc);
patm_feed_lbufs(sc);
patm_feed_vbufs(sc);
}
/*
* Handle raw cell receive.
*
* Note that the description on page 3-8 is wrong. The RAWHND contains not
* the same value as RAWCT. RAWCT points to the next address the chip is
* going to write to whike RAWHND points to the last cell's address the chip
* has written to.
*/
static void
patm_intr_raw(struct patm_softc *sc)
{
uint32_t tail;
uint32_t h, *cell;
#ifdef notyet
bus_dma_sync_size(sc->sq_tag, sc->sq_map, IDT_TSQ_SIZE * IDT_TSQE_SIZE +
PATM_RSQ_SIZE * IDT_RSQE_SIZE, sizeof(*sc->rawhnd),
BUS_DMASYNC_POSTREAD);
#endif
/* first turn */
if (sc->rawh == NULL) {
sc->rawh = &sc->lbufs[le32toh(sc->rawhnd->handle) & MBUF_HMASK];
}
tail = le32toh(sc->rawhnd->tail);
if (tail == sc->rawh->phy)
/* not really a raw interrupt */
return;
while (tail + 64 != sc->rawh->phy + sc->rawi * 64) {
#ifdef notyet
bus_dmamap_sync_size(sc->lbuf_tag, sc->rawh->map,
sc->rawi * 64, 64, BUS_DMASYNC_POSTREAD);
#endif
cell = (uint32_t *)(mtod(sc->rawh->m, u_char *) +
sc->rawi * 64);
if (sc->rawi == (LMBUF_SIZE / 64) - 1) {
/* chain */
h = le32toh(cell[1]);
patm_lbuf_free(sc, sc->rawh);
sc->rawh = &sc->lbufs[h & MBUF_HMASK];
sc->rawi = 0;
continue;
}
patm_rx_raw(sc, (u_char *)cell);
sc->rawi++;
}
}
/*
* Free a large mbuf. This is called by us.
*/
void
patm_lbuf_free(struct patm_softc *sc, struct lmbuf *b)
{
bus_dmamap_unload(sc->lbuf_tag, b->map);
if (b->m != NULL) {
m_free(b->m);
b->m = NULL;
}
SLIST_INSERT_HEAD(&sc->lbuf_free_list, b, link);
}
#ifdef PATM_DEBUG
static int
patm_mbuf_cnt(u_int unit)
{
devclass_t dc;
struct patm_softc *sc;
u_int used, card, free;
dc = devclass_find("patm");
if (dc == NULL) {
printf("%s: can't find devclass\n", __func__);
return (0);
}
sc = devclass_get_softc(dc, unit);
if (sc == NULL) {
printf("%s: invalid unit number: %d\n", __func__, unit);
return (0);
}
mbp_count(sc->sbuf_pool, &used, &card, &free);
printf("sbufs: %u on card, %u used, %u free\n", card, used, free);
mbp_count(sc->vbuf_pool, &used, &card, &free);
printf("aal0 bufs: %u on card, %u used, %u free\n", card, used, free);
return (0);
}
#endif

View File

@ -0,0 +1,450 @@
/*
* Copyright (c) 2003
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
* 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.
*
* Author: Hartmut Brandt <harti@freebsd.org>
*
* Driver for IDT77252 based cards like ProSum's.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_inet.h"
#include "opt_natm.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/errno.h>
#include <sys/conf.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
#include <sys/queue.h>
#include <sys/condvar.h>
#include <vm/uma.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_atm.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/if_atm.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <sys/mbpool.h>
#include <dev/utopia/utopia.h>
#include <dev/patm/idt77252reg.h>
#include <dev/patm/if_patmvar.h>
/*
* Open the VCC with the given parameters
*/
static int
patm_open_vcc(struct patm_softc *sc, struct atmio_openvcc *arg, u_int async)
{
u_int cid;
struct patm_vcc *vcc;
int error = 0;
patm_debug(sc, VCC, "Open VCC: %u.%u flags=%#x", arg->param.vpi,
arg->param.vci, arg->param.flags);
if (!LEGAL_VPI(sc, arg->param.vpi) || !LEGAL_VCI(sc, arg->param.vci))
return (EINVAL);
if (arg->param.vci == 0 && (arg->param.vpi != 0 ||
!(arg->param.flags & ATMIO_FLAG_NOTX) ||
arg->param.aal != ATMIO_AAL_RAW))
return (EINVAL);
cid = PATM_CID(sc, arg->param.vpi, arg->param.vci);
if ((arg->param.flags & ATMIO_FLAG_NOTX) &&
(arg->param.flags & ATMIO_FLAG_NORX))
return (EINVAL);
if ((arg->param.traffic == ATMIO_TRAFFIC_ABR) &&
(arg->param.flags & (ATMIO_FLAG_NOTX | ATMIO_FLAG_NORX)))
return (EINVAL);
/* allocate vcc */
vcc = uma_zalloc(sc->vcc_zone, M_NOWAIT | M_ZERO);
if (vcc == NULL)
return (ENOMEM);
mtx_lock(&sc->mtx);
if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) {
/* stopped while we have analyzed the arguments */
error = EIO;
goto done;
}
if (sc->vccs[cid] != NULL) {
/* ups, already open */
error = EBUSY;
goto done;
}
/* check some parameters */
vcc->cid = cid;
vcc->vcc = arg->param;
vcc->vflags = async;
vcc->rxhand = arg->rxhand;
switch (vcc->vcc.aal) {
case ATMIO_AAL_0:
case ATMIO_AAL_34:
case ATMIO_AAL_5:
break;
case ATMIO_AAL_RAW:
if (arg->param.vci == 0 &&
!(arg->param.flags & ATMIO_FLAG_NOTX)) {
error = EINVAL;
goto done;
}
break;
default:
error = EINVAL;
goto done;
}
switch (vcc->vcc.traffic) {
case ATMIO_TRAFFIC_VBR:
case ATMIO_TRAFFIC_UBR:
case ATMIO_TRAFFIC_CBR:
case ATMIO_TRAFFIC_ABR:
break;
default:
error = EINVAL;
goto done;
}
/* initialize */
vcc->chain = NULL;
vcc->last = NULL;
vcc->ibytes = vcc->ipackets = 0;
vcc->obytes = vcc->opackets = 0;
/* ask the TX and RX sides */
patm_debug(sc, VCC, "Open VCC: asking Rx/Tx");
if (!(vcc->vcc.flags & ATMIO_FLAG_NOTX) &&
(error = patm_tx_vcc_can_open(sc, vcc)) != 0)
goto done;
if (!(vcc->vcc.flags & ATMIO_FLAG_NORX) &&
(error = patm_rx_vcc_can_open(sc, vcc)) != 0)
goto done;
/* ok - go ahead */
sc->vccs[cid] = vcc;
patm_debug(sc, VCC, "Open VCC: opening");
if (!(vcc->vcc.flags & ATMIO_FLAG_NOTX))
patm_tx_vcc_open(sc, vcc);
if (!(vcc->vcc.flags & ATMIO_FLAG_NORX))
patm_rx_vcc_open(sc, vcc);
#ifdef notyet
/* inform management about non-NG and NG-PVCs */
if (!(vcc->vcc.flags & ATMIO_FLAG_NG) ||
(vcc->vcc.flags & ATMIO_FLAG_PVC))
atm_message(&sc->ifatm.ifnet, ATM_MSG_VCC_CHANGED,
(1 << 24) | (vcc->vcc.vpi << 16) | vcc->vcc.vci);
#endif
patm_debug(sc, VCC, "Open VCC: now open");
/* don't free below */
vcc = NULL;
sc->vccs_open++;
/* done */
done:
mtx_unlock(&sc->mtx);
if (vcc != NULL)
uma_zfree(sc->vcc_zone, vcc);
return (error);
}
/*
* Enable ioctl for NATM. Map to an open ioctl.
*/
static int
patm_open_vcc1(struct patm_softc *sc, struct atm_pseudoioctl *ph)
{
struct atmio_openvcc v;
bzero(&v, sizeof(v));
v.param.flags = ATM_PH_FLAGS(&ph->aph) & (ATM_PH_AAL5 | ATM_PH_LLCSNAP);
v.param.vpi = ATM_PH_VPI(&ph->aph);
v.param.vci = ATM_PH_VCI(&ph->aph);
v.param.aal = (ATM_PH_FLAGS(&ph->aph) & ATM_PH_AAL5)
? ATMIO_AAL_5 : ATMIO_AAL_0;
v.param.traffic = ATMIO_TRAFFIC_UBR;;
v.param.tparam.pcr = sc->ifatm.mib.pcr;
v.rxhand = ph->rxhand;
return (patm_open_vcc(sc, &v, PATM_VCC_ASYNC));
}
/*
* Try to close the given VCC
*/
static int
patm_close_vcc(struct patm_softc *sc, struct atmio_closevcc *arg)
{
u_int cid;
struct patm_vcc *vcc;
int error = 0;
patm_debug(sc, VCC, "Close VCC: %u.%u", arg->vpi, arg->vci);
if (!LEGAL_VPI(sc, arg->vpi) || !LEGAL_VCI(sc, arg->vci))
return (EINVAL);
cid = PATM_CID(sc, arg->vpi, arg->vci);
mtx_lock(&sc->mtx);
if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) {
/* stopped while we have analyzed the arguments */
error = EIO;
goto done;
}
vcc = sc->vccs[cid];
if (vcc == NULL || !(vcc->vflags & PATM_VCC_OPEN)) {
error = ENOENT;
goto done;
}
if (vcc->vflags & PATM_VCC_TX_OPEN)
patm_tx_vcc_close(sc, vcc);
if (vcc->vflags & PATM_VCC_RX_OPEN)
patm_rx_vcc_close(sc, vcc);
if (vcc->vflags & PATM_VCC_ASYNC)
goto done;
while (vcc->vflags & (PATM_VCC_TX_CLOSING | PATM_VCC_RX_CLOSING)) {
cv_wait(&sc->vcc_cv, &sc->mtx);
if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) {
/* ups, has been stopped */
error = EIO;
goto done;
}
}
if (!(vcc->vcc.flags & ATMIO_FLAG_NOTX))
patm_tx_vcc_closed(sc, vcc);
if (!(vcc->vcc.flags & ATMIO_FLAG_NORX))
patm_rx_vcc_closed(sc, vcc);
patm_vcc_closed(sc, vcc);
done:
mtx_unlock(&sc->mtx);
return (error);
}
/*
* Close a VCC asynchronuosly
*/
static int
patm_close_vcc1(struct patm_softc *sc, struct atm_pseudoioctl *ph)
{
struct atmio_closevcc v;
v.vpi = ATM_PH_VPI(&ph->aph);
v.vci = ATM_PH_VCI(&ph->aph);
return (patm_close_vcc(sc, &v));
}
/*
* VCC has been finally closed.
*/
void
patm_vcc_closed(struct patm_softc *sc, struct patm_vcc *vcc)
{
#ifdef notyet
/* inform management about non-NG and NG-PVCs */
if (!(vcc->vcc.flags & ATMIO_FLAG_NG) ||
(vcc->vcc.flags & ATMIO_FLAG_PVC))
atm_message(&sc->ifatm.ifnet, ATM_MSG_VCC_CHANGED,
(0 << 24) | (vcc->vcc.vpi << 16) | vcc->vcc.vci);
#endif
sc->vccs_open--;
sc->vccs[vcc->cid] = NULL;
uma_zfree(sc->vcc_zone, vcc);
}
int
patm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct ifreq *ifr = (struct ifreq *)data;
struct ifaddr *ifa = (struct ifaddr *)data;
struct patm_softc *sc = ifp->if_softc;
int error = 0;
uint32_t cfg;
struct atmio_vcctable *vtab;
switch (cmd) {
case SIOCSIFADDR:
mtx_lock(&sc->mtx);
ifp->if_flags |= IFF_UP;
if (!(ifp->if_flags & IFF_RUNNING))
patm_initialize(sc);
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
case AF_INET6:
ifa->ifa_rtrequest = atm_rtrequest;
break;
#endif
default:
break;
}
mtx_unlock(&sc->mtx);
break;
case SIOCSIFFLAGS:
mtx_lock(&sc->mtx);
if (ifp->if_flags & IFF_UP) {
if (!(ifp->if_flags & IFF_RUNNING)) {
patm_initialize(sc);
}
} else {
if (ifp->if_flags & IFF_RUNNING) {
patm_stop(sc);
}
}
mtx_unlock(&sc->mtx);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd);
/*
* We need to toggle unassigned/idle cells ourself because
* the 77252 generates null cells for spacing. When switching
* null cells of it gets the timing wrong.
*/
mtx_lock(&sc->mtx);
if (ifp->if_flags & IFF_RUNNING) {
if (sc->utopia.state & UTP_ST_UNASS) {
if (!(sc->flags & PATM_UNASS)) {
cfg = patm_nor_read(sc, IDT_NOR_CFG);
cfg &= ~IDT_CFG_IDLECLP;
patm_nor_write(sc, IDT_NOR_CFG, cfg);
sc->flags |= PATM_UNASS;
}
} else {
if (sc->flags & PATM_UNASS) {
cfg = patm_nor_read(sc, IDT_NOR_CFG);
cfg |= IDT_CFG_IDLECLP;
patm_nor_write(sc, IDT_NOR_CFG, cfg);
sc->flags &= ~PATM_UNASS;
}
}
} else {
if (sc->utopia.state & UTP_ST_UNASS)
sc->flags |= PATM_UNASS;
else
sc->flags &= ~PATM_UNASS;
}
mtx_unlock(&sc->mtx);
break;
case SIOCSIFMTU:
/*
* Set the interface MTU.
*/
if (ifr->ifr_mtu > ATMMTU)
error = EINVAL;
else
ifp->if_mtu = ifr->ifr_mtu;
break;
case SIOCATMOPENVCC: /* netgraph/harp internal use */
error = patm_open_vcc(sc, (struct atmio_openvcc *)data, 0);
break;
case SIOCATMCLOSEVCC: /* netgraph and HARP internal use */
error = patm_close_vcc(sc, (struct atmio_closevcc *)data);
break;
case SIOCATMENA: /* NATM internal use */
error = patm_open_vcc1(sc, (struct atm_pseudoioctl *)data);
break;
case SIOCATMDIS: /* NATM internal use */
error = patm_close_vcc1(sc, (struct atm_pseudoioctl *)data);
break;
case SIOCATMGVCCS: /* external use */
/* return vcc table */
vtab = atm_getvccs((struct atmio_vcc **)sc->vccs,
sc->mmap->max_conn, sc->vccs_open, &sc->mtx, 1);
error = copyout(vtab, ifr->ifr_data, sizeof(*vtab) +
vtab->count * sizeof(vtab->vccs[0]));
free(vtab, M_DEVBUF);
break;
case SIOCATMGETVCCS: /* netgraph internal use */
vtab = atm_getvccs((struct atmio_vcc **)sc->vccs,
sc->mmap->max_conn, sc->vccs_open, &sc->mtx, 0);
if (vtab == NULL) {
error = ENOMEM;
break;
}
*(void **)data = vtab;
break;
default:
patm_debug(sc, IOCTL, "unknown cmd=%08lx arg=%p", cmd, data);
error = EINVAL;
break;
}
return (error);
}

File diff suppressed because it is too large Load Diff

529
sys/dev/patm/if_patm_rx.c Normal file
View File

@ -0,0 +1,529 @@
/*
* Copyright (c) 2003
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
* 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.
*
* Author: Hartmut Brandt <harti@freebsd.org>
*
* Driver for IDT77252 based cards like ProSum's.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_inet.h"
#include "opt_natm.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/errno.h>
#include <sys/conf.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
#include <sys/queue.h>
#include <sys/condvar.h>
#include <sys/endian.h>
#include <vm/uma.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_atm.h>
#include <net/route.h>
#ifdef ENABLE_BPF
#include <net/bpf.h>
#endif
#include <netinet/in.h>
#include <netinet/if_atm.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <sys/mbpool.h>
#include <dev/utopia/utopia.h>
#include <dev/patm/idt77252reg.h>
#include <dev/patm/if_patmvar.h>
static void *patm_rcv_handle(struct patm_softc *sc, u_int handle);
static void patm_rcv_free(struct patm_softc *, void *, u_int handle);
static struct mbuf *patm_rcv_mbuf(struct patm_softc *, void *, u_int, int);
static __inline void
rct_write(struct patm_softc *sc, u_int cid, u_int w, u_int val)
{
patm_sram_write(sc, sc->mmap->rct + cid * IDT_RCT_ENTRY_SIZE + w, val);
}
static __inline void
rct_init(struct patm_softc *sc, u_int cid, u_int w1)
{
patm_sram_write4(sc, sc->mmap->rct + cid * IDT_RCT_ENTRY_SIZE,
w1, 0, 0, 0xffffffff);
}
static __inline u_int
rct_read(struct patm_softc *sc, u_int cid, u_int w)
{
return (patm_sram_read(sc, sc->mmap->rct +
cid * IDT_RCT_ENTRY_SIZE + w));
}
/* check if we can open this one */
int
patm_rx_vcc_can_open(struct patm_softc *sc, struct patm_vcc *vcc)
{
return (0);
}
/*
* open the VCC
*/
void
patm_rx_vcc_open(struct patm_softc *sc, struct patm_vcc *vcc)
{
uint32_t w1 = IDT_RCT_OPEN;
patm_debug(sc, VCC, "%u.%u RX opening", vcc->vcc.vpi, vcc->vcc.vci);
switch (vcc->vcc.aal) {
case ATMIO_AAL_0:
w1 |= IDT_RCT_AAL0 | IDT_RCT_FBP2 | IDT_RCT_RCI;
break;
case ATMIO_AAL_34:
w1 |= IDT_RCT_AAL34;
break;
case ATMIO_AAL_5:
w1 |= IDT_RCT_AAL5;
break;
case ATMIO_AAL_RAW:
w1 |= IDT_RCT_AALRAW | IDT_RCT_RCI;
break;
}
if (vcc->cid != 0)
rct_init(sc, vcc->cid, w1);
else {
/* switch the interface into promiscuous mode */
patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) |
IDT_CFG_ICAPT | IDT_CFG_VPECA);
}
vcc->vflags |= PATM_VCC_RX_OPEN;
}
/* close the given vcc for transmission */
void
patm_rx_vcc_close(struct patm_softc *sc, struct patm_vcc *vcc)
{
u_int w1;
patm_debug(sc, VCC, "%u.%u RX closing", vcc->vcc.vpi, vcc->vcc.vci);
if (vcc->cid == 0) {
/* switch off promiscuous mode */
patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) &
~(IDT_CFG_ICAPT | IDT_CFG_VPECA));
vcc->vflags &= ~PATM_VCC_RX_OPEN;
return;
}
/* close the connection but keep state */
w1 = rct_read(sc, vcc->cid, 0);
w1 &= ~IDT_RCT_OPEN;
rct_write(sc, vcc->cid, 0, w1);
/* minimum idle count */
w1 = (w1 & ~IDT_RCT_IACT_CNT_MASK) | (1 << IDT_RCT_IACT_CNT_SHIFT);
rct_write(sc, vcc->cid, 0, w1);
/* initialize scan */
patm_nor_write(sc, IDT_NOR_IRCP, vcc->cid);
vcc->vflags &= ~PATM_VCC_RX_OPEN;
vcc->vflags |= PATM_VCC_RX_CLOSING;
/*
* check the RSQ
* This is a hack. The problem is, that although an entry is written
* to the RSQ, no interrupt is generated. Also we must wait 1 cell
* time for the SAR to process the scan of our connection.
*/
DELAY(1);
patm_intr_rsq(sc);
}
/* transmission side finally closed */
void
patm_rx_vcc_closed(struct patm_softc *sc, struct patm_vcc *vcc)
{
patm_debug(sc, VCC, "%u.%u RX finally closed",
vcc->vcc.vpi, vcc->vcc.vci);
}
/*
* Handle the given receive status queue entry
*/
void
patm_rx(struct patm_softc *sc, struct idt_rsqe *rsqe)
{
struct mbuf *m;
void *buf;
u_int stat, cid, w, cells, len, h;
struct patm_vcc *vcc;
struct atm_pseudohdr aph;
u_char *trail;
cid = le32toh(rsqe->cid);
stat = le32toh(rsqe->stat);
h = le32toh(rsqe->handle);
cid = PATM_CID(sc, IDT_RSQE_VPI(cid), IDT_RSQE_VCI(cid));
vcc = sc->vccs[cid];
if (IDT_RSQE_TYPE(stat) == IDT_RSQE_IDLE) {
/* connection has gone idle */
if (stat & IDT_RSQE_BUF)
patm_rcv_free(sc, patm_rcv_handle(sc, h), h);
w = rct_read(sc, cid, 0);
if (w != 0 && !(w & IDT_RCT_OPEN))
rct_write(sc, cid, 0, 0);
if (vcc != NULL && (vcc->vflags & PATM_VCC_RX_CLOSING)) {
patm_debug(sc, VCC, "%u.%u RX closed", vcc->vcc.vpi,
vcc->vcc.vci);
vcc->vflags &= ~PATM_VCC_RX_CLOSING;
if (vcc->vflags & PATM_VCC_ASYNC) {
patm_rx_vcc_closed(sc, vcc);
if (!(vcc->vflags & PATM_VCC_OPEN))
patm_vcc_closed(sc, vcc);
} else
cv_signal(&sc->vcc_cv);
}
return;
}
buf = patm_rcv_handle(sc, h);
if (vcc == NULL || (vcc->vflags & PATM_VCC_RX_OPEN) == 0) {
patm_rcv_free(sc, buf, h);
return;
}
cells = IDT_RSQE_CNT(stat);
KASSERT(cells > 0, ("zero cell count"));
if (vcc->vcc.aal == ATMIO_AAL_0) {
/* deliver this packet as it is */
if ((m = patm_rcv_mbuf(sc, buf, h, 1)) == NULL)
return;
m->m_len = cells * 48;
m->m_pkthdr.len = m->m_len;
m->m_pkthdr.rcvif = &sc->ifatm.ifnet;
} else if (vcc->vcc.aal == ATMIO_AAL_34) {
/* XXX AAL3/4 */
patm_rcv_free(sc, buf, h);
return;
} else if (vcc->vcc.aal == ATMIO_AAL_5) {
if (stat & IDT_RSQE_CRC) {
sc->ifatm.ifnet.if_ierrors++;
if (vcc->chain != NULL) {
m_freem(vcc->chain);
vcc->chain = vcc->last = NULL;
}
return;
}
/* append to current chain */
if (vcc->chain == NULL) {
if ((m = patm_rcv_mbuf(sc, buf, h, 1)) == NULL)
return;
m->m_len = cells * 48;
m->m_pkthdr.len = m->m_len;
m->m_pkthdr.rcvif = &sc->ifatm.ifnet;
vcc->chain = vcc->last = m;
} else {
if ((m = patm_rcv_mbuf(sc, buf, h, 0)) == NULL)
return;
m->m_len = cells * 48;
vcc->last->m_next = m;
vcc->last = m;
vcc->chain->m_pkthdr.len += m->m_len;
}
if (!(stat & IDT_RSQE_EPDU))
return;
trail = mtod(m, u_char *) + m->m_len - 6;
len = (trail[0] << 8) + trail[1];
if ((u_int)vcc->chain->m_pkthdr.len < len + 8) {
patm_printf(sc, "%s: bad aal5 lengths %u %u\n",
__func__, (u_int)m->m_pkthdr.len, len);
m_freem(vcc->chain);
vcc->chain = vcc->last = NULL;
return;
}
m->m_len -= vcc->chain->m_pkthdr.len - len;
KASSERT(m->m_len >= 0, ("bad last mbuf"));
m = vcc->chain;
vcc->chain = vcc->last = NULL;
m->m_pkthdr.len = len;
} else
panic("bad aal");
#if 0
{
u_int i;
for (i = 0; i < m->m_len; i++) {
printf("%02x ", mtod(m, u_char *)[i]);
}
printf("\n");
}
#endif
sc->ifatm.ifnet.if_ipackets++;
/* this is in if_atmsubr.c */
/* sc->ifatm.ifnet.if_ibytes += m->m_pkthdr.len; */
vcc->ibytes += m->m_pkthdr.len;
vcc->ipackets++;
ATM_PH_FLAGS(&aph) = vcc->vcc.flags & 0xff;
ATM_PH_VPI(&aph) = IDT_RSQE_VPI(cid);
ATM_PH_SETVCI(&aph, IDT_RSQE_VCI(cid));
#ifdef ENABLE_BPF
if (!(vcc->vcc.flags & ATMIO_FLAG_NG) &&
(vcc->vcc.flags & ATM_PH_AAL5) &&
(vcc->vcc.flags & ATM_PH_LLCSNAP))
BPF_MTAP(&sc->ifatm.ifnet, m);
#endif
atm_input(&sc->ifatm.ifnet, &aph, m, vcc->rxhand);
}
/*
* Get the buffer for a receive handle. This is either an mbuf for
* a large handle or a pool buffer for the others.
*/
static void *
patm_rcv_handle(struct patm_softc *sc, u_int handle)
{
void *buf;
u_int c;
if ((handle & ~MBUF_HMASK) == LMBUF_HANDLE) {
struct lmbuf *b;
c = handle & MBUF_HMASK;
b = &sc->lbufs[c];
buf = b->m;
b->m = NULL;
bus_dmamap_sync(sc->lbuf_tag, b->map, BUS_DMASYNC_POSTREAD);
patm_lbuf_free(sc, b);
} else if ((handle & ~MBUF_HMASK) == MBUF_VHANDLE) {
mbp_sync(sc->vbuf_pool, handle,
0, VMBUF_SIZE, BUS_DMASYNC_POSTREAD);
buf = mbp_get(sc->vbuf_pool, handle);
} else {
mbp_sync(sc->sbuf_pool, handle,
0, SMBUF_SIZE, BUS_DMASYNC_POSTREAD);
buf = mbp_get(sc->sbuf_pool, handle);
}
return (buf);
}
/*
* Free a buffer.
*/
static void
patm_rcv_free(struct patm_softc *sc, void *p, u_int handle)
{
if ((handle & ~MBUF_HMASK) == LMBUF_HANDLE)
m_free((struct mbuf *)p);
else if ((handle & ~MBUF_HMASK) == MBUF_VHANDLE)
mbp_free(sc->vbuf_pool, p);
else
mbp_free(sc->sbuf_pool, p);
}
/*
* Make an mbuf around the buffer
*/
static struct mbuf *
patm_rcv_mbuf(struct patm_softc *sc, void *buf, u_int h, int hdr)
{
struct mbuf *m;
if ((h & ~MBUF_HMASK) == MBUF_LHANDLE)
return ((struct mbuf *)buf);
if (hdr)
MGETHDR(m, M_DONTWAIT, MT_DATA);
else
MGET(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
patm_rcv_free(sc, buf, h);
return (NULL);
}
if ((h & ~MBUF_HMASK) == MBUF_VHANDLE) {
m_extadd(m, (caddr_t)buf, VMBUF_SIZE, mbp_ext_free,
sc->vbuf_pool, M_PKTHDR, EXT_NET_DRV);
m->m_data += VMBUF_OFFSET;
} else {
m_extadd(m, (caddr_t)buf, SMBUF_SIZE, mbp_ext_free,
sc->sbuf_pool, M_PKTHDR, EXT_NET_DRV);
m->m_data += SMBUF_OFFSET;
}
if (!(m->m_flags & M_EXT)) {
patm_rcv_free(sc, buf, h);
m_free(m);
return (NULL);
}
return (m);
}
/*
* Process the raw cell at the given address.
*/
void
patm_rx_raw(struct patm_softc *sc, u_char *cell)
{
u_int vpi, vci, cid;
struct patm_vcc *vcc;
struct mbuf *m;
u_char *dst;
struct timespec ts;
struct atm_pseudohdr aph;
uint64_t cts;
sc->stats.raw_cells++;
/*
* For some non-appearant reason the cell header
* is in the wrong endian.
*/
*(uint32_t *)cell = bswap32(*(uint32_t *)cell);
vpi = ((cell[0] & 0xf) << 4) | ((cell[1] & 0xf0) >> 4);
vci = ((cell[1] & 0xf) << 12) | (cell[2] << 4) | ((cell[3] & 0xf0) >> 4);
cid = PATM_CID(sc, vpi, vci);
vcc = sc->vccs[cid];
if (vcc == NULL || !(vcc->vflags & PATM_VCC_RX_OPEN) ||
vcc->vcc.aal != ATMIO_AAL_RAW) {
vcc = sc->vccs[0];
if (vcc == NULL || !(vcc->vflags & PATM_VCC_RX_OPEN)) {
sc->stats.raw_no_vcc++;
return;
}
}
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
sc->stats.raw_no_buf++;
return;
}
m->m_pkthdr.rcvif = &sc->ifatm.ifnet;
switch (vcc->vflags & PATM_RAW_FORMAT) {
default:
case PATM_RAW_CELL:
m->m_len = m->m_pkthdr.len = 53;
MH_ALIGN(m, 53);
dst = mtod(m, u_char *);
*dst++ = *cell++;
*dst++ = *cell++;
*dst++ = *cell++;
*dst++ = *cell++;
*dst++ = 0; /* HEC */
bcopy(cell + 12, dst, 48);
break;
case PATM_RAW_NOHEC:
m->m_len = m->m_pkthdr.len = 52;
MH_ALIGN(m, 52);
dst = mtod(m, u_char *);
*dst++ = *cell++;
*dst++ = *cell++;
*dst++ = *cell++;
*dst++ = *cell++;
bcopy(cell + 12, dst, 48);
break;
case PATM_RAW_CS:
m->m_len = m->m_pkthdr.len = 64;
MH_ALIGN(m, 64);
dst = mtod(m, u_char *);
*dst++ = *cell++;
*dst++ = *cell++;
*dst++ = *cell++;
*dst++ = *cell++;
*dst++ = 0; /* HEC */
*dst++ = 0; /* flags */
*dst++ = 0; /* reserved */
*dst++ = 0; /* reserved */
nanotime(&ts);
cts = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
bcopy(dst, &cts, 8);
bcopy(cell + 12, dst + 8, 48);
break;
}
sc->ifatm.ifnet.if_ipackets++;
/* this is in if_atmsubr.c */
/* sc->ifatm.ifnet.if_ibytes += m->m_pkthdr.len; */
vcc->ibytes += m->m_pkthdr.len;
vcc->ipackets++;
ATM_PH_FLAGS(&aph) = vcc->vcc.flags & 0xff;
ATM_PH_VPI(&aph) = vcc->vcc.vpi;
ATM_PH_SETVCI(&aph, vcc->vcc.vci);
atm_input(&sc->ifatm.ifnet, &aph, m, vcc->rxhand);
}

1273
sys/dev/patm/if_patm_tx.c Normal file

File diff suppressed because it is too large Load Diff

517
sys/dev/patm/if_patmvar.h Normal file
View File

@ -0,0 +1,517 @@
/*
* Copyright (c) 2003
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
* 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.
*
* Author: Hartmut Brandt <harti@freebsd.org>
*
* $FreeBSD$
*
* Driver for IDT77252 (ABR) based cards like ProSum's.
*/
/* legal values are 0, 1, 2 and 8 */
#define PATM_VPI_BITS 2
#define PATM_CFG_VPI IDT_CFG_VP2
/* receive status queue size */
#define PATM_RSQ_SIZE 512
#define PATM_CFQ_RSQ_SIZE IDT_CFG_RXQ512
/* alignment for SQ memory */
#define PATM_SQ_ALIGNMENT 8192
#define PATM_PROATM_NAME_OFFSET 060
#define PATM_PROATM_NAME "PROATM"
#define PATM_PROATM_MAC_OFFSET 044
#define PATM_IDT_MAC_OFFSET 0154
/* maximum number of packets on UBR queue */
#define PATM_DLFT_MAXQ 1000
/* maximum number of packets on other queues. This should depend on the
* traffic contract. */
#define PATM_TX_IFQLEN 100
/*
* Maximum number of DMA maps we allocate. This is the minimum that can be
* set larger via a sysctl.
* Starting number of DMA maps.
* Step for growing.
*/
#define PATM_CFG_TXMAPS_MAX 1024
#define PATM_CFG_TXMAPS_INIT 128
#define PATM_CFG_TXMAPS_STEP 128
/* percents of TST slots to keep for non-CBR traffic */
#define PATM_TST_RESERVE 2
/*
* Structure to hold TX DMA maps
*/
struct patm_txmap {
SLIST_ENTRY(patm_txmap) link;
bus_dmamap_t map;
};
/*
* Receive buffers.
*
* We manage our own external mbufs for small receive buffers for two reasons:
* the card may consume a rather large number of buffers. Mapping each buffer
* would consume a lot of iospace on sparc64. Also the card allows us to set
* a 32-bit handle for identification of the buffers. On a 64-bit system this
* requires us to use a mapping between buffers and handles.
*
* For large buffers we use mbuf clusters directly. We track these by using
* an array of pointers (lbufs) to special structs and a free list of these
* structs.
*
* For AAL0 cell we use FBQ2 and make the 1 cell long.
*/
/*
* Define the small buffer chunk so that we have at least 16 byte free
* at the end of the chunk and that there is an integral number of chunks
* in a page.
*/
#define SMBUF_PAGE_SIZE 16384 /* 16k pages */
#define SMBUF_MAX_PAGES 64 /* maximum number of pages */
#define SMBUF_CHUNK_SIZE 256 /* 256 bytes per chunk */
#define SMBUF_CELLS 5
#define SMBUF_SIZE (SMBUF_CELLS * 48)
#define SMBUF_THRESHOLD 9 /* 9/16 of queue size */
#define SMBUF_NI_THRESH 3
#define SMBUF_CI_THRESH 1
#define VMBUF_PAGE_SIZE 16384 /* 16k pages */
#define VMBUF_MAX_PAGES 16 /* maximum number of pages */
#define VMBUF_CHUNK_SIZE 64 /* 64 bytes per chunk */
#define VMBUF_CELLS 1
#define VMBUF_SIZE (VMBUF_CELLS * 48)
#define VMBUF_THRESHOLD 15 /* 15/16 of size */
#define SMBUF_OFFSET (SMBUF_CHUNK_SIZE - 8 - SMBUF_SIZE)
#define VMBUF_OFFSET 0
#define MBUF_SHANDLE 0x00000000
#define MBUF_LHANDLE 0x80000000
#define MBUF_VHANDLE 0x40000000
#define MBUF_HMASK 0x3fffffff
/*
* Large buffers
*
* The problem with these is the maximum count. When the card assembles
* a AAL5 pdu it moves a buffer from the FBQ to the VC. This frees space
* in the FBQ, put the buffer may pend on the card for an unlimited amount
* of time (we don't idle connections). This means that the upper limit
* on buffers on the card may be (no-of-open-vcs + FBQ_SIZE). Because
* this is far too much, make this a tuneable. We could also make
* this dynamic by allocating pages of several lbufs at once during run time.
*/
#define LMBUF_MAX (IDT_FBQ_SIZE * 2)
#define LMBUF_CELLS (MCLBYTES / 48) /* 42 cells = 2048 byte */
#define LMBUF_SIZE (LMBUF_CELLS * 48)
#define LMBUF_THRESHOLD 9 /* 9/16 of queue size */
#define LMBUF_OFFSET (MCLBYTES - LMBUF_SIZE)
#define LMBUF_NI_THRESH 3
#define LMBUF_CI_THRESH 1
#define LMBUF_HANDLE 0x80000000
struct lmbuf {
SLIST_ENTRY(lmbuf) link; /* free list link */
bus_dmamap_t map; /* DMA map */
u_int handle; /* this is the handle index */
struct mbuf *m; /* the current mbuf */
bus_addr_t phy; /* phy addr */
};
#define PATM_CID(SC, VPI, VCI) \
(((VPI) << (SC)->ifatm.mib.vci_bits) | (VCI))
/*
* Internal driver statistics
*/
struct patm_stats {
uint32_t raw_cells;
uint32_t raw_no_vcc;
uint32_t raw_no_buf;
uint32_t tx_qfull;
uint32_t tx_out_of_tbds;
uint32_t tx_out_of_maps;
uint32_t tx_load_err;
};
/*
* These are allocated as DMA able memory
*/
struct patm_scd {
struct idt_tbd scq[IDT_SCQ_SIZE];
LIST_ENTRY(patm_scd) link; /* all active SCDs */
uint32_t sram; /* SRAM address */
bus_addr_t phy; /* physical address */
bus_dmamap_t map; /* DMA map */
u_int tail; /* next free entry for host */
int space; /* number of free entries (minus one) */
u_int slots; /* CBR slots allocated */
uint8_t tag; /* next tag for TSI */
uint8_t last_tag; /* last tag checked in interrupt */
uint8_t num_on_card; /* number of PDUs on tx queue */
uint8_t lacr; /* LogACR value */
uint8_t init_er; /* LogER value */
struct ifqueue q; /* queue of packets */
struct mbuf *on_card[IDT_TSQE_TAG_SPACE];
};
/*
* Per-VCC data
*/
struct patm_vcc {
struct atmio_vcc vcc; /* caller's parameters */
void *rxhand; /* NATM handle */
u_int vflags; /* open and other flags */
uint32_t ipackets; /* packets received */
uint32_t opackets; /* packets sent */
uint64_t ibytes; /* bytes received */
uint64_t obytes; /* bytes sent */
struct mbuf *chain; /* currently received chain */
struct mbuf *last; /* end of chain */
u_int cid; /* index */
u_int cps; /* last ABR cps */
struct patm_scd *scd;
};
#define PATM_VCC_TX_OPEN 0x0001
#define PATM_VCC_RX_OPEN 0x0002
#define PATM_VCC_TX_CLOSING 0x0004
#define PATM_VCC_RX_CLOSING 0x0008
#define PATM_VCC_OPEN 0x000f /* all the above */
#define PATM_VCC_ASYNC 0x0010
#define PATM_RAW_CELL 0x0000 /* 53 byte cells */
#define PATM_RAW_NOHEC 0x0100 /* 52 byte cells */
#define PATM_RAW_CS 0x0200 /* 64 byte cell stream */
#define PATM_RAW_FORMAT 0x0300 /* format mask */
/*
* Per adapter data
*/
struct patm_softc {
struct ifatm ifatm; /* common ATM stuff */
struct mtx mtx; /* lock */
struct ifmedia media; /* media */
device_t dev; /* device */
struct resource * memres; /* memory resource */
bus_space_handle_t memh; /* handle */
bus_space_tag_t memt; /* ... and tag */
int irqid; /* resource id */
struct resource * irqres; /* resource */
void * ih; /* interrupt handle */
struct utopia utopia; /* phy state */
const struct idt_mmap *mmap; /* SRAM memory map */
u_int flags; /* see below */
u_int revision; /* chip revision */
/* DMAable status queue memory */
size_t sq_size; /* size of memory area */
bus_dma_tag_t sq_tag; /* DMA tag */
bus_dmamap_t sq_map; /* map */
bus_addr_t tsq_phy; /* phys addr. */
struct idt_tsqe *tsq; /* transmit status queue */
struct idt_tsqe *tsq_next; /* last processed entry */
struct idt_rsqe *rsq; /* receive status queue */
bus_addr_t rsq_phy; /* phys addr. */
u_int rsq_last; /* last processed entry */
struct idt_rawhnd *rawhnd; /* raw cell handle */
bus_addr_t rawhnd_phy; /* phys addr. */
/* TST */
u_int tst_state; /* active TST and others */
u_int tst_jump[2]; /* address of the jumps */
u_int tst_base[2]; /* base address of TST */
u_int *tst_soft; /* soft TST */
struct mtx tst_lock;
struct callout tst_callout;
u_int tst_free; /* free slots */
u_int tst_reserve; /* non-CBR reserve */
u_int bwrem; /* remaining bandwith */
/* sysctl support */
struct sysctl_ctx_list sysctl_ctx;
struct sysctl_oid *sysctl_tree;
/* EEPROM contents */
uint8_t eeprom[256];
/* large buffer mapping */
bus_dma_tag_t lbuf_tag; /* DMA tag */
u_int lbuf_max; /* maximum number */
struct lmbuf *lbufs; /* array for indexing */
SLIST_HEAD(,lmbuf) lbuf_free_list; /* free list */
/* small buffer handling */
bus_dma_tag_t sbuf_tag; /* DMA tag */
struct mbpool *sbuf_pool; /* pool */
struct mbpool *vbuf_pool; /* pool */
/* raw cell queue */
struct lmbuf *rawh; /* current header buf */
u_int rawi; /* cell index into buffer */
/* statistics */
struct patm_stats stats; /* statistics */
/* Vccs */
struct patm_vcc **vccs; /* channel pointer array */
u_int vccs_open; /* number of open channels */
uma_zone_t vcc_zone;
struct cv vcc_cv;
/* SCDs */
uint32_t scd_free; /* SRAM of first free SCD */
bus_dma_tag_t scd_tag;
struct patm_scd *scd0;
LIST_HEAD(, patm_scd) scd_list; /* list of all active SCDs */
/* Tx */
bus_dma_tag_t tx_tag; /* for transmission */
SLIST_HEAD(, patm_txmap) tx_maps_free; /* free maps */
u_int tx_nmaps; /* allocated maps */
u_int tx_maxmaps; /* maximum number */
struct uma_zone *tx_mapzone; /* zone for maps */
#ifdef PATM_DEBUG
/* debugging */
u_int debug;
#endif
};
/* flags */
#define PATM_25M 0x0001 /* 25MBit card */
#define PATM_SBUFW 0x0002 /* warned */
#define PATM_VBUFW 0x0004 /* warned */
#define PATM_UNASS 0x0010 /* unassigned cells */
#define PATM_CLR 0x0007 /* clear on stop */
/* tst - uses unused fields */
#define TST_BOTH 0x03000000
#define TST_CH0 0x01000000
#define TST_CH1 0x02000000
/* tst_state */
#define TST_ACT1 0x0001 /* active TST */
#define TST_PENDING 0x0002 /* need update */
#define TST_WAIT 0x0004 /* wait fo jump */
#define patm_printf(SC, ...) if_printf(&(SC)->ifatm.ifnet, __VA_ARGS__);
#ifdef PATM_DEBUG
/*
* Debugging
*/
enum {
DBG_ATTACH = 0x0001, /* attaching the card */
DBG_INTR = 0x0002, /* interrupts */
DBG_REG = 0x0004, /* register access */
DBG_SRAM = 0x0008, /* SRAM access */
DBG_PHY = 0x0010, /* PHY access */
DBG_IOCTL = 0x0020, /* ioctl */
DBG_FREEQ = 0x0040, /* free bufq supply */
DBG_VCC = 0x0080, /* open/close */
DBG_TX = 0x0100, /* transmission */
DBG_TST = 0x0200, /* TST */
DBG_ALL = 0xffff
};
#define patm_debug(SC, FLAG, ...) do { \
if((SC)->debug & DBG_##FLAG) { \
if_printf(&(SC)->ifatm.ifnet, "%s: ", __func__); \
printf(__VA_ARGS__); \
printf("\n"); \
} \
} while (0)
#else
#define patm_debug(SC, FLAG, ...) do { } while (0)
#endif
/* start output */
void patm_start(struct ifnet *);
/* ioctl handler */
int patm_ioctl(struct ifnet *, u_long, caddr_t);
/* start the interface */
void patm_init(void *);
/* start the interface with the lock held */
void patm_initialize(struct patm_softc *);
/* stop the interface */
void patm_stop(struct patm_softc *);
/* software reset of interface */
void patm_reset(struct patm_softc *);
/* interrupt handler */
void patm_intr(void *);
/* check RSQ */
void patm_intr_rsq(struct patm_softc *sc);
/* close the given vcc for transmission */
void patm_tx_vcc_close(struct patm_softc *, struct patm_vcc *);
/* close the given vcc for receive */
void patm_rx_vcc_close(struct patm_softc *, struct patm_vcc *);
/* transmission side finally closed */
void patm_tx_vcc_closed(struct patm_softc *, struct patm_vcc *);
/* receive side finally closed */
void patm_rx_vcc_closed(struct patm_softc *, struct patm_vcc *);
/* vcc closed */
void patm_vcc_closed(struct patm_softc *, struct patm_vcc *);
/* check if we can open this one */
int patm_tx_vcc_can_open(struct patm_softc *, struct patm_vcc *);
/* check if we can open this one */
int patm_rx_vcc_can_open(struct patm_softc *, struct patm_vcc *);
/* open it */
void patm_tx_vcc_open(struct patm_softc *, struct patm_vcc *);
/* open it */
void patm_rx_vcc_open(struct patm_softc *, struct patm_vcc *);
/* receive packet */
void patm_rx(struct patm_softc *, struct idt_rsqe *);
/* packet transmitted */
void patm_tx(struct patm_softc *, u_int, u_int);
/* VBR connection went idle */
void patm_tx_idle(struct patm_softc *, u_int);
/* allocate an SCQ */
struct patm_scd *patm_scd_alloc(struct patm_softc *);
/* free an SCD */
void patm_scd_free(struct patm_softc *sc, struct patm_scd *scd);
/* setup SCD in SRAM */
void patm_scd_setup(struct patm_softc *sc, struct patm_scd *scd);
/* setup TCT entry in SRAM */
void patm_tct_setup(struct patm_softc *, struct patm_scd *, struct patm_vcc *);
/* free a large buffer */
void patm_lbuf_free(struct patm_softc *sc, struct lmbuf *b);
/* Process the raw cell at the given address */
void patm_rx_raw(struct patm_softc *sc, u_char *cell);
/* load a one segment DMA map */
void patm_load_callback(void *, bus_dma_segment_t *, int, int);
/* network operation register access */
static __inline uint32_t
patm_nor_read(struct patm_softc *sc, u_int reg)
{
uint32_t val;
val = bus_space_read_4(sc->memt, sc->memh, reg);
patm_debug(sc, REG, "reg(0x%x)=%04x", reg, val);
return (val);
}
static __inline void
patm_nor_write(struct patm_softc *sc, u_int reg, uint32_t val)
{
patm_debug(sc, REG, "reg(0x%x)=%04x", reg, val);
bus_space_write_4(sc->memt, sc->memh, reg, val);
}
/* Execute command */
static __inline void
patm_cmd_wait(struct patm_softc *sc)
{
while (patm_nor_read(sc, IDT_NOR_STAT) & IDT_STAT_CMDBZ)
;
}
static __inline void
patm_cmd_exec(struct patm_softc *sc, uint32_t cmd)
{
patm_cmd_wait(sc);
patm_nor_write(sc, IDT_NOR_CMD, cmd);
}
/* Read/write SRAM at the given word address. */
static __inline uint32_t
patm_sram_read(struct patm_softc *sc, u_int addr)
{
uint32_t val;
patm_cmd_exec(sc, IDT_MKCMD_RSRAM(addr));
patm_cmd_wait(sc);
val = patm_nor_read(sc, IDT_NOR_D0);
patm_debug(sc, SRAM, "read %04x=%08x", addr, val);
return (val);
}
static __inline void
patm_sram_write(struct patm_softc *sc, u_int addr, uint32_t val)
{
patm_debug(sc, SRAM, "write %04x=%08x", addr, val);
patm_cmd_wait(sc);
patm_nor_write(sc, IDT_NOR_D0, val);
patm_cmd_exec(sc, IDT_MKCMD_WSRAM(addr, 0));
}
static __inline void
patm_sram_write4(struct patm_softc *sc, u_int addr, uint32_t v0, uint32_t v1,
uint32_t v2, uint32_t v3)
{
patm_debug(sc, SRAM, "write %04x=%08x,%08x,%08x,%08x",
addr, v0, v1, v2, v3);
patm_cmd_wait(sc);
patm_nor_write(sc, IDT_NOR_D0, v0);
patm_nor_write(sc, IDT_NOR_D1, v1);
patm_nor_write(sc, IDT_NOR_D2, v2);
patm_nor_write(sc, IDT_NOR_D3, v3);
patm_cmd_exec(sc, IDT_MKCMD_WSRAM(addr, 3));
}
#define LEGAL_VPI(SC, VPI) \
(((VPI) & ~((1 << (SC)->ifatm.mib.vpi_bits) - 1)) == 0)
#define LEGAL_VCI(SC, VCI) \
(((VCI) & ~((1 << (SC)->ifatm.mib.vci_bits) - 1)) == 0)
extern const uint32_t patm_rtables155[];
extern const uint32_t patm_rtables25[];
extern const u_int patm_rtables_size;
extern const u_int patm_rtables_ntab;

View File

@ -88,6 +88,7 @@ SUBDIR= accf_data \
nmdm \
ntfs \
nullfs \
patm \
pcn \
plip \
portalfs \

22
sys/modules/patm/Makefile Normal file
View File

@ -0,0 +1,22 @@
# $FreeBSD$
#
# Author: Harti Brandt <harti@freebsd.org>
#
.PATH: ${.CURDIR}/../../dev/patm
KMOD= if_patm
SRCS= if_patm.c if_patm_attach.c if_patm_ioctl.c if_patm_intr.c \
if_patm_tx.c if_patm_rx.c if_patm_rtables.c \
device_if.h bus_if.h pci_if.h opt_inet.h opt_natm.h
CFLAGS+= -DENABLE_BPF
# CFLAGS+= -DPATM_DEBUG=0x0 -DINVARIANT_SUPPORT -DINVARIANTS -g -DDIAGNOSTIC
# LDFLAGS+= -g
opt_inet.h:
echo "#define INET 1" > opt_inet.h
opt_natm.h:
echo "#define NATM 1" > opt_natm.h
.include <bsd.kmod.mk>