This software may be used and distributed according to the terms of
the GNU Public License, incorporated herein by reference. */
-/* 2000-02-28: support added for Dayna and Kinetics cards by
+/* 2000-02-28: support added for Dayna and Kinetics cards by
A.G.deWijn@phys.uu.nl */
/* 2000-04-04: support added for Dayna2 by bart@etpmod.phys.tue.nl */
/* 2001-04-18: support for DaynaPort E/LC-M by rayk@knightsmanor.org */
/* 2001-05-15: support for Cabletron ported from old daynaport driver
- * and fixed access to Sonic Sys card which masquerades as a Farallon
+ * and fixed access to Sonic Sys card which masquerades as a Farallon
* by rayk@knightsmanor.org */
+/* 2002-12-30: Try to support more cards, some clues from NetBSD driver */
+/* 2003-12-26: Make sure Asante cards always work. */
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/hwtest.h>
#include <asm/macints.h>
-#include "8390.h"
+static char version[] =
+ "mac8390.c: v0.4 2001-05-15 David Huggins-Daines <dhd@debian.org> and others\n";
+
+#define EI_SHIFT(x) (ei_local->reg_offset[x])
+#define ei_inb(port) in_8(port)
+#define ei_outb(val,port) out_8(port,val)
+#define ei_inb_p(port) in_8(port)
+#define ei_outb_p(val,port) out_8(port,val)
+
+#include "lib8390.c"
#define WD_START_PG 0x00 /* First page of TX buffer */
#define CABLETRON_RX_START_PG 0x00 /* First page of RX buffer */
#define DAYNA_8390_BASE 0x80000
#define DAYNA_8390_MEM 0x00000
-#define KINETICS_8390_BASE 0x80000
-#define KINETICS_8390_MEM 0x00000
-
-#define CABLETRON_8390_BASE 0x90000
+#define CABLETRON_8390_BASE 0x90000
#define CABLETRON_8390_MEM 0x00000
+#define INTERLAN_8390_BASE 0xE0000
+#define INTERLAN_8390_MEM 0xD0000
+
enum mac8390_type {
MAC8390_NONE = -1,
MAC8390_APPLE,
MAC8390_ASANTE,
- MAC8390_FARALLON, /* Apple, Asante, and Farallon are all compatible */
+ MAC8390_FARALLON,
MAC8390_CABLETRON,
MAC8390_DAYNA,
MAC8390_INTERLAN,
MAC8390_KINETICS,
- MAC8390_FOCUS,
- MAC8390_SONICSYS,
- MAC8390_DAYNA2,
- MAC8390_DAYNA3,
};
static const char * cardname[] = {
"dayna",
"interlan",
"kinetics",
- "focus",
- "sonic systems",
- "dayna2",
- "dayna_lc",
};
static int word16[] = {
0, /* dayna */
1, /* interlan */
0, /* kinetics */
- 1, /* focus (??) */
- 1, /* sonic systems */
- 1, /* dayna2 */
- 1, /* dayna-lc */
};
/* on which cards do we use NuBus resources? */
0, /* dayna */
0, /* interlan */
0, /* kinetics */
- 0, /* focus (??) */
- 1, /* sonic systems */
- 1, /* dayna2 */
- 1, /* dayna-lc */
};
-static char version[] __initdata =
- "mac8390.c: v0.4 2001-05-15 David Huggins-Daines <dhd@debian.org> and others\n";
-
-extern enum mac8390_type mac8390_ident(struct nubus_dev * dev);
-extern int mac8390_memsize(unsigned long membase);
+enum mac8390_access {
+ ACCESS_UNKNOWN = 0,
+ ACCESS_32,
+ ACCESS_16,
+};
+
extern int mac8390_memtest(struct net_device * dev);
static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
enum mac8390_type type);
static int mac8390_open(struct net_device * dev);
static int mac8390_close(struct net_device * dev);
static void mac8390_no_reset(struct net_device *dev);
+static void interlan_reset(struct net_device *dev);
-/* Sane (32-bit chunk memory read/write) - Apple/Asante/Farallon do this*/
+/* Sane (32-bit chunk memory read/write) - Some Farallon and Apple do this*/
static void sane_get_8390_hdr(struct net_device *dev,
struct e8390_pkt_hdr *hdr, int ring_page);
static void sane_block_input(struct net_device * dev, int count,
static void word_memcpy_tocard(void *tp, const void *fp, int count);
static void word_memcpy_fromcard(void *tp, const void *fp, int count);
-enum mac8390_type __init mac8390_ident(struct nubus_dev * dev)
+static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev)
{
- if (dev->dr_sw == NUBUS_DRSW_ASANTE)
- return MAC8390_ASANTE;
- if (dev->dr_sw == NUBUS_DRSW_FARALLON)
- return MAC8390_FARALLON;
- if (dev->dr_sw == NUBUS_DRSW_KINETICS)
- return MAC8390_KINETICS;
- if (dev->dr_sw == NUBUS_DRSW_DAYNA)
- return MAC8390_DAYNA;
- if (dev->dr_sw == NUBUS_DRSW_DAYNA2)
- return MAC8390_DAYNA2;
- if (dev->dr_sw == NUBUS_DRSW_DAYNA_LC)
- return MAC8390_DAYNA3;
- if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
- return MAC8390_CABLETRON;
+ switch (dev->dr_sw) {
+ case NUBUS_DRSW_3COM:
+ switch (dev->dr_hw) {
+ case NUBUS_DRHW_APPLE_SONIC_NB:
+ case NUBUS_DRHW_APPLE_SONIC_LC:
+ case NUBUS_DRHW_SONNET:
+ return MAC8390_NONE;
+ break;
+ default:
+ return MAC8390_APPLE;
+ break;
+ }
+ break;
+
+ case NUBUS_DRSW_APPLE:
+ switch (dev->dr_hw) {
+ case NUBUS_DRHW_ASANTE_LC:
+ return MAC8390_NONE;
+ break;
+ case NUBUS_DRHW_CABLETRON:
+ return MAC8390_CABLETRON;
+ break;
+ default:
+ return MAC8390_APPLE;
+ break;
+ }
+ break;
+
+ case NUBUS_DRSW_ASANTE:
+ return MAC8390_ASANTE;
+ break;
+
+ case NUBUS_DRSW_TECHWORKS:
+ case NUBUS_DRSW_DAYNA2:
+ case NUBUS_DRSW_DAYNA_LC:
+ if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
+ return MAC8390_CABLETRON;
+ else
+ return MAC8390_APPLE;
+ break;
+
+ case NUBUS_DRSW_FARALLON:
+ return MAC8390_FARALLON;
+ break;
+
+ case NUBUS_DRSW_KINETICS:
+ switch (dev->dr_hw) {
+ case NUBUS_DRHW_INTERLAN:
+ return MAC8390_INTERLAN;
+ break;
+ default:
+ return MAC8390_KINETICS;
+ break;
+ }
+ break;
+
+ case NUBUS_DRSW_DAYNA:
+ // These correspond to Dayna Sonic cards
+ // which use the macsonic driver
+ if (dev->dr_hw == NUBUS_DRHW_SMC9194 ||
+ dev->dr_hw == NUBUS_DRHW_INTERLAN )
+ return MAC8390_NONE;
+ else
+ return MAC8390_DAYNA;
+ break;
+ }
return MAC8390_NONE;
}
-int __init mac8390_memsize(unsigned long membase)
+static enum mac8390_access __init mac8390_testio(volatile unsigned long membase)
+{
+ unsigned long outdata = 0xA5A0B5B0;
+ unsigned long indata = 0x00000000;
+ /* Try writing 32 bits */
+ memcpy((char *)membase, (char *)&outdata, 4);
+ /* Now compare them */
+ if (memcmp((char *)&outdata, (char *)membase, 4) == 0)
+ return ACCESS_32;
+ /* Write 16 bit output */
+ word_memcpy_tocard((char *)membase, (char *)&outdata, 4);
+ /* Now read it back */
+ word_memcpy_fromcard((char *)&indata, (char *)membase, 4);
+ if (outdata == indata)
+ return ACCESS_16;
+ return ACCESS_UNKNOWN;
+}
+
+static int __init mac8390_memsize(unsigned long membase)
{
unsigned long flags;
int i, j;
-
+
local_irq_save(flags);
/* Check up to 32K in 4K increments */
for (i = 0; i < 8; i++) {
RAM end located */
if (hwreg_present(m) == 0)
break;
-
+
/* write a distinctive byte */
*m = 0xA5A0 | i;
/* check that we read back what we wrote */
int version_disp = 0;
struct nubus_dev * ndev = NULL;
int err = -ENODEV;
-
+
struct nubus_dir dir;
struct nubus_dirent ent;
int offset;
if (!MACH_IS_MAC)
return ERR_PTR(-ENODEV);
- dev = alloc_ei_netdev();
+ dev = ____alloc_ei_netdev(0);
if (!dev)
return ERR_PTR(-ENOMEM);
if (unit >= 0)
sprintf(dev->name, "eth%d", unit);
- SET_MODULE_OWNER(dev);
-
while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) {
/* Have we seen it already? */
if (slots & (1<<ndev->board->slot))
dev->name, ndev->board->slot);
continue;
}
-
+
/* Get the MAC address */
if ((nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent)) == -1) {
printk(KERN_INFO "%s: Couldn't get MAC address!\n",
continue;
} else {
nubus_get_rsrc_mem(dev->dev_addr, &ent, 6);
- /* Some Sonic Sys cards masquerade as Farallon */
- if (cardtype == MAC8390_FARALLON &&
- dev->dev_addr[0] == 0x0 &&
- dev->dev_addr[1] == 0x40 &&
- dev->dev_addr[2] == 0x10) {
- /* This is really Sonic Sys card */
- cardtype = MAC8390_SONICSYS;
- }
}
-
+
if (useresources[cardtype] == 1) {
nubus_rewinddir(&dir);
if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, &ent) == -1) {
switch (cardtype) {
case MAC8390_KINETICS:
case MAC8390_DAYNA: /* it's the same */
- dev->base_addr =
+ dev->base_addr =
(int)(ndev->board->slot_addr +
DAYNA_8390_BASE);
- dev->mem_start =
+ dev->mem_start =
(int)(ndev->board->slot_addr +
DAYNA_8390_MEM);
dev->mem_end =
dev->mem_start +
mac8390_memsize(dev->mem_start);
break;
+ case MAC8390_INTERLAN:
+ dev->base_addr =
+ (int)(ndev->board->slot_addr +
+ INTERLAN_8390_BASE);
+ dev->mem_start =
+ (int)(ndev->board->slot_addr +
+ INTERLAN_8390_MEM);
+ dev->mem_end =
+ dev->mem_start +
+ mac8390_memsize(dev->mem_start);
+ break;
case MAC8390_CABLETRON:
dev->base_addr =
(int)(ndev->board->slot_addr +
*/
i = (void *)dev->base_addr;
*i = 0x21;
- dev->mem_end =
+ dev->mem_end =
dev->mem_start +
mac8390_memsize(dev->mem_start);
break;
-
+
default:
printk(KERN_ERR "Card type %s is"
- " unsupported, sorry\n",
- cardname[cardtype]);
+ " unsupported, sorry\n",
+ ndev->board->name);
continue;
}
}
#endif /* MODULE */
+static const struct net_device_ops mac8390_netdev_ops = {
+ .ndo_open = mac8390_open,
+ .ndo_stop = mac8390_close,
+ .ndo_start_xmit = __ei_start_xmit,
+ .ndo_tx_timeout = __ei_tx_timeout,
+ .ndo_get_stats = __ei_get_stats,
+ .ndo_set_multicast_list = __ei_set_multicast_list,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_change_mtu = eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = __ei_poll,
+#endif
+};
+
static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
enum mac8390_type type)
{
24, 26, 28, 30
};
- int access_bitmode;
-
+ int access_bitmode = 0;
+
/* Now fill in our stuff */
- dev->open = &mac8390_open;
- dev->stop = &mac8390_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = ei_poll;
-#endif
+ dev->netdev_ops = &mac8390_netdev_ops;
/* GAR, ei_status is actually a macro even though it looks global */
ei_status.name = cardname[type];
ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
ei_status.rmem_end = dev->mem_end;
}
-
+
/* Fill in model-specific information and functions */
switch(type) {
- case MAC8390_SONICSYS:
- /* 16 bit card, register map is reversed */
- ei_status.reset_8390 = &mac8390_no_reset;
- ei_status.block_input = &slow_sane_block_input;
- ei_status.block_output = &slow_sane_block_output;
- ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
- ei_status.reg_offset = back4_offsets;
- access_bitmode = 0;
- break;
case MAC8390_FARALLON:
case MAC8390_APPLE:
+ switch(mac8390_testio(dev->mem_start)) {
+ case ACCESS_UNKNOWN:
+ printk("Don't know how to access card memory!\n");
+ return -ENODEV;
+ break;
+
+ case ACCESS_16:
+ /* 16 bit card, register map is reversed */
+ ei_status.reset_8390 = &mac8390_no_reset;
+ ei_status.block_input = &slow_sane_block_input;
+ ei_status.block_output = &slow_sane_block_output;
+ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+ break;
+
+ case ACCESS_32:
+ /* 32 bit card, register map is reversed */
+ ei_status.reset_8390 = &mac8390_no_reset;
+ ei_status.block_input = &sane_block_input;
+ ei_status.block_output = &sane_block_output;
+ ei_status.get_8390_hdr = &sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+ access_bitmode = 1;
+ break;
+ }
+ break;
+
case MAC8390_ASANTE:
- case MAC8390_DAYNA2:
- case MAC8390_DAYNA3:
- /* 32 bit card, register map is reversed */
- /* sane */
+ /* Some Asante cards pass the 32 bit test
+ * but overwrite system memory when run at 32 bit.
+ * so we run them all at 16 bit.
+ */
ei_status.reset_8390 = &mac8390_no_reset;
- ei_status.block_input = &sane_block_input;
- ei_status.block_output = &sane_block_output;
- ei_status.get_8390_hdr = &sane_get_8390_hdr;
+ ei_status.block_input = &slow_sane_block_input;
+ ei_status.block_output = &slow_sane_block_output;
+ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
ei_status.reg_offset = back4_offsets;
- access_bitmode = 1;
break;
+
case MAC8390_CABLETRON:
/* 16 bit card, register map is short forward */
ei_status.reset_8390 = &mac8390_no_reset;
ei_status.block_output = &slow_sane_block_output;
ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
ei_status.reg_offset = fwrd2_offsets;
- access_bitmode = 0;
break;
+
case MAC8390_DAYNA:
case MAC8390_KINETICS:
- /* 16 bit memory */
+ /* 16 bit memory, register map is forward */
/* dayna and similar */
ei_status.reset_8390 = &mac8390_no_reset;
ei_status.block_input = &dayna_block_input;
ei_status.block_output = &dayna_block_output;
ei_status.get_8390_hdr = &dayna_get_8390_hdr;
ei_status.reg_offset = fwrd4_offsets;
- access_bitmode = 0;
break;
+
+ case MAC8390_INTERLAN:
+ /* 16 bit memory, register map is forward */
+ ei_status.reset_8390 = &interlan_reset;
+ ei_status.block_input = &slow_sane_block_input;
+ ei_status.block_output = &slow_sane_block_output;
+ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+ ei_status.reg_offset = fwrd4_offsets;
+ break;
+
default:
- printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]);
+ printk(KERN_ERR "Card type %s is unsupported, sorry\n", ndev->board->name);
return -ENODEV;
}
-
- NS8390_init(dev, 0);
+
+ __NS8390_init(dev, 0);
/* Good, done, now spit out some messages */
printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
- dev->name, ndev->board->name, ndev->board->slot, cardname[type]);
- printk(KERN_INFO "MAC ");
- {
- int i;
- for (i = 0; i < 6; i++) {
- printk("%2.2x", dev->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- }
- printk(" IRQ %d, shared memory at %#lx-%#lx, %d-bit access.\n",
- dev->irq, dev->mem_start, dev->mem_end-1,
- access_bitmode?32:16);
+ dev->name, ndev->board->name, ndev->board->slot, cardname[type]);
+ printk(KERN_INFO
+ "MAC %pM IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n",
+ dev->dev_addr, dev->irq,
+ (unsigned int)(dev->mem_end - dev->mem_start) >> 10,
+ dev->mem_start, access_bitmode ? 32 : 16);
return 0;
}
static int mac8390_open(struct net_device *dev)
{
- ei_open(dev);
- if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) {
+ __ei_open(dev);
+ if (request_irq(dev->irq, __ei_interrupt, 0, "8390 Ethernet", dev)) {
printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
return -EAGAIN;
- }
+ }
return 0;
}
static int mac8390_close(struct net_device *dev)
{
free_irq(dev->irq, dev);
- ei_close(dev);
+ __ei_close(dev);
return 0;
}
return;
}
+static void interlan_reset(struct net_device *dev)
+{
+ unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq));
+ if (ei_debug > 1)
+ printk("Need to reset the NS8390 t=%lu...", jiffies);
+ ei_status.txing = 0;
+ target[0xC0000] = 0;
+ if (ei_debug > 1)
+ printk("reset complete\n");
+ return;
+}
+
/* dayna_memcpy_fromio/dayna_memcpy_toio */
/* directly from daynaport.c by Alan Cox */
static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
{
- volatile unsigned short *ptr;
- unsigned short *target=to;
+ volatile unsigned char *ptr;
+ unsigned char *target=to;
from<<=1; /* word, skip overhead */
- ptr=(unsigned short *)(dev->mem_start+from);
+ ptr=(unsigned char *)(dev->mem_start+from);
/* Leading byte? */
if (from&2) {
- *((char *)target)++ = *(((char *)ptr++)-1);
+ *target++ = ptr[-1];
+ ptr += 2;
count--;
}
while(count>=2)
{
- *target++=*ptr++; /* Copy and */
- ptr++; /* skip cruft */
+ *(unsigned short *)target = *(unsigned short volatile *)ptr;
+ ptr += 4; /* skip cruft */
+ target += 2;
count-=2;
}
/* Trailing byte? */
if(count)
- {
- /* Big endian */
- unsigned short v=*ptr;
- *((char *)target)=v>>8;
- }
+ *target = *ptr;
}
static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count)
{
volatile unsigned short *ptr;
- const unsigned short *src=from;
+ const unsigned char *src=from;
to<<=1; /* word, skip overhead */
ptr=(unsigned short *)(dev->mem_start+to);
/* Leading byte? */
if (to&2) { /* avoid a byte write (stomps on other data) */
- ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++;
+ ptr[-1] = (ptr[-1]&0xFF00)|*src++;
ptr++;
count--;
}
while(count>=2)
{
- *ptr++=*src++; /* Copy and */
+ *ptr++=*(unsigned short *)src; /* Copy and */
ptr++; /* skip cruft */
+ src += 2;
count-=2;
}
/* Trailing byte? */
if(count)
{
- /* Big endian */
- unsigned short v=*src;
/* card doesn't like byte writes */
- *ptr=(*ptr&0x00FF)|(v&0xFF00);
+ *ptr=(*ptr&0x00FF)|(*src << 8);
}
}
const unsigned char *buf, int start_page)
{
long shmem = (start_page - WD_START_PG)<<8;
-
+
memcpy_toio((char *)dev->mem_start + shmem, buf, count);
}
int start_page)
{
long shmem = (start_page - WD_START_PG)<<8;
-
+
dayna_memcpy_tocard(dev, shmem, buf, count);
}
/* Cabletron block I/O */
-static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page)
{
unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
*to++=*from++;
}
-
+