Linux MIPS Architecture development
 help / color / mirror / Atom feed
* Tool chain for linux using mips
From: Wink Saville @ 2007-11-25 18:43 UTC (permalink / raw)
  To: linux-mips

Hello,

I was wondering which MIPS tool chains people are
using and recommend, prebuilt and/or roll-your-own.
 From http://www.kegel.com/crosstool/crosstool-0.43/buildlogs/
there doesn't seem to be any combination that builds cleanly
for the mips/mipsel.

Regards,

Wink Saville

^ permalink raw reply

* Re: Tool chain for linux using mips
From: Wolfgang Denk @ 2007-11-25 19:22 UTC (permalink / raw)
  To: Wink Saville; +Cc: linux-mips
In-Reply-To: <4749C258.8020400@saville.com>

In message <4749C258.8020400@saville.com> you wrote:
> 
> I was wondering which MIPS tool chains people are
> using and recommend, prebuilt and/or roll-your-own.
>  From http://www.kegel.com/crosstool/crosstool-0.43/buildlogs/
> there doesn't seem to be any combination that builds cleanly
> for the mips/mipsel.

Well, we use the ELDK, obviously.

See http://www.denx.de/wiki/view/DULG/ELDK.

For the ELDK mailing list please see
http://lists.denx.de/mailman/listinfo/eldk

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Accident: A condition in which presence of mind is good, but  absence
of body is better.

^ permalink raw reply

* Re: BigSur: garbled characters during boot
From: Thomas Bogendoerfer @ 2007-11-25 22:17 UTC (permalink / raw)
  To: Atsushi Nemoto; +Cc: tbm, linux-mips, manoj.ekbote, mark.e.mason
In-Reply-To: <20071125.222803.25909189.anemo@mba.ocn.ne.jp>

On Sun, Nov 25, 2007 at 10:28:03PM +0900, Atsushi Nemoto wrote:
> Do you enable EARLY_PRINTK?  If so, this might be the console-handover
> issue.  On the handover, "console handover: boot ..." message will be
> printed both early console and new console.  If they were same device,
> drivers might be confused.

it will not be printed on both consoles, but while early console is
active the real console driver does things to the serial chip,
which might confuse the early console driver/prom.

> IIRC Maciej have tried to fix this issue a while ago on LKML.

this didn't work out for ip22zilog, so I digged through the mess. I
solved the problem by setting up the chip in one go. Before there
was some chip setup during probing, which killed prom_putchar().

Thomas

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessary a
good idea.                                                [ RFC1925, 2.3 ]

^ permalink raw reply

* Re: [SPAM] Tool chain for linux using mips
From: Markus Gothe @ 2007-11-26  9:37 UTC (permalink / raw)
  To: Wink Saville; +Cc: linux-mips
In-Reply-To: <4749C258.8020400@saville.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi, see http://wiki.debian.org/BuildingCrossCompilers for Debian-based
systems.

//Markus


Wink Saville wrote:
> Hello,
>
> I was wondering which MIPS tool chains people are using and
> recommend, prebuilt and/or roll-your-own. From
> http://www.kegel.com/crosstool/crosstool-0.43/buildlogs/ there
> doesn't seem to be any combination that builds cleanly for the
> mips/mipsel.
>
> Regards,
>
> Wink Saville
>
>


- --
_______________________________________

Mr Markus Gothe
Software Engineer

Phone: +46 (0)13 21 81 20 (ext. 1046)
Fax: +46 (0)13 21 21 15
Mobile: +46 (0)73 718 72 80
Diskettgatan 11, SE-583 35 Linköping, Sweden
www.27m.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFHSpPF6I0XmJx2NrwRCIstAKCsVP/rD4WbrgEF4D9ZItDpBIABjQCcCXYd
V4dkQ1XDMEPwAW11wJhUQZs=
=o/UK
-----END PGP SIGNATURE-----

^ permalink raw reply

* Re: ohci-ssb driver on a Broadcom BCM5354
From: Steve Brown @ 2007-11-26 11:05 UTC (permalink / raw)
  To: Michael Buesch; +Cc: John W. Linville, linux-mips
In-Reply-To: <200711191923.56471.mb@bu3sch.de>

Michael Buesch wrote:
> On Sunday 18 November 2007 23:47:52 John W. Linville wrote:
>   
>> You probably want to make Michael Buesch aware of this issue.
>>     
>
> I'm not sure anyone really tested this beyond some insmod tests.
> I did not test this, as I don't have such a device.
> So if you have any patches to fix this, please send them. I'm
> certainly the wrong person who can fix this. ;)
>
>   
Adding the following at the end of ssb_ohci_attach seems to fix the problem.

 if (ssb_dma_set_mask(dev, DMA_32BIT_MASK))
   return -EOPNOTSUPP;

I guessed at the dma mask. Would the code in the b43 driver that selects 
a dma mask be appropriate here?

Steve

^ permalink raw reply

* Re: BigSur: garbled characters during boot
From: Maciej W. Rozycki @ 2007-11-26 11:34 UTC (permalink / raw)
  To: Martin Michlmayr; +Cc: linux-mips, manoj.ekbote, mark.e.mason
In-Reply-To: <20071125134333.GO20922@deprecation.cyrius.com>

On Sun, 25 Nov 2007, Martin Michlmayr wrote:

> > IIRC Maciej have tried to fix this issue a while ago on LKML.
> 
> Right, I think I remember that discussion.  Did anything come out
> of it?

 The exact mess encountered is specific to the chip/board used.  I haven't 
seen too much of clutter on my SWARM, so I just disregarded the issue.  
If this is found problematic, I may have a look at the driver to see if 
anything can be done.  At least CFE sources are available, so if it turns 
out to be an issue there, it can be fixed too.  All the relevant registers 
in the DUART are r/w, so the state can easily be examined and preserved if 
need be.

 But please feel free to complain to the author of the change -- I am not 
sure if the amount of breakage throughout systems is justified by the gain 
from the additional message.  And there may be a way to implement it in a 
less intrusive way.

  Maciej

^ permalink raw reply

* Re: ohci-ssb driver on a Broadcom BCM5354
From: Michael Buesch @ 2007-11-26 14:15 UTC (permalink / raw)
  To: Steve Brown; +Cc: John W. Linville, linux-mips
In-Reply-To: <474AA87D.7000509@cortland.com>

On Monday 26 November 2007 12:05:33 Steve Brown wrote:
> Michael Buesch wrote:
> > On Sunday 18 November 2007 23:47:52 John W. Linville wrote:
> >   
> >> You probably want to make Michael Buesch aware of this issue.
> >>     
> >
> > I'm not sure anyone really tested this beyond some insmod tests.
> > I did not test this, as I don't have such a device.
> > So if you have any patches to fix this, please send them. I'm
> > certainly the wrong person who can fix this. ;)
> >
> >   
> Adding the following at the end of ssb_ohci_attach seems to fix the problem.
> 
>  if (ssb_dma_set_mask(dev, DMA_32BIT_MASK))
>    return -EOPNOTSUPP;
> 
> I guessed at the dma mask. Would the code in the b43 driver that selects 
> a dma mask be appropriate here?

I have no idea. If it makes it work, yeah. Cool. Let's add this.

-- 
Greetings Michael.

^ permalink raw reply

* Re: BigSur: oops loading ramdisk
From: Ralf Baechle @ 2007-11-26 14:45 UTC (permalink / raw)
  To: Martin Michlmayr; +Cc: linux-mips, manoj.ekbote, mark.e.mason
In-Reply-To: <20071125125229.GJ20922@deprecation.cyrius.com>

On Sun, Nov 25, 2007 at 01:52:29PM +0100, Martin Michlmayr wrote:

> With a 32 bit kernel (current git) on BigSur, I get an oops while
> trying to load the ramdisk:
> 
> Linux version 2.6.24-rc3-g2ffbb837-dirty (tbm@em64t) (gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)) #4 Sun Nov 25 12:44:26 UTC 2007

I've just modified the memory initialization code significantly to add
support for ZONE_DMA32 for the Sibyte boxes, so could you retest?

Thanks,

  Ralf

^ permalink raw reply

* [UPDATED PATCH] IP22ZILOG: fix lockup and sysrq
From: Thomas Bogendoerfer @ 2007-11-26 15:58 UTC (permalink / raw)
  To: linux-mips, linux-serial, linux-kernel; +Cc: ralf, akpm

- fix lockup when switching from early console to real console
- make sysrq reliable
- fix panic, if sysrq is issued before console is opened

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
---
 arch/mips/sgi-ip22/ip22-setup.c |   19 ---
 drivers/serial/ip22zilog.c      |  247 +++++++++++++++++----------------------
 include/asm-mips/system.h       |    2 -
 include/linux/serial_core.h     |    2 +-
 4 files changed, 107 insertions(+), 163 deletions(-)

diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c
index 174f09e..5f389ee 100644
--- a/arch/mips/sgi-ip22/ip22-setup.c
+++ b/arch/mips/sgi-ip22/ip22-setup.c
@@ -31,25 +31,6 @@
 unsigned long sgi_gfxaddr;
 EXPORT_SYMBOL_GPL(sgi_gfxaddr);
 
-/*
- * Stop-A is originally a Sun thing that isn't standard on IP22 so to avoid
- * accidents it's disabled by default on IP22.
- *
- * FIXME: provide a mechanism to change the value of stop_a_enabled.
- */
-int stop_a_enabled;
-
-void ip22_do_break(void)
-{
-	if (!stop_a_enabled)
-		return;
-
-	printk("\n");
-	ArcEnterInteractiveMode();
-}
-
-EXPORT_SYMBOL(ip22_do_break);
-
 extern void ip22_be_init(void) __init;
 
 void __init plat_mem_setup(void)
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
index f3257f7..9c95bc0 100644
--- a/drivers/serial/ip22zilog.c
+++ b/drivers/serial/ip22zilog.c
@@ -45,8 +45,6 @@
 
 #include "ip22zilog.h"
 
-void ip22_do_break(void);
-
 /*
  * On IP22 we need to delay after register accesses but we do not need to
  * flush writes.
@@ -81,12 +79,9 @@ struct uart_ip22zilog_port {
 #define IP22ZILOG_FLAG_REGS_HELD	0x00000040
 #define IP22ZILOG_FLAG_TX_STOPPED	0x00000080
 #define IP22ZILOG_FLAG_TX_ACTIVE	0x00000100
+#define IP22ZILOG_FLAG_RESET_DONE	0x00000200
 
-	unsigned int			cflag;
-
-	/* L1-A keyboard break state.  */
-	int				kbd_id;
-	int				l1_down;
+	unsigned int			tty_break;
 
 	unsigned char			parity_mask;
 	unsigned char			prev_status;
@@ -250,13 +245,26 @@ static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up,
 	}
 }
 
-static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
-				   struct zilog_channel *channel)
+#define Rx_BRK 0x0100                   /* BREAK event software flag.  */
+#define Rx_SYS 0x0200                   /* SysRq event software flag.  */
+
+static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
+						  struct zilog_channel *channel)
 {
-	struct tty_struct *tty = up->port.info->tty;	/* XXX info==NULL? */
+	struct tty_struct *tty;
+	unsigned char ch, flag;
+	unsigned int r1;
+
+	tty = NULL;
+	if (up->port.info != NULL &&
+	    up->port.info->tty != NULL)
+		tty = up->port.info->tty;
 
-	while (1) {
-		unsigned char ch, r1, flag;
+	for (;;) {
+		ch = readb(&channel->control);
+		ZSDELAY();
+		if (!(ch & Rx_CH_AV))
+			break;
 
 		r1 = read_zsreg(channel, R1);
 		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
@@ -265,43 +273,26 @@ static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
 			ZS_WSYNC(channel);
 		}
 
-		ch = readb(&channel->control);
-		ZSDELAY();
-
-		/* This funny hack depends upon BRK_ABRT not interfering
-		 * with the other bits we care about in R1.
-		 */
-		if (ch & BRK_ABRT)
-			r1 |= BRK_ABRT;
-
 		ch = readb(&channel->data);
 		ZSDELAY();
 
 		ch &= up->parity_mask;
 
-		if (ZS_IS_CONS(up) && (r1 & BRK_ABRT)) {
-			/* Wait for BREAK to deassert to avoid potentially
-			 * confusing the PROM.
-			 */
-			while (1) {
-				ch = readb(&channel->control);
-				ZSDELAY();
-				if (!(ch & BRK_ABRT))
-					break;
-			}
-			ip22_do_break();
-			return;
-		}
+		/* Handle the null char got when BREAK is removed.  */
+		if (!ch)
+			r1 |= up->tty_break;
 
 		/* A real serial line, record the character and status.  */
 		flag = TTY_NORMAL;
 		up->port.icount.rx++;
-		if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) {
-			if (r1 & BRK_ABRT) {
-				r1 &= ~(PAR_ERR | CRC_ERR);
+		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | Rx_SYS | Rx_BRK)) {
+			up->tty_break = 0;
+
+			if (r1 & (Rx_SYS | Rx_BRK)) {
 				up->port.icount.brk++;
-				if (uart_handle_break(&up->port))
-					goto next_char;
+				if (r1 & Rx_SYS)
+					continue;
+				r1 &= ~(PAR_ERR | CRC_ERR);
 			}
 			else if (r1 & PAR_ERR)
 				up->port.icount.parity++;
@@ -310,30 +301,21 @@ static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
 			if (r1 & Rx_OVR)
 				up->port.icount.overrun++;
 			r1 &= up->port.read_status_mask;
-			if (r1 & BRK_ABRT)
+			if (r1 & Rx_BRK)
 				flag = TTY_BREAK;
 			else if (r1 & PAR_ERR)
 				flag = TTY_PARITY;
 			else if (r1 & CRC_ERR)
 				flag = TTY_FRAME;
 		}
-		if (uart_handle_sysrq_char(&up->port, ch))
-			goto next_char;
 
-		if (up->port.ignore_status_mask == 0xff ||
-		    (r1 & up->port.ignore_status_mask) == 0)
-		    	tty_insert_flip_char(tty, ch, flag);
+		if (uart_handle_sysrq_char(&up->port, ch))
+			continue;
 
-		if (r1 & Rx_OVR)
-			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-	next_char:
-		ch = readb(&channel->control);
-		ZSDELAY();
-		if (!(ch & Rx_CH_AV))
-			break;
+		if (tty)
+			uart_insert_char(&up->port, r1, Rx_OVR, ch, flag);
 	}
-
-	tty_flip_buffer_push(tty);
+	return tty;
 }
 
 static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
@@ -348,6 +330,15 @@ static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
 	ZSDELAY();
 	ZS_WSYNC(channel);
 
+	if (up->curregs[R15] & BRKIE) {
+		if ((status & BRK_ABRT) && !(up->prev_status & BRK_ABRT)) {
+			if (uart_handle_break(&up->port))
+				up->tty_break = Rx_SYS;
+			else
+				up->tty_break = Rx_BRK;
+		}
+	}
+
 	if (ZS_WANTS_MODEM_STATUS(up)) {
 		if (status & SYNC)
 			up->port.icount.dsr++;
@@ -356,10 +347,10 @@ static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
 		 * But it does not tell us which bit has changed, we have to keep
 		 * track of this ourselves.
 		 */
-		if ((status & DCD) ^ up->prev_status)
+		if ((status ^ up->prev_status) ^ DCD)
 			uart_handle_dcd_change(&up->port,
 					       (status & DCD));
-		if ((status & CTS) ^ up->prev_status)
+		if ((status ^ up->prev_status) ^ CTS)
 			uart_handle_cts_change(&up->port,
 					       (status & CTS));
 
@@ -447,19 +438,21 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
 	while (up) {
 		struct zilog_channel *channel
 			= ZILOG_CHANNEL_FROM_PORT(&up->port);
+		struct tty_struct *tty;
 		unsigned char r3;
 
 		spin_lock(&up->port.lock);
 		r3 = read_zsreg(channel, R3);
 
 		/* Channel A */
+		tty = NULL;
 		if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
 			writeb(RES_H_IUS, &channel->control);
 			ZSDELAY();
 			ZS_WSYNC(channel);
 
 			if (r3 & CHARxIP)
-				ip22zilog_receive_chars(up, channel);
+				tty = ip22zilog_receive_chars(up, channel);
 			if (r3 & CHAEXT)
 				ip22zilog_status_handle(up, channel);
 			if (r3 & CHATxIP)
@@ -467,18 +460,22 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
 		}
 		spin_unlock(&up->port.lock);
 
+		if (tty)
+			tty_flip_buffer_push(tty);
+
 		/* Channel B */
 		up = up->next;
 		channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
 
 		spin_lock(&up->port.lock);
+		tty = NULL;
 		if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
 			writeb(RES_H_IUS, &channel->control);
 			ZSDELAY();
 			ZS_WSYNC(channel);
 
 			if (r3 & CHBRxIP)
-				ip22zilog_receive_chars(up, channel);
+				tty = ip22zilog_receive_chars(up, channel);
 			if (r3 & CHBEXT)
 				ip22zilog_status_handle(up, channel);
 			if (r3 & CHBTxIP)
@@ -486,6 +483,9 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
 		}
 		spin_unlock(&up->port.lock);
 
+		if (tty)
+			tty_flip_buffer_push(tty);
+
 		up = up->next;
 	}
 
@@ -681,11 +681,46 @@ static void ip22zilog_break_ctl(struct uart_port *port, int break_state)
 	spin_unlock_irqrestore(&port->lock, flags);
 }
 
+static void __ip22zilog_reset(struct uart_ip22zilog_port *up)
+{
+	struct zilog_channel *channel;
+	int i;
+
+	if (up->flags & IP22ZILOG_FLAG_RESET_DONE)
+		return;
+
+	/* Let pending transmits finish.  */
+	channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+	for (i = 0; i < 1000; i++) {
+		unsigned char stat = read_zsreg(channel, R1);
+		if (stat & ALL_SNT)
+			break;
+		udelay(100);
+	}
+
+	if (!ZS_IS_CHANNEL_A(up)) {
+		up++;
+		channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+	}
+	write_zsreg(channel, R9, FHWRES);
+	ZSDELAY_LONG();
+	(void) read_zsreg(channel, R0);
+
+	up->flags |= IP22ZILOG_FLAG_RESET_DONE;
+	up->next->flags |= IP22ZILOG_FLAG_RESET_DONE;
+}
+
 static void __ip22zilog_startup(struct uart_ip22zilog_port *up)
 {
 	struct zilog_channel *channel;
 
 	channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+
+	__ip22zilog_reset(up);
+
+	__load_zsregs(channel, up->curregs);
+	/* set master interrupt enable */
+	write_zsreg(channel, R9, up->curregs[R9]);
 	up->prev_status = readb(&channel->control);
 
 	/* Enable receiver and transmitter.  */
@@ -859,8 +894,6 @@ ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios,
 	else
 		up->flags &= ~IP22ZILOG_FLAG_MODEM_STATUS;
 
-	up->cflag = termios->c_cflag;
-
 	ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
 	uart_update_timeout(port, termios->c_cflag, baud);
 
@@ -992,74 +1025,29 @@ ip22zilog_console_write(struct console *con, const char *s, unsigned int count)
 	spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
-void
-ip22serial_console_termios(struct console *con, char *options)
-{
-	int baud = 9600, bits = 8, cflag;
-	int parity = 'n';
-	int flow = 'n';
-
-	if (options)
-		uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-	cflag = CREAD | HUPCL | CLOCAL;
-
-	switch (baud) {
-		case 150: cflag |= B150; break;
-		case 300: cflag |= B300; break;
-		case 600: cflag |= B600; break;
-		case 1200: cflag |= B1200; break;
-		case 2400: cflag |= B2400; break;
-		case 4800: cflag |= B4800; break;
-		case 9600: cflag |= B9600; break;
-		case 19200: cflag |= B19200; break;
-		case 38400: cflag |= B38400; break;
-		default: baud = 9600; cflag |= B9600; break;
-	}
-
-	con->cflag = cflag | CS8;			/* 8N1 */
-
-	uart_update_timeout(&ip22zilog_port_table[con->index].port, cflag, baud);
-}
-
 static int __init ip22zilog_console_setup(struct console *con, char *options)
 {
 	struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
 	unsigned long flags;
-	int baud, brg;
-
-	printk("Console: ttyS%d (IP22-Zilog)\n", con->index);
+	int baud = 9600, bits = 8;
+	int parity = 'n';
+	int flow = 'n';
 
-	/* Get firmware console settings.  */
-	ip22serial_console_termios(con, options);
+	up->flags |= IP22ZILOG_FLAG_IS_CONS;
 
-	/* Firmware console speed is limited to 150-->38400 baud so
-	 * this hackish cflag thing is OK.
-	 */
-	switch (con->cflag & CBAUD) {
-	case B150: baud = 150; break;
-	case B300: baud = 300; break;
-	case B600: baud = 600; break;
-	case B1200: baud = 1200; break;
-	case B2400: baud = 2400; break;
-	case B4800: baud = 4800; break;
-	default: case B9600: baud = 9600; break;
-	case B19200: baud = 19200; break;
-	case B38400: baud = 38400; break;
-	};
-
-	brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+	printk(KERN_INFO "Console: ttyS%d (IP22-Zilog)\n", con->index);
 
 	spin_lock_irqsave(&up->port.lock, flags);
 
-	up->curregs[R15] = BRKIE;
-	ip22zilog_convert_to_zs(up, con->cflag, 0, brg);
+	up->curregs[R15] |= BRKIE;
 
 	__ip22zilog_startup(up);
 
 	spin_unlock_irqrestore(&up->port.lock, flags);
 
-	return 0;
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	return uart_set_options(&up->port, con, baud, parity, bits, flow);
 }
 
 static struct uart_driver ip22zilog_reg;
@@ -1140,25 +1128,10 @@ static void __init ip22zilog_prepare(void)
 		up[(chip * 2) + 1].port.line = (chip * 2) + 1;
 		up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
 	}
-}
-
-static void __init ip22zilog_init_hw(void)
-{
-	int i;
-
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
-		struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
-		unsigned long flags;
-		int baud, brg;
 
-		spin_lock_irqsave(&up->port.lock, flags);
-
-		if (ZS_IS_CHANNEL_A(up)) {
-			write_zsreg(channel, R9, FHWRES);
-			ZSDELAY_LONG();
-			(void) read_zsreg(channel, R0);
-		}
+	for (channel = 0; channel < NUM_CHANNELS; channel++) {
+		struct uart_ip22zilog_port *up = &ip22zilog_port_table[channel];
+		int brg;
 
 		/* Normal serial TTY. */
 		up->parity_mask = 0xff;
@@ -1169,16 +1142,10 @@ static void __init ip22zilog_init_hw(void)
 		up->curregs[R9] = NV | MIE;
 		up->curregs[R10] = NRZ;
 		up->curregs[R11] = TCBR | RCBR;
-		baud = 9600;
-		brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+		brg = BPS_TO_BRG(9600, ZS_CLOCK / ZS_CLOCK_DIVISOR);
 		up->curregs[R12] = (brg & 0xff);
 		up->curregs[R13] = (brg >> 8) & 0xff;
 		up->curregs[R14] = BRENAB;
-		__load_zsregs(channel, up->curregs);
-	        /* set master interrupt enable */
-	        write_zsreg(channel, R9, up->curregs[R9]);
-
-		spin_unlock_irqrestore(&up->port.lock, flags);
 	}
 }
 
@@ -1195,8 +1162,6 @@ static int __init ip22zilog_ports_init(void)
 		panic("IP22-Zilog: Unable to register zs interrupt handler.\n");
 	}
 
-	ip22zilog_init_hw();
-
 	ret = uart_register_driver(&ip22zilog_reg);
 	if (ret == 0) {
 		int i;
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 1030562..a944eda 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -209,8 +209,6 @@ extern void *set_except_vector(int n, void *addr);
 extern unsigned long ebase;
 extern void per_cpu_trap_init(void);
 
-extern int stop_a_enabled;
-
 /*
  * See include/asm-ia64/system.h; prevents deadlock on SMP
  * systems.
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 6a5203f..9963f81 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -437,7 +437,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
 #ifdef SUPPORT_SYSRQ
 	if (port->sysrq) {
 		if (ch && time_before(jiffies, port->sysrq)) {
-			handle_sysrq(ch, port->info->tty);
+			handle_sysrq(ch, port->info ? port->info->tty : NULL);
 			port->sysrq = 0;
 			return 1;
 		}
-- 
1.4.4.4

^ permalink raw reply related

* Re: BigSur: oops loading ramdisk
From: Martin Michlmayr @ 2007-11-26 16:17 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: linux-mips, manoj.ekbote, mark.e.mason
In-Reply-To: <20071126144543.GA19679@linux-mips.org>

* Ralf Baechle <ralf@linux-mips.org> [2007-11-26 14:45]:
> > With a 32 bit kernel (current git) on BigSur, I get an oops while
> > trying to load the ramdisk:
> I've just modified the memory initialization code significantly to add
> support for ZONE_DMA32 for the Sibyte boxes, so could you retest?

Same problem with your patch (current Linus git plus your patch):

Freeing unused kernel memory: 136k freed
CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 8029a238, ra == 8029d674
Oops[#1]:
Cpu 0
$ 0   : 00000000 10001f00 00000000 00000000
$ 4   : 8e89f000 00000000 8f421df8 00000000
$ 8   : 80440000 8e889a6c 00000000 0000000e
$12   : 8ec6903c ffffffff 00000000 00000088
$16   : 8eda0240 80450000 00500001 8e89f000
$20   : 00000002 8f00d114 00000000 00000000
$24   : 00000003 000000cd
$28   : 8f420000 8f421da8 00000000 8029d674
Hi    : 00000002
Lo    : 82828285
epc   : 8029a238 init_dev+0x8c/0x56c     Not tainted
ra    : 8029d674 tty_open+0x148/0x330
Status: 10001f03    KERNEL EXL IE
Cause : 00808008
BadVA : 00000000
PrId  : 01041100 (SiByte SB1A)
Modules linked in:
Process swapper (pid: 1, threadinfo=8f420000, task=8f41f928)
Stack : 801789f0 00000003 8044e874 8e89f000 8f421dfc 00000000 8eda0240 80450000
        00500001 00000001 00000002 8f00d114 00000000 00000000 00000000 8029d674
        8ec69d28 00000000 8f421df8 00000000 8ec69d28 00000000 00000000 80496fe0
        8ec69d28 8eda0240 8f4032a0 80172fa8 00000000 8f413000 ffffff9c 8017bb04
        00000000 8043bba0 8eda0240 8ec69d28 00000000 80172e88 8016df1c 80440000
        ...
Call Trace:
[<8029a238>] init_dev+0x8c/0x56c
[<8029d674>] tty_open+0x148/0x330
[<80172fa8>] chrdev_open+0x120/0x178
[<8016df1c>] __dentry_open+0x104/0x210
[<8016e0d4>] nameidata_to_filp+0x30/0x54
[<8016e138>] do_filp_open+0x40/0x54
[<8016e1b0>] do_sys_open+0x64/0x114
[<80100448>] init_post+0x30/0xe8
[<80456874>] kernel_init+0x2e4/0x314


Code: 8c8200a0  00051880  00431021 <8c510000> 162000e2  00000000  8e64003c  10800009  24020002
Kernel panic - not syncing: Attempted to kill init!

-- 
Martin Michlmayr
http://www.cyrius.com/

^ permalink raw reply

* Re: [UPDATED PATCH] IP22ZILOG: fix lockup and sysrq
From: Ralf Baechle @ 2007-11-26 16:19 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: linux-mips, linux-serial, linux-kernel, akpm
In-Reply-To: <20071126160538.507EAC2B22@solo.franken.de>

On Mon, Nov 26, 2007 at 04:58:03PM +0100, Thomas Bogendoerfer wrote:

> - fix lockup when switching from early console to real console
> - make sysrq reliable
> - fix panic, if sysrq is issued before console is opened
> 
> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>

Acked-by: Ralf Baechle <ralf@linux-mips.org>

Several Indy users have reported the issues fixed by this patch so it's
2.6.24 material.

  Ralf

^ permalink raw reply

* Re: [PATCH] IP22: Fix modules for 64bit kernels by using a CKSEG2 MAP_BASE
From: Ralf Baechle @ 2007-11-26 16:56 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: linux-mips
In-Reply-To: <20071125100224.GA17974@alpha.franken.de>

On Sun, Nov 25, 2007 at 11:03:12AM +0100, Thomas Bogendoerfer wrote:

> please drop this bogus patch, it causes vmalloc allocations fails. The bug
> it tries to fix isn't even there.

Ok.

  Ralf

^ permalink raw reply

* Re: [PATCH] [MIPS]: Compliment va_start() with va_end().
From: Ralf Baechle @ 2007-11-26 17:15 UTC (permalink / raw)
  To: Richard Knutsson; +Cc: linux-mips, linux-kernel
In-Reply-To: <20071124211046.9931.46998.sendpatchset@thinktank.campus.ltu.se>

On Sat, Nov 24, 2007 at 10:22:19PM +0100, Richard Knutsson wrote:

> Compliment va_start() with va_end().

Thanks, applied.

  Ralf

^ permalink raw reply

* RE: Tool chain for linux using mips
From: Mitchell, Earl @ 2007-11-26 19:54 UTC (permalink / raw)
  To: Wink Saville, linux-mips
In-Reply-To: <4749C258.8020400@saville.com>


Few months ago I was able to successfully build using 
crosstools-0.43. I used demo-mipsel.sh to build c,c++ using 
the following command line ... 

eval `cat mips.dat gcc-3.4.5-glibc-2.3.6-tls.dat` sh all.sh --notest --gdb

-earlm

> -----Original Message-----
> From: linux-mips-bounce@linux-mips.org
> [mailto:linux-mips-bounce@linux-mips.org]On Behalf Of Wink Saville
> Sent: Sunday, November 25, 2007 10:44 AM
> To: linux-mips@linux-mips.org
> Subject: Tool chain for linux using mips
> 
> 
> Hello,
> 
> I was wondering which MIPS tool chains people are
> using and recommend, prebuilt and/or roll-your-own.
>  From http://www.kegel.com/crosstool/crosstool-0.43/buildlogs/
> there doesn't seem to be any combination that builds cleanly
> for the mips/mipsel.
> 
> Regards,
> 
> Wink Saville
> 
> 
> 

^ permalink raw reply

* RE: Tool chain for linux using mips
From: Mitchell, Earl @ 2007-11-26 19:54 UTC (permalink / raw)
  To: Wink Saville, linux-mips
In-Reply-To: <4749C258.8020400@saville.com>


Few months ago I was able to successfully build using 
crosstools-0.43. I used demo-mipsel.sh to build c,c++ using 
the following command line ... 

eval `cat mips.dat gcc-3.4.5-glibc-2.3.6-tls.dat` sh all.sh --notest --gdb

-earlm

> -----Original Message-----
> From: linux-mips-bounce@linux-mips.org
> [mailto:linux-mips-bounce@linux-mips.org]On Behalf Of Wink Saville
> Sent: Sunday, November 25, 2007 10:44 AM
> To: linux-mips@linux-mips.org
> Subject: Tool chain for linux using mips
> 
> 
> Hello,
> 
> I was wondering which MIPS tool chains people are
> using and recommend, prebuilt and/or roll-your-own.
>  From http://www.kegel.com/crosstool/crosstool-0.43/buildlogs/
> there doesn't seem to be any combination that builds cleanly
> for the mips/mipsel.
> 
> Regards,
> 
> Wink Saville
> 
> 
> 

^ permalink raw reply

* SGI IP28 support
From: Thomas Bogendoerfer @ 2007-11-26 22:38 UTC (permalink / raw)
  To: linux-mips

I finally cleaned up Peter Fuerst's IP28 patches and solved some of
the IP28 issues in an IMHO more eye-friendly way (no ip26ucmem).
My IP28 boots with these patches from an Debian sarge NFS root and
is able to dd data from the harddrive. I'm going to send this patches
to this list and the subsystem maintainers.

There is one change missing to get a working SCSI driver, because
a proper fix will be done in 2.6.25. The quick&dirty workaround is
below. The workaround makes sure that the sense_buffer lives in
its own cache line by aligning and extendin it.

The patch "Use real cache invalidate" still contains one problem.
It will not flush the cache correctly, if the given size is bigger
than the second level cache. The problem is, that there is no index
invalidate cache operation available. I have two ideas to solve that.
One is to always do a range invalidate (maybe just by using this only
for R10k machines, which usually have quite big caches) or scan through
the cache and use the tag informations to do hit invalidate. If anybody
has a better idea please speak up :-)

Have fun with the patches,
Thomas.


diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 3f47e52..3f3d7aa 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -87,11 +87,13 @@ struct scsi_cmnd {
 	struct request *request;	/* The command we are
 				   	   working on */
 
+	unsigned char xxx1[0x48];
 #define SCSI_SENSE_BUFFERSIZE 	96
 	unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
 				/* obtained by REQUEST SENSE when
 				 * CHECK CONDITION is received on original
 				 * command (auto-sense) */
+	unsigned char xxx2[32];
 
 	/* Low-level done function - can be used by low-level driver to point
 	 *        to completion function.  Not used by mid/upper level code. */




-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessary a
good idea.                                                [ RFC1925, 2.3 ]

^ permalink raw reply related

* [PATCH] IP22/IP28: fix extracting board/chip rev
From: Thomas Bogendoerfer @ 2007-11-25 10:27 UTC (permalink / raw)
  To: linux-mips; +Cc: ralf

Taken from Peter Fuersts IP28 patches

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
---
 include/asm-mips/sgi/ioc.h |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/asm-mips/sgi/ioc.h b/include/asm-mips/sgi/ioc.h
index f3e3dc9..343ed15 100644
--- a/include/asm-mips/sgi/ioc.h
+++ b/include/asm-mips/sgi/ioc.h
@@ -138,8 +138,8 @@ struct sgioc_regs {
 	u8 _sysid[3];
 	volatile u8 sysid;
 #define SGIOC_SYSID_FULLHOUSE	0x01
-#define SGIOC_SYSID_BOARDREV(x)	((x & 0xe0) > 5)
-#define SGIOC_SYSID_CHIPREV(x)	((x & 0x1e) > 1)
+#define SGIOC_SYSID_BOARDREV(x)	(((x) & 0x1e) >> 1)
+#define SGIOC_SYSID_CHIPREV(x)	(((x) & 0xe0) >> 5)
 	u32 _unused2;
 	u8 _read[3];
 	volatile u8 read;
-- 
1.4.4.4

^ permalink raw reply related

* [PATCH] fix warning when using PHYS_TO_XKSEG_xx()
From: Thomas Bogendoerfer @ 2007-11-25 10:28 UTC (permalink / raw)
  To: linux-mips; +Cc: ralf

use CONST64 cast in PHYS_TO_XPHYS macro to avoid warning about shifts
longer than the target type.

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
---
 arch/mips/lib/uncached.c     |    8 ++++----
 include/asm-mips/addrspace.h |    2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c
index 58d14f4..b59b770 100644
--- a/arch/mips/lib/uncached.c
+++ b/arch/mips/lib/uncached.c
@@ -46,8 +46,8 @@ unsigned long __init run_uncached(void *func)
 	if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
 		usp = CKSEG1ADDR(sp);
 #ifdef CONFIG_64BIT
-	else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0LL, 0) &&
-		 (long long)sp < (long long)PHYS_TO_XKPHYS(8LL, 0))
+	else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0, 0) &&
+		 (long long)sp < (long long)PHYS_TO_XKPHYS(8, 0))
 		usp = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
 				     XKPHYS_TO_PHYS((long long)sp));
 #endif
