Date: Wed, 3 Dec 1997 15:54:18 GMT
From: Roman Hodek <rnhodek@faui22c.informatik.uni-erlangen.de>
To: linux-m68k@lists.linux-m68k.org
Subject: L68K: Little optimizations
Sender: owner-linux-m68k@phil.uni-sb.de


The patch below implements a few optimizations in various files. The
common issue is that if you access some hardware register(s) via a
global base pointer of some kind, then gcc assumes that the pointer
access could also have changed the pointer itself ... The result is
that the base pointer is loaded from memory each time it is used. The
solution to this is copying into a local variable. [1]

In detail:

 - atari_MFPser.[ch]: Copy info->port into a local variable and
   redefine currMFP for that.

 - atari_SCC.[ch]: Store three values in local variables: pointer to
   SCC registers, pointer to shadow set, and pointer to MFP GPIP
   register (for delays). All these three were recalculated (or
   reloaded) everytime a SCCread or SCCwrite was called.

   This was most expensive for the shadow pointer, because several
   ANDs, SHIFTs, and 'ChannelsReversed' were needed for its
   calculation, even if it wasn't used at all. Another change here
   that not the exact CHANNR() is used now as first-level index into
   SCC_shadow, but the raw (info->port & 4)/4. ChannelReversed needs
   not be obeyed, it doesn't matter if the shadow sets are swapped.

 - atari_SCC.c: Simplify SETUP_INFO(): Just load a global pointer to
   the correct info, instead of recalculating it on every interrupt.
   
 - atari_SCC.[ch]: ChannelsReversed now contains 0 or 4 (instead of
   1), to save some shift operations.

 - atari_SCC.h: in _SCC_read(), make 'normal_case' the last case, to
   avoid backward jumps.

 - atafb.c: Fix base pointer problematic in ext_setcolreg(). (With
   external_vgaiobase). (Something similar in Juergen's svga stuff
   made me aware of the problem :-)

All in all, the patch should give much better assembler code in the
SCC drive, and little better code in the other two files.

Roman

 [1] I've also developed another solution: Declare the base pointer 
with const attribute. Since it's usually only initialized once, this
is more or less true... To assign the base pointer, use the following
macro:

#define IGNORE_CONST_1(var)						\
	({ typedef __base_t = (var);				\
	   __base_t *__p = (__base_t *)&(var);		\
	   __p; })
#define IGNORE_CONST(var) (*IGNORE_CONST_1(var))

I haven't used this solution for the serial drivers, because I didn't
want to change the type of info->port, it's used by many other drivers
also... In atafb.c it would be basically possible, but then the
default initialization of vgaiobase must be moved somewhere else which
isn't as clear. (And if you init a const var, gcc remembers that value
and expands it in if's and the like :-)

------------------------------------------------------------------------------
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.64.orig/drivers/char/atari_MFPser.c linux-2.1.64/drivers/char/atari_MFPser.c
--- linux-2.1.64.orig/drivers/char/atari_MFPser.c	Mon Nov 17 12:47:38 1997
+++ linux-2.1.64/drivers/char/atari_MFPser.c	Wed Dec  3 16:28:36 1997
@@ -206,6 +206,8 @@
 
 static void MFPser_init_port( struct async_struct *info, int type, int tt_flag)
 {
+	INIT_currMFP(info);
+	
 	/* set ISRs, but don't enable interrupts yet (done in init());
 	 * all ints are choosen of type FAST, and they're really quite fast.
 	 * Furthermore, we have to account for the fact that these are three ints,
@@ -244,10 +246,8 @@
   	info->custom_divisor = 4;          /* 9600 Baud */
   	info->baud_base = MFP_BAUD_BASE;
 
-	if (tt_flag || !atari_MFP_init_done) {
-		currMFP(info)->rcv_stat  = 0;	/* disable Rx */
-		currMFP(info)->trn_stat  = 0;	/* disable Tx */
-	}
+	currMFP->rcv_stat  = 0;	/* disable Rx */
+	currMFP->trn_stat  = 0;	/* disable Tx */
 }
 
 
@@ -270,17 +270,14 @@
 {
 	struct async_struct *info = data;
 	int		ch, stat, err;
-/*	unsigned long flags; */
+	INIT_currMFP(info);
 
-	stat = currMFP(info)->rcv_stat;
-	ch   = currMFP(info)->usart_dta;
+	stat = currMFP->rcv_stat;
+	ch   = currMFP->usart_dta;
 	/* Frame Errors don't cause a RxErr IRQ! */
 	err  = (stat & RSR_FRAME_ERR) ? TTY_FRAME : 0;
 
-/*	save_flags(flags);
-	cli(); */
 	rs_receive_char (info, ch, err);
-/*	restore_flags(flags); */
 }
 
 
@@ -288,10 +285,10 @@
 {
 	struct async_struct *info = data;
 	int		ch, stat, err;
-/*	unsigned long flags; */
+	INIT_currMFP(info);
 
-	stat = currMFP(info)->rcv_stat;
-	ch   = currMFP(info)->usart_dta; /* most probably junk data */
+	stat = currMFP->rcv_stat;
+	ch   = currMFP->usart_dta; /* most probably junk data */
 
 	if (stat & RSR_PARITY_ERR)
 		err = TTY_PARITY;
@@ -304,10 +301,7 @@
 	else
 		err = 0;
 
-/*	save_flags(flags);
-	cli(); */
 	rs_receive_char (info, ch, err);
-/*	restore_flags(flags); */
 }
 
 
