Filewatcher File Search
FTP Search
  
Directory 
  
Content Search 
   
pkg://irqtune-0.5-3.src.rpm:67328/irqtune.tgz  info  downloads

irqtune/ 40755    155    764           0  6313664341  10406 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        3107  6314512354  12141 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
##
##REBUILDING FROM SOURCE:
##  kvers      create kernel_version from local system (NOTE: this is normally
##             _not_ required because we use the insmod -f).  You can rebuild
##             _without_ /usr/src/linux/include
##  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 directory
SBIN = /sbin
INSTALL = simple

IRQTUNE_VERSION = 0.5
IRQTUNE_HOME := $(shell pwd)
SMKF = ../src/Makefile
CDEBUG = # -g
DEFS = CDEBUG=$(CDEBUG) IRQTUNE_HOME=$(IRQTUNE_HOME) \
	IRQTUNE_VERSION=$(IRQTUNE_VERSION) INSTALL=$(INSTALL) \
	SBIN=$(SBIN)

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

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

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

custom: kvers sbin install ;
warp9: _warp9 clean kvers sbin install ;
_warp9: FRC ; @echo Take it easy, Jim
FRC:

# show the version
version:
	@echo $(IRQTUNE_VERSION)
irqtune/src/ 40755    155    764           0  6327405007  11172 5ustar  caeengrirqtune/src/irqhigh.c100644    155    764        7072  6265027650  13101 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 irq_high_list[2] = { IRQ_HIGH_MST_DFT, IRQ_HIGH_SLV_DFT };

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

/* irq_high_offset -- compute offset into irq_high_list */
extern inline u_char
irq_high_offset(u_char irq_no)
{

	irq_no >>= 3;

	return irq_no;
}

/* irq_high_calc -- calculate priority table */
static void
irq_high_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 = irq_high_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 = irq_high_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 = IRQ_HIGH_SLV_LO;
			}
		}

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

/* irq_high_insane -- check request sanity */
/* RETURNS: error string (or NULL) */
static char *irq_high_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 >= IRQ_HIGH_SLV_HI) {
			err = "master value out of range";
			break;
		}

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

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

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

	return err;
}

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

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

	/* master */
	else
		port = 0x20;

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

	/* set specific priority (of lowest priority device) */
	if (goflg) {
		lo = (irq_no - 1) & 0x07;
		lo |= 0xC0;
		outb(lo,port);
	}
}

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

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

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

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

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

	return err;
}

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

	/* set standard COM ports highest on master and disk controller on slave */
	irq_high_set(goflg,IRQ_HIGH_MST_DFT,IRQ_HIGH_SLV_DFT);
}
irqtune/src/irqtune.c100644    155    764       27434  6327143454  13161 0ustar  caeengr/* irqtune -- load IRQ tuning module */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <irqhigh.h>
#include <sys/stat.h>
#include <sys/utsname.h>

#include <irqhigh.c>

/* /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 */
};

int allflg;							/* 1=show all devices */
int badflg;							/* 1=use semi default */
int errflg;							/* 1=show verbose errors */
int goflg;							/* 1=actually do it */
int helpflg;						/* 1=display help */
int sortflg;						/* 1=sort table by priority */
int rmflg;							/* 1=force use of rmmod */
int quietflg;						/* 1=quiet mode -- suppress table */
int verflg;							/* 1=display irqtune version */

char *proc_ints;					/* name of /proc/interrupts */
int bigcode;						/* final exit code */

char kernel_version[1];				/* kernel version compiled with */
struct utsname uts;					/* dynamic kernel version */

struct tblblk tblbase[IRQ_HIGH_MAX];

char *pgmname;
char bigbf[1024];
char pathbf[4096];					/* place to store modified $PATH value */

/* module names */
char dirtop[1024];					/* top directory */
char modnames[] = MODULES;			/* list of modules */
char *modlist[10];					/* argv for modnames */
char *modtag = MODTAG;				/* name to install under */
char modcur[1024];					/* current module name */

/* function prototypes */
char *filehead(char *name);
char *filetail(char *name);
void loader(void);
void myexit(int code);
void optget(char *cp);
void tblinit(void);
void tblread(char *file);
void tblshow(void);
int vsystem(const char *cmd);
int xstrsplit(char **argv,int argc,char *bf);
void _usage(void);
void usage(void);

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

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

	goflg = 1;
	proc_ints = "/proc/interrupts";
	setbuf(stderr,NULL);

	/* insure we got "/sbin/irqtune" and not just "irqtune" */
	cp = strchr(pgmname,'/');
	if (cp == NULL) {
		fprintf(stderr,"irqtune: irqtune must be invoked via the full path even if it's in $PATH\n");
		myexit(1);
	}

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

	/* create the list of modules */
	xstrsplit(modlist,sizeof(modlist) / sizeof(modlist[0]),modnames);

	/* decide what kernel we're running under (information only) */
	uname(&uts);

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

		switch (cp[1]) {
		case 'F':
			if (cp[2] == 0)
				usage();
			proc_ints = cp + 2;
			break;

		default:
			optget(cp + 1);
			break;
		}
	}

	/* do version and stop */
	if (verflg) {
		fprintf(stderr,"irqtune: version is %s\n",IRQTUNE_VERSION);
		exit(0);
	}

	/* display help and stop */
	if (helpflg) {
		_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(irq_high_list))
			usage();

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

	/* set bad defaults */
	if (badflg) {
		irq_high_list[0] = IRQ_HIGH_MST_BAD;
		irq_high_list[1] = IRQ_HIGH_SLV_BAD;
	}

	/* check the sanity */
	cp = irq_high_insane(irq_high_list[0],irq_high_list[1]);
	if (cp != NULL) {
		fprintf(stderr,"irqtune: unable to use values %u/%u -- %s\n",
			irq_high_list[0],irq_high_list[1],cp);
		myexit(1);
	}

	/* fake it */
	irq_high_set(0,irq_high_list[0],irq_high_list[1]);

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

	/* send the table */
	if (sortflg || (! goflg))
		quietflg = 0;
	if (bigcode)
		quietflg = 1;
	if (! quietflg) {
		tblinit();
		tblread(proc_ints);
		tblshow();
	}

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

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

	/* decide if /sbin is in $PATH */
	path = getenv("PATH");
	strcpy(pathbf,path);
	bp = pathbf;
	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("/sbin",cp) == 0)
			break;
	}

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

		if (errflg) {
			fprintf(stderr,"irqtune: adding /sbin to $PATH (warning only)\n");
			fflush(stderr);
		}

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

	/* load the module (fallback to simpler versions to insure it loads) */
	modcnt = 0;
	for (modtail = modlist;  *modtail != NULL;  ++modtail) {
		sprintf(modcur,"%s/%s",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 (errflg)
				fprintf(stderr,"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";

		/* show the version discrepancy (it _should_ not matter because of -f) */
		if (errflg && (strcmp(uts.release,kernel_version) != 0))
			fprintf(stderr,"irqtune: kernel version (BUILT: %s) (CURRENT: %s)\n",
				kernel_version,uts.release);

		cp = bigbf;

		cp += sprintf(cp,"insmod -x -o %s -f %s priority=%d,%d",
			modtag,modcur,irq_high_list[0],irq_high_list[1]);

		/* show insmod blah_blah_blah only if full errors enabled */
		if (! errflg)
			cp += sprintf(cp," >> %s 2>&1",logf);

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

		/* sync the disks, just in case */
		if (goflg)
			sync();
		code = 0;

		/* install it */
		if (goflg) {
			if (errflg)
				fprintf(stderr,"irqtune: trying command -- %s\n",bigbf);
			else
				fprintf(stderr,"irqtune: loading %s (%s)\n",modcur,modtag);
			code = vsystem(bigbf);
		}

		/* check for errors */
		bigcode = 0;
		if (code) {
			fprintf(stderr,"irqtune: insmod failed on '%s'\n",modcur);
			bigcode = 1;
			if (! rmflg)
				continue;
		}

		/* the mere act of installing does the job so uninstall immediately */
		if (goflg) {
			sprintf(bigbf,"rmmod %s",modtag);
			if (errflg)
				fprintf(stderr,"irqtune: trying command -- %s\n",bigbf);
			else
				fprintf(stderr,"irqtune: unloading %s (%s)\n",modcur,modtag);
			code = vsystem(bigbf);
		}

		if (code) {
			fprintf(stderr,"irqtune: rmmod failed on '%s'\n",modtag);
			bigcode = 1;
			if (! rmflg)
				break;
		}

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

	/* complain about no modules found whatsoever */
	if (goflg && (modcnt <= 0)) {
		fprintf(stderr,"irqtune: no irqtune modules found\n");
		bigcode = 1;
	}
}

/* optget -- get options */
void
optget(char *cp)
{

	/* decode options */
	for (;  *cp != 0;  ++cp) {
		switch (*cp) {
		case 'e':
			errflg = 1;
			break;

		case 'h':
			helpflg = 1;
			break;

		case 'n':
			goflg = 0;
			break;

		case 'o':
			badflg = 1;
			break;

		case 'q':
			quietflg = 1;
			break;

		case 's':
			sortflg = 1;
			break;

		case 'u':
			rmflg = 1;
			break;

		case 'v':
			verflg = 1;
			break;

		case 'x':
			allflg = 1;
			break;

		default:
			usage();
			break;
		}
	}
}

/* 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 (sortflg)
		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 */
	irq_high_calc();

	/* initialize the table (and calculate priorities) */
	for (irq_no = 0;  irq_no < IRQ_HIGH_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(char *file)
{
	FILE *xf;
	int err;
	char *cp;
	u_long irq_no;
	struct tblblk *tbl;
	char bf[80];

	xf = fopen(file,"r");
	if (xf == NULL) {
		fprintf(stderr,"tblread: unable to open '%s' -- %s\n",
			file,strerror(errno));
		myexit(1);
	}

	while (1) {
		/* 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 > IRQ_HIGH_SLV_HI)
				break;

			err = 0;
		} while (0);

		/* skip entry on error */
		if (err) {
			fprintf(stderr,"tblread: SYNTAX '%s'\n",bf);
			continue;
		}

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

	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 < IRQ_HIGH_MAX;  ++irq_no) {
		tbl = &tblbase[irq_no];
		if (allflg || tbl->tbl_active)
			fprintf(stderr,"I%2.2u/P%2.2u: %s\n",
				tbl->tbl_irq,tbl->tbl_prior - tbl->tbl_bias,tbl->tbl_bf);
	}
}

/* vsystem -- execute program */
/* RETURNS: error code */
int
vsystem(const char *cmd)
{
	int code;

	code = system(cmd);

	return code;
}

/* filehead -- get head of name */
/* RETURNS: pointer to tail */
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;
}

/* myexit -- do cleanup and exit */
void
myexit(int code)
{

	if (code)
		fprintf(stderr,"irqtune: errors occurred%s\n",
			errflg ? "" : " (rerun with -e for full error text)");
	else
		fprintf(stderr,"irqtune: complete\n");

	exit(code);
}

/* xstrsplit -- split buffer into tokens */
/* RETURNS: number of tokens */
int
xstrsplit(char **argv,int argc,char *bf)
{
	int argcnt;
	char *cp;

	/* place for NULL */
	--argc;

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

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

	return argcnt;
}

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

	fprintf(stderr,"usage: irqtune [options] [master] [slave]\n");

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

	fprintf(stderr,"options:\n");
	fprintf(stderr,"  -e -- show verbose errors\n");
	fprintf(stderr,"  -h -- display help\n");
	fprintf(stderr,"  -n -- nogo mode (just show what would happen)\n");
	fprintf(stderr,"  -o -- reset to original values (%u/%u)\n",
		IRQ_HIGH_MST_BAD,IRQ_HIGH_SLV_BAD);
	fprintf(stderr,"  -v -- display irqtune version\n");

	fprintf(stderr,"  -F<file> -- use <file> instead of /proc/interrupts\n");
	fprintf(stderr,"  -q -- suppress priority table printing\n");
	fprintf(stderr,"  -s -- sort table by priority\n");
	fprintf(stderr,"  -u -- force module unload\n");
	fprintf(stderr,"  -x -- show inactive devices in table\n");

	fprintf(stderr,"arguments:\n");
	fprintf(stderr,"  master -- high priority IRQ on PIC master (DEFAULT: %d)\n",
		IRQ_HIGH_MST_DFT);
	fprintf(stderr,"  slave -- high priority IRQ on PIC slave (DEFAULT: %d)\n",
		IRQ_HIGH_SLV_DFT);
}

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

	_usage();
	myexit(1);
}
irqtune/src/load.c100644    155    764        3547  6265027674  12376 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 <irqhigh.c>

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

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