@@ -58,8 +58,8 @@ unsigned long __init run_uncached(void *func)
 	if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2)
 		ufunc = CKSEG1ADDR(lfunc);
 #ifdef CONFIG_64BIT
-	else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0LL, 0) &&
-		 (long long)lfunc < (long long)PHYS_TO_XKPHYS(8LL, 0))
+	else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0, 0) &&
+		 (long long)lfunc < (long long)PHYS_TO_XKPHYS(8, 0))
 		ufunc = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
 				       XKPHYS_TO_PHYS((long long)lfunc));
 #endif
diff --git a/include/asm-mips/addrspace.h b/include/asm-mips/addrspace.h
index 0bb7a93..9002d66 100644
--- a/include/asm-mips/addrspace.h
+++ b/include/asm-mips/addrspace.h
@@ -127,7 +127,7 @@
 #define PHYS_TO_XKSEG_CACHED(p)		PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE, (p))
 #define XKPHYS_TO_PHYS(p)		((p) & TO_PHYS_MASK)
 #define PHYS_TO_XKPHYS(cm, a)		(_CONST64_(0x8000000000000000) | \
-					 ((cm)<<59) | (a))
+					 (_CONST64_(cm)<<59) | (a))
 
 /*
  * The ultimate limited of the 64-bit MIPS architecture:  2 bits for selecting
-- 
1.4.4.4

^ permalink raw reply related

* [PATCH] SGIWD93: use cached memory access to make driver work on IP28
From: Thomas Bogendoerfer @ 2007-11-26 17:41 UTC (permalink / raw)
  To: linux-scsi, linux-mips; +Cc: ralf, James.Bottomley

Following patch is 2.6.25 material needed to get SGI IP28 machines
supported.

Thomas.

SGI IP28 machines would need special treatment (enable adding addtional
wait states) when accessing memory uncached. To avoid this pain I
changed the driver to use only cached access to memory.

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
---
 drivers/scsi/sgiwd93.c |   68 ++++++++++++++++++++++++++++++-----------------
 1 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index eef8275..d4e6468 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -33,19 +33,27 @@
 
 struct ip22_hostdata {
 	struct WD33C93_hostdata wh;
-	struct hpc_data {
-		dma_addr_t      dma;
-		void		*cpu;
-	} hd;
+	dma_addr_t dma;
+	void *cpu;
+	void *dev;
 };
 
 #define host_to_hostdata(host) ((struct ip22_hostdata *)((host)->hostdata))
 
 struct hpc_chunk {
 	struct hpc_dma_desc desc;
-	u32 _padding;	/* align to quadword boundary */
+	u32 _padding[128/4 - 3];	/* align to biggest cache line size */
 };
 
+/* space for hpc dma descriptors */
+#define HPC_DMA_SIZE   (4 * PAGE_SIZE)
+
+/* we only need to sync the dma descriptor */
+#define DMA_HPC_SYNC(dev, hcp, dir) \
+	dma_cache_sync(dev, hcp, sizeof(struct hpc_dma_desc), dir)
+
+#define DMA_DIR(d)   ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE)
+
 static irqreturn_t sgiwd93_intr(int irq, void *dev_id)
 {
 	struct Scsi_Host * host = dev_id;
@@ -59,14 +67,14 @@ static irqreturn_t sgiwd93_intr(int irq, void *dev_id)
 }
 
 static inline
-void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp)
+void fill_hpc_entries(void *dev, struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp)
 {
 	unsigned long len = cmd->SCp.this_residual;
 	void *addr = cmd->SCp.ptr;
 	dma_addr_t physaddr;
 	unsigned long count;
 
-	physaddr = dma_map_single(NULL, addr, len, cmd->sc_data_direction);
+	physaddr = dma_map_single(dev, addr, len, DMA_DIR(datainp));
 	cmd->SCp.dma_handle = physaddr;
 
 	while (len) {
@@ -77,6 +85,7 @@ void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp)
 		count = len > 8192 ? 8192 : len;
 		hcp->desc.pbuf = physaddr;
 		hcp->desc.cntinfo = count;
+		DMA_HPC_SYNC(dev, hcp, DMA_TO_DEVICE);
 		hcp++;
 		len -= count;
 		physaddr += count;
@@ -89,6 +98,7 @@ void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp)
 	 */
 	hcp->desc.pbuf = 0;
 	hcp->desc.cntinfo = HPCDMA_EOX;
+	DMA_HPC_SYNC(dev, hcp, DMA_TO_DEVICE);
 }
 
 static int dma_setup(struct scsi_cmnd *cmd, int datainp)
@@ -96,7 +106,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int datainp)
 	struct ip22_hostdata *hdata = host_to_hostdata(cmd->device->host);
 	struct hpc3_scsiregs *hregs =
 		(struct hpc3_scsiregs *) cmd->device->host->base;
-	struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->hd.cpu;
+	struct hpc_chunk *hcp = (struct hpc_chunk *)hdata->cpu;
 
 	pr_debug("dma_setup: datainp<%d> hcp<%p> ", datainp, hcp);
 
@@ -111,12 +121,12 @@ static int dma_setup(struct scsi_cmnd *cmd, int datainp)
 	if (cmd->SCp.ptr == NULL || cmd->SCp.this_residual == 0)
 		return 1;
 
-	fill_hpc_entries(hcp, cmd, datainp);
+	fill_hpc_entries(hdata->dev, hcp, cmd, datainp);
 
 	pr_debug(" HPCGO\n");
 
 	/* Start up the HPC. */
-	hregs->ndptr = hdata->hd.dma;
+	hregs->ndptr = hdata->dma;
 	if (datainp)
 		hregs->ctrl = HPC3_SCTRL_ACTIVE;
 	else
@@ -134,6 +144,9 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 	if (!SCpnt)
 		return;
 
+	if (SCpnt->SCp.ptr == NULL || SCpnt->SCp.this_residual == 0)
+		return;
+
 	hregs = (struct hpc3_scsiregs *) SCpnt->device->host->base;
 
 	pr_debug("dma_stop: status<%d> ", status);
@@ -145,8 +158,9 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 			barrier();
 	}
 	hregs->ctrl = 0;
-	dma_unmap_single(NULL, SCpnt->SCp.dma_handle, SCpnt->SCp.this_residual,
-	                 SCpnt->sc_data_direction);
+	dma_unmap_single(hdata->dev, SCpnt->SCp.dma_handle,
+			 SCpnt->SCp.this_residual,
+			 DMA_DIR(hdata->wh.dma_dir));
 
 	pr_debug("\n");
 }
@@ -160,22 +174,25 @@ void sgiwd93_reset(unsigned long base)
 	hregs->ctrl = 0;
 }
 
-static inline void init_hpc_chain(struct hpc_data *hd)
+static inline void init_hpc_chain(void *dev, struct ip22_hostdata *hdata)
 {
-	struct hpc_chunk *hcp = (struct hpc_chunk *) hd->cpu;
-	struct hpc_chunk *dma = (struct hpc_chunk *) hd->dma;
+	struct hpc_chunk *hcp = (struct hpc_chunk *)hdata->cpu;
+	dma_addr_t dma = hdata->dma;
 	unsigned long start, end;
 
 	start = (unsigned long) hcp;
-	end = start + PAGE_SIZE;
+	end = start + (4 * PAGE_SIZE);
 	while (start < end) {
-		hcp->desc.pnext = (u32) (dma + 1);
+		hcp->desc.pnext = (u32) (dma + sizeof(struct hpc_chunk));
 		hcp->desc.cntinfo = HPCDMA_EOX;
-		hcp++; dma++;
+		DMA_HPC_SYNC(dev, hcp, DMA_TO_DEVICE);
+		hcp++;
+		dma += sizeof(struct hpc_chunk);
 		start += sizeof(struct hpc_chunk);
 	};
 	hcp--;
-	hcp->desc.pnext = hd->dma;
+	hcp->desc.pnext = hdata->dma;
+	DMA_HPC_SYNC(dev, hcp, DMA_TO_DEVICE);
 }
 
 static int sgiwd93_bus_reset(struct scsi_cmnd *cmd)
@@ -234,16 +251,17 @@ static int __init sgiwd93_probe(struct platform_device *pdev)
 	host->irq = irq;
 
 	hdata = host_to_hostdata(host);
-	hdata->hd.cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
-	                                   &hdata->hd.dma, GFP_KERNEL);
-	if (!hdata->hd.cpu) {
+	hdata->dev = &pdev->dev;
+	hdata->cpu = dma_alloc_noncoherent(&pdev->dev, HPC_DMA_SIZE,
+					   &hdata->dma, GFP_KERNEL);
+	if (!hdata->cpu) {
 		printk(KERN_WARNING "sgiwd93: Could not allocate memory for "
 		       "host %d buffer.\n", unit);
 		err = -ENOMEM;
 		goto out_put;
 	}
 
-	init_hpc_chain(&hdata->hd);
+	init_hpc_chain(&pdev->dev, hdata);
 
 	regs.SASR = wdregs + 3;
 	regs.SCMD = wdregs + 7;
@@ -273,7 +291,7 @@ static int __init sgiwd93_probe(struct platform_device *pdev)
 out_irq:
 	free_irq(irq, host);
 out_free:
-	dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
+	dma_free_noncoherent(NULL, HPC_DMA_SIZE, hdata->cpu, hdata->dma);
 out_put:
 	scsi_host_put(host);
 out:
@@ -289,7 +307,7 @@ static void __exit sgiwd93_remove(struct platform_device *pdev)
 
 	scsi_remove_host(host);
 	free_irq(pd->irq, host);
-	dma_free_coherent(&pdev->dev, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
+	dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma);
 	scsi_host_put(host);
 }
 
-- 
1.4.4.4

^ permalink raw reply related

* [PATCH] IP28: added cache barrier to assembly routines
From: Thomas Bogendoerfer @ 2007-11-25 10:47 UTC (permalink / raw)
  To: linux-mips; +Cc: ralf

IP28 needs special treatment to avoid speculative accesses. gcc
takes care for .c code, but for assembly code we need to do it
manually.

This is taken from Peter Fuersts IP28 patches.

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
---
 arch/mips/lib/memcpy.S       |   10 ++++++++++
 arch/mips/lib/memset.S       |    5 +++++
 arch/mips/lib/strncpy_user.S |    1 +
 include/asm-mips/asm.h       |    8 ++++++++
 4 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S
index a526c62..054399d 100644
--- a/arch/mips/lib/memcpy.S
+++ b/arch/mips/lib/memcpy.S
@@ -194,6 +194,7 @@ FEXPORT(__copy_user)
 	 */
 #define rem t8
 