@@ -315,13 +309,14 @@
 {
 	struct async_struct *info = data;
 	int ch;
+	INIT_currMFP(info);
 
-	if (currMFP(info)->trn_stat & TSR_BUF_EMPTY) {
+	if (currMFP->trn_stat & TSR_BUF_EMPTY) {
 		if ((ch = rs_get_tx_char( info )) >= 0)
-			currMFP(info)->usart_dta = ch;
+			currMFP->usart_dta = ch;
 		if (ch == -1 || rs_no_more_tx( info ))
 			/* disable tx interrupts */
-			currMFP(info)->int_en_a &= ~0x04;
+			currMFP->int_en_a &= ~0x04;
 	}
 }
 
@@ -329,22 +324,24 @@
 static void MFPctrl_dcd_int( int irq, void *data, struct pt_regs *fp)
 {
 	struct async_struct *info = data;
+	INIT_currMFP(info);
 
 	/* Toggle active edge to get next change of DCD! */
-	currMFP(info)->active_edge ^= GPIP_DCD;
+	currMFP->active_edge ^= GPIP_DCD;
 
-	rs_dcd_changed( info, !(currMFP(info)->par_dt_reg & GPIP_DCD) );
+	rs_dcd_changed( info, !(currMFP->par_dt_reg & GPIP_DCD) );
 }
 
 
 static void MFPctrl_cts_int( int irq, void *data, struct pt_regs *fp)
 {
 	struct async_struct *info = data;
+	INIT_currMFP(info);
 
 	/* Toggle active edge to get next change of CTS! */
-	currMFP(info)->active_edge ^= GPIP_CTS;
+	currMFP->active_edge ^= GPIP_CTS;
 
-	rs_check_cts( info, !(currMFP(info)->par_dt_reg & GPIP_CTS) );
+	rs_check_cts( info, !(currMFP->par_dt_reg & GPIP_CTS) );
 }
 
 
@@ -359,20 +356,21 @@
 
 static void MFPser_init( struct async_struct *info )
 {
+	INIT_currMFP(info);
+
 	/* base value for UCR */
-	if (info->type != SER_MFP_CTRL || !atari_MFP_init_done)
-		currMFP(info)->usart_ctr = (UCR_PARITY_OFF | UCR_ASYNC_1 |
-									UCR_CHSIZE_8 | UCR_PREDIV);
+	currMFP->usart_ctr = (UCR_PARITY_OFF | UCR_ASYNC_1 |
+						  UCR_CHSIZE_8 | UCR_PREDIV);
 
 	/* enable Rx and clear any error conditions */
-	currMFP(info)->rcv_stat = RSR_RX_ENAB;
+	currMFP->rcv_stat = RSR_RX_ENAB;
 
 	/* enable Tx */
-	currMFP(info)->trn_stat = TSR_TX_ENAB;
+	currMFP->trn_stat = TSR_TX_ENAB;
 
 	/* enable Rx, RxErr and Tx interrupts */
-	currMFP(info)->int_en_a |= 0x1c;
-	currMFP(info)->int_mk_a |= 0x1c;
+	currMFP->int_en_a |= 0x1c;
+	currMFP->int_mk_a |= 0x1c;
 
 	if (info->type == SER_MFP_CTRL) {
 
@@ -389,24 +387,24 @@
 		 * ++andreas: do it better by looping until stable
 		 */
 		do {
-		    status = currMFP(info)->par_dt_reg & GPIP_CTS;
+		    status = currMFP->par_dt_reg & GPIP_CTS;
 		    if (status)
-			currMFP(info)->active_edge &= ~GPIP_CTS;
+			currMFP->active_edge &= ~GPIP_CTS;
 		    else
-			currMFP(info)->active_edge |= GPIP_CTS;
-		} while ((currMFP(info)->par_dt_reg & GPIP_CTS) != status);
+			currMFP->active_edge |= GPIP_CTS;
+		} while ((currMFP->par_dt_reg & GPIP_CTS) != status);
 
 		do {
-		    status = currMFP(info)->par_dt_reg & GPIP_DCD;
+		    status = currMFP->par_dt_reg & GPIP_DCD;
 		    if (status)
-			currMFP(info)->active_edge &= ~GPIP_DCD;
+			currMFP->active_edge &= ~GPIP_DCD;
 		    else
-			currMFP(info)->active_edge |= GPIP_DCD;
-		} while ((currMFP(info)->par_dt_reg & GPIP_DCD) != status);
+			currMFP->active_edge |= GPIP_DCD;
+		} while ((currMFP->par_dt_reg & GPIP_DCD) != status);
 
 		/* enable CTS and DCD interrupts */
-		currMFP(info)->int_en_b |= 0x06;
-		currMFP(info)->int_mk_b |= 0x06;
+		currMFP->int_en_b |= 0x06;
+		currMFP->int_mk_b |= 0x06;
 	}
 	MOD_INC_USE_COUNT;
 }
@@ -414,20 +412,22 @@
 
 static void MFPser_deinit( struct async_struct *info, int leave_dtr )
 {
+	INIT_currMFP(info);
+
 	/* disable Rx, RxErr and Tx interrupts */
-	currMFP(info)->int_en_a &= ~0x1c;
+	currMFP->int_en_a &= ~0x1c;
 
 	if (info->type == SER_MFP_CTRL) {
 		/* disable CTS and DCD interrupts */
-		currMFP(info)->int_en_b &= ~0x06;
+		currMFP->int_en_b &= ~0x06;
 	}
 
 	/* disable Rx and Tx */
-	currMFP(info)->rcv_stat = 0;
-	currMFP(info)->trn_stat = 0;
+	currMFP->rcv_stat = 0;
+	currMFP->trn_stat = 0;
 
 	/* wait for last byte to be completely shifted out */
-	while( !(currMFP(info)->trn_stat & TSR_LAST_BYTE_SENT) )
+	while( !(currMFP->trn_stat & TSR_LAST_BYTE_SENT) )
 		;
 
 	if (info->type == SER_MFP_CTRL) {
@@ -438,24 +438,26 @@
 	}
 
 	/* read Rx status and data to clean up */
-	(void)currMFP(info)->rcv_stat;
-	(void)currMFP(info)->usart_dta;
+	(void)currMFP->rcv_stat;
+	(void)currMFP->usart_dta;
 	MOD_DEC_USE_COUNT;
 }
 
 
 static void MFPser_enab_tx_int( struct async_struct *info, int enab_flag )
 {
+	INIT_currMFP(info);
+
 	if (enab_flag) {
 		unsigned long flags;
-		currMFP(info)->int_en_a |= 0x04;
+		currMFP->int_en_a |= 0x04;
 		save_flags(flags);
 		cli();
 		MFPser_tx_int (0, info, 0);
 		restore_flags(flags);
 	}
 	else
-		currMFP(info)->int_en_a &= ~0x04;
+		currMFP->int_en_a &= ~0x04;
 }
 
 
@@ -487,6 +489,7 @@
 	unsigned	div = 0, timer_val;
 	int			timer_mode;
 	unsigned long ipl;
+	INIT_currMFP(info);
 
 	if (!info->tty || !info->tty->termios) return;
 
@@ -563,15 +566,15 @@
 	save_flags (ipl);
 	cli();
 	/* disable Rx and Tx while changing parameters */
-	currMFP(info)->rcv_stat = 0;
-	currMFP(info)->trn_stat = 0;
+	currMFP->rcv_stat = 0;
+	currMFP->trn_stat = 0;
 
 	/* stop timer D to set new timer value immediatly after re-enabling */
-	currMFP(info)->tim_ct_cd &= ~0x07;
-	currMFP(info)->tim_dt_d = timer_val;
-	currMFP(info)->tim_ct_cd |= (timer_mode+1);
+	currMFP->tim_ct_cd &= ~0x07;
+	currMFP->tim_dt_d = timer_val;
+	currMFP->tim_ct_cd |= (timer_mode+1);
 
-	currMFP(info)->usart_ctr =
+	currMFP->usart_ctr =
 		( (parity & PARENB) ?
 		      ((parity & PARODD) ? UCR_PARITY_ODD : UCR_PARITY_EVEN) :
 		      UCR_PARITY_OFF ) |
@@ -583,8 +586,8 @@
 		UCR_PREDIV;
 
 	/* re-enable Rx and Tx */
-	currMFP(info)->rcv_stat = RSR_RX_ENAB;
-	currMFP(info)->trn_stat = TSR_TX_ENAB;
+	currMFP->rcv_stat = RSR_RX_ENAB;
+	currMFP->trn_stat = TSR_TX_ENAB;
 	restore_flags (ipl);
 }
 
@@ -605,10 +608,12 @@
 
 static void MFPser_set_break( struct async_struct *info, int break_flag )
 {
+	INIT_currMFP(info);
+	
 	if (break_flag)
-		currMFP(info)->trn_stat |= TSR_SEND_BREAK;
+		currMFP->trn_stat |= TSR_SEND_BREAK;
 	else
-		currMFP(info)->trn_stat &= ~TSR_SEND_BREAK;
+		currMFP->trn_stat &= ~TSR_SEND_BREAK;
 }
 
 
@@ -625,10 +630,11 @@
 	unsigned	gpip, gi;
 	unsigned int ri;
 	unsigned long ipl;
+	INIT_currMFP(info);
 
 	save_flags (ipl);
 	cli();
-	gpip = currMFP(info)->par_dt_reg;
+	gpip = currMFP->par_dt_reg;
 	gi   = GIACCESS( 0 );
 	restore_flags (ipl);
 
@@ -641,7 +647,7 @@
 	   used for SCC channel b */
 	if (ATARIHW_PRESENT (SCC) && !ATARIHW_PRESENT (TT_MFP))
 		ri = 0;
-	else if (currMFP(info) == &mfp)
+	else if (currMFP == &mfp)
 		ri = gpip & GPIP_RI ? 0 : TIOCM_RNG;
 	else
 		ri = 0;