#ifdef NPR
#define PRINTK				printk_npr
/* printk_npr -- all PRINTK's become nulled */
static int
printk_npr(const char *fmt,...)
{
	return 0;
}
#else /*NPR*/
#define PRINTK				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(irq_high_calc);

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

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

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

		/* perform the set */
		save_flags(flags);
		cli();
		err = irq_high_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) {
			PRINTK("irqtune/%s: ERROR expected %u/%u but got %u/%u\n",
				IRQTUNE_VERSION,vals[0],vals[1],
				irq_high_list[0],irq_high_list[1]);
			break;
		}
	} while (0);

	return err;
}

/* cleanup_module -- called by modules package when removing the driver */
void cleanup_module(void)
{
}
irqtune/src/Makefile100644    155    764        3723  6314512244  12732 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 = ../src

# modules
# NOTE: the order of MODULES can be changed if desired
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 = -DMODULES='"$(MODULES)"' \
	-DMODTAG=\"$(MODTAG)\" \
	$(KDEFS)

# things to install
TARGETLIST = $(MODULES) irqtune

WARN = -Wall -Werror -Wno-format
CFLAGSCOM = -O $(CFGINCLUDE) -I$(SDIR) -I../include $(WARN)
CKFLAGS = $(CFLAGSCOM) -D__KERNEL__ $(KDEFS)
CFLAGS = $(CFLAGSCOM) $(CDEBUG)
ifeq "$(CDEBUG)" ""
STRIP = -s
endif

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

# NOTE: making kvers should _not_ be required, but ...
kvers:
	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
	cc -c $(CFLAGS) $(CDEFS) $(SDIR)/irqtune.c

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

# -----------------------------------------------------------------
install:
	../bin/install $(INSTALL) $(SBIN) $(TARGETLIST)

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

clean:
	rm -f $(TARGETLIST) $(KOBJS) irqtune.o
irqtune/src/irqtune.pod100644    155    764      104632  6327404704  13533 0ustar  caeengr=title IRQTUNE -- A Linux x86 IRQ Priority Optimizer
=head0 ${I:IRQTUNE} -- A Linux x86 IRQ Priority Optimizer
=html1
<CENTER><EM>
Copyright 1996, 1997 by Craig Estey.
<BR>
<STRONG>
irqtune version ${IRQTUNE_VERSION}
</STRONG>
<BR>
Last updated: ${date}
<BR>
See the ${L:Changes} section at the bottom of this document.
<BR>
${L:Table of Contents}
<BR>
</EM></CENTER><P>
=html0

${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 4
=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 4
=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 4
=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 SLIP/PPP dies at random times.
=item *
Serial connections are slow or drop data.
=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 4
=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 the 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 4
=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 4
=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 4
=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 4
=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 4
=item *
Go to the containing directory.
=txt2
cd ${topdir}
=txt0
=item *
Unpack the tar file:
=txt1
gzip -d < irqtune.tgz | tar xvf -
=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
=SS1

=head3 Q: How do I do a simple installation?
=SS1
=over 4
=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 4
=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 4
=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 4
=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 4
=item *
irqtune ${I:master} ${I:slave}
=back
The only caveats are:
=over 4
=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.
=back

The default is ${I:3 14} which will work for many standard configurations.
More on this later.

=over 4
=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.
You may also issue another ${I:irqtune} command at any time.

=head3 Q: What if my kernel revision is different from the kernel revision \
that you built it on?

${I:irqtune} is 99.44% kernel revision independent.  It is built
using ELF binaries, so your ${I:insmod} must understand them.  Also, make sure
that you have the correct ${I:insmod} for your kernel.  But that's
really about it.  There are some slight caveats--these are discussed later.

=head3 Q: But what if I don't have ELF binary support, \
how can I still do things?

Well, I'd recommend that you upgrade your kernel as ELF binaries are cool :-)
But if you insist, you'll just have to recompile ${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 be sure to check
your documentation on this (You may need to add a parameter or two).
=SS1
=over 4
=item *
Then, just type:
=txt1
make warp9
=txt0
=item *
Here is the makefile's own documentation:
=include -txt -exec make
=back
=SS0
That should do the trick.  But, if it doesn't, look at revision
numbers on ${I:insmod}, ${I:gcc}, ${I:ld}, and the ${I:kernel} for incompatibilities.
Upgrade as necessary.

=head1 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 4
=item *
Just type ${B:/sbin/irqtune -n -o} and we'll get something like:
=include -txt -exec irqdoc -T${keyT} -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 4
=item *
${B:/sbin/irqtune} ${I:3}
=back
This sets IRQ 3 to the highest priority.

=over 4
=item *
After this command, the IRQ priorities are now:
=include -txt -exec irqdoc -T${keyT} -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 4
=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 4
=item *
The resulting priority would be:
=include -txt -exec irqdoc -T${keyT} -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 4
=item *
${B:/sbin/irqtune} ${I:11}
=item *
The resulting priorities would be more complex and would result in something
like:
=include -txt -exec irqdoc -T${keyT} -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 4
=item *
${B:/sbin/irqtune} ${I:3}
=item *
The resulting priorities would be:
=include -txt -exec irqdoc -T${keyT} -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 4
=item *
${B:/sbin/irqtune} ${I:3}
=item *
The resulting priorities would be:
=include -txt -exec irqdoc -T${keyT} -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 What about incompatibilities with kernel revisions?

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

Under the 2.0.X 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).

=over 4
=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 ${I: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

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

=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.

=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).
Some kernels that use MODVERSIONS
have some difficulty loading ${I:irqtune_mod.o}.

The ${I:irqtune_npr.o} module
is exactly the same as ${I:irqtune_mod.o} except that it does ${B:not} use
${I:printk}.  ${I:irqtune} first trys to load ${I:irqtune_mod.o} and falls
back to ${I:irqtune_npr.o} if it detects a loader error.  Since ${I:irqtune}
pre-checks all parameters before attempting to load the kernel module, the
confirmation message is a nicety but not a necessity.

=head1 What about hardware/config problems?

=head3 Q: What if the serial port doesn't work?
=over 4
=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.
=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 4
=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 4
=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}.

=head1 What about other performance software remedies I've heard about?

=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.

=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.

=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 4
=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 4
=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 Didn't you give another explanation before, involving ${I:bottom-half} routines?
== ${B:Yes.}
== =over 4
== =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 Changes

=head3 Revision 0.2 Changes:
=SS1
=over 4
=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 4
=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 4
=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 4
=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

=head1 Table of Contents
=toc1
irqtune/include/ 40755    155    764           0  6204730653  12030 5ustar  caeengrirqtune/include/irqhigh.h100644    155    764        1316  6265027637  13742 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 IRQ_HIGH_MST_BAD		0
#define IRQ_HIGH_SLV_BAD		8

/* defaults based on standard configuration */
#define IRQ_HIGH_MST_DFT		3
#define IRQ_HIGH_SLV_DFT		14

/* master and slave acceptable ranges */
#define IRQ_HIGH_MST_LO			0
#define IRQ_HIGH_MST_HI			7
#define IRQ_HIGH_SLV_LO			8
#define IRQ_HIGH_SLV_HI			15

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

#define RNGE(x,lo,hi) \
	(((x) >= (lo)) && ((x) <= (hi)))