+	R10KCBARRIER(0(ra))
 	/*
 	 * The "issue break"s below are very approximate.
 	 * Issue delays for dcache fills will perturb the schedule, as will
@@ -226,6 +227,7 @@ both_aligned:
 	PREF(	1, 3*32(dst) )
 	.align	4
 1:
+	R10KCBARRIER(0(ra))
 EXC(	LOAD	t0, UNIT(0)(src),	l_exc)
 EXC(	LOAD	t1, UNIT(1)(src),	l_exc_copy)
 EXC(	LOAD	t2, UNIT(2)(src),	l_exc_copy)
@@ -267,6 +269,7 @@ EXC(	LOAD	t2, UNIT(2)(src),	l_exc_copy)
 EXC(	LOAD	t3, UNIT(3)(src),	l_exc_copy)
 	SUB	len, len, 4*NBYTES
 	ADD	src, src, 4*NBYTES
+	R10KCBARRIER(0(ra))
 EXC(	STORE	t0, UNIT(0)(dst),	s_exc_p4u)
 EXC(	STORE	t1, UNIT(1)(dst),	s_exc_p3u)
 EXC(	STORE	t2, UNIT(2)(dst),	s_exc_p2u)
@@ -280,6 +283,7 @@ less_than_4units:
 	beq	rem, len, copy_bytes
 	 nop
 1:
+	R10KCBARRIER(0(ra))
 EXC(	LOAD	t0, 0(src),		l_exc)
 	ADD	src, src, NBYTES
 	SUB	len, len, NBYTES
@@ -325,6 +329,7 @@ EXC(	LDFIRST	t3, FIRST(0)(src),	l_exc)
 EXC(	LDREST	t3, REST(0)(src),	l_exc_copy)
 	SUB	t2, t2, t1	# t2 = number of bytes copied
 	xor	match, t0, t1
+	R10KCBARRIER(0(ra))
 EXC(	STFIRST t3, FIRST(0)(dst),	s_exc)
 	beq	len, t2, done
 	 SUB	len, len, t2
@@ -345,6 +350,7 @@ src_unaligned_dst_aligned:
  * It's OK to load FIRST(N+1) before REST(N) because the two addresses
  * are to the same unit (unless src is aligned, but it's not).
  */
+	R10KCBARRIER(0(ra))
 EXC(	LDFIRST	t0, FIRST(0)(src),	l_exc)
 EXC(	LDFIRST	t1, FIRST(1)(src),	l_exc_copy)
 	SUB     len, len, 4*NBYTES
@@ -373,6 +379,7 @@ cleanup_src_unaligned:
 	beq	rem, len, copy_bytes
 	 nop
 1:
+	R10KCBARRIER(0(ra))
 EXC(	LDFIRST t0, FIRST(0)(src),	l_exc)
 EXC(	LDREST	t0, REST(0)(src),	l_exc_copy)
 	ADD	src, src, NBYTES
@@ -386,6 +393,7 @@ copy_bytes_checklen:
 	 nop
 copy_bytes:
 	/* 0 < len < NBYTES  */
+	R10KCBARRIER(0(ra))
 #define COPY_BYTE(N)			\
 EXC(	lb	t0, N(src), l_exc);	\
 	SUB	len, len, 1;		\
@@ -498,6 +506,7 @@ LEAF(__rmemcpy)					/* a0=dst a1=src a2=len */
 	ADD	a1, a2				# src = src + len
 
 r_end_bytes:
+	R10KCBARRIER(0(ra))
 	lb	t0, -1(a1)
 	SUB	a2, a2, 0x1
 	sb	t0, -1(a0)
@@ -510,6 +519,7 @@ r_out:
 	 move	a2, zero
 
 r_end_bytes_up:
+	R10KCBARRIER(0(ra))
 	lb	t0, (a1)
 	SUB	a2, a2, 0x1
 	sb	t0, (a0)
diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S
index 3f8b8b3..aad0639 100644
--- a/arch/mips/lib/memset.S
+++ b/arch/mips/lib/memset.S
@@ -77,6 +77,7 @@ FEXPORT(__bzero)
 	beqz		t0, 1f
 	 PTR_SUBU	t0, LONGSIZE		/* alignment in bytes */
 
+	R10KCBARRIER(0(ra))
 #ifdef __MIPSEB__
 	EX(LONG_S_L, a1, (a0), first_fixup)	/* make word/dword aligned */
 #endif
@@ -94,11 +95,13 @@ FEXPORT(__bzero)
 	PTR_ADDU	t1, a0			/* end address */
 	.set		reorder
 1:	PTR_ADDIU	a0, 64
+	R10KCBARRIER(0(ra))
 	f_fill64 a0, -64, a1, fwd_fixup
 	bne		t1, a0, 1b
 	.set		noreorder
 
 memset_partial:
+	R10KCBARRIER(0(ra))
 	PTR_LA		t1, 2f			/* where to start */
 #if LONGSIZE == 4
 	PTR_SUBU	t1, t0
@@ -120,6 +123,7 @@ memset_partial:
 
 	beqz		a2, 1f
 	 PTR_ADDU	a0, a2			/* What's left */
+	R10KCBARRIER(0(ra))
 #ifdef __MIPSEB__
 	EX(LONG_S_R, a1, -1(a0), last_fixup)
 #endif
@@ -134,6 +138,7 @@ small_memset:
 	 PTR_ADDU	t1, a0, a2
 
 1:	PTR_ADDIU	a0, 1			/* fill bytewise */
+	R10KCBARRIER(0(ra))
 	bne		t1, a0, 1b
 	 sb		a1, -1(a0)
 
diff --git a/arch/mips/lib/strncpy_user.S b/arch/mips/lib/strncpy_user.S
index d16c76f..8fd21d5 100644
--- a/arch/mips/lib/strncpy_user.S
+++ b/arch/mips/lib/strncpy_user.S
@@ -38,6 +38,7 @@ FEXPORT(__strncpy_from_user_nocheck_asm)
 	.set		noreorder
 1:	EX(lbu, t0, (v1), fault)
 	PTR_ADDIU	v1, 1
+	R10KCBARRIER(0(ra))
 	beqz		t0, 2f
 	 sb		t0, (a0)
 	PTR_ADDIU	v0, 1
diff --git a/include/asm-mips/asm.h b/include/asm-mips/asm.h
index 12e1758..608cfcf 100644
--- a/include/asm-mips/asm.h
+++ b/include/asm-mips/asm.h
@@ -398,4 +398,12 @@ symbol		=	value
 
 #define SSNOP		sll zero, zero, 1
 
+#ifdef CONFIG_SGI_IP28
+/* Inhibit speculative stores to volatile (e.g.DMA) or invalid addresses. */
+#include <asm/cacheops.h>
+#define R10KCBARRIER(addr)  cache   Cache_Barrier, addr;
+#else
+#define R10KCBARRIER(addr)
+#endif
+
 #endif /* __ASM_ASM_H */
-- 
1.4.4.4

^ permalink raw reply related

* [PATCH] Use real cache invalidate
From: Thomas Bogendoerfer @ 2007-11-26 22:40 UTC (permalink / raw)
  To: linux-mips; +Cc: ralf

R10k non coherent machines need a real dma cache invalidate to get
rid of speculative stores in cache.

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
---

diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 9355f1c..82d0d3e 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -598,7 +598,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
 		if (size >= scache_size)
 			r4k_blast_scache();
 		else
-			blast_scache_range(addr, addr + size);
+			blast_inv_scache_range(addr, addr + size);
 		return;
 	}
 
@@ -606,7 +606,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
 		r4k_blast_dcache();
 	} else {
 		R4600_HIT_CACHEOP_WAR_IMPL;
-		blast_dcache_range(addr, addr + size);
+		blast_inv_dcache_range(addr, addr + size);
 	}
 
 	bc_inv(addr, size);
diff --git a/include/asm-mips/r4kcache.h b/include/asm-mips/r4kcache.h
index 2b8466f..4c140db 100644
--- a/include/asm-mips/r4kcache.h
+++ b/include/asm-mips/r4kcache.h
@@ -403,6 +403,13 @@ __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
 __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
 __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
 
+__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16)
+__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32)
+__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16)
+__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32)
+__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64)
+__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128)
+
 /* build blast_xxx_range, protected_blast_xxx_range */
 #define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
 static inline void prot##blast_##pfx##cache##_range(unsigned long start, \

^ permalink raw reply related

* [PATCH] IP28 support
From: Thomas Bogendoerfer @ 2007-11-26 22:40 UTC (permalink / raw)
  To: linux-mips; +Cc: ralf

Add support for SGI IP28 machines (Indigo 2 with R10k CPUs)
This work is mainly based on Peter Fuersts work.

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
---

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 2f2ce0c..21649e4 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -421,6 +421,27 @@ config SGI_IP27
 	  workstations.  To compile a Linux kernel that runs on these, say Y
 	  here.
 
+config SGI_IP28
+	bool "SGI IP28 (Indigo2 R10k) (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	select ARC
+	select ARC64
+	select CEVT_R4K
+	select DMA_NONCOHERENT
+	select IRQ_CPU
+	select SWAP_IO_SPACE
+	select HW_HAS_EISA
+	select I8253
+	select I8259
+	select SYS_HAS_CPU_R10000
+	select SYS_HAS_EARLY_PRINTK
+	select BOOT_ELF64
+	select SYS_SUPPORTS_64BIT_KERNEL
+	select SYS_SUPPORTS_BIG_ENDIAN
+      help
+        This is the SGI Indigo2 with R10000 processor.  To compile a Linux
+        kernel that runs on these, say Y here.
+
 config SGI_IP32
 	bool "SGI IP32 (O2)"
 	select ARC
@@ -932,7 +953,7 @@ config BOOT_ELF32
 config MIPS_L1_CACHE_SHIFT
 	int
 	default "4" if MACH_DECSTATION
-	default "7" if SGI_IP27 || SNI_RM
+	default "7" if SGI_IP27 || SGI_IP28 || SNI_RM
 	default "4" if PMC_MSP4200_EVAL
 	default "5"
 
@@ -941,7 +962,7 @@ config HAVE_STD_PC_SERIAL_PORT
 
 config ARC_CONSOLE
 	bool "ARC console support"
-	depends on SGI_IP22 || (SNI_RM && CPU_LITTLE_ENDIAN)
+	depends on SGI_IP22 || SGI_IP28 || (SNI_RM && CPU_LITTLE_ENDIAN)
 
 config ARC_MEMORY
 	bool
@@ -950,7 +971,7 @@ config ARC_MEMORY
 
 config ARC_PROMLIB
 	bool
-	depends on MACH_JAZZ || SNI_RM || SGI_IP22 || SGI_IP32
+	depends on MACH_JAZZ || SNI_RM || SGI_IP22 || SGI_IP28 || SGI_IP32
 	default y
 
 config ARC64
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index a1f8d8b..d91fbca 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -475,6 +475,20 @@ endif
 endif
 
 #
+# SGI IP28 (Indigo2 R10k)
+#
+# Set the load address to >= 0xa800000020080000 if you want to leave space for
+# symmon, 0xa800000020004000 for production kernels ?  Note that the value must
+# be 16kb aligned or the handling of the current variable will break.
+# Simplified: what IP22 does at 128MB+ in ksegN, IP28 does at 512MB+ in xkphys
+#
+#core-$(CONFIG_SGI_IP28)		+= arch/mips/sgi-ip22/ arch/mips/arc/arc_con.o
+core-$(CONFIG_SGI_IP28)		+= arch/mips/sgi-ip22/
+cflags-$(CONFIG_SGI_IP28)	+= -mr10k-cache-barrier=1 -Iinclude/asm-mips/mach-ip28
+#cflags-$(CONFIG_SGI_IP28)	+= -Iinclude/asm-mips/mach-ip28
+load-$(CONFIG_SGI_IP28)		+= 0xa800000020004000
+
+#
 # SGI-IP32 (O2)
 #
 # Set the load address to >= 80069000 if you want to leave space for symmon,
diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
index e3acb51..ef1564e 100644
--- a/arch/mips/sgi-ip22/Makefile
+++ b/arch/mips/sgi-ip22/Makefile
@@ -3,9 +3,11 @@
 # under Linux.
 #
 
-obj-y	+= ip22-mc.o ip22-hpc.o ip22-int.o ip22-berr.o \
-	   ip22-time.o ip22-nvram.o ip22-platform.o ip22-reset.o ip22-setup.o
+obj-y	+= ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \
+	   ip22-platform.o ip22-reset.o ip22-setup.o
 
+obj-$(CONFIG_SGI_IP22) += ip22-berr.o
+obj-$(CONFIG_SGI_IP28) += ip28-berr.o
 obj-$(CONFIG_EISA)	+= ip22-eisa.o
 
-EXTRA_CFLAGS += -Werror
+# EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c
index 01a805d..3f35d63 100644
--- a/arch/mips/sgi-ip22/ip22-mc.c
+++ b/arch/mips/sgi-ip22/ip22-mc.c
@@ -4,6 +4,7 @@
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes
  * Copyright (C) 2003 Ladislav Michl  (ladis@linux-mips.org)
+ * Copyright (C) 2004 Peter Fuerst    (pf@net.alphadv.de) - IP28
  */
 
 #include <linux/init.h>
@@ -137,9 +138,12 @@ void __init sgimc_init(void)
 	/* Step 2: Enable all parity checking in cpu control register
 	 *         zero.
 	 */
+	/* don't touch parity settings for IP28 */
+#ifndef CONFIG_SGI_IP28
 	tmp = sgimc->cpuctrl0;
 	tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM |
 		SGIMC_CCTRL0_R4KNOCHKPARR);
+#endif
 	sgimc->cpuctrl0 = tmp;
 
 	/* Step 3: Setup the MC write buffer depth, this is controlled
diff --git a/arch/mips/sgi-ip22/ip28-berr.c b/arch/mips/sgi-ip22/ip28-berr.c
new file mode 100644
index 0000000..e61e8f3
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip28-berr.c
@@ -0,0 +1,704 @@
+/*
+ * ip28-berr.c: Bus error handling.
+ *
+ * Copyright (C) 2002, 2003 Ladislav Michl (ladis@linux-mips.org)
+ * Copyright (C) 2005 Peter Fuerst (pf@net.alphadv.de) - IP28
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+
+#include <asm/addrspace.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/branch.h>
+#include <asm/irq_regs.h>
+#include <asm/sgi/mc.h>
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/ioc.h>
+#include <asm/sgi/ip22.h>
+#include <asm/r4kcache.h>
+#include <asm/uaccess.h>
+#include <asm/bootinfo.h>
+
+static unsigned int count_be_is_fixup;
+static unsigned int count_be_handler;
+static unsigned int count_be_interrupt;
+static int debug_be_interrupt;
+
+static unsigned int cpu_err_stat;	/* Status reg for CPU */
+static unsigned int gio_err_stat;	/* Status reg for GIO */
+static unsigned int cpu_err_addr;	/* Error address reg for CPU */
+static unsigned int gio_err_addr;	/* Error address reg for GIO */
+static unsigned int extio_stat;
+static unsigned int hpc3_berr_stat;	/* Bus error interrupt status */
+
+struct hpc3_stat {
+	unsigned long addr;
+	unsigned int ctrl;
+	unsigned int cbp;
+	unsigned int ndptr;
+};
+
+static struct {
+	struct hpc3_stat pbdma[8];
+	struct hpc3_stat scsi[2];
+	struct hpc3_stat ethrx, ethtx;
+} hpc3;
+
+static struct {
+	unsigned long err_addr;
+	struct {
+		u32 lo;
+		u32 hi;
+	} tags[1][2], tagd[4][2], tagi[4][2]; /* Way 0/1 */
+} cache_tags;
+
+static inline void save_cache_tags(unsigned busaddr)
+{
+	unsigned long addr = CAC_BASE | busaddr;
+	int i;
+	cache_tags.err_addr = addr;
+
+	/*
+	 * Starting with a bus-address, save secondary cache (indexed by
+	 * PA[23..18:7..6]) tags first.
+	 */
+	addr &= ~1L;
+#define tag cache_tags.tags[0]
+	cache_op(Index_Load_Tag_S, addr);
+	tag[0].lo = read_c0_taglo();	/* PA[35:18], VA[13:12] */
+	tag[0].hi = read_c0_taghi();	/* PA[39:36] */
+	cache_op(Index_Load_Tag_S, addr | 1L);
+	tag[1].lo = read_c0_taglo();	/* PA[35:18], VA[13:12] */
+	tag[1].hi = read_c0_taghi();	/* PA[39:36] */
+#undef tag
+
+	/*
+	 * Save all primary data cache (indexed by VA[13:5]) tags which
+	 * might fit to this bus-address, knowing that VA[11:0] == PA[11:0].
+	 * Saving all tags and evaluating them later is easier and safer
+	 * than relying on VA[13:12] from the secondary cache tags to pick
+	 * matching primary tags here already.
+	 */
+	addr &= (0xffL << 56) | ((1 << 12) - 1);
+#define tag cache_tags.tagd[i]
+	for (i = 0; i < 4; ++i, addr += (1 << 12)) {
+		cache_op(Index_Load_Tag_D, addr);
+		tag[0].lo = read_c0_taglo();	/* PA[35:12] */
+		tag[0].hi = read_c0_taghi();	/* PA[39:36] */
+		cache_op(Index_Load_Tag_D, addr | 1L);
+		tag[1].lo = read_c0_taglo();	/* PA[35:12] */
+		tag[1].hi = read_c0_taghi();	/* PA[39:36] */
+	}
+#undef tag
+
+	/*
+	 * Save primary instruction cache (indexed by VA[13:6]) tags
+	 * the same way.
+	 */
+	addr &= (0xffL << 56) | ((1 << 12) - 1);
+#define tag cache_tags.tagi[i]
+	for (i = 0; i < 4; ++i, addr += (1 << 12)) {
+		cache_op(Index_Load_Tag_I, addr);
+		tag[0].lo = read_c0_taglo();	/* PA[35:12] */
+		tag[0].hi = read_c0_taghi();	/* PA[39:36] */
+		cache_op(Index_Load_Tag_I, addr | 1L);
+		tag[1].lo = read_c0_taglo();	/* PA[35:12] */
+		tag[1].hi = read_c0_taghi();	/* PA[39:36] */
+	}
+#undef tag
+}
+
+#define GIO_ERRMASK	0xff00
+#define CPU_ERRMASK	0x3f00
+
+static void save_and_clear_buserr(void)
+{
+	int i;
+
+	/* save status registers */
+	cpu_err_addr = sgimc->cerr;
+	cpu_err_stat = sgimc->cstat;
+	gio_err_addr = sgimc->gerr;
+	gio_err_stat = sgimc->gstat;
+	extio_stat = sgioc->extio;
+	hpc3_berr_stat = hpc3c0->bestat;
+
+	hpc3.scsi[0].addr  = (unsigned long)&hpc3c0->scsi_chan0;
+	hpc3.scsi[0].ctrl  = hpc3c0->scsi_chan0.ctrl; /* HPC3_SCTRL_ACTIVE ? */
+	hpc3.scsi[0].cbp   = hpc3c0->scsi_chan0.cbptr;
+	hpc3.scsi[0].ndptr = hpc3c0->scsi_chan0.ndptr;
+
+	hpc3.scsi[1].addr  = (unsigned long)&hpc3c0->scsi_chan1;
+	hpc3.scsi[1].ctrl  = hpc3c0->scsi_chan1.ctrl; /* HPC3_SCTRL_ACTIVE ? */
+	hpc3.scsi[1].cbp   = hpc3c0->scsi_chan1.cbptr;
+	hpc3.scsi[1].ndptr = hpc3c0->scsi_chan1.ndptr;
+
+	hpc3.ethrx.addr  = (unsigned long)&hpc3c0->ethregs.rx_cbptr;
+	hpc3.ethrx.ctrl  = hpc3c0->ethregs.rx_ctrl; /* HPC3_ERXCTRL_ACTIVE ? */
+	hpc3.ethrx.cbp   = hpc3c0->ethregs.rx_cbptr;
+	hpc3.ethrx.ndptr = hpc3c0->ethregs.rx_ndptr;
+
+	hpc3.ethtx.addr  = (unsigned long)&hpc3c0->ethregs.tx_cbptr;
+	hpc3.ethtx.ctrl  = hpc3c0->ethregs.tx_ctrl; /* HPC3_ETXCTRL_ACTIVE ? */
+	hpc3.ethtx.cbp   = hpc3c0->ethregs.tx_cbptr;
+	hpc3.ethtx.ndptr = hpc3c0->ethregs.tx_ndptr;
+
+	for (i = 0; i < 8; ++i) {
+		/* HPC3_PDMACTRL_ISACT ? */
+		hpc3.pbdma[i].addr  = (unsigned long)&hpc3c0->pbdma[i];
+		hpc3.pbdma[i].ctrl  = hpc3c0->pbdma[i].pbdma_ctrl;
+		hpc3.pbdma[i].cbp   = hpc3c0->pbdma[i].pbdma_bptr;
+		hpc3.pbdma[i].ndptr = hpc3c0->pbdma[i].pbdma_dptr;
+	}
+	i = 0;
+	if (gio_err_stat & CPU_ERRMASK)
+		i = gio_err_addr;
+	if (cpu_err_stat & CPU_ERRMASK)
+		i = cpu_err_addr;
+	save_cache_tags(i);
+
+	sgimc->cstat = sgimc->gstat = 0;
+}
+
+static void print_cache_tags(void)
+{
+	u32 scb, scw;
+	int i;
+
+	printk(KERN_ERR "Cache tags @ %08x:\n", (unsigned)cache_tags.err_addr);
+
+	/* PA[31:12] shifted to PTag0 (PA[35:12]) format */
+	scw = (cache_tags.err_addr >> 4) & 0x0fffff00;
+
+	scb = cache_tags.err_addr & ((1 << 12) - 1) & ~((1 << 5) - 1);
+	for (i = 0; i < 4; ++i) { /* for each possible VA[13:12] value */
+		if ((cache_tags.tagd[i][0].lo & 0x0fffff00) != scw &&
+		    (cache_tags.tagd[i][1].lo & 0x0fffff00) != scw)
+		    continue;
+		printk(KERN_ERR
+		       "D: 0: %08x %08x, 1: %08x %08x  (VA[13:5]  %04x)\n",
+			cache_tags.tagd[i][0].hi, cache_tags.tagd[i][0].lo,
+			cache_tags.tagd[i][1].hi, cache_tags.tagd[i][1].lo,
+			scb | (1 << 12)*i);
+	}
+	scb = cache_tags.err_addr & ((1 << 12) - 1) & ~((1 << 6) - 1);
+	for (i = 0; i < 4; ++i) { /* for each possible VA[13:12] value */
+		if ((cache_tags.tagi[i][0].lo & 0x0fffff00) != scw &&
+		    (cache_tags.tagi[i][1].lo & 0x0fffff00) != scw)
+		    continue;
+		printk(KERN_ERR
+		       "I: 0: %08x %08x, 1: %08x %08x  (VA[13:6]  %04x)\n",
+			cache_tags.tagi[i][0].hi, cache_tags.tagi[i][0].lo,
+			cache_tags.tagi[i][1].hi, cache_tags.tagi[i][1].lo,
+			scb | (1 << 12)*i);
+	}
+	i = read_c0_config();
+	scb = i & (1 << 13) ? 7:6;      /* scblksize = 2^[7..6] */
+	scw = ((i >> 16) & 7) + 19 - 1; /* scwaysize = 2^[24..19] / 2 */
+
+	i = ((1 << scw) - 1) & ~((1 << scb) - 1);
+	printk(KERN_ERR "S: 0: %08x %08x, 1: %08x %08x  (PA[%u:%u] %05x)\n",
+		cache_tags.tags[0][0].hi, cache_tags.tags[0][0].lo,
+		cache_tags.tags[0][1].hi, cache_tags.tags[0][1].lo,
+		scw-1, scb, i & (unsigned)cache_tags.err_addr);
+}
+
+static inline const char *cause_excode_text(int cause)
+{
+	static const char *txt[32] =
+	{	"Interrupt",
+		"TLB modification",
+		"TLB (load or instruction fetch)",
+		"TLB (store)",
+		"Address error (load or instruction fetch)",
+		"Address error (store)",
+		"Bus error (instruction fetch)",
+		"Bus error (data: load or store)",
+		"Syscall",
+		"Breakpoint",
+		"Reserved instruction",
+		"Coprocessor unusable",
+		"Arithmetic Overflow",
+		"Trap",
+		"14",
+		"Floating-Point",
+		"16", "17", "18", "19", "20", "21", "22",
+		"Watch Hi/Lo",
+		"24", "25", "26", "27", "28", "29", "30", "31",
+	};
+	return txt[(cause & 0x7c) >> 2];
+}
+
+static void print_buserr(const struct pt_regs *regs)
+{
+	const int field = 2 * sizeof(unsigned long);
+	int error = 0;
+
+	if (extio_stat & EXTIO_MC_BUSERR) {
+		printk(KERN_ERR "MC Bus Error\n");
+		error |= 1;
+	}
+	if (extio_stat & EXTIO_HPC3_BUSERR) {
+		printk(KERN_ERR "HPC3 Bus Error 0x%x:<id=0x%x,%s,lane=0x%x>\n",
+			hpc3_berr_stat,
+			(hpc3_berr_stat & HPC3_BESTAT_PIDMASK) >>
+					  HPC3_BESTAT_PIDSHIFT,
+			(hpc3_berr_stat & HPC3_BESTAT_CTYPE) ? "PIO" : "DMA",
+			hpc3_berr_stat & HPC3_BESTAT_BLMASK);
+		error |= 2;
+	}
+	if (extio_stat & EXTIO_EISA_BUSERR) {
+		printk(KERN_ERR "EISA Bus Error\n");
+		error |= 4;
+	}
+	if (cpu_err_stat & CPU_ERRMASK) {
+		printk(KERN_ERR "CPU error 0x%x<%s%s%s%s%s%s> @ 0x%08x\n",
+			cpu_err_stat,
+			cpu_err_stat & SGIMC_CSTAT_RD ? "RD " : "",
+			cpu_err_stat & SGIMC_CSTAT_PAR ? "PAR " : "",
+			cpu_err_stat & SGIMC_CSTAT_ADDR ? "ADDR " : "",
+			cpu_err_stat & SGIMC_CSTAT_SYSAD_PAR ? "SYSAD " : "",
+			cpu_err_stat & SGIMC_CSTAT_SYSCMD_PAR ? "SYSCMD " : "",
+			cpu_err_stat & SGIMC_CSTAT_BAD_DATA ? "BAD_DATA " : "",
+			cpu_err_addr);
+		error |= 8;
+	}
+	if (gio_err_stat & GIO_ERRMASK) {
+		printk(KERN_ERR "GIO error 0x%x:<%s%s%s%s%s%s%s%s> @ 0x%08x\n",
+			gio_err_stat,
+			gio_err_stat & SGIMC_GSTAT_RD ? "RD " : "",
+			gio_err_stat & SGIMC_GSTAT_WR ? "WR " : "",
+			gio_err_stat & SGIMC_GSTAT_TIME ? "TIME " : "",
+			gio_err_stat & SGIMC_GSTAT_PROM ? "PROM " : "",
+			gio_err_stat & SGIMC_GSTAT_ADDR ? "ADDR " : "",
+			gio_err_stat & SGIMC_GSTAT_BC ? "BC " : "",
+			gio_err_stat & SGIMC_GSTAT_PIO_RD ? "PIO_RD " : "",
+			gio_err_stat & SGIMC_GSTAT_PIO_WR ? "PIO_WR " : "",
+			gio_err_addr);
+		error |= 16;
+	}
+	if (!error)
+		printk(KERN_ERR "MC: Hmm, didn't find any error condition.\n");
+	else {
+		printk(KERN_ERR "CP0: config %08x,  "
+			"MC: cpuctrl0/1: %08x/%05x, giopar: %04x\n"
+			"MC: cpu/gio_memacc: %08x/%05x, memcfg0/1: %08x/%08x\n",
+			read_c0_config(),
+			sgimc->cpuctrl0, sgimc->cpuctrl0, sgimc->giopar,
+			sgimc->cmacc, sgimc->gmacc,
+			sgimc->mconfig0, sgimc->mconfig1);
+		print_cache_tags();
+	}
+	printk(KERN_ALERT "%s, epc == %0*lx, ra == %0*lx\n",
+	       cause_excode_text(regs->cp0_cause),
+	       field, regs->cp0_epc, field, regs->regs[31]);
+}
+
+/*
+ * Try to find out, whether the bus error is caused by the instruction
+ * at EPC, otherwise we have an asynchronous error.
+ *
+ * Doc1: "MIPS IV Instruction Set", Rev 3.2 (SGI 007-2597-001)
+ * Doc2: "MIPS R10000 Microporcessor User's Manual", Ver 2.0 (SGI 007-2490-001)
+ * Doc3: "MIPS R4000 Microporcessor User's Manual", 2nd Ed. (SGI 007-2489-001)
+ */
+
+#define JMP_INDEX26_OP 1
+#define JMP_REGISTER_OP 2
+#define JMP_PCREL16_OP 3
+#define BASE_OFFSET_OP 4
+#define BASE_IDXREG_OP 5
+
+/* Match virtual address in an insn with physical error address */
+
+static int match_addr(unsigned paddr, unsigned long vaddr)
+{
+	unsigned long uaddr;
+
+	if ((vaddr & 0xffffffff80000000L) == 0xffffffff80000000L)
+		uaddr = (unsigned) CPHYSADDR(vaddr);
+	else if ((vaddr >> 62) == 2)
+		uaddr = (unsigned) XPHYSADDR(vaddr);
+	else {
+		unsigned long eh = vaddr & ~0x1fffL;
+
+		eh |= read_c0_entryhi() & 0xff;
+		write_c0_entryhi(eh);
+		tlb_probe();
+		if (read_c0_index() & 0x80000000)
+			return 0;
+		tlb_read();
+		if (vaddr & (1L << PAGE_SHIFT))
+			uaddr = (unsigned) read_c0_entrylo1();
+		else
+			uaddr = (unsigned) read_c0_entrylo0();
+		uaddr <<= 6;
+		uaddr &= ~PAGE_MASK;
+		uaddr |= vaddr & PAGE_MASK;
+	}
+	return ((uaddr & ~0x7f) == (paddr & ~0x7f));
+}
+
+/* Check, which kind of memory reference is triggered by `insn' */
+
+static int check_special(unsigned insn)
+{
+	/* See Doc1, page A-180 */
+	unsigned func = insn & 0x3f;
+
+	if (8 == func || 8+1 == func) /* JR, JALR */
+		return JMP_REGISTER_OP;
+
+	return 0;
+}
+
+static int check_regimm(unsigned insn)
+{
+	/* See Doc1, page A-180 */
+	unsigned rt = (insn >> 19) & 3; /* bits 20..19[..16] */
+
+	/* BLTZ, BGEZ, BLTZL, BBGEZL || BLTZAL, BGEZAL, BLTZALL, BBGEZALL */
+	if (!rt || 2 == rt)
+		return JMP_PCREL16_OP;
+
+	return 0;
+}
+
+static int check_cop0(unsigned insn)
+{
+	/* See Doc2, pages 287 ff., 187 ff. */
+	if ((insn >> 26) == 5*8+7) /* CACHE */
+		switch ((insn >> 16) & 0x1f) {
+		case Index_Writeback_Inv_D:
+		case Hit_Writeback_Inv_D:
+		case Index_Writeback_Inv_S:
+		case Hit_Writeback_Inv_S:
+			return BASE_OFFSET_OP;
+		}
+	return 0;
+}
+
+static int check_cop1(unsigned insn)
+{
+	/* See Doc1, pages B-108 ff. */
+	unsigned fmt = (insn >> 21) & 0x1f; /* bits 25..21 */
+
+	if (8 == fmt) /* BC1* */
+		return JMP_PCREL16_OP;
+
+	return 0;
+}
+
+static int check_cop1x(unsigned insn)
+{
+	/* See Doc1, pages B-108 ff. */
+	switch (insn & 0x3f) {
+	case 0:   /* LWXC1 */
+	case 1:   /* LDXC1 */
+	case 8:   /* SWXC1 */
+	case 8+1: /* SDXC1 */
+		return BASE_IDXREG_OP;
+	}
+	return 0;
+}
+
+static int check_plain(unsigned insn)
+{
+	/* See Doc1, page A-180 */
+	unsigned opcode = insn >> 26;
+
+	if (2 == opcode || 3 == opcode) /* J, JAL */
+		return JMP_INDEX26_OP;
+
+	if ((4     <= opcode && opcode <= 7) ||   /* BEQ, BNE, BLEZ, BGTZ */
+	    (4+2*8 <= opcode && opcode <= 7+2*8)) /* BEQL, BNEL, BLEZL, BGTZL */
+		return JMP_PCREL16_OP;
+
+	if (6*8+3 == opcode) /* PREF */
+		return 0;
+
+	if (3*8+2 == opcode || 3*8+3 == opcode || /* LDL, LDR */
+	    4*8 <= opcode) /* misc. LOAD, STORE */
+		return BASE_OFFSET_OP;
+
+	return 0;
+}
+
+/* Check, whether the insn at EPC causes a memory access at `paddr' */
+
+static int check_addr_in_insn(unsigned paddr, const struct pt_regs *regs)
+{
+	unsigned long epc;
+	unsigned insn;
+	unsigned long a;
+	int typ;
+
+	epc = regs->cp0_cause & CAUSEF_BD ? regs->cp0_epc:regs->cp0_epc+4;
+
+	/* show_code() from kernel/traps.c */
+	if (__get_user(insn, (u32 *)epc))
+		return 1;
+
+	/* See Doc1, pages A-180, B-108 ff. */
+	switch (insn >> 26) {
+	case 0:
+		typ = check_special(insn);
+		break;
+	case 1:
+		typ = check_regimm(insn);
+		break;
+	case 2*8:   /* COP0 */
+	case 5*8+7: /* CACHE */
+		typ = check_cop0(insn);
+		break;
+	case 2*8+1:
+		typ = check_cop1(insn);
+		break;
+	case 2*8+3:
+		typ = check_cop1x(insn);
+		break;
+	default:
+		typ = check_plain(insn);
+		break;
+	}
+	switch (typ) {
+	case JMP_INDEX26_OP:
+		a = (regs->cp0_epc + 4) & ~0xfffffff;
+		a |= (insn & 0x3ffffff) << 2;
+		return match_addr(paddr, a);
+	case JMP_REGISTER_OP:
+		a = regs->regs[(insn >> 21) & 0x1f];
+		return match_addr(paddr, a);
+	case JMP_PCREL16_OP:
+		a = regs->cp0_epc + 4 + ((insn & 0xffff) << 2);
+		return match_addr(paddr, a);
+	case BASE_OFFSET_OP:
+		a = regs->regs[(insn >> 21) & 0x1f] + (insn & 0xffff);
+		return match_addr(paddr, a);
+	case BASE_IDXREG_OP:
+		a = regs->regs[(insn >> 21) & 0x1f];
+		a += regs->regs[(insn >> 16) & 0x1f];
+		return match_addr(paddr, a);
+	case 0:
+		return 0;
+	}
+	/* Assume it would be too dangerous to continue ... */
+	return 1;
+}
+
+/*
+ * Check, whether MC's (virtual) DMA address caused the bus error.
+ * See "Virtual DMA Specification", Draft 1.5, Feb 13 1992, SGI
+ */
+
+static int addr_is_ram(unsigned long addr, unsigned sz)
+{
+	int i;
+
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		unsigned long a = boot_mem_map.map[i].addr;
+		if (a <= addr && addr+sz <= a+boot_mem_map.map[i].size)
+			return 1;
+	}
+	return 0;
+}
+
+static int check_microtlb(u32 hi, u32 lo, unsigned long vaddr)
+{
+	/* This is likely rather similar to correct code ;-) */
+
+	vaddr &= 0x7fffffff; /* Doc. states that top bit is ignored */
+
+	/* If tlb-entry is valid and VPN-high (bits [30:21] ?) matches... */
+	if ((lo & 2) && (vaddr >> 21) == ((hi<<1) >> 22)) {
+		u32 ctl = sgimc->dma_ctrl;
+		if (ctl & 1) {
+			unsigned int pgsz = (ctl & 2) ? 14:12; /* 16k:4k */
+			/* PTEIndex is VPN-low (bits [22:14]/[20:12] ?) */
+			unsigned long pte = (lo >> 6) << 12; /* PTEBase */
+			pte += 8*((vaddr >> pgsz) & 0x1ff);
+			if (addr_is_ram(pte, 8)) {
+				/*
+				 * Note: Since DMA hardware does look up
+				 * translation on its own, this PTE *must*
+				 * match the TLB/EntryLo-register format !
+				 */
+				unsigned long a = *(unsigned long *)
+						PHYS_TO_XKSEG_UNCACHED(pte);
+				a = (a & 0x3f) << 6; /* PFN */
+				a += vaddr & ((1 << pgsz) - 1);
+				return (cpu_err_addr == a);
+			}
+		}
+	}
+	return 0;
+}
+
+static int check_vdma_memaddr(void)
+{
+	if (cpu_err_stat & CPU_ERRMASK) {
+		u32 a = sgimc->maddronly;
+
+		if (!(sgimc->dma_ctrl & 0x100)) /* Xlate-bit clear ? */
+			return (cpu_err_addr == a);
+
+		if (check_microtlb(sgimc->dtlb_hi0, sgimc->dtlb_lo0, a) ||
+		    check_microtlb(sgimc->dtlb_hi1, sgimc->dtlb_lo1, a) ||
+		    check_microtlb(sgimc->dtlb_hi2, sgimc->dtlb_lo2, a) ||
+		    check_microtlb(sgimc->dtlb_hi3, sgimc->dtlb_lo3, a))
+			return 1;
+	}
+	return 0;
+}
+
+static int check_vdma_gioaddr(void)
+{
+	if (gio_err_stat & GIO_ERRMASK) {
+		u32 a = sgimc->gio_dma_trans;
+		a = (sgimc->gmaddronly & ~a) | (sgimc->gio_dma_sbits & a);
+		return (gio_err_addr == a);
+	}
+	return 0;
+}
+
+/*
+ * MC sends an interrupt whenever bus or parity errors occur. In addition,
+ * if the error happened during a CPU read, it also asserts the bus error
+ * pin on the R4K. Code in bus error handler save the MC bus error registers
+ * and then clear the interrupt when this happens.
+ */
+
+static int ip28_be_interrupt(const struct pt_regs *regs)
+{
+	int i;
+
+	save_and_clear_buserr();
+	/*
+	 * Try to find out, whether we got here by a mispredicted speculative
+	 * load/store operation.  If so, it's not fatal, we can go on.
+	 */
+	/* Any cause other than "Interrupt" (ExcCode 0) is fatal. */
+	if (regs->cp0_cause & CAUSEF_EXCCODE)
+		goto mips_be_fatal;
+
+	/* Any cause other than "Bus error interrupt" (IP6) is weird. */
+	if ((regs->cp0_cause & CAUSEF_IP6) != CAUSEF_IP6)
+		goto mips_be_fatal;
+
+	if (extio_stat & (EXTIO_HPC3_BUSERR | EXTIO_EISA_BUSERR))
+		goto mips_be_fatal;
+
+	/* Any state other than "Memory bus error" is fatal. */
+	if (cpu_err_stat & CPU_ERRMASK & ~SGIMC_CSTAT_ADDR)
+			goto mips_be_fatal;
+
+	/* Any state other than "GIO transaction bus timed out" is fatal. */
+	if (gio_err_stat & GIO_ERRMASK & ~SGIMC_GSTAT_TIME)
+		goto mips_be_fatal;
+
+	/* Finding `cpu_err_addr' in the insn at EPC is fatal. */
+	if ((cpu_err_stat & CPU_ERRMASK) &&
+	     check_addr_in_insn(cpu_err_addr, regs))
+			goto mips_be_fatal;
+
+	/* Finding `gio_err_addr' in the insn at EPC is fatal. */
+	if ((gio_err_stat & GIO_ERRMASK) &&
+	     check_addr_in_insn(gio_err_addr, regs))
+		goto mips_be_fatal;
+	/*
+	 * Now we have an asynchronous bus error, speculatively or DMA caused.
+	 * Need to search all DMA descriptors for the error address.
+	 */
+	for (i = 0; i < sizeof(hpc3)/sizeof(struct hpc3_stat); ++i) {
+		struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i;
+		if ((cpu_err_stat & CPU_ERRMASK) &&
+		    (cpu_err_addr == hp->ndptr || cpu_err_addr == hp->cbp))
+			break;
+		if ((gio_err_stat & GIO_ERRMASK) &&
+		    (gio_err_addr == hp->ndptr || gio_err_addr == hp->cbp))
+			break;
+	}
+	if (i < sizeof(hpc3)/sizeof(struct hpc3_stat)) {
+		struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i;
+		printk(KERN_ERR "at DMA addresses: HPC3 @ %08lx:"
+		       " ctl %08x, ndp %08x, cbp %08x\n",
+		       CPHYSADDR(hp->addr), hp->ctrl, hp->ndptr, hp->cbp);
+		goto mips_be_fatal;
+	}
+	/* Check MC's virtual DMA stuff. */
+	if (check_vdma_memaddr()) {
+		printk(KERN_ERR "at GIO DMA: mem address 0x%08x.\n",
+			sgimc->maddronly);
+		goto mips_be_fatal;
+	}
+	if (check_vdma_gioaddr()) {
+		printk(KERN_ERR "at GIO DMA: gio address 0x%08x.\n",
+			sgimc->gmaddronly);
+		goto mips_be_fatal;
+	}
+	/* A speculative bus error... */
+	if (debug_be_interrupt) {
+		print_buserr(regs);
+		printk(KERN_ERR "discarded!\n");
+	}
+	return MIPS_BE_DISCARD;
+
+mips_be_fatal:
+	print_buserr(regs);
+	return MIPS_BE_FATAL;
+}
+
+void ip22_be_interrupt(int irq)
+{
+	const struct pt_regs *regs = get_irq_regs();
+
+	count_be_interrupt++;
+
+	if (ip28_be_interrupt(regs) != MIPS_BE_DISCARD) {
+		/* Assume it would be too dangerous to continue ... */
+		die_if_kernel("Oops", regs);
+		force_sig(SIGBUS, current);
+	} else if (debug_be_interrupt)
+		show_regs((struct pt_regs *)regs);
+}
+
+static int ip28_be_handler(struct pt_regs *regs, int is_fixup)
+{
+	/*
+	 * We arrive here only in the unusual case of do_be() invocation,
+	 * i.e. by a bus error exception without a bus error interrupt.
+	 */
+	if (is_fixup) {
+		count_be_is_fixup++;
+		save_and_clear_buserr();
+		return MIPS_BE_FIXUP;
+	}
+	count_be_handler++;
+	return ip28_be_interrupt(regs);
+}
+
+void __init ip22_be_init(void)
+{
+	board_be_handler = ip28_be_handler;
+}
+
+int ip28_show_be_info(struct seq_file *m)
+{
+	seq_printf(m, "IP28 be fixups\t\t: %u\n", count_be_is_fixup);
+	seq_printf(m, "IP28 be interrupts\t: %u\n", count_be_interrupt);
+	seq_printf(m, "IP28 be handler\t\t: %u\n", count_be_handler);
+
+	return 0;
+}
+
+static int __init debug_be_setup(char *str)
+{
+	debug_be_interrupt++;
+	return 1;
+}
+__setup("ip28_debug_be", debug_be_setup);
+
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index bf18d75..aa12e26 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -777,7 +777,7 @@ config JS_RTC
 
 config SGI_DS1286
 	tristate "SGI DS1286 RTC support"
