patch-2.1.132 linux/drivers/net/rrunner.c
Next file: linux/drivers/net/rrunner.h
Previous file: linux/drivers/net/rcpci45.c
Back to the patch index
Back to the overall index
- Lines: 447
- Date:
Thu Dec 17 09:04:49 1998
- Orig file:
v2.1.131/linux/drivers/net/rrunner.c
- Orig date:
Fri Oct 9 13:27:09 1998
diff -u --recursive --new-file v2.1.131/linux/drivers/net/rrunner.c linux/drivers/net/rrunner.c
@@ -39,9 +39,11 @@
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/uaccess.h>
#include "rrunner.h"
+
/*
* Implementation notes:
*
@@ -57,7 +59,7 @@
* stack will need to know about I/O vectors or something similar.
*/
-static const char *version = "rrunner.c: v0.06 09/02/98 Jes Sorensen (Jes.Sorensen@cern.ch)\n";
+static const char *version = "rrunner.c: v0.09 12/14/98 Jes Sorensen (Jes.Sorensen@cern.ch)\n";
static unsigned int read_eeprom(struct rr_private *rrpriv,
unsigned long offset,
@@ -68,6 +70,14 @@
static int rr_load_firmware(struct device *dev);
+/*
+ * These are checked at init time to see if they are at least 256KB
+ * and increased to 256KB if they are not. This is done to avoid ending
+ * up with socket buffers smaller than the MTU size,
+ */
+extern __u32 sysctl_wmem_max;
+extern __u32 sysctl_rmem_max;
+
__initfunc(int rr_hippi_probe (struct device *dev))
{
static int i = 0;
@@ -116,6 +126,9 @@
if (dev == NULL)
break;
+ if (!dev->priv)
+ dev->priv = kmalloc(sizeof(*rrpriv), GFP_KERNEL);
+
rrpriv = (struct rr_private *)dev->priv;
/* Read register base address from
@@ -194,12 +207,8 @@
rr_init(dev);
boards_found++;
-
- /*
- * This is bollocks, but we need to tell the net-init
- * code that it shall go for the next device.
- */
dev->base_addr = 0;
+ dev = NULL;
}
/*
@@ -347,6 +356,7 @@
return 0;
}
+
/*
* Read a string from the EEPROM.
*/
@@ -356,18 +366,21 @@
unsigned long length)
{
struct rr_regs *regs = rrpriv->regs;
- u32 misc, io, i;
+ u32 misc, io, host, i;
io = regs->ExtIo;
regs->ExtIo = 0;
misc = regs->LocalCtrl;
regs->LocalCtrl = 0;
+ host = regs->HostCtrl;
+ regs->HostCtrl |= HALT_NIC;
for (i = 0; i < length; i++){
regs->WinBase = (EEPROM_BASE + ((offset+i) << 3));
buf[i] = (regs->WinData >> 24) & 0xff;
}
+ regs->HostCtrl = host;
regs->LocalCtrl = misc;
regs->ExtIo = io;
@@ -391,6 +404,58 @@
}
+/*
+ * Write a string to the EEPROM.
+ *
+ * This is only called when the firmware is not running.
+ */
+static unsigned int write_eeprom(struct rr_private *rrpriv,
+ unsigned long offset,
+ unsigned char *buf,
+ unsigned long length)
+{
+ struct rr_regs *regs = rrpriv->regs;
+ u32 misc, io, data, i, j, ready, error = 0;
+
+ io = regs->ExtIo;
+ regs->ExtIo = 0;
+ misc = regs->LocalCtrl;
+ regs->LocalCtrl = ENABLE_EEPROM_WRITE;
+
+ for (i = 0; i < length; i++){
+ regs->WinBase = (EEPROM_BASE + ((offset+i) << 3));
+ data = buf[i] << 24;
+ /*
+ * Only try to write the data if it is not the same
+ * value already.
+ */
+ if ((regs->WinData & 0xff000000) != data){
+ regs->WinData = data;
+ ready = 0;
+ j = 0;
+ mb();
+ while(!ready){
+ udelay(1000);
+ if ((regs->WinData & 0xff000000) == data)
+ ready = 1;
+ if (j++ > 5000){
+ printk("data mismatch: %08x, "
+ "WinData %08x\n", data,
+ regs->WinData);
+ ready = 1;
+ error = 1;
+ }
+ }
+ }
+ }
+
+ regs->LocalCtrl = misc;
+ regs->ExtIo = io;
+
+ return error;
+}
+
+
__initfunc(static int rr_init(struct device *dev))
{
struct rr_private *rrpriv;
@@ -404,8 +469,13 @@
if (rev > 0x00020024)
printk(" Firmware revision: %i.%i.%i\n", (rev >> 16),
((rev >> 8) & 0xff), (rev & 0xff));
- else{
- printk(" Firmware revision too old: %i.%i.%i, please upgrade to 2.0.37 or later.\n",
+ else if (rev >= 0x00020000) {
+ printk(" Firmware revision: %i.%i.%i (2.0.37 or "
+ "later is recommended)\n", (rev >> 16),
+ ((rev >> 8) & 0xff), (rev & 0xff));
+ }else{
+ printk(" Firmware revision too old: %i.%i.%i, please "
+ "upgrade to 2.0.37 or later.\n",
(rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff));
return -EFAULT;
@@ -416,6 +486,18 @@
sram_size = read_eeprom_word(rrpriv, (void *)8);
printk(" SRAM size 0x%06x\n", sram_size);
+ if (sysctl_rmem_max < 262144){
+ printk(" Receive socket buffer limit too low (%i), "
+ "setting to 262144\n", sysctl_rmem_max);
+ sysctl_rmem_max = 262144;
+ }
+
+ if (sysctl_wmem_max < 262144){
+ printk(" Transmit socket buffer limit too low (%i), "
+ "setting to 262144\n", sysctl_wmem_max);
+ sysctl_wmem_max = 262144;
+ }
+
return 0;
}
@@ -574,7 +656,9 @@
}
#endif
dev->tbusy = 0;
+#if 0
dev->interrupt = 0;
+#endif
dev->start = 1;
return 0;
}
@@ -590,9 +674,6 @@
struct rr_private *rrpriv;
struct rr_regs *regs;
u32 tmp, eidx;
-#if 0
- short i;
-#endif
rrpriv = (struct rr_private *)dev->priv;
regs = rrpriv->regs;
@@ -710,7 +791,8 @@
if (pkt_len < PKT_COPY_THRESHOLD) {
skb = alloc_skb(pkt_len, GFP_ATOMIC);
if (skb == NULL){
- printk("%s: Out of memory deferring packet\n", dev->name);
+ printk("%s: Out of memory deferring "
+ "packet\n", dev->name);
rrpriv->stats.rx_dropped++;
goto defer;
}else
@@ -720,14 +802,16 @@
}else{
struct sk_buff *newskb;
- newskb = alloc_skb(dev->mtu + HIPPI_HLEN, GFP_ATOMIC);
+ newskb = alloc_skb(dev->mtu + HIPPI_HLEN,
+ GFP_ATOMIC);
if (newskb){
skb = rrpriv->rx_skbuff[index];
skb_put(skb, pkt_len);
rrpriv->rx_skbuff[index] = newskb;
rrpriv->rx_ring[index].addr = virt_to_bus(newskb->data);
}else{
- printk("%s: Out of memory, deferring packet\n", dev->name);
+ printk("%s: Out of memory, deferring "
+ "packet\n", dev->name);
rrpriv->stats.rx_dropped++;
goto defer;
}
@@ -766,18 +850,15 @@
rrpriv = (struct rr_private *)dev->priv;
regs = rrpriv->regs;
- if (!(regs->HostCtrl & RR_INT)){
-#if 0
- /* These are harmless */
- printk("%s: spurious interrupt detected\n", dev->name);
-#endif
+ if (!(regs->HostCtrl & RR_INT))
return;
- }
+#if 0
if (test_and_set_bit(0, (void*)&dev->interrupt) != 0) {
printk("%s: Re-entering the interrupt handler.\n", dev->name);
return;
}
+#endif
spin_lock_irqsave(&rrpriv->lock, flags);
@@ -828,7 +909,9 @@
spin_unlock_irqrestore(&rrpriv->lock, flags);
+#if 0
dev->interrupt = 0;
+#endif
}
@@ -844,7 +927,7 @@
regs->HostCtrl |= (HALT_NIC | RR_CLEAR_INT);
#endif
- if (request_irq(dev->irq, rr_interrupt, 0, rrpriv->name, dev))
+ if (request_irq(dev->irq, rr_interrupt, SA_SHIRQ, rrpriv->name, dev))
{
printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
dev->name, dev->irq);
@@ -858,7 +941,9 @@
rr_init1(dev);
dev->tbusy = 0;
+#if 0
dev->interrupt = 0;
+#endif
dev->start = 1;
MOD_INC_USE_COUNT;
@@ -942,6 +1027,12 @@
rrpriv = (struct rr_private *)dev->priv;
regs = rrpriv->regs;
+ /*
+ * Lock to make sure we are not cleaning up while another CPU
+ * handling interrupts.
+ */
+ spin_lock(&rrpriv->lock);
+
tmp = regs->HostCtrl;
if (tmp & NIC_HALTED){
printk("%s: NIC already halted\n", dev->name);
@@ -950,11 +1041,7 @@
tmp |= HALT_NIC;
regs->HostCtrl = tmp;
- /*
- * Lock to make sure we are not cleaning up while another CPU
- * handling interrupts.
- */
- spin_lock(&rrpriv->lock);
+ rrpriv->fw_running = 0;
regs->TxPi = 0;
regs->IpRxPi = 0;
@@ -1080,9 +1167,6 @@
{
struct rr_private *rrpriv;
struct rr_regs *regs;
-#if 0
- unsigned long flags;
-#endif
int i, j;
u32 localctrl, eptr, sptr, segptr, len, tmp;
u32 p2len, p2size, nr_seg, revision, io, sram_size;
@@ -1179,30 +1263,117 @@
static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd)
{
struct rr_private *rrpriv;
+ unsigned char *image, *oldimage;
+ unsigned int i;
+ int error = -EOPNOTSUPP;
rrpriv = (struct rr_private *)dev->priv;
+ spin_lock(&rrpriv->lock);
+
switch(cmd){
+ case SIOCRRGFW:
+ if (!suser()){
+ error = -EPERM;
+ goto out;
+ }
+
+ if (rrpriv->fw_running){
+ printk("%s: Firmware already running\n", dev->name);
+ error = -EPERM;
+ goto out;
+ }
+
+ image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL);
+ if (!image){
+ printk(KERN_ERR "%s: Unable to allocate memory "
+ "for EEPROM image\n", dev->name);
+ error = -ENOMEM;
+ goto out;
+ }
+ i = read_eeprom(rrpriv, 0, image, EEPROM_BYTES);
+ if (i != EEPROM_BYTES){
+ kfree(image);
+ printk(KERN_ERR "%s: Error reading EEPROM\n",
+ dev->name);
+ error = -EFAULT;
+ goto out;
+ }
+ error = copy_to_user(rq->ifr_data, image, EEPROM_BYTES);
+ if (error)
+ error = -EFAULT;
+ kfree(image);
+ break;
case SIOCRRPFW:
- if (!suser())
- return -EPERM;
+ if (!suser()){
+ error = -EPERM;
+ goto out;
+ }
if (rrpriv->fw_running){
- printk("%s: firmware already running\n", dev->name);
- return -EPERM;
+ printk("%s: Firmware already running\n", dev->name);
+ error = -EPERM;
+ goto out;
+ }
+
+ image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL);
+ if (!image){
+ printk(KERN_ERR "%s: Unable to allocate memory "
+ "for EEPROM image\n", dev->name);
+ error = -ENOMEM;
+ goto out;
+ }
+
+ oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL);
+ if (!image){
+ printk(KERN_ERR "%s: Unable to allocate memory "
+ "for old EEPROM image\n", dev->name);
+ error = -ENOMEM;
+ goto out;
}
- printk("%s: updating firmware", dev->name);
+
+ error = copy_from_user(image, rq->ifr_data, EEPROM_BYTES);
+ if (error)
+ error = -EFAULT;
+
+ printk("%s: Updating EEPROM firmware\n", dev->name);
+
+ error = write_eeprom(rrpriv, 0, image, EEPROM_BYTES);
+ if (error)
+ printk(KERN_ERR "%s: Error writing EEPROM\n",
+ dev->name);
+
+ i = read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES);
+ if (i != EEPROM_BYTES)
+ printk(KERN_ERR "%s: Error reading back EEPROM "
+ "image\n", dev->name);
+
+ error = memcmp(image, oldimage, EEPROM_BYTES);
+ if (error){
+ printk(KERN_ERR "%s: Error verifying EEPROM image\n",
+ dev->name);
+ error = -EFAULT;
+ }
+
+ kfree(image);
+ kfree(oldimage);
+ break;
+ case SIOCRRID:
+ error = put_user(0x52523032, (int *)(&rq->ifr_data[0]));
+ if (error)
+ error = -EFAULT;
break;
default:
- return -EOPNOTSUPP;
}
- return 0;
+ out:
+ spin_unlock(&rrpriv->lock);
+ return error;
}
/*
* Local variables:
- * compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -c rrunner.c"
+ * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -c rrunner.c"
* End:
*/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov