diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 2affbc9ff0f03a81f53d8337d639884dd6dbca88..1f152226705c6fdb67047554c46d4576ed972f1e 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -47,10 +47,12 @@ - ethtool support v1.18b 1Mar2002 Zwane Mwaikambo <zwane@commfireservices.com> - Power Management support + v1.18c 1Mar2002 David Ruggiero <jdr@farfalle.com> + - Full duplex support */ #define DRV_NAME "3c509" -#define DRV_VERSION "1.18b" +#define DRV_VERSION "1.18c" #define DRV_RELDATE "1Mar2002" /* A few values that may be tweaked. */ @@ -141,6 +143,8 @@ enum RxFilter { #define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */ #define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */ #define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ +#define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */ +#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */ /* * Must be a power of two (we use a binary and in the @@ -500,12 +504,18 @@ int __init el3_probe(struct net_device *dev, int card_idx) memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); dev->base_addr = ioaddr; dev->irq = irq; - dev->if_port = (dev->mem_start & 0x1f) ? dev->mem_start & 3 : if_port; + + if (dev->mem_start & 0x05) { /* xcvr codes 1/3/4/12 */ + dev->if_port = (dev->mem_start & 0x0f); + } else { /* xcvr codes 0/8 */ + /* use eeprom value, but save user's full-duplex selection */ + dev->if_port = (if_port | (dev->mem_start & 0x08) ); + } { const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; printk("%s: 3c5x9 at %#3.3lx, %s port, address ", - dev->name, dev->base_addr, if_names[dev->if_port]); + dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)]); } /* Read in the station address. */ @@ -1083,7 +1093,7 @@ static void el3_down(struct net_device *dev) static void el3_up(struct net_device *dev) { - int i; + int i, sw_info, net_diag; int ioaddr = dev->base_addr; /* Activating the board required and does no harm otherwise */ @@ -1098,12 +1108,44 @@ static void el3_up(struct net_device *dev) for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + i); - if (dev->if_port == 3) + if ((dev->if_port & 0x03) == 3) /* BNC interface */ /* Start the thinnet transceiver. We should really wait 50ms...*/ outw(StartCoax, ioaddr + EL3_CMD); - else if (dev->if_port == 0) { - /* 10baseT interface, enabled link beat and jabber check. */ + else if ((dev->if_port & 0x03) == 0) { /* 10baseT interface */ + /* Combine secondary sw_info word (the adapter level) and primary + sw_info word (duplex setting plus other useless bits) */ + EL3WINDOW(0); + sw_info = (read_eeprom(ioaddr, 0x14) & 0x400f) | + (read_eeprom(ioaddr, 0x0d) & 0xBff0); + EL3WINDOW(4); + net_diag = inw(ioaddr + WN4_NETDIAG); + net_diag = (net_diag | FD_ENABLE); /* temporarily assume full-duplex will be set */ + printk("%s: ", dev->name); + switch (dev->if_port & 0x0c) { + case 12: + /* force full-duplex mode if 3c5x9b */ + if (sw_info & 0x000f) { + printk("Forcing 3c5x9b full-duplex mode"); + break; + } + case 8: + /* set full-duplex mode based on eeprom config setting */ + if ((sw_info & 0x000f) && (sw_info & 0x8000)) { + printk("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)"); + break; + } + default: + /* xcvr=(0 || 4) OR user has an old 3c5x9 non "B" model */ + printk("Setting 3c5x9/3c5x9B half-duplex mode"); + net_diag = (net_diag & ~FD_ENABLE); /* disable full duplex */ + } + + outw(net_diag, ioaddr + WN4_NETDIAG); + printk(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info); + if (el3_debug > 3) + printk("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_diag); + /* Enable link beat and jabber check. */ outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); } @@ -1208,11 +1250,11 @@ static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data) /* Parameters that may be passed into the module. */ static int debug = -1; static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int xcvr[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int xcvr[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; MODULE_PARM(debug,"i"); MODULE_PARM(irq,"1-8i"); -MODULE_PARM(xcvr,"1-8i"); +MODULE_PARM(xcvr,"1-12i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM_DESC(debug, "debug level (0-6)"); MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");