Commit 6896827e authored by Jeff Garzik's avatar Jeff Garzik

Merge mandrakesoft.com:/home/jgarzik/repo/linus-2.5

into mandrakesoft.com:/home/jgarzik/repo/net-drivers-2.5
parents 461a50a3 7d42b087
...@@ -1525,6 +1525,13 @@ CONFIG_SUNDANCE ...@@ -1525,6 +1525,13 @@ CONFIG_SUNDANCE
More specific information and updates are available from More specific information and updates are available from
<http://www.scyld.com/network/sundance.html>. <http://www.scyld.com/network/sundance.html>.
CONFIG_SUNDANCE_MMIO
Enable memory-mapped I/O for interaction with Sundance NIC registers.
Do NOT enable this by default, PIO (enabled when MMIO is disabled)
is known to solve bugs on certain chips.
If unsure, say N.
CONFIG_ZNET CONFIG_ZNET
The Zenith Z-Note notebook computer has a built-in network The Zenith Z-Note notebook computer has a built-in network
(Ethernet) card, and this is the Linux driver for it. Note that the (Ethernet) card, and this is the Linux driver for it. Note that the
......
...@@ -177,6 +177,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then ...@@ -177,6 +177,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
dep_tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI dep_tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI
dep_tristate ' SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI dep_tristate ' SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI
dep_tristate ' Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI dep_tristate ' Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI
dep_mbool ' Use MMIO instead of PIO' CONFIG_SUNDANCE_MMIO $CONFIG_SUNDANCE
if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
tristate ' TI ThunderLAN support' CONFIG_TLAN tristate ' TI ThunderLAN support' CONFIG_TLAN
fi fi
......
...@@ -70,7 +70,7 @@ obj-$(CONFIG_AIRONET4500_PROC) += aironet4500_proc.o ...@@ -70,7 +70,7 @@ obj-$(CONFIG_AIRONET4500_PROC) += aironet4500_proc.o
obj-$(CONFIG_AIRONET4500_CS) += aironet4500_proc.o obj-$(CONFIG_AIRONET4500_CS) += aironet4500_proc.o
obj-$(CONFIG_WINBOND_840) += mii.o obj-$(CONFIG_WINBOND_840) += mii.o
obj-$(CONFIG_SUNDANCE) += sundance.o obj-$(CONFIG_SUNDANCE) += sundance.o mii.o
obj-$(CONFIG_HAMACHI) += hamachi.o obj-$(CONFIG_HAMACHI) += hamachi.o
obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o
obj-$(CONFIG_SEEQ8005) += seeq8005.o obj-$(CONFIG_SEEQ8005) += seeq8005.o
......
...@@ -850,7 +850,30 @@ static int __devinit speedo_found1(struct pci_dev *pdev, ...@@ -850,7 +850,30 @@ static int __devinit speedo_found1(struct pci_dev *pdev,
return 0; return 0;
} }
static void do_slow_command(struct net_device *dev, int cmd)
{
long cmd_ioaddr = dev->base_addr + SCBCmd;
int wait = 0;
do
if (inb(cmd_ioaddr) == 0) break;
while(++wait <= 200);
if (wait > 100)
printk(KERN_ERR "Command %4.4x never accepted (%d polls)!\n",
inb(cmd_ioaddr), wait);
outb(cmd, cmd_ioaddr);
for (wait = 0; wait <= 100; wait++)
if (inb(cmd_ioaddr) == 0) return;
for (; wait <= 20000; wait++)
if (inb(cmd_ioaddr) == 0) return;
else udelay(1);
printk(KERN_ERR "Command %4.4x was not accepted after %d polls!"
" Current status %8.8x.\n",
cmd, wait, inl(dev->base_addr + SCBStatus));
}
/* Serial EEPROM section. /* Serial EEPROM section.
A "bit" grungy, but we work our way through bit-by-bit :->. */ A "bit" grungy, but we work our way through bit-by-bit :->. */
/* EEPROM_Ctrl bits. */ /* EEPROM_Ctrl bits. */
...@@ -1015,7 +1038,7 @@ speedo_open(struct net_device *dev) ...@@ -1015,7 +1038,7 @@ speedo_open(struct net_device *dev)
/* Start the chip hardware after a full reset. */ /* Start the chip hardware after a full reset. */
static void speedo_resume(struct net_device *dev) static void speedo_resume(struct net_device *dev)
{ {
struct speedo_private *sp = (struct speedo_private *)dev->priv; struct speedo_private *sp = dev->priv;
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
/* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */ /* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */
...@@ -1023,34 +1046,40 @@ static void speedo_resume(struct net_device *dev) ...@@ -1023,34 +1046,40 @@ static void speedo_resume(struct net_device *dev)
/* Set the segment registers to '0'. */ /* Set the segment registers to '0'. */
wait_for_cmd_done(ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd);
outl(0, ioaddr + SCBPointer); if (inb(ioaddr + SCBCmd)) {
/* impose a delay to avoid a bug */ outl(PortPartialReset, ioaddr + SCBPort);
inl(ioaddr + SCBPointer);
udelay(10); udelay(10);
outb(RxAddrLoad, ioaddr + SCBCmd); }
wait_for_cmd_done(ioaddr + SCBCmd);
outb(CUCmdBase, ioaddr + SCBCmd); outl(0, ioaddr + SCBPointer);
inl(ioaddr + SCBPointer); /* Flush to PCI. */
udelay(10); /* Bogus, but it avoids the bug. */
/* Note: these next two operations can take a while. */
do_slow_command(dev, RxAddrLoad);
do_slow_command(dev, CUCmdBase);
/* Load the statistics block and rx ring addresses. */ /* Load the statistics block and rx ring addresses. */
wait_for_cmd_done(ioaddr + SCBCmd);
outl(sp->lstats_dma, ioaddr + SCBPointer); outl(sp->lstats_dma, ioaddr + SCBPointer);
inl(ioaddr + SCBPointer); /* Flush to PCI */
outb(CUStatsAddr, ioaddr + SCBCmd); outb(CUStatsAddr, ioaddr + SCBCmd);
sp->lstats->done_marker = 0; sp->lstats->done_marker = 0;
wait_for_cmd_done(ioaddr + SCBCmd);
if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) { if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) {
if (speedo_debug > 2) if (speedo_debug > 2)
printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n", printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n",
dev->name); dev->name);
} else { } else {
wait_for_cmd_done(ioaddr + SCBCmd);
outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE], outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
ioaddr + SCBPointer); ioaddr + SCBPointer);
outb(RxStart, ioaddr + SCBCmd); inl(ioaddr + SCBPointer); /* Flush to PCI */
} }
wait_for_cmd_done(ioaddr + SCBCmd); /* Note: RxStart should complete instantly. */
outb(CUDumpStats, ioaddr + SCBCmd); do_slow_command(dev, RxStart);
udelay(30); do_slow_command(dev, CUDumpStats);
/* Fill the first command with our physical address. */ /* Fill the first command with our physical address. */
{ {
...@@ -1063,11 +1092,12 @@ static void speedo_resume(struct net_device *dev) ...@@ -1063,11 +1092,12 @@ static void speedo_resume(struct net_device *dev)
ias_cmd->link = ias_cmd->link =
cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE)); cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE));
memcpy(ias_cmd->params, dev->dev_addr, 6); memcpy(ias_cmd->params, dev->dev_addr, 6);
if (sp->last_cmd)
clear_suspend(sp->last_cmd);
sp->last_cmd = ias_cmd; sp->last_cmd = ias_cmd;
} }
/* Start the chip's Tx process and unmask interrupts. */ /* Start the chip's Tx process and unmask interrupts. */
wait_for_cmd_done(ioaddr + SCBCmd);
outl(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE), outl(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE),
ioaddr + SCBPointer); ioaddr + SCBPointer);
/* We are not ACK-ing FCP and ER in the interrupt handler yet so they should /* We are not ACK-ing FCP and ER in the interrupt handler yet so they should
......
...@@ -18,26 +18,54 @@ ...@@ -18,26 +18,54 @@
http://www.scyld.com/network/sundance.html http://www.scyld.com/network/sundance.html
Version 1.01a (jgarzik): Version LK1.01a (jgarzik):
- Replace some MII-related magic numbers with constants - Replace some MII-related magic numbers with constants
Version 1.02 (D-Link): Version LK1.02 (D-Link):
- Add new board to PCI ID list - Add new board to PCI ID list
- Fix multicast bug - Fix multicast bug
Version 1.03 (D-Link): Version LK1.03 (D-Link):
- New Rx scheme, reduce Rx congestion - New Rx scheme, reduce Rx congestion
- Option to disable flow control - Option to disable flow control
Version 1.04 (D-Link): Version LK1.04 (D-Link):
- Tx timeout recovery - Tx timeout recovery
- More support for ethtool. - More support for ethtool.
Version LK1.04a:
- Remove unused/constant members from struct pci_id_info
(which then allows removal of 'drv_flags' from private struct)
(jgarzik)
- If no phy is found, fail to load that board (jgarzik)
- Always start phy id scan at id 1 to avoid problems (Donald Becker)
- Autodetect where mii_preable_required is needed,
default to not needed. (Donald Becker)
Version LK1.04b:
- Remove mii_preamble_required module parameter (Donald Becker)
- Add per-interface mii_preamble_required (setting is autodetected)
(Donald Becker)
- Remove unnecessary cast from void pointer (jgarzik)
- Re-align comments in private struct (jgarzik)
Version LK1.04c (jgarzik):
- Support bitmapped message levels (NETIF_MSG_xxx), and the
two ethtool ioctls that get/set them
- Don't hand-code MII ethtool support, use standard API/lib
Version LK1.04d:
- Merge from Donald Becker's sundance.c: (Jason Lunz)
* proper support for variably-sized MTUs
* default to PIO, to fix chip bugs
- Add missing unregister_netdev (Jason Lunz)
- Add CONFIG_SUNDANCE_MMIO config option (jgarzik)
*/ */
#define DRV_NAME "sundance" #define DRV_NAME "sundance"
#define DRV_VERSION "1.04" #define DRV_VERSION "1.01+LK1.04d"
#define DRV_RELDATE "19-Aug-2002" #define DRV_RELDATE "19-Sep-2002"
/* The user-configurable values. /* The user-configurable values.
...@@ -45,7 +73,6 @@ ...@@ -45,7 +73,6 @@
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 0; static int max_interrupt_work = 0;
static int mtu;
/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
Typical is a 64 element hash table based on the Ethernet CRC. */ Typical is a 64 element hash table based on the Ethernet CRC. */
static int multicast_filter_limit = 32; static int multicast_filter_limit = 32;
...@@ -72,6 +99,8 @@ static int flowctrl=1; ...@@ -72,6 +99,8 @@ static int flowctrl=1;
*/ */
#define MAX_UNITS 8 #define MAX_UNITS 8
static char *media[MAX_UNITS]; static char *media[MAX_UNITS];
/* Operational parameters that are set at compile time. */ /* Operational parameters that are set at compile time. */
/* Keep the ring sizes a power of two for compile efficiency. /* Keep the ring sizes a power of two for compile efficiency.
...@@ -140,16 +169,15 @@ MODULE_DESCRIPTION("Sundance Alta Ethernet driver"); ...@@ -140,16 +169,15 @@ MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(mtu, "i");
MODULE_PARM(debug, "i"); MODULE_PARM(debug, "i");
MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(rx_copybreak, "i");
MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s"); MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s");
MODULE_PARM(flowctrl, "i"); MODULE_PARM(flowctrl, "i");
MODULE_PARM_DESC(max_interrupt_work, "Sundance Alta maximum events handled per interrupt"); MODULE_PARM_DESC(max_interrupt_work, "Sundance Alta maximum events handled per interrupt");
MODULE_PARM_DESC(mtu, "Sundance Alta MTU (all boards)");
MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)"); MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)");
MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]"); MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]");
/* /*
Theory of Operation Theory of Operation
...@@ -224,19 +252,9 @@ IVc. Errata ...@@ -224,19 +252,9 @@ IVc. Errata
*/ */
/* Work-around for Kendin chip bugs. */
enum pci_id_flags_bits { #ifndef CONFIG_SUNDANCE_MMIO
/* Set PCI command register bits before calling probe1(). */ #define USE_IO_OPS 1
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
/* Read and map the single following PCI BAR. */
PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
};
enum chip_capability_flags {CanHaveMII=1, };
#ifdef USE_IO_OPS
#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
#else
#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
#endif #endif
static struct pci_device_id sundance_pci_tbl[] __devinitdata = { static struct pci_device_id sundance_pci_tbl[] __devinitdata = {
...@@ -250,31 +268,20 @@ static struct pci_device_id sundance_pci_tbl[] __devinitdata = { ...@@ -250,31 +268,20 @@ static struct pci_device_id sundance_pci_tbl[] __devinitdata = {
}; };
MODULE_DEVICE_TABLE(pci, sundance_pci_tbl); MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
enum {
netdev_io_size = 128
};
struct pci_id_info { struct pci_id_info {
const char *name; const char *name;
struct match_info {
int pci, pci_mask, subsystem, subsystem_mask;
int revision, revision_mask; /* Only 8 bits. */
} id;
enum pci_id_flags_bits pci_flags;
int io_size; /* Needed for I/O region check or ioremap(). */
int drv_flags; /* Driver use, intended as capability flags. */
}; };
static struct pci_id_info pci_id_tbl[] = { static struct pci_id_info pci_id_tbl[] = {
{"D-Link DFE-550TX FAST Ethernet Adapter", {0x10021186, 0xffffffff,}, {"D-Link DFE-550TX FAST Ethernet Adapter"},
PCI_IOTYPE, 128, CanHaveMII}, {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter", {"D-Link DFE-580TX 4 port Server Adapter"},
{0x10031186, 0xffffffff,}, {"D-Link DFE-530TXS FAST Ethernet Adapter"},
PCI_IOTYPE, 128, CanHaveMII}, {"D-Link DL10050-based FAST Ethernet Adapter"},
{"D-Link DFE-580TX 4 port Server Adapter", {0x10121186, 0xffffffff,}, {"Sundance Technology Alta"},
PCI_IOTYPE, 128, CanHaveMII},
{"D-Link DFE-530TXS FAST Ethernet Adapter", {0x10021186, 0xffffffff,},
PCI_IOTYPE, 128, CanHaveMII},
{"D-Link DL10050-based FAST Ethernet Adapter",
{0x10021186, 0xffffffff,},
PCI_IOTYPE, 128, CanHaveMII},
{"Sundance Technology Alta", {0x020113F0, 0xffffffff,},
PCI_IOTYPE, 128, CanHaveMII},
{0,}, /* 0 terminated list. */ {0,}, /* 0 terminated list. */
}; };
...@@ -331,7 +338,7 @@ enum alta_offsets { ...@@ -331,7 +338,7 @@ enum alta_offsets {
MACCtrl0 = 0x50, MACCtrl0 = 0x50,
MACCtrl1 = 0x52, MACCtrl1 = 0x52,
StationAddr = 0x54, StationAddr = 0x54,
MaxTxSize = 0x5A, MaxFrameSize = 0x5A,
RxMode = 0x5c, RxMode = 0x5c,
MIICtrl = 0x5e, MIICtrl = 0x5e,
MulticastFilter0 = 0x60, MulticastFilter0 = 0x60,
...@@ -430,13 +437,13 @@ struct netdev_private { ...@@ -430,13 +437,13 @@ struct netdev_private {
/* Frequently used values: keep some adjacent for cache effect. */ /* Frequently used values: keep some adjacent for cache effect. */
spinlock_t lock; spinlock_t lock;
spinlock_t rx_lock; /* Group with Tx control cache line. */ spinlock_t rx_lock; /* Group with Tx control cache line. */
int chip_id, drv_flags; int msg_enable;
int chip_id;
unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int rx_buf_sz; /* Based on MTU+slack. */
struct netdev_desc *last_tx; /* Last Tx descriptor used. */ struct netdev_desc *last_tx; /* Last Tx descriptor used. */
unsigned int cur_tx, dirty_tx; unsigned int cur_tx, dirty_tx;
/* These values are keep track of the transceiver/media in use. */ /* These values are keep track of the transceiver/media in use. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
unsigned int flowctrl:1; unsigned int flowctrl:1;
unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int default_port:4; /* Last dev->if_port value. */
unsigned int an_enable:1; unsigned int an_enable:1;
...@@ -447,8 +454,8 @@ struct netdev_private { ...@@ -447,8 +454,8 @@ struct netdev_private {
spinlock_t mcastlock; /* SMP lock multicast updates. */ spinlock_t mcastlock; /* SMP lock multicast updates. */
u16 mcast_filter[4]; u16 mcast_filter[4];
/* MII transceiver section. */ /* MII transceiver section. */
int mii_cnt; /* MII device addresses. */ struct mii_if_info mii_if;
u16 advertising; /* NWay media advertisement */ int mii_preamble_required;
unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */
struct pci_dev *pci_dev; struct pci_dev *pci_dev;
}; };
...@@ -459,6 +466,7 @@ struct netdev_private { ...@@ -459,6 +466,7 @@ struct netdev_private {
IntrDrvRqst | IntrTxDone | StatsMax | \ IntrDrvRqst | IntrTxDone | StatsMax | \
LinkChange) LinkChange)
static int change_mtu(struct net_device *dev, int new_mtu);
static int eeprom_read(long ioaddr, int location); static int eeprom_read(long ioaddr, int location);
static int mdio_read(struct net_device *dev, int phy_id, int location); static int mdio_read(struct net_device *dev, int phy_id, int location);
static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
...@@ -479,7 +487,7 @@ static struct net_device_stats *get_stats(struct net_device *dev); ...@@ -479,7 +487,7 @@ static struct net_device_stats *get_stats(struct net_device *dev);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int netdev_close(struct net_device *dev); static int netdev_close(struct net_device *dev);
static int __devinit sundance_probe1 (struct pci_dev *pdev, static int __devinit sundance_probe1 (struct pci_dev *pdev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
...@@ -521,7 +529,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, ...@@ -521,7 +529,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
ioaddr = pci_resource_start(pdev, 0); ioaddr = pci_resource_start(pdev, 0);
#else #else
ioaddr = pci_resource_start(pdev, 1); ioaddr = pci_resource_start(pdev, 1);
ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size); ioaddr = (long) ioremap (ioaddr, netdev_io_size);
if (!ioaddr) if (!ioaddr)
goto err_out_res; goto err_out_res;
#endif #endif
...@@ -534,9 +542,9 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, ...@@ -534,9 +542,9 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
dev->irq = irq; dev->irq = irq;
np = dev->priv; np = dev->priv;
np->chip_id = chip_idx;
np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
np->pci_dev = pdev; np->pci_dev = pdev;
np->chip_id = chip_idx;
np->msg_enable = (1 << debug) - 1;
spin_lock_init(&np->lock); spin_lock_init(&np->lock);
tasklet_init(&np->rx_tasklet, rx_poll, (unsigned long)dev); tasklet_init(&np->rx_tasklet, rx_poll, (unsigned long)dev);
...@@ -552,6 +560,10 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, ...@@ -552,6 +560,10 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
np->rx_ring = (struct netdev_desc *)ring_space; np->rx_ring = (struct netdev_desc *)ring_space;
np->rx_ring_dma = ring_dma; np->rx_ring_dma = ring_dma;
np->mii_if.dev = dev;
np->mii_if.mdio_read = mdio_read;
np->mii_if.mdio_write = mdio_write;
/* The chip-specific entries in the device structure. */ /* The chip-specific entries in the device structure. */
dev->open = &netdev_open; dev->open = &netdev_open;
dev->hard_start_xmit = &start_tx; dev->hard_start_xmit = &start_tx;
...@@ -561,11 +573,9 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, ...@@ -561,11 +573,9 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
dev->do_ioctl = &netdev_ioctl; dev->do_ioctl = &netdev_ioctl;
dev->tx_timeout = &tx_timeout; dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT; dev->watchdog_timeo = TX_TIMEOUT;
dev->change_mtu = &change_mtu;
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
if (mtu)
dev->mtu = mtu;
i = register_netdev(dev); i = register_netdev(dev);
if (i) if (i)
goto err_out_unmap_rx; goto err_out_unmap_rx;
...@@ -579,21 +589,30 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, ...@@ -579,21 +589,30 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
if (1) { if (1) {
int phy, phy_idx = 0; int phy, phy_idx = 0;
np->phys[0] = 1; /* Default setting */ np->phys[0] = 1; /* Default setting */
for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { np->mii_preamble_required++;
int mii_status = mdio_read(dev, phy, 1); for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
int mii_status = mdio_read(dev, phy, MII_BMSR);
if (mii_status != 0xffff && mii_status != 0x0000) { if (mii_status != 0xffff && mii_status != 0x0000) {
np->phys[phy_idx++] = phy; np->phys[phy_idx++] = phy;
np->advertising = mdio_read(dev, phy, 4); np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
if ((mii_status & 0x0040) == 0)
np->mii_preamble_required++;
printk(KERN_INFO "%s: MII PHY found at address %d, status " printk(KERN_INFO "%s: MII PHY found at address %d, status "
"0x%4.4x advertising %4.4x.\n", "0x%4.4x advertising %4.4x.\n",
dev->name, phy, mii_status, np->advertising); dev->name, phy, mii_status, np->mii_if.advertising);
} }
} }
np->mii_cnt = phy_idx; np->mii_preamble_required--;
if (phy_idx == 0)
printk(KERN_INFO "%s: No MII transceiver found!, ASIC status %x\n", if (phy_idx == 0) {
printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n",
dev->name, readl(ioaddr + ASICCtrl)); dev->name, readl(ioaddr + ASICCtrl));
goto err_out_unregister;
} }
np->mii_if.phy_id = np->phys[0];
}
/* Parse override configuration */ /* Parse override configuration */
np->an_enable = 1; np->an_enable = 1;
if (card_idx < MAX_UNITS) { if (card_idx < MAX_UNITS) {
...@@ -602,19 +621,19 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, ...@@ -602,19 +621,19 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
if (strcmp (media[card_idx], "100mbps_fd") == 0 || if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
strcmp (media[card_idx], "4") == 0) { strcmp (media[card_idx], "4") == 0) {
np->speed = 100; np->speed = 100;
np->full_duplex = 1; np->mii_if.full_duplex = 1;
} else if (strcmp (media[card_idx], "100mbps_hd") == 0 } else if (strcmp (media[card_idx], "100mbps_hd") == 0
|| strcmp (media[card_idx], "3") == 0) { || strcmp (media[card_idx], "3") == 0) {
np->speed = 100; np->speed = 100;
np->full_duplex = 0; np->mii_if.full_duplex = 0;
} else if (strcmp (media[card_idx], "10mbps_fd") == 0 || } else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
strcmp (media[card_idx], "2") == 0) { strcmp (media[card_idx], "2") == 0) {
np->speed = 10; np->speed = 10;
np->full_duplex = 1; np->mii_if.full_duplex = 1;
} else if (strcmp (media[card_idx], "10mbps_hd") == 0 || } else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
strcmp (media[card_idx], "1") == 0) { strcmp (media[card_idx], "1") == 0) {
np->speed = 10; np->speed = 10;
np->full_duplex = 0; np->mii_if.full_duplex = 0;
} else { } else {
np->an_enable = 1; np->an_enable = 1;
} }
...@@ -632,7 +651,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, ...@@ -632,7 +651,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
/* Default 100Mbps Full */ /* Default 100Mbps Full */
if (np->an_enable) { if (np->an_enable) {
np->speed = 100; np->speed = 100;
np->full_duplex = 1; np->mii_if.full_duplex = 1;
np->an_enable = 0; np->an_enable = 0;
} }
} }
...@@ -644,24 +663,26 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, ...@@ -644,24 +663,26 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
if (!np->an_enable) { if (!np->an_enable) {
mii_ctl = 0; mii_ctl = 0;
mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0; mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0;
mii_ctl |= (np->full_duplex) ? BMCR_FULLDPLX : 0; mii_ctl |= (np->mii_if.full_duplex) ? BMCR_FULLDPLX : 0;
mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl); mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl);
printk (KERN_INFO "Override speed=%d, %s duplex\n", printk (KERN_INFO "Override speed=%d, %s duplex\n",
np->speed, np->full_duplex ? "Full" : "Half"); np->speed, np->mii_if.full_duplex ? "Full" : "Half");
} }
/* Perhaps move the reset here? */ /* Perhaps move the reset here? */
/* Reset the chip to erase previous misconfiguration. */ /* Reset the chip to erase previous misconfiguration. */
if (debug > 1) if (netif_msg_hw(np))
printk("ASIC Control is %x.\n", readl(ioaddr + ASICCtrl)); printk("ASIC Control is %x.\n", readl(ioaddr + ASICCtrl));
writew(0x007f, ioaddr + ASICCtrl + 2); writew(0x007f, ioaddr + ASICCtrl + 2);
if (debug > 1) if (netif_msg_hw(np))
printk("ASIC Control is now %x.\n", readl(ioaddr + ASICCtrl)); printk("ASIC Control is now %x.\n", readl(ioaddr + ASICCtrl));
card_idx++; card_idx++;
return 0; return 0;
err_out_unregister:
unregister_netdev(dev);
err_out_unmap_rx: err_out_unmap_rx:
pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
err_out_unmap_tx: err_out_unmap_tx:
...@@ -678,7 +699,16 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, ...@@ -678,7 +699,16 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
return -ENODEV; return -ENODEV;
} }
static int change_mtu(struct net_device *dev, int new_mtu)
{
if ((new_mtu < 68) || (new_mtu > 8191)) /* Set by RxDMAFrameLen */
return -EINVAL;
if (netif_running(dev))
return -EBUSY;
dev->mtu = new_mtu;
return 0;
}
/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */ /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
static int __devinit eeprom_read(long ioaddr, int location) static int __devinit eeprom_read(long ioaddr, int location)
{ {
...@@ -701,11 +731,6 @@ static int __devinit eeprom_read(long ioaddr, int location) ...@@ -701,11 +731,6 @@ static int __devinit eeprom_read(long ioaddr, int location)
met by back-to-back 33Mhz PCI cycles. */ met by back-to-back 33Mhz PCI cycles. */
#define mdio_delay() readb(mdio_addr) #define mdio_delay() readb(mdio_addr)
/* Set iff a MII transceiver on any interface requires mdio preamble.
This only set with older tranceivers, so the extra
code size of a per-interface flag is not worthwhile. */
static const char mii_preamble_required = 1;
enum mii_reg_bits { enum mii_reg_bits {
MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004, MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,
}; };
...@@ -730,11 +755,12 @@ static void mdio_sync(long mdio_addr) ...@@ -730,11 +755,12 @@ static void mdio_sync(long mdio_addr)
static int mdio_read(struct net_device *dev, int phy_id, int location) static int mdio_read(struct net_device *dev, int phy_id, int location)
{ {
struct netdev_private *np = dev->priv;
long mdio_addr = dev->base_addr + MIICtrl; long mdio_addr = dev->base_addr + MIICtrl;
int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
int i, retval = 0; int i, retval = 0;
if (mii_preamble_required) if (np->mii_preamble_required)
mdio_sync(mdio_addr); mdio_sync(mdio_addr);
/* Shift the read command bits out. */ /* Shift the read command bits out. */
...@@ -759,11 +785,12 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) ...@@ -759,11 +785,12 @@ static int mdio_read(struct net_device *dev, int phy_id, int location)
static void mdio_write(struct net_device *dev, int phy_id, int location, int value) static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
{ {
struct netdev_private *np = dev->priv;
long mdio_addr = dev->base_addr + MIICtrl; long mdio_addr = dev->base_addr + MIICtrl;
int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
int i; int i;
if (mii_preamble_required) if (np->mii_preamble_required)
mdio_sync(mdio_addr); mdio_sync(mdio_addr);
/* Shift the command bits out. */ /* Shift the command bits out. */
...@@ -797,7 +824,7 @@ static int netdev_open(struct net_device *dev) ...@@ -797,7 +824,7 @@ static int netdev_open(struct net_device *dev)
if (i) if (i)
return i; return i;
if (debug > 1) if (netif_msg_ifup(np))
printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
dev->name, dev->irq); dev->name, dev->irq);
...@@ -810,6 +837,10 @@ static int netdev_open(struct net_device *dev) ...@@ -810,6 +837,10 @@ static int netdev_open(struct net_device *dev)
writeb(dev->dev_addr[i], ioaddr + StationAddr + i); writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
/* Initialize other registers. */ /* Initialize other registers. */
writew(dev->mtu + 14, ioaddr + MaxFrameSize);
if (dev->mtu > 2047)
writel(readl(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl);
/* Configure the PCI bus bursts and FIFO thresholds. */ /* Configure the PCI bus bursts and FIFO thresholds. */
if (dev->if_port == 0) if (dev->if_port == 0)
...@@ -827,7 +858,7 @@ static int netdev_open(struct net_device *dev) ...@@ -827,7 +858,7 @@ static int netdev_open(struct net_device *dev)
writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
if (debug > 2) if (netif_msg_ifup(np))
printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x " printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x "
"MAC Control %x, %4.4x %4.4x.\n", "MAC Control %x, %4.4x %4.4x.\n",
dev->name, readl(ioaddr + RxStatus), readb(ioaddr + TxStatus), dev->name, readl(ioaddr + RxStatus), readb(ioaddr + TxStatus),
...@@ -852,21 +883,22 @@ static void check_duplex(struct net_device *dev) ...@@ -852,21 +883,22 @@ static void check_duplex(struct net_device *dev)
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA); int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
int negotiated = mii_lpa & np->advertising; int negotiated = mii_lpa & np->mii_if.advertising;
int duplex; int duplex;
/* Force media */ /* Force media */
if (!np->an_enable || mii_lpa == 0xffff) { if (!np->an_enable || mii_lpa == 0xffff) {
if (np->full_duplex) if (np->mii_if.full_duplex)
writew (readw (ioaddr + MACCtrl0) | EnbFullDuplex, writew (readw (ioaddr + MACCtrl0) | EnbFullDuplex,
ioaddr + MACCtrl0); ioaddr + MACCtrl0);
return; return;
} }
/* Autonegotiation */ /* Autonegotiation */
duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
if (np->full_duplex != duplex) { if (np->mii_if.full_duplex != duplex) {
np->full_duplex = duplex; np->mii_if.full_duplex = duplex;
if (debug) if (netif_msg_link(np))
printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d " printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "
"negotiated capability %4.4x.\n", dev->name, "negotiated capability %4.4x.\n", dev->name,
duplex ? "full" : "half", np->phys[0], negotiated); duplex ? "full" : "half", np->phys[0], negotiated);
...@@ -881,7 +913,7 @@ static void netdev_timer(unsigned long data) ...@@ -881,7 +913,7 @@ static void netdev_timer(unsigned long data)
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
int next_tick = 10*HZ; int next_tick = 10*HZ;
if (debug > 3) { if (netif_msg_timer(np)) {
printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, " printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, "
"Tx %x Rx %x.\n", "Tx %x Rx %x.\n",
dev->name, readw(ioaddr + IntrEnable), dev->name, readw(ioaddr + IntrEnable),
...@@ -941,7 +973,7 @@ static void init_ring(struct net_device *dev) ...@@ -941,7 +973,7 @@ static void init_ring(struct net_device *dev)
np->cur_rx = np->cur_tx = 0; np->cur_rx = np->cur_tx = 0;
np->dirty_rx = np->dirty_tx = 0; np->dirty_rx = np->dirty_tx = 0;
np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 36);
/* Initialize all Rx descriptors. */ /* Initialize all Rx descriptors. */
for (i = 0; i < RX_RING_SIZE; i++) { for (i = 0; i < RX_RING_SIZE; i++) {
...@@ -977,7 +1009,7 @@ static void init_ring(struct net_device *dev) ...@@ -977,7 +1009,7 @@ static void init_ring(struct net_device *dev)
static int static int
start_tx (struct sk_buff *skb, struct net_device *dev) start_tx (struct sk_buff *skb, struct net_device *dev)
{ {
struct netdev_private *np = (struct netdev_private *) dev->priv; struct netdev_private *np = dev->priv;
struct netdev_desc *txdesc; struct netdev_desc *txdesc;
unsigned entry; unsigned entry;
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
...@@ -1022,7 +1054,7 @@ start_tx (struct sk_buff *skb, struct net_device *dev) ...@@ -1022,7 +1054,7 @@ start_tx (struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies; dev->trans_start = jiffies;
if (debug > 4) { if (netif_msg_tx_queued(np)) {
printk (KERN_DEBUG printk (KERN_DEBUG
"%s: Transmit frame #%d queued in slot %d.\n", "%s: Transmit frame #%d queued in slot %d.\n",
dev->name, np->cur_tx, entry); dev->name, np->cur_tx, entry);
...@@ -1085,7 +1117,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) ...@@ -1085,7 +1117,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
int intr_status = readw(ioaddr + IntrStatus); int intr_status = readw(ioaddr + IntrStatus);
writew(intr_status, ioaddr + IntrStatus); writew(intr_status, ioaddr + IntrStatus);
if (debug > 4) if (netif_msg_intr(np))
printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
dev->name, intr_status); dev->name, intr_status);
...@@ -1104,7 +1136,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) ...@@ -1104,7 +1136,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
int boguscnt = 32; int boguscnt = 32;
int tx_status = readw (ioaddr + TxStatus); int tx_status = readw (ioaddr + TxStatus);
while (tx_status & 0x80) { while (tx_status & 0x80) {
if (debug > 4) if (netif_msg_tx_done(np))
printk printk
("%s: Transmit status is %2.2x.\n", ("%s: Transmit status is %2.2x.\n",
dev->name, tx_status); dev->name, tx_status);
...@@ -1160,14 +1192,14 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) ...@@ -1160,14 +1192,14 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
netdev_error(dev, intr_status); netdev_error(dev, intr_status);
if (--boguscnt < 0) { if (--boguscnt < 0) {
get_stats(dev); get_stats(dev);
if (debug > 1) if (netif_msg_hw(np))
printk(KERN_WARNING "%s: Too much work at interrupt, " printk(KERN_WARNING "%s: Too much work at interrupt, "
"status=0x%4.4x / 0x%4.4x.\n", "status=0x%4.4x / 0x%4.4x.\n",
dev->name, intr_status, readw(ioaddr + IntrClear)); dev->name, intr_status, readw(ioaddr + IntrClear));
break; break;
} }
} while (1); } while (1);
if (debug > 3) if (netif_msg_intr(np))
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
dev->name, readw(ioaddr + IntrStatus)); dev->name, readw(ioaddr + IntrStatus));
if (np->cur_tx - np->dirty_tx > 0 && tx_coalesce > 1) if (np->cur_tx - np->dirty_tx > 0 && tx_coalesce > 1)
...@@ -1196,7 +1228,7 @@ static void rx_poll(unsigned long data) ...@@ -1196,7 +1228,7 @@ static void rx_poll(unsigned long data)
if (!(desc->status & DescOwn)) if (!(desc->status & DescOwn))
break; break;
pkt_len = frame_status & 0x1fff; /* Chip omits the CRC. */ pkt_len = frame_status & 0x1fff; /* Chip omits the CRC. */
if (debug > 4) if (netif_msg_rx_status(np))
printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n",
frame_status); frame_status);
pci_dma_sync_single(np->pci_dev, desc->frag[0].addr, pci_dma_sync_single(np->pci_dev, desc->frag[0].addr,
...@@ -1204,7 +1236,7 @@ static void rx_poll(unsigned long data) ...@@ -1204,7 +1236,7 @@ static void rx_poll(unsigned long data)
if (frame_status & 0x001f4000) { if (frame_status & 0x001f4000) {
/* There was a error. */ /* There was a error. */
if (debug > 2) if (netif_msg_rx_err(np))
printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n",
frame_status); frame_status);
np->stats.rx_errors++; np->stats.rx_errors++;
...@@ -1220,7 +1252,7 @@ static void rx_poll(unsigned long data) ...@@ -1220,7 +1252,7 @@ static void rx_poll(unsigned long data)
} else { } else {
struct sk_buff *skb; struct sk_buff *skb;
#ifndef final_version #ifndef final_version
if (debug > 4) if (netif_msg_rx_status(np))
printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d"
", bogus_cnt %d.\n", ", bogus_cnt %d.\n",
pkt_len, boguscnt); pkt_len, boguscnt);
...@@ -1421,12 +1453,12 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1421,12 +1453,12 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
{ {
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
u32 ethcmd; u32 ethcmd;
long ioaddr = dev->base_addr;
if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd))) if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
return -EFAULT; return -EFAULT;
switch (ethcmd) { switch (ethcmd) {
/* get constant driver settings/info */
case ETHTOOL_GDRVINFO: { case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
strcpy(info.driver, DRV_NAME); strcpy(info.driver, DRV_NAME);
...@@ -1437,116 +1469,60 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1437,116 +1469,60 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case ETHTOOL_GSET: {
struct ethtool_cmd cmd = { ETHTOOL_GSET };
if (readl (ioaddr + ASICCtrl) & 0x80) {
/* fiber device */
cmd.supported = SUPPORTED_Autoneg |
SUPPORTED_FIBRE;
cmd.advertising= ADVERTISED_Autoneg |
ADVERTISED_FIBRE;
cmd.port = PORT_FIBRE;
cmd.transceiver = XCVR_INTERNAL;
} else {
/* copper device */
cmd.supported = SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_MII;
cmd.advertising = ADVERTISED_10baseT_Half |
ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full |
ADVERTISED_Autoneg |
ADVERTISED_MII;
cmd.port = PORT_MII;
cmd.transceiver = XCVR_INTERNAL;
}
if (readb(ioaddr + MIICtrl) & 0x80) {
cmd.speed = np->speed;
cmd.duplex = np->full_duplex ?
DUPLEX_FULL : DUPLEX_HALF;
} else {
cmd.speed = -1;
cmd.duplex = -1;
}
if ( np->an_enable)
cmd.autoneg = AUTONEG_ENABLE;
else
cmd.autoneg = AUTONEG_DISABLE;
cmd.phy_address = np->phys[0]; /* get media settings */
case ETHTOOL_GSET: {
if (copy_to_user(useraddr, &cmd, struct ethtool_cmd ecmd = { ETHTOOL_GSET };
sizeof(cmd))) spin_lock_irq(&np->lock);
mii_ethtool_gset(&np->mii_if, &ecmd);
spin_unlock_irq(&np->lock);
if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
/* set media settings */
case ETHTOOL_SSET: { case ETHTOOL_SSET: {
struct ethtool_cmd cmd; int r;
if (copy_from_user(&cmd, useraddr, sizeof(cmd))) struct ethtool_cmd ecmd;
if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
return -EFAULT; return -EFAULT;
netif_carrier_off(dev); spin_lock_irq(&np->lock);
if (cmd.autoneg == AUTONEG_ENABLE) { r = mii_ethtool_sset(&np->mii_if, &ecmd);
if (np->an_enable) spin_unlock_irq(&np->lock);
return 0; return r;
else {
np->an_enable = 1;
/* Reset PHY */
mdio_write (dev, np->phys[0], MII_BMCR,
BMCR_RESET);
mdelay (300);
/* Start auto negotiation */
mdio_write (dev, np->phys[0], MII_BMCR,
BMCR_ANENABLE|BMCR_ANRESTART);
return 0;
} }
} else {
/* Reset PHY */
mdio_write (dev, np->phys[0], MII_BMCR,
BMCR_RESET);
mdelay (300);
np->an_enable = 0;
switch(cmd.speed + cmd.duplex){
case SPEED_10 + DUPLEX_HALF: /* restart autonegotiation */
np->speed = 10; case ETHTOOL_NWAY_RST: {
np->full_duplex = 0; return mii_nway_restart(&np->mii_if);
break;
case SPEED_10 + DUPLEX_FULL:
np->speed = 10;
np->full_duplex = 1;
break;
case SPEED_100 + DUPLEX_HALF:
np->speed = 100;
np->full_duplex = 0;
break;
case SPEED_100 + DUPLEX_FULL:
np->speed = 100;
np->full_duplex = 1;
break;
default:
return -EINVAL;
} }
mdio_write (dev, np->phys[0], MII_BMCR,
((np->speed == 100) ? BMCR_SPEED100 : 0) |
((np->full_duplex) ? BMCR_FULLDPLX : 0) );
/* get link status */
case ETHTOOL_GLINK: {
struct ethtool_value edata = {ETHTOOL_GLINK};
edata.data = mii_link_ok(&np->mii_if);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
} }
/* get message-level */
case ETHTOOL_GMSGLVL: {
struct ethtool_value edata = {ETHTOOL_GMSGLVL};
edata.data = np->msg_enable;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0; return 0;
} }
#ifdef ETHTOOL_GLINK /* set message-level */
case ETHTOOL_GLINK:{ case ETHTOOL_SMSGLVL: {
struct ethtool_value link = { ETHTOOL_GLINK }; struct ethtool_value edata;
link.data = readb(ioaddr + MIICtrl) & 0x80; if (copy_from_user(&edata, useraddr, sizeof(edata)))
if (copy_to_user(useraddr, &link, sizeof(link)))
return -EFAULT; return -EFAULT;
np->msg_enable = edata.data;
return 0; return 0;
} }
#endif
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -1587,7 +1563,7 @@ static int netdev_close(struct net_device *dev) ...@@ -1587,7 +1563,7 @@ static int netdev_close(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
if (debug > 1) { if (netif_msg_ifdown(np)) {
printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x " printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x "
"Rx %4.4x Int %2.2x.\n", "Rx %4.4x Int %2.2x.\n",
dev->name, readb(ioaddr + TxStatus), dev->name, readb(ioaddr + TxStatus),
...@@ -1603,7 +1579,7 @@ static int netdev_close(struct net_device *dev) ...@@ -1603,7 +1579,7 @@ static int netdev_close(struct net_device *dev)
writew(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1); writew(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
#ifdef __i386__ #ifdef __i386__
if (debug > 2) { if (netif_msg_hw(np)) {
printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
(int)(np->tx_ring_dma)); (int)(np->tx_ring_dma));
for (i = 0; i < TX_RING_SIZE; i++) for (i = 0; i < TX_RING_SIZE; i++)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment