/* myri_sbus.c: MyriCOM MyriNET SBUS card driver.
*
* Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net)
*/
static char version[] =
"myri_sbus.c:v2.0 June 23, 2006 David S. Miller (davem@davemloft.net)\n";
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <net/dst.h>
#include <net/arp.h>
#include <net/sock.h>
#include <net/ipv6.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <asm/idprom.h>
#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/auxio.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include "myri_sbus.h"
#include "myri_code.h"
/* #define DEBUG_DETECT */
/* #define DEBUG_IRQ */
/* #define DEBUG_TRANSMIT */
/* #define DEBUG_RECEIVE */
/* #define DEBUG_HEADER */
#ifdef DEBUG_DETECT
#define DET(x) printk x
#else
#define DET(x)
#endif
#ifdef DEBUG_IRQ
#define DIRQ(x) printk x
#else
#define DIRQ(x)
#endif
#ifdef DEBUG_TRANSMIT
#define DTX(x) printk x
#else
#define DTX(x)
#endif
#ifdef DEBUG_RECEIVE
#define DRX(x) printk x
#else
#define DRX(x)
#endif
#ifdef DEBUG_HEADER
#define DHDR(x) printk x
#else
#define DHDR(x)
#endif
static void myri_reset_off(void __iomem *lp, void __iomem *cregs)
{
/* Clear IRQ mask. */
sbus_writel(0, lp + LANAI_EIMASK);
/* Turn RESET function off. */
sbus_writel(CONTROL_ROFF, cregs + MYRICTRL_CTRL);
}
static void myri_reset_on(void __iomem *cregs)
{
/* Enable RESET function. */
sbus_writel(CONTROL_RON, cregs + MYRICTRL_CTRL);
/* Disable IRQ's. */
sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL);
}
static void myri_disable_irq(void __iomem *lp, void __iomem *cregs)
{
sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL);
sbus_writel(0, lp + LANAI_EIMASK);
sbus_writel(ISTAT_HOST, lp + LANAI_ISTAT);
}
static void myri_enable_irq(void __iomem *lp, void __iomem *cregs)
{
sbus_writel(CONTROL_EIRQ, cregs + MYRICTRL_CTRL);
sbus_writel(ISTAT_HOST, lp + LANAI_EIMASK);
}
static inline void bang_the_chip(struct myri_eth *mp)
{
struct myri_shmem __iomem *shmem = mp->shmem;
void __iomem *cregs = mp->cregs;
sbus_writel(1, &shmem->send);
sbus_writel(CONTROL_WON, cregs + MYRICTRL_CTRL);
}
static int myri_do_handshake(struct myri_eth *mp)
{
struct myri_shmem __iomem *shmem = mp->shmem;
void __iomem *cregs = mp->cregs;
struct myri_channel __iomem *chan = &shmem->channel;
int tick = 0;
DET(("myri_do_handshake: "));
if (sbus_readl(&chan->state) == STATE_READY) {
DET(("Already STATE_READY, failed.\n"));
return -1; /* We're hosed... */
}
myri_disable_irq(mp->lregs, cregs);
while (tick++ <= 25) {
u32 softstate;
/* Wake it up. */
DET(("shakedown, CONTROL_WON, "));
sbus_writel(1, &shmem->shakedown);
sbus_writel(CONTROL_WON, cregs + MYR