-	depends on SGI_IP22
+	depends on (SGI_IP22 || SGI_IP28)
 	help
 	  If you say Y here and create a character special file /dev/rtc with
 	  major number 10 and minor number 135 using mknod ("man mknod"), you
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
index dd22d91..08a5f20 100644
--- a/drivers/input/serio/i8042.h
+++ b/drivers/input/serio/i8042.h
@@ -16,7 +16,7 @@
 
 #if defined(CONFIG_MACH_JAZZ)
 #include "i8042-jazzio.h"
-#elif defined(CONFIG_SGI_IP22)
+#elif defined(CONFIG_SGI_IP22) || defined(CONFIG_SGI_IP28)
 #include "i8042-ip22io.h"
 #elif defined(CONFIG_PPC)
 #include "i8042-ppcio.h"
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 7a55bc1..816d20f 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1795,7 +1795,7 @@ config DE620
 
 config SGISEEQ
 	tristate "SGI Seeq ethernet controller support"
-	depends on SGI_IP22
+	depends on SGI_IP22 || SGI_IP28
 	help
 	  Say Y here if you have an Seeq based Ethernet network card. This is
 	  used in many Silicon Graphics machines.
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index a6676be..e422484 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -345,7 +345,7 @@ config ISCSI_TCP
 
 config SGIWD93_SCSI
 	tristate "SGI WD93C93 SCSI Driver"
-	depends on SGI_IP22 && SCSI
+	depends on (SGI_IP22 || SGI_IP26 || SGI_IP28) && SCSI
   	help
 	  If you have a Western Digital WD93 SCSI controller on
 	  an SGI MIPS system, say Y.  Otherwise, say N.
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index ed438bc..ab59185 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -878,16 +878,18 @@ config SERIAL_SUNHV
 
 config SERIAL_IP22_ZILOG
 	tristate "IP22 Zilog8530 serial support"
-	depends on SGI_IP22
+	depends on (SGI_IP22 || SGI_IP28)
 	select SERIAL_CORE
+	default y if SGI_IP28
 	help
-	  This driver supports the Zilog8530 serial ports found on SGI IP22
+	This driver supports the Zilog8530 serial ports found on SGI IP22-IP28
 	  systems.  Say Y or M if you want to be able to these serial ports.
 
 config SERIAL_IP22_ZILOG_CONSOLE
-	bool "Console on IP22 Zilog8530 serial port"
+	bool "Console on IP22/IP28 Zilog8530 serial port"
 	depends on SERIAL_IP22_ZILOG=y
 	select SERIAL_CORE_CONSOLE