@@ -689,18 +695,21 @@
 
 static void MFPser_stop_receive (struct async_struct *info)
 {
+	INIT_currMFP(info);
+
 	/* disable rx and rxerr interrupt */
-	currMFP (info)->int_en_a &= ~0x18;
+	currMFP->int_en_a &= ~0x18;
 
 	/* disable receiver */
-	currMFP (info)->rcv_stat = 0;
+	currMFP->rcv_stat = 0;
 	/* disable transmitter */
-	currMFP (info)->trn_stat = 0;
+	currMFP->trn_stat = 0;
 }
 
 static int MFPser_trans_empty (struct async_struct *info)
 {
-	return (currMFP (info)->trn_stat & TSR_LAST_BYTE_SENT) != 0;
+	INIT_currMFP(info);
+	return (currMFP->trn_stat & TSR_LAST_BYTE_SENT) != 0;
 }
 
 #ifdef MODULE
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.64.orig/drivers/char/atari_MFPser.h linux-2.1.64/drivers/char/atari_MFPser.h
--- linux-2.1.64.orig/drivers/char/atari_MFPser.h	Fri Oct 31 19:13:40 1997
+++ linux-2.1.64/drivers/char/atari_MFPser.h	Tue Dec  2 16:05:03 1997
@@ -14,8 +14,8 @@
 #ifndef _ATARI_MFPSER_H
 #define _ATARI_MFPSER_H
 
-
-#define	currMFP(info)	((volatile struct MFP *)(info->port))
+#define INIT_currMFP(info)	\
+	volatile struct MFP *currMFP = (volatile struct MFP *)(info->port)
 
 /* MFP input frequency, divided by 16 (USART prediv for async modes)
  * and 2 because of each timer run _toggles_ the output, resulting in
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.64.orig/drivers/char/atari_SCC.c linux-2.1.64/drivers/char/atari_SCC.c
--- linux-2.1.64.orig/drivers/char/atari_SCC.c	Mon Nov 17 12:47:38 1997
+++ linux-2.1.64/drivers/char/atari_SCC.c	Wed Dec  3 14:50:59 1997
@@ -280,6 +280,9 @@
 /* For which line has channel A been opened? */
 static int SCC_chan_a_line;
 
+/* info pointer for SCC_chan_a_line */
+static struct async_struct *SCC_chan_a_info;
+
 /* Are the register addresses for the channels reversed? (B before A). This is
  * the case for the ST_ESCC. */
 static int ChannelsReversed;
@@ -318,11 +321,10 @@
 
 #endif
 
