Second try.. :-)
When and if this passes code inspection, it should be included in 2.4 and
2.5.
Thanks,
Kent
-------------
Sorry, in round 2 I neglected to #include version.h. Please ignore round
2.
Below is the old changelog, with this now added:
* #include linux/version.h for in-kernel support
--------------
Changes made:
* No more magic numbers, all come from pci.h
* no more udelay()'s, which covered up PCI posting effects
* got rid of a __u8/__u16 here and there for u8/u16
* ioctl code disabled for kernel >= 2.5 (now with version.h, too!)
* bounded the number of times we could loop inside the interrupt function
* spin_lock_irqsave/restore in open()/close()
* better formatting
Thanks,
Kent
Sorry I've been slow to respond... I'm going to apply your driver
locally, so you and I have a good baseline to work with, but there are
some small issues related to PCI initialization that I want to review
and discuss with you, before submitting officially to Marcelo...
(another message should follow during the upcoming work week)
Regards,
Jeff
--
Jeff Garzik | "Why is it that attractive girls like you
Building 1024 | always seem to have a boyfriend?"
MandrakeSoft | "Because I'm a nympho that owns a brewery?"
| - BBC TV show "Coupling"
Jeff,
I have a feeling you're talking about this section:
> pci_write_config_byte (pdev, PCI_CACHE_LINE_SIZE, cls);
> pci_read_config_word (pdev, PCI_COMMAND, &pcr);
>
> /* Turn off Fast B2B enable */
> pcr &= ~PCI_COMMAND_FAST_BACK;
> /* Turn on SERR# enable and others */
> pcr |= (PCI_COMMAND_SERR | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
> PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
>
> pci_write_config_word (pdev, PCI_COMMAND, pcr);
> pci_read_config_word (pdev, PCI_COMMAND, &pcr);
Basically, this section exists from a time when I had no idea why the
card was behaving badly, so I was trying everything :-).
So, after revisiting them, I see that setting cache line size to 0 and
then using memory write and invalidate doesn't make any sense. I'm thinking
both can just be dropped, since I haven't seen any change in performance on
the machines I've made netperf runs with (a constant 14.7 Mb/s) after
changing these.
Any thoughts?
Kent
Thus Spake Jeff Garzik:
>Sorry I've been slow to respond... I'm going to apply your driver
>locally, so you and I have a good baseline to work with, but there are
>some small issues related to PCI initialization that I want to review
>and discuss with you, before submitting officially to Marcelo...
>
>(another message should follow during the upcoming work week)
>
>Regards,
>
> Jeff
>
>
>
Kent Yoder wrote:
>
> Jeff,
>
> I have a feeling you're talking about this section:
>
> > pci_write_config_byte (pdev, PCI_CACHE_LINE_SIZE, cls);
> > pci_read_config_word (pdev, PCI_COMMAND, &pcr);
> >
> > /* Turn off Fast B2B enable */
> > pcr &= ~PCI_COMMAND_FAST_BACK;
> > /* Turn on SERR# enable and others */
> > pcr |= (PCI_COMMAND_SERR | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
> > PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
> >
> > pci_write_config_word (pdev, PCI_COMMAND, pcr);
> > pci_read_config_word (pdev, PCI_COMMAND, &pcr);
>
> Basically, this section exists from a time when I had no idea why the
> card was behaving badly, so I was trying everything :-).
>
> So, after revisiting them, I see that setting cache line size to 0 and
> then using memory write and invalidate doesn't make any sense. I'm thinking
> both can just be dropped, since I haven't seen any change in performance on
> the machines I've made netperf runs with (a constant 14.7 Mb/s) after
> changing these.
I agree to the first part :)
Set cache line size just like drivers/net/acenic.c does, and enable
memory-write-invalidate...
Jeff
--
Jeff Garzik |
Building 1024 |
MandrakeSoft | Choose life.
Jeff Garzik wrote:
> Set cache line size just like drivers/net/acenic.c does, and enable
> memory-write-invalidate...
Does this mean the setup pci_enable_device() does on the cache line size
is not sufficient?
I ask, because I've been relying on it for a driver I'm working on;
should I be setting this as acenic does? It would seem that this is
something many drivers would need to do...
Thanks,
Dave Dillow
[email protected]
David Dillow wrote:
>
> Jeff Garzik wrote:
> > Set cache line size just like drivers/net/acenic.c does, and enable
> > memory-write-invalidate...
>
> Does this mean the setup pci_enable_device() does on the cache line size
> is not sufficient?
pci_enable_device doesn't touch the PCI_COMMAND_INVALIDATE bit at all...
> I ask, because I've been relying on it for a driver I'm working on;
> should I be setting this as acenic does? It would seem that this is
> something many drivers would need to do...
Yes, acenic is the code to copy, for setting that up.
I need to create a pci_set_mwi() helper function.
Jeff
--
Jeff Garzik |
Building 1024 |
MandrakeSoft | Choose life.
Jeff Garzik wrote:
>
> David Dillow wrote:
> >
> > Jeff Garzik wrote:
> > > Set cache line size just like drivers/net/acenic.c does, and enable
> > > memory-write-invalidate...
> >
> > Does this mean the setup pci_enable_device() does on the cache line size
> > is not sufficient?
>
> pci_enable_device doesn't touch the PCI_COMMAND_INVALIDATE bit at all...
Right, I was talking more about the cache line size... is it sufficient
for that?
As for PCI_COMMAND_INVALIDATE, what does that do for me; my PCI spec
isn't handy....
> > I ask, because I've been relying on it for a driver I'm working on;
> > should I be setting this as acenic does? It would seem that this is
> > something many drivers would need to do...
>
> Yes, acenic is the code to copy, for setting that up.
INVALIDATE, or cache line size?
Thanks,
Dave Dillow
[email protected]
David Dillow wrote:
>
> Jeff Garzik wrote:
> >
> > David Dillow wrote:
> > >
> > > Jeff Garzik wrote:
> > > > Set cache line size just like drivers/net/acenic.c does, and enable
> > > > memory-write-invalidate...
> > >
> > > Does this mean the setup pci_enable_device() does on the cache line size
> > > is not sufficient?
> >
> > pci_enable_device doesn't touch the PCI_COMMAND_INVALIDATE bit at all...
>
> Right, I was talking more about the cache line size... is it sufficient
> for that?
pci_enable_device doesn't touch PCI_COMMAND_INVALIDATE either, on most
platforms (particularly ia32, i.e. the popular one :))
> As for PCI_COMMAND_INVALIDATE, what does that do for me; my PCI spec
> isn't handy....
Enables Memory-Write-Invalidate (MWI).
> > > I ask, because I've been relying on it for a driver I'm working on;
> > > should I be setting this as acenic does? It would seem that this is
> > > something many drivers would need to do...
> >
> > Yes, acenic is the code to copy, for setting that up.
>
> INVALIDATE, or cache line size?
both.
Jeff
--
Jeff Garzik |
Building 1024 |
MandrakeSoft | Choose life.
Thus Spake Jeff Garzik:
>I agree to the first part :)
>
>Set cache line size just like drivers/net/acenic.c does, and enable
>memory-write-invalidate...
>
Ok, hopefully below is the section you were referring to:
-------
pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls);
cls <<= 2;
if (cls != SMP_CACHE_BYTES) {
printk(KERN_INFO " PCI cache line size set incorrectly "
"(%i bytes) by BIOS/FW, ", cls);
if (cls > SMP_CACHE_BYTES)
printk("expecting %i\n", SMP_CACHE_BYTES);
else {
printk("correcting to %i\n", SMP_CACHE_BYTES);
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
SMP_CACHE_BYTES >> 2);
}
}
pci_read_config_word (pdev, PCI_COMMAND, &pcr);
/* Turn off Fast B2B enable */
pcr &= ~PCI_COMMAND_FAST_BACK;
/* Turn on SERR# enable and others */
pcr |= (PCI_COMMAND_SERR | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
pci_write_config_word (pdev, PCI_COMMAND, pcr);
pci_read_config_word (pdev, PCI_COMMAND, &pcr);
------
Out of curiosity, does it in fact make sense to use memory write and
invalidate and set cache line size to 0 in some cases? This seems to go
against the PCI spec, which, if I'm reading it correctly, says that memory
write and invalidate is the same as a memory write, but it guarantees that
at least 1 cache line will be written. So, setting cacheline size =0 would
negate this effect(?)
Kent
>
> Jeff
>
>
>
Jeff Garzik wrote:
>
> David Dillow wrote:
> > Right, I was talking more about the cache line size... is it sufficient
> > for that?
>
> pci_enable_device doesn't touch PCI_COMMAND_INVALIDATE either, on most
> platforms (particularly ia32, i.e. the popular one :))
Doh! I see my mistake; I was reading pdev_enable_device() which sets it
to L1_CACHE_BYTES. And a quick grep shows me that it is called from
pci_assign_unassigned_resources(), which is not called on ia32 as far as
I can see....
This seems to be a common thing to set; shouldn't we have a helper for
it as well, or have pci_enable_device() do it?
Thanks,
Dave Dillow
[email protected]
Kent Yoder wrote:
> Ok, hopefully below is the section you were referring to:
>
> -------
>
> pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls);
> cls <<= 2;
> if (cls != SMP_CACHE_BYTES) {
> printk(KERN_INFO " PCI cache line size set incorrectly "
> "(%i bytes) by BIOS/FW, ", cls);
> if (cls > SMP_CACHE_BYTES)
> printk("expecting %i\n", SMP_CACHE_BYTES);
> else {
> printk("correcting to %i\n", SMP_CACHE_BYTES);
> pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
> SMP_CACHE_BYTES >> 2);
> }
> }
this gets cache line size correct
> /* Turn off Fast B2B enable */
> pcr &= ~PCI_COMMAND_FAST_BACK;
> /* Turn on SERR# enable and others */
> pcr |= (PCI_COMMAND_SERR | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
> PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
>
> pci_write_config_word (pdev, PCI_COMMAND, pcr);
> pci_read_config_word (pdev, PCI_COMMAND, &pcr);
You only need to worry about the PCI_COMMAND_INVALIDATE bit here, unless
your chip requires other setup, or you care to handle PCI hard errors in
the driver.
> Out of curiosity, does it in fact make sense to use memory write and
> invalidate and set cache line size to 0 in some cases? This seems to go
> against the PCI spec, which, if I'm reading it correctly, says that memory
> write and invalidate is the same as a memory write, but it guarantees that
> at least 1 cache line will be written. So, setting cacheline size =0 would
> negate this effect(?)
The rule is, never ever enable MWI if cache line size is zero.
MWI -does- make a difference in performance, though you may need to
check lanstreamer docs to see if there is a chip-specific MWI bit you
need to enable, over and above the PCI_COMMAND bit.
Jeff
--
Jeff Garzik |
Building 1024 |
MandrakeSoft | Choose life.
David Dillow wrote:
> Jeff Garzik wrote:
> > pci_enable_device doesn't touch PCI_COMMAND_INVALIDATE either, on most
> > platforms (particularly ia32, i.e. the popular one :))
> This seems to be a common thing to set; shouldn't we have a helper for
> it as well, or have pci_enable_device() do it?
Quoting my message to you from a couple hours ago:
> I need to create a pci_set_mwi() helper function.
Jeff
--
Jeff Garzik |
Building 1024 |
MandrakeSoft | Choose life.
Jeff Garzik wrote:
>
> MWI -does- make a difference in performance, though you may need to
> check lanstreamer docs to see if there is a chip-specific MWI bit you
> need to enable, over and above the PCI_COMMAND bit.
My experience - which is 2-3 years old now - is that many BIOSes will
enable MWI for you. Which makes it very easy to forget to do this,
and then have it discovered by your customers who have machines that
don't set MWI...
............................................................................
Peter Desnoyers
162 Pleasant St. (617) 661-1979 [email protected]
Cambridge, Mass. 02139
Ok, below is the current patch including the MWI changes as well as adding
printk log levels (as suggested by someone).
*fingers crossed* :-)
Kent
diff -urN linux-2.4.17.vanilla/drivers/net/tokenring/lanstreamer.c linux-2.4.17/drivers/net/tokenring/lanstreamer.c
--- linux-2.4.17.vanilla/drivers/net/tokenring/lanstreamer.c Mon Feb 4 11:09:30 2002
+++ linux-2.4.17/drivers/net/tokenring/lanstreamer.c Mon Mar 4 17:40:16 2002
@@ -60,6 +60,11 @@
* malloc free checks, reviewed code. <[email protected]>
* 03/13/00 - Added spinlocks for smp
* 03/08/01 - Added support for module_init() and module_exit()
+ * 08/15/01 - Added ioctl() functionality for debugging, changed netif_*_queue
+ * calls and other incorrectness - Kent Yoder <[email protected]>
+ * 11/05/01 - Restructured the interrupt function, added delays, reduced the
+ * the number of TX descriptors to 1, which together can prevent
+ * the card from locking up the box - <[email protected]>
*
* To Do:
*
@@ -84,6 +89,14 @@
#define STREAMER_NETWORK_MONITOR 0
+/* #define CONFIG_PROC_FS */
+
+/*
+ * Allow or disallow ioctl's for debugging
+ */
+
+#define STREAMER_IOCTL 0
+
#include <linux/config.h>
#include <linux/module.h>
@@ -105,6 +118,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
+#include <linux/version.h>
#include <net/checksum.h>
#include <asm/io.h>
@@ -121,7 +135,8 @@
* Official releases will only have an a.b.c version number format.
*/
-static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan";
+static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n"
+ " v0.5.1 03/04/02 - Kent Yoder";
static struct pci_device_id streamer_pci_tbl[] __initdata = {
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,},
@@ -175,6 +190,10 @@
MODULE_PARM(message_level,
"1-" __MODULE_STRING(STREAMER_MAX_ADAPTERS) "i");
+#if STREAMER_IOCTL
+static int streamer_ioctl(struct net_device *, struct ifreq *, int);
+#endif
+
static int streamer_reset(struct net_device *dev);
static int streamer_open(struct net_device *dev);
static int streamer_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -206,6 +225,8 @@
__u32 mmio_start, mmio_end, mmio_flags, mmio_len;
int rc=0;
static int card_no=-1;
+ u16 pcr;
+ u8 cls = 0;
#if STREAMER_DEBUG
printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev);
@@ -281,7 +302,11 @@
dev->hard_start_xmit = &streamer_xmit;
dev->change_mtu = &streamer_change_mtu;
dev->stop = &streamer_close;
+#if STREAMER_IOCTL
+ dev->do_ioctl = &streamer_ioctl;
+#else
dev->do_ioctl = NULL;
+#endif
dev->set_multicast_list = &streamer_set_rx_mode;
dev->get_stats = &streamer_get_stats;
dev->set_mac_address = &streamer_set_mac_address;
@@ -303,6 +328,27 @@
spin_lock_init(&streamer_priv->streamer_lock);
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls);
+ cls <<= 2;
+ if (cls != SMP_CACHE_BYTES) {
+ printk(KERN_INFO " PCI cache line size set incorrectly "
+ "(%i bytes) by BIOS/FW, ", cls);
+ if (cls > SMP_CACHE_BYTES)
+ printk("expecting %i\n", SMP_CACHE_BYTES);
+ else {
+ printk("correcting to %i\n", SMP_CACHE_BYTES);
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+ SMP_CACHE_BYTES >> 2);
+ }
+ }
+
+ pci_read_config_word (pdev, PCI_COMMAND, &pcr);
+
+ pcr |= (PCI_COMMAND_INVALIDATE | PCI_COMMAND_SERR);
+
+ pci_write_config_word (pdev, PCI_COMMAND, pcr);
+ pci_read_config_word (pdev, PCI_COMMAND, &pcr);
+
printk("%s \n", version);
printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name,
streamer_priv->streamer_card_name,
@@ -403,6 +449,7 @@
printk("GPR: %x\n", readw(streamer_mmio + GPR));
printk("SISRMASK: %x\n", readw(streamer_mmio + SISR_MASK));
#endif
+ writew(readw(streamer_mmio + BCTL) | (BCTL_RX_FIFO_8 | BCTL_TX_FIFO_8), streamer_mmio + BCTL );
if (streamer_priv->streamer_ring_speed == 0) { /* Autosense */
writew(readw(streamer_mmio + GPR) | GPR_AUTOSENSE,
@@ -558,8 +605,6 @@
do {
int i;
- save_flags(flags);
- cli();
for (i = 0; i < SRB_COMMAND_SIZE; i += 2) {
writew(0, streamer_mmio + LAPDINC);
}
@@ -599,11 +644,12 @@
}
printk("\n");
#endif
-
+ spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
streamer_priv->srb_queued = 1;
/* signal solo that SRB command has been issued */
writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
+ spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags);
while (streamer_priv->srb_queued) {
interruptible_sleep_on_timeout(&streamer_priv->srb_wait, 5 * HZ);
@@ -617,7 +663,6 @@
break;
}
}
- restore_flags(flags);
#if STREAMER_DEBUG
printk("SISR_MASK: %x\n", readw(streamer_mmio + SISR_MASK));
@@ -767,9 +812,12 @@
streamer_priv->streamer_tx_ring[i].bufcnt_framelen = 0;
streamer_priv->streamer_tx_ring[i].buffer = 0;
streamer_priv->streamer_tx_ring[i].buflen = 0;
+ streamer_priv->streamer_tx_ring[i].rsvd1 = 0;
+ streamer_priv->streamer_tx_ring[i].rsvd2 = 0;
+ streamer_priv->streamer_tx_ring[i].rsvd3 = 0;
}
streamer_priv->streamer_tx_ring[STREAMER_TX_RING_SIZE - 1].forward =
- virt_to_bus(&streamer_priv->streamer_tx_ring[0]);;
+ virt_to_bus(&streamer_priv->streamer_tx_ring[0]);
streamer_priv->free_tx_ring_entries = STREAMER_TX_RING_SIZE;
streamer_priv->tx_ring_free = 0; /* next entry in tx ring to use */
@@ -941,37 +989,30 @@
__u8 *streamer_mmio = streamer_priv->streamer_mmio;
__u16 sisr;
__u16 misr;
- __u16 sisrmask;
+ u8 max_intr = MAX_INTR;
- sisrmask = SISR_MI;
- writew(~sisrmask, streamer_mmio + SISR_MASK_RUM);
+ spin_lock(&streamer_priv->streamer_lock);
sisr = readw(streamer_mmio + SISR);
- writew(~sisr, streamer_mmio + SISR_RUM);
- misr = readw(streamer_mmio + MISR_RUM);
- writew(~misr, streamer_mmio + MISR_RUM);
- if (!sisr)
- { /* Interrupt isn't for us */
- writew(~misr,streamer_mmio+MISR_RUM);
- return;
- }
+ while((sisr & (SISR_MI | SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE |
+ SISR_ARB_CMD | SISR_TRB_REPLY | SISR_PAR_ERR | SISR_SERR_ERR))
+ && (max_intr > 0)) {
- spin_lock(&streamer_priv->streamer_lock);
+ if(sisr & SISR_PAR_ERR) {
+ writew(~SISR_PAR_ERR, streamer_mmio + SISR_RUM);
+ (void)readw(streamer_mmio + SISR_RUM);
+ }
- if ((sisr & (SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY))
- || (misr & (MISR_TX2_EOF | MISR_RX_NOBUF | MISR_RX_EOF))) {
- if (sisr & SISR_SRB_REPLY) {
- if (streamer_priv->srb_queued == 1) {
- wake_up_interruptible(&streamer_priv->srb_wait);
- } else if (streamer_priv->srb_queued == 2) {
- streamer_srb_bh(dev);
- }
- streamer_priv->srb_queued = 0;
+ else if(sisr & SISR_SERR_ERR) {
+ writew(~SISR_SERR_ERR, streamer_mmio + SISR_RUM);
+ (void)readw(streamer_mmio + SISR_RUM);
}
- /* SISR_SRB_REPLY */
+
+ else if(sisr & SISR_MI) {
+ misr = readw(streamer_mmio + MISR_RUM);
+
if (misr & MISR_TX2_EOF) {
- while (streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status)
- {
+ while(streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status) {
streamer_priv->tx_ring_last_status = (streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1);
streamer_priv->free_tx_ring_entries++;
streamer_priv->streamer_stats.tx_bytes += streamer_priv->tx_ring_skb[streamer_priv->tx_ring_last_status]->len;
@@ -981,6 +1022,9 @@
streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].status = 0;
streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].bufcnt_framelen = 0;
streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].buflen = 0;
+ streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd1 = 0;
+ streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd2 = 0;
+ streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd3 = 0;
}
netif_wake_queue(dev);
}
@@ -989,7 +1033,30 @@
streamer_rx(dev);
}
/* MISR_RX_EOF */
- if (sisr & SISR_ADAPTER_CHECK) {
+
+ if (misr & MISR_RX_NOBUF) {
+ /* According to the documentation, we don't have to do anything,
+ * but trapping it keeps it out of /var/log/messages.
+ */
+ } /* SISR_RX_NOBUF */
+
+ writew(~misr, streamer_mmio + MISR_RUM);
+ (void)readw(streamer_mmio + MISR_RUM);
+ }
+
+ else if (sisr & SISR_SRB_REPLY) {
+ if (streamer_priv->srb_queued == 1) {
+ wake_up_interruptible(&streamer_priv->srb_wait);
+ } else if (streamer_priv->srb_queued == 2) {
+ streamer_srb_bh(dev);
+ }
+ streamer_priv->srb_queued = 0;
+
+ writew(~SISR_SRB_REPLY, streamer_mmio + SISR_RUM);
+ (void)readw(streamer_mmio + SISR_RUM);
+ }
+
+ else if (sisr & SISR_ADAPTER_CHECK) {
printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name);
writel(readl(streamer_mmio + LAPWWO), streamer_mmio + LAPA);
printk(KERN_WARNING "%s: Words %x:%x:%x:%x:\n",
@@ -1001,38 +1068,37 @@
}
/* SISR_ADAPTER_CHECK */
- if (sisr & SISR_ASB_FREE) {
+ else if (sisr & SISR_ASB_FREE) {
/* Wake up anything that is waiting for the asb response */
if (streamer_priv->asb_queued) {
streamer_asb_bh(dev);
}
+ writew(~SISR_ASB_FREE, streamer_mmio + SISR_RUM);
+ (void)readw(streamer_mmio + SISR_RUM);
}
/* SISR_ASB_FREE */
- if (sisr & SISR_ARB_CMD) {
+ else if (sisr & SISR_ARB_CMD) {
streamer_arb_cmd(dev);
+ writew(~SISR_ARB_CMD, streamer_mmio + SISR_RUM);
+ (void)readw(streamer_mmio + SISR_RUM);
}
/* SISR_ARB_CMD */
- if (sisr & SISR_TRB_REPLY) {
+ else if (sisr & SISR_TRB_REPLY) {
/* Wake up anything that is waiting for the trb response */
if (streamer_priv->trb_queued) {
wake_up_interruptible(&streamer_priv->
trb_wait);
}
streamer_priv->trb_queued = 0;
+ writew(~SISR_TRB_REPLY, streamer_mmio + SISR_RUM);
+ (void)readw(streamer_mmio + SISR_RUM);
}
/* SISR_TRB_REPLY */
- if (misr & MISR_RX_NOBUF) {
- /* According to the documentation, we don't have to do anything, but trapping it keeps it out of
- /var/log/messages. */
- } /* SISR_RX_NOBUF */
- } else {
- printk(KERN_WARNING "%s: Unexpected interrupt: %x\n",
- dev->name, sisr);
- printk(KERN_WARNING "%s: SISR_MASK: %x\n", dev->name,
- readw(streamer_mmio + SISR_MASK));
- } /* One if the interrupts we want */
- writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+ sisr = readw(streamer_mmio + SISR);
+ max_intr--;
+ } /* while() */
+
spin_unlock(&streamer_priv->streamer_lock) ;
}
@@ -1044,13 +1110,16 @@
unsigned long flags ;
spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
- netif_stop_queue(dev);
if (streamer_priv->free_tx_ring_entries) {
streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0;
- streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len;
+ streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00020000 | skb->len;
streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buffer = virt_to_bus(skb->data);
+ streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd1 = skb->len;
+ streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd2 = 0;
+ streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd3 = 0;
streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buflen = skb->len;
+
streamer_priv->tx_ring_skb[streamer_priv->tx_ring_free] = skb;
streamer_priv->free_tx_ring_entries--;
#if STREAMER_DEBUG_PACKETS
@@ -1067,12 +1136,13 @@
#endif
writel(virt_to_bus (&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free]),streamer_mmio + TX2LFDA);
+ (void)readl(streamer_mmio + TX2LFDA);
streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
- netif_wake_queue(dev);
spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
return 0;
} else {
+ netif_stop_queue(dev);
spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
return 1;
}
@@ -1092,12 +1162,13 @@
writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC);
writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
streamer_priv->srb_queued = 1;
writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
+ spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags);
+
while (streamer_priv->srb_queued)
{
interruptible_sleep_on_timeout(&streamer_priv->srb_wait,
@@ -1114,7 +1185,6 @@
}
}
- restore_flags(flags);
streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1);
for (i = 0; i < STREAMER_RX_RING_SIZE; i++) {
@@ -1808,6 +1878,64 @@
#endif
#endif
+#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+static int streamer_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ int i;
+ struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+ u8 *streamer_mmio = streamer_priv->streamer_mmio;
+
+ switch(cmd) {
+ case IOCTL_SISR_MASK:
+ writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+ break;
+ case IOCTL_SPIN_LOCK_TEST:
+ printk(KERN_INFO "spin_lock() called.\n");
+ spin_lock(&streamer_priv->streamer_lock);
+ spin_unlock(&streamer_priv->streamer_lock);
+ printk(KERN_INFO "spin_unlock() finished.\n");
+ break;
+ case IOCTL_PRINT_BDAS:
+ printk(KERN_INFO "bdas: RXBDA: %x RXLBDA: %x TX2FDA: %x TX2LFDA: %x\n",
+ readw(streamer_mmio + RXBDA),
+ readw(streamer_mmio + RXLBDA),
+ readw(streamer_mmio + TX2FDA),
+ readw(streamer_mmio + TX2LFDA));
+ break;
+ case IOCTL_PRINT_REGISTERS:
+ printk(KERN_INFO "registers:\n");
+ printk(KERN_INFO "SISR: %04x MISR: %04x LISR: %04x BCTL: %04x BMCTL: %04x\nmask %04x mask %04x\n",
+ readw(streamer_mmio + SISR),
+ readw(streamer_mmio + MISR_RUM),
+ readw(streamer_mmio + LISR),
+ readw(streamer_mmio + BCTL),
+ readw(streamer_mmio + BMCTL_SUM),
+ readw(streamer_mmio + SISR_MASK),
+ readw(streamer_mmio + MISR_MASK));
+ break;
+ case IOCTL_PRINT_RX_BUFS:
+ printk(KERN_INFO "Print rx bufs:\n");
+ for(i=0; i<STREAMER_RX_RING_SIZE; i++)
+ printk(KERN_INFO "rx_ring %d status: 0x%x\n", i,
+ streamer_priv->streamer_rx_ring[i].status);
+ break;
+ case IOCTL_PRINT_TX_BUFS:
+ printk(KERN_INFO "Print tx bufs:\n");
+ for(i=0; i<STREAMER_TX_RING_SIZE; i++)
+ printk(KERN_INFO "tx_ring %d status: 0x%x\n", i,
+ streamer_priv->streamer_tx_ring[i].status);
+ break;
+ case IOCTL_RX_CMD:
+ streamer_rx(dev);
+ printk(KERN_INFO "Sent rx command.\n");
+ break;
+ default:
+ printk(KERN_INFO "Bad ioctl!\n");
+ }
+ return 0;
+}
+#endif
+
static struct pci_driver streamer_pci_driver = {
name: "lanstreamer",
id_table: streamer_pci_tbl,
diff -urN linux-2.4.17.vanilla/drivers/net/tokenring/lanstreamer.h linux-2.4.17/drivers/net/tokenring/lanstreamer.h
--- linux-2.4.17.vanilla/drivers/net/tokenring/lanstreamer.h Mon Feb 4 11:09:30 2002
+++ linux-2.4.17/drivers/net/tokenring/lanstreamer.h Mon Feb 4 10:21:42 2002
@@ -56,11 +56,36 @@
*
* 12/10/99 - Alpha Release 0.1.0
* First release to the public
+ * 08/15/01 - Added ioctl() definitions and others - Kent Yoder <[email protected]>
*
*/
+#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#include <asm/ioctl.h>
+#define IOCTL_PRINT_RX_BUFS SIOCDEVPRIVATE
+#define IOCTL_PRINT_TX_BUFS SIOCDEVPRIVATE+1
+#define IOCTL_RX_CMD SIOCDEVPRIVATE+2
+#define IOCTL_TX_CMD SIOCDEVPRIVATE+3
+#define IOCTL_PRINT_REGISTERS SIOCDEVPRIVATE+4
+#define IOCTL_PRINT_BDAS SIOCDEVPRIVATE+5
+#define IOCTL_SPIN_LOCK_TEST SIOCDEVPRIVATE+6
+#define IOCTL_SISR_MASK SIOCDEVPRIVATE+7
+#endif
+
+/* MAX_INTR - the maximum number of times we can loop
+ * inside the interrupt function before returning
+ * control to the OS (maximum value is 256)
+ */
+#define MAX_INTR 5
+
+#define CLS 0x0C
+#define MLR 0x86
+#define LTR 0x0D
+
#define BCTL 0x60
#define BCTL_SOFTRESET (1<<15)
+#define BCTL_RX_FIFO_8 (1<<1)
+#define BCTL_TX_FIFO_8 (1<<3)
#define GPR 0x4a
#define GPR_AUTOSENSE (1<<2)
@@ -89,6 +114,7 @@
#define SISR_MASK_RUM 0x58
#define SISR_MI (1<<15)
+#define SISR_SERR_ERR (1<<14)
#define SISR_TIMER (1<<11)
#define SISR_LAP_PAR_ERR (1<<10)
#define SISR_LAP_ACC_ERR (1<<9)
@@ -218,7 +244,13 @@
/* Streamer defaults for buffers */
#define STREAMER_RX_RING_SIZE 16 /* should be a power of 2 */
-#define STREAMER_TX_RING_SIZE 8 /* should be a power of 2 */
+/* Setting the number of TX descriptors to 1 is a workaround for an
+ * undocumented hardware problem with the lanstreamer board. Setting
+ * this to something higher may slightly increase the throughput you
+ * can get from the card, but at the risk of locking up the box. -
+ * <[email protected]>
+ */
+#define STREAMER_TX_RING_SIZE 1 /* should be a power of 2 */
#define PKT_BUF_SZ 4096 /* Default packet size */