+	default y if SGI_IP28
 
 config V850E_UART
 	bool "NEC V850E on-chip UART support"
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 2792bc1..9170501 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -586,7 +586,7 @@ config SBC_EPX_C3_WATCHDOG
 
 config INDYDOG
 	tristate "Indy/I2 Hardware Watchdog"
-	depends on SGI_IP22
+	depends on SGI_IP22 || SGI_IP28
 	help
 	  Hardware driver for the Indy's/I2's watchdog. This is a
 	  watchdog timer that will reboot the machine after a 60 second
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
index a99acd8..4ee783b 100644
--- a/fs/partitions/Kconfig
+++ b/fs/partitions/Kconfig
@@ -198,7 +198,7 @@ config LDM_DEBUG
 
 config SGI_PARTITION
 	bool "SGI partition support" if PARTITION_ADVANCED
-	default y if (SGI_IP22 || SGI_IP27 || ((MACH_JAZZ || SNI_RM) && !CPU_LITTLE_ENDIAN))
+	default y if (SGI_IP22 || SGI_IP27 || SGI_IP28 || ((MACH_JAZZ || SNI_RM) && !CPU_LITTLE_ENDIAN))
 	help
 	  Say Y here if you would like to be able to read the hard disk
 	  partition table format used by SGI machines.
diff --git a/include/asm-mips/dma.h b/include/asm-mips/dma.h
index 833437d..80caf6b 100644
--- a/include/asm-mips/dma.h
+++ b/include/asm-mips/dma.h
@@ -88,6 +88,9 @@
 /* Horrible hack to have a correct DMA window on IP22 */
 #include <asm/sgi/mc.h>
 #define MAX_DMA_ADDRESS		(PAGE_OFFSET + SGIMC_SEG0_BADDR + 0x01000000)
+#elif defined(CONFIG_SGI_IP28)
+#include <asm/sgi/mc.h>
+#define MAX_DMA_ADDRESS		(PAGE_OFFSET + SGIMC_SEG1_BADDR + 0x01000000)
 #else
 #define MAX_DMA_ADDRESS		(PAGE_OFFSET + 0x01000000)
 #endif
diff --git a/include/asm-mips/mach-ip28/cpu-feature-overrides.h b/include/asm-mips/mach-ip28/cpu-feature-overrides.h
new file mode 100644
index 0000000..9a53b32
--- /dev/null
+++ b/include/asm-mips/mach-ip28/cpu-feature-overrides.h
@@ -0,0 +1,50 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Ralf Baechle
+ * 6/2004	pf
+ */
+#ifndef __ASM_MACH_IP28_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_IP28_CPU_FEATURE_OVERRIDES_H
+
+/*
+ * IP28 only comes with R10000 family processors all using the same config
+ */
+#define cpu_has_watch		1
+#define cpu_has_mips16		0
+#define cpu_has_divec		0
+#define cpu_has_vce		0
+#define cpu_has_cache_cdex_p	0
+#define cpu_has_cache_cdex_s	0
+#define cpu_has_prefetch	1
+#define cpu_has_mcheck		0
+#define cpu_has_ejtag		0
+
+#define cpu_has_llsc		1
+#define cpu_has_vtag_icache	0
+#define cpu_has_dc_aliases	0 /* see probe_pcache() */
+#define cpu_has_ic_fills_f_dc	0
+#define cpu_has_dsp		0
+#define cpu_icache_snoops_remote_store  1
+#define cpu_has_mipsmt		0
+#define cpu_has_userlocal	0
+
+#define cpu_has_nofpuex		0
+#define cpu_has_64bits		1
+
+#define cpu_has_4kex		1
+#define cpu_has_4k_cache	1
+
+#define cpu_has_inclusive_pcaches	1
+
+#define cpu_dcache_line_size()	32
+#define cpu_icache_line_size()	64
+
+#define cpu_has_mips32r1	0
+#define cpu_has_mips32r2	0
+#define cpu_has_mips64r1	0
+#define cpu_has_mips64r2	0
+
+#endif /* __ASM_MACH_IP28_CPU_FEATURE_OVERRIDES_H */
diff --git a/include/asm-mips/mach-ip28/ds1286.h b/include/asm-mips/mach-ip28/ds1286.h
new file mode 100644
index 0000000..471bb9a
--- /dev/null
+++ b/include/asm-mips/mach-ip28/ds1286.h
@@ -0,0 +1,4 @@
+#ifndef __ASM_MACH_IP28_DS1286_H
+#define __ASM_MACH_IP28_DS1286_H
+#include <asm/mach-ip22/ds1286.h>
+#endif /* __ASM_MACH_IP28_DS1286_H */
diff --git a/include/asm-mips/mach-ip28/spaces.h b/include/asm-mips/mach-ip28/spaces.h
new file mode 100644
index 0000000..05aabb2
--- /dev/null
+++ b/include/asm-mips/mach-ip28/spaces.h
@@ -0,0 +1,22 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994 - 1999, 2000, 03, 04 Ralf Baechle
+ * Copyright (C) 2000, 2002  Maciej W. Rozycki
+ * Copyright (C) 1990, 1999, 2000 Silicon Graphics, Inc.
+ * 2004	pf
+ */
+#ifndef _ASM_MACH_IP28_SPACES_H
+#define _ASM_MACH_IP28_SPACES_H
+
+#define CAC_BASE		0xa800000000000000
+
+#define HIGHMEM_START		(~0UL)
+
+#define PHYS_OFFSET		_AC(0x20000000, UL)
+
+#include <asm/mach-generic/spaces.h>
+
+#endif /* _ASM_MACH_IP28_SPACES_H */
diff --git a/include/asm-mips/mach-ip28/war.h b/include/asm-mips/mach-ip28/war.h
new file mode 100644
index 0000000..a1baafa
--- /dev/null
+++ b/include/asm-mips/mach-ip28/war.h
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_IP28_WAR_H
+#define __ASM_MIPS_MACH_IP28_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR	0
+#define R4600_V1_HIT_CACHEOP_WAR	0
+#define R4600_V2_HIT_CACHEOP_WAR	0
+#define R5432_CP0_INTERRUPT_WAR		0
+#define BCM1250_M3_WAR			0
+#define SIBYTE_1956_WAR			0
+#define MIPS4K_ICACHE_REFILL_WAR	0
+#define MIPS_CACHE_SYNC_WAR		0
+#define TX49XX_ICACHE_INDEX_INV_WAR	0
+#define RM9000_CDEX_SMP_WAR		0
+#define ICACHE_REFILLS_WORKAROUND_WAR	0
+#define R10000_LLSC_WAR			1
+#define MIPS34K_MISSED_ITLB_WAR		0
+
+#endif /* __ASM_MIPS_MACH_IP28_WAR_H */

^ permalink raw reply related

* [PATCH] SGISEEQ: use cached memory access to make driver work on IP28
From: Thomas Bogendoerfer @ 2007-11-24 12:29 UTC (permalink / raw)
  To: netdev, linux-mips; +Cc: ralf, jgarzik

Following patch is clearly 2.6.25 material and is needed to get SGI IP28
machines supported.

Thomas.

SGI IP28 machines would need special treatment (enable adding addtional
wait states) when accessing memory uncached. To avoid this pain I changed
the driver to use only cached access to memory.

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
---
 drivers/net/sgiseeq.c |  239 ++++++++++++++++++++++++++++++++++---------------
 1 files changed, 166 insertions(+), 73 deletions(-)

diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index ff40563..3145ca1 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
@@ -53,14 +52,35 @@ static char *sgiseeqstr = "SGI Seeq8003";
 			    sp->tx_old + (SEEQ_TX_BUFFERS - 1) - sp->tx_new : \
 			    sp->tx_old - sp->tx_new - 1)
 
+#define VIRT_TO_DMA(sp, v) ((sp)->srings_dma +                                 \
+				  (dma_addr_t)((unsigned long)(v) -            \
+					       (unsigned long)((sp)->rx_desc)))
+
+#define DMA_SYNC_DESC_CPU(dev, addr) \
+	do { dma_cache_sync((dev)->dev.parent, (void *)addr, \
+	     sizeof(struct sgiseeq_rx_desc), DMA_FROM_DEVICE); } while (0)
+
+#define DMA_SYNC_DESC_DEV(dev, addr) \
+	do { dma_cache_sync((dev)->dev.parent, (void *)addr, \
+	     sizeof(struct sgiseeq_rx_desc), DMA_TO_DEVICE); } while (0)
+
+/* Copy frames shorter than rx_copybreak, otherwise pass on up in
+ * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
+ */
+static int rx_copybreak = 100;
+
+#define PAD_SIZE    (128 - sizeof(struct hpc_dma_desc) - sizeof(void *))
+
 struct sgiseeq_rx_desc {
 	volatile struct hpc_dma_desc rdma;
-	volatile signed int buf_vaddr;
+	u8 padding[PAD_SIZE];
+	struct sk_buff *skb;
 };
 
 struct sgiseeq_tx_desc {
 	volatile struct hpc_dma_desc tdma;
-	volatile signed int buf_vaddr;
+	u8 padding[PAD_SIZE];
+	struct sk_buff *skb;
 };
 
 /*
@@ -163,35 +183,55 @@ static int seeq_init_ring(struct net_device *dev)
 
 	/* Setup tx ring. */
 	for(i = 0; i < SEEQ_TX_BUFFERS; i++) {
-		if (!sp->tx_desc[i].tdma.pbuf) {
-			unsigned long buffer;
-
-			buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
-			if (!buffer)
-				return -ENOMEM;
-			sp->tx_desc[i].buf_vaddr = CKSEG1ADDR(buffer);
-			sp->tx_desc[i].tdma.pbuf = CPHYSADDR(buffer);
-		}
 		sp->tx_desc[i].tdma.cntinfo = TCNTINFO_INIT;
+		DMA_SYNC_DESC_DEV(dev, &sp->tx_desc[i]);
 	}
 
 	/* And now the rx ring. */
 	for (i = 0; i < SEEQ_RX_BUFFERS; i++) {
 		if (!sp->rx_desc[i].rdma.pbuf) {
-			unsigned long buffer;
+			dma_addr_t dma_addr;
+			struct sk_buff *skb = netdev_alloc_skb(dev, PKT_BUF_SZ);
 
-			buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
-			if (!buffer)
+			if (skb == NULL)
 				return -ENOMEM;
-			sp->rx_desc[i].buf_vaddr = CKSEG1ADDR(buffer);
-			sp->rx_desc[i].rdma.pbuf = CPHYSADDR(buffer);
+			skb_reserve(skb, 2);
+			dma_addr = dma_map_single(dev->dev.parent,
+						  skb->data - 2,
+						  PKT_BUF_SZ, DMA_FROM_DEVICE);
+			sp->rx_desc[i].skb = skb;
+			sp->rx_desc[i].rdma.pbuf = dma_addr;
 		}
 		sp->rx_desc[i].rdma.cntinfo = RCNTINFO_INIT;
+		DMA_SYNC_DESC_DEV(dev, &sp->rx_desc[i]);
 	}
 	sp->rx_desc[i - 1].rdma.cntinfo |= HPCDMA_EOR;
+	DMA_SYNC_DESC_DEV(dev, &sp->rx_desc[i - 1]);
 	return 0;
 }
 
+static void seeq_purge_ring(struct net_device *dev)
+{
+	struct sgiseeq_private *sp = netdev_priv(dev);
+	int i;
+
+	/* clear tx ring. */
+	for (i = 0; i < SEEQ_TX_BUFFERS; i++) {
+		if (sp->tx_desc[i].skb) {
+			dev_kfree_skb(sp->tx_desc[i].skb);
+			sp->tx_desc[i].skb = NULL;
+		}
+	}
+
+	/* And now the rx ring. */
+	for (i = 0; i < SEEQ_RX_BUFFERS; i++) {
+		if (sp->rx_desc[i].skb) {
+			dev_kfree_skb(sp->rx_desc[i].skb);
+			sp->rx_desc[i].skb = NULL;
+		}
+	}
+}
+
 #ifdef DEBUG
 static struct sgiseeq_private *gpriv;
 static struct net_device *gdev;
@@ -258,8 +298,8 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
 		sregs->tstat = TSTAT_INIT_SEEQ;
 	}
 
-	hregs->rx_ndptr = CPHYSADDR(sp->rx_desc);
-	hregs->tx_ndptr = CPHYSADDR(sp->tx_desc);
+	hregs->rx_ndptr = VIRT_TO_DMA(sp, sp->rx_desc);
+	hregs->tx_ndptr = VIRT_TO_DMA(sp, sp->tx_desc);
 
 	seeq_go(sp, hregs, sregs);
 	return 0;
@@ -283,69 +323,90 @@ static inline void rx_maybe_restart(struct sgiseeq_private *sp,
 				    struct sgiseeq_regs *sregs)
 {
 	if (!(hregs->rx_ctrl & HPC3_ERXCTRL_ACTIVE)) {
-		hregs->rx_ndptr = CPHYSADDR(sp->rx_desc + sp->rx_new);
+		hregs->rx_ndptr = VIRT_TO_DMA(sp, sp->rx_desc + sp->rx_new);
 		seeq_go(sp, hregs, sregs);
 	}
 }
 