-#define	SETUP_INFO(info)					\
-	do {							\
-		if (info->line == cha232_line &&		\
-		    SCC_chan_a_line == cha422_line)		\
-			info = &rs_table[cha422_line];		\
+#define	SETUP_INFO(info)						\
+	do {										\
+		if (info->line == cha232_line)			\
+			info = SCC_chan_a_info;				\
 	} while(0)
 
 
@@ -410,7 +412,7 @@
 		SCC_chan_a_switchable = SCCA_SWITCH_SERIAL2_ONLY;
 
 	/* General initialization */
-	ChannelsReversed = escc;
+	ChannelsReversed = escc ? 4 : 0;
 	SCC_chan_a_open = 0;
 
 	/* Init channel B */
@@ -461,6 +463,7 @@
 static void SCC_init_port( struct async_struct *info, int type, int channel )
 {
 	static int called = 0, ch_a_inited = 0;
+	SCC_ACCESS_INIT(info);
 
 	info->sw = &SCC_switch;
 
@@ -938,6 +941,7 @@
 	struct async_struct *info = data;
 	static int delay = 4;
 	ulong flags;
+	SCC_ACCESS_INIT(info);
 
 	/* if 'fp' is NULL we're called from SCC_dma_int, in which case we must
 	 * respond immediately!
@@ -1011,7 +1015,8 @@
 {
 	struct async_struct *info = data;
 	unsigned char	ch;
-
+	SCC_ACCESS_INIT(info);
+	
 	SETUP_INFO(info);
 
 	ch = SCCread_NB( RX_DATA_REG );
@@ -1056,7 +1061,8 @@
 	int isdma = (CHANNR(info) == CHANNEL_A) && scca_dma;
 	ulong flags = 0;
 #endif
-
+	SCC_ACCESS_INIT(info);
+	
 	SETUP_INFO(info);
 
 #ifdef CONFIG_ATARI_SCC_DMA
@@ -1139,6 +1145,7 @@
 {
 	struct async_struct *info = data;
 	int ch;
+	SCC_ACCESS_INIT(info);
 
 	SETUP_INFO(info);
 
@@ -1171,6 +1178,7 @@
 	struct async_struct *info = data;
 	unsigned channel = CHANNR(info);
 	unsigned char	last_sr, sr, changed;
+	SCC_ACCESS_INIT(info);
 
 	SETUP_INFO(info);
 
@@ -1241,6 +1249,7 @@
 
 		SCC_chan_a_open = 1;
 		SCC_chan_a_line = info->line;
+		SCC_chan_a_info = &rs_table[info->line];
 
 		if (SCC_chan_a_switchable == SCCA_SWITCH_BOTH) {
 			save_flags(flags);
@@ -1267,6 +1276,7 @@
 {
 	int i, channel = CHANNR(info);
 	unsigned long	flags;
+	SCC_ACCESS_INIT(info);
 	static const struct {
 		unsigned reg, val;
 	} init_tab[] = {
@@ -1395,6 +1405,7 @@
 static void SCC_deinit( struct async_struct *info, int leave_dtr )
 {
 	unsigned long	flags, timeout;
+	SCC_ACCESS_INIT(info);
 
 #if DEBUG & DEBUG_INIT
 	printk( "SCC channel %d about to be deinited\n", CHANNR(info) );
@@ -1453,6 +1464,7 @@
 {
 	unsigned long	flags;
 	unsigned char	iadr;
+	SCC_ACCESS_INIT(info);
 
 	save_flags(flags);
 	cli();
@@ -1521,6 +1533,7 @@
 	unsigned channel, div = 0, clkmode, brgmode, brgval;
 	int clksrc = 0;
 	unsigned long flags;
+	SCC_ACCESS_INIT(info);
 
 	if (!info->tty || !info->tty->termios) return;
 
@@ -1691,6 +1704,7 @@
 static void SCC_throttle( struct async_struct *info, int status )
 {
 	unsigned long	flags;
+	SCC_ACCESS_INIT(info);
 
 #if DEBUG & DEBUG_THROTTLE
 	printk( "SCC channel %d: throttle %s\n",
@@ -1715,6 +1729,7 @@
 static void SCC_set_break( struct async_struct *info, int break_flag )
 {
 	unsigned long	flags;
+	SCC_ACCESS_INIT(info);
 
 	save_flags(flags);
 	cli();
@@ -1741,7 +1756,8 @@
 {
 	unsigned	sr, tcr, ri, dsr;
 	unsigned long	flags;
-
+	SCC_ACCESS_INIT(info);
+	
 	save_flags(flags);
 	cli();
 	sr = SCCread( STATUS_REG );
@@ -1775,7 +1791,8 @@
 			      int new_dtr, int new_rts )
 {
 	unsigned long	flags;
-
+	SCC_ACCESS_INIT(info);
+	
 	save_flags(flags);
 	cli();
 
@@ -1802,6 +1819,8 @@
 
 static void SCC_stop_receive (struct async_struct *info)
 {
+	SCC_ACCESS_INIT(info);
+	
 #ifdef CONFIG_ATARI_SCC_DMA
 	dma_stop ();
 #endif
@@ -1815,6 +1834,8 @@
 
 static int SCC_trans_empty (struct async_struct *info)
 {
+	SCC_ACCESS_INIT(info);
+	
 	return (SCCread (SPCOND_STATUS_REG) & SCSR_ALL_SENT) != 0;
 }
 
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.64.orig/drivers/char/atari_SCC.h linux-2.1.64/drivers/char/atari_SCC.h
--- linux-2.1.64.orig/drivers/char/atari_SCC.h	Sat Nov 22 00:07:08 1997
+++ linux-2.1.64/drivers/char/atari_SCC.h	Wed Dec  3 14:54:30 1997
@@ -348,10 +348,8 @@
  * quite right
  */
 
-static __inline__ void scc_reg_delay( void )
-{
-	MFPDELAY();
-}
+#define scc_reg_delay() \
+	__asm__ __volatile__ ( "tstb %0" : : "g" (*_mfp_gpip) : "cc" )
 
 /* Another version with only 3 nop's for cases when some other
  * statement intervenes between the two SCC accesses
@@ -359,10 +357,8 @@
  * 10/16/95: use MFPDELAY, too.
  */
 
-static __inline__ void scc_reg3_delay( void )
-{
-	MFPDELAY();
-}
+#define scc_reg3_delay() \
+	__asm__ __volatile__ ( "tstb %0" : : "g" (*_mfp_gpip) : "cc" )
 
 
 struct PARTIAL_SCC {		/* just one channel */
@@ -413,14 +409,14 @@
  *
  */
 
-static __inline__ void _SCCwrite( struct async_struct *info, int regno,
-				 unsigned char val, int final_delay )
+static __inline__ void _SCCwrite(
+	volatile struct PARTIAL_SCC *sc,
+	unsigned char *shadow,
+	volatile unsigned char *_mfp_gpip,
+	int regno,
+	unsigned char val, int final_delay )
 
 {
-	volatile struct PARTIAL_SCC *sc =
-		(volatile struct PARTIAL_SCC *)info->port;
-	unsigned char *shadow = SCC_shadow[CHANNR(info)];
-
 	switch( regno ) {
 
 	  case COMMAND_REG:
@@ -496,13 +492,13 @@
 }
 
 
-static __inline__ unsigned char _SCCread( struct async_struct *info,
-					 int regno, int final_delay )
-
-{	volatile struct PARTIAL_SCC *sc =
-		(volatile struct PARTIAL_SCC *)info->port;
+static __inline__ unsigned char _SCCread(
+	volatile struct PARTIAL_SCC *sc,
+	unsigned char *shadow,
+	volatile unsigned char *_mfp_gpip,
+	int regno, int final_delay )
+{
 	unsigned char rv;
-	unsigned char *shadow = SCC_shadow[CHANNR(info)];
 
 	switch( regno ) {
 
@@ -511,20 +507,10 @@
 		rv = sc->ctrl;
 		break;
 
-	  case SPCOND_STATUS_REG:
-	  case FS_FIFO_LOW_REG:
-	  case FS_FIFO_HIGH_REG:
-	  case DPLL_STATUS_REG:
-	  normal_case:
-		sc->ctrl = regno & 0x0f;
-		scc_reg_delay();
-		rv = sc->ctrl;
-		break;
-		
 	  case INT_PENDING_REG:
 		/* RR3: read only from Channel A! */
 		sc = (volatile struct PARTIAL_SCC *)
-			((info->port & ~4) ^ (ChannelsReversed << 2));
+			(((unsigned long)sc & ~4) ^ ChannelsReversed);
 		goto normal_case;
 
 	  case RX_DATA_REG:
@@ -535,7 +521,7 @@
 	  case CURR_VECTOR_REG:
 		/* RR2 (vector including status) from Ch. B */
 		sc = (volatile struct PARTIAL_SCC *)
-			((info->port | 4) ^ (ChannelsReversed << 2));
+			(((unsigned long)sc | 4) ^ ChannelsReversed);
 		goto normal_case;
 		
 		/* --- reading write registers: access the shadow --- */
@@ -556,6 +542,16 @@
 				regno & ~16 );
 		break;
 		
+	  case SPCOND_STATUS_REG:
+	  case FS_FIFO_LOW_REG:
+	  case FS_FIFO_HIGH_REG:
+	  case DPLL_STATUS_REG:
+	  normal_case:
+		sc->ctrl = regno & 0x0f;
+		scc_reg_delay();
+		rv = sc->ctrl;
+		break;
+		
 	}
 
 	if (final_delay)
@@ -563,11 +559,25 @@
 	return rv;
 }
 
-
-#define	SCCwrite(reg,val)		_SCCwrite( info, (reg), (val), 1 )
-#define	SCCwrite_NB(reg,val)	_SCCwrite( info, (reg), (val), 0 )
-#define	SCCread(reg)			_SCCread( info, (reg), 1 )
-#define	SCCread_NB(reg)			_SCCread( info, (reg), 0 )
+#define SCC_ACCESS_INIT(info)												\
+	volatile struct PARTIAL_SCC *_SCC_p =									\
+		(volatile struct PARTIAL_SCC *)info->port;							\
+	unsigned char *_SCC_shadow =											\
+		({  unsigned char *_rv = (unsigned char *)SCC_shadow;				\
+			/* gcc generates suboptimal code for this, so I use an asm */	\
+			__asm__ ( "and.l #4,%1; lea %0@(%1:l:4),%0"						\
+					  /* alternative: lea %za0@(%2,%1:l:4),%0				\
+					   * what's faster? */									\
+					  : "=&a" (_rv)											\
+					  : "d" (_SCC_p), "0" (_rv) );							\
+			_rv;															\
+		});																	\
+	volatile unsigned char *_mfp_gpip = &mfp.par_dt_reg
+
+#define	SCCwrite(reg,val)		_SCCwrite(_SCC_p,_SCC_shadow,_mfp_gpip,(reg),(val),1)
+#define	SCCwrite_NB(reg,val)	_SCCwrite(_SCC_p,_SCC_shadow,_mfp_gpip,(reg),(val),0)
+#define	SCCread(reg)			_SCCread(_SCC_p,_SCC_shadow,_mfp_gpip,(reg),1)
+#define	SCCread_NB(reg)			_SCCread(_SCC_p,_SCC_shadow,_mfp_gpip,(reg),0)
 
 #define SCCmod(reg,and,or)		SCCwrite((reg),(SCCread(reg)&(and))|(or))
 
diff -u --recursive --exclude-from=diff-excludes --new-file linux-2.1.64.orig/drivers/video/atafb.c linux-2.1.64/drivers/video/atafb.c
--- linux-2.1.64.orig/drivers/video/atafb.c	Tue Dec  2 13:59:06 1997
+++ linux-2.1.64/drivers/video/atafb.c	Wed Dec  3 15:29:57 1997
@@ -2242,9 +2242,9 @@
 }
 
 #define OUTB(port,val) \
-	*((unsigned volatile char *) ((port)+external_vgaiobase))=(val)
+	*((unsigned volatile char *) ((port)+base))=(val)
 #define INB(port) \
-	(*((unsigned volatile char *) ((port)+external_vgaiobase)))
+	({ unsigned char __v = (*((unsigned volatile char *)((port)+base))); __v;})
 #define DACDelay 				\
 	do {					\
 		unsigned char tmp=INB(0x3da);	\
@@ -2270,8 +2270,9 @@
 						  unsigned transp )
 
 {	unsigned char colmask = (1 << external_bitspercol) - 1;
+	unsigned long base;
 
-	if (! external_vgaiobase)
+	if (!(base = external_vgaiobase))
 		return 1;
 
 	ext_color[regno].red = red;
