8dd4275c36
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.
459 lines
9.2 KiB
C
459 lines
9.2 KiB
C
/*
|
|
* 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);
|
|
}
|