/*
 * romconfig.i86  -  Configuration definitions for the bootrom
 *
 * Copyright (C) 2003-2007 Gero Kuhlmann   <gero@gkminix.han.de>
 *
 *  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
 *  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.
 *
 * $Id: romconfig.i86,v 1.6 2007/01/06 18:30:52 gkminix Exp $
 */

#ifndef HEADERS_ROMCONFIG_I86
#define HEADERS_ROMCONFIG_I86


/*
 * Include the main C header file
 */
#define GAS_INCLUDE
#include <romconfig.h86>



/*
 *****************************************************************************
 *
 * According to the UNDI specification, the kernel or protocol driver handles
 * the hardware interrupt of the network card initially. It will then call
 * UNDI to check if this interrupt really came from the network card. Upon
 * return, it will then send an EOI to the PICs and calls UNDI again to finally
 * process the interrupt. On the first call, UNDI has to disable the network
 * card interrupts. Lateron, with the second call, UNDI has to reenable the
 * network card interrupt.
 *
 * The problem here is that with precompiled network drivers (like packet
 * drivers or NDIS drivers) the EOI will be sent to the PICs by the driver
 * itself. Therefore, the kernel or protocol driver will issue a second EOI
 * upon return from this call. Normally, when this routine gets executed
 * no other ISR bit is set but ours, which will get reset by the driver EOI.
 * Therefore the kernel EOI remains without effect. This is because in a normal
 * system, any interrupt service routine should send an EOI before enabling
 * interrupts at the processor level which means that low-priority interrupts
 * can get interrupted by higher level interrupts only after EOI. When the
 * higher-priority interrupt executes, no lower-level ISR bit remains set.
 * There is just one possible situation where this double-EOI can cause
 * problems. In this situation the following conditions have to apply:
 *
 *	1.) An interrupt service routine with lower priority than our
 *	    network interrupt gets called and enables interrupts at the
 *	    processor level _before_ sending its own EOI. This really is
 *	    a serious software bug, especially since there exist 8259-
 *	    clones (especially within C&T chipsets) which incorrectly handle
 *	    a non-specific EOI by resetting all ISR bits instead of just
 *	    the one with the highest priority.
 *	2.) The network card produces an interrupt in the time between
 *	    enabling interrupts and the lower-priority interrupt service
 *	    routine sending its EOI.
 *	3.) The kernel or protocol driver uses a non-specific EOI instead
 *	    of a specific EOI. The network card ISR bit has already been
 *	    reset by the network card driver, so the highest priority ISR
 *	    bit seen by the PIC when it receives a non-specific EOI is that
 *	    of the interrupt with the lower-than-ours priority.
 *
 * There are three solutions for this problem:
 *
 *	1.) We simply ignore it and assume that all hardware interrupt
 *	    handlers are written correctly. This should be pretty safe,
 *	    but if you have buggy software and the kernel or protocol driver
 *	    uses non-specific EOI, you might experience occasional hangups.
 *	2.) We check that we are the only routine with an ISR bit set (which
 *	    should always be true as long as all interrupt service routines
 *	    are written correctly). If thats not true, we have to ignore the
 *	    network card interrupt. As with option 1 this should be pretty
 *	    safe, but with buggy software we are going to loose network
 *	    packets - independent of the kernel using specific or non-specific
 *	    EOI. At least it doesnt hang the system.
 *	3.) We mask out all interrupts with a set ISR bit and then enter
 *	    special mask mode on both PICs. When the kernel or protocol
 *	    driver sends a non-specific EOI the PIC will not be able to
 *	    find a set ISR bit. In special mask mode, masked ISR bits are
 *	    invisible to the PIC according to the Intel 8259A data sheet.
 *	    Unfortunately we dont know if all higher level interrupts can
 *	    safely deal with the special mask mode. Also this would not
 *	    prevent the EOI to reset the ISR bits on buggy chips like with
 *	    those C&T chipsets.
 *
 * All three solutions have their individual draw-backs. I think option 1
 * will be the safest (as at least our own network kernel will use specific
 * EOI), so we make it the default. The INTMODE value set in romconfig.h86
 * specifies one of the options mentioned above.
 *
 * Another problem is the UNDI requirement of disabling the interrupt line of
 * the network card. This can be done at two positions: directly at the network
 * card chip set, or by masking the interrupt at the PIC. The first case is
 * not suitable for us because only the network driver (e.g. packet or NDIS
 * driver) has access to the network card chipset. However, the second case
 * is unsafe when using a PCI network card, because the PCI bus allows shared
 * interrupts. If another card uses the same interrupt as the network card,
 * it wont receive its own interrupt while it has been masked out at the PIC.
 * In addition, we can run into a race condition with disabling interrupts at
 * the PIC: the base code starts its second call to the UNDI ISR routine
 * independently from the actual hardware interrupt. If the base code just
 * started a transmit operation, and a network interrupt appears before the
 * network driver disables interrupts, the second UNDI call cant get initiated
 * by the base code. This means that during the transmit operation, interrupts
 * are masked off at the PIC. Many network chip sets are still able to send
 * the packet, but some network drivers wait until they receive the transmit
 * interrupt - which will never appear because interrupts are masked. This
 * problem gets even worse when there are many PCI devices shared by the
 * same interrupt line. The MASKINT values defines the masking behaviour.
 * It has always to be set for interrupt mode 3. For the other two modes
 * we turn it off by default. However, if masking has been turned on, the
 * network driver interface has to make sure that they cant get masked again
 * before a transmit operation has been finished. This will likely fail with
 * interrupt mode 3!
 *
 * The third selectable parameter is INTCHECK. It defines if we should check
 * the ISR bit before calling the network driver interrupt service routine.
 * With mode 1 this is usually not necessary. If the first UNDI interrupt
 * service API gets called, we can be pretty sure that the corresponding ISR
 * bit is set. However, with interrupt mode 2, we check that the network card
 * interrupt is the only currently serviced interrupt, and therefore INTCHECK
 * should be turned on.
 *
 * All the logic for these values can be found in the file
 * bootrom/netdrvr/lib/interrupt.S86 and in the corresponding network driver
 * interface files packet.S86 and ndis.S86. You should probably never change
 * any of the values defined here!
 *
 * Note that the original definitions for these values appear in the file
 * romconfig.h86.
 */
#ifndef INTMODE
# define INTMODE 1
#endif

#if INTMODE == 1
# define DEFAULT_INTCHECK	0
# define DEFAULT_MASKINT	0
#else
# if INTMODE == 2
#  define DEFAULT_INTCHECK	1
#  define DEFAULT_MASKINT	0
# else
#  if INTMODE == 3
#   define DEFAULT_INTCHECK	1
#   define DEFAULT_MASKINT	1
#  else
#   error Invalid INTMODE value
#  endif
# endif
#endif

#ifndef INTCHECK
# define INTCHECK DEFAULT_INTCHECK
#else
# if INTCHECK != 0 && INTCHECK != 1
#  error Invalid INTCHECK value
# endif
#endif

#ifndef MASKINT
# define MASKINT DEFAULT_MASKINT
#else
# if MASKINT != 0 && MASKINT != 1
#  error Invalid MASKINT value
# endif
#endif


#endif

