Filewatcher File Search
FTP Search
  
Directory 
  
Content Search 
   
pkg://irqtune-0.6-1.src.rpm:106316/irqtune.tgz  info  downloads

irqtune/ 40755    155    764           0  6414544745  10415 5ustar  caeengrirqtune/COPYING100644    155    764       44032  6173130530  11551 0ustar  caeengr
   NOTE! This copyright does *not* cover user programs that use kernel
 services by normal system calls - this is merely considered normal use
 of the kernel, and does *not* fall under the heading of "derived work".
 Also note that the GPL below is copyrighted by the Free Software
 Foundation, but the instance of code that it refers to (the linux
 kernel) is copyrighted by me and others who actually wrote it.

			Linus Torvalds

----------------------------------------

		    GNU GENERAL PUBLIC LICENSE
		       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
                          675 Mass Ave, Cambridge, MA 02139, USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

			    Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

		    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

			    NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

		     END OF TERMS AND CONDITIONS

	Appendix: How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) 19yy  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) 19yy name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Library General
Public License instead of this License.
irqtune/Makefile100644    155    764        3323  6414547306  12147 0ustar  caeengr# Makefile for irqtune

##INSTALLATION:
##  install    install prebuilt binaries in /sbin
##  custom     create custom installation -- Normally _not_ required -- Try
##             install first (EQUIVALENT: kvers sbin install)
##  uninstall  remove prebuilt binaries from /sbin
##
##INSTALLATION OVERRIDES:
##  SBIN       SBIN=/whatever specify installation directory (DEFAULT: /sbin)
##  INSTALL    INSTALL=simple simple installation (DEFAULT: simple)
##             INSTALL=sh install as shell stub
##  INSTALLER  installation program (bin/install) (DEFAULT: sbin/irqtune)
##
##REBUILDING FROM SOURCE:
##  kvers      create kernel_version
##  sbin       rebuild binaries from source (full or partial)
##
##FORCE FULL REBUILD (requires /usr/src/linux/include):
##  clean      remove .o files to force full recompile)
##  warp9      rebuild all (EQUIVALENT: clean kvers sbin install)
##

# installation control
SBIN = /sbin
INSTALL = simple
INSTALLER = sbin/irqtune

IRQTUNE_VERSION = 0.6
IRQTUNE_HOME := $(shell pwd)
SMKF = $(IRQTUNE_HOME)/src/Makefile
ODIR = $(IRQTUNE_HOME)/sbin
KVERS = kvers
CDEBUG = # -g
CFLAGS_EXTRA =
DEFS = CDEBUG='$(CDEBUG)' CFLAGS_EXTRA='$(CFLAGS_EXTRA)' \
	IRQTUNE_HOME=$(IRQTUNE_HOME) \
	IRQTUNE_VERSION=$(IRQTUNE_VERSION) \
	INSTALL=$(INSTALL) INSTALLER=$(IRQTUNE_HOME)/$(INSTALLER) \
	SBIN=$(SBIN)

zilch:
	@egrep '^##' ./Makefile | sed -e 's/^##//'

sbin $(KVERS) uninstall install proto: FRC
	(cd $(ODIR) ; $(MAKE) -f $(SMKF) $(DEFS) $@)

clean: FRC
	(cd $(ODIR) ; $(MAKE) -f $(SMKF) $(DEFS) $@)

mkdir: FRC
	mkdir -p $(ODIR)

custom: mkdir $(KVERS) sbin install ;
warp9: _warp9 clean mkdir $(KVERS) sbin install ;
_warp9: FRC ; @echo Take it easy, Jim
FRC:

# show the version
version:
	@echo $(IRQTUNE_VERSION)
irqtune/src/ 40755    155    764           0  6361370301  11166 5ustar  caeengrirqtune/src/irqhigh.c100644    155    764        7650  6366007517  13105 0ustar  caeengr/* irqhigh.c -- set high priority IRQ's */

/*
// Copyright 1996, 1997 by Craig Estey -- See the file COPYING for details
*/

#include <irqhigh.h>
#include <asm/io.h>

#if defined(__GNUC__) && (! defined(__OPTIMIZE__))
#error irqhigh: yes, we really need the optimizer enabled
#endif

/* current value */
u_char irqhigh_list[2] = { IRQHIGH_MST_DFT, IRQHIGH_SLV_DFT };

/* list of resultant priorites */
u_char irq_prior_list[IRQHIGH_MAX];
u_char irq_prior_bias[IRQHIGH_MAX];

/* irqhigh_offset -- compute offset into irqhigh_list */
extern inline u_char
irqhigh_offset(u_char irq_no)
{

	irq_no >>= 3;

	return irq_no;
}

/* irqhigh_calc -- calculate priority table */
static void
irqhigh_calc(void)
{
	u_char mst_no;
	u_char mst_idx;
	u_char slv_no;
	u_char slv_idx;
	u_char prior;
	u_char bias;

	prior = 0;
	bias = 0;

	/* start at master highest */
	mst_no = irqhigh_list[0];
	for (mst_idx = 0;  mst_idx <= 7;  ++mst_idx) {
		irq_prior_list[mst_no] = prior++;
		irq_prior_bias[mst_no] = bias;

		/* when we hit the slave cascade, process slave, then resume master */
		if (mst_no == 2) {
			bias = 1;
			slv_no = irqhigh_list[1];
			for (slv_idx = 0;  slv_idx <= 7;  ++slv_idx) {
				irq_prior_list[slv_no] = prior++;
				irq_prior_bias[slv_no] = bias;
				slv_no = (slv_no + 1) & 0x0F;
				if (slv_no == 0)
					slv_no = IRQHIGH_SLV_LO;
			}
		}

		mst_no = (mst_no + 1) & 0x07;
	}
}

/* irqhigh_insane -- check request sanity */
/* RETURNS: error string (or NULL) */
static char *
irqhigh_insane(u_char mst_no,u_char slv_no)
{
	char *err;
	u_char off;

	err = NULL;

	do {
		/* check for master within range */
		if (mst_no >= IRQHIGH_SLV_HI) {
			err = "master value out of range";
			break;
		}

		/* don't check slave value if master is actually a slave */
		if (RNGE(slv_no,IRQHIGH_SLV_LO,IRQHIGH_SLV_HI))
			break;

		/* check slave value */
		if (! RNGE(slv_no,IRQHIGH_SLV_LO,IRQHIGH_SLV_HI)) {
			err = "slave value out of range";
			break;
		}

		/* insure that we have a genuine master/slave combination */
		off = irqhigh_offset(mst_no);
		if (off == irqhigh_offset(slv_no)) {
			if (off > 0)
				err = "two slaves specified";
			else
				err = "two masters specified";
			break;
		}
	} while (0);

	return err;
}

/* irqhigh_set1 -- set highest priority IRQ device on given 8259 */
static void
irqhigh_set1(int goflg,u_char irq_no)
{
	u_char lo;
	u_short port;
	u_char idx;

	/* decide on master vs. slave 8259 */
	idx = irqhigh_offset(irq_no);
	if (idx > 0) {
		port = 0xA0;
		irqhigh_set1(goflg,2);
	}

	/* master */
	else
		port = 0x20;

	irqhigh_list[idx] = irq_no;
	irq_no &= 0x07;

	/* set specific priority (of lowest priority device) */
	if (goflg) {
		/*
		// on the odd chance that the PIC state is indeterminate.  that is:
		// (1)  somebody did an outb to select an alternate PIC register
		// (2A) forgot to do the followup inb/outb.
		// (2B) this was done from task level _without_ interrupts locked
		// in that case, we'd be writing to the wrong register.  this is
		// unlikely because (2A) and (2B) are bugs, but this is CYA
		*/
		inb(port);

		lo = (irq_no - 1) & 0x07;
		lo |= 0xC0;
		outb(lo,port);
	}
}

/* irqhigh_set -- set highest priority IRQ device for both 8259's */
/* RETURNS: error code if things don't match */
static int
irqhigh_set(int goflg,u_char mst_no,u_char slv_no)
{
	int err;
	int slvflg;

	/* order is important -- set slave then master */
	slvflg = (irqhigh_offset(mst_no) == 0);
	if (slvflg)
		irqhigh_set1(goflg,slv_no);
	irqhigh_set1(goflg,mst_no);

	/* check for errors */
	err = -EINVAL;
	do {
		/* check slave number */
		if (slvflg) {
			if (irqhigh_list[1] != slv_no)
				break;
		}

		/* check master number */
		if (irqhigh_list[0] != mst_no)
			break;

		/* no errors */
		err = 0;
	} while (0);

	return err;
}

/* irqhigh_init -- initialize to default */
extern inline void
irqhigh_init(int goflg)
{

	/* set standard COM ports highest on master and disk controller on slave */
	irqhigh_set(goflg,IRQHIGH_MST_DFT,IRQHIGH_SLV_DFT);
}
irqtune/src/irqtune.c100644    155    764       45675  6366011434  13163 0ustar  caeengr/* irqtune -- load IRQ tuning module */

#pragma member irqtune.h
#include <irqtune.h>

#include <lib/cmd.c>
#include <lib/file.c>
#include <lib/opt.c>
#include <lib/xstr.c>
#include <lib/sys.c>
#include <lib/zprt.c>
#include <lib/zprtx.c>

/* main -- main program */
void
main(int argc,char **argv)
{
	char *cp;
	int idx;
	int val;

	pgmname = *argv;
	--argc;
	++argv;

	proc_ints = "/proc/interrupts";
	setbuf(stderr,NULL);
	sprintf(tmpf,"/tmp/irqtune.%d",getpid());

	/* insure we got "/sbin/irqtune" and not just "irqtune" */
	cp = strchr(pgmname,'/');
	if (cp != NULL)
		dynstat |= DYN_FULL_PATH;

	/* locate the top directory */
	strcpy(dirtop,pgmname);
	filehead(dirtop);

	/* decode options */
	for (;  argc > 0;  --argc, ++argv) {
		cp = *argv;
		if (*cp != '-')
			break;
		if (! optget(opthelp,cp + 1))
			usage();
	}

	/* do install and stop */
	if (mstopt & OPTINSTALL)
		install(argc,argv);

	/* do version and stop */
	if (mstopt & (OPTVERSION | OPTERR)) {
		zprtx("irqtune: version is %s\n",IRQTUNE_VERSION);
		if (mstopt & OPTVERSION)
			exit(0);
	}

	/* display help and stop */
	if (mstopt & OPTHELP) {
		_usage();
		exit(0);
	}

	/* get IRQ priority arguments */
	idx = 0;
	for (;  argc > 0;  --argc, ++argv) {
		cp = *argv;
		if (! RNGE(*cp,'0','9'))
			break;

		if (idx >= sizeof(irqhigh_list))
			usage();

		val = atoi(cp);
		if (! RNGE(val,0,15))
			usage();
		irqhigh_list[idx++] = val & 0x0F;
	}

	/* set bad defaults */
	if (mstopt & OPTRESET) {
		irqhigh_list[0] = IRQHIGH_MST_BAD;
		irqhigh_list[1] = IRQHIGH_SLV_BAD;
	}

	/* check the sanity */
	cp = irqhigh_insane(irqhigh_list[0],irqhigh_list[1]);
	if (cp != NULL)
		sysfault("irqtune: unable to use values %u/%u -- %s\n",
			irqhigh_list[0],irqhigh_list[1],cp);

	/* fake it */
	irqhigh_set(0,irqhigh_list[0],irqhigh_list[1]);

	/* probe the configuration and find any trouble */
	probectl();

	/* load the module by whatever means necessary */
	loader();

	/* send the table */
	if ((mstopt & OPTSORT) || (mstopt & OPTNOGO))
		mstopt &= ~OPTQUIET;
	if (bigcode)
		mstopt |= OPTQUIET;
	if (! (mstopt & OPTQUIET)) {
		tblinit();
		tblread(1,proc_ints);
		tblshow();
	}

	/* do final exit */
	sysexit(bigcode);
}

/* install -- install program */
void
install(int argc,char **argv)
{
	char **modtail;
	int idx;
	int err;
	int ok;
	int unit;
	FILE *xf;
	char srcfile[1024];
	char dstfile[1024];

	bigcode = 1;
	xf = NULL;
	unit = -1;
	do {
		/* insure we're invoked by full path */
		if (! (dynstat & DYN_FULL_PATH)) {
			zprtx("install: must be invoked via full path\n");
			break;
		}

		/* check number of arguments */
		if (argc != 3) {
			zprtx("install: wrong number of arguments\n");
			break;
		}

		/* get SBIN directory */
		strcpy(pathtmp,argv[1]);

		/* do simple installation */
		if (strcmp(argv[0],"simple") == 0) {
			zprtx("irqtune: simple installation ...\n");

			/* copy over self */
			err = -1;
			for (idx = 0;  idx <= 1;  ++idx) {
				err = filecpy(idx,pathtmp,dirtop,"irqtune");
				if (err < 0)
					break;
			}
			if (err < 0)
				break;

			/* copy over our modules */
			err = -1;
			ok = 0;
			for (modtail = modnames;  *modtail != NULL;  ++modtail) {
				for (idx = 0;  idx <= 1;  ++idx) {
					sprintf(srcfile,"%s.o",*modtail);
					err = filecpy(idx,pathtmp,dirtop,srcfile);
					if (err < 0)
						continue;
					ok = 1;
				}
			}
			if (! ok) {
				zprtx("install: no modules found\n");
				break;
			}

			bigcode = 0;
			break;
		}

		/* do stub installation */
		if (strcmp(argv[0],"sh") == 0) {
			zprtx("install: stub installation ...\n");

			/* open/create the stub file */
			unit = filecpy(1,pathtmp,NULL,"irqtune");
			if (unit < 0)
				break;

			/* attach a stream */
			xf = fdopen(unit,"a");
			if (xf == NULL) {
				zprtx("install: unable to fdopen -- %s\n",
					strerror(errno));
				break;
			}
			unit = -1;

			fprintf(xf,"#!/bin/sh -\n");
			fprintf(xf,"IRQTUNE_HOME='%s'\n",argv[2]);
			fprintf(xf,"exec $IRQTUNE_HOME/sbin/irqtune $*\n");
			fclose(xf);
			xf = NULL;

			/* remove .o files */
			for (modtail = modnames;  *modtail != NULL;  ++modtail) {
				sprintf(dstfile,"%s/%s.o",pathtmp,*modtail);
				err = unlink(dstfile);
				if (err >= 0)
					zprtx("install: removing %s ...\n",dstfile);
			}

			bigcode = 0;
			break;
		}

		zprtx("install: unknown installation mode  -- '%s'\n",
			argv[0]);
	} while (0);

	if (xf != NULL)
		fclose(xf);
	if (unit >= 0)
		close(unit);

	sysexit(bigcode);
}

/* loader -- load module */
void
loader(void)
{
	char *cp;
	int err;
	int ldcode;
	int rmcode;
	char **modtail;
	int modcnt;
	char *logf;
	struct stat mystat;

	bigcode = 1;

	/* force unloading if requested (do this silently as it's likely to */
	/* fail in the normal case) we will unload anything (even stuff loaded */
	/* manually without the "-o" option) */
	rmcode = 0;
	for (modtail = modnames;  *modtail != NULL;  ++modtail) {
		if (mstopt & OPTNOGO)
			break;
		if (! (mstopt & OPTUNLOAD))
			break;
		sprintf(bigbf,"%s %s",rmmod_file,*modtail);
		rmcode = vsystem(0,"pre-unloading",*modtail,NULL,bigbf);
	} while (0);

	/* load the module (fallback to simpler versions to insure it loads) */
	modcnt = 0;

	/* don't try something that is likely to fail (unless forced) */
	modtail = modnames;
	if (! (mstopt & OPTFORCE)) {
		if (dynstat & DYN_NPRONLY)
			++modtail;
	}

	for (;  *modtail != NULL;  ++modtail) {
		sprintf(modcur,"%s/%s.o",dirtop,*modtail);

		/* check for module existence -- don't spew unless full errors as */
		/* known useless modules may be removed to speed things up */
		err = stat(modcur,&mystat);
		if (err < 0) {
			if (mstopt & OPTERR)
				zprtx("irqtune: module %s not found -- skipping\n",
					modcur);
			continue;
		}
		++modcnt;

		/* NOTE: we are version independent */
		/* insmod complains even with the force option */
		logf = "/dev/null";

		cp = bigbf;

		cp += sprintf(cp,"%s -x -o %s -f %s",
			insmod_file,modtag,modcur);

		/* tell insmod to do verbose output */
#ifdef NEVERWAS
		if (mstopt & OPTERR)
			cp += sprintf(cp," -v");
#endif /*NEVERWAS*/

		/* add the desired priority */
		cp += sprintf(cp," priority=%d,%d",irqhigh_list[0],irqhigh_list[1]);

		/* we don't need to check system log (we really should to be sure) */
		zprtx("irqtune: %s %u/%u\n",
			(mstopt & OPTNOGO) ? "simulating IRQ priority of" : "setting system IRQ priority to",
			irqhigh_list[0],irqhigh_list[1]);
		fflush(stderr);

		/* perform module load */
		ldcode = 0;
		do {
			if (mstopt & OPTNOGO)
				break;

			/* sync the disks, just in case */
			sync();

			/* install it */
			ldcode = vsystem(mstopt & OPTERR,"loading",
				modcur,modtag,bigbf);
		} while (0);

		/* check for errors -- the normal presumption is if insmod failed, */
		/* there is no module to unload */
		if (ldcode) {
			if (! (mstopt & OPTUNLOAD))
				continue;
		}

		/* the mere act of installing does the job so uninstall immediately */
		rmcode = 0;
		do {
			if (mstopt & OPTNOGO)
				break;
			sprintf(bigbf,"%s %s",rmmod_file,modtag);
			rmcode = vsystem(1,"unloading",modcur,modtag,bigbf);
		} while (0);

		/*
		// normally, failure to unload is bad because it's so simple.
		// if we're forcing unload, we may attempt to unload a module that
		// never got loaded.  this isn't an immediate killer, it will be
		// detected in the final sweep (e.g. bigcode will stay set).
		// it could also be some nasty, genuine failure of rmmod to unload.
		// we can't tell the difference without some arcane version dependent
		// digesting of rmmod stderr output, so we'll just go on and hope for
		// the best.
		*/
		if (rmcode) {
			if (! (mstopt & OPTUNLOAD))
				break;
		}

		/* stop loading if we found one that works */
		if ((ldcode == 0) && (rmcode == 0)) {
			bigcode = 0;
			break;
		}
	}

	/* complain about no modules found whatsoever */
	do {
		if (mstopt & OPTNOGO)
			break;
		if (modcnt <= 0) {
			zprtx("irqtune: no irqtune modules found\n");
			bigcode = 1;
		}
	} while (0);
}

/* probechk -- check dynamic configuration */
void
probechk(mskof_t actmsk,const char *fmt,...)
{
	int ok;
	int errflg;
	mskof_t errmsk;
	const char *tag;
	va_list ap;

	/* decide if we're missing something required */
	ok = BOOL(dynstat & actmsk);
	if (actmsk & DYN_NEG)
		ok = ! ok;

	/* decide on fatal error */
	errmsk = DYN_FATAL;
	if (mstopt & OPTWARN)
		errmsk |= DYN_WARN;
	errflg = 0;
	if (actmsk & errmsk)
		errflg = (! ok);

	if ((mstopt & OPTERR) || errflg) {
		zprtx("probe: ");

		va_start(ap,fmt);
		zprtvx(0,fmt,ap);
		va_end(ap);

		do {
			if (actmsk & DYN_FATAL) {
				tag = ok ? "OK" : "ERROR";
				break;
			}
			if (actmsk & DYN_WARN) {
				tag = ok ? "OK" : "WARNING";
				break;
			}
			tag = ok ? "YES" : "NO";
		} while (0);
		zprtx(" -- %s\n",tag);
	}

	/* mark fatal error */
	if (errflg)
		dynerr |= actmsk;
}

/* probectl -- probe control (to probe 1) */
void
probectl(void)
{

	/* do the probes */
	probeknl();
	probeksyms();
	probeins();
	tblread(0,proc_ints);

	/* check for insmod conflicts against kernel */
	do {
		/* check for the first nicely working version */
		dynstat &= ~DYN_INSMOD_STRONG;
		if (insmod_version >= INSMOD_VERGOOD) {
			dynstat |= DYN_INSMOD_STRONG;
			break;
		}

		/* both insmod and kernel are 2.0.X */
		if ((insmod_version < VERMK(2,1,0)) &&
			(kvers_dynamic < VERMK(2,1,0)))
			break;

		/* the killer a bad 2.1.X insmod on a 2.0.X kernel */
		if (RNGEM1(insmod_version,VERMK(2,1,0),INSMOD_VERGOOD) &&
			(kvers_dynamic < VERMK(2,1,0))) {
			dynstat |= DYN_INSMOD_CRASH;
			break;
		}
	} while (0);

	/* avert possible insmod crash */
	if ((dynstat & DYN_INSMOD_CRASH) &&
		(dynstat & (DYN_KSYMS_USING | DYN_KSYMS_CSUM)))
		dynstat |= DYN_NPRONLY;

	/* mention a 1.X insmod on a 2.X kernel */
	if (kvers_dynamic >= VERMK(2,0,0)) {
		if (VERMAJ(kvers_dynamic) > VERMAJ(insmod_version))
			dynstat |= DYN_INSMOD_OLD;
	}

	/* detect and show errors */
	probectl2();

	/* abort on detected errors */
	if (dynerr) {
		zprtx("irqtune: probe detected errors\n");

		if (mstopt & OPTFORCE)
			zprtx("irqtune: loading forced\n");

		else
			sysfault("irqtune: loading not performed (may be overriden by -f)\n");
	}
}

/* probectl2 -- probe control (to probe 2) */
void
probectl2(void)
{

	probechk(DYN_FATAL | DYN_FULL_PATH,
		"irqtune must be invoked via the full path");

	/* show basic insmod operation */
	probechk(DYN_SBIN_PATH,"/sbin in $PATH");
	probechk(DYN_FATAL | DYN_INSMOD_PATH,"insmod found in $PATH (%s)",
		insmod_dir);
	probechk(DYN_FATAL | DYN_INSMOD_EXEC,"insmod simple execution");
	probechk(DYN_INSMOD_VERSION,"insmod has version (" VERFMT ")",
		VERPRT(insmod_version));
	probechk(DYN_FATAL | DYN_RMMOD_PATH,"rmmod found in insmod directory");

	/* show an unusable insmod (it accepts no dash options) */
	/* FIXME -- we could support this at some cost, but really this is likely */
	/* some early beta copy of insmod.  sanity beats flexibility here */
	probechk(DYN_FATAL | DYN_NEG | DYN_INSMOD_ANCIENT,
		"insmod version supports command line options");

	/* show a downrev insmod */
	probechk(DYN_FATAL | DYN_NEG | DYN_INSMOD_OLD,
		"insmod version (" VERFMT ") compatible with kernel version (" VERFMT ")",
		VERPRT(insmod_version),VERPRT(kvers_dynamic));

	/* show a no-problems insmod */
	probechk(DYN_WARN | DYN_INSMOD_STRONG,
		"insmod version should be " VERFMT " (or better)",
		VERPRT(INSMOD_VERGOOD));

	/* show possible insmod crash (we can compensate) */
	probechk(DYN_WARN | DYN_NEG | DYN_INSMOD_CRASH,
		"insmod and kernel compatible with CONFIG_MODVERSIONS");

	/* show that we're doing crash compensation */
	probechk(DYN_WARN | DYN_NEG | DYN_NPRONLY,"%s loading will be tried",
		modnames[0]);

	probechk(DYN_KNL_CPLDIFF | DYN_NEG,
		"kernel version irqtune built under (" VERFMT ") matches current system",
		VERPRT(kvers_compile));

	/* complain about kernels where IRQ handling renders us ineffective */
	probechk(DYN_FATAL | DYN_KNL_VEROK,"kernel IRQ handling is compatible");

	/* show kernels built without modules support */
	probechk(DYN_FATAL | DYN_KNL_GSYM,"kernel has module support (CONFIG_MODULES)");
	probechk(DYN_FATAL | DYN_KSYMS_FOUND,"kernel has symbols");

	/* show modversions information */
	probechk(DYN_KSYMS_USING,"kernel is using versions (CONFIG_MODVERSIONS)");
	probechk(DYN_KSYMS_CSUM,"kernel symbols are checksummed (CONFIG_MODVERSIONS)");

	/* require /proc/interrupts */
	probechk(DYN_FATAL | DYN_PROC_INTS,"kernel has /proc/interrupts");
}

/* probeins -- probe for insmod */
void
probeins(void)
{
	char *cp;
	int nextflg;
	int err;
	struct cmdblk *cmd;
	char **av;
	char *argv[10];
	char bf[1024];

	/* add most probable place for insmod */
	cp = pathdir("/sbin");
	if (cp != NULL)
		dynstat |= DYN_SBIN_PATH;

	cmd = NULL;
	do {
		strcpy(insmod_file,"insmod");
		strcpy(rmmod_file,"rmmod");

		/* probe for insmod in $PATH */
		cp = pathlook("insmod",insmod_path);
		if (cp == NULL) {
			sprintf(insmod_dir,"???");
			break;
		}

		/* directory where insmod was found */
		dynstat |= DYN_INSMOD_PATH;
		strcpy(insmod_dir,cp);
		if (insmod_path != NULL)
			sprintf(insmod_file,"%s/insmod",insmod_dir);

		/* NOTE: we require that rmmod be in the same directory as insmod */
		/* flexibility is one thing, but probable sanity is more important */
		cp = pathlook("rmmod",insmod_dir);
		if (cp != NULL) {
			dynstat |= DYN_RMMOD_PATH;
			if (insmod_path != NULL)
				sprintf(rmmod_file,"%s/rmmod",insmod_dir);
		}

		/* capture output of simple insmod execution (and get version) */
		/* WARNING: don't change this without change to ANCIENT string below */
		sprintf(bf,"%s -V",insmod_file);
		cmd = cmdopen(bf);
		if (cmd == NULL)
			break;
		dynstat |= DYN_INSMOD_EXEC;

		/* find the version */
		while (1) {
			/* read next line */
			err = cmdread(cmd,bigbf,sizeof(bigbf));
			if (err < 0)
				break;

			/* look for ancient insmod that supports no command line options */
			if (strcmp(bigbf,"Cannot open -V") == 0)
				dynstat |= DYN_INSMOD_ANCIENT;

			/* look for "x.y.z" */
			xstrargv(argv,Cntof(argv),bigbf);
			nextflg = 0;
			for (av = argv;  *av != NULL;  ++av) {
				cp = *av;

				if (strcasecmp(cp,"version") == 0)
					nextflg = 1;

				/* bug out if we've found a version number */
				insmod_version = verdcd(cp);
				if (insmod_version)
					break;
			}
			if (insmod_version)
				break;
		}

		/* insure that we got a version */
		if (insmod_version != 0)
			dynstat |= DYN_INSMOD_VERSION;
	} while (0);

	/* remove temp file */
	cmdclose(cmd);
}

/* probeknl -- probe the kernel */
void
probeknl(void)
{
	int err;

	/* decide what kernel we were compiled under */
	kvers_compile = verdcd(kernel_version);

	/* decide what kernel we're running under */
	uname(&uts);
	kvers_dynamic = verdcd(uts.release);
	if (mstopt & OPTERR)
		zprtx("irqtune: kernel version " VERFMT "\n",
			VERPRT(kvers_dynamic));

	/* show the version discrepancy (it _should_ not matter because of -f) */
	if (kvers_compile != kvers_dynamic)
		dynstat |= DYN_KNL_CPLDIFF;

	/* check for incompatible kernel IRQ handling */
	if (! RNGE(kvers_dynamic,KNL_VERBADLO,KNL_VERBADHI))
		dynstat |= DYN_KNL_VEROK;

	/* check for module support compiled into kernel (if kernel has */
	/* CONFIG_MODULES off, this will return ENOSYS).  since we're only using */
	/* this to probe, it should still work even with 2.1.18 or later */
	err = get_kernel_syms(NULL);
	if (err >= 0)
		dynstat |= DYN_KNL_GSYM;
}

/* probeksyms -- probe /proc/ksyms */
void
probeksyms(void)
{
	char *cp;
	FILE *xf;
	int argc;
	int len;
	char *argv[10];

	dynstat &= ~DYN_KSYMS_FOUND;
	do {
		xf = fopen("/proc/ksyms","r");
		if (xf == NULL)
			break;

		/* scan the symbols */
		while (1) {
			cp = fgets(bigbf,sizeof(bigbf),xf);
			if (cp == NULL)
				break;

			/* clean the line */
			cp = strrchr(bigbf,'\n');
			if (cp != NULL)
				*cp = 0;

			argc = xstrargv(argv,Cntof(argv),bigbf);
			if (argc < 2)
				continue;

			/* look for <value> <symbol> */
			dynstat |= DYN_KSYMS_FOUND;
			cp = argv[1];

			/* decide if version numbers are being used */
			if (! (dynstat & DYN_KSYMS_USING)) {
				if (strcmp(cp,"Using_Versions") == 0)
					dynstat |= DYN_KSYMS_USING;
			}

			/* decide if symbol has been checksummed */
			len = strlen(cp);
			if (len > 10) {
				if ((cp[len - 10] == '_') && (cp[len - 9] == 'R')) {
					dynstat |= DYN_KSYMS_CSUM;
					len -= 10;
				}
			}
		}

		fclose(xf);
	} while (0);
}

/* verdcd -- decode version number */
/* RETURNS: decoded version number */
u_long
verdcd(char *bf)
{
	char *bp;
	u_long valmaj;
	u_long valmin;
	u_long valsub;

	valmaj = 0;
	valmin = 0;
	valsub = 0;
	do {
		for (bp = bf;  *bp != 0;  ++bp) {
			if (RNGE(*bp,'0','9'))
				continue;
			if (*bp != '.')
				break;
		}
		if (*bp != 0)
			break;

		bp = bf;

		valmaj = strtol(bp,&bp,10);

		++bp;
		valmin = strtol(bp,&bp,10);

		++bp;
		valsub = strtol(bp,&bp,10);
	} while (0);

	valmaj = VERMK(valmaj,valmin,valsub);

	return valmaj;
}

/* tblfind -- find table entry */
/* RETURNS: pointer to /proc/interrupts table entry */
struct tblblk *
tblfind(u_char irq_no)
{
	struct tblblk *tbl;

	/* NOTE: we can do a sort cheaply by indexing here by priority */
	if (mstopt & OPTSORT)
		irq_no = irq_prior_list[irq_no];

	tbl = &tblbase[irq_no];

	return tbl;
}

/* tblinit -- initialize to default */
void
tblinit(void)
{
	u_char irq_no;
	struct tblblk *tbl;

	/* calculate priorities */
	irqhigh_calc();

	/* initialize the table (and calculate priorities) */
	for (irq_no = 0;  irq_no < IRQHIGH_MAX;  ++irq_no) {
		tbl = tblfind(irq_no);
		tbl->tbl_irq = irq_no;
		tbl->tbl_prior = irq_prior_list[irq_no];
		tbl->tbl_bias = irq_prior_bias[irq_no];
		strcpy(tbl->tbl_bf,"        0 ? Inactive");
	}
}

/* tblread -- read in /proc/interrupts table */
void
tblread(int goflg,char *file)
{
	FILE *xf;
	int err;
	char *cp;
	u_long irq_no;
	struct tblblk *tbl;
	char bf[80];

	xf = fopen(file,"r");

	while (xf != NULL) {
		/* read a line */
		cp = fgets(bf,sizeof(bf),xf);
		if (cp == NULL)
			break;

		/* clean the line */
		cp = strchr(bf,'\n');
		if (cp != NULL)
			*cp = 0;

		/* get the irq number */
		irq_no = strtol(bf,&cp,10);

		/* do a modest syntax check */
		err = 1;
		do {
			if (*cp != ':')
				break;
			++cp;

			if (irq_no > IRQHIGH_SLV_HI)
				break;

			err = 0;
		} while (0);

		/* skip entry on error */
		if (err) {
			zprtx("tblread: SYNTAX '%s'\n",bf);
			continue;
		}
		dynstat |= DYN_PROC_INTS;

		if (! goflg)
			break;

		/* copy into table */
		tbl = tblfind(irq_no);
		strcpy(tbl->tbl_bf,cp);
		tbl->tbl_active = 1;
	}

	if (xf != NULL)
		fclose(xf);
}

/* tblshow -- show table */
void
tblshow(void)
{
	u_char irq_no;
	struct tblblk *tbl;

	/* NOTE: do _not_ use tblfind here (and this completes the sort) */
	for (irq_no = 0;  irq_no < IRQHIGH_MAX;  ++irq_no) {
		tbl = &tblbase[irq_no];
		if ((mstopt & OPTALL) || tbl->tbl_active)
			zprtx("I%2.2u/P%2.2u: %s\n",
				tbl->tbl_irq,tbl->tbl_prior - tbl->tbl_bias,tbl->tbl_bf);
	}
}

/* _usage -- show program usage */
void
_usage(void)
{

	zprtx("usage: irqtune [options] [master] [slave]\n");

	zprtx("version: %s\n",IRQTUNE_VERSION);

	zprtx("arguments:\n");
	zprtx("  master -- high priority IRQ on PIC master (DEFAULT: %d)\n",
		IRQHIGH_MST_DFT);
	zprtx("  slave -- high priority IRQ on PIC slave (DEFAULT: %d)\n",
		IRQHIGH_SLV_DFT);

	optusage(opthelp);
}

/* usage -- show program usage and exit */
void
usage(void)
{

	_usage();
	sysexit(1);
}
irqtune/src/load.c100644    155    764        3627  6414563233  12365 0ustar  caeengr/* irqtune/load.c -- irqtune module loader */

/*
// Copyright 1996, 1997 by Craig Estey -- See the file COPYING for details
*/

#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <asm/system.h>

#include <src/irqhigh.c>

/* overridden by insmod command line (e.g. "priority=3,14") */
u_long priority[] = { IRQHIGH_MST_DFT, IRQHIGH_SLV_DFT };

/* yes_we_used_it -- allow us to compile */
extern inline void
yes_we_used_it(void *x)
{
}

#ifdef NPR
#define zprtx				printk_npr
/* printk_npr -- all zprtx's become nulled */
static int
printk_npr(const char *fmt,...)
{
	return 0;
}
#else /*NPR*/
#define zprtx				printk
#endif /*NPR*/

/* init_module -- called by modules package when installing the driver */
/* RETURNS: error code */
int
init_module(void)
{
	int err;
	int idx;
	char *cp;
	u_long flags;
	u_char vals[2];

	err = 0;

	yes_we_used_it(irqhigh_calc);

	/* grab data from insmod command line */
	for (idx = 0;  idx <= 1;  ++idx)
		vals[idx] = priority[idx] & 0x0F;

	do {
		/* check the sanity */
		cp = irqhigh_insane(vals[0],vals[1]);
		if (cp != NULL) {
			zprtx("irqtune/%s: SANITYERROR %u/%u -- %s\n",
				IRQTUNE_VERSION,vals[0],vals[1],cp);
			err = -EINVAL;
			break;
		}

		zprtx("irqtune/%s: setting system IRQ priority to %u/%u\n",
			IRQTUNE_VERSION,vals[0],vals[1]);

		/* perform the set */
		save_flags(flags);
		cli();
		err = irqhigh_set(1,vals[0],vals[1]);
		restore_flags(flags);

		/* insure that things worked (should not occur if irqtune invoked us */
		/* as it does the exact same check) */
		if (err) {
			zprtx("irqtune/%s: ERROR expected %u/%u but got %u/%u\n",
				IRQTUNE_VERSION,vals[0],vals[1],
				irqhigh_list[0],irqhigh_list[1]);
			break;
		}
	} while (0);

	return err;
}

/* cleanup_module -- called by modules package when removing the driver */
void
cleanup_module(void)
{

	zprtx("irqtune/%s: module cleanup\n",IRQTUNE_VERSION);
}
irqtune/src/Makefile100644    155    764        5242  6414542140  12727 0ustar  caeengr# src/Makefile for irqtune

# NOTE: remake from the top directory -- not here
ifndef IRQTUNE_VERSION
# the next line is designed to cause an error
_run_from_the_top_directory_as_irqtune_version_is_not_defined_
endif

# sub-directories
SDIR = $(IRQTUNE_HOME)/src
PROTO = $(IRQTUNE_HOME)/include/P

# modules
MODTAG = irqtune_mod
MODULES = irqtune_mod.o irqtune_npr.o
KOBJS = load_mod.o load_npr.o kvers.o
KDEFS = \
	-DIRQTUNE_VERSION=\"$(IRQTUNE_VERSION)\"

CDEFS = -DMODTAG=\"$(MODTAG)\" \
	$(KDEFS)

# things to install
TARGETLIST = $(MODULES) irqtune

WARN = -Wall -Werror -Wno-format
CFLAGS_COM = -O \
	-I$(IRQTUNE_HOME)/include -I$(IRQTUNE_HOME)/include/P -I$(IRQTUNE_HOME) \
	$(WARN) $(CFLAGS_EXTRA)
CKFLAGS = $(CFLAGS_COM) -D__KERNEL__ $(KDEFS)
CFLAGS = $(CFLAGS_COM) $(CDEBUG)
ifeq "$(CDEBUG)" ""
STRIP = -s
endif

LIBSFILES := $(shell find $(IRQTUNE_HOME)/lib -name '*.c' -print)

# -----------------------------------------------------------------
sbin: $(TARGETLIST)

# make kernel version (only valid revision and syntax are required)
kvers:
	echo 'char kernel_version[] = "'1.0.0'";' > kvers.c

# WARNING: if you think this will fix any genuine error other than the warning
# message, you should RTFM!  if it does, file a bug report!
kvers_stop_insmod_pedantic_rev_warning:
	echo 'char kernel_version[] = "'`uname -r`'";' > kvers.c

# compile the local site version
kvers.o: kvers.c
	cc -c kvers.c

# -----------------------------------------------------------------
# standard loader
load_mod.o: $(SDIR)/load.c $(SDIR)/irqhigh.c
	cc -c $(CKFLAGS) -o $@ $(SDIR)/load.c

# loader without printk's
load_npr.o: $(SDIR)/load.c $(SDIR)/irqhigh.c
	cc -c $(CKFLAGS) -DNPR -o $@ $(SDIR)/load.c

# standard module
irqtune_mod.o: load_mod.o kvers.o
	ld -r -o $@ load_mod.o kvers.o

# module without printk's
irqtune_npr.o: load_npr.o kvers.o
	ld -r -o $@ load_npr.o kvers.o

# -----------------------------------------------------------------
irqtune.o: $(SDIR)/irqtune.c $(SDIR)/irqhigh.c $(LIBSFILES)
	cc -c $(CFLAGS) $(CDEFS) $(SDIR)/irqtune.c

irqtune: irqtune.o kvers.o
	cc $(STRIP) -o irqtune irqtune.o kvers.o

# -----------------------------------------------------------------
install:
	$(INSTALLER) -i $(INSTALL) $(SBIN) $(IRQTUNE_HOME)

uninstall:
	/bin/sh -c "cd $(SBIN) ; rm -f $(TARGETLIST)"

clean:
	rm -f $(TARGETLIST) $(KOBJS) irqtune.o

# -----------------------------------------------------------------
# remake function prototypes (needs the prototype program)
# this will fail for lack of it
proto:
	cp $(XI)/softnet/{types,macros}.h \
		$(XI)/softnet/{zprt,zprtdef,zprtundef}.h \
		$(IRQTUNE_HOME)/include/softnet
	cp $(GEN)/comlib/zprt.c $(IRQTUNE_HOME)/lib
	rawtype -C$(IRQTUNE_HOME) -I$(PROTO)
irqtune/src/irqtune.pod100644    155    764      127510  6366006366  13540 0ustar  caeengr=title IRQTUNE -- A Linux IRQ Priority Optimizer
=code1
=head0 ${I:IRQTUNE} -- A Linux IRQ Priority Optimizer
=center1
=I1
Copyright 1996, 1997 by Craig Estey.
=br
=B1
irqtune version ${IRQTUNE_VERSION}
=B0
=br
Last updated: ${DATELONG}
=br
See the ${SCT:changes} section at the bottom of this document.
=br
${SCT:toc}
=I0
=center0

${I:irqtune} changes the IRQ priority of devices to allow devices that require
high priority and fast service (e.g. serial ports, modems) to have it.

=B1
With ${I:irqtune}, a 3X speedup of serial/modem throughput is possible.
=B0

=head1 Where do I get ${I:irqtune}?
${I:irqtune} is free software under the terms and conditions of the GNU Public
License.  See the file COPYING, included in the distribution, for details.
=over
=item
The author is Craig Estey, (${cae@best.com}).
=item
This FAQ is available online via
${http://www.best.com/~cae/irqtune}.  This is the most authoritative reference
and will always contain the most up-to-date information.
=item
The distribution is a gzipped tar archive that contains all programs, sources,
and this FAQ (in both HTML and text versions).  It is available from:

=SS1
=over
=item
${http://www.best.com/~cae/irqtune/irqtune.tgz}
=item
${ftp://shell5.ba.best.com/pub/cae/irqtune.tgz}
=back
=SS0
=back

=head1 How do I know if I need ${I:irqtune}?
${B:You are running Linux on an x86 PC, other architectures to be implemented}
${B:later--Sorry.}

=B1
You probably need ${I:irqtune}, if you are experiencing any of the following:
=B0
=over
=item
SLIP/PPP transfers seem slow.  For example, using a 28.8 (or better) modem,
the effective throughput is approximately 700 bytes/second instead of the
expected 2500 bytes/second.
=item
A running serial or SLIP/PPP connection is slow, drops data, hangs, or
times out.
=item
Netscape hangs mysteriously or stalls when trying to access a web page.
=item
Equivalent serial/PPP programs under Windoze run much faster than under Linux.
=item
Disk accesses seem to interfere with SLIP/PPP.
=item
Interrupt handlers for specialized, time critical devices don't get control
when they need to.
=back
=head1 What is actually happening to cause these problems?

When the PC boots Linux, the timer is
given, by default, the highest IRQ priority in the system (it's IRQ 0 and thus,
priority 0).  On a standard configuration, the serial ports are priority
11 and 12!!!  This means that 10 other devices have higher priority.

=head3 Q: So what does IRQ priority do?

When multiple devices are in contention to interrupt the CPU, their priority
decides which interrupts will occur in what order.

=head3 Q: When does this contention occur?

After an arbitrary period of having interrupts disabled (e.g after a ${I:cli}),
at the point where they're reenabled (${I:sti}).  This can happen in several
places:
=over
=item
In an ISR that runs with interrupts locked, it happens in the ${I:epilog}, just
before attempting to execute the ${I:bottom-half}.
=item
The ${I:bottom-half} itself may do a lock and unlock.
=item
When a task that enters the kernel to do a system call, the system call
handler may lock and unlock interrupts briefly.
=item
Almost anywhere in the kernel are brief periods where it does a ${I:cli} to
lock interrupts and then an ${I:sti} to unlock them again.
=item
Under Linux, from the moment the first instruction of the ISR ${I:prolog} is
executed until an ${I:sti} is done (This occurs even in ${I:slow} interrupts
where the ${I:prolog} does an ${I:sti} after just a few instructions).
=back
=head3 Q: If there are multiple interrupts now pending, \
which one gets the service, \
the serial or some other?

In the default configuration, the serial ISR will usually lose as it's
priority 11.

=head1 How does irqtune help this?

${I:irqtune} gives priority 0 to whatever device we specify.  If we
specify
a serial device, ${I:irqtune} guarantees that the serial ISR gets control
whenever a contention occurs.

=head1 Why does the serial interrupt service require the highest priority?

=head3 Q: Why does the serial device merit such special treatment?

Serial devices are somewhat unique.  Even though they have one of
the slowest data rates (relative to a disk), they are the largest consumer
of interrupts and are extremely sensitive to ${I:interrupt latency} (the time
from when a device yanks the IRQ line until its ISR is executed).

=head3 Q: Could you give a concrete example of this?

=over
=item
For a modem running at 33.6, we can have a peak maximum (with
compression) of 6700 bytes/second.  The serial driver programs the silo to
interrupt after 8 bytes, leaving a latency window of 8 bytes.  This means
that when the serial port yanks its IRQ line, it can still absorb 8 more
characters before its buffer will overflow and data will be dropped
=item
In terms of time, this means that the maximum that the serial ISR may be
delayed is
(8 / 6700) seconds or 1194 microseconds.  It also means that the serial ISR
will require 838 interrupts/second.
=item
Currently there are 52 devices that install their ISR with the SA_INTERRUPT
option.
This means that they wish to run with interrupts disabled.
I have not looked at all the devices, but just
assume for the moment that all will run with interrupts locked for an
arbitrary period.
=item
Assume we've got 4 of them pending (remember,
at ${I:higher} priority).  Assume that they will lock interrupts individually
for 320, 300, 190, and 500 microseconds, respectively.  Assume that the
serial ISR also wants an interrupt.
=item
This means that the serial ISR will have to wait for (320 + 300 + 190 + 500)
or 1310us
for these other higher priority ISR's to run to completion.  This is greater
than the maximum of 1194 us.
=item
With internal
modems, we probably just see start/stop behavior causing a slowdown.
With an external modem, ${B:data will be dropped}.  This will cause PPP to see
a CRC error and request transmission.  Remember, the ${I:entire} packet must be
retransmitted, which means we just wasted 296-1500 bytes (depending on the
selected MRU).
With an MRU of 1500 bytes, we just
wasted 23.4% of the bandwidth in a given second--all for the loss of a single
byte!
=item
Worse yet, consider a 115 Kbps ISDN card that is
masquerading as a serial device ${I:(Yes, I know it should be a DMA device)}.
In this case, the maximum delay the serial ISR can wait is 695 us.  And that's
just one ISDN channel.  Try adding the other and, well, ${I:golly :-)}.
=back

=head3 Q: In this example, how would boosting serial IRQ priority help?
=over
=item
If the serial IRQ had priority 0, it would get in ${I:before} the others.  It
could also ${B:re-interrupt} after any individual lockout window.  Thus, the
maximum
it would be forced to wait would be largest individual time, not the
${B:summation} of all of these times.  In this example, this means 500 us.
which is now within the 1194 us. maximum for the serial ISR.
=item
It has been my experience that the serial device ${B:must always} win these
battles for contention.  When serial devices don't get what they ${I:need},
when they need it, they slow horribly or drop data outright.
=back

=head1 Isn't that example very ${I:unlikely} under Linux?

${I:Unlikely} doesn't mean never.  There are places were the contention period
${B:must} occur, no matter how we program the CPU.

Variations in CPU speed,
RAM size, RAM speed, cache size, disk speed, disk rotational position,
number and type of other devices, system workload, etc, etc etc, all
contribute to variations of order and timing of internal OS events.

${I:Unlikely} on one system may mean 1/1000th % chance.  On another system, it
may mean ${I:happens 50 times/second}.  Beyond a certain point, it all comes
down to ${I:measurement}.

Tight, accurate, repeatable measurement is the key
to system tuning.  If we can't measure it, we can't tune it.  Once we
${I:can} measure 
these things, we can then ${I:try} various combinations until we achieve
our desired results.  It can often be pointless to guess at performance.

In fact, the interrupt disable windows themselves are used to prevent data
corruption caused by various parts of the kernel that try to update a data
structure simultaneously and get corrupted.  Many of these windows are put
there in the ${I:unlikely} case that such corruption would occur.  In this
context, ${I:unlikely} is ${B:never} considered a reason to forego interrupt
locking.  Eliminating a necessary interrupt lock window could result in
kernel panics, RAM corruption, disk data corruption, etc.

=head1 Doesn't this hurt the performance of other devices?

${B:Not really}.

In actual practice, most devices don't even notice the difference.
Most other
devices (e.g. disks, tape, ethernet) are ${I:DMA} devices.  The ${I:DMA} does
most of the work, thus greatly reducing their need for interrupts.  If the
device allows a request queue, it may function autonomously on several
requests, producing only one interrupt for the entire batch.

Furthermore, serial interrupt services are, themselves, ${I:very} fast.  They
slam their data as quickly as possible and get out ASAP.  No fancy
calculations, just the minimum, mindless data transfer.  Almost everything
else is handled later, in the ${I:bottom-half} with interrupts enabled.  In
fact, a serial ISR may have to re-interrupt it's own ${I:bottom-half} several
times.

Those devices that
${I:do} experience some slight slowdown are more likely to have long interrupt
disable windows themselves.  Having several smaller ${I:cli/sti} windows is
much better than one large ${I:cli/sti} window--It's just harder to program.

=head3 Q: But suppose I want a balanced priority system?

Well, actually a ${I:prioritized} system behaves like a ${I:balanced}
system--most of the time.  This occurs when all devices have short interrupt
lockout windows and short ISR execution times.  The priority mechanism is
like a safety valve--it only really matters when some device or combination
of devices has held interrupts locked for an extended period of time.

=head3 Q: But doesn't that seem ${I:unfair} to other devices?

When a disk ISR gets delayed,
that's all that happens, a slight delay--disks and tapes are ${B:not} real-time
devices.  When a serial ISR gets delayed, data is destroyed--serial devices
${B:are} real-time devices that dictate the cadence of the entire system.

=B1
It may sound cruel, but you just can't be ${I:fair}.
=B0

And speaking of sound, if the sound card gets delayed,
we hear an annoying pop right in the middle of our favorite piece of music.

These are real-time devices that can ${B:not} tolerate excessive delays.  If we
must defer some less time critical devices to meet the minimum real-time
criteria of devices, then that's a bargain.

=head3 Q: But suppose I really want both fast serial and fast disk?

Ultimately, it's a bit of a compromise.  Which is better:
=SS1
=over
=item
Reliable serial and ${I:slightly} slower disk.
=item
${I:Slightly} faster disk and ${I:unreliable} serial/modem support.
=back
=SS0
=I1
When paying an ISP for Internet access in $$$/hour, it's an easy decision :-).
=I0

=head1 Isn't this IRQ priority thing a bit of a new idea?

No.  It's actually an old idea.  I've been doing device drivers since 1977
and Unix kernel work since 1981.  I've personally written 8 serial drivers
have used this many times commercially.  Giving the serial device the
highest priority is actually standard practice in many systems.
${I:With a 4Mhz CPU, these problems used to occur at 1200 baud :-)}

=head1 How do I install ${I:irqtune}?
=setenv topdir /usr/local
=setenv irqtune_home ${topdir}/irqtune

=head3 Q: Where should I place ${I:irqtune} files?
=SS1
=over
=item
Decide what directory you would like to ${B:contain} ${I:irqtune}'s
home directory.
Some good choices are:
${B:/usr/local},
${B:/usr/lib},
${B:/usr/lib/hwtools},
${B:/home}.
=item
Exactly where depends upon your local conventions.
=item
In this example, we'll use ${B:${topdir}}.
=back
=SS0

=head3 Q: How do I unpack the archive?
=SS1
=over
=item
Go to the containing directory.
=txt2
cd ${topdir}
=txt0
=item
Unpack the tar file:
=txt1
tar zxvf irqtune.tgz
=txt0
=item
This will create a directory, ${B:irqtune} in ${B:${topdir}}.  This is
${B:${irqtune_home}}.  We will call this ${B:IRQTUNE_HOME}.
=back
=SS0

=SS1
=I1
Note: If tar's
=I0
${B:z}
=I1
option has problems:
=I0
=over
=item
An alternate unpack command:
=txt2
gzip -d < irqtune.tgz | tar xvf -
=txt0
=back
=SS0

=head3 Q: How do I do a simple installation?
=SS1
=over
=item
Go to the ${B:IRQTUNE_HOME} directory:
=txt2
cd ${irqtune_home}
=txt0
=item
To install ${I:irqtune}, enter:
=txt1
make install
=txt0
=item
This will install the files:
=txt1
/sbin/irqtune
/sbin/irqtune_mod.o
/sbin/irqtune_npr.o
=txt0
=back
=SS0

=head3 Q: Why are .o files being placed in the /sbin directory?

=I1
As a note to purists, the installation directory is completely arbitrary.
${B:/sbin} is short, sweet, and easy to type.
=I0

The standard convention would be to install ${B:irqtune} as ${B:/sbin/irqtune}
and the .o files as, say, ${B:/usr/lib/irqtune/*.o}.
${I:irqtune} uses a slightly different convention.  It wants all installed
files to be in the same directory.  
This works fine because argv[0] will
point to the .o files.  This also allows:
=SS1
=over
=item
Multiple versions of ${I:irqtune} to be installed simultaneously (in different
directories).
=item
Simplifies testing of new versions.
=item
Provides better assurance that the built version is correct.
=item
Using one directory produces less clutter.
=item
One directory is more portable across all the myriad kernel revisions.
=item
Future versions of ${I:irqtune} may imbed the .o's directly into ${B:irqtune}.
=back
=SS0

=head3 Q: What if I really don't want .o files in ${B:/sbin}?

If placing .o files in ${B:/sbin} is deemed to be an
anathema, we have two options:
=SS1
=over
=item
Simply use another directory in place of ${B:/sbin}:
=txt1
make SBIN=/whatever install
=txt0
=item
Install with a stub (This will install /sbin/irqtune as a shell script and use
${B:IRQTUNE_HOME}/sbin/irqtune_*.o):
=txt1
make INSTALL=sh install
=txt0
=back
=SS0

=head3 Q: Are there any special considerations for this alternate \
installation method?

Yes.  If the shell/stub installation method is used:
=SS1
=over
=item
${B:IRQTUNE_HOME} must not be removed.
=item
If using ${I:irqtune} from an /etc/rc.d/rc.* file ${B:and} ${I:irqtune} will be
invoked ${B:before} secondary mounts are done, ${B:IRQTUNE_HOME} should be
placed on the root device.
=back

=head1 How do I use ${I:irqtune}?  Don't I have to rebuild my kernel?
No, we do ${B:not} have to rebuild the kernel.  ${I:irqtune} uses ${I:insmod}
and
${I:rmmod} to dynamically load and unload a kernel module.  But it is correct
to sense that irqtune is a kernel patch.

=head3 Q: Ok, if it's a kernel patch, why not just issue a kernel patch like \
everybody else does (e.g. diff -u output)?

${I:irqtune} will work even if we don't have the kernel source loaded.  It uses
${I:insmod} to load the patch, invoke it, and then unload it.  The IRQ priority
changes will last so long as the kernel is booted.

=head3 Q: How do we invoke it?

${I:irqtune} takes two arguments optional arguments:
=over
=item
irqtune ${I:master} ${I:slave}
=back
The default is ${I:3 14} which will work for many standard configurations.
See ${SCT:non_standard_irq} for details.
=over
=item
Here is the usage output from irqtune:
=include -txt -exec ./sbin/irqtune -h
=back

=head3 Q: Could we do this from my /etc/rc.d/rc.local file?

Yes. Just add a ${B:/sbin/irqtune} line to this file and we're
in business.
We may also issue another ${I:irqtune} command at any time.

=head3 Q: What if irqtune fails to load?
See the ${SCT:incompat} section.

=head3 Q: After ${I:irqtune} sets a priority, how can we query the results \
later?

=B1
We can't.
=B0

Due to a limitation of the PC interrupt hardware, it is ${B:not} possible
to read back values set previously.

${I:irqtune} will attempt to place a message in the system log
(/usr/spool/syslog/syslog) when it changes the configuration.  Examining this
log file, or simply invoking ${I:irqtune} again,
may be the best ways to work around the hardware limitations.

=I1
Note: Some users have tried to use the "-n" option, thinking it
will act as a "query" mode.  This option is used, primarily, to generate
examples in this document and will not have the desired effect.
=I0

=head1 -Nnon_standard_irq What about my non-standard hardware configuration?
${I:irqtune} defaults for a standard IRQ configuration.  It assumes that the
highest priority device should be on IRQ 3.  This is normally the first serial
port on standard configurations, which is what you want.

=head3 Q: How do I determine what my IRQ configuration is?

=I1
NOTE: For brevity, we've combined the non-sorted and sorted output in
these examples.
=I0
=over
=item
Just type ${B:/sbin/irqtune -n -o} and we'll get something like:
=include -txt -exec -T irqdoc -exec nop -o
=back

=I1
NOTE:
${B:/proc/interrupts}, and therefore irqtune, only reports on active devices.
So to scope out
the serial IRQ's, ideally, you'd have X Windows up with your serial mouse and
be connected via PPP to the net.
=I0

=head3 Q: OK, we've got the output from /sbin/irqtune -n -o, \
what do we do with it?

The leftmost number is the IRQ number.  The next number is the priority.
The rightmost column is the ${B:internal}
device name (not to be confused with /dev names).  In the above case, the two
serial ports are on IRQ 3 and IRQ 4.  Just use the lower number, in this
case 3:
=over
=item
${B:/sbin/irqtune} ${I:3}
=back
This sets IRQ 3 to the highest priority.

=over
=item
After this command, the IRQ priorities are now:
=include -txt -exec -T irqdoc -exec nop 3
=back

=head3 Q: BTW, What's the cascade device I saw in the output of irqtune?

Glad you asked.  There are actually two interrupt controllers, a ${I:master}
and a ${I:slave}.  The ${I:slave} is ${I:cascaded} to the ${I:master} via its IRQ 2.
The ${I:master} controls IRQ's 0-7 and the ${I:slave} controls IRQ's 8-15.

You actually may select two high IRQ priorities, one for the ${I:master} and one
for the ${I:slave}.  ${I:irqtune} defaults the ${I:slave} to IRQ 14, which is
normally the disk controller.

In fact, ${I:cascade} is sort of a "zero width" device as it does not
contribute to interrupt latency.  Setting the ${I:cascade} to top
priority on the ${I:master} has an interesting effect which we'll see shortly.

=head3 Q: But we've also got an Ethernet controller on IRQ 12.  What about that?

In this case, we might want to use:
=over
=item
${B:/sbin/irqtune} ${I:3 12}
=back
because we want our ethernet card to have a higher priority than the disk
controller.  Actually if we did have this configuration, setting 3 14
(the default) would make the ethernet card, the lowest priority device in the
system.

=over
=item
The resulting priority would be:
=include -txt -exec -T irqdoc -exec nop 3 12
=back

=head3 Q: What about the serial multiplexer card on IRQ 11?

This is a bit tricky because now we've got a serial device on
the ${I:slave} controller.  It would be much better to put all serial cards on
the ${I:master} controller.  Things would stay much simpler.

In this case we would want to use:
=over
=item
${B:/sbin/irqtune} ${I:11}
=item
The resulting priorities would be more complex and would result in something
like:
=include -txt -exec -T irqdoc -exec nop 11
=back

=head3 Q: Wait a minute.  didn't we just specify a ${I:slave} IRQ number \
as the ${I:master} to ${I:irqtune}?

Yes, this is shorthand way of saying ${I:2 11}.  You can make a ${I:slave}
device top priority, but we get no options for the ${I:master} IRQ.  It
will always be ${I:2}, the ${I:cascade} device.  Remember, the ${I:cascade}
device contributes no latency delay by itself.

=head3 Q: So why is this configuration so bad?

Well, we boosted the priority of the serial multiplexer at the expense of the
regular serial ports.  The only way to allow all serial ports equally high
priority is to group them on consecutive IRQ's and set the high priority for
the lowest of those IRQ's.

=head3 Q: How can we fix this with software?

=B1
We can't.

We're limited by the architecture of the PC and its interrupt controllers.
We must change the IRQ of a device by physical restrapping--we can't
do it by reprogramming the priority alone.
=B0

We'll go back to the earlier example.  We'll wave a magic wand and
${I:Poof!}--assume we just restrapped the serial multiplexer to IRQ 5:
=over
=item
${B:/sbin/irqtune} ${I:3}
=item
The resulting priorities would be:
=include -txt -exec -T irqdoc -exec muxfix 3
=back

=head3 Q: Could we do more of this restrapping, say, with the ethernet \
controller?

Sure.  Waving the wand again, we restrap the ethernet card to IRQ 6.
=over
=item
${B:/sbin/irqtune} ${I:3}
=item
The resulting priorities would be:
=include -txt -exec -T irqdoc -exec ethfix 3
=back

=head3 So in order to get the best overall system, we may need to change \
IRQ priority ${I:and} physically change the hardware IRQ configuration?

${B:${I:Exactly}}.

Different systems may have highly different criteria for what
is optimum.  It is, ultimately, a choice that each system administrator must
make based upon the specific requirements for the particular system in
question.  We can only provide tools to do the job, but the final choice
is ultimately decided on a case-by-case basis.  There is no
=I1
one size fits all
=I0
solution.

=head1 -Nincompat What about ${I:irqtune} load failures or \
incompatibilities with kernel revisions?

=head3 Q: What's the bottom line?

${I:irqtune} makes every attempt to load its kernel module.
${I:irqtune} probes the kernel, /proc/ksyms, and ${I:insmod}.
It attempts to detect, correct, or work around any difficulties.  If the
problems are truly severe, ${I:irqtune} will report this also.
Normally, ${I:irqtune} probes silently, only reporting the results of
the local system configuration if there's an non-recoverable error.

=over
=item
To show what ${I:irqtune} actually checks for each time it's invoked,
here is the full error output (-e) from irqtune:
=include -txt -exec -T irqdoc -exec -raw nop -e
=item
${I:irqtune} probes report ${B:YES/NO} for informative messages.
These may be ignored.  ${I:irqtune} will automatically compensate for any
irregularities found.
=item
${I:irqtune} probes report ${B:OK/WARNING} for problems that ${B:may} prevent
proper operation.  These may require changes to the local configuration.
Generally, these may be ignored unless ${I:irqtune} fails to load.
=item
${I:irqtune} probes report ${B:OK/ERROR} for problems that ${B:will} prevent
proper operation.  These will require changes or upgrades to the local
configuration.
=item
If it is believed that the probes are reporting errors when none actually
exist,
the ${B:-f} option may be used to force ${I:irqtune} to continue anyway.
=back

No matter what happens with probes or loads, ${I:irqtune} will report the final
completion status as its last line: ${B:complete} or ${B:error}.

=head3 Q: What should be checked first?
=over
=item
If we did a simple installation, we must specify the full pathname, even
if ${I:irqtune} is placed in a directory that is in $PATH.  This is required
because ${I:irqtune} uses argv[0] to locate its ${B:irqtune_mod.o} file.
=item
${B:/sbin} ${I:should} be in $PATH--this is the probable place for
${I:insmod}.  As a convenience, ${I:irqtune} will add ${B:/sbin} to $PATH
automatically.
=item
Be sure that the kernel was built with modules support (CONFIG_MODULES)
enabled.  ${I:irqtune} will probe for and report this condition.
=back

=head3 Q: What if the current kernel revision is different from the kernel \
revision in the prebuilt modules?

=B1
This does not matter.
=B0
${I:irqtune} is 99.44% kernel revision independent.
It is almost never necessary to rebuild the prebuilt modules.  If
${I:irqtune} fails to load the modules,
consider everything in this section carefully before rebuilding ${I:irqtune}.

=SS1
Notes to programmers:
=over
=item
The "kernel_version[]" does ${B:not} need to match the kernel revision for a
module to load successfully.
=item
A module does ${B:not} need MODVERSIONS to load in a MODVERSIONS kernel.
=back
=SS0

=I1
Rebuilding the binaries before exploring the other options is a lot like
Vonnegut's ${B:OFF} switch--it's comforting but not connected to anything :-)
=I0

=head3 Q: Are there any kernel revisions that ${I:irqtune} won't work with?

When ${I:irqtune} was first released, some experimental changes were made
to the kernel to solve the IRQ priority problem by use of a round-robin,
balanced priority system that was incompatible with ${I:irqtune}.  These
changes were ultimately removed but ${I:irqtune} will not work with kernel
revisions 2.0.15 to 2.0.18.  ${I:irqtune} will detect this condition and
report an error.  See the ${SCT:download} section.

=head3 Q: Are there any ${I:insmod} revisions that are incompatible?

${I:irqtune} first trys to load ${I:irqtune_mod.o} and falls
back to ${I:irqtune_npr.o} if it detects a load error in ${I:insmod}.

=SS1
Some versions of ${I:insmod} have severe difficulty loading modules when the
kernel is using MODVERSIONS.  There is a known bug in ${I:insmod}:
=over
=item
2.1.X ${I:insmod} prior to 2.1.34 (e.g. 2.1.23)
=item
2.0.X kernel
=item
kernel built with CONFIG_MODVERSIONS
=back
=SS0
Loading ${I:irqtune_mod.o} will crash ${I:insmod},
partially lock up ${I:irqtune}'s module.  ${I:irqtune} will detect this and
skip the ${I:irqtune_mod.o} loading entirely.

Generally, we should not use an older ${I:insmod} with a newer kernel
(e.g. using a 2.0.X ${I:insmod} on a 2.1.X kernel).  ${I:irqtune} will detect
and report this.

If ${I:insmod} still has difficulties, we may want to upgrade it to 2.1.34
(or better).  Newer versions of ${I:insmod} are guaranteed to be backward
compatible to older kernels.
This will increase the probability that the ${I:irqtune_mod.o}
will load and ${I:irqtune} will not have to fallback to ${I:irqtune_npr.o}.
Note: ${I:insmod} is actually part of the ${I:modutils} package.  ${I:modutils}
under 2.0.X is called ${I:modules}.  See the ${SCT:download} section.

=head3 Q: What is the difference between ${I:irqtune_mod.o} and \
${I:irqtune_npr.o}?

The only kernel symbol that ${I:irqtune}'s kernel module (${I:irqtune_mod.o})
uses is ${I:printk} (to print a confirmation message to syslog).
The ${I:irqtune_npr.o} module
is exactly the same as ${I:irqtune_mod.o} except that it does ${B:not} use
${I:printk}.
Since ${I:irqtune}
pre-checks all parameters before attempting to load the kernel module, the
confirmation message is a nicety but not a necessity.

=head3 Q: What if we don't have ELF binary support?

=I1
Well, we should upgrade the kernel as ELF binaries are cool :-).
=I0
But if that's not possible, we'll just have to recompile ${I:irqtune} to
create ${I:a.out} binaries.  This is,
perhaps, the only justification for rebuilding ${I:irqtune}.
Just be sure
that ${B:/usr/src/linux/include} is installed.  The exact procedure for building
${I:a.out} binaries can vary with compiler revision, so it's important to check
the documentation on this (a parameter or two may need to be added).
=SS1
=over
=item
Then, just type:
=txt1
make warp9
=txt0
=item
Here is the makefile's own documentation:
=include -txt -exec make
=back
=SS0

=head3 Q: What about IRQ sharing of serial ports?

Under the 2.0.X (and later) kernels, use of IRQ sharing will defeat IRQ
priority because
the serial port ISR's are installed as ${I:slow} rather than ${I:fast}
interrupts (e.g. they don't use the SA_INTERRUPT flag).

=SS1
=over
=item
Change the serial port IRQ configuration so that ports don't share
IRQ's
=item
The other option is a kernel source patch to ${B:drivers/char/serial.c}:
${PP}
Change the following line:
=txt1
#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
=txt0
and replace it with:
=txt1
#define IRQ_T(info) (((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : 0) | SA_INTERRUPT)
=txt0
=back
=SS0

Under earlier kernels this is not a problem because the serial ISR was always
installed with SA_INTERRUPT.

=head1 What about hardware/config problems?

=head3 Q: What if the serial port doesn't work?
=over
=item
The First Law of Computing:  Make sure it's plugged in.
=item
Double check the strapping for port and IRQ assignments.  Verify that the
port/IRQ desired is actually the one that is strapped.
Some serial ports will appear to work even if the IRQ is wrong--they will just
be ${I:extremely} slow.
Some Plug-N-Play (PnP) ports may need to be explicitly strapped.
=item
Check for port/IRQ conflicts with other devices.  Serial ports may share IRQ
assignments but sharing an IRQ between a serial port and something else (e.g. an
ethernet card) is fraught with peril.  See the previous section about serial
IRQ sharing under 2.0.X kernels.
=item
Verify that the IRQ that the kernel reports as a result of auto-detection is
the IRQ that was strapped.  Some serial ports or hardware configurations can
fool the auto-detect.  If necessary, use the ${I:${B:setserial}} program (in
${B:/etc/rc.d/rc.local}) to force
the kernel port/IRQ settings to match the hardware strapping.
=item
Verify that ${I:irqtune} got the correct IRQ numbers for the specific
configuration.
For example, suppose our primary serial port is on IRQ 3, but we gave
${I:irqtune} the value ${I:4}.  We just made the serial device on IRQ 3 into
priority 14, not priority 0.
=item
Verify that the serial port baud rate is set correctly.  That is, it is the
same as what the modem expects.  The serial port baud rate also has performance
implications (See ${SCT:other_baud} for details).
=back

=head3 Q: What if PPP doesn't work?

See the PPP man page and PPP-Howto for best information, but some recommended
options:
=SS1
=over
=item
asyncmap 0
=item
crtscts
=item
defaultroute
=item
modem
=item
mru 296 mtu 296
=item
passive
=back
=SS0

AT-like modems have a special character to escape from data mode to command
mode.
To avoid confusion here, we'll call this modem escape character a ${I:guard}
character.

The default ${I:guard} character is '+' (decimal 43, hex 2B).
Normally, 3 such characters are required within a special timing sequence.

Although it is ${I:unlikely}, it is still possible that some PPP packets could
generate the ${I:guard} sequence inadvertantly.  To prevent this, we may want
to inhibit the generation of the ${I:guard} character in a data sequence.  To
do this,
we would add the additional PPP option:
=SS1
=over
=item
escape 2B
=back
=SS0

Since '+' is a common ASCII character (PPP escaped characters generate two
characters), we may wish to use a less common value
for the ${I:guard} character.  For example, a less common value might be
(decimal 200, hex C8).  We would add an ${B:ATS2=200} command to our modem
dialer script and change the PPP escape option to ${B:C8}.

=head3 -Nhardware_ppp_flag Q: Why does PPP ${I:consistently} drop every \
second packet sent from Linux, resulting in a 50% packet loss?

=B1
Some braindamaged PPP implementations do not handle PPP ${I:flag}
optimization!
=B0

=SS1
The PPP protocol uses a ${I:flag} byte to separate packets.  Each packet
begins with a ${I:flag} and ends with a second ${I:flag}.
=over
=item
Loosely, each packet looks something this:
=txt1
<FLAG> <PACKET (e.g. header, data, CRC)> <FLAG>
=txt0
=item
Thus, a sequence of packets might look like this:
=txt1
<FLAG><PACKET1><FLAG> <FLAG><PACKET2><FLAG> <FLAG><PACKET3><FLAG> ...
=txt0
=item
However, as an optimization, the PPP protocol permits trailing and
leading
${I:flag} bytes to be combined within a sequence of packets:
=txt1
<FLAG> <PACKET1> <FLAG> <PACKET2> <FLAG> <PACKET3> <FLAG> ...
=txt0
=back
=SS0

Although the PPP protocol ${B:requires} implementations receiving packets
to handle ${I:flag}
optimization, some ${B:broken} PPP implementations do not understand it!

These implementations
see the trailing ${I:flag}, process the packet, then look for a fresh
${I:flag}.  They don't realize that the trailing ${I:flag} of PACKET1 may
perform double duty as the leading ${I:flag} of PACKET2.  They will
ignore all data until they see a new ${I:flag} (which, in this example, is the
${I:flag} between PACKET2 and PACKET3).  Thus, PACKET2 will be seen as noise
data and be ignored.  These implementations will
only see only the odd number packets (e.g. PACKET1, PACKET3, PACKET5, etc.),
resulting in a 50% packet loss!

Linux PPP implements ${I:flag} optimization correctly and enables it by
default.  As charity to others, Linux does allow ${I:flag} optimization to be
turned off, but currently, this this requires the kernel to be rebuilt.

=SS1
In Linux, to turn off ${I:flag} optimization on transmit, do the following:
=over
=item
Edit the file ${B:drivers/net/ppp.c}
=item
Change the line:
=txt1
static int  flag_time = OPTIMIZE_FLAG_TIME;
=txt0
=item
Replace this with:
=txt1
static int  flag_time = 0;
=txt0
=item
Rebuild the kernel.
=back
=SS0

=I1
Note: A better solution is to return the defective PPP implementation to the
vendor and demand a refund or replacement!
=I0

=head3 Q: How can we be certain that the PPP ${I:flag} optimzation loss is \
occuring?

By lowering the baud rate to something that is guaranteed not to drop
data due to speed problems (e.g. 300 baud).  If we get a consistent 50% loss at
this low rate, this is almost certain proof of the ${I:flag} optimization
problem.

=head1 What other performance software remedies must be done?

=head3 Q: What about using ${I:hdparm -u} to set the interrupt-unmask flag in \
the hard disk driver?

This is only necessary for the ${I:IDE} driver.  The SCSI driver has short
disable windows by default.  This will shorten the IDE interrupt disable
windows.

${I:${B:Beware:}} Without this option, IDE disk activity will almost certainly
cause serial data dropouts.  If we have an IDE disk, this is ${B:mandatory}.

=head3 Q: What about disabling Van Jacobsen header compression in PPP?

This reduces the amount of ${I:bottom-half} processing the system has to do at
the expense of larger packets being sent.  This may be helpful on slower CPU's
or heavily loaded configurations.

=head3 Q: What about adjusting the MRU/MTU numbers in PPP?

Reducing the MRU/MTU
to a minimum (296) reduces the ${I:bottom-half} processing and ${I:flip-buffer}
latency at the expense of
adding extra overhead bytes due to the reduced packet size.
The optimal value will vary from configuration to configuration.

${I:${B:Beware:}} Start with 296 as the optimal may not be 1500.

=I1
The ${B:flip-buffer} is a double buffer mechanism
in the serial/tty drivers through which all data ${B:must} pass.  It has a
fixed size of only 512 bytes.
MRU/MTU greater than the ${B:flip-buffer} size may create an internal
race condition that may cause dropouts on slower CPU's or heavily loaded
configurations.
=I0

=head3 Q: What about going to newer kernel revisions?

Although ${I:irqtune} will work surprisingly well with just about any kernel
revision, the low level IRQ handlers and device drivers have been vastly
improved in the 2.0.X kernels.  This will only improve ${I:irqtune}'s effect.

=head3 -Nother_baud Q: What about increasing the serial port baud rate?

The serial port baud rate should be high enough to support the maximum expected
transfer rate--but no higher.  Higher speed settings place extra strain on the
CPU, increasing the likelihood of overruns.

For a 33.6 modem, the minimum baud rate would be 38400.  However, with
compression, the expected transfer rate can be as high as 6 KB/second.  This
would require a baud rate of 57600.  This may strain the CPU, and since the
transfer rate is nominally about 4 KB/second, a lower baud rate may be a good
compromise.

The best way is to try several rates, then benchmark them to see which provides
the best overall performance.

${I:${B:Note:}}
Because of backward compatibility to older systems, we can't just
set 57600 directly with
${I:stty},
${I:kermit},
${I:pppd},
etc.  Specify 38400 to these programs, and use
the ${I:setserial} program with an option of ${B:spd_hi}.
For ISDN speeds, use ${B:spd_vhi}.  Other options are possible so be sure to
consult the manpage.

=head1 How can I tell if ${I:irqtune} actually did anything for me?

Well, first off, if PPP/SLIP was dying mysteriously, it will probably be more
reliable.

=head3 Q: How can we benchmark ${I:irqtune}?
Run without it and get a feel for the transfer rate:
=over
=item
Hit ${I:many} favorite web sites and note the transfer rates in
bytes/second.  Make life easy.  Netscape is at least one browser
that reports transfer rates in bytes/second in the status line.
=item
FTP reports the transfer time of a file in bytes/second.  Download (or upload)
a few files (300K or greater to smooth out the benchmark) and note the
transfer rates.  Use a mix of ${I:ascii} and ${I:binary} files that to see
the effect of modem compression.  ${I:Binary} won't compress too well so the
numbers will reflect the ${I:real} transfer rate.  ${I:Ascii} files which
typically compress 2:1 will up the ${I:effective} rate by 2X, making it
more stressful.
=item
Try several things of varying duration, different times of day, different
sites to accomodate variations in network loading.  Don't stop until
there is an average set of numbers that are more or less repeatable.
=back

Repeat this using ${I:irqtune} and note the transfer times again.

${I:NOTE: IRQTUNE just won't quit--if you want to test in the original mode}
${I:again, reboot the system first.}

=head3 Q: What if we still don't see any real improvement?

It's a matter of probability.  Performance measurement is as much art as
science.
=over
=item
We're much more likely to see improvement on a DX2/66 than a Pentium/166.
With the 166, we may be ${I:overpowering} the problem.  We'll still have a
problem, we just won't notice it as much because the Pentium has the
extra speed to burn.
${I:A badly tuned Ferrari may still outperform a well-tuned VW :-)}
=item
What problem was occurring before?  Which of the symptoms listed earlier is
happening?  If performance was 2500
bytes/second ${I:before} using ${I:irqtune}, we're less likely to notice the
smaller jump to, say, 2800.
=item
System loading is very light.  The problems that ${I:irqtune} will fix are
more likely to happen when more devices and more work are added.  On a certain
configuration, ${I:irqtune} had little effect.  However, when a brand new
SCSI DAT drive was added, serial performance nosedived.  Using ${I:irqtune}
brought performance back to the correct level.
=item
We may have a ${B:rogue} interrupt service that disables interrupts for
something outrageous, say 2 ms.  This is singularly longer than the 1194 us. in
the earlier example. ${I:irqtune} will still help, but the real solution here
is to reduce interrupt lockout times in the other device below the 1194 us.
threshold.
=back

=head1 -Ndownload Where can I find additional documentation or downloads?

=SS1
=over
=item
man pages for: ${I:insmod}, ${I:hdparm}, ${I:pppd}, ${I:setserial}
=item
The Linux Documentation Project
=over
=item
Homepage: ${http://sunsite.unc.edu/LDP}
=item
HOWTO's: ${ftp://sunsite.unc.edu/pub/Linux/doc/HOWTO}
=back
=item
The Linux Software Map (Hypertext)
=over
=item
${http://www.boutell.com/lsm}
=back
=item
Linux v2 Information HQ
=over
=item
${http:/www.linuxhq.com}
=back
=item
ftp.kernel.org
=over
=item
${http://ftp.kernel.org}
=back
=item
2.0.X kernel and compatible modutils downloads
=over
=item
${ftp://ftp.funet.fi/pub/Linux/kernel/linux/v2.0},
${ftp://ftp.funet.fi/pub/Linux/kernel/linux/v2.0/modules-2.0.0.tar.gz}
=item
${ftp://ftp.kernel.org/pub/linux/kernel/v2.0},
${ftp://ftp.kernel.org/pub/linux/kernel/v2.0/modules-2.0.0.tar.gz}
=back
=item
2.1.X kernel and compatible modutils downloads
=over
=item
${ftp://ftp.funet.fi/pub/Linux/kernel/linux/v2.1},
${ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.34.tar.gz}
=item
${ftp://ftp.kernel.org/pub/linux/kernel/v2.1},
${ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.34.tar.gz}
=back
=back
=SS0

== =head1 Didn't you give another explanation before, involving ${I:bottom-half} routines?
== ${B:Yes.}
== =over
== =item
== My error was that I had looked at all the existing IRQ code in Linux,
== when I was first
== investigating the serial problem.  I spaced out, misread the code, and
== concluded the EOI was done in the epilog.  I also was looking at the ${I:slow}
== interrupt prolog/epilog.
== =item
== Anyway, I then did measurements and verified that
== the serial ISR never got control at an effective rate higher than 1000
== bytes/sec.
== =item
== It was clear that something was holding up the serial ISR.
== =item
== This pointed to a priority problem.
== =item
== I coded up ${I:irqtune} and tried it.
== =item
== ${I:irqtune} worked.  I went from 700 bytes/second to 2500 bytes/second.
== =item
== I was so happy surfing at 3X my former speed, that I didn't bother to try
== to track down the culprit ${I:exactly} as I had used this priority fix before.
== =item
== After running it for about a month, I decided to package it up so others
== could use it.  In my haste to get it out, I wrote the explanation too quickly.
== I also wanted to get some feedback from various configurations and change
== things accordingly.
== It was a case of ${I:round up the usual suspects}.
== =item
== In fact, now I'll be adding kernel tracing that will give some real world
== numbers to back things up.  When I have completed this analysis, I'll add them
== to this FAQ.
== =back
== ${I:Many thanks to those that pointed this out.}
== 
=head1 -Nchanges Changes

=head3 Revision 0.2 Changes:
=SS1
=over
=item
No code changes
=item
Major rewrite and expansion of the problem explanation section
=item
More thorough explanation of how and why ${I:irqtune} works
=item
Explanation of why serial devices must be highest priority
=item
Impact on other devices
=item
Cleaner and better installation instructions
=item
Better benchmarking section
=item
Problem resolution section
=item
Explanation of my prior misread on the EOI thing
=back
=SS0

=head3 Revision 0.3 Changes:
=SS1
=over
=item
irqtune automatically prints interrupt priority table
=item
Significantly improved error detection and reporting
=item
Improved loading under different kernel revisions
=item
${I:insmod} now invoked with ${I:-x} to improve loading
=item
Added module ${I:without} printk's -- irqtune_npr.o
=item
Special makefile options for difficult or custom rebuilds
=item
Corrected error in ${I:hdparm -u} note.
=item
Improved the non-standard configuration section
=item
Added note and patch about IRQ sharing under 2.0.X kernels
=back
=SS0

=head3 Revision 0.4 Changes:
=SS1
=over
=item
No code changes
=item
Updated links in the FAQ to reflect configuration changes at my ISP, best.com.
Specifically, the FTP address changed from
ftp://www.best.com/pub/cae/irqtune.tgz
to
ftp://ftp.best.com/pub/cae/irqtune.tgz
=item
${I:irqtune} distribution now available via HTTP as well as FTP.
=item
Consolidated and improved trouble resolution sections.
=item
Added explanation of irqtune_mod.o vs. irqtune_npr.o.
=item
Added explanation of /sbin usage.
=item
Corrected some typos.
=back
=SS0

=head3 Revision 0.5 Changes:
=SS1
=over
=item
Added alternate installation procedure with "INSTALL=" option.
=item
/sbin is added to $PATH automatically.
=item
Added "-u" option.
=item
Consolidated and improved installation documentation.
=item
Additional trouble resolution documentation.
=item
Again, updated links in the FAQ to reflect configuration changes at my ISP,
best.com.
Specifically, the FTP address changed from
ftp://ftp.best.com/pub/cae/irqtune.tgz
to
ftp://shell5.ba.best.com/pub/cae/irqtune.tgz
=back
=SS0

=head3 Revision 0.6 Changes:
=SS1
=over
=item
Added an "inb" to force PIC to a determinate state before setting priority.
=item
Added include of errno.h to allow compilation with newer libc distributions.
=item
Added code to probe ksyms, kernel, insmod for incompatibilities.
Specifically, versions of insmod that have bugs (fixed in insmod 2.1.34) are
detected and handled correctly.
=item
Added "-f" option.
=item
Added documentation about insmod incompatibilities and upgrades.
=item
Added documentation and workaround for broken PPP implementations of PPP
${I:flag} optimization.
=item
Added documentation about recommended serial port baud rates.
=item
Added section with hyperlinks to other documentation and downloads.
=item
Added irqtune to LSM (finally :-).
=item
Install script now obsolete.  irqtune now self installs.  Some moronic systems
still don't have csh installed.
=back
=SS0

=head1 -Ntoc Table of Contents
=toc1
irqtune/src/irqtune.lsm100644    155    764        1114  6335466242  13477 0ustar  caeengrBegin3
Title:		IRQTUNE -- A Linux IRQ Priority Optimizer
Version:	${IRQTUNE_VERSION}
Entered-date:	${DATELSM}
Description:	irqtune changes the IRQ priority of devices to allow devices
		that require high priority and fast service (e.g. serial ports,
		modems) to have it.  With irqtune, a 3X speedup of serial/modem
		throughput is possible.
Keywords:	irqtune, IRQ, interrupt, priority, performance, serial, PPP, tuning
Author: 	cae@best.com (Craig Estey)
Maintained-by:	cae@best.com (Craig Estey)
Primary-site:	http://www.best.com/~cae/irqtune/
Platforms:	x86-PC
Copying-policy:	GPL
End
irqtune/src/BIG100644    155    764       35724  6361367714  11660 0ustar  caeengr// APPEND TOP
/* lib -- irqtune support library */

#pragma member irqtune.h

// APPEND libcmd.c
/* cmdopen -- open command pipe */
/* RETURNS: stream pointer */
struct cmdblk *
cmdopen(const char *bf)
{
	int ok;
	int err;
	int unit;
	int idx;
	int argc;
	struct cmdblk *cmd;
	char *argv[100];

	do {
		/* allocate a new command block */
		ok = 0;
		for (CMDFOR(cmd)) {
			if (! (cmd->cmd_opt & CMDBUSY)) {
				ok = 1;
				break;
			}
		}
		if (! ok) {
			fprintf(stderr,"cmdopen: unable to locate cmdblk\n");
			break;
		}
		memset(cmd,0,sizeof(struct cmdblk));
		cmd->cmd_opt |= CMDBUSY;

		/* enable signal handler */
		cmdsigon();

		/* copy command to buffer */
		strcpy(cmd->cmd_bf,bf);

		/* create a pipe */
		err = pipe(cmd->cmd_units);
		if (err < 0) {
			fprintf(stderr,"cmdopen: unable to create pipe -- %s\n",
				strerror(errno));
			cmd->cmd_units[0] = -1;
			cmd->cmd_units[1] = -1;
			break;
		}

		/* fork a child */
		cmd->cmd_pid = fork();
		if (cmd->cmd_pid < 0) {
			fprintf(stderr,"cmdopen: unable to fork -- %s\n",strerror(errno));
			break;
		}

		/* handle parent */
		if (cmd->cmd_pid > 0) {
			ok = 1;
			close(cmd->cmd_units[1]);
			break;
		}

		/* close parent's unit */
		close(cmd->cmd_units[0]);

		/* open our stuff on the write units */
		for (unit = 1;  unit <= 2;  ++unit) {
			switch (unit) {
			case 1:
				fclose(stdout);
				break;
			case 2:
				fclose(stderr);
				break;
			}

			/* force it onto the correct unit */
			err = dup2(cmd->cmd_units[1],unit);
			if (err < 0)
				exit(errno);

			/* preserve it across exec */
			err = fcntl(F_SETFD,unit,0);
			if (err < 0)
				exit(errno);
		}

		/* close pipe units now that they've been dup'ed */
		for (idx = 0;  idx <= 1;  ++idx)
			close(cmd->cmd_units[idx]);

		/* split the arguments */
		argc = xstrargv(argv,Cntof(argv),cmd->cmd_bf);

		/* execute the program */
		err = execvp(argv[0],argv);
		if (err < 0)
			exit(errno);
	} while (0);

	/* kill off stuff if error */
	if (! ok) {
		cmdclose(cmd);
		cmd = NULL;
	}

	return cmd;
}

/* cmdclose -- close command pipe */
/* RETURNS: final status */
int
cmdclose(struct cmdblk *cmd)
{
	int status;
	int err;
	char bf[1000];

	status = -1;
	do {
		if (cmd == NULL)
			break;

		/* autoreap the child cleanly */
		while (1) {
			if (cmdread(cmd,bf,sizeof(bf)) < 0)
				break;
		}

		/* get status */
		status = cmd->cmd_status;

		/* close open pipe */
		if (cmd->cmd_units[0] >= 0) {
			close(cmd->cmd_units[0]);
			cmd->cmd_units[0] = -1;
		}

		/* release storage */
		cmd->cmd_opt &= ~CMDBUSY;

		/* release signal handler */
		cmdsigoff();
	} while (0);

	return status;
}

/* cmdcoredump -- decide if program terminated due to core dump */
/* RETURNS: 0=normal, 1=limited, 2=dumped */
int
cmdcoredump(int status)
{
	int err;

	err = 0;
	do {
		/* all core dumps are done via the signal mechanism */
		if (! WIFSIGNALED(status))
			break;

		switch (WTERMSIG(status)) {
		case SIGQUIT:
		case SIGILL:
		case SIGTRAP:
		case SIGIOT:
		case SIGFPE:
		case SIGSEGV:
			err = 1;
			break;
		}
		if (! err)
			break;

		/* FIXME -- WCOREDUMP only defined if __USE_BSD? */
		if (WCOREDUMP(status))
			err = 2;
	} while (0);

	return err;
}

/* cmdread -- read in command line */
/* RETURNS: length (-1=EOF or error) */
int
cmdread(struct cmdblk *cmd,char *bf,int bflen)
{
	int err;
	int totlen;
	int unit;
	char *bp;
	char *bfe;
	fd_set selmsk;
	struct timeval tv;

	bp = bf;
	bfe = bp + bflen - 1;

	totlen = 0;
	unit = cmd->cmd_units[0];
	for (;  bp < bfe;  ++bp, ++totlen) {
		/* try to reap the child */
		if (cmd->cmd_pid > 0) {
			err = waitpid(cmd->cmd_pid,&cmd->cmd_status,WNOHANG);
			if (err < 0) {
				fprintf(stderr,"cmdread: wait failure -- %s\n",strerror(errno));
				totlen = -1;
				break;
			}

			/* ok got it */
			if (err > 0)
				cmd->cmd_pid = -1;
		}

		/* wait for data */
		FD_ZERO(&selmsk);
		FD_SET(unit,&selmsk);
		err = select(unit + 1,&selmsk,NULL,NULL,NULL);
		if (err < 0) {
			if (errno == EINTR)
		}

		/* get a character */
		err = read(unit,bp,1);
		if (err < 0) {
			fprintf(stderr,"cmdread: error -- %s\n",strerror(errno));
			totlen = -1;
			break;
		}

		/* handle an EOF */
		if (err == 0) {
			if (totlen <= 0)
				totlen = -1;
			break;
		}

		/* stop when we've got a line */
		if (*bp == '\n')
			break;
	}

	/* close off buffer */
	if (totlen < 0)
		bp = bf;
	*bp = 0;

	return totlen;
}

/* cmdsigon -- enable signal handler */
void
cmdsigon(void)
{
	sigset_t sigmsk;

	/* attach signal handler for SIGCHLD */
	if (cmdsigcnt++ == 0) {
		/* prepare */
		sigemptyset(&sigmsk);
		sigaddset(&sigmsk,SIGCHLD);
		newact.sa_handler = cmdsighdr;
		newact.sa_mask = sigmask(SIGCHLD);
		newact.sa_flags = SA_RESTART;

		/* block the signals before setting signal handler */
		err = sigprocmask(SIG_BLOCK,&sigmsk,&cmdsigmsksv);
		if (err < 0) {
			fprintf(stderr,"cmdclose: unable to sigprocmask -- %s\n",
			strerror(errno);
		}

		/* set handler */
		err = sigaction(SIGCHLD,&newact,&cmdsigactsv);
		if (err < 0) {
			fprintf(stderr,"cmdclose: unable to sigaction -- %s\n",
				strerror(errno);
		}

		/* unblock the signals after setting signal handler */
		err = sigprocmask(SIG_UNBLOCK,&sigmsk,NULL);
		if (err < 0) {
			fprintf(stderr,"cmdclose: unable to sigprocmask -- %s\n",
			strerror(errno);
		}
	}
}

/* cmdsigoff -- disable signal handler */
void
cmdsigoff(void)
{
	int err;

	/* detach signal handler for SIGCHLD */
	if (--cmdsigcnt == 0) {
		err = sigaction(SIGCHLD,&cmdsigactsv,NULL);
		if (err < 0) {
			fprintf(stderr,"cmdclose: unable to sigaction -- %s\n",
			strerror(errno);
		}

		/* restore original block mask */
		err = sigprocmask(SIG_SETMASK,&cmdsigmsksv,NULL);
		if (err < 0) {
			fprintf(stderr,"cmdclose: unable to sigaction -- %s\n",
			strerror(errno);
		}
	}
}

/* cmdsighdr -- command signal handler */
void
cmdsighdr(int signo)
{
	struct cmdblk *cmd;
	int status;
	int pid;

	switch (signo) {
	case SIGCHLD:
		pid = wait(&status);
		for (CMDFOR(cmd)) {
			if (! cmd->cmd_opt & CMDBUSY))
				continue;

			/* reap the child */
			if (cmd->cmd_pid == pid) {
				cmd->cmd_status = status;
				cmd->cmd_pid = 0;
				break;
			}
		}
		break;
	}
}

// APPEND libfile.c
/* filecpy -- copy file */
/* RETURNS: error code */
int
filecpy(int goflg,const char *dirdst,const char *dirsrc,const char *tail)
{
	int perm;
	int srcunit;
	int dstunit;
	int err;
	int rlen;
	struct stat stdst;
	struct stat stsrc;
	struct stat stself;
	char dstfile[1024];
	char srcfile[1024];

	do {
		/* insure self exists (and it's a directory) */
		err = stat(dirtop,&stself);
		if (err < 0) {
			fprintf(stderr,"filecpy: unable to stat self '%s' -- %s\n",
				dirtop,strerror(errno));
			break;
		}
		if (! S_ISDIR(stself.st_mode)) {
			fprintf(stderr,"filecpy: self is not a directory '%s'\n",
				dirtop);
			err = -1;
			break;
		}

		/* insure destination exists (and it's a directory) */
		err = stat(dirdst,&stdst);
		if (err < 0) {
			fprintf(stderr,"filecpy: unable to stat destination '%s' -- %s\n",
				dirdst,strerror(errno));
			break;
		}
		if (! S_ISDIR(stdst.st_mode)) {
			fprintf(stderr,"filecpy: destination is not a directory '%s'\n",
				dirdst);
			err = -1;
			break;
		}

		/* insure self/destination directories are different */
		if ((stdst.st_dev == stself.st_dev) &&
			(stdst.st_ino == stself.st_ino)) {
			fprintf(stderr,"filecpy: self '%s' and destination '%s' are the same\n",
				dirtop,dirdst);
			err = -1;
			break;
		}

		if (dirsrc != NULL) {
			/* insure source exists (and it's a directory) */
			err = stat(dirsrc,&stsrc);
			if (err < 0) {
				fprintf(stderr,"filecpy: unable to stat source '%s' -- %s\n",
					dirsrc,strerror(errno));
				break;
			}
			if (! S_ISDIR(stsrc.st_mode)) {
				fprintf(stderr,"filecpy: source is not a directory '%s'\n",
					dirdst);
				err = -1;
				break;
			}

			/* insure source/destination directories are different */
			if ((stdst.st_dev == stsrc.st_dev) &&
				(stdst.st_ino == stsrc.st_ino)) {
				fprintf(stderr,"filecpy: source '%s' and destination '%s' are the same\n",
					dirsrc,dirdst);
				err = -1;
				break;
			}
		}
	} while (0);

	dstunit = -1;
	srcunit = -1;
	do {
		/* bug out if error */
		if (err < 0)
			break;

		/* bug out if nogo mode */
		if (! goflg)
			break;

		/* show files we're copying */
		sprintf(dstfile,"%s/%s",dirdst,tail);
		fprintf(stderr,"filecpy: %s",dstfile);
		if (dirsrc != NULL) {
			sprintf(srcfile,"%s/%s",dirsrc,tail);
			fprintf(stderr," <-- %s",srcfile);
		}
		fprintf(stderr," ...\n");

		/* get permissions (mimic source if possible) */
		perm = 0755;
		if (dirsrc != NULL)
			perm = stsrc.st_mode & 0777;

		/* open/create the destination file */
		dstunit = open(dstfile,O_WRONLY | O_CREAT | O_TRUNC,perm);
		if (dstunit < 0) {
			fprintf(stderr,"filecpy: unable to open destination '%s' -- %s\n",
				dstfile,strerror(errno));
			err = -1;
			break;
		}

		/* force correct permissions (in case of a prior bogus install) */
		err = fchmod(dstunit,perm);
		if (err < 0) {
			fprintf(stderr,"install: unable change permissions on '%s' -- %s\n",
				dstfile,strerror(errno));
			break;
		}

		/* just open the destination for caller */
		if (dirsrc == NULL)
			break;

		/* open the source */
		srcunit = open(srcfile,O_RDONLY);
		if (srcunit < 0) {
			fprintf(stderr,"filecpy: unable to open source '%s' -- %s\n",
				srcfile,strerror(errno));
			break;
		}

		/* copy the data */
		err = 0;
		while (1) {
			/* read a chunk */
			rlen = read(srcunit,bigbf,sizeof(bigbf));
			if (rlen < 0) {
				fprintf(stderr,"filecpy: read error on '%s' -- %s\n",
					srcfile,strerror(errno));
				err = -1;
				break;
			}
			if (rlen == 0)
				break;

			/* write a chunk */
			err = write(dstunit,bigbf,rlen);
			if (err < 0) {
				fprintf(stderr,"filecpy: write error on '%s' -- %s\n",
					dstfile,strerror(errno));
				break;
			}
		}
	} while (0);

	/* close units */
	if ((dirsrc != NULL) || (err < 0)) {
		if (dstunit >= 0)
			close(dstunit);
		if (srcunit >= 0)
			close(srcunit);
	}

	/* return open destination unit to caller */
	else
		err = dstunit;

	return err;
}

/* filehead -- get head of name */
/* RETURNS: pointer to head */
char *
filehead(char *name)
/* name -- name to get head of */
{
	char *head;

	head = strrchr(name,'/');
	if (head != NULL)
		*head = 0;

	return name;
}

/* filetail -- get tail of name */
/* RETURNS: pointer to tail */
char *
filetail(char *name)
/* name -- name to get tail of */
{
	char *tail;

	tail = strrchr(name,'/');
	if (tail != NULL)
		++tail;
	else
		tail = name;

	return tail;
}

// APPEND libopt.c
/* optget -- get options */
/* RETURNS: 1=ok, 0=error */
int
optget(struct optblk *opt,char *cp)
{
	int ok;

	ok = 0;
	for (;  *cp != 0;  ++cp) {
		for (;  opt->opt_fmt != NULL;  ++opt) {
			if (opt->opt_fmt[0] != '-')
				continue;
			if (*cp == opt->opt_fmt[1])
				break;
		}

		/* bug out if no match */
		if (opt->opt_fmt == NULL) {
			ok = 0;
			break;
		}

		mstopt |= opt->opt_msk;
		ok = 1;

		/* handle single valued option */
		if (opt->opt_ptr != NULL) {
			++cp;
			*opt->opt_ptr = cp;
			break;
		}
	}

	return ok;
}

/* optusage -- show option usage */
void
optusage(const struct optblk *opt)
{

	for (;  opt->opt_fmt != NULL;  ++opt) {
		if (opt->opt_fmt[0] == '-')
			fprintf(stderr,"  %s\n",opt->opt_fmt);
		else
			fprintf(stderr,"%s options:\n",opt->opt_fmt);
	}
}

// APPEND libfile.c
/* pathdir -- insure a directory is in $PATH */
/* RETURNS: pointer to $PATH match (or NULL) */
char *
pathdir(const char *dir)
{
	char *bp;
	char *cp;

	/* get path value */
	cp = getenv("PATH");
	strcpy(pathtmp,cp);

	bp = pathtmp;
	while (1) {
		/* get next element of the path */
		cp = strtok(bp,":");
		if (cp == NULL)
			break;
		bp = NULL;

		/* bug out if we found it */
		if (strcmp(dir,cp) == 0)
			break;
	}

	/* add directory to path (this is the probable place for insmod et. al.) */
	if (cp == NULL) {
		cp = getenv("PATH");
		sprintf(pathtmp,"PATH=%s:%s",cp,dir);

		/* NOTE: putenv won't strdup (e.g. pathbf must stay stable) */
		strcpy(pathbf,pathtmp);
		putenv(pathbf);
	}

	return cp;
}

/* pathlook -- lookup file in $PATH */
/* RETURNS: pointer to directory name (or NULL) */
char *
pathlook(const char *tail,const char *dir)
/* tail -- file to locate */
{
	char *cp;
	char *bp;
	int err;
	struct stat mystat;
	char file[1024];

	/* create path to program */
	if (dir == NULL)
		dir = getenv("PATH");
	strcpy(pathtmp,dir);

	bp = pathtmp;
	while (1) {
		/* get next element of the path */
		cp = strtok(bp,":");
		if (cp == NULL)
			break;
		bp = NULL;

		/* create file name */
		sprintf(file,"%s/%s",cp,tail);

		/* ignore nonexistent file */
		err = stat(file,&mystat);
		if (err < 0)
			continue;

		/* only want regular files */
		if (! S_ISREG(mystat.st_mode))
			continue;

		/* it must be executable by us */
		err = access(file,X_OK);
		if (err >= 0)
			break;
	}

	/* copy result to stable area */
	if (cp != NULL) {
		strcpy(bigbf,cp);
		cp = bigbf;
	}

	return cp;
}

// APPEND libcmd.c
/* vsystem -- execute program */
/* RETURNS: error code */
int
vsystem(int verbose,const char *tag0,const char *tag1,const char *tag2,const char *bf0)
/* tag0 -- primary command (e.g. loading, unloading, etc.) */
/* tag1 -- primary tag */
/* tag2 -- secondary tag */
/* bf0 -- actual command buffer */
{
	char *logf;
	char *cp;
	int code;
	int status;
	struct cmdblk *cmd;
	char bf[4096];

	/* copy command to buffer */
	strcpy(bf,bf0);

	/* show blah_blah_blah only if full errors or verbosity enabled */
	logf = "/dev/null";
	if (! (verbose || (mstopt & OPTVERBOSE))) {
		cp = &bf[strlen(bf)];
		sprintf(cp," >> %s 2>&1",logf);
	}

	/* show stuff beforehand */
	if (mstopt & OPTERR)
		fprintf(stderr,"irqtune: trying command -- %s\n",bf0);
	else {
		fprintf(stderr,"irqtune: %s",tag0);
		if (tag1 != NULL)
			fprintf(stderr," %s",tag1);
		if (tag2 != NULL)
			fprintf(stderr," (%s)",tag2);
		fprintf(stderr,"\n");
	}

	/* get command status */
	cmd = cmdopen(bf);
	status = cmdclose(cmd);

	/* check the status */
	code = 1;
	do {
		/* handle exec error */
		if (status < 0) {
			fprintf(stderr,"irqtune: exec failed of '%s' -- %s\n",
				bf0,strerror(errno));
			break;
		}

		/* handle semi-normal program termination */
		if (WIFEXITED(status)) {
			code = WEXITSTATUS(status);
			code = BOOL(code);
		}
		if (! code)
			break;

		/* show a short, sweet, to the point error message */
		cp = strtok(bf," \t");
		cp = filetail(cp);
		fprintf(stderr,"irqtune: %s failed on '%s'",cp,tag1);

		/* show the really nasty core dumps */
		code = cmdcoredump(status);
		switch (code) {
		case 1:
			fprintf(stderr," (crashed -- core dump not taken)");
			break;
		case 2:
			fprintf(stderr," (crashed -- core dumped)");
			break;
		}

		/* show the absolute raw status */
		if (mstopt & (OPTERR | OPTVERBOSE))
			fprintf(stderr," status=%8.8X",cmd->cmd_status);

		code = 1;
	} while (0);
	if (code)
		fprintf(stderr,"\n");

	return code;
}

// APPEND libstr.c
/* xstrargv -- split buffer into tokens */
/* RETURNS: number of tokens */
int
xstrargv(char **argv,int argc,char *bf)
{
	int argcnt;
	char *cp;

	/* place for NULL */
	--argc;

	for (argcnt = 0;  argc > 0;  --argc, ++argcnt) {
		cp = strtok(bf," \t");
		if (cp == NULL)
			break;

		argv[argcnt] = cp;
		bf = NULL;
	}
	argv[argcnt] = NULL;

	return argcnt;
}
irqtune/src/TOP100644    155    764         100  6361367722  11634 0ustar  caeengr/* lib -- irqtune support library */

#pragma member irqtune.h

irqtune/include/ 40755    155    764           0  6371305677  12041 5ustar  caeengrirqtune/include/irqhigh.h100644    155    764        1311  6360633641  13727 0ustar  caeengr/* irqhigh.h -- set high priority IRQ's */

/*
// Copyright 1996, 1997 by Craig Estey -- See the file COPYING for details
*/

#include <linux/types.h>

#ifndef i386
#error irqhigh: this only works/is needed for x86/PC architecture -- sorry
#endif

/* original PC issue configuration */
#define IRQHIGH_MST_BAD			0
#define IRQHIGH_SLV_BAD			8

/* defaults based on standard configuration */
#define IRQHIGH_MST_DFT			3
#define IRQHIGH_SLV_DFT			14

/* master and slave acceptable ranges */
#define IRQHIGH_MST_LO			0
#define IRQHIGH_MST_HI			7
#define IRQHIGH_SLV_LO			8
#define IRQHIGH_SLV_HI			15

/* maximum number of IRQ's */
#define IRQHIGH_MAX			16

#define RNGE(x,lo,hi) \
	(((x) >= (lo)) && ((x) <= (hi)))
irqtune/include/irqtune.h100644    155    764       15600  6414552604  14010 0ustar  caeengr/* irqtune.h -- load IRQ tuning module */

#ifndef _irqtune_h_
#define _irqtune_h_

#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>

#include <irqhigh.h>

#include <sys/time.h>
#include <sys/stat.h>
#include <sys/utsname.h>

#include <asm/unistd.h>

#include <src/irqhigh.c>

/*
// FIXME -- "errno.h" et. al. for glibc does a #define of errno :-( :-( :-(.
// This conflicts with "int errno" in a struct in "linux/sched.h" as well as
// thousands of other programs.  Include "errno.h" afterwards.
// GNU strikes again:  28 years of compatibility broken--Film at 11!
*/

#include <softnet/types.h>
#include <softnet/macros.h>

#define zprtok(lvl) \
	(irqhow & (lvl))
#include <softnet/zprt.h>

/* signal control */
int cmdsigcnt;							/* number of active blocks */
struct sigaction cmdsigactsv;			/* sigaction save area */
sigset_t cmdsigmsksv;					/* sigmask save area */

/* command execution control block */
struct cmdblk {
	mskof_t cmd_opt;					/* options */
	int cmd_status;						/* wait status */
	int cmd_pid;						/* child process ID */
	int cmd_units[2];					/* pipe units */
	char cmd_bf[1000];					/* cmd buffer (tokenized) */
};

/* equates to cmd_opt */
#define CMDBUSY				RMSKOF(0)	/* 1=command block busy */

#define CMDBLKMAX		5
struct cmdblk cmdblks[CMDBLKMAX];
#define CMDMORE(_cmd) \
	(_cmd < &cmdblks[CMDBLKMAX])
#define CMDFOR(_cmd) \
	_cmd = cmdblks;  CMDMORE(_cmd);  ++_cmd

/* /proc/interrupts control */
struct tblblk {
	u_char tbl_irq;						/* irq number */
	u_char tbl_prior;					/* irq priority */
	u_char tbl_bias;					/* irq priority bias */
	u_char tbl_active;					/* 1=irq is active */
	char tbl_bf[100];					/* id string */
};

#define OPTDEFALLA(_cmd) \
	_cmd(0,OPTHELP,NULL,"-h -- display help"), \
	_cmd(1,OPTVERSION,NULL,"-v -- display irqtune version"), \
	_cmd(2,OPTRESET,NULL,"-o -- reset to original values (0/8)")

#define OPTDEFALLB(_cmd) \
	_cmd(3,OPTQUIET,NULL,"-q -- suppress priority table printing"), \
	_cmd(4,OPTSORT,NULL,"-s -- sort table by priority"), \
	_cmd(5,OPTALL,NULL,"-x -- show inactive devices in table")

#define OPTDEFALLC(_cmd) \
	_cmd(6,OPTERR,NULL,"-e -- show full errors"), \
	_cmd(7,OPTFORCE,NULL,"-f -- force loading even if probe detects errors"), \
	_cmd(8,OPTUNLOAD,NULL,"-u -- force module unload"), \
	_cmd(9,OPTVERBOSE,NULL,"-V -- insmod verbose mode"), \
	_cmd(10,OPTWARN,NULL,"-w -- treat warnings as errors")

#define OPTDEFALLD(_cmd) \
	_cmd(11,OPTPROC,&proc_ints,"-F<file> -- use <file> instead of /proc/interrupts"), \
	_cmd(12,OPTINSTALL,NULL,"-i -- install program"), \
	_cmd(13,OPTINSPGM,&insmod_path,"-L<directory> -- directory to search for insmod"), \
	_cmd(14,OPTNOGO,NULL,"-n -- nogo mode (just show what would happen)")

#define OPTDEFENUM(_idx,_msk,_ptr,_fmt...) \
	_msk = RMSKOF(_idx)
#define OPTDEFHELP(_idx,_msk,_ptr,_fmt...) \
	{ _msk, _ptr, _fmt }
#define OPTDEFSCT(_fmt...) \
	OPTDEFHELP(0,0,NULL,_fmt)

/* option control */
struct optblk {
	mskof_t opt_msk;					/* option mask */
	char **opt_ptr;						/* point to string value storage area */
	const char *opt_fmt;				/* option help */
};

mskof_t mstopt;							/* master options */
typedef enum {
	OPTDEFALLA(OPTDEFENUM),
	OPTDEFALLB(OPTDEFENUM),
	OPTDEFALLC(OPTDEFENUM),
	OPTDEFALLD(OPTDEFENUM)
} optenum_t;

char *proc_ints;						/* name of /proc/interrupts */
char *ins_ptr;							/* install argument */
char tmpf[1024];						/* temp file name */
int bigcode;							/* final exit code */

char *insmod_path;						/* specified insmod directory */
char insmod_dir[1024];					/* insmod probed full path name */
char insmod_file[1024];					/* insmod probed full file name */
char rmmod_file[1024];					/* rmmod probed full file name */
u_long insmod_version;					/* version of insmod program */
#define INSMOD_VERGOOD		VERMK(2,1,34)

mskof_t dynstat;						/* dynamic configuration status */
mskof_t dynerr;							/* dynamic error status */
#define DYN_FULL_PATH		RMSKOF(0)	/* 1=insmod invoked via full path */

#define DYN_INSMOD_ANCIENT	RMSKOF(1)	/* 1=insmod too old for irqtune */
#define DYN_INSMOD_OLD		RMSKOF(2)	/* 1=insmod too old for kernel */
#define DYN_INSMOD_PATH		RMSKOF(3)	/* 1=insmod was found in $PATH */
#define DYN_INSMOD_EXEC		RMSKOF(4)	/* 1=insmod was exec'ed ok */
#define DYN_INSMOD_VERSION	RMSKOF(5)	/* 1=insmod has version */
#define DYN_INSMOD_CRASH	RMSKOF(6)	/* 1=insmod will crash on irqtune_mod.o */
#define DYN_INSMOD_STRONG	RMSKOF(7)	/* 1=insmod is strong (>= 2.1.34) */
#define DYN_RMMOD_PATH		RMSKOF(8)	/* 1=rmmod was found in insmod_dir */

#define DYN_KNL_CPLDIFF		RMSKOF(9)	/* 1=compiled version differs */
#define DYN_KNL_GSYM		RMSKOF(10)	/* 1=kernel has get_kernel_syms */
#define DYN_KNL_VEROK		RMSKOF(11)	/* 1=kernel compatible */

#define DYN_KSYMS_CSUM		RMSKOF(12)	/* 1=/proc/ksyms has a checksum symbol */
#define DYN_KSYMS_FOUND		RMSKOF(13)	/* 1=/proc/ksyms has any symbol */
#define DYN_KSYMS_USING		RMSKOF(14)	/* 1=/proc/ksyms is using versions */

#define DYN_NPRONLY			RMSKOF(15)	/* 1=irqtune_mod.o will probably fail */
#define DYN_PROC_INTS		RMSKOF(16)	/* 1=/proc/interrupts valid */
#define DYN_SBIN_PATH		RMSKOF(17)	/* 1=/sbin in $PATH */

#define DYN_FATAL			LMSKOF(0)	/* 1=fatal error */
#define DYN_NEG				LMSKOF(1)	/* 1=logical negation */
#define DYN_WARN			LMSKOF(2)	/* 1=warning */

char kernel_version[1];					/* kernel version compiled with */
u_long kvers_compile;					/* compiled kernel version */
struct utsname uts;						/* dynamic kernel version */
u_long kvers_dynamic;					/* dynamic kernel version */
#define KNL_VERBADLO	VERMK(2,0,15)	/* lowest incompatible kernel version */
#define KNL_VERBADHI	VERMK(2,0,18)	/* highest incompatible kernel version */

struct tblblk tblbase[IRQHIGH_MAX];

#define PSIZE			4096			/* size of $PATH buffer */

char *pgmname;
char bigbf[PSIZE];						/* large temporary buffer */
char pathtmp[PSIZE];					/* temp place to store $PATH value */
char pathbf[PSIZE];						/* perm place to store $PATH value */

/* module names */
char dirtop[1024];						/* top directory */
char *modnames[] = {
	"irqtune_mod",
	"irqtune_npr",
	NULL,
};
char *modtag = MODTAG;					/* name to install under */
char modcur[1024];						/* current module name */

#define VERFMT \
	"%u.%u.%u"
#define VERPRT(_ver) \
	(_ver >> 16) & 0xFF, \
	(_ver >> 8) & 0xFF, \
	(_ver) & 0xFF
#define VERMK(_maj,_min,_sub) \
	((_maj & 0xFF) << 16 | \
	(_min & 0xFF) << 8 | \
	(_sub & 0xFF))
#define VERMAJ(_ver) \
	((_ver) & VERMK(0xFF,0xFF,0))

struct optblk opthelp[] = {
	OPTDEFSCT("general"),
	OPTDEFALLA(OPTDEFHELP),

	OPTDEFSCT("priority table"),
	OPTDEFALLB(OPTDEFHELP),

	OPTDEFSCT("error control"),
	OPTDEFALLC(OPTDEFHELP),

	OPTDEFSCT("documentation"),
	OPTDEFALLD(OPTDEFHELP),

	OPTDEFSCT(NULL),
};

mskof_t irqhow;								/* trace control */

/* hidden system calls */
VXInline _syscall1(int,get_kernel_syms,void *,ksyms)

/* function prototypes */
#include <irqtune.P>

#endif /*_irqtune_h_*/
irqtune/include/P/ 40755    155    764           0  6363006517  12230 5ustar  caeengrirqtune/include/P/irqtune.P100644    155    764       12375  6421553734  14170 0ustar  caeengr/* irqtune.P -- function prototypes generated by pgmtypex */
#ifndef _irqtune_P_
#define _irqtune_P_

/* FILE: ./lib/cmd.c */
#ifndef __ASSEMBLER__
#pragma member irqtune.h

	/* cmdopen -- open command pipe */
	/* RETURNS: stream pointer */
#ifndef cmdopen
	struct cmdblk *
	cmdopen(const char *cmdbf);
#endif /*cmdopen*/

	/* cmdclose -- close command pipe */
	/* RETURNS: final status */
#ifndef cmdclose
	int
	cmdclose(struct cmdblk *cmd);
#endif /*cmdclose*/

	/* cmdcoredump -- decide if program terminated due to core dump */
	/* RETURNS: 0=normal, 1=limited, 2=dumped */
#ifndef cmdcoredump
	int
	cmdcoredump(int status);
#endif /*cmdcoredump*/

	/* cmdread -- read in command line */
	/* RETURNS: length (-1=EOF or error) */
#ifndef cmdread
	int
	cmdread(struct cmdblk *cmd,char *bf,int bflen);
#endif /*cmdread*/

	/* cmdsigon -- enable signal handler */
#ifndef cmdsigon
	void
	cmdsigon(void);
#endif /*cmdsigon*/

	/* cmdsigoff -- disable signal handler */
#ifndef cmdsigoff
	void
	cmdsigoff(void);
#endif /*cmdsigoff*/

	/* cmdsighdr -- command signal handler */
#ifndef cmdsighdr
	void
	cmdsighdr(int signo);
#endif /*cmdsighdr*/

	/* vsystem -- execute program */
	/* RETURNS: error code */
#ifndef vsystem
	int
	vsystem(int verbose,const char *tag0,const char *tag1,const char *tag2,const char *cmdbf0);
	/* tag0 -- primary command (e.g. loading, unloading, etc.) */
	/* tag1 -- primary tag */
	/* tag2 -- secondary tag */
	/* cmdbf0 -- actual command buffer */
#endif /*vsystem*/
#endif /*__ASSEMBLER__*/

/* FILE: ./lib/file.c */
#ifndef __ASSEMBLER__
#pragma member irqtune.h

	/* filecpy -- copy file */
	/* RETURNS: error code */
#ifndef filecpy
	int
	filecpy(int goflg,const char *dirdst,const char *dirsrc,const char *tail);
#endif /*filecpy*/

	/* filehead -- get head of name */
	/* RETURNS: pointer to head */
#ifndef filehead
	char *
	filehead(char *name);
	/* name -- name to get head of */
#endif /*filehead*/

	/* filetail -- get tail of name */
	/* RETURNS: pointer to tail */
#ifndef filetail
	char *
	filetail(char *name);
	/* name -- name to get tail of */
#endif /*filetail*/

	/* pathdir -- insure a directory is in $PATH */
	/* RETURNS: pointer to $PATH match (or NULL) */
#ifndef pathdir
	char *
	pathdir(const char *dir);
#endif /*pathdir*/

	/* pathlook -- lookup file in $PATH */
	/* RETURNS: pointer to directory name (or NULL) */
#ifndef pathlook
	char *
	pathlook(const char *tail,const char *dir);
	/* tail -- file to locate */
#endif /*pathlook*/
#endif /*__ASSEMBLER__*/

/* FILE: ./lib/opt.c */
#ifndef __ASSEMBLER__
#pragma member irqtune.h

	/* optget -- get options */
	/* RETURNS: 1=ok, 0=error */
#ifndef optget
	int
	optget(struct optblk *opt,char *cp);
#endif /*optget*/

	/* optusage -- show option usage */
#ifndef optusage
	void
	optusage(const struct optblk *opt);
#endif /*optusage*/
#endif /*__ASSEMBLER__*/

/* FILE: ./lib/sys.c */
#ifndef __ASSEMBLER__
#pragma member irqtune.h

	/* sysexit -- do cleanup and exit */
#ifndef sysexit
	void
	sysexit(int code);
#endif /*sysexit*/

	/* sysfault -- output howfar to stxerr */
	/* RETURNS: length of output string */
#ifndef sysfault
	int
	sysfault(const char *fmt,...);
	/* fmt -- format */
#endif /*sysfault*/
#endif /*__ASSEMBLER__*/

/* FILE: ./lib/xstr.c */
#ifndef __ASSEMBLER__
#pragma member irqtune.h

	/* xstrargv -- split buffer into tokens */
	/* RETURNS: number of tokens */
#ifndef xstrargv
	int
	xstrargv(char **argv,int argc,char *bf);
#endif /*xstrargv*/
#endif /*__ASSEMBLER__*/

/* FILE: ./src/irqtune.c */
#ifndef __ASSEMBLER__
#pragma member irqtune.h

	/* main -- main program */
#ifndef main
	void
	main(int argc,char **argv);
#endif /*main*/

	/* install -- install program */
#ifndef install
	void
	install(int argc,char **argv);
#endif /*install*/

	/* loader -- load module */
#ifndef loader
	void
	loader(void);
#endif /*loader*/

	/* probechk -- check dynamic configuration */
#ifndef probechk
	void
	probechk(mskof_t actmsk,const char *fmt,...);
#endif /*probechk*/

	/* probectl -- probe control (to probe 1) */
#ifndef probectl
	void
	probectl(void);
#endif /*probectl*/

	/* probectl2 -- probe control (to probe 2) */
#ifndef probectl2
	void
	probectl2(void);
#endif /*probectl2*/

	/* probeins -- probe for insmod */
#ifndef probeins
	void
	probeins(void);
#endif /*probeins*/

	/* probeknl -- probe the kernel */
#ifndef probeknl
	void
	probeknl(void);
#endif /*probeknl*/

	/* probeksyms -- probe /proc/ksyms */
#ifndef probeksyms
	void
	probeksyms(void);
#endif /*probeksyms*/

	/* verdcd -- decode version number */
	/* RETURNS: decoded version number */
#ifndef verdcd
	u_long
	verdcd(char *bf);
#endif /*verdcd*/

	/* tblfind -- find table entry */
	/* RETURNS: pointer to /proc/interrupts table entry */
#ifndef tblfind
	struct tblblk *
	tblfind(u_char irq_no);
#endif /*tblfind*/

	/* tblinit -- initialize to default */
#ifndef tblinit
	void
	tblinit(void);
#endif /*tblinit*/

	/* tblread -- read in /proc/interrupts table */
#ifndef tblread
	void
	tblread(int goflg,char *file);
#endif /*tblread*/

	/* tblshow -- show table */
#ifndef tblshow
	void
	tblshow(void);
#endif /*tblshow*/

	/* _usage -- show program usage */
#ifndef _usage
	void
	_usage(void);
#endif /*_usage*/

	/* usage -- show program usage and exit */
#ifndef usage
	void
	usage(void);
#endif /*usage*/
#endif /*__ASSEMBLER__*/

#endif /*_irqtune_P_*/
irqtune/include/P/softnet/ 40755    155    764           0  6363006517  13712 5ustar  caeengrirqtune/include/P/softnet/sysring.P100644    155    764         710  6363006517  15604 0ustar  caeengr/* softnet/sysring.P -- function prototypes generated by pgmtype */
#ifndef _softnet_sysring_P_
#define _softnet_sysring_P_

/* FILE: ./lib/sys.c */
#ifndef LOCORE
#pragma member softnet/sysring.h  

	/* sysexit -- do cleanup and exit */
	void
	sysexit(int code);

	/* sysfault -- output howfar to stxerr */
	/* RETURNS: length of output string */
	int
	sysfault(const char *fmt,...);
	/* fmt -- format */
#endif /*LOCORE*/

#endif /*_softnet_sysring_P_*/
irqtune/include/P/softnet/zprt.P100644    155    764        2343  6421553734  15134 0ustar  caeengr/* softnet/zprt.P -- function prototypes generated by pgmtypex */
#ifndef _softnet_zprt_P_
#define _softnet_zprt_P_

/* FILE: ./lib/zprt.c */
#ifndef __ASSEMBLER__
#pragma member softnet/zprt.h

	/* ztodx -- send TOD stamp */
#ifndef ztodx
	void
	ztodx(void);
#endif /*ztodx*/

	/* zmsgvx -- output howfar */
	/* RETURNS: length of output string */
#ifndef zmsgvx
	int
	zmsgvx(const char *fmt,va_list ap);
	/* fmt -- format */
#endif /*zmsgvx*/

	/* zmsgx -- output howfar */
	/* RETURNS: length of output string */
#ifndef zmsgx
	int
	zmsgx(const char *fmt,...);
	/* fmt -- format */
#endif /*zmsgx*/

	/* zprtx -- output howfar to stxerr */
	/* RETURNS: length of output string */
#ifndef zprtx
	int
	zprtx(const char *fmt,...);
	/* fmt -- format */
#endif /*zprtx*/
#endif /*__ASSEMBLER__*/

/* FILE: ./lib/zprtx.c */
#ifndef __ASSEMBLER__
#pragma member softnet/zprt.h

	/* zprtvx -- output howfar (low level) */
	/* RETURNS: length of output string */
#ifndef zprtvx
	int
	zprtvx(mskof_t opt,const char *fmt,va_list ap);
	/* fmt -- format */
#endif /*zprtvx*/

	/* ztodtime -- get time of day */
	/* RETURNS: time of day (GMT) */
#ifndef ztodtime
	u_long
	ztodtime(void);
#endif /*ztodtime*/
#endif /*__ASSEMBLER__*/

#endif /*_softnet_zprt_P_*/
irqtune/include/softnet/ 40755    155    764           0  6371373335  13517 5ustar  caeengrirqtune/include/softnet/macros.h100644    155    764       14015  6421553730  15265 0ustar  caeengr/* softnet/macros.h -- softnet macros */

#ifndef _softnet_macros_h_
#define _softnet_macros_h_

#include <softnet/types.h>

CDEFBEGIN

/* tell compiler/lint/whatever that a variable is used */
VXInline void
_variable_used(long x)
{
}
#define variable_used(x) \
	_variable_used((long) (x))

/* tell lint that a variable is used */
#ifdef lint
#define lintuse(x)	variable_used(x)
#else /*lint*/
#define lintuse(x)	/**/
#endif /*lint*/

/* define variable only if HOWFAR mode */
#ifdef HOWFAR
#define howfar_define(thing)			thing;
#else /*HOWFAR*/
#define howfar_define(thing)			/**/
#endif /*HOWFAR*/

/* variables that are used only when debugging */
#if !defined(HOWFAR) && !defined(HOWCHECK)
#define howfar_used(x)	variable_used(x)
#else /*HOWFAR/HOWCHECK*/
#define howfar_used(x)	/**/
#endif /*HOWFAR/HOWCHECK*/

/* tell compiler to not put variable in a register */
#define variable_unregister(x) \
	do { \
		void *variable_unregister_tmp; \
		variable_unregister_tmp = &(x); \
	} while (0)

/* casts */
#define CAST(y,x)	((y) (x))
#define DOUBLE(x)	CAST(double,x)

/* FIXME -- this has a conflict with -DFLOAT for kernel */
#ifndef FLOAT
#define FLOAT(x)	CAST(float,x)
#endif /*FLOAT*/

/* value casts */
#define SHORT(x)	CAST(short,x)
#define LG(x)		CAST(long,x)
#define WD(x)		CAST(u_short,x)
#define LW(x)		CAST(u_long,x)

/* pointer casts */
#define LP(x)		CAST(u_long *,x)
#define WP(x)		CAST(u_short *,x)
#define BP(x)		CAST(u_char *,x)
#define CP(x)		CAST(char *,x)
#define VP(x)		CAST(void *,x)

#define VDCODE(ptr)	((vdcode) ptr)
#define VPCODE(ptr)	((vpcode) ptr)
#define LGCODE(ptr)	((lgcode) ptr)
#define LWCODE(ptr)	((lwcode) ptr)

/* definition to print a pointer */
#define PP(x)		LW(x)

/* number of bits */
#define Sizeof(x) \
	(sizeof(x) * 8)

/* number of longs */
#define LSizeof(x) \
	(sizeof(x) / sizeof(long))

/* number of vector elements */
#define Cntof(x) \
	(sizeof(x) / sizeof(x[0]))

#ifndef MIN
#define MIN(x,y)	(((x) < (y)) ? (x) : (y))
#endif /*MIN*/

#ifndef MAX
#define MAX(x,y)	(((x) > (y)) ? (x) : (y))
#endif /*MAX*/

#define XABS(x)		(((x) < 0) ? -(x) : (x))
#define XSGN(x)		(((x) < 0) ? -1 : 1)

/* align to arbitrary (power of 2) boundaries */
#define ALIGN(x,y)	(LW(x) & (~((y) - 1)))
#define ALIGNUP(x,y)	ALIGN((x) + (y) - 1,y)

/* align to longword boundary */
#define WDALIGN(x)	ALIGN(x,sizeof(word))
#define LWALIGN(x)	ALIGN(x,sizeof(longword))
#define LWALIGNUP(x)	ALIGNUP(x,sizeof(longword))

/* find nonblank stuff */
#define NONBLANK(cp,ep) \
	for (;  (cp < ep) && (*cp != 0) && (*cp == ' ');  ++cp);

/* create control character */
#define CTRL(c) \
	(((c) - 'a') + 1)

/* square of number */
#define SQUARE(x) \
	((x) * (x))

/* common thing */
#define DUAL(item) \
	item,sizeof(item)
#define BFE(item) \
	&item[sizeof(item) / sizeof(item[0])]
#define DUALBFE(item) \
	item,BFE(item)

/* check that range is active */
#define RNGEON(lo,hi) \
	((lo) <= (hi))

/* check value within a range (lo <= x <= hi) */
#define RNGE(x,lo,hi) \
	(((x) >= (lo)) && ((x) <= (hi)))

/* check value within a range (lo <= x < hi) */
#define RNGEM1(x,lo,hi) \
	(((x) >= (lo)) && ((x) < (hi)))

/* check range is active and value is with range (if range not active, */
/* all data values are "within" range) */
#define RNGEOK(x,lo,hi) \
	(RNGEON(lo,hi) ? RNGE(x,lo,hi) : 1)

/* printable characters */
#define _PRTABLE(c) \
	RNGE(c,0x20,0x7E)
#define PRTABLE(c) \
	(_PRTABLE(c) ? (u_char) (c) : (u_char) '.')

/* bitmask has all its bits on */
#define ANDEQ(val,msk) \
	(((val) & (msk)) == (msk))

/* insure absolute boolean */
#define BOOL(x) \
	(((x) != 0) ? 1 : 0)

/* structure base pointer */
#define STRCTBAS(strnam) \
	CAST(strnam *,0)

/* compute the offset of a structure item */
#define STRCTOFF(strnam,stritem) \
	LW(&(STRCTBAS(strnam)->stritem))

/* compute the structure pointer from pointer to structure item */
#define STRCTPAR(strnam,stritem,ptr) \
	CAST(strnam *,VP(ptr) - STRCTOFF(strnam,stritem))

/* compute the size of a structure item (bytes) */
#define STRCTSIZ(strnam,stritem) \
	sizeof(STRCTBAS(strnam)->stritem)

/* compute the size of a structure item (bits) */
#define STRCTSIZB(strnam,stritem) \
	Sizeof(STRCTBAS(strnam)->stritem)

/* virtual functions */
#define VRT(vrt,vidx,vargs,falt) \
	(((vrt)[vidx] != NULL) ? (*(vrt)[vidx])vargs : (falt))

/* creates a 1 bit wide mask from its bit number (0 is LSB, n is MSB) */
#define RMSKOF(bitno) \
	(CAST(mskof_t,0x00000001) << (bitno))
#define RMSKOF1(bitno) \
	RMSKOF((bitno) - 1)
/* creates a bit mask of "wid" bits wide */
#define RMSKOFWID(wid) \
	(~(CAST(mskof_t,-1) << (wid)))

/* creates a 1 bit wide mask from its bit number (0 is MSB, n is LSB) */
#define LMSKOF(idx) \
	RMSKOF(Sizeof(mskof_t) - 1 - (idx))
#define LMSKOF1(bitno) \
	LMSKOF((bitno) - 1)
/* creates a bit mask of "wid" bits wide */
#define LMSKOFWID(wid) \
	(~(CAST(mskof_t,-1) >> (wid)))

/* set bits from mask */
#define MSKSET(tgt,msk) \
	tgt |= (msk)

/* clear bits from mask */
#define MSKCLEAR(tgt,msk) \
	tgt &= ~(msk)

/* clear bits from mask */
#define MSKFLIP(tgt,msk) \
	tgt ^= (msk)

/* speedup a part of strcmp */
#define STRCMP(dif,cp1,cp2) \
	do { \
		dif = LW(cp1[0]) - LW(cp2[0]); \
		if (dif == 0) \
			dif = strcmp(cp1,cp2); \
	} while (0)

/* speedup a part of strcmp */
#define STRMATCH(cp1,cp2) \
	(strcmp(cp1,cp2) == 0)

/* define an enum value */
#define ENUMDEF(name,idx,reason) \
	name = idx,
#define ENUMDEFX(name,idx,reason) \
	name idx,

/* define tagblk for enum with short and long names */
#define ENUMTAGSHORT(name,idx,reason) \
	TAGDUAL(name),

/* define tagblk for enum with long names */
#define ENUMTAGLONG(name,idx,reason) \
	TAGINIT(name,reason),

/* define tagblk for enum with short and long names */
#define ENUMTAGBOTH(name,idx,reason) \
	TAGINIT(name,#name " -- " reason),

/* check integrity */
#ifdef HOWCHECK
#define HOWCHKX(boolflg,op) \
	do { \
		if (boolflg) \
			op; \
	} while (0)
#else /*HOWCHECK*/
#define HOWCHKX(boolflg,op)		/**/
#endif /*HOWCHECK*/
#define HOWCHK(lvl,op) \
	HOWCHKX(zprtok(lvl),op)
#define HOWCHKIF(lvl,boolflg,abtmsg) \
	HOWCHK(lvl,if (boolflg) abtmsg)

CDEFEND

#endif /*_softnet_macros_h_*/
irqtune/include/softnet/types.h100644    155    764        4416  6421553730  15131 0ustar  caeengr/* softnet/types.h -- define special types */

#ifndef _softnet_types_h_
#define _softnet_types_h_

#ifndef __KERNEL__
/* FIXME -- byte/word conflict with linux/smb.h */
typedef unsigned char byte;				/* 8 bit unsigned */
typedef unsigned short word;			/* 16 bit unsigned */
typedef unsigned long longword;			/* 32 bit unsigned */
#endif /*__KERNEL__*/

#ifdef linux
#include <linux/linkage.h>
#include <linux/types.h>
#else /*linux*/
typedef unsigned char u_char;			/* 8 bit unsigned */
typedef unsigned short u_short;			/* 16 bit unsigned */
typedef unsigned int u_int;				/* 16/32 bit unsigned */
typedef unsigned long u_long;			/* 32 bit unsigned */
#endif /*linux*/
typedef long long quad;					/* 64 bit signed */
typedef unsigned long long u_quad;		/* 64 bit unsigned */
typedef long double huge;				/* 128 bit float */
typedef u_long mskof_t;					/* standard bit mask */

/* type to use to absolutely force an inline function despite gratuitous */
/* meddling by compiler/library writers :-) */
#define VXInline	extern inline
#define VSInline	static inline
#define VInline		VXInline

/* NOTE: linux kernel is compiled with strict prototypes on */
#ifdef __KERNEL__
#define PROCPTR_T(typ,name) \
	typedef typ (*name)(void)
#else /*__KERNEL__*/
#define PROCPTR_T(typ,name) \
	typedef typ (*name)()
#endif /*__KERNEL__*/

PROCPTR_T(void,vdcode);					/* pointer to function */
PROCPTR_T(void *,vpcode);				/* pointer to function returning void pointer */
PROCPTR_T(long,lgcode);					/* pointer to function returning long */
PROCPTR_T(u_long,lwcode);				/* pointer to function returning u_long */

#ifndef NULL
#define NULL		0
#endif /*NULL*/

/* FIXME -- kluge to support more modern compiler stuff */
#ifdef factor
#ifndef const
#define const		/**/
#endif /*const*/
#ifndef volatile
#define volatile	/**/
#endif /*volatile*/
#endif /*factor*/

#ifdef __cplusplus
#define CDEFBEGIN		extern "C" {
#define CDEFEND			}
#define CDEFPROC		extern "C"
#define CDEFMAIN		extern "C" void
#define voidarg			/*voidarg*/
#else /*__cplusplus*/
#define CDEFBEGIN		/**/
#define CDEFEND			/**/
#define CDEFPROC		/**/
#define CDEFMAIN		void
#define voidarg			void
#endif /*__cplusplus*/

/* FIXME -- GCC complains about certain function pointer typedefs */
#define GCC_TYPEDEF_BUG(fnc,args) \
	(fnc)()

#endif /*_softnet_types_h_*/
irqtune/include/softnet/zprt.h100644    155    764         575  6421553730  14746 0ustar  caeengr/* softnet/zprt.h -- zprt control */

#ifndef _softnet_zprt_h_
#define _softnet_zprt_h_

#include <stdarg.h>

#include <softnet/types.h>
#include <softnet/macros.h>

CDEFBEGIN

#include <softnet/zprtundef.h>
#include <softnet/zprtdef.h>

/* GDB syncup */
#define gdbhold_define(_val) \
	volatile int gdbhold = _val;

#include <softnet/zprt.P>

CDEFEND

#endif /*_softnet_zprt_h_*/
irqtune/include/softnet/zprtdef.h100644    155    764        2570  6421553730  15442 0ustar  caeengr/* softnet/zprtdef.h -- zprt definition control */

#define zprta(lvl,args) \
	if (zprtok(lvl)) \
		zprtx/**/args
#define zmsga(lvl,args) \
	if (zprtok(lvl)) \
		zmsgx/**/args

#ifdef HOWFAR
#define zprt(lvl,args)			zprta(lvl,args)
#else /*HOWFAR*/
#define zprt(lvl,args)			/**/
#endif /*HOWFAR*/

#ifdef HOWFAR
#define zmsg(lvl,args)			zmsga(lvl,args)
#else /*HOWFAR*/
#define zmsg(lvl,args)			/**/
#endif /*HOWFAR*/

/* execute an arbitrary command */
#ifdef HOWFAR
#define zprtexec(lvl,args) \
	if (zprtok(lvl)) \
		args
#else /*HOWFAR*/
#define zprtexec(lvl,args)		/**/
#endif /*HOWFAR*/

/* wait for GDB to catch up */
#ifdef HOWFAR
#ifndef zprtgdb
#define zprtgdb(lvl,args) \
	if (lvl) \
		zprtgdbx/**/args
#endif /*zprtgdb*/
#else /*HOWFAR*/
#ifdef zprtgdb
#undef zprtgdb
#endif /*zprtgdb*/
#define zprtgdb(lvl,args)		/**/
#endif /*HOWFAR*/

/* execute a dump command */
#define zdmp(lvl,opt,bf,bflen,reason) \
	zprtexec(lvl,zdmpx(opt,bf,bflen,reason))

#ifdef HOWFAR
#define zprt_enter(lvl,args) \
	if (zprtok(lvl)) \
		zprtx_enter/**/args
#else /*HOWFAR*/
#define zprt_enter(lvl,args)			/**/
#endif /*HOWFAR*/

#define _zprt_exit(lvl,boolflg,name,what,fmt,err) \
	zprtexec(lvl,if (boolflg) zprtx_exit(name ": " what " " #err "=" fmt,err))
#define zprt_exit(lvl,name,err) \
	_zprt_exit(lvl,1,name,"EXIT","%d",err)
#define zprt_exitx(lvl,name,err) \
	_zprt_exit(lvl,1,name,"EXIT","%8.8X",err)
irqtune/include/softnet/zprtundef.h100644    155    764         354  6421553730  15763 0ustar  caeengr/* softnet/zprtundef.h -- zprt undefine control */

/* insure that things are defined properly undefined */
#undef zprta
#undef zmsga
#undef zprt
#undef zmsg
#undef zprtexec
#undef zprtgdb
#undef zprt_enter
#undef zprt_exit
#undef zdmp
irqtune/README.html100644    155    764      225377  6422514524  12404 0ustar  caeengr<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN//3.0">
<HTML>
<HEAD>
<CENTER>
<TITLE>IRQTUNE -- A Linux IRQ Priority Optimizer</TITLE>
</CENTER>
</HEAD>
<BODY>
<P><P>
<CENTER>
<HR>
<H1>
<A NAME="__irqtune_0__"><EM>IRQTUNE</EM> -- A Linux IRQ Priority Optimizer</A>
</H1>
</CENTER>
<CENTER>
<EM>
Copyright 1996, 1997 by Craig Estey.
<BR>
<STRONG>
irqtune version 0.6
</STRONG>
<BR>
Last updated: Sun Oct 19 16:35:00 PDT 1997
<BR>
See the <A HREF="#__irqtune_66__">Changes</A> section at the bottom of this document.
<BR>
<A HREF="#__irqtune_72__">Table of Contents</A>
</EM>
</CENTER>
<P>
<EM>irqtune</EM> changes the IRQ priority of devices to allow devices that require
high priority and fast service (e.g. serial ports, modems) to have it.
<P>
<STRONG>
With <EM>irqtune</EM>, a 3X speedup of serial/modem throughput is possible.
</STRONG>
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_1__">Where do I get <EM>irqtune</EM>?</A>
</H1>
<EM>irqtune</EM> is free software under the terms and conditions of the GNU Public
License.  See the file COPYING, included in the distribution, for details.
<P>
<UL>
<LI>
The author is Craig Estey, (<A HREF="MAILTO:cae@best.com">cae@best.com</A>).
<P>
<LI>
This FAQ is available online via
<A HREF="http://www.best.com/~cae/irqtune">http://www.best.com/~cae/irqtune</A>.  This is the most authoritative reference
and will always contain the most up-to-date information.
<P>
<LI>
The distribution is a gzipped tar archive that contains all programs, sources,
and this FAQ (in both HTML and text versions).  It is available from:
<P>
<UL>
<LI>
<A HREF="http://www.best.com/~cae/irqtune/irqtune.tgz">http://www.best.com/~cae/irqtune/irqtune.tgz</A>
<BR>
<LI>
<A HREF="ftp://shell5.ba.best.com/pub/cae/irqtune.tgz">ftp://shell5.ba.best.com/pub/cae/irqtune.tgz</A>
<BR>
</UL>
</UL>
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_2__">How do I know if I need <EM>irqtune</EM>?</A>
</H1>
<STRONG>You are running Linux on an x86 PC, other architectures to be implemented</STRONG>
<STRONG>later--Sorry.</STRONG>
<P>
<STRONG>
You probably need <EM>irqtune</EM>, if you are experiencing any of the following:
</STRONG>
<P>
<UL>
<LI>
SLIP/PPP transfers seem slow.  For example, using a 28.8 (or better) modem,
the effective throughput is approximately 700 bytes/second instead of the
expected 2500 bytes/second.
<P>
<LI>
A running serial or SLIP/PPP connection is slow, drops data, hangs, or
times out.
<P>
<LI>
Netscape hangs mysteriously or stalls when trying to access a web page.
<P>
<LI>
Equivalent serial/PPP programs under Windoze run much faster than under Linux.
<P>
<LI>
Disk accesses seem to interfere with SLIP/PPP.
<P>
<LI>
Interrupt handlers for specialized, time critical devices don't get control
when they need to.
<P>
</UL>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_3__">What is actually happening to cause these problems?</A>
</H1>
<P>
When the PC boots Linux, the timer is
given, by default, the highest IRQ priority in the system (it's IRQ 0 and thus,
priority 0).  On a standard configuration, the serial ports are priority
11 and 12!!!  This means that 10 other devices have higher priority.
<P>
<P><P>
<H3>
<A NAME="__irqtune_4__">Q: So what does IRQ priority do?</A>
</H3>
<P>
When multiple devices are in contention to interrupt the CPU, their priority
decides which interrupts will occur in what order.
<P>
<P><P>
<H3>
<A NAME="__irqtune_5__">Q: When does this contention occur?</A>
</H3>
<P>
After an arbitrary period of having interrupts disabled (e.g after a <EM>cli</EM>),
at the point where they're reenabled (<EM>sti</EM>).  This can happen in several
places:
<P>
<UL>
<LI>
In an ISR that runs with interrupts locked, it happens in the <EM>epilog</EM>, just
before attempting to execute the <EM>bottom-half</EM>.
<P>
<LI>
The <EM>bottom-half</EM> itself may do a lock and unlock.
<P>
<LI>
When a task that enters the kernel to do a system call, the system call
handler may lock and unlock interrupts briefly.
<P>
<LI>
Almost anywhere in the kernel are brief periods where it does a <EM>cli</EM> to
lock interrupts and then an <EM>sti</EM> to unlock them again.
<P>
<LI>
Under Linux, from the moment the first instruction of the ISR <EM>prolog</EM> is
executed until an <EM>sti</EM> is done (This occurs even in <EM>slow</EM> interrupts
where the <EM>prolog</EM> does an <EM>sti</EM> after just a few instructions).
<P>
</UL>
<P><P>
<H3>
<A NAME="__irqtune_6__">Q: If there are multiple interrupts now pending, which one gets the service, the serial or some other?</A>
</H3>
<P>
In the default configuration, the serial ISR will usually lose as it's
priority 11.
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_7__">How does irqtune help this?</A>
</H1>
<P>
<EM>irqtune</EM> gives priority 0 to whatever device we specify.  If we
specify
a serial device, <EM>irqtune</EM> guarantees that the serial ISR gets control
whenever a contention occurs.
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_8__">Why does the serial interrupt service require the highest priority?</A>
</H1>
<P>
<P><P>
<H3>
<A NAME="__irqtune_9__">Q: Why does the serial device merit such special treatment?</A>
</H3>
<P>
Serial devices are somewhat unique.  Even though they have one of
the slowest data rates (relative to a disk), they are the largest consumer
of interrupts and are extremely sensitive to <EM>interrupt latency</EM> (the time
from when a device yanks the IRQ line until its ISR is executed).
<P>
<P><P>
<H3>
<A NAME="__irqtune_10__">Q: Could you give a concrete example of this?</A>
</H3>
<P>
<UL>
<LI>
For a modem running at 33.6, we can have a peak maximum (with
compression) of 6700 bytes/second.  The serial driver programs the silo to
interrupt after 8 bytes, leaving a latency window of 8 bytes.  This means
that when the serial port yanks its IRQ line, it can still absorb 8 more
characters before its buffer will overflow and data will be dropped
<P>
<LI>
In terms of time, this means that the maximum that the serial ISR may be
delayed is
(8 / 6700) seconds or 1194 microseconds.  It also means that the serial ISR
will require 838 interrupts/second.
<P>
<LI>
Currently there are 52 devices that install their ISR with the SA_INTERRUPT
option.
This means that they wish to run with interrupts disabled.
I have not looked at all the devices, but just
assume for the moment that all will run with interrupts locked for an
arbitrary period.
<P>
<LI>
Assume we've got 4 of them pending (remember,
at <EM>higher</EM> priority).  Assume that they will lock interrupts individually
for 320, 300, 190, and 500 microseconds, respectively.  Assume that the
serial ISR also wants an interrupt.
<P>
<LI>
This means that the serial ISR will have to wait for (320 + 300 + 190 + 500)
or 1310us
for these other higher priority ISR's to run to completion.  This is greater
than the maximum of 1194 us.
<P>
<LI>
With internal
modems, we probably just see start/stop behavior causing a slowdown.
With an external modem, <STRONG>data will be dropped</STRONG>.  This will cause PPP to see
a CRC error and request transmission.  Remember, the <EM>entire</EM> packet must be
retransmitted, which means we just wasted 296-1500 bytes (depending on the
selected MRU).
With an MRU of 1500 bytes, we just
wasted 23.4% of the bandwidth in a given second--all for the loss of a single
byte!
<P>
<LI>
Worse yet, consider a 115 Kbps ISDN card that is
masquerading as a serial device <EM>(Yes, I know it should be a DMA device)</EM>.
In this case, the maximum delay the serial ISR can wait is 695 us.  And that's
just one ISDN channel.  Try adding the other and, well, <EM>golly :-)</EM>.
<P>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_11__">Q: In this example, how would boosting serial IRQ priority help?</A>
</H3>
<UL>
<LI>
If the serial IRQ had priority 0, it would get in <EM>before</EM> the others.  It
could also <STRONG>re-interrupt</STRONG> after any individual lockout window.  Thus, the
maximum
it would be forced to wait would be largest individual time, not the
<STRONG>summation</STRONG> of all of these times.  In this example, this means 500 us.
which is now within the 1194 us. maximum for the serial ISR.
<P>
<LI>
It has been my experience that the serial device <STRONG>must always</STRONG> win these
battles for contention.  When serial devices don't get what they <EM>need</EM>,
when they need it, they slow horribly or drop data outright.
<P>
</UL>
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_12__">Isn't that example very <EM>unlikely</EM> under Linux?</A>
</H1>
<P>
<EM>Unlikely</EM> doesn't mean never.  There are places were the contention period
<STRONG>must</STRONG> occur, no matter how we program the CPU.
<P>
Variations in CPU speed,
RAM size, RAM speed, cache size, disk speed, disk rotational position,
number and type of other devices, system workload, etc, etc etc, all
contribute to variations of order and timing of internal OS events.
<P>
<EM>Unlikely</EM> on one system may mean 1/1000th % chance.  On another system, it
may mean <EM>happens 50 times/second</EM>.  Beyond a certain point, it all comes
down to <EM>measurement</EM>.
<P>
Tight, accurate, repeatable measurement is the key
to system tuning.  If we can't measure it, we can't tune it.  Once we
<EM>can</EM> measure 
these things, we can then <EM>try</EM> various combinations until we achieve
our desired results.  It can often be pointless to guess at performance.
<P>
In fact, the interrupt disable windows themselves are used to prevent data
corruption caused by various parts of the kernel that try to update a data
structure simultaneously and get corrupted.  Many of these windows are put
there in the <EM>unlikely</EM> case that such corruption would occur.  In this
context, <EM>unlikely</EM> is <STRONG>never</STRONG> considered a reason to forego interrupt
locking.  Eliminating a necessary interrupt lock window could result in
kernel panics, RAM corruption, disk data corruption, etc.
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_13__">Doesn't this hurt the performance of other devices?</A>
</H1>
<P>
<STRONG>Not really</STRONG>.
<P>
In actual practice, most devices don't even notice the difference.
Most other
devices (e.g. disks, tape, ethernet) are <EM>DMA</EM> devices.  The <EM>DMA</EM> does
most of the work, thus greatly reducing their need for interrupts.  If the
device allows a request queue, it may function autonomously on several
requests, producing only one interrupt for the entire batch.
<P>
Furthermore, serial interrupt services are, themselves, <EM>very</EM> fast.  They
slam their data as quickly as possible and get out ASAP.  No fancy
calculations, just the minimum, mindless data transfer.  Almost everything
else is handled later, in the <EM>bottom-half</EM> with interrupts enabled.  In
fact, a serial ISR may have to re-interrupt it's own <EM>bottom-half</EM> several
times.
<P>
Those devices that
<EM>do</EM> experience some slight slowdown are more likely to have long interrupt
disable windows themselves.  Having several smaller <EM>cli/sti</EM> windows is
much better than one large <EM>cli/sti</EM> window--It's just harder to program.
<P>
<P><P>
<H3>
<A NAME="__irqtune_14__">Q: But suppose I want a balanced priority system?</A>
</H3>
<P>
Well, actually a <EM>prioritized</EM> system behaves like a <EM>balanced</EM>
system--most of the time.  This occurs when all devices have short interrupt
lockout windows and short ISR execution times.  The priority mechanism is
like a safety valve--it only really matters when some device or combination
of devices has held interrupts locked for an extended period of time.
<P>
<P><P>
<H3>
<A NAME="__irqtune_15__">Q: But doesn't that seem <EM>unfair</EM> to other devices?</A>
</H3>
<P>
When a disk ISR gets delayed,
that's all that happens, a slight delay--disks and tapes are <STRONG>not</STRONG> real-time
devices.  When a serial ISR gets delayed, data is destroyed--serial devices
<STRONG>are</STRONG> real-time devices that dictate the cadence of the entire system.
<P>
<STRONG>
It may sound cruel, but you just can't be <EM>fair</EM>.
</STRONG>
<P>
And speaking of sound, if the sound card gets delayed,
we hear an annoying pop right in the middle of our favorite piece of music.
<P>
These are real-time devices that can <STRONG>not</STRONG> tolerate excessive delays.  If we
must defer some less time critical devices to meet the minimum real-time
criteria of devices, then that's a bargain.
<P>
<P><P>
<H3>
<A NAME="__irqtune_16__">Q: But suppose I really want both fast serial and fast disk?</A>
</H3>
<P>
Ultimately, it's a bit of a compromise.  Which is better:
<BR>
<UL>
<LI>
Reliable serial and <EM>slightly</EM> slower disk.
<BR>
<LI>
<EM>Slightly</EM> faster disk and <EM>unreliable</EM> serial/modem support.
<BR>
</UL>
<EM>
When paying an ISP for Internet access in $$$/hour, it's an easy decision :-).
</EM>
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_17__">Isn't th
Results 1 - 1
Help - FTP Sites List - Software Dir.
Searching half a billion files worldwide
© 1997-2009 MARUHN Internet Solutions