Commit bb8abfed authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/greg/linux/BK/bleed-2.6

into kroah.com:/home/greg/linux/BK/usb-2.6
parents c7f22f7a 277c7105
......@@ -2487,16 +2487,6 @@ config IPHASE5526
To compile this driver as a module, choose M here: the module
will be called iph5526.
config RCPCI
tristate "Red Creek Hardware VPN (EXPERIMENTAL)"
depends on NETDEVICES && EXPERIMENTAL && PCI && !64BIT
help
This is a driver for hardware which provides a Virtual Private
Network (VPN). Say Y if you have it.
To compile this driver as a module, choose M here: the module
will be called rcpci.
config SHAPER
tristate "Traffic Shaper (EXPERIMENTAL)"
depends on NETDEVICES && EXPERIMENTAL
......
......@@ -2,8 +2,6 @@
# Makefile for the Linux network (ethercard) device drivers.
#
rcpci-objs := rcpci45.o rclanmtl.o
ifeq ($(CONFIG_ISDN_PPP),y)
obj-$(CONFIG_ISDN) += slhc.o
endif
......@@ -32,7 +30,6 @@ obj-$(CONFIG_BMAC) += bmac.o
obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
obj-$(CONFIG_DGRS) += dgrs.o
obj-$(CONFIG_RCPCI) += rcpci.o
obj-$(CONFIG_VORTEX) += 3c59x.o
obj-$(CONFIG_TYPHOON) += typhoon.o
obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
......
......@@ -84,6 +84,7 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/crc32.h>
#include <linux/delay.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
......@@ -233,15 +234,29 @@ enum intr_status_bits {
RxErr = 0x00000002, /* receive error */
};
/* Bits in the NetworkConfig register. */
/* Bits in the NetworkConfig register, W for writing, R for reading */
/* FIXME: some names are invented by me. Marked with (name?) */
/* If you have docs and know bit names, please fix 'em */
enum rx_mode_bits {
RxModeMask = 0xe0,
PROM = 0x80, /* promiscuous mode */
AB = 0x40, /* accept broadcast */
AM = 0x20, /* accept mutlicast */
ARP = 0x08, /* receive runt pkt */
ALP = 0x04, /* receive long pkt */
SEP = 0x02, /* receive error pkt */
CR_W_ENH = 0x02000000, /* enhanced mode (name?) */
CR_W_FD = 0x00100000, /* full duplex */
CR_W_PS10 = 0x00080000, /* 10 mbit */
CR_W_TXEN = 0x00040000, /* tx enable (name?) */
CR_W_PS1000 = 0x00010000, /* 1000 mbit */
/* CR_W_RXBURSTMASK= 0x00000e00, Im unsure about this */
CR_W_RXMODEMASK = 0x000000e0,
CR_W_PROM = 0x00000080, /* promiscuous mode */
CR_W_AB = 0x00000040, /* accept broadcast */
CR_W_AM = 0x00000020, /* accept mutlicast */
CR_W_ARP = 0x00000008, /* receive runt pkt */
CR_W_ALP = 0x00000004, /* receive long pkt */
CR_W_SEP = 0x00000002, /* receive error pkt */
CR_W_RXEN = 0x00000001, /* rx enable (unicast?) (name?) */
CR_R_TXSTOP = 0x04000000, /* tx stopped (name?) */
CR_R_FD = 0x00100000, /* full duplex detected */
CR_R_PS10 = 0x00080000, /* 10 mbit detected */
CR_R_RXSTOP = 0x00008000, /* rx stopped (name?) */
};
/* The Tulip Rx and Tx buffer descriptors. */
......@@ -375,10 +390,7 @@ enum tx_desc_control_bits {
#define LXT1000_Full 0x200
// 89/12/29 add, for phy specific status register, levelone phy, (end)
/* for 3-in-1 case */
#define PS10 0x00080000
#define FD 0x00100000
#define PS1000 0x00010000
/* for 3-in-1 case, BMCRSR register */
#define LinkIsUp2 0x00040000
/* for PHY */
......@@ -400,6 +412,12 @@ struct netdev_private {
/* Media monitoring timer. */
struct timer_list timer;
/* Reset timer */
struct timer_list reset_timer;
int reset_timer_armed;
unsigned long crvalue_sv;
unsigned long imrvalue_sv;
/* Frequently used values: keep some adjacent for cache effect. */
int flags;
struct pci_dev *pci_dev;
......@@ -435,49 +453,44 @@ static int netdev_open(struct net_device *dev);
static void getlinktype(struct net_device *dev);
static void getlinkstatus(struct net_device *dev);
static void netdev_timer(unsigned long data);
static void reset_timer(unsigned long data);
static void tx_timeout(struct net_device *dev);
static void init_ring(struct net_device *dev);
static int start_tx(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
static int netdev_rx(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static void __set_rx_mode(struct net_device *dev);
static struct net_device_stats *get_stats(struct net_device *dev);
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static struct ethtool_ops netdev_ethtool_ops;
static int netdev_close(struct net_device *dev);
static void reset_rx_descriptors(struct net_device *dev);
static void reset_tx_descriptors(struct net_device *dev);
void stop_nic_tx(long ioaddr, long crvalue)
static void stop_nic_rx(long ioaddr, long crvalue)
{
writel(crvalue & (~0x40000), ioaddr + TCRRCR);
/* wait for tx stop */
{
int i = 0, delay = 0x1000;
while ((!(readl(ioaddr + TCRRCR) & 0x04000000)) && (i < delay)) {
++i;
}
int delay = 0x1000;
writel(crvalue & ~(CR_W_RXEN), ioaddr + TCRRCR);
while (--delay) {
if ( (readl(ioaddr + TCRRCR) & CR_R_RXSTOP) == CR_R_RXSTOP)
break;
}
}
void stop_nic_rx(long ioaddr, long crvalue)
static void stop_nic_rxtx(long ioaddr, long crvalue)
{
writel(crvalue & (~0x1), ioaddr + TCRRCR);
/* wait for rx stop */
{
int i = 0, delay = 0x1000;
while ((!(readl(ioaddr + TCRRCR) & 0x00008000)) && (i < delay)) {
++i;
}
int delay = 0x1000;
writel(crvalue & ~(CR_W_RXEN+CR_W_TXEN), ioaddr + TCRRCR);
while (--delay) {
if ( (readl(ioaddr + TCRRCR) & (CR_R_RXSTOP+CR_R_TXSTOP))
== (CR_R_RXSTOP+CR_R_TXSTOP) )
break;
}
}
static int __devinit fealnx_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
......@@ -495,7 +508,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
#ifndef MODULE
static int printed_version;
if (!printed_version++)
printk (version);
printk(version);
#endif
card_idx++;
......@@ -622,7 +635,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
np->phys[0] = 32;
/* 89/6/23 add, (begin) */
/* get phy type */
if (readl(dev->base_addr + PHYIDENTIFIER) == MysonPHYID)
if (readl(ioaddr + PHYIDENTIFIER) == MysonPHYID)
np->PHYType = MysonPHY;
else
np->PHYType = OtherPHY;
......@@ -657,7 +670,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
if (np->flags == HAS_MII_XCVR)
mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
else
writel(ADVERTISE_FULL, dev->base_addr + ANARANLPAR);
writel(ADVERTISE_FULL, ioaddr + ANARANLPAR);
np->mii.force_media = 1;
}
......@@ -669,7 +682,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &mii_ioctl;
dev->ethtool_ops = &netdev_ethtool_ops;
dev->tx_timeout = tx_timeout;
dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
err = register_netdev(dev);
......@@ -699,6 +712,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
return err;
}
static void __devexit fealnx_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
......@@ -721,42 +735,6 @@ static void __devexit fealnx_remove_one(struct pci_dev *pdev)
printk(KERN_ERR "fealnx: remove for unknown device\n");
}
unsigned int m80x_read_tick(void)
/* function: Reads the Timer tick count register which decrements by 2 from */
/* 65536 to 0 every 1/36.414 of a second. Each 2 decrements of the *//* count represents 838 nsec's. */
/* input : none. */
/* output : none. */
{
unsigned char tmp;
int value;
writeb((char) 0x06, 0x43); // Command 8254 to latch T0's count
// now read the count.
tmp = (unsigned char) readb(0x40);
value = ((int) tmp) << 8;
tmp = (unsigned char) readb(0x40);
value |= (((int) tmp) & 0xff);
return (value);
}
void m80x_delay(unsigned int interval)
/* function: to wait for a specified time. */
/* input : interval ... the specified time. */
/* output : none. */
{
unsigned int interval1, interval2, i = 0;
interval1 = m80x_read_tick(); // get initial value
do {
interval2 = m80x_read_tick();
if (interval1 < interval2)
interval1 = interval2;
++i;
} while (((interval1 - interval2) < (ushort) interval) && (i < 65535));
}
static ulong m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad)
{
......@@ -796,7 +774,7 @@ static ulong m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad
/* high MDC */
miir |= MASK_MIIR_MII_MDC;
writel(miir, miiport);
m80x_delay(30);
udelay(30);
/* next */
mask >>= 1;
......@@ -831,7 +809,7 @@ static int mdio_read(struct net_device *dev, int phyad, int regad)
/* high MDC, and wait */
miir |= MASK_MIIR_MII_MDC;
writel(miir, miiport);
m80x_delay((int) 30);
udelay(30);
/* next */
mask >>= 1;
......@@ -873,8 +851,6 @@ static void mdio_write(struct net_device *dev, int phyad, int regad, int data)
/* low MDC */
miir &= ~MASK_MIIR_MII_MDC;
writel(miir, miiport);
return;
}
......@@ -949,7 +925,7 @@ static int netdev_open(struct net_device *dev)
np->imrvalue = TUNF | CNTOVF | RBU | TI | RI;
if (np->pci_dev->device == 0x891) {
np->bcrvalue |= 0x200; /* set PROG bit */
np->crvalue |= 0x02000000; /* set enhanced bit */
np->crvalue |= CR_W_ENH; /* set enhanced bit */
np->imrvalue |= ETI;
}
writel(np->bcrvalue, ioaddr + BCR);
......@@ -957,7 +933,7 @@ static int netdev_open(struct net_device *dev)
if (dev->if_port == 0)
dev->if_port = np->default_port;
writel(0, dev->base_addr + RXPDR);
writel(0, ioaddr + RXPDR);
// 89/9/1 modify,
// np->crvalue = 0x00e40001; /* tx store and forward, tx/rx enable */
np->crvalue |= 0x00e40001; /* tx store and forward, tx/rx enable */
......@@ -965,7 +941,7 @@ static int netdev_open(struct net_device *dev)
getlinkstatus(dev);
if (np->linkok)
getlinktype(dev);
set_rx_mode(dev);
__set_rx_mode(dev);
netif_start_queue(dev);
......@@ -985,6 +961,11 @@ static int netdev_open(struct net_device *dev)
/* timer handler */
add_timer(&np->timer);
init_timer(&np->reset_timer);
np->reset_timer.data = (unsigned long) dev;
np->reset_timer.function = &reset_timer;
np->reset_timer_armed = 0;
return 0;
}
......@@ -1005,8 +986,7 @@ static void getlinkstatus(struct net_device *dev)
np->linkok = 1;
return;
}
// delay
m80x_delay(100);
udelay(100);
}
} else {
for (i = 0; i < DelayTime; ++i) {
......@@ -1014,8 +994,7 @@ static void getlinkstatus(struct net_device *dev)
np->linkok = 1;
return;
}
// delay
m80x_delay(100);
udelay(100);
}
}
}
......@@ -1026,11 +1005,11 @@ static void getlinktype(struct net_device *dev)
struct netdev_private *np = dev->priv;
if (np->PHYType == MysonPHY) { /* 3-in-1 case */
if (readl(dev->base_addr + TCRRCR) & FD)
if (readl(dev->base_addr + TCRRCR) & CR_R_FD)
np->duplexmode = 2; /* full duplex */
else
np->duplexmode = 1; /* half duplex */
if (readl(dev->base_addr + TCRRCR) & PS10)
if (readl(dev->base_addr + TCRRCR) & CR_R_PS10)
np->line_speed = 1; /* 10M */
else
np->line_speed = 2; /* 100M */
......@@ -1112,19 +1091,18 @@ static void getlinktype(struct net_device *dev)
else
np->line_speed = 1; /* 10M */
}
// chage crvalue
// np->crvalue&=(~PS10)&(~FD);
np->crvalue &= (~PS10) & (~FD) & (~PS1000);
np->crvalue &= (~CR_W_PS10) & (~CR_W_FD) & (~CR_W_PS1000);
if (np->line_speed == 1)
np->crvalue |= PS10;
np->crvalue |= CR_W_PS10;
else if (np->line_speed == 3)
np->crvalue |= PS1000;
np->crvalue |= CR_W_PS1000;
if (np->duplexmode == 2)
np->crvalue |= FD;
np->crvalue |= CR_W_FD;
}
}
/* Take lock before calling this */
static void allocate_rx_buffers(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
......@@ -1134,15 +1112,17 @@ static void allocate_rx_buffers(struct net_device *dev)
struct sk_buff *skb;
skb = dev_alloc_skb(np->rx_buf_sz);
np->lack_rxbuf->skbuff = skb;
if (skb == NULL)
break; /* Better luck next round. */
while (np->lack_rxbuf->skbuff)
np->lack_rxbuf = np->lack_rxbuf->next_desc_logical;
skb->dev = dev; /* Mark as being used by this device. */
np->lack_rxbuf->skbuff = skb;
np->lack_rxbuf->buffer = pci_map_single(np->pci_dev, skb->tail,
np->rx_buf_sz, PCI_DMA_FROMDEVICE);
np->lack_rxbuf = np->lack_rxbuf->next_desc_logical;
np->lack_rxbuf->status = RXOWN;
++np->really_rx_count;
}
}
......@@ -1153,22 +1133,23 @@ static void netdev_timer(unsigned long data)
struct net_device *dev = (struct net_device *) data;
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
int next_tick = 10 * HZ;
int old_crvalue = np->crvalue;
unsigned int old_linkok = np->linkok;
unsigned long flags;
if (debug)
printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x "
"config %8.8x.\n", dev->name, readl(ioaddr + ISR),
readl(ioaddr + TCRRCR));
spin_lock_irqsave(&np->lock, flags);
if (np->flags == HAS_MII_XCVR) {
getlinkstatus(dev);
if ((old_linkok == 0) && (np->linkok == 1)) { /* we need to detect the media type again */
getlinktype(dev);
if (np->crvalue != old_crvalue) {
stop_nic_tx(ioaddr, np->crvalue);
stop_nic_rx(ioaddr, np->crvalue & (~0x40000));
stop_nic_rxtx(ioaddr, np->crvalue);
writel(np->crvalue, ioaddr + TCRRCR);
}
}
......@@ -1176,69 +1157,120 @@ static void netdev_timer(unsigned long data)
allocate_rx_buffers(dev);
np->timer.expires = RUN_AT(next_tick);
spin_unlock_irqrestore(&np->lock, flags);
np->timer.expires = RUN_AT(10 * HZ);
add_timer(&np->timer);
}
static void tx_timeout(struct net_device *dev)
/* Take lock before calling */
/* Reset chip and disable rx, tx and interrupts */
static void reset_and_disable_rxtx(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
int i;
printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
" resetting...\n", dev->name, readl(ioaddr + ISR));
{
printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
printk(" %8.8x", (unsigned int) np->rx_ring[i].status);
printk("\n" KERN_DEBUG " Tx ring %p: ", np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
printk(" %4.4x", np->tx_ring[i].status);
printk("\n");
}
/* Reinit. Gross */
int delay=51;
/* Reset the chip's Tx and Rx processes. */
stop_nic_tx(ioaddr, 0);
reset_rx_descriptors(dev);
stop_nic_rxtx(ioaddr, 0);
/* Disable interrupts by clearing the interrupt mask. */
writel(0x0000, ioaddr + IMR);
writel(0, ioaddr + IMR);
/* Reset the chip to erase previous misconfiguration. */
writel(0x00000001, ioaddr + BCR);
/* Ueimor: wait for 50 PCI cycles (and flush posted writes btw).
We surely wait too long (address+data phase). Who cares ? */
for (i = 0; i < 50; i++) {
We surely wait too long (address+data phase). Who cares? */
while (--delay) {
readl(ioaddr + BCR);
rmb();
}
}
/* Take lock before calling */
/* Restore chip after reset */
static void enable_rxtx(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
writel((np->cur_tx - np->tx_ring)*sizeof(struct fealnx_desc) +
np->tx_ring_dma, ioaddr + TXLBA);
writel((np->cur_rx - np->rx_ring)*sizeof(struct fealnx_desc) +
np->rx_ring_dma, ioaddr + RXLBA);
reset_rx_descriptors(dev);
writel(np->tx_ring_dma + ((char*)np->cur_tx - (char*)np->tx_ring),
ioaddr + TXLBA);
writel(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring),
ioaddr + RXLBA);
writel(np->bcrvalue, ioaddr + BCR);
writel(0, dev->base_addr + RXPDR);
set_rx_mode(dev);
writel(0, ioaddr + RXPDR);
__set_rx_mode(dev); /* changes np->crvalue, writes it into TCRRCR */
/* Clear and Enable interrupts by setting the interrupt mask. */
writel(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR);
writel(np->imrvalue, ioaddr + IMR);
writel(0, dev->base_addr + TXPDR);
writel(0, ioaddr + TXPDR);
}
static void reset_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
struct netdev_private *np = dev->priv;
unsigned long flags;
printk(KERN_WARNING "%s: resetting tx and rx machinery\n", dev->name);
spin_lock_irqsave(&np->lock, flags);
np->crvalue = np->crvalue_sv;
np->imrvalue = np->imrvalue_sv;
reset_and_disable_rxtx(dev);
/* works for me without this:
reset_tx_descriptors(dev); */
enable_rxtx(dev);
netif_start_queue(dev); /* FIXME: or netif_wake_queue(dev); ? */
np->reset_timer_armed = 0;
spin_unlock_irqrestore(&np->lock, flags);
}
static void tx_timeout(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
unsigned long flags;
int i;
printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
" resetting...\n", dev->name, readl(ioaddr + ISR));
{
printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
printk(" %8.8x", (unsigned int) np->rx_ring[i].status);
printk("\n" KERN_DEBUG " Tx ring %p: ", np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
printk(" %4.4x", np->tx_ring[i].status);
printk("\n");
}
spin_lock_irqsave(&np->lock, flags);
reset_and_disable_rxtx(dev);
reset_tx_descriptors(dev);
enable_rxtx(dev);
spin_unlock_irqrestore(&np->lock, flags);
dev->trans_start = jiffies;
np->stats.tx_errors++;
return;
netif_wake_queue(dev); /* or .._start_.. ?? */
}
......@@ -1251,7 +1283,7 @@ static void init_ring(struct net_device *dev)
/* initialize rx variables */
np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
np->cur_rx = &np->rx_ring[0];
np->lack_rxbuf = NULL;
np->lack_rxbuf = np->rx_ring;
np->really_rx_count = 0;
/* initial rx descriptors. */
......@@ -1294,6 +1326,7 @@ static void init_ring(struct net_device *dev)
for (i = 0; i < TX_RING_SIZE; i++) {
np->tx_ring[i].status = 0;
/* do we need np->tx_ring[i].control = XXX; ?? */
np->tx_ring[i].next_desc = np->tx_ring_dma +
(i + 1)*sizeof(struct fealnx_desc);
np->tx_ring[i].next_desc_logical = &np->tx_ring[i + 1];
......@@ -1341,7 +1374,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
np->cur_tx_copy->control |= (BPT << TBSShift); /* buffer size */
/* for the last descriptor */
next = (struct fealnx *) np->cur_tx_copy.next_desc_logical;
next = np->cur_tx_copy->next_desc_logical;
next->skbuff = skb;
next->control = TXIC | TXLD | CRCEnable | PADEnable;
next->control |= (skb->len << PKTSShift); /* pkt size */
......@@ -1383,35 +1416,59 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
}
void free_one_rx_descriptor(struct netdev_private *np)
/* Take lock before calling */
/* Chip probably hosed tx ring. Clean up. */
static void reset_tx_descriptors(struct net_device *dev)
{
if (np->really_rx_count == RX_RING_SIZE)
np->cur_rx->status = RXOWN;
else {
np->lack_rxbuf->skbuff = np->cur_rx->skbuff;
np->lack_rxbuf->buffer = np->cur_rx->buffer;
np->lack_rxbuf->status = RXOWN;
++np->really_rx_count;
np->lack_rxbuf = np->lack_rxbuf->next_desc_logical;
struct netdev_private *np = dev->priv;
struct fealnx_desc *cur;
int i;
/* initialize tx variables */
np->cur_tx = &np->tx_ring[0];
np->cur_tx_copy = &np->tx_ring[0];
np->really_tx_count = 0;
np->free_tx_count = TX_RING_SIZE;
for (i = 0; i < TX_RING_SIZE; i++) {
cur = &np->tx_ring[i];
if (cur->skbuff) {
pci_unmap_single(np->pci_dev, cur->buffer,
cur->skbuff->len, PCI_DMA_TODEVICE);
dev_kfree_skb(cur->skbuff);
/* or dev_kfree_skb_irq(cur->skbuff); ? */
cur->skbuff = NULL;
}
cur->status = 0;
cur->control = 0; /* needed? */
/* probably not needed. We do it for purely paranoid reasons */
cur->next_desc = np->tx_ring_dma +
(i + 1)*sizeof(struct fealnx_desc);
cur->next_desc_logical = &np->tx_ring[i + 1];
}
np->cur_rx = np->cur_rx->next_desc_logical;
/* for the last tx descriptor */
np->tx_ring[TX_RING_SIZE - 1].next_desc = np->tx_ring_dma;
np->tx_ring[TX_RING_SIZE - 1].next_desc_logical = &np->tx_ring[0];
}
void reset_rx_descriptors(struct net_device *dev)
/* Take lock and stop rx before calling this */
static void reset_rx_descriptors(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
stop_nic_rx(dev->base_addr, np->crvalue);
while (!(np->cur_rx->status & RXOWN))
free_one_rx_descriptor(np);
struct fealnx_desc *cur = np->cur_rx;
int i;
allocate_rx_buffers(dev);
writel(np->rx_ring_dma + (np->cur_rx - np->rx_ring),
for (i = 0; i < RX_RING_SIZE; i++) {
if (cur->skbuff)
cur->status = RXOWN;
cur = cur->next_desc_logical;
}
writel(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring),
dev->base_addr + RXLBA);
writel(np->crvalue, dev->base_addr + TCRRCR);
}
......@@ -1421,16 +1478,14 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
{
struct net_device *dev = (struct net_device *) dev_instance;
struct netdev_private *np = dev->priv;
long ioaddr, boguscnt = max_interrupt_work;
long ioaddr = dev->base_addr;
long boguscnt = max_interrupt_work;
unsigned int num_tx = 0;
int handled = 0;
spin_lock(&np->lock);
writel(0, dev->base_addr + IMR);
ioaddr = dev->base_addr;
np = dev->priv;
writel(0, ioaddr + IMR);
do {
u32 intr_status = readl(ioaddr + ISR);
......@@ -1471,8 +1526,11 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
if (intr_status & (RI | RBU)) {
if (intr_status & RI)
netdev_rx(dev);
else
else {
stop_nic_rx(ioaddr, np->crvalue);
reset_rx_descriptors(dev);
writel(np->crvalue, ioaddr + TCRRCR);
}
}
while (np->really_tx_count) {
......@@ -1490,7 +1548,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
if (tx_status & TXOWN)
break;
if (!(np->crvalue & 0x02000000)) {
if (!(np->crvalue & CR_W_ENH)) {
if (tx_status & (CSL | LC | EC | UDF | HF)) {
np->stats.tx_errors++;
if (tx_status & EC)
......@@ -1539,7 +1597,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
netif_wake_queue(dev);
/* read transmit status for enhanced mode only */
if (np->crvalue & 0x02000000) {
if (np->crvalue & CR_W_ENH) {
long data;
data = readl(ioaddr + TSR);
......@@ -1552,6 +1610,20 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
if (--boguscnt < 0) {
printk(KERN_WARNING "%s: Too much work at interrupt, "
"status=0x%4.4x.\n", dev->name, intr_status);
if (!np->reset_timer_armed) {
np->reset_timer_armed = 1;
np->reset_timer.expires = RUN_AT(HZ/2);
add_timer(&np->reset_timer);
stop_nic_rxtx(ioaddr, 0);
netif_stop_queue(dev);
/* or netif_tx_disable(dev); ?? */
/* Prevent other paths from enabling tx,rx,intrs */
np->crvalue_sv = np->crvalue;
np->imrvalue_sv = np->imrvalue;
np->crvalue &= ~(CR_W_TXEN | CR_W_RXEN); /* or simply = 0? */
np->imrvalue = 0;
}
break;
}
} while (1);
......@@ -1580,9 +1652,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
static int netdev_rx(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
/* If EOP is set on the next entry, it's a new packet. Send it up. */
while (!(np->cur_rx->status & RXOWN)) {
while (!(np->cur_rx->status & RXOWN) && np->cur_rx->skbuff) {
s32 rx_status = np->cur_rx->status;
if (np->really_rx_count == 0)
......@@ -1634,11 +1707,20 @@ static int netdev_rx(struct net_device *dev)
np->stats.rx_length_errors++;
/* free all rx descriptors related this long pkt */
for (i = 0; i < desno; ++i)
free_one_rx_descriptor(np);
for (i = 0; i < desno; ++i) {
if (!np->cur_rx->skbuff) {
printk(KERN_DEBUG
"%s: I'm scared\n", dev->name);
break;
}
np->cur_rx->status = RXOWN;
np->cur_rx = np->cur_rx->next_desc_logical;
}
continue;
} else { /* something error, need to reset this chip */
} else { /* rx error, need to reset this chip */
stop_nic_rx(ioaddr, np->crvalue);
reset_rx_descriptors(dev);
writel(np->crvalue, ioaddr + TCRRCR);
}
break; /* exit the while loop */
}
......@@ -1685,8 +1767,6 @@ static int netdev_rx(struct net_device *dev)
PCI_DMA_FROMDEVICE);
skb_put(skb = np->cur_rx->skbuff, pkt_len);
np->cur_rx->skbuff = NULL;
if (np->really_rx_count == RX_RING_SIZE)
np->lack_rxbuf = np->cur_rx;
--np->really_rx_count;
}
skb->protocol = eth_type_trans(skb, dev);
......@@ -1696,24 +1776,7 @@ static int netdev_rx(struct net_device *dev)
np->stats.rx_bytes += pkt_len;
}
if (np->cur_rx->skbuff == NULL) {
struct sk_buff *skb;
skb = dev_alloc_skb(np->rx_buf_sz);
if (skb != NULL) {
skb->dev = dev; /* Mark as being used by this device. */
np->cur_rx->buffer = pci_map_single(np->pci_dev,
skb->tail,
np->rx_buf_sz,
PCI_DMA_FROMDEVICE);
np->cur_rx->skbuff = skb;
++np->really_rx_count;
}
}
if (np->cur_rx->skbuff != NULL)
free_one_rx_descriptor(np);
np->cur_rx = np->cur_rx->next_desc_logical;
} /* end of while loop */
/* allocate skb for rx buffers */
......@@ -1737,7 +1800,20 @@ static struct net_device_stats *get_stats(struct net_device *dev)
return &np->stats;
}
/* for dev->set_multicast_list */
static void set_rx_mode(struct net_device *dev)
{
spinlock_t *lp = &((struct netdev_private *)dev->priv)->lock;
unsigned long flags;
spin_lock_irqsave(lp, flags);
__set_rx_mode(dev);
spin_unlock_irqrestore(&lp, flags);
}
/* Take lock before calling */
static void __set_rx_mode(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
......@@ -1748,12 +1824,12 @@ static void set_rx_mode(struct net_device *dev)
/* Unconditionally log net taps. */
printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
memset(mc_filter, 0xff, sizeof(mc_filter));
rx_mode = PROM | AB | AM;
rx_mode = CR_W_PROM | CR_W_AB | CR_W_AM;
} else if ((dev->mc_count > multicast_filter_limit)
|| (dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
memset(mc_filter, 0xff, sizeof(mc_filter));
rx_mode = AB | AM;
rx_mode = CR_W_AB | CR_W_AM;
} else {
struct dev_mc_list *mclist;
int i;
......@@ -1765,26 +1841,25 @@ static void set_rx_mode(struct net_device *dev)
bit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F;
mc_filter[bit >> 5] |= (1 << bit);
}
rx_mode = AB | AM;
rx_mode = CR_W_AB | CR_W_AM;
}
stop_nic_tx(ioaddr, np->crvalue);
stop_nic_rx(ioaddr, np->crvalue & (~0x40000));
stop_nic_rxtx(ioaddr, np->crvalue);
writel(mc_filter[0], ioaddr + MAR0);
writel(mc_filter[1], ioaddr + MAR1);
np->crvalue &= ~RxModeMask;
np->crvalue &= ~CR_W_RXMODEMASK;
np->crvalue |= rx_mode;
writel(np->crvalue, ioaddr + TCRRCR);
}
static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct netdev_private *np = dev->priv;
strcpy (info->driver, DRV_NAME);
strcpy (info->version, DRV_VERSION);
strcpy (info->bus_info, pci_name(np->pci_dev));
strcpy(info->driver, DRV_NAME);
strcpy(info->version, DRV_VERSION);
strcpy(info->bus_info, pci_name(np->pci_dev));
}
static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
......@@ -1874,10 +1949,10 @@ static int netdev_close(struct net_device *dev)
writel(0x0000, ioaddr + IMR);
/* Stop the chip's Tx and Rx processes. */
stop_nic_tx(ioaddr, 0);
stop_nic_rx(ioaddr, 0);
stop_nic_rxtx(ioaddr, 0);
del_timer_sync(&np->timer);
del_timer_sync(&np->reset_timer);
free_irq(dev->irq, dev);
......@@ -1928,7 +2003,7 @@ static int __init fealnx_init(void)
{
/* when a module, this is printed whether or not devices are found in probe */
#ifdef MODULE
printk (version);
printk(version);
#endif
return pci_module_init(&fealnx_driver);
......
/*
** *************************************************************************
**
**
** R C I F . H
**
**
** RedCreek InterFace include file.
**
** ---------------------------------------------------------------------
** --- Copyright (c) 1998-1999, RedCreek Communications Inc. ---
** --- All rights reserved. ---
** ---------------------------------------------------------------------
**
** File Description:
**
** Header file private ioctl commands.
**
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
** *************************************************************************
*/
#ifndef RCIF_H
#define RCIF_H
/* The following protocol revision # should be incremented every time
a new protocol or new structures are used in this file. */
int USER_PROTOCOL_REV = 2; /* used to track different protocol revisions */
/* define a single TCB & buffer */
typedef struct { /* a single buffer */
U32 context; /* context */
U32 scount; /* segment count */
U32 size; /* segment size */
U32 addr; /* segment physical address */
} __attribute__ ((packed))
singleB, *psingleB;
typedef struct { /* a single TCB */
/*
** +-----------------------+
** | 1 | one buffer in the TCB
** +-----------------------+
** | <user's Context> | user's buffer reference
** +-----------------------+
** | 1 | one segment buffer
** +-----------------------+ _
** | <buffer size> | size \
** +-----------------------+ \ segment descriptor
** | <physical address> | physical address of buffer /
** +-----------------------+ _/
*/
U32 bcount; /* buffer count */
singleB b; /* buffer */
} __attribute__ ((packed))
singleTCB, *psingleTCB;
/*
When adding new entries, please add all 5 related changes, since
it helps keep everything consistent:
1) User structure entry
2) User data entry
3) Structure short-cut entry
4) Data short-cut entry
5) Command identifier entry
For Example ("GETSPEED"):
1) struct RCgetspeed_tag { U32 LinkSpeedCode; } RCgetspeed;
2) struct RCgetspeed_tag *getspeed;
3) #define RCUS_GETSPEED data.RCgetspeed;
4) #define RCUD_GETSPEED _RC_user_data.getspeed
5) #define RCUC_GETSPEED 0x02
Notes for the "GETSPEED" entry, above:
1) RCgetspeed - RC{name}
RCgetspeed_tag - RC{name}_tag
LinkSpeedCode - create any structure format desired (not too large,
since memory will be unioned with all other entries)
2) RCgetspeed_tag - RC{name}_tag chosen in #1
getspeed - arbitrary name (ptr to structure in #1)
3) RCUS_GETSPEED - RCUS_{NAME} ("NAME" & "name" do not have to the same)
data.RCgetspeed - data.RC{name} ("RC{name}" from #1)
4) RCUD_GETSPEED - _RC_user_data.getspeed ("getspeed" from #2)
5) RCUC_GETSPEED - unique hex identifier entry.
*/
typedef struct RC_user_tag RCuser_struct;
/* 1) User structure entry */
struct RC_user_tag {
int cmd;
union {
/* GETINFO structure */
struct RCgetinfo_tag {
unsigned long int mem_start;
unsigned long int mem_end;
unsigned long int base_addr;
unsigned char irq;
unsigned char dma;
unsigned char port;
} RCgetinfo; /* <---- RCgetinfo */
/* GETSPEED structure */
struct RCgetspeed_tag {
U32 LinkSpeedCode;
} RCgetspeed; /* <---- RCgetspeed */
/* SETSPEED structure */
struct RCsetspeed_tag {
U16 LinkSpeedCode;
} RCsetspeed; /* <---- RCsetspeed */
/* GETPROM structure */
struct RCgetprom_tag {
U32 PromMode;
} RCgetprom; /* <---- RCgetprom */
/* SETPROM structure */
struct RCsetprom_tag {
U16 PromMode;
} RCsetprom; /* <---- RCsetprom */
/* GETBROADCAST structure */
struct RCgetbroadcast_tag {
U32 BroadcastMode;
} RCgetbroadcast; /* <---- RCgetbroadcast */
/* SETBROADCAST structure */
struct RCsetbroadcast_tag {
U16 BroadcastMode;
} RCsetbroadcast; /* <---- RCsetbroadcast */
/* GETFIRMWAREVER structure */
#define FirmStringLen 80
struct RCgetfwver_tag {
U8 FirmString[FirmStringLen];
} RCgetfwver; /* <---- RCgetfwver */
/* GETIPANDMASK structure */
struct RCgetipnmask_tag {
U32 IpAddr;
U32 NetMask;
} RCgetipandmask; /* <---- RCgetipandmask */
/* SETIPANDMASK structure */
struct RCsetipnmask_tag {
U32 IpAddr;
U32 NetMask;
} RCsetipandmask; /* <---- RCsetipandmask */
/* GETMAC structure */
#define MAC_SIZE 10
struct RCgetmac_tag {
U8 mac[MAC_SIZE];
} RCgetmac; /* <---- RCgetmac */
/* SETMAC structure */
struct RCsetmac_tag {
U8 mac[MAC_SIZE];
} RCsetmac; /* <---- RCsetmac */
/* GETLINKSTATUS structure */
struct RCgetlnkstatus_tag {
U32 ReturnStatus;
} RCgetlnkstatus; /* <---- RCgetlnkstatus */
/* GETLINKSTATISTICS structure */
struct RCgetlinkstats_tag {
RCLINKSTATS StatsReturn;
} RCgetlinkstats; /* <---- RCgetlinkstats */
/* DEFAULT structure (when no command was recognized) */
struct RCdefault_tag {
int rc;
} RCdefault; /* <---- RCdefault */
} data;
}; /* struct RC_user_tag { ... } */
/* 2) User data entry */
/* RCUD = RedCreek User Data */
union RC_user_data_tag { /* structure tags used are taken from RC_user_tag structure above */
struct RCgetinfo_tag *getinfo;
struct RCgetspeed_tag *getspeed;
struct RCgetprom_tag *getprom;
struct RCgetbroadcast_tag *getbroadcast;
struct RCgetfwver_tag *getfwver;
struct RCgetipnmask_tag *getipandmask;
struct RCgetmac_tag *getmac;
struct RCgetlnkstatus_tag *getlinkstatus;
struct RCgetlinkstats_tag *getlinkstatistics;
struct RCdefault_tag *rcdefault;
struct RCsetspeed_tag *setspeed;
struct RCsetprom_tag *setprom;
struct RCsetbroadcast_tag *setbroadcast;
struct RCsetipnmask_tag *setipandmask;
struct RCsetmac_tag *setmac;
} _RC_user_data; /* declare as a global, so the defines below will work */
/* 3) Structure short-cut entry */
/* define structure short-cuts *//* structure names are taken from RC_user_tag structure above */
#define RCUS_GETINFO data.RCgetinfo;
#define RCUS_GETSPEED data.RCgetspeed;
#define RCUS_GETPROM data.RCgetprom;
#define RCUS_GETBROADCAST data.RCgetbroadcast;
#define RCUS_GETFWVER data.RCgetfwver;
#define RCUS_GETIPANDMASK data.RCgetipandmask;
#define RCUS_GETMAC data.RCgetmac;
#define RCUS_GETLINKSTATUS data.RCgetlnkstatus;
#define RCUS_GETLINKSTATISTICS data.RCgetlinkstats;
#define RCUS_DEFAULT data.RCdefault;
#define RCUS_SETSPEED data.RCsetspeed;
#define RCUS_SETPROM data.RCsetprom;
#define RCUS_SETBROADCAST data.RCsetbroadcast;
#define RCUS_SETIPANDMASK data.RCsetipandmask;
#define RCUS_SETMAC data.RCsetmac;
/* 4) Data short-cut entry */
/* define data short-cuts *//* pointer names are from RC_user_data_tag union (just below RC_user_tag) */
#define RCUD_GETINFO _RC_user_data.getinfo
#define RCUD_GETSPEED _RC_user_data.getspeed
#define RCUD_GETPROM _RC_user_data.getprom
#define RCUD_GETBROADCAST _RC_user_data.getbroadcast
#define RCUD_GETFWVER _RC_user_data.getfwver
#define RCUD_GETIPANDMASK _RC_user_data.getipandmask
#define RCUD_GETMAC _RC_user_data.getmac
#define RCUD_GETLINKSTATUS _RC_user_data.getlinkstatus
#define RCUD_GETLINKSTATISTICS _RC_user_data.getlinkstatistics
#define RCUD_DEFAULT _RC_user_data.rcdefault
#define RCUD_SETSPEED _RC_user_data.setspeed
#define RCUD_SETPROM _RC_user_data.setprom
#define RCUD_SETBROADCAST _RC_user_data.setbroadcast
#define RCUD_SETIPANDMASK _RC_user_data.setipandmask
#define RCUD_SETMAC _RC_user_data.setmac
/* 5) Command identifier entry */
/* define command identifiers */
#define RCUC_GETINFO 0x01
#define RCUC_GETSPEED 0x02
#define RCUC_GETFWVER 0x03
#define RCUC_GETIPANDMASK 0x04
#define RCUC_GETMAC 0x05
#define RCUC_GETLINKSTATUS 0x06
#define RCUC_GETLINKSTATISTICS 0x07
#define RCUC_GETPROM 0x14
#define RCUC_GETBROADCAST 0x15
#define RCUC_DEFAULT 0xff
#define RCUC_SETSPEED 0x08
#define RCUC_SETIPANDMASK 0x09
#define RCUC_SETMAC 0x0a
#define RCUC_SETPROM 0x16
#define RCUC_SETBROADCAST 0x17
/* define ioctl commands to use, when talking to RC 45/PCI driver */
#define RCU_PROTOCOL_REV SIOCDEVPRIVATE
#define RCU_COMMAND SIOCDEVPRIVATE+1
/*
Intended use for the above defines is shown below (GETINFO, as this example):
RCuser_struct RCuser; // declare RCuser structure
struct ifreq ifr; // declare an interface request structure
RCuser.cmd = RCUC_GETINFO; // set user command to GETINFO
ifr->ifr_data = (caddr_t) &RCuser; // set point to user structure
sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); // get a socket
ioctl(sock, RCU_COMMAND, &ifr); // do ioctl on socket
RCUD_GETINFO = &RCuser.RCUS_GETINFO; // set data pointer for GETINFO
// print results
printf("memory 0x%lx-0x%lx, base address 0x%x, irq 0x%x\n",
RCUD_GETINFO->mem_start, RCUD_GETINFO->mem_end,
RCUD_GETINFO->base_addr, RCUD_GETINFO->irq);
*/
#endif /* RCIF_H */
/*
** *************************************************************************
**
**
** R C L A N M T L . C $Revision: 6 $
**
**
** RedCreek I2O LAN Message Transport Layer program module.
**
** ---------------------------------------------------------------------
** --- Copyright (c) 1997-1999, RedCreek Communications Inc. ---
** --- All rights reserved. ---
** ---------------------------------------------------------------------
**
** File Description:
**
** Host side I2O (Intelligent I/O) LAN message transport layer.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
** 1998-1999, LAN API was modified and enhanced by Alice Hennessy.
**
** Sometime in 1997, LAN API was written from scratch by Wendell Nichols.
** *************************************************************************
*/
#define DEBUG 1
#define RC_LINUX_MODULE
#include "rclanmtl.h"
/* RedCreek LAN device Target ID */
#define RC_LAN_TARGET_ID 0x10
/* RedCreek's OSM default LAN receive Initiator */
#define DEFAULT_RECV_INIT_CONTEXT 0xA17
/*
** I2O message structures
*/
#define I2O_TID_SZ 12
#define I2O_FUNCTION_SZ 8
/* Transaction Reply Lists (TRL) Control Word structure */
#define I2O_TRL_FLAGS_SINGLE_FIXED_LENGTH 0x00
#define I2O_TRL_FLAGS_SINGLE_VARIABLE_LENGTH 0x40
#define I2O_TRL_FLAGS_MULTIPLE_FIXED_LENGTH 0x80
/* LAN Class specific functions */
#define I2O_LAN_PACKET_SEND 0x3B
#define I2O_LAN_SDU_SEND 0x3D
#define I2O_LAN_RECEIVE_POST 0x3E
#define I2O_LAN_RESET 0x35
#define I2O_LAN_SHUTDOWN 0x37
/* Private Class specfic function */
#define I2O_PRIVATE 0xFF
/* I2O Executive Function Codes. */
#define I2O_EXEC_ADAPTER_ASSIGN 0xB3
#define I2O_EXEC_ADAPTER_READ 0xB2
#define I2O_EXEC_ADAPTER_RELEASE 0xB5
#define I2O_EXEC_BIOS_INFO_SET 0xA5
#define I2O_EXEC_BOOT_DEVICE_SET 0xA7
#define I2O_EXEC_CONFIG_VALIDATE 0xBB
#define I2O_EXEC_CONN_SETUP 0xCA
#define I2O_EXEC_DEVICE_ASSIGN 0xB7
#define I2O_EXEC_DEVICE_RELEASE 0xB9
#define I2O_EXEC_HRT_GET 0xA8
#define I2O_EXEC_IOP_CLEAR 0xBE
#define I2O_EXEC_IOP_CONNECT 0xC9
#define I2O_EXEC_IOP_RESET 0xBD
#define I2O_EXEC_LCT_NOTIFY 0xA2
#define I2O_EXEC_OUTBOUND_INIT 0xA1
#define I2O_EXEC_PATH_ENABLE 0xD3
#define I2O_EXEC_PATH_QUIESCE 0xC5
#define I2O_EXEC_PATH_RESET 0xD7
#define I2O_EXEC_STATIC_MF_CREATE 0xDD
#define I2O_EXEC_STATIC_MF_RELEASE 0xDF
#define I2O_EXEC_STATUS_GET 0xA0
#define I2O_EXEC_SW_DOWNLOAD 0xA9
#define I2O_EXEC_SW_UPLOAD 0xAB
#define I2O_EXEC_SW_REMOVE 0xAD
#define I2O_EXEC_SYS_ENABLE 0xD1
#define I2O_EXEC_SYS_MODIFY 0xC1
#define I2O_EXEC_SYS_QUIESCE 0xC3
#define I2O_EXEC_SYS_TAB_SET 0xA3
/* Init Outbound Q status */
#define I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS 0x01
#define I2O_EXEC_OUTBOUND_INIT_REJECTED 0x02
#define I2O_EXEC_OUTBOUND_INIT_FAILED 0x03
#define I2O_EXEC_OUTBOUND_INIT_COMPLETE 0x04
#define I2O_UTIL_NOP 0x00
/* I2O Get Status State values */
#define I2O_IOP_STATE_INITIALIZING 0x01
#define I2O_IOP_STATE_RESET 0x02
#define I2O_IOP_STATE_HOLD 0x04
#define I2O_IOP_STATE_READY 0x05
#define I2O_IOP_STATE_OPERATIONAL 0x08
#define I2O_IOP_STATE_FAILED 0x10
#define I2O_IOP_STATE_FAULTED 0x11
/* Defines for Request Status Codes: Table 3-1 Reply Status Codes. */
#define I2O_REPLY_STATUS_SUCCESS 0x00
#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01
#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
#define I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03
#define I2O_REPLY_STATUS_ERROR_DIRTY 0x04
#define I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05
#define I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER 0x06
#define I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY 0x07
#define I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER 0x08
#define I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER 0x09
#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0A
#define I2O_REPLY_STATUS_PROGRESS_REPORT 0x80
/* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.*/
#define I2O_DETAIL_STATUS_SUCCESS 0x0000
#define I2O_DETAIL_STATUS_BAD_KEY 0x0001
#define I2O_DETAIL_STATUS_CHAIN_BUFFER_TOO_LARGE 0x0002
#define I2O_DETAIL_STATUS_DEVICE_BUSY 0x0003
#define I2O_DETAIL_STATUS_DEVICE_LOCKED 0x0004
#define I2O_DETAIL_STATUS_DEVICE_NOT_AVAILABLE 0x0005
#define I2O_DETAIL_STATUS_DEVICE_RESET 0x0006
#define I2O_DETAIL_STATUS_INAPPROPRIATE_FUNCTION 0x0007
#define I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_HARD 0x0008
#define I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_SOFT 0x0009
#define I2O_DETAIL_STATUS_INVALID_INITIATOR_ADDRESS 0x000A
#define I2O_DETAIL_STATUS_INVALID_MESSAGE_FLAGS 0x000B
#define I2O_DETAIL_STATUS_INVALID_OFFSET 0x000C
#define I2O_DETAIL_STATUS_INVALID_PARAMETER 0x000D
#define I2O_DETAIL_STATUS_INVALID_REQUEST 0x000E
#define I2O_DETAIL_STATUS_INVALID_TARGET_ADDRESS 0x000F
#define I2O_DETAIL_STATUS_MESSAGE_TOO_LARGE 0x0010
#define I2O_DETAIL_STATUS_MESSAGE_TOO_SMALL 0x0011
#define I2O_DETAIL_STATUS_MISSING_PARAMETER 0x0012
#define I2O_DETAIL_STATUS_NO_SUCH_PAGE 0x0013
#define I2O_DETAIL_STATUS_REPLY_BUFFER_FULL 0x0014
#define I2O_DETAIL_STATUS_TCL_ERROR 0x0015
#define I2O_DETAIL_STATUS_TIMEOUT 0x0016
#define I2O_DETAIL_STATUS_UNKNOWN_ERROR 0x0017
#define I2O_DETAIL_STATUS_UNKNOWN_FUNCTION 0x0018
#define I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION 0x0019
#define I2O_DETAIL_STATUS_UNSUPPORTED_VERSION 0x001A
/* I2O msg header defines for VersionOffset */
#define I2OMSGVER_1_5 0x0001
#define SGL_OFFSET_0 I2OMSGVER_1_5
#define SGL_OFFSET_4 (0x0040 | I2OMSGVER_1_5)
#define TRL_OFFSET_5 (0x0050 | I2OMSGVER_1_5)
#define TRL_OFFSET_6 (0x0060 | I2OMSGVER_1_5)
/* I2O msg header defines for MsgFlags */
#define MSG_STATIC 0x0100
#define MSG_64BIT_CNTXT 0x0200
#define MSG_MULTI_TRANS 0x1000
#define MSG_FAIL 0x2000
#define MSG_LAST 0x4000
#define MSG_REPLY 0x8000
/* normal LAN request message MsgFlags and VersionOffset (0x1041) */
#define LAN_MSG_REQST (MSG_MULTI_TRANS | SGL_OFFSET_4)
/* minimum size msg */
#define THREE_WORD_MSG_SIZE 0x00030000
#define FOUR_WORD_MSG_SIZE 0x00040000
#define FIVE_WORD_MSG_SIZE 0x00050000
#define SIX_WORD_MSG_SIZE 0x00060000
#define SEVEN_WORD_MSG_SIZE 0x00070000
#define EIGHT_WORD_MSG_SIZE 0x00080000
#define NINE_WORD_MSG_SIZE 0x00090000
/* Special TID Assignments */
#define I2O_IOP_TID 0
#define I2O_HOST_TID 0xB91
/* RedCreek I2O private message codes */
#define RC_PRIVATE_GET_MAC_ADDR 0x0001/**/ /* OBSOLETE */
#define RC_PRIVATE_SET_MAC_ADDR 0x0002
#define RC_PRIVATE_GET_NIC_STATS 0x0003
#define RC_PRIVATE_GET_LINK_STATUS 0x0004
#define RC_PRIVATE_SET_LINK_SPEED 0x0005
#define RC_PRIVATE_SET_IP_AND_MASK 0x0006
/* #define RC_PRIVATE_GET_IP_AND_MASK 0x0007 *//* OBSOLETE */
#define RC_PRIVATE_GET_LINK_SPEED 0x0008
#define RC_PRIVATE_GET_FIRMWARE_REV 0x0009
/* #define RC_PRIVATE_GET_MAC_ADDR 0x000A */
#define RC_PRIVATE_GET_IP_AND_MASK 0x000B
#define RC_PRIVATE_DEBUG_MSG 0x000C
#define RC_PRIVATE_REPORT_DRIVER_CAPABILITY 0x000D
#define RC_PRIVATE_SET_PROMISCUOUS_MODE 0x000e
#define RC_PRIVATE_GET_PROMISCUOUS_MODE 0x000f
#define RC_PRIVATE_SET_BROADCAST_MODE 0x0010
#define RC_PRIVATE_GET_BROADCAST_MODE 0x0011
#define RC_PRIVATE_REBOOT 0x00FF
/* I2O message header */
typedef struct _I2O_MESSAGE_FRAME {
U8 VersionOffset;
U8 MsgFlags;
U16 MessageSize;
BF TargetAddress:I2O_TID_SZ;
BF InitiatorAddress:I2O_TID_SZ;
BF Function:I2O_FUNCTION_SZ;
U32 InitiatorContext;
/* SGL[] */
} I2O_MESSAGE_FRAME, *PI2O_MESSAGE_FRAME;
/* assumed a 16K minus 256 byte space for outbound queue message frames */
#define MSG_FRAME_SIZE 512
#define NMBR_MSG_FRAMES 30
/*
** in reserved space right after PAB in host memory is area for returning
** values from card
*/
/*
** typedef NICSTAT
**
** Data structure for NIC statistics retruned from PCI card. Data copied from
** here to user allocated RCLINKSTATS (see rclanmtl.h) structure.
*/
typedef struct tag_NicStat {
unsigned long TX_good;
unsigned long TX_maxcol;
unsigned long TX_latecol;
unsigned long TX_urun;
unsigned long TX_crs; /* lost carrier sense */
unsigned long TX_def; /* transmit deferred */
unsigned long TX_singlecol; /* single collisions */
unsigned long TX_multcol;
unsigned long TX_totcol;
unsigned long Rcv_good;
unsigned long Rcv_CRCerr;
unsigned long Rcv_alignerr;
unsigned long Rcv_reserr; /* rnr'd pkts */
unsigned long Rcv_orun;
unsigned long Rcv_cdt;
unsigned long Rcv_runt;
unsigned long dump_status; /* last field directly from the chip */
} NICSTAT, *P_NICSTAT;
#define DUMP_DONE 0x0000A005 /* completed statistical dump */
#define DUMP_CLEAR 0x0000A007 /* completed stat dump and clear counters */
static volatile int msgFlag;
/* local function prototypes */
static void ProcessOutboundI2OMsg (PPAB pPab, U32 phyMsgAddr);
static int FillI2OMsgSGLFromTCB (PU32 pMsg, PRCTCB pXmitCntrlBlock);
static int GetI2OStatus (PPAB pPab);
static int SendI2OOutboundQInitMsg (PPAB pPab);
static int SendEnableSysMsg (PPAB pPab);
/*
** =========================================================================
** RCInitI2OMsgLayer()
**
** Initialize the RedCreek I2O Module and adapter.
**
** Inputs: dev - the devices net_device struct
** TransmitCallbackFunction - address of transmit callback function
** ReceiveCallbackFunction - address of receive callback function
**
** private message block is allocated by user. It must be in locked pages.
** p_msgbuf and p_phymsgbuf point to the same location. Must be contigous
** memory block of a minimum of 16K byte and long word aligned.
** =========================================================================
*/
RC_RETURN
RCInitI2OMsgLayer (struct net_device *dev,
PFNTXCALLBACK TransmitCallbackFunction,
PFNRXCALLBACK ReceiveCallbackFunction,
PFNCALLBACK RebootCallbackFunction)
{
int result;
PPAB pPab;
U32 pciBaseAddr = dev->base_addr;
PDPA pDpa = dev->priv;
PU8 p_msgbuf = pDpa->msgbuf;
PU8 p_phymsgbuf = (PU8) pDpa->msgbuf_dma;
dprintk
("InitI2O: Adapter:0x%04ux ATU:0x%08ulx msgbuf:%p phymsgbuf:0x%08ulx\n"
"TransmitCallbackFunction:0x%08ulx ReceiveCallbackFunction:0x%08ulx\n",
pDpa->id, pciBaseAddr, p_msgbuf, (u32) p_phymsgbuf,
(u32) TransmitCallbackFunction, (u32) ReceiveCallbackFunction);
/* Check if this interface already initialized - if so, shut it down */
if (pDpa->pPab != NULL) {
printk (KERN_WARNING
"(rcpci45 driver:) pDpa->pPab [%d] != NULL\n",
pDpa->id);
/* RCResetLANCard(pDpa->id, 0, (PU32)NULL, (PFNCALLBACK)NULL); */
pDpa->pPab = NULL;
}
/* store adapter instance values in adapter block.
* Adapter block is at beginning of message buffer */
pPab = kmalloc (sizeof (*pPab), GFP_KERNEL);
if (!pPab) {
printk (KERN_ERR
"(rcpci45 driver:) RCInitI2OMsgLayer: Could not allocate memory for PAB struct!\n");
result = RC_RTN_MALLOC_ERROR;
goto err_out;
}
memset (pPab, 0, sizeof (*pPab));
pDpa->pPab = pPab;
pPab->p_atu = (PATU) pciBaseAddr;
pPab->pPci45LinBaseAddr = (PU8) pciBaseAddr;
/* Set outbound message frame addr */
pPab->outMsgBlockPhyAddr = (U32) p_phymsgbuf;
pPab->pLinOutMsgBlock = (PU8) p_msgbuf;
/* store callback function addresses */
pPab->pTransCallbackFunc = TransmitCallbackFunction;
pPab->pRecvCallbackFunc = ReceiveCallbackFunction;
pPab->pRebootCallbackFunc = RebootCallbackFunction;
pPab->pCallbackFunc = (PFNCALLBACK) NULL;
/*
** Initialize I2O IOP
*/
result = GetI2OStatus (pPab);
if (result != RC_RTN_NO_ERROR)
goto err_out_dealloc;
if (pPab->IOPState == I2O_IOP_STATE_OPERATIONAL) {
printk (KERN_INFO
"(rcpci45 driver:) pPab->IOPState == op: resetting adapter\n");
RCResetLANCard (dev, 0, (PU32) NULL, (PFNCALLBACK) NULL);
}
result = SendI2OOutboundQInitMsg (pPab);
if (result != RC_RTN_NO_ERROR)
goto err_out_dealloc;
result = SendEnableSysMsg (pPab);
if (result != RC_RTN_NO_ERROR)
goto err_out_dealloc;
return RC_RTN_NO_ERROR;
err_out_dealloc:
kfree (pPab);
err_out:
return result;
}
/*
** =========================================================================
** Disable and Enable I2O interrupts. I2O interrupts are enabled at Init time
** but can be disabled and re-enabled through these two function calls.
** Packets will still be put into any posted received buffers and packets will
** be sent through RCI2OSendPacket() functions. Disabling I2O interrupts
** will prevent hardware interrupt to host even though the outbound I2O msg
** queue is not emtpy.
** =========================================================================
*/
#define i960_OUT_POST_Q_INT_BIT 0x0008 /* bit set masks interrupts */
RC_RETURN
RCDisableI2OInterrupts (struct net_device * dev)
{
PPAB pPab = ((PDPA) dev->priv)->pPab;
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
pPab->p_atu->OutIntMask |= i960_OUT_POST_Q_INT_BIT;
return RC_RTN_NO_ERROR;
}
RC_RETURN
RCEnableI2OInterrupts (struct net_device * dev)
{
PPAB pPab = ((PDPA) dev->priv)->pPab;
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
pPab->p_atu->OutIntMask &= ~i960_OUT_POST_Q_INT_BIT;
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCI2OSendPacket()
** =========================================================================
*/
RC_RETURN
RCI2OSendPacket (struct net_device * dev, U32 InitiatorContext,
PRCTCB pTransCtrlBlock)
{
U32 msgOffset;
PU32 pMsg;
int size;
PPAB pPab = ((PDPA) dev->priv)->pPab;
dprintk ("RCI2OSendPacket()...\n");
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
/* get Inbound free Q entry - reading from In Q gets free Q entry */
/* offset to Msg Frame in PCI msg block */
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
dprintk ("RCI2OSendPacket(): Inbound Free Q empty!\n");
return RC_RTN_FREE_Q_EMPTY;
}
/* calc virtual address of msg - virtual already mapped to physical */
pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset);
size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock);
if (size == -1) { /* error processing TCB - send NOP msg */
dprintk ("RCI2OSendPacket(): Error Rrocess TCB!\n");
pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] =
I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
return RC_RTN_TCB_ERROR;
} else { /* send over msg header */
pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
pMsg[1] =
I2O_LAN_PACKET_SEND << 24 | I2O_HOST_TID << 12 |
RC_LAN_TARGET_ID;
pMsg[2] = InitiatorContext;
pMsg[3] = 0; /* batch reply */
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
return RC_RTN_NO_ERROR;
}
}
/*
** =========================================================================
** RCI2OPostRecvBuffer()
**
** inputs: pBufrCntrlBlock - pointer to buffer control block
**
** returns TRUE if successful in sending message, else FALSE.
** =========================================================================
*/
RC_RETURN
RCPostRecvBuffers (struct net_device * dev, PRCTCB pTransCtrlBlock)
{
U32 msgOffset;
PU32 pMsg;
int size;
PPAB pPab = ((PDPA) dev->priv)->pPab;
dprintk ("RCPostRecvBuffers()...\n");
/* search for DeviceHandle */
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
/* get Inbound free Q entry - reading from In Q gets free Q entry */
/* offset to Msg Frame in PCI msg block */
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
dprintk ("RCPostRecvBuffers(): Inbound Free Q empty!\n");
return RC_RTN_FREE_Q_EMPTY;
}
/* calc virtual address of msg - virtual already mapped to physical */
pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset);
size = FillI2OMsgSGLFromTCB (pMsg + 4, pTransCtrlBlock);
if (size == -1) { /* error prcessing TCB - send 3 DWORD private msg == NOP */
dprintk
("RCPostRecvBuffers(): Error Processing TCB! size = %d\n",
size);
pMsg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] =
I2O_UTIL_NOP << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
/* post to Post Q */
pPab->p_atu->InQueue = msgOffset;
return RC_RTN_TCB_ERROR;
} else { /* send over size msg header */
pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */
pMsg[1] =
I2O_LAN_RECEIVE_POST << 24 | I2O_HOST_TID << 12 |
RC_LAN_TARGET_ID;
pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
pMsg[3] = *(PU32) pTransCtrlBlock; /* number of packet buffers */
/* post to Post Q */
pPab->p_atu->InQueue = msgOffset;
return RC_RTN_NO_ERROR;
}
}
/*
** =========================================================================
** RCProcI2OMsgQ()
**
** Process I2O outbound message queue until empty.
** =========================================================================
*/
irqreturn_t
RCProcI2OMsgQ (struct net_device *dev)
{
U32 phyAddrMsg;
PU8 p8Msg;
PU32 p32;
U16 count;
PPAB pPab = ((PDPA) dev->priv)->pPab;
unsigned char debug_msg[20];
if (pPab == NULL)
return IRQ_NONE;
phyAddrMsg = pPab->p_atu->OutQueue;
while (phyAddrMsg != 0xFFFFFFFF) {
p8Msg =
pPab->pLinOutMsgBlock + (phyAddrMsg -
pPab->outMsgBlockPhyAddr);
p32 = (PU32) p8Msg;
dprintk ("msg: 0x%x 0x%x \n", p8Msg[7], p32[5]);
/* Send Packet Reply Msg */
if (I2O_LAN_PACKET_SEND == p8Msg[7]) { /* function code byte */
count = *(PU16) (p8Msg + 2);
count -= p8Msg[0] >> 4;
/* status, count, context[], adapter */
(*pPab->pTransCallbackFunc) (p8Msg[19], count, p32 + 5,
dev);
} else if (I2O_LAN_RECEIVE_POST == p8Msg[7]) { /* Receive Packet Reply Msg */
dprintk
("I2O_RECV_REPLY pPab:0x%08ulx p8Msg:0x%08ulx p32:0x%08ulx\n",
(u32) pPab, (u32) p8Msg, (u32) p32);
dprintk ("msg: 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n",
p32[0], p32[1], p32[2], p32[3]);
dprintk (" 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n",
p32[4], p32[5], p32[6], p32[7]);
dprintk (" 0x%08ulx:0X%08ulx:0x%08ulx:0x%08ulx\n",
p32[8], p32[9], p32[10], p32[11]);
/* status, count, buckets remaining, packetParmBlock, adapter */
(*pPab->pRecvCallbackFunc) (p8Msg[19], p8Msg[12],
p32[5], p32 + 6, dev);
} else if (I2O_LAN_RESET == p8Msg[7]
|| I2O_LAN_SHUTDOWN == p8Msg[7])
if (pPab->pCallbackFunc)
(*pPab->pCallbackFunc) (p8Msg[19], 0, 0, dev);
else
pPab->pCallbackFunc = (PFNCALLBACK) 1;
else if (I2O_PRIVATE == p8Msg[7]) {
dprintk ("i2o private 0x%x, 0x%x \n", p8Msg[7], p32[5]);
switch (p32[5]) {
case RC_PRIVATE_DEBUG_MSG:
msgFlag = 1;
dprintk ("Received I2O_PRIVATE msg\n");
debug_msg[15] = (p32[6] & 0xff000000) >> 24;
debug_msg[14] = (p32[6] & 0x00ff0000) >> 16;
debug_msg[13] = (p32[6] & 0x0000ff00) >> 8;
debug_msg[12] = (p32[6] & 0x000000ff);
debug_msg[11] = (p32[7] & 0xff000000) >> 24;
debug_msg[10] = (p32[7] & 0x00ff0000) >> 16;
debug_msg[9] = (p32[7] & 0x0000ff00) >> 8;
debug_msg[8] = (p32[7] & 0x000000ff);
debug_msg[7] = (p32[8] & 0xff000000) >> 24;
debug_msg[6] = (p32[8] & 0x00ff0000) >> 16;
debug_msg[5] = (p32[8] & 0x0000ff00) >> 8;
debug_msg[4] = (p32[8] & 0x000000ff);
debug_msg[3] = (p32[9] & 0xff000000) >> 24;
debug_msg[2] = (p32[9] & 0x00ff0000) >> 16;
debug_msg[1] = (p32[9] & 0x0000ff00) >> 8;
debug_msg[0] = (p32[9] & 0x000000ff);
debug_msg[16] = '\0';
dprintk ("%s", debug_msg);
break;
case RC_PRIVATE_REBOOT:
dprintk ("Adapter reboot initiated...\n");
if (pPab->pRebootCallbackFunc)
(*pPab->pRebootCallbackFunc) (0, 0, 0,
dev);
break;
default:
printk (KERN_WARNING
"(rcpci45 driver:) Unknown private I2O msg received: 0x%x\n",
p32[5]);
break;
}
}
/*
** Process other Msg's
*/
else
ProcessOutboundI2OMsg (pPab, phyAddrMsg);
/* return MFA to outbound free Q */
pPab->p_atu->OutQueue = phyAddrMsg;
/* any more msgs? */
phyAddrMsg = pPab->p_atu->OutQueue;
}
return IRQ_HANDLED;
}
/*
** =========================================================================
** Returns LAN interface statistical counters to space provided by caller at
** StatsReturnAddr. Returns 0 if success, else RC_RETURN code.
** This function will call the WaitCallback function provided by
** user while waiting for card to respond.
** =========================================================================
*/
RC_RETURN
RCGetLinkStatistics (struct net_device *dev,
P_RCLINKSTATS StatsReturnAddr,
PFNWAITCALLBACK WaitCallback)
{
U32 msgOffset;
volatile U32 timeout;
volatile PU32 pMsg;
volatile PU32 p32, pReturnAddr;
P_NICSTAT pStats;
int i;
PPAB pPab = ((PDPA) dev->priv)->pPab;
/*dprintk("Get82558Stats() StatsReturnAddr:0x%08ulx\n", StatsReturnAddr); */
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
dprintk ("Get8255XStats(): Inbound Free Q empty!\n");
return RC_RTN_FREE_Q_EMPTY;
}
/* calc virtual address of msg - virtual already mapped to physical */
pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset);
/*dprintk("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
/*dprintk("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
pMsg[3] = 0x112; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_NIC_STATS;
pMsg[5] = pPab->outMsgBlockPhyAddr;
p32 = (PU32) pPab->outMsgBlockPhyAddr;
pStats = (P_NICSTAT) pPab->pLinOutMsgBlock;
pStats->dump_status = 0xFFFFFFFF;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
timeout = 100000;
while (1) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10);
if (pStats->dump_status != 0xFFFFFFFF)
break;
if (!timeout--) {
dprintk
("RCGet82558Stats() Timeout waiting for NIC statistics\n");
return RC_RTN_MSG_REPLY_TIMEOUT;
}
}
pReturnAddr = (PU32) StatsReturnAddr;
/* copy Nic stats to user's structure */
for (i = 0; i < (int) sizeof (RCLINKSTATS) / 4; i++)
pReturnAddr[i] = p32[i];
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** Get82558LinkStatus()
** =========================================================================
*/
RC_RETURN
RCGetLinkStatus (struct net_device * dev, PU32 ReturnAddr,
PFNWAITCALLBACK WaitCallback)
{
U32 msgOffset;
volatile U32 timeout;
volatile PU32 pMsg;
volatile PU32 p32;
PPAB pPab = ((PDPA) dev->priv)->pPab;
dprintk ("Get82558LinkStatus() ReturnPhysAddr:0x%08ulx\n",
(u32) ReturnAddr);
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
dprintk ("Get82558LinkStatus(): Inbound Free Q empty!\n");
return RC_RTN_FREE_Q_EMPTY;
}
/* calc virtual address of msg - virtual already mapped to physical */
pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset);
/*dprintk("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/
/*dprintk("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
pMsg[3] = 0x112; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_STATUS;
pMsg[5] = pPab->outMsgBlockPhyAddr;
p32 = (PU32) pPab->pLinOutMsgBlock;
*p32 = 0xFFFFFFFF;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
timeout = 100000;
while (1) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10);
if (*p32 != 0xFFFFFFFF)
break;
if (!timeout--) {
dprintk ("Timeout waiting for link status\n");
return RC_RTN_MSG_REPLY_TIMEOUT;
}
}
*ReturnAddr = *p32; /* 1 = up 0 = down */
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCGetMAC()
**
** get the MAC address the adapter is listening for in non-promiscous mode.
** MAC address is in media format.
** =========================================================================
*/
RC_RETURN
RCGetMAC (struct net_device * dev, PFNWAITCALLBACK WaitCallback)
{
unsigned timeout;
U32 off;
PU8 mac = dev->dev_addr;
PU32 p;
U32 temp[2];
PPAB pPab = ((PDPA) dev->priv)->pPab;
PATU p_atu;
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
p_atu = pPab->p_atu;
p_atu->EtherMacLow = 0; /* first zero return data */
p_atu->EtherMacHi = 0;
off = p_atu->InQueue; /* get addresss of message */
if (0xFFFFFFFF == off)
return RC_RTN_FREE_Q_EMPTY;
p = (PU32) (pPab->pPci45LinBaseAddr + off);
dprintk ("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n",
(uint) p_atu, (uint) off, (uint) p);
/* setup private message */
p[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
p[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
p[2] = 0; /* initiator context */
p[3] = 0x218; /* transaction context */
p[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_MAC_ADDR;
p_atu->InQueue = off; /* send it to the I2O device */
dprintk ("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n",
(uint) p_atu, (uint) off, (uint) p);
/* wait for the rcpci45 board to update the info */
timeout = 1000000;
while (0 == p_atu->EtherMacLow) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10);
if (!timeout--) {
printk ("rc_getmac: Timeout\n");
return RC_RTN_MSG_REPLY_TIMEOUT;
}
}
/* read the mac address */
temp[0] = p_atu->EtherMacLow;
temp[1] = p_atu->EtherMacHi;
memcpy ((char *) mac, (char *) temp, 6);
dprintk ("rc_getmac: 0x%x\n", (u32) mac);
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCSetMAC()
**
** set MAC address the adapter is listening for in non-promiscous mode.
** MAC address is in media format.
** =========================================================================
*/
RC_RETURN
RCSetMAC (struct net_device * dev, PU8 mac)
{
U32 off;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
off = pPab->p_atu->InQueue; /* get addresss of message */
if (0xFFFFFFFF == off)
return RC_RTN_FREE_Q_EMPTY;
pMsg = (PU32) (pPab->pPci45LinBaseAddr + off);
/* setup private message */
pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_MAC_ADDR;
pMsg[5] = *(unsigned *) mac; /* first four bytes */
pMsg[6] = *(unsigned *) (mac + 4); /* last two bytes */
pPab->p_atu->InQueue = off; /* send it to the I2O device */
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCSetLinkSpeed()
**
** set ethernet link speed.
** input: speedControl - determines action to take as follows
** 0 = reset and auto-negotiate (NWay)
** 1 = Full Duplex 100BaseT
** 2 = Half duplex 100BaseT
** 3 = Full Duplex 10BaseT
** 4 = Half duplex 10BaseT
** all other values are ignore (do nothing)
** =========================================================================
*/
RC_RETURN
RCSetLinkSpeed (struct net_device * dev, U16 LinkSpeedCode)
{
U32 off;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
off = pPab->p_atu->InQueue; /* get addresss of message */
if (0xFFFFFFFF == off)
return RC_RTN_FREE_Q_EMPTY;
pMsg = (PU32) (pPab->pPci45LinBaseAddr + off);
/* setup private message */
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_LINK_SPEED;
pMsg[5] = LinkSpeedCode; /* link speed code */
pPab->p_atu->InQueue = off; /* send it to the I2O device */
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCSetPromiscuousMode()
**
** Defined values for Mode:
** 0 - turn off promiscuous mode
** 1 - turn on promiscuous mode
**
** =========================================================================
*/
RC_RETURN
RCSetPromiscuousMode (struct net_device * dev, U16 Mode)
{
U32 off;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
off = pPab->p_atu->InQueue; /* get addresss of message */
if (0xFFFFFFFF == off)
return RC_RTN_FREE_Q_EMPTY;
pMsg = (PU32) (pPab->pPci45LinBaseAddr + off);
/* setup private message */
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_PROMISCUOUS_MODE;
pMsg[5] = Mode; /* promiscuous mode setting */
pPab->p_atu->InQueue = off; /* send it to the device */
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCGetPromiscuousMode()
**
** get promiscuous mode setting
**
** Possible return values placed in pMode:
** 0 = promisuous mode not set
** 1 = promisuous mode is set
**
** =========================================================================
*/
RC_RETURN
RCGetPromiscuousMode (struct net_device * dev, PU32 pMode,
PFNWAITCALLBACK WaitCallback)
{
U32 msgOffset, timeout;
PU32 pMsg;
volatile PU32 p32;
PPAB pPab = ((PDPA) dev->priv)->pPab;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
printk (KERN_WARNING
"(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n");
return RC_RTN_FREE_Q_EMPTY;
}
/* calc virtual address of msg - virtual already mapped to physical */
pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset);
/* virtual pointer to return buffer - clear first two dwords */
p32 = (volatile PU32) pPab->pLinOutMsgBlock;
p32[0] = 0xff;
/* setup private message */
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_PROMISCUOUS_MODE;
/* phys address to return status - area right after PAB */
pMsg[5] = pPab->outMsgBlockPhyAddr;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
/* wait for response */
timeout = 1000000;
while (1) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10); /* please don't hog the bus!!! */
if (p32[0] != 0xff)
break;
if (!timeout--) {
dprintk
("Timeout waiting for promiscuous mode from adapter\n");
dprintk ("0x%8x\n", p32[0]);
return RC_RTN_NO_LINK_SPEED;
}
}
/* get mode */
*pMode = (U8) ((volatile PU8) p32)[0] & 0x0f;
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCSetBroadcastMode()
**
** Defined values for Mode:
** 0 - turn off promiscuous mode
** 1 - turn on promiscuous mode
**
** =========================================================================
*/
RC_RETURN
RCSetBroadcastMode (struct net_device * dev, U16 Mode)
{
U32 off;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
off = pPab->p_atu->InQueue; /* get addresss of message */
if (0xFFFFFFFF == off)
return RC_RTN_FREE_Q_EMPTY;
pMsg = (PU32) (pPab->pPci45LinBaseAddr + off);
/* setup private message */
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_BROADCAST_MODE;
pMsg[5] = Mode; /* promiscuous mode setting */
pPab->p_atu->InQueue = off; /* send it to the device */
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCGetBroadcastMode()
**
** get promiscuous mode setting
**
** Possible return values placed in pMode:
** 0 = promisuous mode not set
** 1 = promisuous mode is set
**
** =========================================================================
*/
RC_RETURN
RCGetBroadcastMode (struct net_device * dev, PU32 pMode,
PFNWAITCALLBACK WaitCallback)
{
U32 msgOffset, timeout;
PU32 pMsg;
volatile PU32 p32;
PPAB pPab = ((PDPA) dev->priv)->pPab;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
printk (KERN_WARNING
"(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n");
return RC_RTN_FREE_Q_EMPTY;
}
/* calc virtual address of msg - virtual already mapped to physical */
pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset);
/* virtual pointer to return buffer - clear first two dwords */
p32 = (volatile PU32) pPab->pLinOutMsgBlock;
p32[0] = 0xff;
/* setup private message */
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_BROADCAST_MODE;
/* phys address to return status - area right after PAB */
pMsg[5] = pPab->outMsgBlockPhyAddr;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
/* wait for response */
timeout = 1000000;
while (1) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10); /* please don't hog the bus!!! */
if (p32[0] != 0xff)
break;
if (!timeout--) {
printk (KERN_WARNING
"(rcpci45 driver:) Timeout waiting for promiscuous mode from adapter\n");
printk (KERN_WARNING "(rcpci45 driver:) 0x%8x\n",
p32[0]);
return RC_RTN_NO_LINK_SPEED;
}
}
/* get mode */
*pMode = (U8) ((volatile PU8) p32)[0] & 0x0f;
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCGetLinkSpeed()
**
** get ethernet link speed.
**
** 0 = Unknown
** 1 = Full Duplex 100BaseT
** 2 = Half duplex 100BaseT
** 3 = Full Duplex 10BaseT
** 4 = Half duplex 10BaseT
**
** =========================================================================
*/
RC_RETURN
RCGetLinkSpeed (struct net_device * dev, PU32 pLinkSpeedCode,
PFNWAITCALLBACK WaitCallback)
{
U32 msgOffset, timeout;
PU32 pMsg;
volatile PU32 p32;
U8 IOPLinkSpeed;
PPAB pPab = ((PDPA) dev->priv)->pPab;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
printk (KERN_WARNING
"(rcpci45 driver:) RCGetLinkSpeed(): Inbound Free Q empty!\n");
return RC_RTN_FREE_Q_EMPTY;
}
/* calc virtual address of msg - virtual already mapped to physical */
pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset);
/* virtual pointer to return buffer - clear first two dwords */
p32 = (volatile PU32) pPab->pLinOutMsgBlock;
p32[0] = 0xff;
/* setup private message */
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_SPEED;
/* phys address to return status - area right after PAB */
pMsg[5] = pPab->outMsgBlockPhyAddr;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
/* wait for response */
timeout = 1000000;
while (1) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10); /* please don't hog the bus!!! */
if (p32[0] != 0xff)
break;
if (!timeout--) {
dprintk ("Timeout waiting for link speed from IOP\n");
dprintk ("0x%8x\n", p32[0]);
return RC_RTN_NO_LINK_SPEED;
}
}
/* get Link speed */
IOPLinkSpeed = (U8) ((volatile PU8) p32)[0] & 0x0f;
*pLinkSpeedCode = IOPLinkSpeed;
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCReportDriverCapability(struct net_device *dev, U32 capability)
**
** Currently defined bits:
** WARM_REBOOT_CAPABLE 0x01
**
** =========================================================================
*/
RC_RETURN
RCReportDriverCapability (struct net_device * dev, U32 capability)
{
U32 off;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
off = pPab->p_atu->InQueue; /* get addresss of message */
if (0xFFFFFFFF == off)
return RC_RTN_FREE_Q_EMPTY;
pMsg = (PU32) (pPab->pPci45LinBaseAddr + off);
/* setup private message */
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] =
RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_REPORT_DRIVER_CAPABILITY;
pMsg[5] = capability;
pPab->p_atu->InQueue = off; /* send it to the I2O device */
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCGetFirmwareVer()
**
** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
**
** =========================================================================
*/
RC_RETURN
RCGetFirmwareVer (struct net_device * dev, PU8 pFirmString,
PFNWAITCALLBACK WaitCallback)
{
U32 msgOffset, timeout;
PU32 pMsg;
volatile PU32 p32;
PPAB pPab = ((PDPA) dev->priv)->pPab;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
dprintk ("RCGetFirmwareVer(): Inbound Free Q empty!\n");
return RC_RTN_FREE_Q_EMPTY;
}
/* calc virtual address of msg - virtual already mapped to physical */
pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset);
/* virtual pointer to return buffer - clear first two dwords */
p32 = (volatile PU32) pPab->pLinOutMsgBlock;
p32[0] = 0xff;
/* setup private message */
pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_FIRMWARE_REV;
/* phys address to return status - area right after PAB */
pMsg[5] = pPab->outMsgBlockPhyAddr;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
/* wait for response */
timeout = 1000000;
while (1) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10); /* please don't hog the bus!!! */
if (p32[0] != 0xff)
break;
if (!timeout--) {
dprintk ("Timeout waiting for link speed from IOP\n");
return RC_RTN_NO_FIRM_VER;
}
}
strcpy (pFirmString, (PU8) p32);
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCResetLANCard()
**
** ResourceFlags indicates whether to return buffer resource explicitly
** to host or keep and reuse.
** CallbackFunction (if not NULL) is the function to be called when
** reset is complete.
** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
** reset is done (if not NULL).
**
** =========================================================================
*/
RC_RETURN
RCResetLANCard (struct net_device * dev, U16 ResourceFlags, PU32 ReturnAddr,
PFNCALLBACK CallbackFunction)
{
unsigned long off;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
long timeout = 0;
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
off = pPab->p_atu->InQueue; /* get addresss of message */
if (0xFFFFFFFF == off)
return RC_RTN_FREE_Q_EMPTY;
pPab->pCallbackFunc = CallbackFunction;
pMsg = (PU32) (pPab->pPci45LinBaseAddr + off);
/* setup message */
pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_LAN_RESET << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
pMsg[3] = ResourceFlags << 16; /* resource flags */
pPab->p_atu->InQueue = off; /* send it to the I2O device */
if (CallbackFunction == (PFNCALLBACK) NULL) {
/* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc
or until timer goes off */
while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) {
RCProcI2OMsgQ (dev);
udelay (1000); /* please don't hog the bus!!! */
timeout++;
if (timeout > 10000) {
break;
}
}
if (ReturnAddr != (PU32) NULL)
*ReturnAddr = (U32) pPab->pCallbackFunc;
}
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCResetIOP()
**
** Send StatusGet Msg, wait for results return directly to buffer.
**
** =========================================================================
*/
RC_RETURN
RCResetIOP (struct net_device * dev)
{
U32 msgOffset, timeout;
PU32 pMsg;
PPAB pPab = ((PDPA) dev->priv)->pPab;
volatile PU32 p32;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
return RC_RTN_FREE_Q_EMPTY;
}
/* calc virtual address of msg - virtual already mapped to physical */
pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset);
pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_EXEC_IOP_RESET << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID;
pMsg[2] = 0; /* universal context */
pMsg[3] = 0; /* universal context */
pMsg[4] = 0; /* universal context */
pMsg[5] = 0; /* universal context */
/* phys address to return status - area right after PAB */
pMsg[6] = pPab->outMsgBlockPhyAddr;
pMsg[7] = 0;
pMsg[8] = 1; /* return 1 byte */
/* virtual pointer to return buffer - clear first two dwords */
p32 = (volatile PU32) pPab->pLinOutMsgBlock;
p32[0] = 0;
p32[1] = 0;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
/* wait for response */
timeout = 1000000;
while (1) {
udelay (10); /* please don't hog the bus!!! */
if (p32[0] || p32[1])
break;
if (!timeout--) {
dprintk ("RCResetIOP timeout\n");
return RC_RTN_MSG_REPLY_TIMEOUT;
}
}
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCShutdownLANCard()
**
** ResourceFlags indicates whether to return buffer resource explicitly
** to host or keep and reuse.
** CallbackFunction (if not NULL) is the function to be called when
** shutdown is complete.
** If CallbackFunction is NULL, ReturnAddr will have a 1 placed in it when
** shutdown is done (if not NULL).
**
** =========================================================================
*/
RC_RETURN
RCShutdownLANCard (struct net_device * dev, U16 ResourceFlags,
PU32 ReturnAddr, PFNCALLBACK CallbackFunction)
{
volatile PU32 pMsg;
U32 off;
PPAB pPab = ((PDPA) dev->priv)->pPab;
long timeout = 0;
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
off = pPab->p_atu->InQueue; /* get addresss of message */
if (0xFFFFFFFF == off)
return RC_RTN_FREE_Q_EMPTY;
pPab->pCallbackFunc = CallbackFunction;
pMsg = (PU32) (pPab->pPci45LinBaseAddr + off);
/* setup message */
pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] =
I2O_LAN_SHUTDOWN << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
pMsg[3] = ResourceFlags << 16; /* resource flags */
pPab->p_atu->InQueue = off; /* send it to the I2O device */
if (CallbackFunction == (PFNCALLBACK) NULL) {
/* call RCProcI2OMsgQ() until something in pPab->pCallbackFunc
or until timer goes off */
while (pPab->pCallbackFunc == (PFNCALLBACK) NULL) {
RCProcI2OMsgQ (dev);
udelay (1000); /* please don't hog the bus!!! */
timeout++;
if (timeout > 10000) {
printk (KERN_WARNING
"(rcpci45 driver:) RCShutdownLANCard(): timeout\n");
break;
}
}
if (ReturnAddr != (PU32) NULL)
*ReturnAddr = (U32) pPab->pCallbackFunc;
}
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCSetRavlinIPandMask()
**
** Set the Ravlin 45/PCI cards IP address and network mask.
**
** IP address and mask must be in network byte order.
** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
** 0x04030201 and 0x00FFFFFF on a little endian machine.
**
** =========================================================================
*/
RC_RETURN
RCSetRavlinIPandMask (struct net_device * dev, U32 ipAddr, U32 netMask)
{
volatile PU32 pMsg;
U32 off;
PPAB pPab = ((PDPA) dev->priv)->pPab;
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
off = pPab->p_atu->InQueue; /* get addresss of message */
if (0xFFFFFFFF == off)
return RC_RTN_FREE_Q_EMPTY;
pMsg = (PU32) (pPab->pPci45LinBaseAddr + off);
/* setup private message */
pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x219; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_SET_IP_AND_MASK;
pMsg[5] = ipAddr;
pMsg[6] = netMask;
pPab->p_atu->InQueue = off; /* send it to the I2O device */
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** RCGetRavlinIPandMask()
**
** get the IP address and MASK from the card
**
** =========================================================================
*/
RC_RETURN
RCGetRavlinIPandMask (struct net_device * dev, PU32 pIpAddr, PU32 pNetMask,
PFNWAITCALLBACK WaitCallback)
{
unsigned timeout;
U32 off;
PU32 pMsg, p32;
PPAB pPab = ((PDPA) dev->priv)->pPab;
PATU p_atu;
dprintk
("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n",
(u32) pIpAddr, *pIpAddr);
if (pPab == NULL)
return RC_RTN_ADPTR_NOT_REGISTERED;
p_atu = pPab->p_atu;
off = p_atu->InQueue; /* get addresss of message */
if (0xFFFFFFFF == off)
return RC_RTN_FREE_Q_EMPTY;
p32 = (volatile PU32) pPab->pLinOutMsgBlock;
*p32 = 0xFFFFFFFF;
pMsg = (PU32) (pPab->pPci45LinBaseAddr + off);
dprintk
("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n",
(u32) p_atu, off, (u32) p32);
/* setup private message */
pMsg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_PRIVATE << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID;
pMsg[2] = 0; /* initiator context */
pMsg[3] = 0x218; /* transaction context */
pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_IP_AND_MASK;
pMsg[5] = pPab->outMsgBlockPhyAddr;
p_atu->InQueue = off; /* send it to the I2O device */
dprintk
("RCGetRavlinIPandMask: p_atu 0x%08ulx, off 0x%08ulx, p32 0x%08ulx\n",
(u32) p_atu, off, (u32) p32);
/* wait for the rcpci45 board to update the info */
timeout = 100000;
while (0xffffffff == *p32) {
if (WaitCallback)
(*WaitCallback) ();
udelay (10);
if (!timeout--) {
dprintk ("RCGetRavlinIPandMask: Timeout\n");
return RC_RTN_MSG_REPLY_TIMEOUT;
}
}
dprintk
("RCGetRavlinIPandMask: after time out\np32[0] (IpAddr) 0x%08ulx, p32[1] (IPmask) 0x%08ulx\n",
p32[0], p32[1]);
/* send IP and mask to user's space */
*pIpAddr = p32[0];
*pNetMask = p32[1];
dprintk
("RCGetRavlinIPandMask: pIpAddr is 0x%08ulx, *IpAddr is 0x%08ulx\n",
(u32) pIpAddr, *pIpAddr);
return RC_RTN_NO_ERROR;
}
/*
** /////////////////////////////////////////////////////////////////////////
** /////////////////////////////////////////////////////////////////////////
**
** local functions
**
** /////////////////////////////////////////////////////////////////////////
** /////////////////////////////////////////////////////////////////////////
*/
/*
** =========================================================================
** SendI2OOutboundQInitMsg()
**
** =========================================================================
*/
static int
SendI2OOutboundQInitMsg (PPAB pPab)
{
U32 msgOffset, timeout, phyOutQFrames, i;
volatile PU32 pMsg;
volatile PU32 p32;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
dprintk ("SendI2OOutboundQInitMsg(): Inbound Free Q empty!\n");
return RC_RTN_FREE_Q_EMPTY;
}
/* calc virtual address of msg - virtual already mapped to physical */
pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset);
dprintk
("SendI2OOutboundQInitMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n",
(u32) pMsg, msgOffset);
pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6;
pMsg[1] =
I2O_EXEC_OUTBOUND_INIT << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID;
pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
pMsg[3] = 0x106; /* transaction context */
pMsg[4] = 4096; /* Host page frame size */
pMsg[5] = MSG_FRAME_SIZE << 16 | 0x80; /* outbound msg frame size and Initcode */
pMsg[6] = 0xD0000004; /* simple sgl element LE, EOB */
/* phys address to return status - area right after PAB */
pMsg[7] = pPab->outMsgBlockPhyAddr;
/* virtual pointer to return buffer - clear first two dwords */
p32 = (PU32) pPab->pLinOutMsgBlock;
p32[0] = 0;
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
/* wait for response */
timeout = 100000;
while (1) {
udelay (10); /* please don't hog the bus!!! */
if (p32[0])
break;
if (!timeout--) {
dprintk
("Timeout wait for InitOutQ InPrgress status from IOP\n");
return RC_RTN_NO_I2O_STATUS;
}
}
timeout = 100000;
while (1) {
udelay (10); /* please don't hog the bus!!! */
if (p32[0] == I2O_EXEC_OUTBOUND_INIT_COMPLETE)
break;
if (!timeout--) {
dprintk
("Timeout wait for InitOutQ Complete status from IOP\n");
return RC_RTN_NO_I2O_STATUS;
}
}
/* load PCI outbound free Q with MF physical addresses */
phyOutQFrames = pPab->outMsgBlockPhyAddr;
for (i = 0; i < NMBR_MSG_FRAMES; i++) {
pPab->p_atu->OutQueue = phyOutQFrames;
phyOutQFrames += MSG_FRAME_SIZE;
}
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** GetI2OStatus()
**
** Send StatusGet Msg, wait for results return directly to buffer.
**
** =========================================================================
*/
static int
GetI2OStatus (PPAB pPab)
{
U32 msgOffset, timeout;
PU32 pMsg;
volatile PU32 p32;
msgOffset = pPab->p_atu->InQueue;
dprintk ("GetI2OStatus: msg offset = 0x%x\n", msgOffset);
if (msgOffset == 0xFFFFFFFF) {
dprintk ("GetI2OStatus(): Inbound Free Q empty!\n");
return RC_RTN_FREE_Q_EMPTY;
}
/* calc virtual address of msg - virtual already mapped to physical */
pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset);
pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_EXEC_STATUS_GET << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID;
pMsg[2] = 0; /* universal context */
pMsg[3] = 0; /* universal context */
pMsg[4] = 0; /* universal context */
pMsg[5] = 0; /* universal context */
/* phys address to return status - area right after PAB */
pMsg[6] = pPab->outMsgBlockPhyAddr;
pMsg[7] = 0;
pMsg[8] = 88; /* return 88 bytes */
/* virtual pointer to return buffer - clear first two dwords */
p32 = (volatile PU32) pPab->pLinOutMsgBlock;
p32[0] = 0;
p32[1] = 0;
dprintk
("GetI2OStatus - pMsg:0x%08ulx, msgOffset:0x%08ulx, [1]:0x%08ulx, [6]:0x%08ulx\n",
(u32) pMsg, msgOffset, pMsg[1], pMsg[6]);
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
dprintk ("Return status to p32 = 0x%08ulx\n", (u32) p32);
/* wait for response */
timeout = 1000000;
while (1) {
udelay (10); /* please don't hog the bus!!! */
if (p32[0] && p32[1])
break;
if (!timeout--) {
dprintk ("Timeout waiting for status from IOP\n");
dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n",
p32[0], p32[1], p32[2], p32[3]);
dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n",
p32[4], p32[5], p32[6], p32[7]);
dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n",
p32[8], p32[9], p32[10], p32[11]);
return RC_RTN_NO_I2O_STATUS;
}
}
dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1],
p32[2], p32[3]);
dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5],
p32[6], p32[7]);
dprintk ("0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[8], p32[9],
p32[10], p32[11]);
/* get IOP state */
pPab->IOPState = ((volatile PU8) p32)[10];
pPab->InboundMFrameSize = ((volatile PU16) p32)[6];
dprintk ("IOP state 0x%02x InFrameSize = 0x%04x\n",
pPab->IOPState, pPab->InboundMFrameSize);
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** SendEnableSysMsg()
**
**
** =========================================================================
*/
static int
SendEnableSysMsg (PPAB pPab)
{
U32 msgOffset;
volatile PU32 pMsg;
msgOffset = pPab->p_atu->InQueue;
if (msgOffset == 0xFFFFFFFF) {
dprintk ("SendEnableSysMsg(): Inbound Free Q empty!\n");
return RC_RTN_FREE_Q_EMPTY;
}
/* calc virtual address of msg - virtual already mapped to physical */
pMsg = (PU32) (pPab->pPci45LinBaseAddr + msgOffset);
dprintk
("SendEnableSysMsg - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n",
(u32) pMsg, msgOffset);
pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0;
pMsg[1] = I2O_EXEC_SYS_ENABLE << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID;
pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
pMsg[3] = 0x110; /* transaction context */
pMsg[4] = 0x50657465; /* RedCreek Private */
/* post to Inbound Post Q */
pPab->p_atu->InQueue = msgOffset;
return RC_RTN_NO_ERROR;
}
/*
** =========================================================================
** FillI2OMsgFromTCB()
**
** inputs pMsgU32 - virtual pointer (mapped to physical) of message frame
** pXmitCntrlBlock - pointer to caller buffer control block.
**
** fills in LAN SGL after Transaction Control Word or Bucket Count.
** =========================================================================
*/
static int
FillI2OMsgSGLFromTCB (PU32 pMsgFrame, PRCTCB pTransCtrlBlock)
{
unsigned int nmbrBuffers, nmbrSeg, nmbrDwords, context, flags;
PU32 pTCB, pMsg;
/* SGL element flags */
#define EOB 0x40000000
#define LE 0x80000000
#define SIMPLE_SGL 0x10000000
#define BC_PRESENT 0x01000000
pTCB = (PU32) pTransCtrlBlock;
pMsg = pMsgFrame;
nmbrDwords = 0;
dprintk ("FillI2OMsgSGLFromTCBX\n");
dprintk ("TCB 0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n",
pTCB[0], pTCB[1], pTCB[2], pTCB[3], pTCB[4]);
dprintk ("pTCB 0x%08ulx, pMsg 0x%08ulx\n", (u32) pTCB, (u32) pMsg);
nmbrBuffers = *pTCB++;
if (!nmbrBuffers) {
return -1;
}
do {
context = *pTCB++; /* buffer tag (context) */
nmbrSeg = *pTCB++; /* number of segments */
if (!nmbrSeg) {
return -1;
}
flags = SIMPLE_SGL | BC_PRESENT;
if (1 == nmbrSeg) {
flags |= EOB;
if (1 == nmbrBuffers)
flags |= LE;
}
/* 1st SGL buffer element has context */
pMsg[0] = pTCB[0] | flags; /* send over count (segment size) */
pMsg[1] = context;
pMsg[2] = pTCB[1]; /* send buffer segment physical address */
nmbrDwords += 3;
pMsg += 3;
pTCB += 2;
if (--nmbrSeg) {
do {
flags = SIMPLE_SGL;
if (1 == nmbrSeg) {
flags |= EOB;
if (1 == nmbrBuffers)
flags |= LE;
}
pMsg[0] = pTCB[0] | flags; /* send over count */
pMsg[1] = pTCB[1]; /* send buffer segment physical address */
nmbrDwords += 2;
pTCB += 2;
pMsg += 2;
} while (--nmbrSeg);
}
} while (--nmbrBuffers);
return nmbrDwords;
}
/*
** =========================================================================
** ProcessOutboundI2OMsg()
**
** process I2O reply message
** * change to msg structure *
** =========================================================================
*/
static void
ProcessOutboundI2OMsg (PPAB pPab, U32 phyAddrMsg)
{
PU8 p8Msg;
PU32 p32;
/* U16 count; */
p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr);
p32 = (PU32) p8Msg;
dprintk
("VXD: ProcessOutboundI2OMsg - pPab 0x%08ulx, phyAdr 0x%08ulx, linAdr 0x%08ulx\n",
(u32) pPab, phyAddrMsg, (u32) p8Msg);
dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[0], p32[1],
p32[2], p32[3]);
dprintk ("msg :0x%08ulx:0x%08ulx:0x%08ulx:0x%08ulx\n", p32[4], p32[5],
p32[6], p32[7]);
if (p32[4] >> 24 != I2O_REPLY_STATUS_SUCCESS) {
dprintk ("Message reply status not success\n");
return;
}
switch (p8Msg[7]) { /* function code byte */
case I2O_EXEC_SYS_TAB_SET:
msgFlag = 1;
dprintk ("Received I2O_EXEC_SYS_TAB_SET reply\n");
break;
case I2O_EXEC_HRT_GET:
msgFlag = 1;
dprintk ("Received I2O_EXEC_HRT_GET reply\n");
break;
case I2O_EXEC_LCT_NOTIFY:
msgFlag = 1;
dprintk ("Received I2O_EXEC_LCT_NOTIFY reply\n");
break;
case I2O_EXEC_SYS_ENABLE:
msgFlag = 1;
dprintk ("Received I2O_EXEC_SYS_ENABLE reply\n");
break;
default:
dprintk ("Received UNKNOWN reply\n");
break;
}
}
/*
** *************************************************************************
**
**
** R C L A N M T L . H $Revision: 6 $
**
**
** RedCreek I2O LAN Message Transport Layer header file.
**
** ---------------------------------------------------------------------
** --- Copyright (c) 1997-1999, RedCreek Communications Inc. ---
** --- All rights reserved. ---
** ---------------------------------------------------------------------
**
** File Description:
**
** Header file for host I2O (Intelligent I/O) LAN message transport layer
** API and data types.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
** *************************************************************************
*/
#ifndef RCLANMTL_H
#define RCLANMTL_H
/* Linux specific includes */
#include <asm/types.h>
#ifdef RC_LINUX_MODULE /* linux modules need non-library version of string functions */
#include <linux/string.h>
#else
#include <string.h>
#endif
#include <linux/delay.h> /* for udelay() */
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <asm/io.h>
/* Debug stuff. Define for debug output */
#undef RCDEBUG
#ifdef RCDEBUG
#define dprintk(args...) printk(KERN_DEBUG "rc: " args)
#else
#define dprintk(args...) { }
#endif
/* Typedefs */
/* scalar data types */
typedef __u8 U8;
typedef __u16 U16;
typedef __u32 U32;
typedef __u8 *PU8;
typedef __u16 *PU16;
typedef __u32 *PU32;
typedef unsigned long BF;
typedef int RC_RETURN;
/*
** type PFNWAITCALLBACK
**
** pointer to void function - type used for WaitCallback in some functions
*/
typedef void (*PFNWAITCALLBACK) (void); /* void argument avoids compiler complaint */
/*
** type PFNTXCALLBACK
**
** Pointer to user's transmit callback function. This user function is
** called from RCProcI2OMsgQ() when packet have been transmitted from buffers
** given in the RCI2OSendPacket() function. BufferContext is a pointer to
** an array of 32 bit context values. These are the values the user assigned
** and passed in the TCB to the RCI2OSendPacket() function. PcktCount
** indicates the number of buffer context values in the BufferContext[] array.
** The User's TransmitCallbackFunction should recover (put back in free queue)
** the packet buffers associated with the buffer context values.
*/
typedef void (*PFNTXCALLBACK) (U32 Status,
U16 PcktCount,
PU32 BufferContext, struct net_device *);
/*
** type PFNRXCALLBACK
**
** Pointer to user's receive callback function. This user function
** is called from RCProcI2OMsgQ() when packets have been received into
** previously posted packet buffers throught the RCPostRecvBuffers() function.
** The received callback function should process the Packet Descriptor Block
** pointed to by PacketDescBlock. See Packet Decription Block below.
*/
typedef void (*PFNRXCALLBACK) (U32 Status,
U8 PktCount,
U32 BucketsRemain,
PU32 PacketDescBlock, struct net_device *);
/*
** type PFNCALLBACK
**
** Pointer to user's generic callback function. This user function
** can be passed to LANReset or LANShutdown and is called when the
** the reset or shutdown is complete.
** Param1 and Param2 are invalid for LANReset and LANShutdown.
*/
typedef void (*PFNCALLBACK) (U32 Status,
U32 Param1, U32 Param2, struct net_device * dev);
/*
** Message Unit CSR definitions for RedCreek PCI45 board
*/
typedef struct tag_rcatu {
volatile unsigned long APICRegSel; /* APIC Register Select */
volatile unsigned long reserved0;
volatile unsigned long APICWinReg; /* APIC Window Register */
volatile unsigned long reserved1;
volatile unsigned long InMsgReg0; /* inbound message register 0 */
volatile unsigned long InMsgReg1; /* inbound message register 1 */
volatile unsigned long OutMsgReg0; /* outbound message register 0 */
volatile unsigned long OutMsgReg1; /* outbound message register 1 */
volatile unsigned long InDoorReg; /* inbound doorbell register */
volatile unsigned long InIntStat; /* inbound interrupt status register */
volatile unsigned long InIntMask; /* inbound interrupt mask register */
volatile unsigned long OutDoorReg; /* outbound doorbell register */
volatile unsigned long OutIntStat; /* outbound interrupt status register */
volatile unsigned long OutIntMask; /* outbound interrupt mask register */
volatile unsigned long reserved2;
volatile unsigned long reserved3;
volatile unsigned long InQueue; /* inbound queue port */
volatile unsigned long OutQueue; /* outbound queue port */
volatile unsigned long reserved4;
volatile unsigned long reserver5;
/* RedCreek extension */
volatile unsigned long EtherMacLow;
volatile unsigned long EtherMacHi;
volatile unsigned long IPaddr;
volatile unsigned long IPmask;
} *PATU;
/*
** typedef PAB
**
** PCI Adapter Block - holds instance specific information.
*/
typedef struct {
PATU p_atu; /* ptr to ATU register block */
PU8 pPci45LinBaseAddr;
PU8 pLinOutMsgBlock;
U32 outMsgBlockPhyAddr;
PFNTXCALLBACK pTransCallbackFunc;
PFNRXCALLBACK pRecvCallbackFunc;
PFNCALLBACK pRebootCallbackFunc;
PFNCALLBACK pCallbackFunc;
U16 IOPState;
U16 InboundMFrameSize;
} *PPAB;
/*
* Driver Private Area, DPA.
*/
typedef struct {
U8 id; /* the AdapterID */
/* These two field are basically for the RCioctl function.
* I could not determine if they could be avoided. (RAA)*/
U32 pci_addr; /* the pci address of the adapter */
U32 pci_addr_len;
struct pci_dev *pci_dev;
struct timer_list timer; /* timer */
struct net_device_stats stats; /* the statistics structure */
unsigned long numOutRcvBuffers; /* number of outstanding receive buffers */
unsigned char shutdown;
unsigned char reboot;
unsigned char nexus;
PU8 msgbuf; /* Pointer to Lan Api Private Area */
dma_addr_t msgbuf_dma;
PPAB pPab; /* Pointer to the PCI Adapter Block */
} *PDPA;
/* PCI/45 Configuration space values */
#define RC_PCI45_VENDOR_ID 0x4916
#define RC_PCI45_DEVICE_ID 0x1960
/* RedCreek API function return values */
#define RC_RTN_NO_ERROR 0
#define RC_RTN_I2O_NOT_INIT 1
#define RC_RTN_FREE_Q_EMPTY 2
#define RC_RTN_TCB_ERROR 3
#define RC_RTN_TRANSACTION_ERROR 4
#define RC_RTN_ADAPTER_ALREADY_INIT 5
#define RC_RTN_MALLOC_ERROR 6
#define RC_RTN_ADPTR_NOT_REGISTERED 7
#define RC_RTN_MSG_REPLY_TIMEOUT 8
#define RC_RTN_NO_I2O_STATUS 9
#define RC_RTN_NO_FIRM_VER 10
#define RC_RTN_NO_LINK_SPEED 11
/* Driver capability flags */
#define WARM_REBOOT_CAPABLE 0x01
/*
** Status - Transmit and Receive callback status word
**
** A 32 bit Status is returned to the TX and RX callback functions. This value
** contains both the reply status and the detailed status as follows:
**
** 32 24 16 0
** +------+------+------------+
** | Reply| | Detailed |
** |Status| 0 | Status |
** +------+------+------------+
**
** Reply Status and Detailed Status of zero indicates No Errors.
*/
/* reply message status defines */
#define I2O_REPLY_STATUS_SUCCESS 0x00
#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0A
/* DetailedStatusCode defines */
#define I2O_LAN_DSC_SUCCESS 0x0000
#define I2O_LAN_DSC_DEVICE_FAILURE 0x0001
#define I2O_LAN_DSC_DESTINATION_NOT_FOUND 0x0002
#define I2O_LAN_DSC_TRANSMIT_ERROR 0x0003
#define I2O_LAN_DSC_TRANSMIT_ABORTED 0x0004
#define I2O_LAN_DSC_RECEIVE_ERROR 0x0005
#define I2O_LAN_DSC_RECEIVE_ABORTED 0x0006
#define I2O_LAN_DSC_DMA_ERROR 0x0007
#define I2O_LAN_DSC_BAD_PACKET_DETECTED 0x0008
#define I2O_LAN_DSC_OUT_OF_MEMORY 0x0009
#define I2O_LAN_DSC_BUCKET_OVERRUN 0x000A
#define I2O_LAN_DSC_IOP_INTERNAL_ERROR 0x000B
#define I2O_LAN_DSC_CANCELED 0x000C
#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT 0x000D
#define I2O_LAN_DSC_DESTINATION_ADDRESS_DETECTED 0x000E
#define I2O_LAN_DSC_DESTINATION_ADDRESS_OMITTED 0x000F
#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED 0x0010
/*
** Packet Description Block (Received packets)
**
** A pointer to this block structure is returned to the ReceiveCallback
** function. It contains the list of packet buffers which have either been
** filled with a packet or returned to host due to a LANReset function.
** Currently there will only be one packet per receive bucket (buffer) posted.
**
** 32 24 0
** +-----------------------+ -\
** | Buffer 1 Context | \
** +-----------------------+ \
** | 0xC0000000 | / First Bucket Descriptor
** +-----+-----------------+ /
** | 0 | packet 1 length | /
** +-----------------------+ -\
** | Buffer 2 Context | \
** +-----------------------+ \
** | 0xC0000000 | / Second Bucket Descriptor
** +-----+-----------------+ /
** | 0 | packet 2 length | /
** +-----+-----------------+ -
** | ... | ----- more bucket descriptors
** +-----------------------+ -\
** | Buffer n Context | \
** +-----------------------+ \
** | 0xC0000000 | / Last Bucket Descriptor
** +-----+-----------------+ /
** | 0 | packet n length | /
** +-----+-----------------+ -
**
** Buffer Context values are those given to adapter in the TCB on calls to
** RCPostRecvBuffers().
**
*/
/*
** Transaction Control Block (TCB) structure
**
** A structure like this is filled in by the user and passed by reference to
** RCI2OSendPacket() and RCPostRecvBuffers() functions. Minimum size is five
** 32-bit words for one buffer with one segment descriptor.
** MAX_NMBR_POST_BUFFERS_PER_MSG defines the maximum single segment buffers
** that can be described in a given TCB.
**
** 32 0
** +-----------------------+
** | Buffer Count | Number of buffers in the TCB
** +-----------------------+
** | Buffer 1 Context | first buffer reference
** +-----------------------+
** | Buffer 1 Seg Count | number of segments in buffer
** +-----------------------+
** | Buffer 1 Seg Desc 1 | first segment descriptor (size, physical address)
** +-----------------------+
** | ... | more segment descriptors (size, physical address)
** +-----------------------+
** | Buffer 1 Seg Desc n | last segment descriptor (size, physical address)
** +-----------------------+
** | Buffer 2 Context | second buffer reference
** +-----------------------+
** | Buffer 2 Seg Count | number of segments in buffer
** +-----------------------+
** | Buffer 2 Seg Desc 1 | segment descriptor (size, physical address)
** +-----------------------+
** | ... | more segment descriptors (size, physical address)
** +-----------------------+
** | Buffer 2 Seg Desc n |
** +-----------------------+
** | ... | more buffer descriptor blocks ...
** +-----------------------+
** | Buffer n Context |
** +-----------------------+
** | Buffer n Seg Count |
** +-----------------------+
** | Buffer n Seg Desc 1 |
** +-----------------------+
** | ... |
** +-----------------------+
** | Buffer n Seg Desc n |
** +-----------------------+
**
**
** A TCB for one contigous packet buffer would look like the following:
**
** 32 0
** +-----------------------+
** | 1 | one buffer in the TCB
** +-----------------------+
** | <user's Context> | user's buffer reference
** +-----------------------+
** | 1 | one segment buffer
** +-----------------------+ _
** | <buffer size> | size \
** +-----------------------+ \ segment descriptor
** | <physical address> | physical address of buffer /
** +-----------------------+ _/
**
*/
/* Buffer Segment Descriptor */
typedef struct {
U32 size;
U32 phyAddress;
} BSD, *PBSD;
typedef PU32 PRCTCB;
/*
** -------------------------------------------------------------------------
** Exported functions comprising the API to the LAN I2O message transport layer
** -------------------------------------------------------------------------
*/
/*
** InitRCI2OMsgLayer()
**
** Called once prior to using the I2O LAN message transport layer. User
** provides both the physical and virual address of a locked page buffer
** that is used as a private buffer for the RedCreek I2O message
** transport layer. This buffer must be a contigous memory block of a
** minimum of 16K bytes and long word aligned. The user also must provide
** the base address of the RedCreek PCI adapter assigned by BIOS or operating
** system.
**
** Inputs: dev - the net_device struct for the device.
** TransmitCallbackFunction - address of user's TX callback function
** ReceiveCallbackFunction - address of user's RX callback function
** RebootCallbackFunction - address of user's reboot callback function
**
*/
RC_RETURN RCInitI2OMsgLayer (struct net_device *dev,
PFNTXCALLBACK TransmitCallbackFunction,
PFNRXCALLBACK ReceiveCallbackFunction,
PFNCALLBACK RebootCallbackFunction);
/*
** RCSetRavlinIPandMask()
**
** Set the Ravlin 45/PCI cards IP address and network mask.
**
** IP address and mask must be in network byte order.
** For example, IP address 1.2.3.4 and mask 255.255.255.0 would be
** 0x04030201 and 0x00FFFFFF on a little endian machine.
**
*/
RC_RETURN RCSetRavlinIPandMask (struct net_device *dev, U32 ipAddr,
U32 netMask);
/*
** =========================================================================
** RCGetRavlinIPandMask()
**
** get the IP address and MASK from the card
**
** =========================================================================
*/
RC_RETURN
RCGetRavlinIPandMask (struct net_device *dev, PU32 pIpAddr, PU32 pNetMask,
PFNWAITCALLBACK WaitCallback);
/*
** RCProcI2OMsgQ()
**
** Called from user's polling loop or Interrupt Service Routine for a PCI
** interrupt from the RedCreek PCI adapter. User responsible for determining
** and hooking the PCI interrupt. This function will call the registered
** callback functions, TransmitCallbackFunction or ReceiveCallbackFunction,
** if a TX or RX transaction has completed.
*/
irqreturn_t RCProcI2OMsgQ (struct net_device *dev);
/*
** Disable and Enable I2O interrupts. I2O interrupts are enabled at Init time
** but can be disabled and re-enabled through these two function calls.
** Packets will still be put into any posted received buffers and packets will
** be sent through RCI2OSendPacket() functions. Disabling I2O interrupts
** will prevent hardware interrupt to host even though the outbound I2O msg
** queue is not emtpy.
*/
RC_RETURN RCEnableI2OInterrupts (struct net_device *dev);
RC_RETURN RCDisableI2OInterrupts (struct net_device *dev);
/*
** RCPostRecvBuffers()
**
** Post user's page locked buffers for use by the PCI adapter to
** return ethernet packets received from the LAN. Transaction Control Block,
** provided by user, contains buffer descriptor(s) which includes a buffer
** context number along with buffer size and physical address. See TCB above.
** The buffer context and actual packet length are returned to the
** ReceiveCallbackFunction when packets have been received. Buffers posted
** to the RedCreek adapter are considered owned by the adapter until the
** context is return to user through the ReceiveCallbackFunction.
*/
RC_RETURN RCPostRecvBuffers (struct net_device *dev,
PRCTCB pTransactionCtrlBlock);
#define MAX_NMBR_POST_BUFFERS_PER_MSG 32
/*
** RCI2OSendPacket()
**
** Send user's ethernet packet from a locked page buffer.
** Packet must have full MAC header, however without a CRC.
** Initiator context is a user provided value that is returned
** to the TransmitCallbackFunction when packet buffer is free.
** Transmit buffer are considered owned by the adapter until context's
** returned to user through the TransmitCallbackFunction.
*/
RC_RETURN RCI2OSendPacket (struct net_device *dev,
U32 context, PRCTCB pTransactionCtrlBlock);
/* Ethernet Link Statistics structure */
typedef struct tag_RC_link_stats {
U32 TX_good; /* good transmit frames */
U32 TX_maxcol; /* frames not TX due to MAX collisions */
U32 TX_latecol; /* frames not TX due to late collisions */
U32 TX_urun; /* frames not TX due to DMA underrun */
U32 TX_crs; /* frames TX with lost carrier sense */
U32 TX_def; /* frames deferred due to activity on link */
U32 TX_singlecol; /* frames TX with one and only on collision */
U32 TX_multcol; /* frames TX with more than one collision */
U32 TX_totcol; /* total collisions detected during TX */
U32 Rcv_good; /* good frames received */
U32 Rcv_CRCerr; /* frames RX and discarded with CRC errors */
U32 Rcv_alignerr; /* frames RX with alignment and CRC errors */
U32 Rcv_reserr; /* good frames discarded due to no RX buffer */
U32 Rcv_orun; /* RX frames lost due to FIFO overrun */
U32 Rcv_cdt; /* RX frames with collision during RX */
U32 Rcv_runt; /* RX frames shorter than 64 bytes */
} RCLINKSTATS, *P_RCLINKSTATS;
/*
** RCGetLinkStatistics()
**
** Returns link statistics in user's structure at address StatsReturnAddr
** If given, not NULL, the function WaitCallback is called during the wait
** loop while waiting for the adapter to respond.
*/
RC_RETURN RCGetLinkStatistics (struct net_device *dev,
P_RCLINKSTATS StatsReturnAddr,
PFNWAITCALLBACK WaitCallback);
/*
** RCGetLinkStatus()
**
** Return link status, up or down, to user's location addressed by ReturnAddr.
** If given, not NULL, the function WaitCallback is called during the wait
** loop while waiting for the adapter to respond.
*/
RC_RETURN RCGetLinkStatus (struct net_device *dev,
PU32 pReturnStatus, PFNWAITCALLBACK WaitCallback);
/* Link Status defines - value returned in pReturnStatus */
#define RC_LAN_LINK_STATUS_DOWN 0
#define RC_LAN_LINK_STATUS_UP 1
/*
** RCGetMAC()
**
** Get the current MAC address assigned to user. RedCreek Ravlin 45/PCI
** has two MAC addresses. One which is private to the PCI Card, and
** another MAC which is given to the user as its link layer MAC address. The
** adapter runs in promiscous mode because of the dual address requirement.
** The MAC address is returned to the unsigned char array pointer to by mac.
*/
RC_RETURN RCGetMAC (struct net_device *dev, PFNWAITCALLBACK WaitCallback);
/*
** RCSetMAC()
**
** Set a new user port MAC address. This address will be returned on
** subsequent RCGetMAC() calls.
*/
RC_RETURN RCSetMAC (struct net_device *dev, PU8 mac);
/*
** RCSetLinkSpeed()
**
** set adapter's link speed based on given input code.
*/
RC_RETURN RCSetLinkSpeed (struct net_device *dev, U16 LinkSpeedCode);
/* Set link speed codes */
#define LNK_SPD_AUTO_NEG_NWAY 0
#define LNK_SPD_100MB_FULL 1
#define LNK_SPD_100MB_HALF 2
#define LNK_SPD_10MB_FULL 3
#define LNK_SPD_10MB_HALF 4
/*
** RCGetLinkSpeed()
**
** Return link speed code.
*/
/* Return link speed codes */
#define LNK_SPD_UNKNOWN 0
#define LNK_SPD_100MB_FULL 1
#define LNK_SPD_100MB_HALF 2
#define LNK_SPD_10MB_FULL 3
#define LNK_SPD_10MB_HALF 4
RC_RETURN
RCGetLinkSpeed (struct net_device *dev, PU32 pLinkSpeedCode,
PFNWAITCALLBACK WaitCallback);
/*
** =========================================================================
** RCSetPromiscuousMode(struct net_device *dev, U16 Mode)
**
** Defined values for Mode:
** 0 - turn off promiscuous mode
** 1 - turn on promiscuous mode
**
** =========================================================================
*/
#define PROMISCUOUS_MODE_OFF 0
#define PROMISCUOUS_MODE_ON 1
RC_RETURN RCSetPromiscuousMode (struct net_device *dev, U16 Mode);
/*
** =========================================================================
** RCGetPromiscuousMode(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallback)
**
** get promiscuous mode setting
**
** Possible return values placed in pMode:
** 0 = promisuous mode not set
** 1 = promisuous mode is set
**
** =========================================================================
*/
RC_RETURN
RCGetPromiscuousMode (struct net_device *dev, PU32 pMode,
PFNWAITCALLBACK WaitCallback);
/*
** =========================================================================
** RCSetBroadcastMode(struct net_device *dev, U16 Mode)
**
** Defined values for Mode:
** 0 - turn off promiscuous mode
** 1 - turn on promiscuous mode
**
** =========================================================================
*/
#define BROADCAST_MODE_OFF 0
#define BROADCAST_MODE_ON 1
RC_RETURN RCSetBroadcastMode (struct net_device *dev, U16 Mode);
/*
** =========================================================================
** RCGetBroadcastMode(struct net_device *dev, PU32 pMode, PFNWAITCALLBACK WaitCallback)
**
** get broadcast mode setting
**
** Possible return values placed in pMode:
** 0 = broadcast mode not set
** 1 = broadcast mode is set
**
** =========================================================================
*/
RC_RETURN
RCGetBroadcastMode (struct net_device *dev, PU32 pMode,
PFNWAITCALLBACK WaitCallback);
/*
** =========================================================================
** RCReportDriverCapability(struct net_device *dev, U32 capability)
**
** Currently defined bits:
** WARM_REBOOT_CAPABLE 0x01
**
** =========================================================================
*/
RC_RETURN RCReportDriverCapability (struct net_device *dev, U32 capability);
/*
** RCGetFirmwareVer()
**
** Return firmware version in the form "SoftwareVersion : Bt BootVersion"
**
** WARNING: user's space pointed to by pFirmString should be at least 60 bytes.
*/
RC_RETURN
RCGetFirmwareVer (struct net_device *dev, PU8 pFirmString,
PFNWAITCALLBACK WaitCallback);
/*
** ----------------------------------------------
** LAN adapter Reset and Shutdown functions
** ----------------------------------------------
*/
/* resource flag bit assignments for RCResetLANCard() & RCShutdownLANCard() */
#define RC_RESOURCE_RETURN_POSTED_RX_BUCKETS 0x0001
#define RC_RESOURCE_RETURN_PEND_TX_BUFFERS 0x0002
/*
** RCResetLANCard()
**
** Reset LAN card operation. Causes a software reset of the ethernet
** controller and restarts the command and receive units. Depending on
** the ResourceFlags given, the buffers are either returned to the
** host with reply status of I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER and
** detailed status of I2O_LAN_DSC_CANCELED (new receive buffers must be
** posted after issuing this) OR the buffers are kept and reused by
** the ethernet controller. If CallbackFunction is not NULL, the function
** will be called when the reset is complete. If the CallbackFunction is
** NULL,a 1 will be put into the ReturnAddr after waiting for the reset
** to complete (please disable I2O interrupts during this method).
** Any outstanding transmit or receive buffers that are complete will be
** returned via the normal reply messages before the requested resource
** buffers are returned.
** A call to RCPostRecvBuffers() is needed to return the ethernet to full
** operation if the receive buffers were returned during LANReset.
** Note: The IOP status is not affected by a LAN reset.
*/
RC_RETURN RCResetLANCard (struct net_device *dev, U16 ResourceFlags,
PU32 ReturnAddr, PFNCALLBACK CallbackFunction);
/*
** RCShutdownLANCard()
**
** Shutdown LAN card operation and put into an idle (suspended) state.
** The LAN card is restarted with RCResetLANCard() function.
** Depending on the ResourceFlags given, the buffers are either returned
** to the host with reply status of I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER
** and detailed status of I2O_LAN_DSC_CANCELED (new receive buffers must be
** posted after issuing this) OR the buffers are kept and reused by
** the ethernet controller. If CallbackFunction is not NULL, the function
** will be called when the reset is complete. If the CallbackFunction is
** NULL,a 1 will be put into the ReturnAddr after waiting for the reset
** to complete (please disable I2O interrupts during this method).
** Any outstanding transmit or receive buffers that are complete will be
** returned via the normal reply messages before the requested resource
** buffers are returned.
** Note: The IOP status is not affected by a LAN shutdown.
*/
RC_RETURN
RCShutdownLANCard (struct net_device *dev, U16 ResourceFlags, PU32 ReturnAddr,
PFNCALLBACK CallbackFunction);
/*
** RCResetIOP();
** Initializes IOPState to I2O_IOP_STATE_RESET.
** Stops access to outbound message Q.
** Discards any outstanding transmit or posted receive buffers.
** Clears outbound message Q.
*/
RC_RETURN RCResetIOP (struct net_device *dev);
#endif /* RCLANMTL_H */
/*
**
** RCpci45.c
**
**
**
** ---------------------------------------------------------------------
** --- Copyright (c) 1998, 1999, RedCreek Communications Inc. ---
** --- All rights reserved. ---
** ---------------------------------------------------------------------
**
** Written by Pete Popov and Brian Moyle.
**
** Known Problems
**
** None known at this time.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
** Francois Romieu, Apr 2003: Converted to pci DMA mapping API.
**
** Pete Popov, Oct 2001: Fixed a few bugs to make the driver functional
** again. Note that this card is not supported or manufactured by
** RedCreek anymore.
**
** Rasmus Andersen, December 2000: Converted to new PCI API and general
** cleanup.
**
** Pete Popov, January 11,99: Fixed a couple of 2.1.x problems
** (virt_to_bus() not called), tested it under 2.2pre5 (as a module), and
** added a #define(s) to enable the use of the same file for both, the 2.0.x
** kernels as well as the 2.1.x.
**
** Ported to 2.1.x by Alan Cox 1998/12/9.
**
** Sometime in mid 1998, written by Pete Popov and Brian Moyle.
**
***************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/in.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/timer.h>
#include <asm/irq.h> /* For NR_IRQS only. */
#include <asm/bitops.h>
#include <asm/uaccess.h>
static char version[] __initdata =
"RedCreek Communications PCI linux driver version 2.21\n";
#define RC_LINUX_MODULE
#include "rclanmtl.h"
#include "rcif.h"
#define RUN_AT(x) (jiffies + (x))
#define NEW_MULTICAST
#define MAX_ETHER_SIZE 1520
#define MAX_NMBR_RCV_BUFFERS 96
#define RC_POSTED_BUFFERS_LOW_MARK MAX_NMBR_RCV_BUFFERS-16
#define BD_SIZE 3 /* Bucket Descriptor size */
#define BD_LEN_OFFSET 2 /* Bucket Descriptor offset to length field */
/* RedCreek LAN device Target ID */
#define RC_LAN_TARGET_ID 0x10
/* RedCreek's OSM default LAN receive Initiator */
#define DEFAULT_RECV_INIT_CONTEXT 0xA17
/* minimum msg buffer size needed by the card
* Note that the size of this buffer is hard code in the
* ipsec card's firmware. Thus, the size MUST be a minimum
* of 16K. Otherwise the card will end up using memory
* that does not belong to it.
*/
#define MSG_BUF_SIZE 16384
/* 2003/04/20: I don't know about the hardware ability but the driver won't
* play safe with 64 bit addressing and DAC without NETIF_F_HIGHDMA doesn't
* really make sense anyway. Let's play safe - romieu.
*/
#define RCPCI45_DMA_MASK ((u64) 0xffffffff)
static U32 DriverControlWord;
static void rc_timer (unsigned long);
static int RCopen (struct net_device *);
static int RC_xmit_packet (struct sk_buff *, struct net_device *);
static irqreturn_t RCinterrupt (int, void *, struct pt_regs *);
static int RCclose (struct net_device *dev);
static struct net_device_stats *RCget_stats (struct net_device *);
static int RCioctl (struct net_device *, struct ifreq *, int);
static int RCconfig (struct net_device *, struct ifmap *);
static void RCxmit_callback (U32, U16, PU32, struct net_device *);
static void RCrecv_callback (U32, U8, U32, PU32, struct net_device *);
static void RCreset_callback (U32, U32, U32, struct net_device *);
static void RCreboot_callback (U32, U32, U32, struct net_device *);
static int RC_allocate_and_post_buffers (struct net_device *, int);
static struct pci_device_id rcpci45_pci_table[] = {
{ PCI_VENDOR_ID_REDCREEK, PCI_DEVICE_ID_RC45, PCI_ANY_ID, PCI_ANY_ID,},
{}
};
MODULE_DEVICE_TABLE (pci, rcpci45_pci_table);
MODULE_LICENSE("GPL");
static void __devexit
rcpci45_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata (pdev);
PDPA pDpa = dev->priv;
RCResetIOP (dev);
unregister_netdev (dev);
free_irq (dev->irq, dev);
iounmap ((void *) dev->base_addr);
pci_release_regions (pdev);
pci_free_consistent (pdev, MSG_BUF_SIZE, pDpa->msgbuf,
pDpa->msgbuf_dma);
if (pDpa->pPab)
kfree (pDpa->pPab);
free_netdev (dev);
pci_set_drvdata (pdev, NULL);
}
static int
rcpci45_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
unsigned long *vaddr;
PDPA pDpa;
int error;
static int card_idx = -1;
struct net_device *dev;
unsigned long pci_start, pci_len;
card_idx++;
/*
* Allocate and fill new device structure.
* We need enough for struct net_device plus DPA plus the LAN
* API private area, which requires a minimum of 16KB. The top
* of the allocated area will be assigned to struct net_device;
* the next chunk will be assigned to DPA; and finally, the rest
* will be assigned to the LAN API layer.
*/
dev = alloc_etherdev(sizeof(*pDpa));
if (!dev) {
printk (KERN_ERR
"(rcpci45 driver:) alloc_etherdev alloc failed\n");
error = -ENOMEM;
goto err_out;
}
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
error = pci_enable_device (pdev);
if (error) {
printk (KERN_ERR
"(rcpci45 driver:) %d: pci enable device error\n",
card_idx);
goto err_out;
}
pci_start = pci_resource_start (pdev, 0);
pci_len = pci_resource_len (pdev, 0);
printk("pci_start %lx pci_len %lx\n", pci_start, pci_len);
pci_set_drvdata (pdev, dev);
pDpa = dev->priv;
pDpa->id = card_idx;
pDpa->pci_dev = pdev;
pDpa->pci_addr = pci_start;
if (!pci_start || !(pci_resource_flags (pdev, 0) & IORESOURCE_MEM)) {
printk (KERN_ERR
"(rcpci45 driver:) No PCI mem resources! Aborting\n");
error = -EBUSY;
goto err_out_free_dev;
}
/*
* pDpa->msgbuf is where the card will dma the I2O
* messages. Thus, we need contiguous physical pages of memory.
* 2003/04/20: pci_alloc_consistent() provides well over the needed
* alignment on a 256 bytes boundary for the LAN API private area.
* Thus it isn't needed anymore to align it by hand.
*/
pDpa->msgbuf = pci_alloc_consistent (pdev, MSG_BUF_SIZE,
&pDpa->msgbuf_dma);
if (!pDpa->msgbuf) {
printk (KERN_ERR "(rcpci45 driver:) \
Could not allocate %d byte memory for the \
private msgbuf!\n", MSG_BUF_SIZE);
error = -ENOMEM;
goto err_out_free_dev;
}
/* The adapter is accessible through memory-access read/write, not
* I/O read/write. Thus, we need to map it to some virtual address
* area in order to access the registers as normal memory.
*/
error = pci_request_regions (pdev, dev->name);
if (error)
goto err_out_free_msgbuf;
error = pci_set_dma_mask (pdev, RCPCI45_DMA_MASK);
if (error) {
printk (KERN_ERR
"(rcpci45 driver:) pci_set_dma_mask failed!\n");
goto err_out_free_region;
}
vaddr = (ulong *) ioremap (pci_start, pci_len);
if (!vaddr) {
printk (KERN_ERR
"(rcpci45 driver:) \
Unable to remap address range from %lu to %lu\n",
pci_start, pci_start + pci_len);
error = -EIO;
goto err_out_free_region;
}
dev->base_addr = (unsigned long) vaddr;
dev->irq = pdev->irq;
dev->open = &RCopen;
dev->hard_start_xmit = &RC_xmit_packet;
dev->stop = &RCclose;
dev->get_stats = &RCget_stats;
dev->do_ioctl = &RCioctl;
dev->set_config = &RCconfig;
if ((error = register_netdev(dev)))
goto err_out_iounmap;
return 0; /* success */
err_out_iounmap:
iounmap((void *) dev->base_addr);
err_out_free_region:
pci_release_regions (pdev);
err_out_free_msgbuf:
pci_free_consistent (pdev, MSG_BUF_SIZE, pDpa->msgbuf,
pDpa->msgbuf_dma);
err_out_free_dev:
free_netdev (dev);
err_out:
card_idx--;
return error;
}
static struct pci_driver rcpci45_driver = {
.name = "rcpci45",
.id_table = rcpci45_pci_table,
.probe = rcpci45_init_one,
.remove = __devexit_p(rcpci45_remove_one),
};
static int __init
rcpci_init_module (void)
{
int rc = pci_module_init (&rcpci45_driver);
if (!rc)
printk (KERN_ERR "%s", version);
return rc;
}
static int
RCopen (struct net_device *dev)
{
int post_buffers = MAX_NMBR_RCV_BUFFERS;
PDPA pDpa = dev->priv;
int count = 0;
int requested = 0;
int error;
if (pDpa->nexus) {
/* This is not the first time RCopen is called. Thus,
* the interface was previously opened and later closed
* by RCclose(). RCclose() does a Shutdown; to wake up
* the adapter, a reset is mandatory before we can post
* receive buffers. However, if the adapter initiated
* a reboot while the interface was closed -- and interrupts
* were turned off -- we need will need to reinitialize
* the adapter, rather than simply waking it up.
*/
printk (KERN_INFO "Waking up adapter...\n");
RCResetLANCard (dev, 0, 0, 0);
} else {
pDpa->nexus = 1;
/*
* RCInitI2OMsgLayer is done only once, unless the
* adapter was sent a warm reboot
*/
error = RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback,
(PFNRXCALLBACK) RCrecv_callback,
(PFNCALLBACK) RCreboot_callback);
if (error) {
printk (KERN_ERR "%s: Unable to init msg layer (%x)\n",
dev->name, error);
goto err_out;
}
if ((error = RCGetMAC (dev, NULL))) {
printk (KERN_ERR "%s: Unable to get adapter MAC\n",
dev->name);
goto err_out;
}
}
/* Request a shared interrupt line. */
error = request_irq (dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev);
if (error) {
printk (KERN_ERR "%s: unable to get IRQ %d\n",
dev->name, dev->irq);
goto err_out;
}
DriverControlWord |= WARM_REBOOT_CAPABLE;
RCReportDriverCapability (dev, DriverControlWord);
printk (KERN_INFO "%s: RedCreek Communications IPSEC VPN adapter\n",
dev->name);
RCEnableI2OInterrupts (dev);
while (post_buffers) {
if (post_buffers > MAX_NMBR_POST_BUFFERS_PER_MSG)
requested = MAX_NMBR_POST_BUFFERS_PER_MSG;
else
requested = post_buffers;
count = RC_allocate_and_post_buffers (dev, requested);
if (count < requested) {
/*
* Check to see if we were able to post
* any buffers at all.
*/
if (post_buffers == MAX_NMBR_RCV_BUFFERS) {
printk (KERN_ERR "%s: \
unable to allocate any buffers\n",
dev->name);
goto err_out_free_irq;
}
printk (KERN_WARNING "%s: \
unable to allocate all requested buffers\n", dev->name);
break; /* we'll try to post more buffers later */
} else
post_buffers -= count;
}
pDpa->numOutRcvBuffers = MAX_NMBR_RCV_BUFFERS - post_buffers;
pDpa->shutdown = 0; /* just in case */
netif_start_queue (dev);
return 0;
err_out_free_irq:
free_irq (dev->irq, dev);
err_out:
return error;
}
static int
RC_xmit_packet (struct sk_buff *skb, struct net_device *dev)
{
PDPA pDpa = dev->priv;
singleTCB tcb;
psingleTCB ptcb = &tcb;
RC_RETURN status = 0;
netif_stop_queue (dev);
if (pDpa->shutdown || pDpa->reboot) {
printk ("RC_xmit_packet: tbusy!\n");
return 1;
}
/*
* The user is free to reuse the TCB after RCI2OSendPacket()
* returns, since the function copies the necessary info into its
* own private space. Thus, our TCB can be a local structure.
* The skb, on the other hand, will be freed up in our interrupt
* handler.
*/
ptcb->bcount = 1;
/*
* we'll get the context when the adapter interrupts us to tell us that
* the transmission is done. At that time, we can free skb.
*/
ptcb->b.context = (U32) skb;
ptcb->b.scount = 1;
ptcb->b.size = skb->len;
ptcb->b.addr = pci_map_single(pDpa->pci_dev, skb->data, skb->len,
PCI_DMA_TODEVICE);
if ((status = RCI2OSendPacket (dev, (U32) NULL, (PRCTCB) ptcb))
!= RC_RTN_NO_ERROR) {
printk ("%s: send error 0x%x\n", dev->name, (uint) status);
return 1;
} else {
dev->trans_start = jiffies;
netif_wake_queue (dev);
}
/*
* That's it!
*/
return 0;
}
/*
* RCxmit_callback()
*
* The transmit callback routine. It's called by RCProcI2OMsgQ()
* because the adapter is done with one or more transmit buffers and
* it's returning them to us, or we asked the adapter to return the
* outstanding transmit buffers by calling RCResetLANCard() with
* RC_RESOURCE_RETURN_PEND_TX_BUFFERS flag.
* All we need to do is free the buffers.
*/
static void
RCxmit_callback (U32 Status,
U16 PcktCount, PU32 BufferContext, struct net_device *dev)
{
struct sk_buff *skb;
PDPA pDpa = dev->priv;
if (!pDpa) {
printk (KERN_ERR "%s: Fatal Error in xmit callback, !pDpa\n",
dev->name);
return;
}
if (Status != I2O_REPLY_STATUS_SUCCESS)
printk (KERN_INFO "%s: xmit_callback: Status = 0x%x\n",
dev->name, (uint) Status);
if (pDpa->shutdown || pDpa->reboot)
printk (KERN_INFO "%s: xmit callback: shutdown||reboot\n",
dev->name);
while (PcktCount--) {
skb = (struct sk_buff *) (BufferContext[0]);
BufferContext++;
pci_unmap_single(pDpa->pci_dev, BufferContext[1], skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb_irq (skb);
}
netif_wake_queue (dev);
}
static void
RCreset_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev)
{
PDPA pDpa = dev->priv;
printk ("RCreset_callback Status 0x%x\n", (uint) Status);
/*
* Check to see why we were called.
*/
if (pDpa->shutdown) {
printk (KERN_INFO "%s: shutting down interface\n",
dev->name);
pDpa->shutdown = 0;
pDpa->reboot = 0;
} else if (pDpa->reboot) {
printk (KERN_INFO "%s: reboot, shutdown adapter\n",
dev->name);
/*
* We don't set any of the flags in RCShutdownLANCard()
* and we don't pass a callback routine to it.
* The adapter will have already initiated the reboot by
* the time the function returns.
*/
RCDisableI2OInterrupts (dev);
RCShutdownLANCard (dev, 0, 0, 0);
printk (KERN_INFO "%s: scheduling timer...\n", dev->name);
init_timer (&pDpa->timer);
pDpa->timer.expires = RUN_AT ((40 * HZ) / 10); /* 4 sec. */
pDpa->timer.data = (unsigned long) dev;
pDpa->timer.function = &rc_timer; /* timer handler */
add_timer (&pDpa->timer);
}
}
static void
RCreboot_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev)
{
PDPA pDpa = dev->priv;
printk (KERN_INFO "%s: reboot: rcv buffers outstanding = %d\n",
dev->name, (uint) pDpa->numOutRcvBuffers);
if (pDpa->shutdown) {
printk (KERN_INFO "%s: skip reboot, shutdown initiated\n",
dev->name);
return;
}
pDpa->reboot = 1;
/*
* OK, we reset the adapter and ask it to return all
* outstanding transmit buffers as well as the posted
* receive buffers. When the adapter is done returning
* those buffers, it will call our RCreset_callback()
* routine. In that routine, we'll call RCShutdownLANCard()
* to tell the adapter that it's OK to start the reboot and
* schedule a timer callback routine to execute 3 seconds
* later; this routine will reinitialize the adapter at that time.
*/
RCResetLANCard (dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS |
RC_RESOURCE_RETURN_PEND_TX_BUFFERS, 0,
(PFNCALLBACK) RCreset_callback);
}
/*
* RCrecv_callback()
*
* The receive packet callback routine. This is called by
* RCProcI2OMsgQ() after the adapter posts buffers which have been
* filled (one ethernet packet per buffer).
*/
static void
RCrecv_callback (U32 Status,
U8 PktCount,
U32 BucketsRemain,
PU32 PacketDescBlock, struct net_device *dev)
{
U32 len, count;
PDPA pDpa = dev->priv;
struct sk_buff *skb;
singleTCB tcb;
psingleTCB ptcb = &tcb;
ptcb->bcount = 1;
if ((pDpa->shutdown || pDpa->reboot) && !Status)
printk (KERN_INFO "%s: shutdown||reboot && !Status (%d)\n",
dev->name, PktCount);
if ((Status != I2O_REPLY_STATUS_SUCCESS) || pDpa->shutdown) {
/*
* Free whatever buffers the adapter returned, but don't
* pass them to the kernel.
*/
if (!pDpa->shutdown && !pDpa->reboot)
printk (KERN_INFO "%s: recv error status = 0x%x\n",
dev->name, (uint) Status);
else
printk (KERN_DEBUG "%s: Returning %d buffs stat 0x%x\n",
dev->name, PktCount, (uint) Status);
/*
* TO DO: check the nature of the failure and put the
* adapter in failed mode if it's a hard failure.
* Send a reset to the adapter and free all outstanding memory.
*/
if (PacketDescBlock) {
while (PktCount--) {
skb = (struct sk_buff *) PacketDescBlock[0];
dev_kfree_skb (skb);
pDpa->numOutRcvBuffers--;
/* point to next context field */
PacketDescBlock += BD_SIZE;
}
}
return;
} else {
while (PktCount--) {
skb = (struct sk_buff *) PacketDescBlock[0];
len = PacketDescBlock[2];
skb->dev = dev;
skb_put (skb, len); /* adjust length and tail */
skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb); /* send the packet to the kernel */
dev->last_rx = jiffies;
pDpa->numOutRcvBuffers--;
/* point to next context field */
PacketDescBlock += BD_SIZE;
}
}
/*
* Replenish the posted receive buffers.
* DO NOT replenish buffers if the driver has already
* initiated a reboot or shutdown!
*/
if (!pDpa->shutdown && !pDpa->reboot) {
count = RC_allocate_and_post_buffers (dev,
MAX_NMBR_RCV_BUFFERS -
pDpa->numOutRcvBuffers);
pDpa->numOutRcvBuffers += count;
}
}
/*
* RCinterrupt()
*
* Interrupt handler.
* This routine sets up a couple of pointers and calls
* RCProcI2OMsgQ(), which in turn process the message and
* calls one of our callback functions.
*/
static irqreturn_t
RCinterrupt (int irq, void *dev_id, struct pt_regs *regs)
{
PDPA pDpa;
struct net_device *dev = dev_id;
pDpa = dev->priv;
if (pDpa->shutdown)
printk (KERN_DEBUG "%s: shutdown, service irq\n",
dev->name);
return RCProcI2OMsgQ (dev);
}
#define REBOOT_REINIT_RETRY_LIMIT 4
static void
rc_timer (unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
PDPA pDpa = dev->priv;
int init_status;
static int retry;
int post_buffers = MAX_NMBR_RCV_BUFFERS;
int count = 0;
int requested = 0;
if (pDpa->reboot) {
init_status =
RCInitI2OMsgLayer (dev, (PFNTXCALLBACK) RCxmit_callback,
(PFNRXCALLBACK) RCrecv_callback,
(PFNCALLBACK) RCreboot_callback);
switch (init_status) {
case RC_RTN_NO_ERROR:
pDpa->reboot = 0;
pDpa->shutdown = 0; /* just in case */
RCReportDriverCapability (dev, DriverControlWord);
RCEnableI2OInterrupts (dev);
if (!(dev->flags & IFF_UP)) {
retry = 0;
return;
}
while (post_buffers) {
if (post_buffers >
MAX_NMBR_POST_BUFFERS_PER_MSG)
requested =
MAX_NMBR_POST_BUFFERS_PER_MSG;
else
requested = post_buffers;
count =
RC_allocate_and_post_buffers (dev,
requested);
post_buffers -= count;
if (count < requested)
break;
}
pDpa->numOutRcvBuffers =
MAX_NMBR_RCV_BUFFERS - post_buffers;
printk ("Initialization done.\n");
netif_wake_queue (dev);
retry = 0;
return;
case RC_RTN_FREE_Q_EMPTY:
retry++;
printk (KERN_WARNING "%s inbound free q empty\n",
dev->name);
break;
default:
retry++;
printk (KERN_WARNING "%s bad stat after reboot: %d\n",
dev->name, init_status);
break;
}
if (retry > REBOOT_REINIT_RETRY_LIMIT) {
printk (KERN_WARNING "%s unable to reinitialize adapter after reboot\n", dev->name);
printk (KERN_WARNING "%s shutting down interface\n", dev->name);
RCDisableI2OInterrupts (dev);
dev->flags &= ~IFF_UP;
} else {
printk (KERN_INFO "%s: rescheduling timer...\n",
dev->name);
init_timer (&pDpa->timer);
pDpa->timer.expires = RUN_AT ((40 * HZ) / 10);
pDpa->timer.data = (unsigned long) dev;
pDpa->timer.function = &rc_timer;
add_timer (&pDpa->timer);
}
} else
printk (KERN_WARNING "%s: unexpected timer irq\n", dev->name);
}
static int
RCclose (struct net_device *dev)
{
PDPA pDpa = dev->priv;
printk("RCclose\n");
netif_stop_queue (dev);
if (pDpa->reboot) {
printk (KERN_INFO "%s skipping reset -- adapter already in reboot mode\n", dev->name);
dev->flags &= ~IFF_UP;
pDpa->shutdown = 1;
return 0;
}
pDpa->shutdown = 1;
/*
* We can't allow the driver to be unloaded until the adapter returns
* all posted receive buffers. It doesn't hurt to tell the adapter
* to return all posted receive buffers and outstanding xmit buffers,
* even if there are none.
*/
RCShutdownLANCard (dev, RC_RESOURCE_RETURN_POSTED_RX_BUCKETS |
RC_RESOURCE_RETURN_PEND_TX_BUFFERS, 0,
(PFNCALLBACK) RCreset_callback);
dev->flags &= ~IFF_UP;
return 0;
}
static struct net_device_stats *
RCget_stats (struct net_device *dev)
{
RCLINKSTATS RCstats;
PDPA pDpa = dev->priv;
if (!pDpa) {
return 0;
} else if (!(dev->flags & IFF_UP)) {
return 0;
}
memset (&RCstats, 0, sizeof (RCLINKSTATS));
if ((RCGetLinkStatistics (dev, &RCstats, (void *) 0)) ==
RC_RTN_NO_ERROR) {
/* total packets received */
pDpa->stats.rx_packets = RCstats.Rcv_good
/* total packets transmitted */;
pDpa->stats.tx_packets = RCstats.TX_good;
pDpa->stats.rx_errors = RCstats.Rcv_CRCerr +
RCstats.Rcv_alignerr + RCstats.Rcv_reserr +
RCstats.Rcv_orun + RCstats.Rcv_cdt + RCstats.Rcv_runt;
pDpa->stats.tx_errors = RCstats.TX_urun + RCstats.TX_crs +
RCstats.TX_def + RCstats.TX_totcol;
/*
* This needs improvement.
*/
pDpa->stats.rx_dropped = 0; /* no space in linux buffers */
pDpa->stats.tx_dropped = 0; /* no space available in linux */
pDpa->stats.multicast = 0; /* multicast packets received */
pDpa->stats.collisions = RCstats.TX_totcol;
/* detailed rx_errors: */
pDpa->stats.rx_length_errors = 0;
pDpa->stats.rx_over_errors = RCstats.Rcv_orun;
pDpa->stats.rx_crc_errors = RCstats.Rcv_CRCerr;
pDpa->stats.rx_frame_errors = 0;
pDpa->stats.rx_fifo_errors = 0;
pDpa->stats.rx_missed_errors = 0;
/* detailed tx_errors */
pDpa->stats.tx_aborted_errors = 0;
pDpa->stats.tx_carrier_errors = 0;
pDpa->stats.tx_fifo_errors = 0;
pDpa->stats.tx_heartbeat_errors = 0;
pDpa->stats.tx_window_errors = 0;
return ((struct net_device_stats *) &(pDpa->stats));
}
return 0;
}
static int
RCioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{
RCuser_struct RCuser;
PDPA pDpa = dev->priv;
if (!capable (CAP_NET_ADMIN))
return -EPERM;
switch (cmd) {
case RCU_PROTOCOL_REV:
/*
* Assign user protocol revision, to tell user-level
* controller program whether or not it's in sync.
*/
rq->ifr_ifru.ifru_data = (caddr_t) USER_PROTOCOL_REV;
break;
case RCU_COMMAND:
{
if (copy_from_user
(&RCuser, rq->ifr_data, sizeof (RCuser)))
return -EFAULT;
dprintk ("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd);
switch (RCuser.cmd) {
case RCUC_GETFWVER:
RCUD_GETFWVER = &RCuser.RCUS_GETFWVER;
RCGetFirmwareVer (dev,
(PU8) & RCUD_GETFWVER->
FirmString, NULL);
break;
case RCUC_GETINFO:
RCUD_GETINFO = &RCuser.RCUS_GETINFO;
RCUD_GETINFO->mem_start = dev->base_addr;
RCUD_GETINFO->mem_end =
dev->base_addr + pDpa->pci_addr_len;
RCUD_GETINFO->base_addr = pDpa->pci_addr;
RCUD_GETINFO->irq = dev->irq;
break;
case RCUC_GETIPANDMASK:
RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK;
RCGetRavlinIPandMask (dev,
(PU32) &
RCUD_GETIPANDMASK->IpAddr,
(PU32) &
RCUD_GETIPANDMASK->
NetMask, NULL);
break;
case RCUC_GETLINKSTATISTICS:
RCUD_GETLINKSTATISTICS =
&RCuser.RCUS_GETLINKSTATISTICS;
RCGetLinkStatistics (dev,
(P_RCLINKSTATS) &
RCUD_GETLINKSTATISTICS->
StatsReturn, NULL);
break;
case RCUC_GETLINKSTATUS:
RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS;
RCGetLinkStatus (dev,
(PU32) & RCUD_GETLINKSTATUS->
ReturnStatus, NULL);
break;
case RCUC_GETMAC:
RCUD_GETMAC = &RCuser.RCUS_GETMAC;
RCGetMAC (dev, NULL);
memcpy(RCUD_GETMAC, dev->dev_addr, 8);
break;
case RCUC_GETPROM:
RCUD_GETPROM = &RCuser.RCUS_GETPROM;
RCGetPromiscuousMode (dev,
(PU32) & RCUD_GETPROM->
PromMode, NULL);
break;
case RCUC_GETBROADCAST:
RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST;
RCGetBroadcastMode (dev,
(PU32) & RCUD_GETBROADCAST->
BroadcastMode, NULL);
break;
case RCUC_GETSPEED:
if (!(dev->flags & IFF_UP)) {
return -ENODATA;
}
RCUD_GETSPEED = &RCuser.RCUS_GETSPEED;
RCGetLinkSpeed (dev,
(PU32) & RCUD_GETSPEED->
LinkSpeedCode, NULL);
break;
case RCUC_SETIPANDMASK:
RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK;
RCSetRavlinIPandMask (dev,
(U32) RCUD_SETIPANDMASK->
IpAddr,
(U32) RCUD_SETIPANDMASK->
NetMask);
break;
case RCUC_SETMAC:
RCSetMAC (dev, (PU8) & RCUD_SETMAC->mac);
break;
case RCUC_SETSPEED:
RCUD_SETSPEED = &RCuser.RCUS_SETSPEED;
RCSetLinkSpeed (dev,
(U16) RCUD_SETSPEED->
LinkSpeedCode);
break;
case RCUC_SETPROM:
RCUD_SETPROM = &RCuser.RCUS_SETPROM;
RCSetPromiscuousMode (dev,
(U16) RCUD_SETPROM->
PromMode);
break;
case RCUC_SETBROADCAST:
RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST;
RCSetBroadcastMode (dev,
(U16) RCUD_SETBROADCAST->
BroadcastMode);
break;
default:
RCUD_DEFAULT = &RCuser.RCUS_DEFAULT;
RCUD_DEFAULT->rc = 0x11223344;
break;
}
if (copy_to_user (rq->ifr_data, &RCuser,
sizeof (RCuser)))
return -EFAULT;
break;
} /* RCU_COMMAND */
default:
rq->ifr_ifru.ifru_data = (caddr_t) 0x12345678;
return -EINVAL;
}
return 0;
}
static int
RCconfig (struct net_device *dev, struct ifmap *map)
{
/*
* To be completed ...
*/
return 0;
if (dev->flags & IFF_UP) /* can't act on a running interface */
return -EBUSY;
/* Don't allow changing the I/O address */
if (map->base_addr != dev->base_addr) {
printk (KERN_WARNING "%s Change I/O address not implemented\n",
dev->name);
return -EOPNOTSUPP;
}
return 0;
}
static void __exit
rcpci_cleanup_module (void)
{
pci_unregister_driver (&rcpci45_driver);
}
module_init (rcpci_init_module);
module_exit (rcpci_cleanup_module);
static int
RC_allocate_and_post_buffers (struct net_device *dev, int numBuffers)
{
int i;
PU32 p;
psingleB pB;
struct sk_buff *skb;
PDPA pDpa = dev->priv;
RC_RETURN status;
U32 res = 0;
if (!numBuffers)
return 0;
else if (numBuffers > MAX_NMBR_POST_BUFFERS_PER_MSG) {
printk (KERN_ERR "%s: Too many buffers requested!\n",
dev->name);
numBuffers = 32;
}
p = (PU32) kmalloc (sizeof (U32) + numBuffers * sizeof (singleB),
GFP_DMA | GFP_ATOMIC);
if (!p) {
printk (KERN_WARNING "%s unable to allocate TCB\n",
dev->name);
goto out;
}
p[0] = 0; /* Buffer Count */
pB = (psingleB) ((U32) p + sizeof (U32));/* point to the first buffer */
for (i = 0; i < numBuffers; i++) {
skb = dev_alloc_skb (MAX_ETHER_SIZE + 2);
if (!skb) {
printk (KERN_WARNING
"%s: unable to allocate enough skbs!\n",
dev->name);
goto err_out_unmap;
}
skb_reserve (skb, 2); /* Align IP on 16 byte boundaries */
pB->context = (U32) skb;
pB->scount = 1; /* segment count */
pB->size = MAX_ETHER_SIZE;
pB->addr = pci_map_single(pDpa->pci_dev, skb->data,
MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE);
p[0]++;
pB++;
}
if ((status = RCPostRecvBuffers (dev, (PRCTCB) p)) != RC_RTN_NO_ERROR) {
printk (KERN_WARNING "%s: Post buffer failed, error 0x%x\n",
dev->name, status);
goto err_out_unmap;
}
out_free:
res = p[0];
kfree (p);
out:
return (res); /* return the number of posted buffers */
err_out_unmap:
for (; p[0] > 0; p[0]--) {
--pB;
skb = (struct sk_buff *) pB->context;
pci_unmap_single(pDpa->pci_dev, pB->addr, MAX_ETHER_SIZE,
PCI_DMA_FROMDEVICE);
dev_kfree_skb (skb);
}
goto out_free;
}
......@@ -818,7 +818,7 @@ static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
* @dev: Device whose IDENTIFY DEVICE results we will examine
* @s: string into which data is output
* @ofs: offset into identify device page
* @len: length of string to return
* @len: length of string to return. must be an even number.
*
* The strings in the IDENTIFY DEVICE page are broken up into
* 16-bit chunks. Run through the string, and output each
......@@ -847,29 +847,6 @@ void ata_dev_id_string(struct ata_device *dev, unsigned char *s,
}
}
/**
* ata_dev_parse_strings - Store useful IDENTIFY DEVICE page strings
* @dev: Device whose IDENTIFY DEVICE page info we use
*
* We store 'vendor' and 'product' strings read from the device,
* for later use in the SCSI simulator's INQUIRY data.
*
* Set these strings here, in the case of 'product', using
* data read from the ATA IDENTIFY DEVICE page.
*
* LOCKING:
* caller.
*/
static void ata_dev_parse_strings(struct ata_device *dev)
{
assert (dev->class == ATA_DEV_ATA);
memcpy(dev->vendor, "ATA ", 8);
ata_dev_id_string(dev, dev->product, ATA_ID_PROD_OFS,
sizeof(dev->product));
}
/**
* __ata_dev_select - Select device 0/1 on ATA bus
* @ap: ATA channel to manipulate
......@@ -1127,8 +1104,6 @@ static void ata_dev_identify(struct ata_port *ap, unsigned int device)
ata_dump_id(dev);
ata_dev_parse_strings(dev);
/* ATA-specific feature tests */
if (dev->class == ATA_DEV_ATA) {
if (!ata_id_is_ata(dev)) /* sanity check */
......@@ -2346,7 +2321,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
if (cmd) {
if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) {
if (qc->flags & ATA_QCFLAG_ATAPI)
if (is_atapi_taskfile(&qc->tf))
cmd->result = SAM_STAT_CHECK_CONDITION;
else
ata_to_sense_error(qc);
......@@ -2659,6 +2634,8 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
unsigned int handled = 0;
switch (qc->tf.protocol) {
/* BMDMA completion */
case ATA_PROT_DMA:
case ATA_PROT_ATAPI_DMA:
if (ap->flags & ATA_FLAG_MMIO) {
......@@ -2677,8 +2654,16 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
handled = 1;
break;
/* command completion, but no data xfer */
/* FIXME: a shared interrupt _will_ cause a non-data command
* to be completed prematurely, with an error.
*
* This doesn't matter right now, since we aren't sending
* non-data commands down this pipe except in development
* situations.
*/
case ATA_PROT_ATAPI:
case ATA_PROT_NODATA: /* command completion, but no data xfer */
case ATA_PROT_NODATA:
status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
ata_qc_complete(qc, status);
......@@ -3525,3 +3510,4 @@ EXPORT_SYMBOL_GPL(ata_scsi_error);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
EXPORT_SYMBOL_GPL(ata_scsi_release);
EXPORT_SYMBOL_GPL(ata_host_intr);
EXPORT_SYMBOL_GPL(ata_dev_id_string);
......@@ -498,7 +498,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
unsigned int buflen)
{
const u8 hdr[] = {
struct ata_device *dev = args->dev;
u8 hdr[] = {
TYPE_DISK,
0,
0x5, /* claim SPC-3 version compatibility */
......@@ -506,14 +508,20 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
96 - 4
};
/* set scsi removeable (RMB) bit per ata bit */
if (ata_id_removeable(dev))
hdr[1] |= (1 << 7);
VPRINTK("ENTER\n");
memcpy(rbuf, hdr, sizeof(hdr));
if (buflen > 36) {
memcpy(&rbuf[8], args->dev->vendor, 8);
memcpy(&rbuf[16], args->dev->product, 16);
memcpy(&rbuf[32], DRV_VERSION, 4);
memcpy(&rbuf[8], "ATA ", 8);
ata_dev_id_string(dev, &rbuf[16], ATA_ID_PROD_OFS, 16);
ata_dev_id_string(dev, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
if (rbuf[32] == 0 || rbuf[32] == ' ')
memcpy(&rbuf[32], "n/a ", 4);
}
if (buflen > 63) {
......@@ -687,9 +695,17 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last,
static unsigned int ata_msense_caching(struct ata_device *dev, u8 **ptr_io,
const u8 *last)
{
u8 page[7] = { 0xf, 0, 0x10, 0, 0x8, 0xa, 0 };
if (dev->flags & ATA_DFLAG_WCACHE)
page[6] = 0x4;
u8 page[] = {
0x8, /* page code */
0x12, /* page length */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 zeroes */
0, 0, 0, 0, 0, 0, 0, 0 /* 8 zeroes */
};
if (ata_id_wcache_enabled(dev))
page[2] |= (1 << 2); /* write cache enable */
if (!ata_id_rahead_enabled(dev))
page[12] |= (1 << 5); /* disable read ahead */
ata_msense_push(ptr_io, last, page, sizeof(page));
return sizeof(page);
......@@ -715,6 +731,31 @@ static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
return sizeof(page);
}
/**
* ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
* @dev: Device associated with this MODE SENSE command
* @ptr_io: (input/output) Location to store more output data
* @last: End of output data buffer
*
* Generate a generic MODE SENSE r/w error recovery page.
*
* LOCKING:
* None.
*/
static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
{
const u8 page[] = {
0x1, /* page code */
0xa, /* page length */
(1 << 7) | (1 << 6), /* note auto r/w reallocation */
0, 0, 0, 0, 0, 0, 0, 0, 0 /* 9 zeroes */
};
ata_msense_push(ptr_io, last, page, sizeof(page));
return sizeof(page);
}
/**
* ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands
* @args: Port / device / SCSI command of interest.
......@@ -754,6 +795,10 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
last = rbuf + buflen - 1;
switch(scsicmd[2] & 0x3f) {
case 0x01: /* r/w error recovery */
output_len += ata_msense_rw_recovery(&p, last);
break;
case 0x08: /* caching */
output_len += ata_msense_caching(dev, &p, last);
break;
......@@ -764,6 +809,7 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
}
case 0x3f: /* all pages */
output_len += ata_msense_rw_recovery(&p, last);
output_len += ata_msense_caching(dev, &p, last);
output_len += ata_msense_ctl_mode(&p, last);
break;
......@@ -804,20 +850,23 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
VPRINTK("ENTER\n");
n_sectors--; /* one off */
n_sectors--; /* ATA TotalUserSectors - 1 */
tmp = n_sectors; /* note: truncates, if lba48 */
if (args->cmd->cmnd[0] == READ_CAPACITY) {
/* sector count, 32-bit */
rbuf[0] = tmp >> (8 * 3);
rbuf[1] = tmp >> (8 * 2);
rbuf[2] = tmp >> (8 * 1);
rbuf[3] = tmp;
/* sector size */
tmp = ATA_SECT_SIZE;
rbuf[6] = tmp >> 8;
rbuf[7] = tmp;
} else {
/* sector count, 64-bit */
rbuf[2] = n_sectors >> (8 * 7);
rbuf[3] = n_sectors >> (8 * 6);
rbuf[4] = n_sectors >> (8 * 5);
......@@ -827,6 +876,7 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
rbuf[8] = tmp >> (8 * 1);
rbuf[9] = tmp;
/* sector size */
tmp = ATA_SECT_SIZE;
rbuf[12] = tmp >> 8;
rbuf[13] = tmp;
......@@ -901,8 +951,6 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
{
struct scsi_cmnd *cmd = qc->scsicmd;
qc->flags |= ATA_QCFLAG_ATAPI;
qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
if (cmd->sc_data_direction == SCSI_DATA_WRITE) {
qc->tf.flags |= ATA_TFLAG_WRITE;
......@@ -1106,7 +1154,11 @@ static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
args.done = done;
switch(scsicmd[0]) {
case TEST_UNIT_READY: /* FIXME: correct? */
/* no-op's, complete with success */
case REZERO_UNIT:
case SEEK_6:
case SEEK_10:
case TEST_UNIT_READY:
case FORMAT_UNIT: /* FIXME: correct? */
case SEND_DIAGNOSTIC: /* FIXME: correct? */
ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
......
......@@ -36,8 +36,6 @@ struct ata_scsi_args {
};
/* libata-core.c */
extern void ata_dev_id_string(struct ata_device *dev, unsigned char *s,
unsigned int ofs, unsigned int len);
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev);
extern int ata_qc_issue(struct ata_queued_cmd *qc);
......
......@@ -276,8 +276,14 @@ static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
{
unsigned int n, quirks = 0;
const char *s = &dev->product[0];
unsigned int len = strnlen(s, sizeof(dev->product));
unsigned char model_num[40];
const char *s;
unsigned int len;
ata_dev_id_string(dev, model_num, ATA_ID_PROD_OFS,
sizeof(model_num));
s = &model_num[0];
len = strnlen(s, sizeof(model_num));
/* ATAPI specifies that empty space is blank-filled; remove blanks */
while ((len > 0) && (s[len - 1] == ' '))
......
......@@ -38,6 +38,7 @@ enum {
ATA_ID_WORDS = 256,
ATA_ID_PROD_OFS = 27,
ATA_ID_FW_REV_OFS = 23,
ATA_ID_SERNO_OFS = 10,
ATA_ID_MAJOR_VER = 80,
ATA_ID_PIO_MODES = 64,
......@@ -103,6 +104,7 @@ enum {
ATA_REG_IRQ = ATA_REG_NSECT,
/* ATA device commands */
ATA_CMD_CHK_POWER = 0xE5, /* check power mode */
ATA_CMD_EDD = 0x90, /* execute device diagnostic */
ATA_CMD_FLUSH = 0xE7,
ATA_CMD_FLUSH_EXT = 0xEA,
......@@ -200,11 +202,14 @@ struct ata_taskfile {
};
#define ata_id_is_ata(dev) (((dev)->id[0] & (1 << 15)) == 0)
#define ata_id_rahead_enabled(dev) ((dev)->id[85] & (1 << 6))
#define ata_id_wcache_enabled(dev) ((dev)->id[85] & (1 << 5))
#define ata_id_has_lba48(dev) ((dev)->id[83] & (1 << 10))
#define ata_id_has_wcache(dev) ((dev)->id[82] & (1 << 5))
#define ata_id_has_pm(dev) ((dev)->id[82] & (1 << 3))
#define ata_id_has_lba(dev) ((dev)->id[49] & (1 << 8))
#define ata_id_has_dma(dev) ((dev)->id[49] & (1 << 9))
#define ata_id_removeable(dev) ((dev)->id[0] & (1 << 7))
#define ata_id_u32(dev,n) \
(((u32) (dev)->id[(n) + 1] << 16) | ((u32) (dev)->id[(n)]))
#define ata_id_u64(dev,n) \
......@@ -213,4 +218,10 @@ struct ata_taskfile {
((u64) dev->id[(n) + 1] << 16) | \
((u64) dev->id[(n) + 0]) )
static inline int is_atapi_taskfile(struct ata_taskfile *tf)
{
return (tf->protocol == ATA_PROT_ATAPI) ||
(tf->protocol == ATA_PROT_ATAPI_DMA);
}
#endif /* __LINUX_ATA_H__ */
......@@ -111,7 +111,6 @@ enum {
ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */
ATA_QCFLAG_DMA = (1 << 2), /* data delivered via DMA */
ATA_QCFLAG_ATAPI = (1 << 3), /* is ATAPI packet command? */
ATA_QCFLAG_SG = (1 << 4), /* have s/g table? */
/* various lengths of time */
......@@ -260,12 +259,6 @@ struct ata_device {
unsigned int pio_mode;
unsigned int udma_mode;
unsigned char vendor[8]; /* space-padded, not ASCIIZ */
unsigned char product[32]; /* WARNING: shorter than
* ATAPI7 spec size, 40 ASCII
* characters
*/
/* cache info about current transfer mode */
u8 xfer_protocol; /* taskfile xfer protocol */
u8 read_cmd; /* opcode to use on read */
......@@ -398,6 +391,8 @@ extern int ata_port_start (struct ata_port *ap);
extern void ata_port_stop (struct ata_port *ap);
extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
extern void ata_fill_sg(struct ata_queued_cmd *qc);
extern void ata_dev_id_string(struct ata_device *dev, unsigned char *s,
unsigned int ofs, unsigned int len);
extern void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc);
extern void ata_bmdma_start_mmio (struct ata_queued_cmd *qc);
extern void ata_bmdma_setup_pio (struct ata_queued_cmd *qc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment