[patch] Re: via-rhine and MMIO

Urban Widmark (urban@teststation.com)
Sat, 3 Nov 2001 16:55:17 +0100 (CET)


On Tue, 30 Oct 2001, Jeff Garzik wrote:

> WRT the above code, you should add a check to see if '150' is enough of
> a wait. MMIO is faster and would affect that loop. Maybe you want to
> schedule_timeout before reading MACRegEEcsr to delay a little bit.

The problem is (also) that the reload from eeprom reloads cfgA, cfgB, ...
so it changes the mode back to PIO (or whatever the eeprom says).

Since I can't verify that the reset-from-win98-powerdown thing still works
when moving the eeprom reload before resetting, I don't move the reload.
Instead I enable mmio twice (wait_for_reset is shared and wants one mode).

There is also a difference between the older vt3043/vt86c100a chips and
the vt6102 in which bit to flip to enable MMIO. More recent docs say that
the bit used for vt3043/vt86c100a is reserved.

The vt6102 was listed as using a 4096 byte io_size in mmio mode, which
isn't true when looking at the pci cfg (or the docs) and conflicts with
the sanity checks.

The code below works for me on both a vt6102 and a vt3043.

Anyone wanting to test the effects of this patch should edit
drivers/net/via-rhine.c and enable the define for VIA_USE_MEMORY.
VIA_USE_MEMORY could be turned into CONFIG_VIA_RHINE_USE_MEMORY ...

/Urban

diff -urN -X exclude linux-2.4.14-pre6-orig/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- linux-2.4.14-pre6-orig/drivers/net/via-rhine.c Sat Nov 3 00:25:11 2001
+++ linux/drivers/net/via-rhine.c Sat Nov 3 16:40:35 2001
@@ -73,6 +73,9 @@
- David Woodhouse: Set dev->base_addr before the first time we call
wait_for_reset(). It's a lot happier that way.
Free np->tx_bufs only if we actually allocated it.
+
+ LK1.1.12:
+ - Martin Eriksson: Allow Memory-Mapped IO to be enabled.
*/


@@ -155,7 +158,7 @@

/* These identify the driver base version and may not be removed. */
static char version[] __devinitdata =
-KERN_INFO "via-rhine.c:v1.10-LK1.1.11 20/08/2001 Written by Donald Becker\n"
+KERN_INFO "via-rhine.c:v1.10-LK1.1.12 03/11/2001 Written by Donald Becker\n"
KERN_INFO " http://www.scyld.com/network/via-rhine.html\n";

static char shortname[] __devinitdata = "via-rhine";
@@ -163,7 +166,9 @@

/* This driver was written to use PCI memory space, however most versions
of the Rhine only work correctly with I/O space accesses. */
+/* #define VIA_USE_MEMORY */
#if defined(VIA_USE_MEMORY)
+#define USE_MEM
#warning Many adapters using the VIA Rhine chip are not configured to work
#warning with PCI memory space accesses.
#else
@@ -320,10 +325,8 @@

#if defined(VIA_USE_MEMORY)
#define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1)
-#define RHINEII_IOSIZE 4096
#else
#define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR0)
-#define RHINEII_IOSIZE 256
#endif

/* directly indexed by enum via_rhine_chips, above */
@@ -331,7 +334,7 @@
{
{ "VIA VT86C100A Rhine", RHINE_IOTYPE, 128,
CanHaveMII | ReqTxAlign },
- { "VIA VT6102 Rhine-II", RHINE_IOTYPE, RHINEII_IOSIZE,
+ { "VIA VT6102 Rhine-II", RHINE_IOTYPE, 256,
CanHaveMII | HasWOL },
{ "VIA VT3043 Rhine", RHINE_IOTYPE, 128,
CanHaveMII | ReqTxAlign }
@@ -355,10 +358,19 @@
RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54,
MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74,
- Config=0x78, ConfigA=0x7A, RxMissed=0x7C, RxCRCErrs=0x7E,
+ ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B,
+ RxMissed=0x7C, RxCRCErrs=0x7E,
StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC,
};

+#ifdef USE_MEM
+/* Registers we check that mmio and reg are the same. */
+int mmio_verify_registers[] = {
+ RxConfig, TxConfig, IntrEnable, ConfigA, ConfigB, ConfigC, ConfigD,
+ 0
+};
+#endif
+
/* Bits in the interrupt status/mask registers. */
enum intr_status_bits {
IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020,
@@ -505,6 +517,31 @@
name, 5*i);
}

+#ifdef USE_MEM
+static void __devinit enable_mmio(long ioaddr, int chip_id)
+{
+ int n;
+ if (chip_id == VT3043 || chip_id == VT86C100A) {
+ /* More recent docs say that this bit is reserved ... */
+ n = inb(ioaddr + ConfigA) | 0x20;
+ outb(n, ioaddr + ConfigA);
+ } else if (chip_id == VT6102) {
+ n = inb(ioaddr + ConfigD) | 0x80;
+ outb(n, ioaddr + ConfigD);
+ }
+}
+#endif
+
+static void __devinit reload_eeprom(long ioaddr)
+{
+ int i;
+ outb(0x20, ioaddr + MACRegEEcsr);
+ /* Typically 2 cycles to reload. */
+ for (i = 0; i < 150; i++)
+ if (! (inb(ioaddr + MACRegEEcsr) & 0x20))
+ break;
+}
+
static int __devinit via_rhine_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -514,8 +551,12 @@
int chip_id = (int) ent->driver_data;
static int card_idx = -1;
long ioaddr;
+ long memaddr;
int io_size;
int pci_flags;
+#ifdef USE_MEM
+ long ioaddr0;
+#endif

/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -545,8 +586,9 @@
goto err_out;
}

- ioaddr = pci_resource_start (pdev, pci_flags & PCI_ADDR0 ? 0 : 1);
-
+ ioaddr = pci_resource_start (pdev, 0);
+ memaddr = pci_resource_start (pdev, 1);
+
if (pci_flags & PCI_USES_MASTER)
pci_set_master (pdev);

@@ -560,14 +602,29 @@
if (pci_request_regions(pdev, shortname))
goto err_out_free_netdev;

-#ifndef USE_IO
- ioaddr = (long) ioremap (ioaddr, io_size);
+#ifdef USE_MEM
+ ioaddr0 = ioaddr;
+ enable_mmio(ioaddr0, chip_id);
+
+ ioaddr = (long) ioremap (memaddr, io_size);
if (!ioaddr) {
- printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n",
- pdev->slot_name, io_size,
- pci_resource_start (pdev, 1));
+ printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%lX\n",
+ pdev->slot_name, io_size, memaddr);
goto err_out_free_res;
}
+
+ /* Check that selected MMIO registers match the PIO ones */
+ i = 0;
+ while (mmio_verify_registers[i]) {
+ int reg = mmio_verify_registers[i++];
+ unsigned char a = inb(ioaddr0+reg);
+ unsigned char b = readb(ioaddr+reg);
+ if (a != b) {
+ printk (KERN_ERR "MMIO do not match PIO [%02x] (%02x != %02x)\n",
+ reg, a, b);
+ goto err_out_unmap;
+ }
+ }
#endif

/* D-Link provided reset code (with comment additions) */
@@ -595,11 +652,16 @@
wait_for_reset(dev, shortname);

/* Reload the station address from the EEPROM. */
- writeb(0x20, ioaddr + MACRegEEcsr);
- /* Typically 2 cycles to reload. */
- for (i = 0; i < 150; i++)
- if (! (readb(ioaddr + MACRegEEcsr) & 0x20))
- break;
+#ifdef USE_IO
+ reload_eeprom(ioaddr);
+#else
+ reload_eeprom(ioaddr0);
+ /* Reloading from eeprom overwrites cfgA-D, so we must re-enable MMIO.
+ If reload_eeprom() was done first this could be avoided, but it is
+ not known if that still works with the "win98-reboot" problem. */
+ enable_mmio(ioaddr0, chip_id);
+#endif
+
for (i = 0; i < 6; i++)
dev->dev_addr[i] = readb(ioaddr + StationAddr + i);

@@ -660,7 +722,9 @@
goto err_out_unmap;

printk(KERN_INFO "%s: %s at 0x%lx, ",
- dev->name, via_rhine_chip_info[chip_id].name, ioaddr);
+ dev->name, via_rhine_chip_info[chip_id].name,
+ (pci_flags & PCI_USES_IO) ? ioaddr : memaddr);
+
for (i = 0; i < 5; i++)
printk("%2.2x:", dev->dev_addr[i]);
printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq);
@@ -711,7 +775,7 @@
return 0;

err_out_unmap:
-#ifndef USE_IO
+#ifdef USE_MEM
iounmap((void *)ioaddr);
err_out_free_res:
#endif
@@ -1587,13 +1651,12 @@
static void __devexit via_rhine_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct netdev_private *np = dev->priv;

unregister_netdev(dev);

pci_release_regions(pdev);

-#ifndef USE_IO
+#ifdef USE_MEM
iounmap((char *)(dev->base_addr));
#endif

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/