irqtune/README.html100644    155    764      132624  6327405006  12372 0ustar  caeengr<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN//3.0">
<HTML>
<HEAD>
<CENTER>
<TITLE>IRQTUNE -- A Linux x86 IRQ Priority Optimizer</TITLE>
</CENTER>
</HEAD>
<BODY>
<P><P>
<CENTER>
<HR>
<H1>
<A NAME="__irqtune_0__"><EM>IRQTUNE</EM> -- A Linux x86 IRQ Priority Optimizer</A>
</H1>
</CENTER>
<CENTER><EM>
Copyright 1996, 1997 by Craig Estey.
<BR>
<STRONG>
irqtune version 0.5
</STRONG>
<BR>
Last updated: Wed Apr 23 06:08:54 PDT 1997
<BR>
See the <A HREF="#__irqtune_57__">Changes</A> section at the bottom of this document.
<BR>
<A HREF="#__irqtune_62__">Table of Contents</A>
<BR>
</EM></CENTER><P>
<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 SLIP/PPP dies at random times.
<P>
<LI>
Serial connections are slow or drop data.
<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 the 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>
<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 this IRQ priority thing a bit of a new idea?</A>
</H1>
<P>
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.
<EM>With a 4Mhz CPU, these problems used to occur at 1200 baud :-)</EM>
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_18__">How do I install <EM>irqtune</EM>?</A>
</H1>
<P>
<P><P>
<H3>
<A NAME="__irqtune_19__">Q: Where should I place <EM>irqtune</EM> files?</A>
</H3>
<UL>
<LI>
Decide what directory you would like to <STRONG>contain</STRONG> <EM>irqtune</EM>'s
home directory.
Some good choices are:
<STRONG>/usr/local</STRONG>,
<STRONG>/usr/lib</STRONG>,
<STRONG>/usr/lib/hwtools</STRONG>,
<STRONG>/home</STRONG>.
<BR>
<LI>
Exactly where depends upon your local conventions.
<BR>
<LI>
In this example, we'll use <STRONG>/usr/local</STRONG>.
<BR>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_20__">Q: How do I unpack the archive?</A>
</H3>
<UL>
<LI>
Go to the containing directory.
<BR>
<CODE>
cd /usr/local
<BR>
</CODE>
<LI>
Unpack the tar file:
<BR>
<CODE>
gzip -d &#60; irqtune.tgz | tar xvf -
<BR>
</CODE>
<LI>
This will create a directory, <STRONG>irqtune</STRONG> in <STRONG>/usr/local</STRONG>.  This is
<STRONG>/usr/local/irqtune</STRONG>.  We will call this <STRONG>IRQTUNE_HOME</STRONG>.
<BR>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_21__">Q: How do I do a simple installation?</A>
</H3>
<UL>
<LI>
Go to the <STRONG>IRQTUNE_HOME</STRONG> directory:
<BR>
<CODE>
cd /usr/local/irqtune
<BR>
</CODE>
<LI>
To install <EM>irqtune</EM>, enter:
<BR>
<CODE>
make install
<BR>
</CODE>
<LI>
This will install the files:
<BR>
<CODE>
/sbin/irqtune
<BR>
/sbin/irqtune_mod.o
<BR>
/sbin/irqtune_npr.o
<BR>
</CODE>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_22__">Q: Why are .o files being placed in the /sbin directory?</A>
</H3>
<P>
<EM>
As a note to purists, the installation directory is completely arbitrary.
<STRONG>/sbin</STRONG> is short, sweet, and easy to type.
</EM>
<P>
The standard convention would be to install <STRONG>irqtune</STRONG> as <STRONG>/sbin/irqtune</STRONG>
and the .o files as, say, <STRONG>/usr/lib/irqtune/*.o</STRONG>.
<EM>irqtune</EM> 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:
<BR>
<UL>
<LI>
Multiple versions of <EM>irqtune</EM> to be installed simultaneously (in different
directories).
<BR>
<LI>
Simplifies testing of new versions.
<BR>
<LI>
Provides better assurance that the built version is correct.
<BR>
<LI>
Using one directory produces less clutter.
<BR>
<LI>
One directory is more portable across all the myriad kernel revisions.
<BR>
<LI>
Future versions of <EM>irqtune</EM> may imbed the .o's directly into <STRONG>irqtune</STRONG>.
<BR>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_23__">Q: What if I really don't want .o files in <STRONG>/sbin</STRONG>?</A>
</H3>
<P>
If placing .o files in <STRONG>/sbin</STRONG> is deemed to be an
anathema, we have two options:
<BR>
<UL>
<LI>
Simply use another directory in place of <STRONG>/sbin</STRONG>:
<BR>
<CODE>
make SBIN=/whatever install
<BR>
</CODE>
<LI>
Install with a stub (This will install /sbin/irqtune as a shell script and use
<STRONG>IRQTUNE_HOME</STRONG>/sbin/irqtune_*.o):
<BR>
<CODE>
make INSTALL=sh install
<BR>
</CODE>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_24__">Q: Are there any special considerations for this alternate installation method?</A>
</H3>
<P>
Yes.  If the shell/stub installation method is used:
<BR>
<UL>
<LI>
<STRONG>IRQTUNE_HOME</STRONG> must not be removed.
<BR>
<LI>
If using <EM>irqtune</EM> from an /etc/rc.d/rc.* file <STRONG>and</STRONG> <EM>irqtune</EM> will be
invoked <STRONG>before</STRONG> secondary mounts are done, <STRONG>IRQTUNE_HOME</STRONG> should be
placed on the root device.
<BR>
</UL>
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_25__">How do I use <EM>irqtune</EM>?  Don't I have to rebuild my kernel?</A>
</H1>
No, we do <STRONG>not</STRONG> have to rebuild the kernel.  <EM>irqtune</EM> uses <EM>insmod</EM>
and
<EM>rmmod</EM> to dynamically load and unload a kernel module.  But it is correct
to sense that irqtune is a kernel patch.
<P>
<P><P>
<H3>
<A NAME="__irqtune_26__">Q: Ok, if it's a kernel patch, why not just issue a kernel patch like everybody else does (e.g. diff -u output)?</A>
</H3>
<P>
<EM>irqtune</EM> will work even if we don't have the kernel source loaded.  It uses
<EM>insmod</EM> to load the patch, invoke it, and then unload it.  The IRQ priority
changes will last so long as the kernel is booted.
<P>
<P><P>
<H3>
<A NAME="__irqtune_27__">Q: How do we invoke it?</A>
</H3>
<P>
<EM>irqtune</EM> takes two arguments optional arguments:
<BR>
<UL>
<LI>
irqtune <EM>master</EM> <EM>slave</EM>
<BR>
</UL>
The only caveats are:
<BR>
<UL>
<LI>
If we did a simple installation, we must specify the full pathname, even
if <EM>irqtune</EM> is placed in a directory that is in $PATH.  This is required
because <EM>irqtune</EM> uses argv[0] to locate its <STRONG>irqtune_mod.o</STRONG> file.
<BR>
<LI>
<STRONG>/sbin</STRONG> <EM>should</EM> be in $PATH--this is the probable place for
<EM>insmod</EM>.  As a convenience, <EM>irqtune</EM> will add <STRONG>/sbin</STRONG> to $PATH
automatically.
<BR>
</UL>
<P>
The default is <EM>3 14</EM> which will work for many standard configurations.
More on this later.
<P>
<BR>
<UL>
<LI>
Here is the usage output from irqtune:
<BR>
<CODE>
usage: irqtune [options] [master] [slave]
<BR>
version: 0.5
<BR>
options:
<BR>
  -e -- show verbose errors
<BR>
  -h -- display help
<BR>
  -n -- nogo mode (just show what would happen)
<BR>
  -o -- reset to original values (0/8)
<BR>
  -v -- display irqtune version
<BR>
  -F&#60;file&#62; -- use &#60;file&#62; instead of /proc/interrupts
<BR>
  -q -- suppress priority table printing
<BR>
  -s -- sort table by priority
<BR>
  -u -- force module unload
<BR>
  -x -- show inactive devices in table
<BR>
arguments:
<BR>
  master -- high priority IRQ on PIC master (DEFAULT: 3)
<BR>
  slave -- high priority IRQ on PIC slave (DEFAULT: 14)
<BR>
</CODE>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_28__">Q: Could we do this from my /etc/rc.d/rc.local file?</A>
</H3>
<P>
Yes. Just add a <STRONG>/sbin/irqtune</STRONG> line to this file and we're
in business.
You may also issue another <EM>irqtune</EM> command at any time.
<P>
<P><P>
<H3>
<A NAME="__irqtune_29__">Q: What if my kernel revision is different from the kernel revision that you built it on?</A>
</H3>
<P>
<EM>irqtune</EM> is 99.44% kernel revision independent.  It is built
using ELF binaries, so your <EM>insmod</EM> must understand them.  Also, make sure
that you have the correct <EM>insmod</EM> for your kernel.  But that's
really about it.  There are some slight caveats--these are discussed later.
<P>
<P><P>
<H3>
<A NAME="__irqtune_30__">Q: But what if I don't have ELF binary support, how can I still do things?</A>
</H3>
<P>
Well, I'd recommend that you upgrade your kernel as ELF binaries are cool :-)
But if you insist, you'll just have to recompile <EM>irqtune</EM>.  Just be sure
that <STRONG>/usr/src/linux/include</STRONG> is installed.  The exact procedure for building
<EM>a.out</EM> binaries can vary with compiler revision, so be sure to check
your documentation on this (You may need to add a parameter or two).
<BR>
<UL>
<LI>
Then, just type:
<BR>
<CODE>
make warp9
<BR>
</CODE>
<LI>
Here is the makefile's own documentation:
<BR>
<CODE>
INSTALLATION:
<BR>
  install    install prebuilt binaries in /sbin
<BR>
  custom     create custom installation -- Normally _not_ required -- Try
<BR>
             install first (EQUIVALENT: kvers sbin install)
<BR>
  uninstall  remove prebuilt binaries from /sbin
<BR>

<BR>
INSTALLATION OVERRIDES:
<BR>
  SBIN       SBIN=/whatever specify installation directory (DEFAULT: /sbin)
<BR>
  INSTALL    INSTALL=simple simple installation (DEFAULT: simple)
<BR>
             INSTALL=sh install as shell stub
<BR>

<BR>
REBUILDING FROM SOURCE:
<BR>
  kvers      create kernel_version from local system (NOTE: this is normally
<BR>
             _not_ required because we use the insmod -f).  You can rebuild
<BR>
             _without_ /usr/src/linux/include
<BR>
  sbin       rebuild binaries from source (full or partial)
<BR>

<BR>
FORCE FULL REBUILD (requires /usr/src/linux/include):
<BR>
  clean      remove .o files to force full recompile)
<BR>
  warp9      rebuild all (EQUIVALENT: clean kvers sbin install)
<BR>

<BR>
</CODE>
</UL>
That should do the trick.  But, if it doesn't, look at revision
numbers on <EM>insmod</EM>, <EM>gcc</EM>, <EM>ld</EM>, and the <EM>kernel</EM> for incompatibilities.
Upgrade as necessary.
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_31__">What about my non-standard hardware configuration?</A>
</H1>
<EM>irqtune</EM> 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.
<P>
<P><P>
<H3>
<A NAME="__irqtune_32__">Q: How do I determine what my IRQ configuration is?</A>
</H3>
<P>
<EM>
NOTE: For brevity, we've combined the non-sorted and sorted output in
these examples.
</EM>
<P>
<UL>
<LI>
Just type <STRONG>/sbin/irqtune -n -o</STRONG> and we'll get something like:
<P>
<PRE>
SORTED BY IRQ:                          SORTED BY PRIORITY:                     
I00/P00:   8578913   timer              I00/P00:   8578913   timer              
I01/P01:    109547   keyboard           I01/P01:    109547   keyboard           
I02/P02:         0 + cascade            I02/P02:         0 + cascade            
I03/P10:     86470 + serial             I11/P05:    197648 + sermux             
I04/P11:    197648 + serial             I12/P06:     17968 + eth                
I11/P05:    197648 + sermux             I13/P07:         1   math error         
I12/P06:     17968 + eth                I14/P08:     93123 + Ux4F               
I13/P07:         1   math error         I03/P10:     86470 + serial             
I14/P08:     93123 + Ux4F               I04/P11:    197648 + serial             
</PRE>
</UL>
<P>
<EM>
NOTE:
<STRONG>/proc/interrupts</STRONG>, 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.
</EM>
<P>
<P><P>
<H3>
<A NAME="__irqtune_33__">Q: OK, we've got the output from /sbin/irqtune -n -o, what do we do with it?</A>
</H3>
<P>
The leftmost number is the IRQ number.  The next number is the priority.
The rightmost column is the <STRONG>internal</STRONG>
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:
<P>
<UL>
<LI>
<STRONG>/sbin/irqtune</STRONG> <EM>3</EM>
<P>
</UL>
This sets IRQ 3 to the highest priority.
<P>
<P>
<UL>
<LI>
After this command, the IRQ priorities are now:
<P>
<PRE>
SORTED BY IRQ:                          SORTED BY PRIORITY:                     
I00/P05:   8578913   timer              I03/P00:     86470 + serial             
I01/P06:    109547   keyboard           I04/P01:    197648 + serial             
I02/P07:         0 + cascade            I00/P05:   8578913   timer              
I03/P00:     86470 + serial             I01/P06:    109547   keyboard           
I04/P01:    197648 + serial             I02/P07:         0 + cascade            
I11/P12:    197648 + sermux             I14/P07:     93123 + Ux4F               
I12/P13:     17968 + eth                I11/P12:    197648 + sermux             
I13/P14:         1   math error         I12/P13:     17968 + eth                
I14/P07:     93123 + Ux4F               I13/P14:         1   math error         
</PRE>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_34__">Q: BTW, What's the cascade device I saw in the output of irqtune?</A>
</H3>
<P>
Glad you asked.  There are actually two interrupt controllers, a <EM>master</EM>
and a <EM>slave</EM>.  The <EM>slave</EM> is <EM>cascaded</EM> to the <EM>master</EM> via its IRQ 2.
The <EM>master</EM> controls IRQ's 0-7 and the <EM>slave</EM> controls IRQ's 8-15.
<P>
You actually may select two high IRQ priorities, one for the <EM>master</EM> and one
for the <EM>slave</EM>.  <EM>irqtune</EM> defaults the <EM>slave</EM> to IRQ 14, which is
normally the disk controller.
<P>
In fact, <EM>cascade</EM> is sort of a "zero width" device as it does not
contribute to interrupt latency.  Setting the <EM>cascade</EM> to top
priority on the <EM>master</EM> has an interesting effect which we'll see shortly.
<P>
<P><P>
<H3>
<A NAME="__irqtune_35__">Q: But we've also got an Ethernet controller on IRQ 12.  What about that?</A>
</H3>
<P>
In this case, we might want to use:
<P>
<UL>
<LI>
<STRONG>/sbin/irqtune</STRONG> <EM>3 12</EM>
<P>
</UL>
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.
<P>
<P>
<UL>
<LI>
The resulting priority would be:
<P>
<PRE>
SORTED BY IRQ:                          SORTED BY PRIORITY:                     
I00/P05:   8578913   timer              I03/P00:     86470 + serial             
I01/P06:    109547   keyboard           I04/P01:    197648 + serial             
I02/P07:         0 + cascade            I00/P05:   8578913   timer              
I03/P00:     86470 + serial             I01/P06:    109547   keyboard           
I04/P01:    197648 + serial             I02/P07:         0 + cascade            
I11/P14:    197648 + sermux             I12/P07:     17968 + eth                
I12/P07:     17968 + eth                I13/P08:         1   math error         
I13/P08:         1   math error         I14/P09:     93123 + Ux4F               
I14/P09:     93123 + Ux4F               I11/P14:    197648 + sermux             
</PRE>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_36__">Q: What about the serial multiplexer card on IRQ 11?</A>
</H3>
<P>
This is a bit tricky because now we've got a serial device on
the <EM>slave</EM> controller.  It would be much better to put all serial cards on
the <EM>master</EM> controller.  Things would stay much simpler.
<P>
In this case we would want to use:
<P>
<UL>
<LI>
<STRONG>/sbin/irqtune</STRONG> <EM>11</EM>
<P>
<LI>
The resulting priorities would be more complex and would result in something
like:
<P>
<PRE>
SORTED BY IRQ:                          SORTED BY PRIORITY:                     
I00/P13:   8578913   timer              I02/P00:         0 + cascade            
I01/P14:    109547   keyboard           I11/P00:    197648 + sermux             
I02/P00:         0 + cascade            I12/P01:     17968 + eth                
I03/P08:     86470 + serial             I13/P02:         1   math error         
I04/P09:    197648 + serial             I14/P03:     93123 + Ux4F               
I11/P00:    197648 + sermux             I03/P08:     86470 + serial             
I12/P01:     17968 + eth                I04/P09:    197648 + serial             
I13/P02:         1   math error         I00/P13:   8578913   timer              
I14/P03:     93123 + Ux4F               I01/P14:    109547   keyboard           
</PRE>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_37__">Q: Wait a minute.  didn't we just specify a <EM>slave</EM> IRQ number as the <EM>master</EM> to <EM>irqtune</EM>?</A>
</H3>
<P>
Yes, this is shorthand way of saying <EM>2 11</EM>.  You can make a <EM>slave</EM>
device top priority, but we get no options for the <EM>master</EM> IRQ.  It
will always be <EM>2</EM>, the <EM>cascade</EM> device.  Remember, the <EM>cascade</EM>
device contributes no latency delay by itself.
<P>
<P><P>
<H3>
<A NAME="__irqtune_38__">Q: So why is this configuration so bad?</A>
</H3>
<P>
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.
<P>
<P><P>
<H3>
<A NAME="__irqtune_39__">Q: How can we fix this with software?</A>
</H3>
<P>
<STRONG>
We can't.
<P>
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.
</STRONG>
<P>
We'll go back to the earlier example.  We'll wave a magic wand and
<EM>Poof!</EM>--assume we just restrapped the serial multiplexer to IRQ 5:
<P>
<UL>
<LI>
<STRONG>/sbin/irqtune</STRONG> <EM>3</EM>
<P>
<LI>
The resulting priorities would be:
<P>
<PRE>
SORTED BY IRQ:                          SORTED BY PRIORITY:                     
I00/P05:   8578913   timer              I03/P00:     86470 + serial             
I01/P06:    109547   keyboard           I04/P01:    197648 + serial             
I02/P07:         0 + cascade            I05/P02:    197648 + sermux             
I03/P00:     86470 + serial             I00/P05:   8578913   timer              
I04/P01:    197648 + serial             I01/P06:    109547   keyboard           
I05/P02:    197648 + sermux             I02/P07:         0 + cascade            
I12/P13:     17968 + eth                I14/P07:     93123 + Ux4F               
I13/P14:         1   math error         I12/P13:     17968 + eth                
I14/P07:     93123 + Ux4F               I13/P14:         1   math error         
</PRE>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_40__">Q: Could we do more of this restrapping, say, with the ethernet controller?</A>
</H3>
<P>
Sure.  Waving the wand again, we restrap the ethernet card to IRQ 6.
<P>
<UL>
<LI>
<STRONG>/sbin/irqtune</STRONG> <EM>3</EM>
<P>
<LI>
The resulting priorities would be:
<P>
<PRE>
SORTED BY IRQ:                          SORTED BY PRIORITY:                     
I00/P05:   8578913   timer              I03/P00:     86470 + serial             
I01/P06:    109547   keyboard           I04/P01:    197648 + serial             
I02/P07:         0 + cascade            I05/P02:    197648 + sermux             
I03/P00:     86470 + serial             I06/P03:     17968 + eth                
I04/P01:    197648 + serial             I00/P05:   8578913   timer              
I05/P02:    197648 + sermux             I01/P06:    109547   keyboard           
I06/P03:     17968 + eth                I02/P07:         0 + cascade            
I13/P14:         1   math error         I14/P07:     93123 + Ux4F               
I14/P07:     93123 + Ux4F               I13/P14:         1   math error         
</PRE>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_41__">So in order to get the best overall system, we may need to change IRQ priority <EM>and</EM> physically change the hardware IRQ configuration?</A>
</H3>
<P>
<STRONG><EM>Exactly</EM></STRONG>.
<P>
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
<EM>
one size fits all
</EM>
solution.
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_42__">What about incompatibilities with kernel revisions?</A>
</H1>
<P>
<P><P>
<H3>
<A NAME="__irqtune_43__">Q: What about IRQ sharing of serial ports?</A>
</H3>
<P>
Under the 2.0.X kernels, use of IRQ sharing will defeat IRQ priority because
the serial port ISR's are installed as <EM>slow</EM> rather than <EM>fast</EM>
interrupts (e.g. they don't use the SA_INTERRUPT flag).
<P>
<P>
<UL>
<LI>
Change the serial port IRQ configuration so that ports don't share
IRQ's
<P>
<LI>
The other option is a kernel source patch to <EM>drivers/char/serial.c</EM>:
<P>
Change the following line:
<P>
<PRE>
#define IRQ_T(info) ((info-&#62;flags &#38; ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
</PRE>
and replace it with:
<PRE>
#define IRQ_T(info) (((info-&#62;flags &#38; ASYNC_SHARE_IRQ) ? SA_SHIRQ : 0) | SA_INTERRUPT)
</PRE>
</UL>
<P>
Under earlier kernels this is not a problem because the serial ISR was always
installed with SA_INTERRUPT.
<P>
<P><P>
<H3>
<A NAME="__irqtune_44__">Q: Are there any kernel revisions that <EM>irqtune</EM> won't work with?</A>
</H3>
<P>
When <EM>irqtune</EM> 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 <EM>irqtune</EM>.  These
changes were ultimately removed but <EM>irqtune</EM> will not work with kernel
revisions 2.0.15 to 2.0.18.
<P>
<P><P>
<H3>
<A NAME="__irqtune_45__">Q: What is the difference between <EM>irqtune_mod.o</EM> and <EM>irqtune_npr.o</EM>?</A>
</H3>
<P>
The only kernel symbol that <EM>irqtune</EM>'s kernel module (<EM>irqtune_mod.o</EM>)
uses is <EM>printk</EM> (to print a confirmation message to syslog).
Some kernels that use MODVERSIONS
have some difficulty loading <EM>irqtune_mod.o</EM>.
<P>
The <EM>irqtune_npr.o</EM> module
is exactly the same as <EM>irqtune_mod.o</EM> except that it does <STRONG>not</STRONG> use
<EM>printk</EM>.  <EM>irqtune</EM> first trys to load <EM>irqtune_mod.o</EM> and falls
back to <EM>irqtune_npr.o</EM> if it detects a loader error.  Since <EM>irqtune</EM>
pre-checks all parameters before attempting to load the kernel module, the
confirmation message is a nicety but not a necessity.
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_46__">What about hardware/config problems?</A>
</H1>
<P>
<P><P>
<H3>
<A NAME="__irqtune_47__">Q: What if the serial port doesn't work?</A>
</H3>
<UL>
<LI>
The First Law of Computing:  Make sure it's plugged in.
<P>
<LI>
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 <EM>extremely</EM> slow.
Some Plug-N-Play (PnP) ports may need to be explicitly strapped.
<P>
<LI>
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.
<P>
<LI>
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 <EM><STRONG>setserial</STRONG></EM> program (in
<STRONG>/etc/rc.d/rc.local</STRONG>) to force
the kernel port/IRQ settings to match the hardware strapping.
<P>
<LI>
Verify that <EM>irqtune</EM> got the correct IRQ numbers for the specific
configuration.
For example, suppose our primary serial port is on IRQ 3, but we gave
<EM>irqtune</EM> the value <EM>4</EM>.  We just made the serial device on IRQ 3 into
priority 14, not priority 0.
<P>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_48__">Q: What if PPP doesn't work?</A>
</H3>
<P>
See the PPP man page and PPP-Howto for best information, but some recommended
options:
<BR>
<UL>
<LI>
asyncmap 0
<BR>
<LI>
crtscts
<BR>
<LI>
defaultroute
<BR>
<LI>
modem
<BR>
<LI>
mru 296 mtu 296
<BR>
<LI>
passive
<BR>
</UL>
<P>
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 <EM>guard</EM>
character.
<P>
The default <EM>guard</EM> character is '+' (decimal 43, hex 2B).
Normally, 3 such characters are required within a special timing sequence.
<P>
Although it is <EM>unlikely</EM>, it is still possible that some PPP packets could
generate the <EM>guard</EM> sequence inadvertantly.  To prevent this, we may want
to inhibit the generation of the <EM>guard</EM> character in a data sequence.  To
do this,
we would add the additional PPP option:
<BR>
<UL>
<LI>
escape 2B
<BR>
</UL>
<P>
Since '+' is a common ASCII character (PPP escaped characters generate two
characters), we may wish to use a less common value
for the <EM>guard</EM> character.  For example, a less common value might be
(decimal 200, hex C8).  We would add an <STRONG>ATS2=200</STRONG> command to our modem
dialer script and change the PPP escape option to <STRONG>C8</STRONG>.
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_49__">What about other performance software remedies I've heard about?</A>
</H1>
<P>
<P><P>
<H3>
<A NAME="__irqtune_50__">Q: What about using <EM>hdparm -u</EM> to set the interrupt-unmask flag in the hard disk driver?</A>
</H3>
<P>
This is only necessary for the <EM>IDE</EM> driver.  The SCSI driver has short
disable windows by default.  This will shorten the IDE interrupt disable
windows.
<P>
<EM><STRONG>Beware:</STRONG></EM> Without this option, IDE disk activity will almost certainly
cause serial data dropouts.
<P>
<P><P>
<H3>
<A NAME="__irqtune_51__">Q: What about disabling Van Jacobsen header compression in PPP?</A>
</H3>
<P>
This reduces the amount of <EM>bottom-half</EM> 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.
<P>
<P><P>
<H3>
<A NAME="__irqtune_52__">Q: What about adjusting the MRU/MTU numbers in PPP?</A>
</H3>
<P>
Reducing the MRU/MTU
to a minimum (296) reduces the <EM>bottom-half</EM> processing and <EM>flip-buffer</EM>
latency at the expense of
adding extra overhead bytes due to the reduced packet size.
The optimal value will vary from configuration to configuration.
<P>
<EM><STRONG>Beware:</STRONG></EM> Start with 296 as the optimal may not be 1500.
<P>
<EM>
The <STRONG>flip-buffer</STRONG> is a double buffer mechanism
in the serial/tty drivers through which all data <STRONG>must</STRONG> pass.  It has a
fixed size of only 512 bytes.
MRU/MTU greater than the <STRONG>flip-buffer</STRONG> size may create an internal
race condition that may cause dropouts on slower CPU's or heavily loaded
configurations.
</EM>
<P>
<P><P>
<H3>
<A NAME="__irqtune_53__">Q: What about going to newer kernel revisions?</A>
</H3>
<P>
Although <EM>irqtune</EM> 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 <EM>irqtune</EM>'s effect.
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_54__">How can I tell if <EM>irqtune</EM> actually did anything for me?</A>
</H1>
<P>
Well, first off, if PPP/SLIP was dying mysteriously, it will probably be more
reliable.
<P>
<P><P>
<H3>
<A NAME="__irqtune_55__">Q: How can we benchmark <EM>irqtune</EM>?</A>
</H3>
Run without it and get a feel for the transfer rate:
<P>
<UL>
<LI>
Hit <EM>many</EM> 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.
<P>
<LI>
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 <EM>ascii</EM> and <EM>binary</EM> files that to see
the effect of modem compression.  <EM>Binary</EM> won't compress too well so the
numbers will reflect the <EM>real</EM> transfer rate.  <EM>Ascii</EM> files which
typically compress 2:1 will up the <EM>effective</EM> rate by 2X, making it
more stressful.
<P>
<LI>
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.
<P>
</UL>
<P>
Repeat this using <EM>irqtune</EM> and note the transfer times again.
<P>
<EM>NOTE: IRQTUNE just won't quit--if you want to test in the original mode</EM>
<EM>again, reboot the system first.</EM>
<P>
<P><P>
<H3>
<A NAME="__irqtune_56__">Q: What if we still don't see any real improvement?</A>
</H3>
<P>
It's a matter of probability.  Performance measurement is as much art as
science.
<P>
<UL>
<LI>
We're much more likely to see improvement on a DX2/66 than a Pentium/166.
With the 166, we may be <EM>overpowering</EM> 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.
<EM>A badly tuned Ferrari may still outperform a well-tuned VW :-)</EM>
<P>
<LI>
What problem was occurring before?  Which of the symptoms listed earlier is
happening?  If performance was 2500
bytes/second <EM>before</EM> using <EM>irqtune</EM>, we're less likely to notice the
smaller jump to, say, 2800.
<P>
<LI>
System loading is very light.  The problems that <EM>irqtune</EM> will fix are
more likely to happen when more devices and more work are added.  On a certain
configuration, <EM>irqtune</EM> had little effect.  However, when a brand new
SCSI DAT drive was added, serial performance nosedived.  Using <EM>irqtune</EM>
brought performance back to the correct level.
<P>
<LI>
We may have a <STRONG>rogue</STRONG> interrupt service that disables interrupts for
something outrageous, say 2 ms.  This is singularly longer than the 1194 us. in
the earlier example. <EM>irqtune</EM> will still help, but the real solution here
is to reduce interrupt lockout times in the other device below the 1194 us.
threshold.
<P>
</UL>
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_57__">Changes</A>
</H1>
<P>
<P><P>
<H3>
<A NAME="__irqtune_58__">Revision 0.2 Changes:</A>
</H3>
<UL>
<LI>
No code changes
<BR>
<LI>
Major rewrite and expansion of the problem explanation section
<BR>
<LI>
More thorough explanation of how and why <EM>irqtune</EM> works
<BR>
<LI>
Explanation of why serial devices must be highest priority
<BR>
<LI>
Impact on other devices
<BR>
<LI>
Cleaner and better installation instructions
<BR>
<LI>
Better benchmarking section
<BR>
<LI>
Problem resolution section
<BR>
<LI>
Explanation of my prior misread on the EOI thing
<BR>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_59__">Revision 0.3 Changes:</A>
</H3>
<UL>
<LI>
irqtune automatically prints interrupt priority table
<BR>
<LI>
Significantly improved error detection and reporting
<BR>
<LI>
Improved loading under different kernel revisions
<BR>
<LI>
<EM>insmod</EM> now invoked with <EM>-x</EM> to improve loading
<BR>
<LI>
Added module <EM>without</EM> printk's -- irqtune_npr.o
<BR>
<LI>
Special makefile options for difficult or custom rebuilds
<BR>
<LI>
Corrected error in <EM>hdparm -u</EM> note.
<BR>
<LI>
Improved the non-standard configuration section
<BR>
<LI>
Added note and patch about IRQ sharing under 2.0.X kernels
<BR>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_60__">Revision 0.4 Changes:</A>
</H3>
<UL>
<LI>
No code changes
<BR>
<LI>
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
<BR>
<LI>
<EM>irqtune</EM> distribution now available via HTTP as well as FTP.
<BR>
<LI>
Consolidated and improved trouble resolution sections.
<BR>
<LI>
Added explanation of irqtune_mod.o vs. irqtune_npr.o.
<BR>
<LI>
Added explanation of /sbin usage.
<BR>
<LI>
Corrected some typos.
<BR>
</UL>
<P>
<P><P>
<H3>
<A NAME="__irqtune_61__">Revision 0.5 Changes:</A>
</H3>
<UL>
<LI>
Added alternate installation procedure with "INSTALL=" option.
<BR>
<LI>
/sbin is added to $PATH automatically.
<BR>
<LI>
Added "-u" option.
<BR>
<LI>
Consolidated and improved installation documentation.
<BR>
<LI>
Additional trouble resolution documentation.
<BR>
<LI>
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
<BR>
</UL>
<P>
<P><P>
<HR>
<H1>
<A NAME="__irqtune_62__">Table of Contents</A>
</H1>
<UL>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#__irqtune_0__"><EM>IRQTUNE</EM> -- A Linux x86 IRQ Priority Optimizer</A>
<LI>
<A HREF="#__irqtune_1__">Where do I get <EM>irqtune</EM>?</A>
<BR>
<LI>
<A HREF="#__irqtune_2__">How do I know if I need <EM>irqtune</EM>?</A>
<BR>
<LI>
<A HREF="#__irqtune_3__">What is actually happening to cause these problems?</A>
<BR>
<LI>
<A HREF="#__irqtune_7__">How does irqtune help this?</A>
<BR>
<LI>
<A HREF="#__irqtune_8__">Why does the serial interrupt service require the highest priority?</A>
<BR>
<LI>
<A HREF="#__irqtune_12__">Isn't that example very <EM>unlikely</EM> under Linux?</A>
<BR>
<LI>
<A HREF="#__irqtune_13__">Doesn't this hurt the performance of other devices?</A>
<BR>
<LI>
<A HREF="#__irqtune_17__">Isn't this IRQ priority thing a bit of a new idea?</A>
<BR>
<LI>
<A HREF="#__irqtune_18__">How do I install <EM>irqtune</EM>?</A>
<BR>
<LI>
<A HREF="#__irqtune_25__">How do I use <EM>irqtune</EM>?  Don't I have to rebuild my kernel?</A>
<BR>
<LI>
<A HREF="#__irqtune_31__">What about my non-standard hardware configuration?</A>
<BR>
<LI>
<A HREF="#__irqtune_42__">What about incompatibilities with kernel revisions?</A>
<BR>
<LI>
<A HREF="#__irqtune_46__">What about hardware/config problems?</A>
<BR>
<LI>
<A HREF="#__irqtune_49__">What about other performance software remedies I've heard about?</A>
<BR>
<LI>
<A HREF="#__irqtune_54__">How can I tell if <EM>irqtune</EM> actually did anything for me?</A>
<BR>
<LI>
<A HREF="#__irqtune_57__">Changes</A>
<BR>
<LI>
<A HREF="#__irqtune_62__">Table of Contents</A>
<BR>
</UL>
irqtune/sbin/ 40755    155    764           0  6327143505  11340 5ustar  caeengrirqtune/sbin/load.o100644    155    764        3634  6211311003  12520 0ustar  caeengrELFl4(USEʃ*t	jË]]ÐUE1Ҁ}v<vЉ]ÐUWVS}]EtjW
 Et$e[^_]ÐUWVS}]UUt
PWrPWetU8u8u1e[^_]ÐUVS1T(@~EPEPt*PEPEPh^eEPEPh[EPEPjSt$PPEPEPhe[^]ÐU]01.01master value out of rangeslave value out of rangetwo slaves specifiedtwo masters specifiedirqtune: SANITYERROR %u/%u -- %s
irqtune: setting system IRQ priority to %u/%u
irqtune: ERROR expected %u/%u but got %u/%u
GCC: (GNU) 2.6.3.symtab.strtab.shstrtab.text.rel.text.data.bss.note.rodata.comment3$@14[BdO]fPry load.cgcc2_compiled.irq_high_getirq_high_insaneirq_high_set1irq_high_setirq_high_listpriorityinit_moduleprintkcleanup_module@'!	$x	+h1t6t<DdvM 

	
Og
)
2
_

irqtune/sbin/load_mod.o100644    155    764        4170  6313661052  13372 0ustar  caeengrELF 4(US0E
ME6EÊM}u;EEvˆÊM€uE}vEeE}v]]Í&UE1Ҁ}vt&&<vЉ]
UWVS}]EtjW
& Et$e[^_]Ðt&UWVS}]UUt
PWrPWetU8u8u1e[^_]ÍUVS16T(@~EPEPt*PEPEPh^hbj6&EPEPh^h[EPEPjSt)PPEPEPh^he[^]Ít&U]01.01master value out of rangeslave value out of rangetwo slaves specifiedtwo masters specified0.5irqtune/%s: SANITYERROR %u/%u -- %s
irqtune/%s: setting system IRQ priority to %u/%u
irqtune/%s: ERROR expected %u/%u but got %u/%u
GCC: (GNU) 2.7.2.symtab.strtab.shstrtab.text.rel.text.data.bss.note.rodata.comment@w!		+16<DM@

	%15[C0dP^m|pload.cgcc2_compiled.irq_high_calcirq_high_insaneirq_high_set1irq_high_setirq_high_listirq_prior_listirq_prior_biaspriorityinit_moduleprintkcleanup_module
"-=
MX
y

;
C
SX]irqtune/sbin/kvers.c100644    155    764          42  6314513063  12663 0ustar  caeengrchar kernel_version[] = "1.2.13";
irqtune/sbin/kvers.o100644    155    764        1277  6314513101  12743 0ustar  caeengrELF4(	1.2.1301.01GCC: (GNU) 2.7.2.symtab.strtab.shstrtab.text.data.bss.note.comment4!4'<,<2Pb;	'	kvers.cgcc2_compiled.kernel_versionirqtune/sbin/irqtune_mod.o100644    155    764        4312  6314513102  14131 0ustar  caeengrELF$4(
US0E
ME6EÊM}u;EEvˆÊM€uE}vEeE}v]]Í&UE1Ҁ}vt&&<vЉ]
UWVS}]EtjW
& Et$e[^_]Ðt&UWVS}]UUt
PWrPWetU8u8u1e[^_]ÍUVS16T(@~EPEPt*PEPEPh^hbj6&EPEPh^h[EPEPjSt)PPEPEPh^he[^]Ít&U]Ðmaster value out of rangeslave value out of rangetwo slaves specifiedtwo masters specified0.5irqtune/%s: SANITYERROR %u/%u -- %s
irqtune/%s: setting system IRQ priority to %u/%u
irqtune/%s: ERROR expected %u/%u but got %u/%u
1.2.13GCC: (GNU) 2.7.2GCC: (GNU) 2.7.2.symtab.strtab.shstrtab.text.rel.text.rodata.data.bss.comment@x!	+39>$Gl		"-=MXy;CSX]	%15[C0dPxXpgvload.cgcc2_compiled.irq_high_calcirq_high_insaneirq_high_set1irq_high_setkvers.ccleanup_moduleirq_prior_biaspriorityinit_moduleirq_prior_listprintkkernel_versionirq_high_listirqtune/sbin/load_npr.o100644    155    764        4164  6313661055  13420 0ustar  caeengrELF04(US0E
ME6EÊM}u;EEvˆÊM€uE}vEeE}v]]Í&UE1Ҁ}vt&&<vЉ]
UWVS}]EtjW
& Et$e[^_]Ðt&UWVS}]UUt
PWrPWetU8u8u1e[^_]ÍU1]Í&UVS16T(@~EPEPt*PEPEPh^hbj6&EPEPh^hw[EPEPjSt)PPEPEPh^h/e[^]Ít&U]01.01master value out of rangeslave value out of rangetwo slaves specifiedtwo masters specified0.5irqtune/%s: SANITYERROR %u/%u -- %s
irqtune/%s: setting system IRQ priority to %u/%u
irqtune/%s: ERROR expected %u/%u but got %u/%u
GCC: (GNU) 2.7.2.symtab.strtab.shstrtab.text.rel.text.data.bss.note.rodata.comment@!		+16<DM@
	(%15[C0dP	[ixload.cgcc2_compiled.irq_high_calcirq_high_insaneirq_high_set1irq_high_setprintk_nprirq_high_listirq_prior_listirq_prior_biaspriorityinit_modulecleanup_module"-=MXy KSchirqtune/sbin/irqtune_npr.o100644    155    764        4306  6314513102  14154 0ustar  caeengrELF44(
US0E
ME6EÊM}u;EEvˆÊM€uE}vEeE}v]]Í&UE1Ҁ}vt&&<vЉ]
UWVS}]EtjW
& Et$e[^_]Ðt&UWVS}]UUt
PWrPWetU8u8u1e[^_]ÍU1]Í&UVS16T(@~EPEPt*PEPEPh^hbj6&EPEPh^hw[EPEPjSt)PPEPEPh^h/e[^]Ít&U]Ðmaster value out of rangeslave value out of rangetwo slaves specifiedtwo masters specified0.5irqtune/%s: SANITYERROR %u/%u -- %s
irqtune/%s: setting system IRQ priority to %u/%u
irqtune/%s: ERROR expected %u/%u but got %u/%u
1.2.13GCC: (GNU) 2.7.2GCC: (GNU) 2.7.2.symtab.strtab.shstrtab.text.rel.text.rodata.data.bss.comment@!	+39>$Gd		"-=MXy KSch	%15[C0dP	[crload.cgcc2_compiled.irq_high_calcirq_high_insaneirq_high_set1irq_high_setprintk_nprkvers.ccleanup_moduleirq_prior_biaspriorityinit_moduleirq_prior_listkernel_versionirq_high_listirqtune/sbin/irqtune.o100644    155    764       22654  6327143505  13335 0ustar  caeengrELF4(	US0E
ME6EÊM}u;EEvˆÊM€uE}vEeE}v]]Í&UE1Ҁ}vt&&<vЉ]
UWVS}]EtjW
& Et$e[^_]Ðt&UWVS}]UUt
PWrPWetU8u8u1e[^_]ÍUWVSU}OUjjhj/PÃuh{hjPhhhj
h,	h~@vU;-u3{Fu{u]
6CPOEÃ=t"hhhj&=tjt&&1~G6U<	w8v	jj
jSÃv	FOE=tPPGÃt*SPPhhjPPjh=u	=u
=t
=uP]XP
e[^_]UDWVShShhRt1ҾǹuمuEShh=th'hhhE=vPhhVhEPhj}+=Bhh\h&6E=t2hhthhhhPPhPhh=uShPPP=tPh.hh=t1=tV=t!hhAh%&Phh`hhYƃt.hhzh==tkPhh=thhAh"t&Phhhhƃt+Phh=t=t?t=t}hhe[^_]Í&&US];$6& 0@P`pyt&it&Yt&It&9t&)t&t&	t&+C;]]Ív&UE=t%%@]UWVSE6]SŠM
BBz󥤃E}ve[^_]Í6UTWVS]hSǃu&PPShhj}uvWjPVEj
VEtEjj
PVE8:u
Ew1҅tVh<h두t&PËEPCPChWe[^_]US0ۍ6Í@=uyt%APAQ)PPhRhÀv]]ÍUEP]US]j/St؋]]ÐUS]j/St
@v&؋]]Í&US]t5f=tePhh&hhS&UWVS}E]K1~6hPt1KFe[^_]Ð&Uhhhhhhhhh$hhh1hjjhbh hhhhhhh
h h-hhJhhrhjh~h$jhh]Uj1]irqtune_mod.o irqtune_npr.o^01.01master value out of rangeslave value out of rangetwo slaves specifiedtwo masters specifiedirqtune_mod/proc/interruptsirqtune: irqtune must be invoked via the full path even if it's in $PATH
0.5irqtune: version is %s
irqtune: unable to use values %u/%u -- %s
PATH:/sbinPATH=%s:/sbinirqtune: adding /sbin to $PATH (warning only)
%s/%sirqtune: module %s not found -- skipping
/dev/nullirqtune: kernel version (BUILT: %s) (CURRENT: %s)
insmod -x -o %s -f %s priority=%d,%d >> %s 2>&1setting system IRQ priority tosimulating IRQ priority ofirqtune: %s %u/%u
irqtune: trying command -- %s
irqtune: loading %s (%s)
irqtune: insmod failed on '%s'
rmmod %sirqtune: unloading %s (%s)
irqtune: rmmod failed on '%s'
irqtune: no irqtune modules found
        0 ? Inactivertblread: unable to open '%s' -- %s
tblread: SYNTAX '%s'
I%2.2u/P%2.2u: %s
 (rerun with -e for full error text)irqtune: errors occurred%s
irqtune: complete
 usage: irqtune [options] [master] [slave]
version: %s
options:
  -e -- show verbose errors
  -h -- display help
  -n -- nogo mode (just show what would happen)
  -o -- reset to original values (%u/%u)
  -v -- display irqtune version
  -F<file> -- use <file> instead of /proc/interrupts
  -q -- suppress priority table printing
  -s -- sort table by priority
  -u -- force module unload
  -x -- show inactive devices in table
arguments:
  master -- high priority IRQ on PIC master (DEFAULT: %d)
  slave -- high priority IRQ on PIC slave (DEFAULT: %d)
GCC: (GNU) 2.7.2.symtab.strtab.shstrtab.text.rel.text.data.rel.data.bss.note.rodata.comment@!	|(	
+
$1	%
;8
@8
FL
N>PW
	8A(18[F0dSap ``
(`H&!)0BIrPXai^q@	y@
Z
0
")08
)irqtune.cgcc2_compiled.irq_high_calcirq_high_insaneirq_high_set1irq_high_setirq_high_listirq_prior_listirq_prior_biasmodnamesmodtagmainpgmnamegoflgproc_ints_IO_stderr_setbufstrchrfprintfmyexitdirtopstrcpyfileheadmodlistxstrsplitutsunameusageoptgetverflgexithelpflg_usage__strtol_internalbadflgloadersortflgquietflgbigcodetblinittblreadtblshowgetenvpathbfstrtoksprintferrflgfflushputenvmodcur_xstatkernel_versionstrcmpbigbfsyncvsystemrmflgallflgtblfindtblbasefopenerrnostrerrorfgetsfclosesystemstrrchrfiletail
"-=
MX
y


$+5 :!h$%&%(
)(
/
7
?
V
^
din

+,-,,-
12!2)/3=UZ2_4h5puz6278489585":' ,;8 =:BGLV
^
d8iot<y4~<54

6=5<
!'8,16><N-[8`ejp-}?<45<8<-$?--BPUZ`-5&"2)B,R+b?r$@+B			M	S	Ca	Dg	En	s	x		F		(			
2
GT
BZ
@{



H
I
I5 %*AFKT%y3$,16;@EJOTY^ckpuz irqtune/sbin/irqtune100755    155    764       21231  6327143510  13065 0ustar  caeengrELFP484 (44

,< &,/lib/ld-linux.so.1%'
$ "&!#
	%#,$o+P- 1C"IX-TU"\(dc8"jH]q,{X"hFx, "-"""
&"8P,	&(>8g"P-)0L-7L-C0Rlibc.so.5strcpystrerror_DYNAMICgetenverrno__strtol_internalfgets_IO_stderr_system_xstatfflushputenv__environ_inituname__libc_initstrrchrenvironfprintf__fpu_controlsyncstrtokfopenfclosestrcmp_finisprintfatexit_GLOBAL_OFFSET_TABLE_exitsetbuf__setfpucwstrchr_errno_etext_edata__bss_start_endX--P-"\,`,d,h,l,p,	t,
x,|,,,,,,,,,,,,,,, ,!+5T,%X,%\,h%`,h%d,h%h,h%l,h %p,h(%t,h0%x,h8p%|,h@`%,hHP%,hP@%,hX0%,h` %,hh%,hp%,hx%,h%,h%,h%,h%,h%,h%,h%,hpYЃ1UUUPSQ̀D$,-PhZ
PW[&&̀&SL,=L,t
Ѓ;u[Í6ÐUS0E
,ME6EXCÊM@?}u;E,EvˆXCÊM@?€uE}vEeE}v]]Í&UE1Ҁ}vt&&<v2Љ]
UWVS}]EtjW
& E,t$e[^_]Ðt&UWVS}]UUt
PWrPWetU8,u8,u1e[^_]ÍUWVSUQ}OUlGTCjhX->j/QPQÃuhhX-jQPhlChlCh,j
hQ,	h=~@vU;-u3{Fu{u]
TC6CPOEÃ=(Rt"hhhX-j_&=QtjCt&&1~G6U<	w8v	jj
jSÃv	,FOE=8?t,,,P,PGÃt*S,P,PhhX-j,P,Pjh=$Ru	=lGu
P?=<?t
P?=P?uTCP]X<?P
e[^_]UDWVSh$Sh--h)Rut1Ҿ+ǹuمuESh1h-=,Rth?hX-
hX-h-EQ=QvPhlChnhT?EPhT?jJ}+=,RBhT?hthX-&6E=,Rt2h8,h2>th2>h8,hhX-8,P,PhT?4,PhhMkM=,RuShPN,P,P+=lGtPhFhX-hX-^=lGt1=lGtV=,Rt!hMhYhX-u%&4,PhT?hxhX-NhMYƃ<?t.hT?hhX-<?=hC=lGtk4,PhhMB=,RthMhYhX-"t&4,PhT?hhX-hMƃt+4,PhhX-s<?=hCt=<?t?t=lGt}hhX-*<?e[^_]Í&&US];$6& 0@P`p,RQyt&lGit&8?Yt&P?It&$R9t&hC)t&(Rt&Q	t&+C;]]Ív&UE=$Rt%XC%@pG]UWVSE6]SŠM
XCB@?Bz󥤃E}ve[^_]Í6UTWVS]h.Saǃu&P-PmPSh0hX-j}uvWjPVsEj
VEtEjj
PV2E8:u
Ew1҅tVhThX-두t&PËEPCPChWe[^_]US0ۍ6Í@pG=Quyt%APAQ)PPhjhX-Àv]]ÍUEPl]US]j/St؋]]ÐUS]j/St
@v&؋]]Í&US]t5~=,Rt}PhhX-Z&hhX-9S&UWVS}E]K1~6hP%t1KFe[^_]Ð&UhhX-hhhX-hhX-hhX-$h3hX-hIhX-sjjhzhX-` hhX-NhhX-?hhX-0h%hX-! hEhX-hbhX-hhX-jhhX-$jhhX-]Uj1]ÐS@,=@,t
Ѓ;u[Í6Ðmaster value out of rangeslave value out of rangetwo slaves specifiedtwo masters specifiedirqtune_mod/proc/interruptsirqtune: irqtune must be invoked via the full path even if it's in $PATH
0.5irqtune: version is %s
irqtune: unable to use values %u/%u -- %s
PATH:/sbinPATH=%s:/sbinirqtune: adding /sbin to $PATH (warning only)
%s/%sirqtune: module %s not found -- skipping
/dev/nullirqtune: kernel version (BUILT: %s) (CURRENT: %s)
insmod -x -o %s -f %s priority=%d,%d >> %s 2>&1setting system IRQ priority tosimulating IRQ priority ofirqtune: %s %u/%u
irqtune: trying command -- %s
irqtune: loading %s (%s)
irqtune: insmod failed on '%s'
rmmod %sirqtune: unloading %s (%s)
irqtune: rmmod failed on '%s'
irqtune: no irqtune modules found
        0 ? Inactivertblread: unable to open '%s' -- %s
tblread: SYNTAX '%s'
I%2.2u/P%2.2u: %s
 (rerun with -e for full error text)irqtune: errors occurred%s
irqtune: complete
 usage: irqtune [options] [master] [slave]
version: %s
options:
  -e -- show verbose errors
  -h -- display help
  -n -- nogo mode (just show what would happen)
  -o -- reset to original values (%u/%u)
  -v -- display irqtune version
  -F<file> -- use <file> instead of /proc/interrupts
  -q -- suppress priority table printing
  -s -- sort table by priority
  -u -- force module unload
  -x -- show inactive devices in table
arguments:
  master -- high priority IRQ on PIC master (DEFAULT: %d)
  slave -- high priority IRQ on PIC slave (DEFAULT: %d)
irqtune_mod.o irqtune_npr.ov1.2.13,.>N^n~.>
 
HP,GCC: (GNU) 2.7.2.l.3GCC: (GNU) 2.7.2GCC: (GNU) 2.7.2GCC: (GNU) 2.7.2.l.3.symtab.strtab.shstrtab.interp.ha
Results 1 - 1
Help - FTP Sites List - Software Dir.
Searching half a billion files worldwide
© 1997-2009 MARUHN Internet Solutions