-#define for_each_rx(rd, sp) for((rd) = &(sp)->rx_desc[(sp)->rx_new]; \
-				!((rd)->rdma.cntinfo & HPCDMA_OWN); \
-				(rd) = &(sp)->rx_desc[(sp)->rx_new])
-
 static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp,
 			      struct hpc3_ethregs *hregs,
 			      struct sgiseeq_regs *sregs)
 {
 	struct sgiseeq_rx_desc *rd;
 	struct sk_buff *skb = NULL;
+	struct sk_buff *newskb;
 	unsigned char pkt_status;
-	unsigned char *pkt_pointer = NULL;
 	int len = 0;
 	unsigned int orig_end = PREV_RX(sp->rx_new);
 
 	/* Service every received packet. */
-	for_each_rx(rd, sp) {
+	rd = &sp->rx_desc[sp->rx_new];
+	DMA_SYNC_DESC_CPU(dev, rd);
+	while (!(rd->rdma.cntinfo & HPCDMA_OWN)) {
 		len = PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3;
-		pkt_pointer = (unsigned char *)(long)rd->buf_vaddr;
-		pkt_status = pkt_pointer[len + 2];
-
+		dma_unmap_single(dev->dev.parent, rd->rdma.pbuf,
+				 PKT_BUF_SZ, DMA_FROM_DEVICE);
+		pkt_status = rd->skb->data[len];
 		if (pkt_status & SEEQ_RSTAT_FIG) {
 			/* Packet is OK. */
-			skb = dev_alloc_skb(len + 2);
-
-			if (skb) {
-				skb_reserve(skb, 2);
-				skb_put(skb, len);
-
-				/* Copy out of kseg1 to avoid silly cache flush. */
-				skb_copy_to_linear_data(skb, pkt_pointer + 2, len);
-				skb->protocol = eth_type_trans(skb, dev);
-
-				/* We don't want to receive our own packets */
-				if (memcmp(eth_hdr(skb)->h_source, dev->dev_addr, ETH_ALEN)) {
+			/* We don't want to receive our own packets */
+			if (memcmp(rd->skb->data + 6, dev->dev_addr, ETH_ALEN)) {
+				if (len > rx_copybreak) {
+					skb = rd->skb;
+					newskb = netdev_alloc_skb(dev, PKT_BUF_SZ);
+					if (!newskb) {
+						newskb = skb;
+						skb = NULL;
+						goto memory_squeeze;
+					}
+					skb_reserve(newskb, 2);
+				} else {
+					skb = netdev_alloc_skb(dev, len + 2);
+					if (skb) {
+						skb_reserve(skb, 2);
+						skb_copy_to_linear_data(skb, rd->skb->data, len);
+					}
+					newskb = rd->skb;
+				}
+memory_squeeze:
+				if (skb) {
+					skb_put(skb, len);
+					skb->protocol = eth_type_trans(skb, dev);
 					netif_rx(skb);
 					dev->last_rx = jiffies;
 					dev->stats.rx_packets++;
 					dev->stats.rx_bytes += len;
 				} else {
-					/* Silently drop my own packets */
-					dev_kfree_skb_irq(skb);
+					printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
+						dev->name);
+					dev->stats.rx_dropped++;
 				}
 			} else {
-				printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
-					dev->name);
-				dev->stats.rx_dropped++;
+				/* Silently drop my own packets */
+				newskb = rd->skb;
 			}
 		} else {
 			record_rx_errors(dev, pkt_status);
+			newskb = rd->skb;
 		}
+		rd->skb = newskb;
+		rd->rdma.pbuf = dma_map_single(dev->dev.parent,
+					       newskb->data - 2,
+					       PKT_BUF_SZ, DMA_FROM_DEVICE);
 
 		/* Return the entry to the ring pool. */
 		rd->rdma.cntinfo = RCNTINFO_INIT;
 		sp->rx_new = NEXT_RX(sp->rx_new);
+		DMA_SYNC_DESC_DEV(dev, rd);
+		rd = &sp->rx_desc[sp->rx_new];
+		DMA_SYNC_DESC_CPU(dev, rd);
 	}
+	DMA_SYNC_DESC_CPU(dev, &sp->rx_desc[orig_end]);
 	sp->rx_desc[orig_end].rdma.cntinfo &= ~(HPCDMA_EOR);
+	DMA_SYNC_DESC_DEV(dev, &sp->rx_desc[orig_end]);
+	DMA_SYNC_DESC_CPU(dev, &sp->rx_desc[PREV_RX(sp->rx_new)]);
 	sp->rx_desc[PREV_RX(sp->rx_new)].rdma.cntinfo |= HPCDMA_EOR;
+	DMA_SYNC_DESC_DEV(dev, &sp->rx_desc[PREV_RX(sp->rx_new)]);
 	rx_maybe_restart(sp, hregs, sregs);
 }
 
@@ -358,20 +419,29 @@ static inline void tx_maybe_reset_collisions(struct sgiseeq_private *sp,
 	}
 }
 
-static inline void kick_tx(struct sgiseeq_tx_desc *td,
+static inline void kick_tx(struct net_device *dev,
+			   struct sgiseeq_private *sp,
 			   struct hpc3_ethregs *hregs)
 {
+	struct sgiseeq_tx_desc *td;
+	int i = sp->tx_old;
+
 	/* If the HPC aint doin nothin, and there are more packets
 	 * with ETXD cleared and XIU set we must make very certain
 	 * that we restart the HPC else we risk locking up the
 	 * adapter.  The following code is only safe iff the HPCDMA
 	 * is not active!
 	 */
+	td = &sp->tx_desc[i];
+	DMA_SYNC_DESC_CPU(dev, td);
 	while ((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) ==
-	      (HPCDMA_XIU | HPCDMA_ETXD))
-		td = (struct sgiseeq_tx_desc *)(long) CKSEG1ADDR(td->tdma.pnext);
+	      (HPCDMA_XIU | HPCDMA_ETXD)) {
+		i = NEXT_TX(i);
+		td = &sp->tx_desc[i];
+		DMA_SYNC_DESC_CPU(dev, td);
+	}
 	if (td->tdma.cntinfo & HPCDMA_XIU) {
-		hregs->tx_ndptr = CPHYSADDR(td);
+		hregs->tx_ndptr = VIRT_TO_DMA(sp, td);
 		hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
 	}
 }
@@ -400,11 +470,12 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp
 	for (j = sp->tx_old; j != sp->tx_new; j = NEXT_TX(j)) {
 		td = &sp->tx_desc[j];
 
+		DMA_SYNC_DESC_CPU(dev, td);
 		if (!(td->tdma.cntinfo & (HPCDMA_XIU)))
 			break;
 		if (!(td->tdma.cntinfo & (HPCDMA_ETXD))) {
 			if (!(status & HPC3_ETXCTRL_ACTIVE)) {
-				hregs->tx_ndptr = CPHYSADDR(td);
+				hregs->tx_ndptr = VIRT_TO_DMA(sp, td);
 				hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
 			}
 			break;
@@ -413,6 +484,11 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp
 		sp->tx_old = NEXT_TX(sp->tx_old);
 		td->tdma.cntinfo &= ~(HPCDMA_XIU | HPCDMA_XIE);
 		td->tdma.cntinfo |= HPCDMA_EOX;
+		if (td->skb) {
+			dev_kfree_skb_any(td->skb);
+			td->skb = NULL;
+		}
+		DMA_SYNC_DESC_DEV(dev, td);
 	}
 }
 
@@ -480,6 +556,7 @@ static int sgiseeq_close(struct net_device *dev)
 	/* Shutdown the Seeq. */
 	reset_hpc3_and_seeq(sp->hregs, sregs);
 	free_irq(irq, dev);
+	seeq_purge_ring(dev);
 
 	return 0;
 }
@@ -506,16 +583,22 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	struct hpc3_ethregs *hregs = sp->hregs;
 	unsigned long flags;
 	struct sgiseeq_tx_desc *td;
-	int skblen, len, entry;
+	int len, entry;
 
 	spin_lock_irqsave(&sp->tx_lock, flags);
 
 	/* Setup... */
-	skblen = skb->len;
-	len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+	len = skb->len;
+	if (len < ETH_ZLEN) {
+		if (skb_padto(skb, ETH_ZLEN))
+			return 0;
+		len = ETH_ZLEN;
+	}
+
 	dev->stats.tx_bytes += len;
 	entry = sp->tx_new;
 	td = &sp->tx_desc[entry];
+	DMA_SYNC_DESC_CPU(dev, td);
 
 	/* Create entry.  There are so many races with adding a new
 	 * descriptor to the chain:
@@ -530,25 +613,27 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	 *    entry and the HPC got to the end of the chain before we
 	 *    added this new entry and restarted it.
 	 */
-	skb_copy_from_linear_data(skb, (char *)(long)td->buf_vaddr, skblen);
-	if (len != skblen)
-		memset((char *)(long)td->buf_vaddr + skb->len, 0, len-skblen);
+	td->skb = skb;
+	td->tdma.pbuf = dma_map_single(dev->dev.parent, skb->data,
+				       len, DMA_TO_DEVICE);
 	td->tdma.cntinfo = (len & HPCDMA_BCNT) |
 	                   HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX;
+	DMA_SYNC_DESC_DEV(dev, td);
 	if (sp->tx_old != sp->tx_new) {
 		struct sgiseeq_tx_desc *backend;
 
 		backend = &sp->tx_desc[PREV_TX(sp->tx_new)];
+		DMA_SYNC_DESC_CPU(dev, backend);
 		backend->tdma.cntinfo &= ~HPCDMA_EOX;
+		DMA_SYNC_DESC_DEV(dev, backend);
 	}
 	sp->tx_new = NEXT_TX(sp->tx_new); /* Advance. */
 
 	/* Maybe kick the HPC back into motion. */
 	if (!(hregs->tx_ctrl & HPC3_ETXCTRL_ACTIVE))
-		kick_tx(&sp->tx_desc[sp->tx_old], hregs);
+		kick_tx(dev, sp, hregs);
 
 	dev->trans_start = jiffies;
-	dev_kfree_skb(skb);
 
 	if (!TX_BUFFS_AVAIL(sp))
 		netif_stop_queue(dev);
@@ -586,33 +671,41 @@ static void sgiseeq_set_multicast(struct net_device *dev)
 		sgiseeq_reset(dev);
 }
 
-static inline void setup_tx_ring(struct sgiseeq_tx_desc *buf, int nbufs)
+static inline void setup_tx_ring(struct net_device *dev,
+				 struct sgiseeq_tx_desc *buf,
+				 int nbufs)
 {
+	struct sgiseeq_private *sp = netdev_priv(dev);
 	int i = 0;
 
 	while (i < (nbufs - 1)) {
-		buf[i].tdma.pnext = CPHYSADDR(buf + i + 1);
+		buf[i].tdma.pnext = VIRT_TO_DMA(sp, buf + i + 1);
 		buf[i].tdma.pbuf = 0;
+		DMA_SYNC_DESC_DEV(dev, &buf[i]);
 		i++;
 	}
-	buf[i].tdma.pnext = CPHYSADDR(buf);
+	buf[i].tdma.pnext = VIRT_TO_DMA(sp, buf);
+	DMA_SYNC_DESC_DEV(dev, &buf[i]);
 }
 
-static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs)
+static inline void setup_rx_ring(struct net_device *dev,
+				 struct sgiseeq_rx_desc *buf,
+				 int nbufs)
 {
+	struct sgiseeq_private *sp = netdev_priv(dev);
 	int i = 0;
 
 	while (i < (nbufs - 1)) {
-		buf[i].rdma.pnext = CPHYSADDR(buf + i + 1);
+		buf[i].rdma.pnext = VIRT_TO_DMA(sp, buf + i + 1);
 		buf[i].rdma.pbuf = 0;
+		DMA_SYNC_DESC_DEV(dev, &buf[i]);
 		i++;
 	}
 	buf[i].rdma.pbuf = 0;
-	buf[i].rdma.pnext = CPHYSADDR(buf);
+	buf[i].rdma.pnext = VIRT_TO_DMA(sp, buf);
+	DMA_SYNC_DESC_DEV(dev, &buf[i]);
 }
 
-#define ALIGNED(x)  ((((unsigned long)(x)) + 0xf) & ~(0xf))
-
 static int __init sgiseeq_probe(struct platform_device *pdev)
 {
 	struct sgiseeq_platform_data *pd = pdev->dev.platform_data;
@@ -621,7 +714,7 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
 	unsigned int irq = pd->irq;
 	struct sgiseeq_private *sp;
 	struct net_device *dev;
-	int err, i;
+	int err;
 	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(sizeof (struct sgiseeq_private));
@@ -635,7 +728,7 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
 	sp = netdev_priv(dev);
 
 	/* Make private data page aligned */
-	sr = dma_alloc_coherent(&pdev->dev, sizeof(*sp->srings),
+	sr = dma_alloc_noncoherent(&pdev->dev, sizeof(*sp->srings),
 				&sp->srings_dma, GFP_KERNEL);
 	if (!sr) {
 		printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n");
@@ -647,8 +740,8 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
 	sp->tx_desc = sp->srings->txvector;
 
 	/* A couple calculations now, saves many cycles later. */
-	setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS);
-	setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS);
+	setup_rx_ring(dev, sp->rx_desc, SEEQ_RX_BUFFERS);
+	setup_tx_ring(dev, sp->tx_desc, SEEQ_TX_BUFFERS);
 
 	memcpy(dev->dev_addr, pd->mac, ETH_ALEN);
 
@@ -716,8 +809,8 @@ static int __exit sgiseeq_remove(struct platform_device *pdev)
 	struct sgiseeq_private *sp = netdev_priv(dev);
 
 	unregister_netdev(dev);
-	dma_free_coherent(&pdev->dev, sizeof(*sp->srings), sp->srings,
-	                  sp->srings_dma);
+	dma_free_noncoherent(&pdev->dev, sizeof(*sp->srings), sp->srings,
+			     sp->srings_dma);
 	free_netdev(dev);
 	platform_set_drvdata(pdev, NULL);
 
-- 
1.4.4.4

^ permalink raw reply related

* Re: SGI IP28 support
From: Thomas Bogendoerfer @ 2007-11-26 23:01 UTC (permalink / raw)
  To: linux-mips
In-Reply-To: <20071126223814.GA21339@alpha.franken.de>

On Mon, Nov 26, 2007 at 11:38:14PM +0100, Thomas Bogendoerfer wrote:
> [..]

There is one thing I forgot: You need a special gcc, which will generate
cache barriers to avoid speculative stores done by the R10k. Peter
had some patches submitted to the gcc maintainers, which I used to
build my own gcc 4.2.1 cross compiler. Does anybody know, if Peter's
paches are already intergrated in newer gcc versions ?

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessary a
good idea.                                                [ RFC1925, 2.3 ]

^ permalink raw reply

* Re: [PATCH] fix warning when using PHYS_TO_XKSEG_xx()
From: Andrew Sharp @ 2007-11-26 23:06 UTC (permalink / raw)
  To: Thomas Bogendoerfer; +Cc: linux-mips, ralf
In-Reply-To: <20071126223948.C7CB3C2B26@solo.franken.de>

This is the basically the patch I submitted 10/31 and I believe is
queued for 2.6.25 ...

On Sun, 25 Nov 2007 11:28:03 +0100 Thomas Bogendoerfer
<tsbogend@alpha.franken.de> wrote:

> use CONST64 cast in PHYS_TO_XPHYS macro to avoid warning about shifts
> longer than the target type.
> 
> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> ---
>  arch/mips/lib/uncached.c     |    8 ++++----
>  include/asm-mips/addrspace.h |    2 +-
>  2 files changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c
> index 58d14f4..b59b770 100644
> --- a/arch/mips/lib/uncached.c
> +++ b/arch/mips/lib/uncached.c
> @@ -46,8 +46,8 @@ unsigned long __init run_uncached(void *func)
>  	if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
>  		usp = CKSEG1ADDR(sp);
>  #ifdef CONFIG_64BIT
> -	else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0LL, 0)
> &&
> -		 (long long)sp < (long long)PHYS_TO_XKPHYS(8LL, 0))
> +	else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0, 0) &&
> +		 (long long)sp < (long long)PHYS_TO_XKPHYS(8, 0))
>  		usp = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
>  				     XKPHYS_TO_PHYS((long long)sp));
>  #endif
> @@ -58,8 +58,8 @@ unsigned long __init run_uncached(void *func)
>  	if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2)
>  		ufunc = CKSEG1ADDR(lfunc);
>  #ifdef CONFIG_64BIT
> -	else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0LL,
> 0) &&
> -		 (long long)lfunc < (long long)PHYS_TO_XKPHYS(8LL,
> 0))
> +	else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0, 0)
> &&
> +		 (long long)lfunc < (long long)PHYS_TO_XKPHYS(8, 0))
>  		ufunc = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
>  				       XKPHYS_TO_PHYS((long
> long)lfunc)); #endif
> diff --git a/include/asm-mips/addrspace.h
> b/include/asm-mips/addrspace.h index 0bb7a93..9002d66 100644
> --- a/include/asm-mips/addrspace.h
> +++ b/include/asm-mips/addrspace.h
> @@ -127,7 +127,7 @@
>  #define PHYS_TO_XKSEG_CACHED(p)
> PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE, (p)) #define
> XKPHYS_TO_PHYS(p)		((p) & TO_PHYS_MASK) #define
> PHYS_TO_XKPHYS(cm, a)		(_CONST64_(0x8000000000000000) |
> \
> -					 ((cm)<<59) | (a))
> +					 (_CONST64_(cm)<<59) | (a))
>  
>  /*
>   * The ultimate limited of the 64-bit MIPS architecture:  2 bits for
> selecting

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox