Commit 2c119559 authored by Richard Henderson's avatar Richard Henderson

Merge kanga.twiddle.home:/home/rth/work/linux/linus-2.5

into kanga.twiddle.home:/home/rth/work/linux/axp-2.5
parents c37e4ef0 30084613
......@@ -110,16 +110,18 @@ S: San Jose, California 95129
S: USA
N: Andrea Arcangeli
E: andrea@e-mind.com
W: http://e-mind.com/~andrea/
P: 1024/CB4660B9 CC A0 71 81 F4 A0 63 AC C0 4B 81 1D 8C 15 C8 E5
E: andrea@suse.de
W: http://www.kernel.org/pub/linux/kernel/people/andrea/
P: 1024D/68B9CB43 13D9 8355 295F 4823 7C49 C012 DFA1 686E 68B9 CB43
P: 1024R/CB4660B9 CC A0 71 81 F4 A0 63 AC C0 4B 81 1D 8C 15 C8 E5
D: Parport hacker
D: Implemented a workaround for some interrupt buggy printers
D: Author of pscan that helps to fix lp/parport bug
D: Author of pscan that helps to fix lp/parport bugs
D: Author of lil (Linux Interrupt Latency benchmark)
D: Fixed the shm swap deallocation at swapoff time (try_to_unuse message)
D: VM hacker
D: Various other kernel hacks
S: Via Ciaclini 26
S: Via Cicalini 26
S: Imola 40026
S: Italy
......
......@@ -82,7 +82,7 @@ static int DAC960_open(struct inode *inode, struct file *file)
} else {
DAC960_V2_LogicalDeviceInfo_T *i =
p->V2.LogicalDeviceInformation[drive_nr];
if (i->LogicalDeviceState == DAC960_V2_LogicalDevice_Offline)
if (!i || i->LogicalDeviceState == DAC960_V2_LogicalDevice_Offline)
return -ENXIO;
}
......
......@@ -25,13 +25,12 @@ struct eisa_device_info {
char name[DEVICE_NAME_SIZE];
};
static struct eisa_device_info __initdata eisa_table[] = {
#ifdef CONFIG_EISA_NAMES
static struct eisa_device_info __initdata eisa_table[] = {
#include "devlist.h"
#endif
};
#define EISA_INFOS (sizeof (eisa_table) / (sizeof (struct eisa_device_info)))
#endif
#define EISA_MAX_FORCED_DEV 16
#define EISA_FORCED_OFFSET 2
......@@ -59,11 +58,11 @@ static int is_forced_dev (int *forced_tab,
static void __init eisa_name_device (struct eisa_device *edev)
{
#ifdef CONFIG_EISA_NAMES
int i;
for (i = 0; i < EISA_INFOS; i++) {
if (!strcmp (edev->id.sig, eisa_table[i].id.sig)) {
strlcpy (edev->dev.name,
strlcpy (edev->pretty_name,
eisa_table[i].name,
DEVICE_NAME_SIZE);
return;
......@@ -71,7 +70,8 @@ static void __init eisa_name_device (struct eisa_device *edev)
}
/* No name was found */
sprintf (edev->dev.name, "EISA device %.7s", edev->id.sig);
sprintf (edev->pretty_name, "EISA device %.7s", edev->id.sig);
#endif
}
static char __init *decode_eisa_sig(unsigned long addr)
......@@ -172,7 +172,6 @@ static int __init eisa_init_device (struct eisa_root_device *root,
{
char *sig;
unsigned long sig_addr;
int i;
sig_addr = SLOT_ADDRESS (root, slot) + EISA_VENDOR_ID_OFFSET;
......@@ -190,8 +189,13 @@ static int __init eisa_init_device (struct eisa_root_device *root,
edev->dev.dma_mask = &edev->dma_mask;
sprintf (edev->dev.bus_id, "%02X:%02X", root->bus_nr, slot);
#ifdef CONFIG_EISA_NAMES
{
int i;
for (i = 0; i < EISA_MAX_RESOURCES; i++)
edev->res[i].name = edev->dev.name;
edev->res[i].name = edev->pretty_name;
}
#endif
if (is_forced_dev (enable_dev, root, edev))
edev->state = EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED;
......@@ -270,8 +274,7 @@ static int __init eisa_probe (struct eisa_root_device *root)
int i, c;
struct eisa_device *edev;
printk (KERN_INFO "EISA: Probing bus %d at %s\n",
root->bus_nr, root->dev->name);
printk (KERN_INFO "EISA: Probing bus %d\n", root->bus_nr);
/* First try to get hold of slot 0. If there is no device
* here, simply fail, unless root->force_probe is set. */
......
......@@ -2042,6 +2042,17 @@ config R8169
say M here and read <file:Documentation/modules.txt>. This is
recommended. The module will be called r8169.
config SIS190
tristate "SiS190 gigabit ethernet support (EXPERIMENTAL)"
depends on PCI && EXPERIMENTAL
---help---
Say Y here if you have a SiS 190 PCI Gigabit Ethernet adapter.
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. This is
recommended. The module will be called sis190.
config SK98LIN
tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support"
depends on PCI
......
......@@ -41,6 +41,7 @@ obj-$(CONFIG_PCNET32) += pcnet32.o mii.o
obj-$(CONFIG_EEPRO100) += eepro100.o mii.o
obj-$(CONFIG_TLAN) += tlan.o
obj-$(CONFIG_EPIC100) += epic100.o mii.o
obj-$(CONFIG_SIS190) += sis190.o
obj-$(CONFIG_SIS900) += sis900.o
obj-$(CONFIG_YELLOWFIN) += yellowfin.o
obj-$(CONFIG_ACENIC) += acenic.o
......
......@@ -25,6 +25,7 @@ obj-$(CONFIG_PCMCIA_SMC91C92) += crc32.o
obj-$(CONFIG_PCMCIA_XIRTULIP) += crc32.o
obj-$(CONFIG_PCNET32) += crc32.o
obj-$(CONFIG_SGI_IOC3_ETH) += crc32.o
obj-$(CONFIG_SIS190) += crc32.o
obj-$(CONFIG_SIS900) += crc32.o
obj-$(CONFIG_SMC9194) += crc32.o
obj-$(CONFIG_ADAPTEC_STARFIRE) += crc32.o
......
......@@ -97,7 +97,7 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de
dev->base_addr = ioaddr;
dev->irq = pdev->irq;
dev->dev_addr[0] = node;
lp->card_name = pdev->dev.name;
lp->card_name = "PCI COM20020";
lp->card_flags = id->driver_data;
lp->backplane = backplane;
lp->clockp = clockp & 7;
......@@ -105,7 +105,7 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de
lp->timeout = timeout;
lp->hw.owner = THIS_MODULE;
if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) {
if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) {
BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n",
ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
err = -EBUSY;
......@@ -122,6 +122,8 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de
goto out_priv;
}
release_region(ioaddr, ARCNET_TOTAL_SIZE);
if ((err = com20020_found(dev, SA_SHIRQ)) != 0)
goto out_priv;
......
......@@ -55,7 +55,7 @@ static void com20020_copy_to_card(struct net_device *dev, int bufnum,
static void com20020_copy_from_card(struct net_device *dev, int bufnum,
int offset, void *buf, int count);
static void com20020_set_mc_list(struct net_device *dev);
static void com20020_close(struct net_device *, bool);
static void com20020_close(struct net_device *);
static void com20020_copy_from_card(struct net_device *dev, int bufnum,
int offset, void *buf, int count)
......@@ -86,7 +86,7 @@ static void com20020_copy_to_card(struct net_device *dev, int bufnum,
/* Reset the card and check some basic stuff during the detection stage. */
int __devinit com20020_check(struct net_device *dev)
int com20020_check(struct net_device *dev)
{
int ioaddr = dev->base_addr, status;
struct arcnet_local *lp = dev->priv;
......@@ -152,7 +152,7 @@ int __devinit com20020_check(struct net_device *dev)
/* Set up the struct net_device associated with this card. Called after
* probing succeeds.
*/
int __devinit com20020_found(struct net_device *dev, int shared)
int com20020_found(struct net_device *dev, int shared)
{
struct arcnet_local *lp;
int ioaddr = dev->base_addr;
......@@ -180,6 +180,10 @@ int __devinit com20020_found(struct net_device *dev, int shared)
if (!dev->dev_addr[0])
dev->dev_addr[0] = inb(ioaddr + 8); /* FIXME: do this some other way! */
/* reserve the I/O region */
if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)"))
return -EBUSY;
SET_SUBADR(SUB_SETUP1);
outb(lp->setup, _XREG);
......@@ -203,13 +207,10 @@ int __devinit com20020_found(struct net_device *dev, int shared)
if (request_irq(dev->irq, &arcnet_interrupt, shared,
"arcnet (COM20020)", dev)) {
BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq);
release_region(ioaddr, ARCNET_TOTAL_SIZE);
return -ENODEV;
}
/* reserve the I/O region */
if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)")) {
free_irq(dev->irq, dev);
return -EBUSY;
}
dev->base_addr = ioaddr;
BUGMSG(D_NORMAL, "%s: station %02Xh found at %03lXh, IRQ %d.\n",
......@@ -226,8 +227,8 @@ int __devinit com20020_found(struct net_device *dev, int shared)
clockrates[3 - ((lp->setup2 & 0xF0) >> 4) + ((lp->setup & 0x0F) >> 1)]);
if (!dev->init && register_netdev(dev)) {
free_irq(dev->irq, dev);
release_region(ioaddr, ARCNET_TOTAL_SIZE);
free_irq(dev->irq, dev);
return -EIO;
}
return 0;
......@@ -298,16 +299,14 @@ static int com20020_status(struct net_device *dev)
return ASTATUS();
}
static void com20020_close(struct net_device *dev, bool open)
static void com20020_close(struct net_device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
int ioaddr = dev->base_addr;
if (!open) {
/* disable transmitter */
lp->config &= ~TXENcfg;
SETCONF;
}
}
/* Set or clear the multicast filter for this adaptor.
......@@ -339,7 +338,7 @@ static void com20020_set_mc_list(struct net_device *dev)
}
}
void __devexit com20020_remove(struct net_device *dev)
void com20020_remove(struct net_device *dev)
{
unregister_netdev(dev);
free_irq(dev->irq, dev);
......
......@@ -158,14 +158,14 @@ static int __init com90io_probe(struct net_device *dev)
"must specify the base address!\n");
return -ENODEV;
}
if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) {
if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com90io probe")) {
BUGMSG(D_INIT_REASONS, "IO check_region %x-%x failed.\n",
ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
return -ENXIO;
}
if (ASTATUS() == 0xFF) {
BUGMSG(D_INIT_REASONS, "IO address %x empty\n", ioaddr);
return -ENODEV;
goto err_out;
}
inb(_RESET);
mdelay(RESETtime);
......@@ -174,7 +174,7 @@ static int __init com90io_probe(struct net_device *dev)
if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
BUGMSG(D_INIT_REASONS, "Status invalid (%Xh).\n", status);
return -ENODEV;
goto err_out;
}
BUGMSG(D_INIT_REASONS, "Status after reset: %X\n", status);
......@@ -186,7 +186,7 @@ static int __init com90io_probe(struct net_device *dev)
if (status & RESETflag) {
BUGMSG(D_INIT_REASONS, "Eternal reset (status=%Xh)\n", status);
return -ENODEV;
goto err_out;
}
outb((0x16 | IOMAPflag) & ~ENABLE16flag, _CONFIG);
......@@ -198,7 +198,7 @@ static int __init com90io_probe(struct net_device *dev)
if ((status = inb(_MEMDATA)) != 0xd1) {
BUGMSG(D_INIT_REASONS, "Signature byte not found"
" (%Xh instead).\n", status);
return -ENODEV;
goto err_out;
}
if (!dev->irq) {
/*
......@@ -215,10 +215,15 @@ static int __init com90io_probe(struct net_device *dev)
if (dev->irq <= 0) {
BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed\n");
return -ENODEV;
goto err_out;
}
}
release_region(ioaddr, ARCNET_TOTAL_SIZE); /* end of probing */
return com90io_found(dev);
err_out:
release_region(ioaddr, ARCNET_TOTAL_SIZE);
return -ENODEV;
}
......
......@@ -33,20 +33,8 @@
#include "8390.h"
#define NE_BASE (dev->base_addr)
#define NE_CMD (0x00*2)
#define NE_EN0_ISR (0x07*2)
#define NE_EN0_DCFG (0x0e*2)
#define NE_EN0_RSARLO (0x08*2)
#define NE_EN0_RSARHI (0x09*2)
#define NE_EN0_RCNTLO (0x0a*2)
#define NE_EN0_RXCR (0x0c*2)
#define NE_EN0_TXCR (0x0d*2)
#define NE_EN0_RCNTHI (0x0b*2)
#define NE_EN0_IMR (0x0f*2)
#define NESM_START_PG 0x0 /* First page of TX buffer */
#define NESM_STOP_PG 0x40 /* Last page +1 of RX ring */
......@@ -56,12 +44,10 @@
#define WORDSWAP(a) ((((a)>>8)&0xff) | ((a)<<8))
#ifdef MODULE
static struct net_device *root_hydra_dev;
#endif
static int __init hydra_probe(void);
static int hydra_init(unsigned long board);
static int __init hydra_init(unsigned long board);
static int hydra_open(struct net_device *dev);
static int hydra_close(struct net_device *dev);
static void hydra_reset_8390(struct net_device *dev);
......@@ -96,11 +82,11 @@ static int __init hydra_probe(void)
return err;
}
int __init hydra_init(unsigned long board)
static int __init hydra_init(unsigned long board)
{
struct net_device *dev;
unsigned long ioaddr = board+HYDRA_NIC_BASE;
const char *name = NULL;
const char name[] = "NE2000";
int start_page, stop_page;
int j;
......@@ -136,8 +122,6 @@ int __init hydra_init(unsigned long board)
return -ENOMEM;
}
name = "NE2000";
printk("%s: hydra at 0x%08lx, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n", dev->name, ZTWO_PADDR(board),
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
......@@ -235,7 +219,6 @@ static void hydra_block_output(struct net_device *dev, int count,
static void __exit hydra_cleanup(void)
{
#ifdef MODULE
struct net_device *dev, *next;
while ((dev = root_hydra_dev)) {
......@@ -246,7 +229,6 @@ static void __exit hydra_cleanup(void)
kfree(dev);
root_hydra_dev = next;
}
#endif
}
module_init(hydra_probe);
......
/* SiS190.c: A Linux PCI Ethernet driver for the SiS190 chips. */
/*
=========================================================================
SiS190.c: A SiS190 Gigabit Ethernet driver for Linux kernel 2.6.x.
--------------------------------------------------------------------
drivers/net/SiS190.c
Maintained by K.M. Liu <kmliu@sis.com>
Modified from the driver which is originally written by Donald Becker.
This software may be used and distributed according to the terms of
the GNU General Public License (GPL), incorporated herein by reference.
Drivers based on or derived from this code fall under the GPL and must
retain the authorship, copyright and license notice. This file is not
a complete program and may only be used when the entire operating
system is licensed under the GPL.
History:
=========================================================================
VERSION 1.0 <2003/8/7> K.M. Liu, Test 100bps Full in 2.6.0 O.K.
1.1 <2003/8/8> K.M. Liu, Add mode detection.
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/crc32.h>
#include <linux/init.h>
#include <asm/io.h>
#define SiS190_VERSION "1.1"
#define MODULENAME "SiS190"
#define SiS190_DRIVER_NAME MODULENAME " Gigabit Ethernet driver " SiS190_VERSION
#define PFX MODULENAME ": "
#ifdef SiS190_DEBUG
#define assert(expr) \
if(unlikely(!(expr))) { \
printk( "Assertion failed! %s,%s,%s,line=%d\n", \
#expr,__FILE__,__FUNCTION__,__LINE__); \
}
#else
#define assert(expr) do {} while (0)
#endif
/* media options */
#define MAX_UNITS 8
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 20;
/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
The chips use a 64 element hash table based on the Ethernet CRC. */
static int multicast_filter_limit = 32;
/* MAC address length*/
#define MAC_ADDR_LEN 6
/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/
#define MAX_ETH_FRAME_SIZE 1536
#define TX_FIFO_THRESH 256 /* In bytes */
#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */
#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
#define RxPacketMaxSize 0x0800 /* Maximum size supported is 16K-1 */
#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
#define NUM_TX_DESC 64 /* Number of Tx descriptor registers */
#define NUM_RX_DESC 64 /* Number of Rx descriptor registers */
#define RX_BUF_SIZE 1536 /* Rx Buffer size */
#define SiS190_MIN_IO_SIZE 0x80
#define TX_TIMEOUT (6*HZ)
/* enhanced PHY access register bit definitions */
#define EhnMIIread 0x0000
#define EhnMIIwrite 0x0020
#define EhnMIIdataShift 16
#define EhnMIIpmdShift 6 /* 7016 only */
#define EhnMIIregShift 11
#define EhnMIIreq 0x0010
#define EhnMIInotDone 0x0010
//-------------------------------------------------------------------------
// Bit Mask definitions
//-------------------------------------------------------------------------
#define BIT_0 0x0001
#define BIT_1 0x0002
#define BIT_2 0x0004
#define BIT_3 0x0008
#define BIT_4 0x0010
#define BIT_5 0x0020
#define BIT_6 0x0040
#define BIT_7 0x0080
#define BIT_8 0x0100
#define BIT_9 0x0200
#define BIT_10 0x0400
#define BIT_11 0x0800
#define BIT_12 0x1000
#define BIT_13 0x2000
#define BIT_14 0x4000
#define BIT_15 0x8000
#define BIT_16 0x10000
#define BIT_17 0x20000
#define BIT_18 0x40000
#define BIT_19 0x80000
#define BIT_20 0x100000
#define BIT_21 0x200000
#define BIT_22 0x400000
#define BIT_23 0x800000
#define BIT_24 0x1000000
#define BIT_25 0x2000000
#define BIT_26 0x04000000
#define BIT_27 0x08000000
#define BIT_28 0x10000000
#define BIT_29 0x20000000
#define BIT_30 0x40000000
#define BIT_31 0x80000000
/* write/read MMIO register */
#define SiS_W8(reg, val8) writeb ((val8), ioaddr + (reg))
#define SiS_W16(reg, val16) writew ((val16), ioaddr + (reg))
#define SiS_W32(reg, val32) writel ((val32), ioaddr + (reg))
#define SiS_R8(reg) readb (ioaddr + (reg))
#define SiS_R16(reg) readw (ioaddr + (reg))
#define SiS_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
static struct {
const char *name;
} board_info[] __devinitdata = {
{ "SiS190 Gigabit Ethernet" },
};
static struct pci_device_id sis190_pci_tbl[] __devinitdata = {
{ 0x1039, 0x0190, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0,},
};
MODULE_DEVICE_TABLE(pci, sis190_pci_tbl);
enum SiS190_registers {
TxControl = 0x0,
TxDescStartAddr = 0x4,
TxNextDescAddr = 0x0c,
RxControl = 0x10,
RxDescStartAddr = 0x14,
RxNextDescAddr = 0x1c,
IntrStatus = 0x20,
IntrMask = 0x24,
IntrControl = 0x28,
IntrTimer = 0x2c,
PMControl = 0x30,
ROMControl = 0x38,
ROMInterface = 0x3c,
StationControl = 0x40,
GMIIControl = 0x44,
TxMacControl = 0x50,
RxMacControl = 0x60,
RxMacAddr = 0x62,
RxHashTable = 0x68,
RxWakeOnLan = 0x70,
RxMPSControl = 0x78,
};
enum sis190_register_content {
/*InterruptStatusBits */
SoftInt = 0x40000000,
Timeup = 0x20000000,
PauseFrame = 0x80000,
MagicPacket = 0x40000,
WakeupFrame = 0x20000,
LinkChange = 0x10000,
RxQEmpty = 0x80,
RxQInt = 0x40,
TxQ1Empty = 0x20,
TxQ1Int = 0x10,
TxQ0Empty = 0x08,
TxQ0Int = 0x04,
RxHalt = 0x02,
TxHalt = 0x01,
/*RxStatusDesc */
RxRES = 0x00200000,
RxCRC = 0x00080000,
RxRUNT = 0x00100000,
RxRWT = 0x00400000,
/*ChipCmdBits */
CmdReset = 0x10,
CmdRxEnb = 0x08,
CmdTxEnb = 0x01,
RxBufEmpty = 0x01,
/*Cfg9346Bits */
Cfg9346_Lock = 0x00,
Cfg9346_Unlock = 0xC0,
/*rx_mode_bits */
AcceptErr = 0x20,
AcceptRunt = 0x10,
AcceptBroadcast = 0x0800,
AcceptMulticast = 0x0400,
AcceptMyPhys = 0x0200,
AcceptAllPhys = 0x0100,
/*RxConfigBits */
RxCfgFIFOShift = 13,
RxCfgDMAShift = 8,
/*TxConfigBits */
TxInterFrameGapShift = 24,
TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
/*_PHYstatus */
TBI_Enable = 0x80,
TxFlowCtrl = 0x40,
RxFlowCtrl = 0x20,
_1000bpsF = 0x1c,
_1000bpsH = 0x0c,
_100bpsF = 0x18,
_100bpsH = 0x08,
_10bpsF = 0x14,
_10bpsH = 0x04,
LinkStatus = 0x02,
FullDup = 0x01,
/*GIGABIT_PHY_registers */
PHY_CTRL_REG = 0,
PHY_STAT_REG = 1,
PHY_AUTO_NEGO_REG = 4,
PHY_1000_CTRL_REG = 9,
/*GIGABIT_PHY_REG_BIT */
PHY_Restart_Auto_Nego = 0x0200,
PHY_Enable_Auto_Nego = 0x1000,
//PHY_STAT_REG = 1;
PHY_Auto_Neco_Comp = 0x0020,
//PHY_AUTO_NEGO_REG = 4;
PHY_Cap_10_Half = 0x0020,
PHY_Cap_10_Full = 0x0040,
PHY_Cap_100_Half = 0x0080,
PHY_Cap_100_Full = 0x0100,
//PHY_1000_CTRL_REG = 9;
PHY_Cap_1000_Full = 0x0200,
PHY_Cap_Null = 0x0,
/*_MediaType*/
_10_Half = 0x01,
_10_Full = 0x02,
_100_Half = 0x04,
_100_Full = 0x08,
_1000_Full = 0x10,
/*_TBICSRBit*/
TBILinkOK = 0x02000000,
};
const static struct {
const char *name;
u8 version; /* depend on docs */
u32 RxConfigMask; /* should clear the bits supported by this chip */
} sis_chip_info[] = {
{ "SiS-0190", 0x00, 0xff7e1880,},
};
enum _DescStatusBit {
OWNbit = 0x80000000,
INTbit = 0x40000000,
DEFbit = 0x200000,
CRCbit = 0x20000,
PADbit = 0x10000,
ENDbit = 0x80000000,
};
struct TxDesc {
u32 PSize;
u32 status;
u32 buf_addr;
u32 buf_Len;
};
struct RxDesc {
u32 PSize;
u32 status;
u32 buf_addr;
u32 buf_Len;
};
struct sis190_private {
void *mmio_addr; /* memory map physical address */
struct pci_dev *pci_dev; /* Index of PCI device */
struct net_device_stats stats; /* statistics of net device */
spinlock_t lock; /* spin lock flag */
int chipset;
unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
unsigned long dirty_tx;
void *tx_desc_raw; /* Tx descriptor buffer */
dma_addr_t tx_dma_raw;
dma_addr_t tx_dma_aligned;
void *rx_desc_raw; /* Rx descriptor buffer */
dma_addr_t rx_dma_raw;
dma_addr_t rx_dma_aligned;
struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */
struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */
unsigned char *RxBufferRings; /* Index of Rx Buffer */
unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */
struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Index of Transmit data buffer */
};
MODULE_AUTHOR("K.M. Liu <kmliu@sis.com>");
MODULE_DESCRIPTION("SiS SiS190 Gigabit Ethernet driver");
MODULE_LICENSE("GPL");
MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i");
static int SiS190_open(struct net_device *dev);
static int SiS190_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t SiS190_interrupt(int irq, void *dev_instance,
struct pt_regs *regs);
static void SiS190_init_ring(struct net_device *dev);
static void SiS190_hw_start(struct net_device *dev);
static int SiS190_close(struct net_device *dev);
static void SiS190_set_rx_mode(struct net_device *dev);
static void SiS190_tx_timeout(struct net_device *dev);
static struct net_device_stats *SiS190_get_stats(struct net_device *netdev);
static const u32 sis190_intr_mask =
RxQEmpty | RxQInt | TxQ1Empty | TxQ1Int | TxQ0Empty | TxQ0Int | RxHalt |
TxHalt;
void
smdio_write(void *ioaddr, int RegAddr, int value)
{
u32 l;
u16 i;
u32 pmd;
pmd = 1;
l = 0;
l = EhnMIIwrite | (((u32) RegAddr) << EhnMIIregShift) | EhnMIIreq |
(((u32) value) << EhnMIIdataShift) | (((u32) pmd) <<
EhnMIIpmdShift);
SiS_W32(GMIIControl, l);
udelay(1000);
for (i = 0; i < 1000; i++) {
if (SiS_R32(GMIIControl) & EhnMIInotDone) {
udelay(100);
} else {
break;
}
}
if (i > 999)
printk(KERN_ERR PFX "Phy write Error!!!\n");
}
int
smdio_read(void *ioaddr, int RegAddr)
{
u32 l;
u16 i;
u32 pmd;
pmd = 1;
l = 0;
l = EhnMIIread | EhnMIIreq | (((u32) RegAddr) << EhnMIIregShift) |
(((u32) pmd) << EhnMIIpmdShift);
SiS_W32(GMIIControl, l);
udelay(1000);
for (i = 0; i < 1000; i++) {
if ((l == SiS_R32(GMIIControl)) & EhnMIInotDone) {
udelay(100);
} else {
break;
}
if (i > 999)
printk(KERN_ERR PFX "Phy Read Error!!!\n");
}
l = SiS_R32(GMIIControl);
return ((u16) (l >> EhnMIIdataShift));
}
int
ReadEEprom(void *ioaddr, u32 RegAddr)
{
u16 data;
u32 i;
u32 ulValue;
if (!(SiS_R32(ROMControl) & BIT_1)) {
return 0;
}
ulValue = (BIT_7 | (0x2 << 8) | (RegAddr << 10));
SiS_W32(ROMInterface, ulValue);
for (i = 0; i < 200; i++) {
if (!(SiS_R32(ROMInterface) & BIT_7))
break;
udelay(1000);
}
data = (u16) ((SiS_R32(ROMInterface) & 0xffff0000) >> 16);
return data;
}
static int __devinit
SiS190_init_board(struct pci_dev *pdev, struct net_device **dev_out,
void **ioaddr_out)
{
void *ioaddr = NULL;
struct net_device *dev;
struct sis190_private *tp;
u16 rc;
unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
assert(pdev != NULL);
assert(ioaddr_out != NULL);
*ioaddr_out = NULL;
*dev_out = NULL;
// dev zeroed in init_etherdev
dev = alloc_etherdev(sizeof (*tp));
if (dev == NULL) {
printk(KERN_ERR PFX "unable to alloc new ethernet\n");
return -ENOMEM;
}
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
tp = dev->priv;
// enable device (incl. PCI PM wakeup and hotplug setup)
rc = pci_enable_device(pdev);
if (rc)
goto err_out;
mmio_start = pci_resource_start(pdev, 0);
mmio_end = pci_resource_end(pdev, 0);
mmio_flags = pci_resource_flags(pdev, 0);
mmio_len = pci_resource_len(pdev, 0);
// make sure PCI base addr 0 is MMIO
if (!(mmio_flags & IORESOURCE_MEM)) {
printk(KERN_ERR PFX
"region #0 not an MMIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
// check for weird/broken PCI region reporting
if (mmio_len < SiS190_MIN_IO_SIZE) {
printk(KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
rc = -ENODEV;
goto err_out;
}
rc = pci_request_regions(pdev, dev->name);
if (rc)
goto err_out;
// enable PCI bus-mastering
pci_set_master(pdev);
// ioremap MMIO region
ioaddr = ioremap(mmio_start, mmio_len);
if (ioaddr == NULL) {
printk(KERN_ERR PFX "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out_free_res;
}
// Soft reset the chip.
SiS_W32(IntrControl, 0x8000);
udelay(1000);
SiS_W32(IntrControl, 0x0);
SiS_W32(TxControl, 0x1a00);
SiS_W32(RxControl, 0x1a00);
udelay(1000);
*ioaddr_out = ioaddr;
*dev_out = dev;
return 0;
err_out_free_res:
pci_release_regions(pdev);
err_out:
pci_disable_device(pdev);
unregister_netdev(dev);
kfree(dev);
return rc;
}
static int __devinit
SiS190_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct net_device *dev = NULL;
struct sis190_private *tp = NULL;
void *ioaddr = NULL;
static int board_idx = -1;
static int printed_version = 0;
int i, rc;
u16 reg31;
assert(pdev != NULL);
assert(ent != NULL);
board_idx++;
if (!printed_version) {
printk(KERN_INFO SiS190_DRIVER_NAME " loaded\n");
printed_version = 1;
}
i = SiS190_init_board(pdev, &dev, &ioaddr);
if (i < 0) {
return i;
}
tp = dev->priv;
assert(ioaddr != NULL);
assert(dev != NULL);
assert(tp != NULL);
// Get MAC address //
// Read node address from the EEPROM
if (SiS_R32(ROMControl) & 0x2) {
for (i = 0; i < 6; i += 2) {
SiS_W16(RxMacAddr + i, ReadEEprom(ioaddr, 3 + (i / 2)));
}
} else {
SiS_W32(RxMacAddr, 0x11111100); //If 9346 does not exist
SiS_W32(RxMacAddr + 2, 0x00111111);
}
for (i = 0; i < MAC_ADDR_LEN; i++) {
dev->dev_addr[i] = SiS_R8(RxMacAddr + i);
printk("SiS_R8(RxMacAddr+%x)= %x ", i, SiS_R8(RxMacAddr + i));
}
dev->open = SiS190_open;
dev->hard_start_xmit = SiS190_start_xmit;
dev->get_stats = SiS190_get_stats;
dev->stop = SiS190_close;
dev->tx_timeout = SiS190_tx_timeout;
dev->set_multicast_list = SiS190_set_rx_mode;
dev->watchdog_timeo = TX_TIMEOUT;
dev->irq = pdev->irq;
dev->base_addr = (unsigned long) ioaddr;
// dev->do_ioctl = mii_ioctl;
tp = dev->priv; // private data //
tp->pci_dev = pdev;
tp->mmio_addr = ioaddr;
printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n", dev->name,
sis_chip_info[tp->chipset].name);
spin_lock_init(&tp->lock);
rc = register_netdev(dev);
if (rc) {
iounmap(ioaddr);
pci_release_regions(pdev);
pci_disable_device(pdev);
kfree(dev);
return rc;
}
printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n", dev->name,
sis_chip_info[tp->chipset].name);
pci_set_drvdata(pdev, dev);
printk(KERN_INFO "%s: %s at 0x%lx, "
"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
"IRQ %d\n",
dev->name,
board_info[ent->driver_data].name,
dev->base_addr,
dev->dev_addr[0], dev->dev_addr[1],
dev->dev_addr[2], dev->dev_addr[3],
dev->dev_addr[4], dev->dev_addr[5], dev->irq);
int val = smdio_read(ioaddr, PHY_AUTO_NEGO_REG);
printk(KERN_INFO "%s: Auto-negotiation Enabled.\n", dev->name);
// enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
smdio_write(ioaddr, PHY_AUTO_NEGO_REG,
PHY_Cap_10_Half | PHY_Cap_10_Full |
PHY_Cap_100_Half | PHY_Cap_100_Full | (val & 0x1F));
// enable 1000 Full Mode
smdio_write(ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full);
// Enable auto-negotiation and restart auto-nigotiation
smdio_write(ioaddr, PHY_CTRL_REG,
PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego);
udelay(100);
// wait for auto-negotiation process
for (i = 10000; i > 0; i--) {
//check if auto-negotiation complete
if (smdio_read(ioaddr, PHY_STAT_REG) & PHY_Auto_Neco_Comp) {
udelay(100);
reg31 = smdio_read(ioaddr, 31);
reg31 &= 0x1c; //bit 4:2
switch (reg31) {
case _1000bpsF:
SiS_W16(0x40, 0x1c01);
printk
("SiS190 Link on 1000 bps Full Duplex mode. \n");
break;
case _1000bpsH:
SiS_W16(0x40, 0x0c01);
printk
("SiS190 Link on 1000 bps Half Duplex mode. \n");
break;
case _100bpsF:
SiS_W16(0x40, 0x1801);
printk
("SiS190 Link on 100 bps Full Duplex mode. \n");
break;
case _100bpsH:
SiS_W16(0x40, 0x0801);
printk
("SiS190 Link on 100 bps Half Duplex mode. \n");
break;
case _10bpsF:
SiS_W16(0x40, 0x1401);
printk
("SiS190 Link on 10 bps Full Duplex mode. \n");
break;
case _10bpsH:
SiS_W16(0x40, 0x0401);
printk
("SiS190 Link on 10 bps Half Duplex mode. \n");
break;
default:
printk(KERN_ERR PFX
"Error! SiS190 Can not detect mode !!! \n");
break;
}
break;
} else {
udelay(100);
}
} // end for-loop to wait for auto-negotiation process
return 0;
}
static void __devexit
SiS190_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct sis190_private *tp = (struct sis190_private *) (dev->priv);
assert(dev != NULL);
assert(tp != NULL);
unregister_netdev(dev);
iounmap(tp->mmio_addr);
pci_release_regions(pdev);
// poison memory before freeing
memset(dev, 0xBC,
sizeof (struct net_device) + sizeof (struct sis190_private));
kfree(dev);
pci_set_drvdata(pdev, NULL);
}
static int
SiS190_open(struct net_device *dev)
{
struct sis190_private *tp = dev->priv;
int retval;
u8 diff;
int rc;
retval =
request_irq(dev->irq, SiS190_interrupt, SA_SHIRQ, dev->name, dev);
if (retval) {
return retval;
}
tp->tx_desc_raw = pci_alloc_consistent(tp->pci_dev,
(NUM_TX_DESC * sizeof (struct TxDesc)) + 256,
&tp->tx_dma_raw);
if (!tp->tx_desc_raw) {
rc = -ENOMEM;
goto err_out;
}
// Tx Desscriptor needs 256 bytes alignment;
diff = 256 - (tp->tx_dma_raw - ((tp->tx_dma_raw >> 8) << 8));
tp->tx_dma_aligned = tp->tx_dma_raw + diff;
tp->TxDescArray = (struct TxDesc *) (tp->tx_desc_raw + diff);
tp->rx_desc_raw = pci_alloc_consistent(tp->pci_dev,
(NUM_RX_DESC * sizeof (struct RxDesc)) + 256,
&tp->rx_dma_raw);
if (!tp->rx_desc_raw) {
rc = -ENOMEM;
goto err_out_free_tx;
}
// Rx Desscriptor needs 256 bytes alignment;
diff = 256 - (tp->rx_dma_raw - ((tp->rx_dma_raw >> 8) << 8));
tp->rx_dma_aligned = tp->rx_dma_raw + diff;
tp->RxDescArray = (struct RxDesc *) (tp->rx_desc_raw + diff);
tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL);
if (tp->RxBufferRings == NULL) {
printk(KERN_INFO "Allocate RxBufferRing failed\n");
}
SiS190_init_ring(dev);
SiS190_hw_start(dev);
return 0;
err_out_free_tx:
pci_free_consistent(tp->pci_dev,
(NUM_TX_DESC * sizeof (struct TxDesc)) + 256,
tp->tx_desc_raw, tp->tx_dma_raw);
err_out:
free_irq(dev->irq, dev);
return rc;
}
static void
SiS190_hw_start(struct net_device *dev)
{
struct sis190_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
/* Soft reset the chip. */
SiS_W32(IntrControl, 0x8000);
udelay(1000);
SiS_W32(IntrControl, 0x0);
SiS_W32(0x0, 0x01a00);
SiS_W32(0x4, tp->tx_dma_aligned);
SiS_W32(0x10, 0x1a00);
SiS_W32(0x14, tp->rx_dma_aligned);
SiS_W32(0x20, 0xffffffff);
SiS_W32(0x24, 0x0);
SiS_W16(0x40, 0x1901); //default is 100Mbps
SiS_W32(0x44, 0x0);
SiS_W32(0x50, 0x60);
SiS_W16(0x60, 0x02);
SiS_W32(0x68, 0x0);
SiS_W32(0x6c, 0x0);
SiS_W32(0x70, 0x0);
SiS_W32(0x74, 0x0);
// Set Rx Config register
tp->cur_rx = 0;
udelay(10);
SiS190_set_rx_mode(dev);
/* Enable all known interrupts by setting the interrupt mask. */
SiS_W32(IntrMask, sis190_intr_mask);
SiS_W32(0x0, 0x1a01);
SiS_W32(0x10, 0x1a1d);
netif_start_queue(dev);
}
static void
SiS190_init_ring(struct net_device *dev)
{
struct sis190_private *tp = dev->priv;
int i;
tp->cur_rx = 0;
tp->cur_tx = 0;
tp->dirty_tx = 0;
memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof (struct TxDesc));
memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof (struct RxDesc));
for (i = 0; i < NUM_TX_DESC; i++) {
tp->Tx_skbuff[i] = NULL;
}
for (i = 0; i < NUM_RX_DESC; i++) {
tp->RxDescArray[i].PSize = 0x0;
if (i == (NUM_RX_DESC - 1))
tp->RxDescArray[i].buf_Len = BIT_31 + RX_BUF_SIZE; //bit 31 is End bit
else
tp->RxDescArray[i].buf_Len = RX_BUF_SIZE;
#warning Replace virt_to_bus with DMA mapping
tp->RxBufferRing[i] = &(tp->RxBufferRings[i * RX_BUF_SIZE]);
tp->RxDescArray[i].buf_addr = virt_to_bus(tp->RxBufferRing[i]);
tp->RxDescArray[i].status = OWNbit | INTbit;
}
}
static void
SiS190_tx_clear(struct sis190_private *tp)
{
int i;
tp->cur_tx = 0;
for (i = 0; i < NUM_TX_DESC; i++) {
if (tp->Tx_skbuff[i] != NULL) {
dev_kfree_skb(tp->Tx_skbuff[i]);
tp->Tx_skbuff[i] = NULL;
tp->stats.tx_dropped++;
}
}
}
static void
SiS190_tx_timeout(struct net_device *dev)
{
struct sis190_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
u8 tmp8;
/* disable Tx, if not already */
tmp8 = SiS_R8(TxControl);
if (tmp8 & CmdTxEnb)
SiS_W8(TxControl, tmp8 & ~CmdTxEnb);
/* Disable interrupts by clearing the interrupt mask. */
SiS_W32(IntrMask, 0x0000);
/* Stop a shared interrupt from scavenging while we are. */
spin_lock_irq(&tp->lock);
SiS190_tx_clear(tp);
spin_unlock_irq(&tp->lock);
/* ...and finally, reset everything */
SiS190_hw_start(dev);
netif_wake_queue(dev);
}
static int
SiS190_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct sis190_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
int entry = tp->cur_tx % NUM_TX_DESC;
if (skb->len < ETH_ZLEN) {
skb = skb_padto(skb, ETH_ZLEN);
if (skb == NULL)
return 0;
}
spin_lock_irq(&tp->lock);
if ((tp->TxDescArray[entry].status & OWNbit) == 0) {
#warning Replace virt_to_bus with DMA mapping
tp->Tx_skbuff[entry] = skb;
tp->TxDescArray[entry].buf_addr = virt_to_bus(skb->data);
tp->TxDescArray[entry].PSize =
((skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN);
if (entry != (NUM_TX_DESC - 1)) {
tp->TxDescArray[entry].buf_Len =
tp->TxDescArray[entry].PSize;
} else {
tp->TxDescArray[entry].buf_Len =
tp->TxDescArray[entry].PSize | ENDbit;
}
tp->TxDescArray[entry].status |=
(OWNbit | INTbit | DEFbit | CRCbit | PADbit);
SiS_W32(TxControl, 0x1a11); //Start Send
dev->trans_start = jiffies;
tp->cur_tx++;
}
spin_unlock_irq(&tp->lock);
if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) {
netif_stop_queue(dev);
}
return 0;
}
static void
SiS190_tx_interrupt(struct net_device *dev, struct sis190_private *tp,
void *ioaddr)
{
unsigned long dirty_tx, tx_left = 0;
int entry = tp->cur_tx % NUM_TX_DESC;
assert(dev != NULL);
assert(tp != NULL);
assert(ioaddr != NULL);
dirty_tx = tp->dirty_tx;
tx_left = tp->cur_tx - dirty_tx;
while (tx_left > 0) {
if ((tp->TxDescArray[entry].status & OWNbit) == 0) {
dev_kfree_skb_irq(tp->
Tx_skbuff[dirty_tx % NUM_TX_DESC]);
tp->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL;
tp->stats.tx_packets++;
dirty_tx++;
tx_left--;
entry++;
}
}
if (tp->dirty_tx != dirty_tx) {
tp->dirty_tx = dirty_tx;
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
}
}
static void
SiS190_rx_interrupt(struct net_device *dev, struct sis190_private *tp,
void *ioaddr)
{
int cur_rx;
struct sk_buff *skb;
int pkt_size = 0;
assert(dev != NULL);
assert(tp != NULL);
assert(ioaddr != NULL);
cur_rx = tp->cur_rx;
while ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) {
if (tp->RxDescArray[cur_rx].PSize & 0x0080000) {
printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
tp->stats.rx_errors++;
tp->stats.rx_length_errors++;
} else if (!(tp->RxDescArray[cur_rx].PSize & 0x0010000)) {
printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
tp->stats.rx_errors++;
tp->stats.rx_crc_errors++;
} else {
pkt_size =
(int) (tp->RxDescArray[cur_rx].
PSize & 0x0000FFFF) - 4;
skb = dev_alloc_skb(pkt_size + 2);
if (skb != NULL) {
skb->dev = dev;
skb_reserve(skb, 2); // 16 byte align the IP fields. //
eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx],
pkt_size, 0);
skb_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
tp->RxDescArray[cur_rx].PSize = 0x0;
if (cur_rx == (NUM_RX_DESC - 1))
tp->RxDescArray[cur_rx].buf_Len =
ENDbit + RX_BUF_SIZE;
else
tp->RxDescArray[cur_rx].buf_Len =
RX_BUF_SIZE;
#warning Replace virt_to_bus with DMA mapping
tp->RxDescArray[cur_rx].buf_addr =
virt_to_bus(tp->RxBufferRing[cur_rx]);
dev->last_rx = jiffies;
tp->stats.rx_bytes += pkt_size;
tp->stats.rx_packets++;
tp->RxDescArray[cur_rx].status =
OWNbit | INTbit;
} else {
printk(KERN_WARNING
"%s: Memory squeeze, deferring packet.\n",
dev->name);
/* We should check that some rx space is free.
If not, free one and mark stats->rx_dropped++. */
tp->stats.rx_dropped++;
}
}
cur_rx = (cur_rx + 1) % NUM_RX_DESC;
}
tp->cur_rx = cur_rx;
}
/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
static irqreturn_t
SiS190_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct sis190_private *tp = dev->priv;
int boguscnt = max_interrupt_work;
void *ioaddr = tp->mmio_addr;
unsigned long status = 0;
int handled = 0;
do {
status = SiS_R32(IntrStatus);
/* h/w no longer present (hotplug?) or major error, bail */
SiS_W32(IntrStatus, status);
if ((status & (TxQ0Int | RxQInt)) == 0)
break;
// Rx interrupt
if (status & (RxQInt)) {
SiS190_rx_interrupt(dev, tp, ioaddr);
}
// Tx interrupt
if (status & (TxQ0Int)) {
spin_lock(&tp->lock);
SiS190_tx_interrupt(dev, tp, ioaddr);
spin_unlock(&tp->lock);
}
boguscnt--;
} while (boguscnt > 0);
if (boguscnt <= 0) {
printk(KERN_WARNING "%s: Too much work at interrupt!\n",
dev->name);
/* Clear all interrupt sources. */
SiS_W32(IntrStatus, 0xffffffff);
}
return IRQ_RETVAL(handled);
}
static int
SiS190_close(struct net_device *dev)
{
struct sis190_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
int i;
netif_stop_queue(dev);
spin_lock_irq(&tp->lock);
/* Stop the chip's Tx and Rx DMA processes. */
SiS_W32(TxControl, 0x1a00);
SiS_W32(RxControl, 0x1a00);
/* Disable interrupts by clearing the interrupt mask. */
SiS_W32(IntrMask, 0x0000);
/* Update the error counts. */
//tp->stats.rx_missed_errors += _R32(RxMissed);
spin_unlock_irq(&tp->lock);
synchronize_irq();
free_irq(dev->irq, dev);
SiS190_tx_clear(tp);
pci_free_consistent(tp->pci_dev,
(NUM_TX_DESC * sizeof (struct TxDesc)) + 256,
tp->tx_desc_raw, tp->tx_dma_raw);
pci_free_consistent(tp->pci_dev,
(NUM_RX_DESC * sizeof (struct RxDesc)) + 256,
tp->rx_desc_raw, tp->rx_dma_raw);
tp->TxDescArray = NULL;
tp->RxDescArray = NULL;
kfree(tp->RxBufferRings);
for (i = 0; i < NUM_RX_DESC; i++) {
tp->RxBufferRing[i] = NULL;
}
return 0;
}
static void
SiS190_set_rx_mode(struct net_device *dev)
{
struct sis190_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
unsigned long flags;
u32 mc_filter[2]; /* Multicast hash filter */
int i, rx_mode;
u32 tmp = 0;
if (dev->flags & IFF_PROMISC) {
/* Unconditionally log net taps. */
printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
dev->name);
rx_mode =
AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
} else if ((dev->mc_count > multicast_filter_limit)
|| (dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
} else {
struct dev_mc_list *mclist;
rx_mode = AcceptBroadcast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0;
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
int bit_nr =
ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
rx_mode |= AcceptMulticast;
}
}
spin_lock_irqsave(&tp->lock, flags);
tmp = rx_mode | 0x2;
SiS_W16(RxMacControl, tmp);
SiS_W32(RxHashTable, mc_filter[0]);
SiS_W32(RxHashTable + 4, mc_filter[1]);
spin_unlock_irqrestore(&tp->lock, flags);
}
struct net_device_stats *
SiS190_get_stats(struct net_device *dev)
{
struct sis190_private *tp = dev->priv;
return &tp->stats;
}
static struct pci_driver sis190_pci_driver = {
.name = MODULENAME,
.id_table = sis190_pci_tbl,
.probe = SiS190_init_one,
.remove = SiS190_remove_one,
};
static int __init
SiS190_init_module(void)
{
return pci_module_init(&sis190_pci_driver);
}
static void __exit
SiS190_cleanup_module(void)
{
pci_unregister_driver(&sis190_pci_driver);
}
module_init(SiS190_init_module);
module_exit(SiS190_cleanup_module);
......@@ -5051,16 +5051,20 @@ static void tg3_set_rx_mode(struct net_device *dev)
#define TG3_REGDUMP_LEN (32 * 1024)
static u8 *tg3_get_regs(struct tg3 *tp)
static int tg3_get_regs_len(struct net_device *dev)
{
u8 *orig_p = kmalloc(TG3_REGDUMP_LEN, GFP_KERNEL);
u8 *p;
return TG3_REGDUMP_LEN;
}
static void tg3_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
{
struct tg3 *tp = dev->priv;
u8 *orig_p = p;
int i;
if (orig_p == NULL)
return NULL;
regs->version = 0;
memset(orig_p, 0, TG3_REGDUMP_LEN);
memset(p, 0, TG3_REGDUMP_LEN);
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
......@@ -5114,113 +5118,58 @@ do { p = orig_p + (reg); \
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);
return orig_p;
}
static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct tg3 *tp = dev->priv;
struct pci_dev *pci_dev = tp->pdev;
u32 ethcmd;
if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
return -EFAULT;
switch (ethcmd) {
case ETHTOOL_GDRVINFO:{
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strcpy (info.driver, DRV_MODULE_NAME);
strcpy (info.version, DRV_MODULE_VERSION);
memset(&info.fw_version, 0, sizeof(info.fw_version));
strcpy (info.bus_info, pci_name(pci_dev));
info.eedump_len = 0;
info.regdump_len = TG3_REGDUMP_LEN;
if (copy_to_user (useraddr, &info, sizeof (info)))
return -EFAULT;
return 0;
}
case ETHTOOL_GSET: {
struct ethtool_cmd cmd = { ETHTOOL_GSET };
if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
tp->link_config.phy_is_low_power)
return -EAGAIN;
cmd.supported = (SUPPORTED_Autoneg);
cmd->supported = (SUPPORTED_Autoneg);
if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
cmd.supported |= (SUPPORTED_1000baseT_Half |
cmd->supported |= (SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full);
if (tp->phy_id != PHY_ID_SERDES)
cmd.supported |= (SUPPORTED_100baseT_Half |
cmd->supported |= (SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_MII);
else
cmd.supported |= SUPPORTED_FIBRE;
cmd.advertising = tp->link_config.advertising;
cmd.speed = tp->link_config.active_speed;
cmd.duplex = tp->link_config.active_duplex;
cmd.port = 0;
cmd.phy_address = PHY_ADDR;
cmd.transceiver = 0;
cmd.autoneg = tp->link_config.autoneg;
cmd.maxtxpkt = 0;
cmd.maxrxpkt = 0;
if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
return -EFAULT;
cmd->supported |= SUPPORTED_FIBRE;
cmd->advertising = tp->link_config.advertising;
cmd->speed = tp->link_config.active_speed;
cmd->duplex = tp->link_config.active_duplex;
cmd->port = 0;
cmd->phy_address = PHY_ADDR;
cmd->transceiver = 0;
cmd->autoneg = tp->link_config.autoneg;
cmd->maxtxpkt = 0;
cmd->maxrxpkt = 0;
return 0;
}
case ETHTOOL_SSET: {
struct ethtool_cmd cmd;
}
static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct tg3 *tp = dev->priv;
if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
tp->link_config.phy_is_low_power)
return -EAGAIN;
if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
return -EFAULT;
/* Fiber PHY only supports 1000 full/half */
if (cmd.autoneg == AUTONEG_ENABLE) {
if (tp->phy_id == PHY_ID_SERDES &&
(cmd.advertising &
(ADVERTISED_10baseT_Half |
ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full)))
return -EINVAL;
if ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
(cmd.advertising &
(ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full)))
return -EINVAL;
} else {
if (tp->phy_id == PHY_ID_SERDES &&
(cmd.speed == SPEED_10 ||
cmd.speed == SPEED_100))
return -EINVAL;
if ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
(cmd.speed == SPEED_10 ||
cmd.speed == SPEED_100))
return -EINVAL;
}
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
tp->link_config.autoneg = cmd.autoneg;
if (cmd.autoneg == AUTONEG_ENABLE) {
tp->link_config.advertising = cmd.advertising;
if (cmd->autoneg == AUTONEG_ENABLE) {
tp->link_config.advertising = cmd->advertising;
tp->link_config.speed = SPEED_INVALID;
tp->link_config.duplex = DUPLEX_INVALID;
} else {
tp->link_config.speed = cmd.speed;
tp->link_config.duplex = cmd.duplex;
tp->link_config.speed = cmd->speed;
tp->link_config.duplex = cmd->duplex;
}
tg3_setup_phy(tp);
......@@ -5228,80 +5177,64 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
spin_unlock_irq(&tp->lock);
return 0;
}
case ETHTOOL_GREGS: {
struct ethtool_regs regs;
u8 *regbuf;
int ret;
}
if (copy_from_user(&regs, useraddr, sizeof(regs)))
return -EFAULT;
if (regs.len > TG3_REGDUMP_LEN)
regs.len = TG3_REGDUMP_LEN;
regs.version = 0;
if (copy_to_user(useraddr, &regs, sizeof(regs)))
return -EFAULT;
static void tg3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct tg3 *tp = dev->priv;
regbuf = tg3_get_regs(tp);
if (!regbuf)
return -ENOMEM;
strcpy(info->driver, DRV_MODULE_NAME);
strcpy(info->version, DRV_MODULE_VERSION);
strcpy(info->bus_info, pci_name(tp->pdev));
}
useraddr += offsetof(struct ethtool_regs, data);
ret = 0;
if (copy_to_user(useraddr, regbuf, regs.len))
ret = -EFAULT;
kfree(regbuf);
return ret;
}
case ETHTOOL_GWOL: {
struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct tg3 *tp = dev->priv;
wol.supported = WAKE_MAGIC;
wol.wolopts = 0;
wol->supported = WAKE_MAGIC;
wol->wolopts = 0;
if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
wol.wolopts = WAKE_MAGIC;
memset(&wol.sopass, 0, sizeof(wol.sopass));
if (copy_to_user(useraddr, &wol, sizeof(wol)))
return -EFAULT;
return 0;
}
case ETHTOOL_SWOL: {
struct ethtool_wolinfo wol;
wol->wolopts = WAKE_MAGIC;
memset(&wol->sopass, 0, sizeof(wol->sopass));
}
if (copy_from_user(&wol, useraddr, sizeof(wol)))
return -EFAULT;
if (wol.wolopts & ~WAKE_MAGIC)
static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct tg3 *tp = dev->priv;
if (wol->wolopts & ~WAKE_MAGIC)
return -EINVAL;
if ((wol.wolopts & WAKE_MAGIC) &&
if ((wol->wolopts & WAKE_MAGIC) &&
tp->phy_id == PHY_ID_SERDES &&
!(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
return -EINVAL;
spin_lock_irq(&tp->lock);
if (wol.wolopts & WAKE_MAGIC)
if (wol->wolopts & WAKE_MAGIC)
tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
else
tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
spin_unlock_irq(&tp->lock);
return 0;
}
case ETHTOOL_GMSGLVL: {
struct ethtool_value edata = { ETHTOOL_GMSGLVL };
edata.data = tp->msg_enable;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
case ETHTOOL_SMSGLVL: {
struct ethtool_value edata;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
tp->msg_enable = edata.data;
return 0;
}
case ETHTOOL_NWAY_RST: {
}
static u32 tg3_get_msglevel(struct net_device *dev)
{
struct tg3 *tp = dev->priv;
return tp->msg_enable;
}
static void tg3_set_msglevel(struct net_device *dev, u32 value)
{
struct tg3 *tp = dev->priv;
tp->msg_enable = value;
}
static int tg3_nway_reset(struct net_device *dev)
{
struct tg3 *tp = dev->priv;
u32 bmcr;
int r;
......@@ -5310,57 +5243,47 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
tg3_readphy(tp, MII_BMCR, &bmcr);
r = -EINVAL;
if (bmcr & BMCR_ANENABLE) {
tg3_writephy(tp, MII_BMCR,
bmcr | BMCR_ANRESTART);
tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART);
r = 0;
}
spin_unlock_irq(&tp->lock);
return r;
}
case ETHTOOL_GLINK: {
struct ethtool_value edata = { ETHTOOL_GLINK };
edata.data = netif_carrier_ok(tp->dev) ? 1 : 0;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
case ETHTOOL_GRINGPARAM: {
struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
}
ering.rx_max_pending = TG3_RX_RING_SIZE - 1;
ering.rx_mini_max_pending = 0;
ering.rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1;
static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
{
struct tg3 *tp = dev->priv;
ering.rx_pending = tp->rx_pending;
ering.rx_mini_pending = 0;
ering.rx_jumbo_pending = tp->rx_jumbo_pending;
ering.tx_pending = tp->tx_pending;
ering->rx_max_pending = TG3_RX_RING_SIZE - 1;
ering->rx_mini_max_pending = 0;
ering->rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1;
if (copy_to_user(useraddr, &ering, sizeof(ering)))
return -EFAULT;
return 0;
}
case ETHTOOL_SRINGPARAM: {
struct ethtool_ringparam ering;
ering->rx_pending = tp->rx_pending;
ering->rx_mini_pending = 0;
ering->rx_jumbo_pending = tp->rx_jumbo_pending;
ering->tx_pending = tp->tx_pending;
}
if (copy_from_user(&ering, useraddr, sizeof(ering)))
return -EFAULT;
static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
{
struct tg3 *tp = dev->priv;
if ((ering.rx_pending > TG3_RX_RING_SIZE - 1) ||
(ering.rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
(ering.tx_pending > TG3_TX_RING_SIZE - 1))
if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) ||
(ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
(ering->tx_pending > TG3_TX_RING_SIZE - 1))
return -EINVAL;
tg3_netif_stop(tp);
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
tp->rx_pending = ering.rx_pending;
tp->rx_jumbo_pending = ering.rx_jumbo_pending;
tp->tx_pending = ering.tx_pending;
tp->rx_pending = ering->rx_pending;
tp->rx_jumbo_pending = ering->rx_jumbo_pending;
tp->tx_pending = ering->tx_pending;
tg3_halt(tp);
tg3_init_rings(tp);
tg3_init_hw(tp);
netif_wake_queue(tp->dev);
spin_unlock(&tp->tx_lock);
......@@ -5368,132 +5291,88 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
tg3_netif_start(tp);
return 0;
}
case ETHTOOL_GPAUSEPARAM: {
struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM };
epause.autoneg =
(tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
epause.rx_pause =
(tp->tg3_flags & TG3_FLAG_PAUSE_RX) != 0;
epause.tx_pause =
(tp->tg3_flags & TG3_FLAG_PAUSE_TX) != 0;
if (copy_to_user(useraddr, &epause, sizeof(epause)))
return -EFAULT;
return 0;
}
case ETHTOOL_SPAUSEPARAM: {
struct ethtool_pauseparam epause;
}
static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
{
struct tg3 *tp = dev->priv;
if (copy_from_user(&epause, useraddr, sizeof(epause)))
return -EFAULT;
epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
epause->rx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_RX) != 0;
epause->tx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_TX) != 0;
}
static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
{
struct tg3 *tp = dev->priv;
tg3_netif_stop(tp);
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
if (epause.autoneg)
if (epause->autoneg)
tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
else
tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
if (epause.rx_pause)
if (epause->rx_pause)
tp->tg3_flags |= TG3_FLAG_PAUSE_RX;
else
tp->tg3_flags &= ~TG3_FLAG_PAUSE_RX;
if (epause.tx_pause)
if (epause->tx_pause)
tp->tg3_flags |= TG3_FLAG_PAUSE_TX;
else
tp->tg3_flags &= ~TG3_FLAG_PAUSE_TX;
tg3_halt(tp);
tg3_init_rings(tp);
tg3_init_hw(tp);
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);
tg3_netif_start(tp);
return 0;
}
case ETHTOOL_GRXCSUM: {
struct ethtool_value edata = { ETHTOOL_GRXCSUM };
}
edata.data =
(tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
case ETHTOOL_SRXCSUM: {
struct ethtool_value edata;
static u32 tg3_get_rx_csum(struct net_device *dev)
{
struct tg3 *tp = dev->priv;
return (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0;
}
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
static int tg3_set_rx_csum(struct net_device *dev, u32 data)
{
struct tg3 *tp = dev->priv;
if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
if (edata.data != 0)
if (data != 0)
return -EINVAL;
return 0;
}
spin_lock_irq(&tp->lock);
if (edata.data)
if (data)
tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
else
tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
spin_unlock_irq(&tp->lock);
return 0;
}
case ETHTOOL_GTXCSUM: {
struct ethtool_value edata = { ETHTOOL_GTXCSUM };
edata.data =
(tp->dev->features & NETIF_F_IP_CSUM) != 0;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
case ETHTOOL_STXCSUM: {
struct ethtool_value edata;
}
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
static int tg3_set_tx_csum(struct net_device *dev, u32 data)
{
struct tg3 *tp = dev->priv;
if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
if (edata.data != 0)
if (data != 0)
return -EINVAL;
return 0;
}
if (edata.data)
tp->dev->features |= NETIF_F_IP_CSUM;
if (data)
dev->features |= NETIF_F_IP_CSUM;
else
tp->dev->features &= ~NETIF_F_IP_CSUM;
dev->features &= ~NETIF_F_IP_CSUM;
return 0;
}
case ETHTOOL_GSG: {
struct ethtool_value edata = { ETHTOOL_GSG };
edata.data =
(tp->dev->features & NETIF_F_SG) != 0;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
case ETHTOOL_SSG: {
struct ethtool_value edata;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
if (edata.data)
tp->dev->features |= NETIF_F_SG;
else
tp->dev->features &= ~NETIF_F_SG;
return 0;
}
};
return -EOPNOTSUPP;
}
static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
......@@ -5503,8 +5382,6 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
int err;
switch(cmd) {
case SIOCETHTOOL:
return tg3_ethtool_ioctl(dev, (void *) ifr->ifr_data);
case SIOCGMIIPHY:
data->phy_id = PHY_ADDR;
......@@ -5568,6 +5445,30 @@ static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
}
#endif
static struct ethtool_ops tg3_ethtool_ops = {
.get_settings = tg3_get_settings,
.set_settings = tg3_set_settings,
.get_drvinfo = tg3_get_drvinfo,
.get_regs_len = tg3_get_regs_len,
.get_regs = tg3_get_regs,
.get_wol = tg3_get_wol,
.set_wol = tg3_set_wol,
.get_msglevel = tg3_get_msglevel,
.set_msglevel = tg3_set_msglevel,
.nway_reset = tg3_nway_reset,
.get_link = ethtool_op_get_link,
.get_ringparam = tg3_get_ringparam,
.set_ringparam = tg3_set_ringparam,
.get_pauseparam = tg3_get_pauseparam,
.set_pauseparam = tg3_set_pauseparam,
.get_rx_csum = tg3_get_rx_csum,
.set_rx_csum = tg3_set_rx_csum,
.get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = tg3_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
};
/* Chips other than 5700/5701 use the NVRAM for fetching info. */
static void __devinit tg3_nvram_init(struct tg3 *tp)
{
......@@ -6880,6 +6781,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
dev->do_ioctl = tg3_ioctl;
dev->tx_timeout = tg3_tx_timeout;
dev->poll = tg3_poll;
dev->ethtool_ops = &tg3_ethtool_ops;
dev->weight = 64;
dev->watchdog_timeo = TG3_TX_TIMEOUT;
dev->change_mtu = tg3_change_mtu;
......
......@@ -315,7 +315,7 @@ int __devinit xl_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->irq=pdev->irq;
dev->base_addr=pci_resource_start(pdev,0) ;
dev->init=NULL ; /* Must be null with new api, otherwise get called twice */
xl_priv->xl_card_name = (char *)pdev->dev.name ;
xl_priv->xl_card_name = pci_name(pdev);
xl_priv->xl_mmio=ioremap(pci_resource_start(pdev,1), XL_IO_SPACE);
xl_priv->pdev = pdev ;
......
......@@ -230,9 +230,10 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device
dev->irq=pdev->irq;
dev->base_addr=pci_resource_start(pdev, 0);
dev->init=NULL; /* Must be NULL otherwise we get called twice */
olympic_priv->olympic_card_name = (char *)pdev->dev.name ;
olympic_priv->olympic_card_name = pci_name(pdev);
olympic_priv->olympic_mmio = ioremap(pci_resource_start(pdev,1),256);
olympic_priv->olympic_lap = ioremap(pci_resource_start(pdev,2),2048);
#warning check ioremap return value
olympic_priv->pdev = pdev ;
if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) )
......
......@@ -226,6 +226,7 @@ static struct pci_device_id tulip_pci_tbl[] = {
{ 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, /* ALi 1563 integrated ethernet */
{ 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
......
......@@ -890,12 +890,12 @@ int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c)
if(c->mtu > PAGE_SIZE/2)
return -EMSGSIZE;
c->rx_buf[0]=(void *)get_free_page(GFP_KERNEL|GFP_DMA);
c->rx_buf[0]=(void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
if(c->rx_buf[0]==NULL)
return -ENOBUFS;
c->rx_buf[1]=c->rx_buf[0]+PAGE_SIZE/2;
c->tx_dma_buf[0]=(void *)get_free_page(GFP_KERNEL|GFP_DMA);
c->tx_dma_buf[0]=(void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
if(c->tx_dma_buf[0]==NULL)
{
free_page((unsigned long)c->rx_buf[0]);
......@@ -1080,7 +1080,7 @@ int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c)
if(c->mtu > PAGE_SIZE/2)
return -EMSGSIZE;
c->tx_dma_buf[0]=(void *)get_free_page(GFP_KERNEL|GFP_DMA);
c->tx_dma_buf[0]=(void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
if(c->tx_dma_buf[0]==NULL)
return -ENOBUFS;
......
......@@ -1025,6 +1025,7 @@ struct airo_info {
#define FLAG_802_11 0x200
#define FLAG_PENDING_XMIT 0x400
#define FLAG_PENDING_XMIT11 0x800
#define FLAG_PCI 0x1000
int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
int whichbap);
unsigned short *flash;
......@@ -4093,6 +4094,7 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev,
return -ENODEV;
pci_set_drvdata(pdev, dev);
((struct airo_info *)dev->priv)->flags |= FLAG_PCI;
return 0;
}
......@@ -4134,11 +4136,19 @@ static int __init airo_init_module( void )
static void __exit airo_cleanup_module( void )
{
int is_pci = 0;
while( airo_devices ) {
printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
#ifdef CONFIG_PCI
if (((struct airo_info *)airo_devices->dev->priv)->flags & FLAG_PCI)
is_pci = 1;
#endif
stop_airo_card( airo_devices->dev, 1 );
}
remove_proc_entry("aironet", proc_root_driver);
if (is_pci)
pci_unregister_driver(&airo_driver);
}
#ifdef WIRELESS_EXT
......@@ -5612,7 +5622,7 @@ static const struct iw_handler_def airo_handler_def =
.standard = (iw_handler *) airo_handler,
.private = (iw_handler *) airo_private_handler,
.private_args = (struct iw_priv_args *) airo_private_args,
#if 0 && WIRELESS_EXT > 15
#if WIRELESS_EXT > 15
.spy_offset = ((void *) (&((struct airo_info *) NULL)->spy_data) -
(void *) NULL),
#endif /* WIRELESS_EXT > 15 */
......
......@@ -39,7 +39,6 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/netdevice.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
......@@ -108,7 +107,7 @@ void stop_atmel_card( struct net_device *, int );
int reset_atmel_card( struct net_device * );
static void atmel_config(dev_link_t *link);
static void atmel_release(u_long arg);
static void atmel_release(dev_link_t *link);
static int atmel_event(event_t event, int priority,
event_callback_args_t *args);
......@@ -222,9 +221,6 @@ static dev_link_t *atmel_attach(void)
return NULL;
}
memset(link, 0, sizeof(struct dev_link_t));
init_timer(&link->release);
link->release.function = &atmel_release;
link->release.data = (u_long)link;
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
......@@ -300,9 +296,8 @@ static void atmel_detach(dev_link_t *link)
if (*linkp == NULL)
return;
del_timer(&link->release);
if ( link->state & DEV_CONFIG ) {
atmel_release( (int)link );
atmel_release(link);
if ( link->state & DEV_STALE_CONFIG ) {
link->state |= DEV_STALE_LINK;
return;
......@@ -379,7 +374,6 @@ static struct {
/* This is strictly temporary, until PCMCIA devices get integrated into the device model. */
static struct device atmel_device = {
.name = "Atmel at76c50x wireless",
.bus_id = "pcmcia",
};
......@@ -606,9 +600,8 @@ static void atmel_config(dev_link_t *link)
cs_failed:
cs_error(link->handle, last_fn, last_ret);
atmel_release((u_long)link);
} /* atmel_config */
atmel_release(link);
}
/*======================================================================
......@@ -618,9 +611,8 @@ static void atmel_config(dev_link_t *link)
======================================================================*/
static void atmel_release(u_long arg)
static void atmel_release(dev_link_t *link)
{
dev_link_t *link = (dev_link_t *)arg;
struct net_device *dev = ((local_info_t*)link->priv)->eth_dev;
DEBUG(0, "atmel_release(0x%p)\n", link);
......@@ -639,8 +631,7 @@ static void atmel_release(u_long arg)
if (link->irq.AssignedIRQ)
CardServices(ReleaseIRQ, link->handle, &link->irq);
link->state &= ~DEV_CONFIG;
} /* atmel_release */
}
/*======================================================================
......@@ -667,7 +658,7 @@ static int atmel_event(event_t event, int priority,
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
netif_device_detach(local->eth_dev);
mod_timer(&link->release, jiffies + HZ/20);
atmel_release(link);
}
break;
case CS_EVENT_CARD_INSERTION:
......@@ -719,7 +710,7 @@ static void atmel_cs_cleanup(void)
/* XXX: this really needs to move into generic code.. */
while (dev_list != NULL) {
if (dev_list->state & DEV_CONFIG)
atmel_release((u_long)dev_list);
atmel_release(dev_list);
atmel_detach(dev_list);
}
}
......
......@@ -111,7 +111,7 @@ static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
b->mask.data = data;
b->mask.clock = clock;
b->adapter = matrox_i2c_adapter_template;
snprintf(b->adapter.dev.name, DEVICE_NAME_SIZE, name,
snprintf(b->adapter.name, DEVICE_NAME_SIZE, name,
minfo->fbcon.node);
i2c_set_adapdata(&b->adapter, b);
b->adapter.algo_data = &b->bac;
......
......@@ -1255,7 +1255,7 @@ static int maven_detect_client(struct i2c_adapter* adapter, int address, int kin
new_client->adapter = adapter;
new_client->driver = &maven_driver;
new_client->flags = 0;
strcpy(new_client->dev.name, "maven client");
strcpy(new_client->name, "maven client");
if ((err = i2c_attach_client(new_client)))
goto ERROR3;
err = maven_init_client(new_client);
......
......@@ -362,7 +362,7 @@ static int kstat_read_proc(char *page, char **start, off_t off,
int i, len;
extern unsigned long total_forks;
u64 jif;
unsigned int sum = 0, user = 0, nice = 0, system = 0, idle = 0, iowait = 0;
unsigned int sum = 0, user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0;
struct timeval now;
unsigned long seq;
......@@ -388,25 +388,31 @@ static int kstat_read_proc(char *page, char **start, off_t off,
system += kstat_cpu(i).cpustat.system;
idle += kstat_cpu(i).cpustat.idle;
iowait += kstat_cpu(i).cpustat.iowait;
irq += kstat_cpu(i).cpustat.irq;
softirq += kstat_cpu(i).cpustat.softirq;
for (j = 0 ; j < NR_IRQS ; j++)
sum += kstat_cpu(i).irqs[j];
}
len = sprintf(page, "cpu %u %u %u %u %u\n",
len = sprintf(page, "cpu %u %u %u %u %u %u %u\n",
jiffies_to_clock_t(user),
jiffies_to_clock_t(nice),
jiffies_to_clock_t(system),
jiffies_to_clock_t(idle),
jiffies_to_clock_t(iowait));
jiffies_to_clock_t(iowait),
jiffies_to_clock_t(irq),
jiffies_to_clock_t(softirq));
for (i = 0 ; i < NR_CPUS; i++){
if (!cpu_online(i)) continue;
len += sprintf(page + len, "cpu%d %u %u %u %u %u\n",
len += sprintf(page + len, "cpu%d %u %u %u %u %u %u %u\n",
i,
jiffies_to_clock_t(kstat_cpu(i).cpustat.user),
jiffies_to_clock_t(kstat_cpu(i).cpustat.nice),
jiffies_to_clock_t(kstat_cpu(i).cpustat.system),
jiffies_to_clock_t(kstat_cpu(i).cpustat.idle),
jiffies_to_clock_t(kstat_cpu(i).cpustat.iowait));
jiffies_to_clock_t(kstat_cpu(i).cpustat.iowait),
jiffies_to_clock_t(kstat_cpu(i).cpustat.irq),
jiffies_to_clock_t(kstat_cpu(i).cpustat.softirq));
}
len += sprintf(page + len, "intr %u", sum);
......
......@@ -42,6 +42,9 @@ struct eisa_device {
struct resource res[EISA_MAX_RESOURCES];
u64 dma_mask;
struct device dev; /* generic device */
#ifdef CONFIG_EISA_NAMES
char pretty_name[DEVICE_NAME_SIZE];
#endif
};
#define to_eisa_device(n) container_of(n, struct eisa_device, dev)
......
......@@ -97,7 +97,7 @@ struct ethtool_coalesce {
u32 rx_max_coalesced_frames;
/* Same as above two parameters, except that these values
* apply while an IRQ is being services by the host. Not
* apply while an IRQ is being serviced by the host. Not
* all cards support this feature and the values are ignored
* in that case.
*/
......@@ -119,7 +119,7 @@ struct ethtool_coalesce {
u32 tx_max_coalesced_frames;
/* Same as above two parameters, except that these values
* apply while an IRQ is being services by the host. Not
* apply while an IRQ is being serviced by the host. Not
* all cards support this feature and the values are ignored
* in that case.
*/
......@@ -250,6 +250,101 @@ struct ethtool_stats {
u64 data[0];
};
struct net_device;
/* Some generic methods drivers may use in their ethtool_ops */
u32 ethtool_op_get_link(struct net_device *dev);
u32 ethtool_op_get_tx_csum(struct net_device *dev);
u32 ethtool_op_get_sg(struct net_device *dev);
int ethtool_op_set_sg(struct net_device *dev, u32 data);
/**
* &ethtool_ops - Alter and report network device settings
* get_settings: Get device-specific settings
* set_settings: Set device-specific settings
* get_drvinfo: Report driver information
* get_regs: Get device registers
* get_wol: Report whether Wake-on-Lan is enabled
* set_wol: Turn Wake-on-Lan on or off
* get_msglevel: Report driver message level
* set_msglevel: Set driver message level
* nway_reset: Restart autonegotiation
* get_link: Get link status
* get_eeprom: Read data from the device EEPROM
* set_eeprom: Write data to the device EEPROM
* get_coalesce: Get interrupt coalescing parameters
* set_coalesce: Set interrupt coalescing parameters
* get_ringparam: Report ring sizes
* set_ringparam: Set ring sizes
* get_pauseparam: Report pause parameters
* set_pauseparam: Set pause paramters
* get_rx_csum: Report whether receive checksums are turned on or off
* set_rx_csum: Turn receive checksum on or off
* get_tx_csum: Report whether transmit checksums are turned on or off
* set_tx_csum: Turn transmit checksums on or off
* get_sg: Report whether scatter-gather is enabled
* set_sg: Turn scatter-gather on or off
* self_test: Run specified self-tests
* get_strings: Return a set of strings that describe the requested objects
* phys_id: Identify the device
* get_stats: Return statistics about the device
*
* Description:
*
* get_settings:
* @get_settings is passed an &ethtool_cmd to fill in. It returns
* an negative errno or zero.
*
* set_settings:
* @set_settings is passed an &ethtool_cmd and should attempt to set
* all the settings this device supports. It may return an error value
* if something goes wrong (otherwise 0).
*
* get_eeprom:
* Should fill in the magic field. Don't need to check len for zero
* or wraparound but must check offset + len < size. Fill in the data
* argument with the eeprom values from offset to offset + len. Update
* len to the amount read. Returns an error or zero.
*
* set_eeprom:
* Should validate the magic field. Don't need to check len for zero
* or wraparound but must check offset + len < size. Update len to
* the amount written. Returns an error or zero.
*/
struct ethtool_ops {
int (*get_settings)(struct net_device *, struct ethtool_cmd *);
int (*set_settings)(struct net_device *, struct ethtool_cmd *);
void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
int (*get_regs_len)(struct net_device *);
void (*get_regs)(struct net_device *, struct ethtool_regs *, void *);
void (*get_wol)(struct net_device *, struct ethtool_wolinfo *);
int (*set_wol)(struct net_device *, struct ethtool_wolinfo *);
u32 (*get_msglevel)(struct net_device *);
void (*set_msglevel)(struct net_device *, u32);
int (*nway_reset)(struct net_device *);
u32 (*get_link)(struct net_device *);
int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
int (*set_coalesce)(struct net_device *, struct ethtool_coalesce *);
void (*get_ringparam)(struct net_device *, struct ethtool_ringparam *);
int (*set_ringparam)(struct net_device *, struct ethtool_ringparam *);
void (*get_pauseparam)(struct net_device *, struct ethtool_pauseparam*);
int (*set_pauseparam)(struct net_device *, struct ethtool_pauseparam*);
u32 (*get_rx_csum)(struct net_device *);
int (*set_rx_csum)(struct net_device *, u32);
u32 (*get_tx_csum)(struct net_device *);
int (*set_tx_csum)(struct net_device *, u32);
u32 (*get_sg)(struct net_device *);
int (*set_sg)(struct net_device *, u32);
int (*self_test_count)(struct net_device *);
void (*self_test)(struct net_device *, struct ethtool_test *, u64 *);
void (*get_strings)(struct net_device *, u32 stringset, u8 *);
int (*phys_id)(struct net_device *, u32);
int (*get_stats_count)(struct net_device *);
void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *);
};
/* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001 /* Get settings. */
#define ETHTOOL_SSET 0x00000002 /* Set settings. */
......
......@@ -17,6 +17,8 @@ struct cpu_usage_stat {
unsigned int user;
unsigned int nice;
unsigned int system;
unsigned int softirq;
unsigned int irq;
unsigned int idle;
unsigned int iowait;
};
......
......@@ -43,6 +43,11 @@
struct divert_blk;
struct vlan_group;
struct ethtool_ops;
/* source back-compat hook */
#define SET_ETHTOOL_OPS(netdev,ops) \
( (netdev)->ethtool_ops = (ops) )
#define HAVE_ALLOC_NETDEV /* feature macro: alloc_xxxdev
functions are available. */
......@@ -300,6 +305,8 @@ struct net_device
* See <net/iw_handler.h> for details. Jean II */
struct iw_handler_def * wireless_handlers;
struct ethtool_ops *ethtool_ops;
/*
* This marks the end of the "visible" part of the structure. All
* fields hereafter are internal to the system, and may change at
......@@ -482,7 +489,6 @@ struct packet_type
struct list_head list;
};
#include <linux/interrupt.h>
#include <linux/notifier.h>
......@@ -630,6 +636,7 @@ extern int netif_rx(struct sk_buff *skb);
#define HAVE_NETIF_RECEIVE_SKB 1
extern int netif_receive_skb(struct sk_buff *skb);
extern int dev_ioctl(unsigned int cmd, void *);
extern int dev_ethtool(struct ifreq *);
extern unsigned dev_get_flags(const struct net_device *);
extern int dev_change_flags(struct net_device *, unsigned);
extern int dev_set_mtu(struct net_device *, int);
......
......@@ -34,4 +34,14 @@
# define PR_FP_EXC_ASYNC 2 /* async recoverable exception mode */
# define PR_FP_EXC_PRECISE 3 /* precise exception mode */
/* Get/set whether we use statistical process timing or accurate timestamp
* based process timing */
#define PR_GET_TIMING 13
#define PR_SET_TIMING 14
# define PR_TIMING_STATISTICAL 0 /* Normal, traditional,
statistical process timing */
# define PR_TIMING_TIMESTAMP 1 /* Accurate timestamp based
process timing */
#endif /* _LINUX_PRCTL_H */
......@@ -118,7 +118,6 @@ typedef struct dev_link_t {
dev_node_t *dev;
u_int state, open;
wait_queue_head_t pending;
struct timer_list release;
client_handle_t handle;
io_req_t io;
irq_req_t irq;
......
......@@ -6,6 +6,8 @@
* the scsi code for linux.
*/
#include <linux/types.h>
/*
$Header: /usr/src/linux/include/linux/RCS/scsi.h,v 1.3 1993/09/24 12:20:33 drew Exp $
......@@ -208,18 +210,18 @@ static inline int scsi_status_is_good(int status)
struct ccs_modesel_head
{
u_char _r1; /* reserved */
u_char medium; /* device-specific medium type */
u_char _r2; /* reserved */
u_char block_desc_length; /* block descriptor length */
u_char density; /* device-specific density code */
u_char number_blocks_hi; /* number of blocks in this block desc */
u_char number_blocks_med;
u_char number_blocks_lo;
u_char _r3;
u_char block_length_hi; /* block length for blocks in this desc */
u_char block_length_med;
u_char block_length_lo;
u8 _r1; /* reserved */
u8 medium; /* device-specific medium type */
u8 _r2; /* reserved */
u8 block_desc_length; /* block descriptor length */
u8 density; /* device-specific density code */
u8 number_blocks_hi; /* number of blocks in this block desc */
u8 number_blocks_med;
u8 number_blocks_lo;
u8 _r3;
u8 block_length_hi; /* block length for blocks in this desc */
u8 block_length_med;
u8 block_length_lo;
};
/*
......
......@@ -1201,11 +1201,17 @@ void scheduler_tick(int user_ticks, int sys_ticks)
if (rcu_pending(cpu))
rcu_check_callbacks(cpu, user_ticks);
if (p == rq->idle) {
/* note: this timer irq context must be accounted for as well */
if (irq_count() - HARDIRQ_OFFSET >= SOFTIRQ_OFFSET)
cpustat->system += sys_ticks;
else if (atomic_read(&rq->nr_iowait) > 0)
if (hardirq_count() - HARDIRQ_OFFSET) {
cpustat->irq += sys_ticks;
sys_ticks = 0;
} else if (softirq_count()) {
cpustat->softirq += sys_ticks;
sys_ticks = 0;
}
if (p == rq->idle) {
if (atomic_read(&rq->nr_iowait) > 0)
cpustat->iowait += sys_ticks;
else
cpustat->idle += sys_ticks;
......
......@@ -1399,7 +1399,15 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
case PR_GET_FPEXC:
error = GET_FPEXC_CTL(current, arg2);
break;
case PR_GET_TIMING:
error = PR_TIMING_STATISTICAL;
break;
case PR_SET_TIMING:
if (arg2 == PR_TIMING_STATISTICAL)
error = 0;
else
error = -EINVAL;
break;
case PR_GET_KEEPCAPS:
if (current->keep_capabilities)
......
......@@ -87,13 +87,12 @@ char * strncpy(char * dest,const char *src,size_t count)
{
char *tmp = dest;
while (count && (*dest++ = *src++) != '\0')
count--;
while (count > 1) {
*dest++ = 0;
while (count) {
if ((*tmp = *src) != 0) src++;
tmp++;
count--;
}
return tmp;
return dest;
}
#endif
......
......@@ -6,8 +6,8 @@ obj-y := sock.o skbuff.o iovec.o datagram.o scm.o
obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
obj-y += flow.o dev.o net-sysfs.o dev_mcast.o dst.o neighbour.o \
rtnetlink.o utils.o link_watch.o filter.o
obj-y += flow.o dev.o ethtool.o net-sysfs.o dev_mcast.o dst.o \
neighbour.o rtnetlink.o utils.o link_watch.o filter.o
obj-$(CONFIG_NETFILTER) += netfilter.o
obj-$(CONFIG_NET_DIVERT) += dv.o
......
......@@ -2368,7 +2368,6 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
cmd == SIOCBONDSLAVEINFOQUERY ||
cmd == SIOCBONDINFOQUERY ||
cmd == SIOCBONDCHANGEACTIVE ||
cmd == SIOCETHTOOL ||
cmd == SIOCGMIIPHY ||
cmd == SIOCGMIIREG ||
cmd == SIOCSMIIREG ||
......@@ -2465,13 +2464,26 @@ int dev_ioctl(unsigned int cmd, void *arg)
}
return ret;
case SIOCETHTOOL:
dev_load(ifr.ifr_name);
rtnl_lock();
ret = dev_ethtool(&ifr);
rtnl_unlock();
if (!ret) {
if (colon)
*colon = ':';
if (copy_to_user(arg, &ifr,
sizeof(struct ifreq)))
ret = -EFAULT;
}
return ret;
/*
* These ioctl calls:
* - require superuser power.
* - require strict serialization.
* - return a value
*/
case SIOCETHTOOL:
case SIOCGMIIPHY:
case SIOCGMIIREG:
if (!capable(CAP_NET_ADMIN))
......
/*
* net/core/ethtool.c - Ethtool ioctl handler
* Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
*
* This file is where we call all the ethtool_ops commands to get
* the information ethtool needs. We fall back to calling do_ioctl()
* for drivers which haven't been converted to ethtool_ops yet.
*
* It's GPL, stupid.
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
/*
* Some useful ethtool_ops methods that're device independent.
* If we find that all drivers want to do the same thing here,
* we can turn these into dev_() function calls.
*/
u32 ethtool_op_get_link(struct net_device *dev)
{
return netif_carrier_ok(dev) ? 1 : 0;
}
u32 ethtool_op_get_tx_csum(struct net_device *dev)
{
return (dev->features & NETIF_F_IP_CSUM) != 0;
}
u32 ethtool_op_get_sg(struct net_device *dev)
{
return (dev->features & NETIF_F_SG) != 0;
}
int ethtool_op_set_sg(struct net_device *dev, u32 data)
{
if (data)
dev->features |= NETIF_F_SG;
else
dev->features &= ~NETIF_F_SG;
return 0;
}
/* Handlers for each ethtool command */
static int ethtool_get_settings(struct net_device *dev, void *useraddr)
{
struct ethtool_cmd cmd = { ETHTOOL_GSET };
int err;
if (!dev->ethtool_ops->get_settings)
return -EOPNOTSUPP;
err = dev->ethtool_ops->get_settings(dev, &cmd);
if (err < 0)
return err;
if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
return -EFAULT;
return 0;
}
static int ethtool_set_settings(struct net_device *dev, void *useraddr)
{
struct ethtool_cmd cmd;
if (!dev->ethtool_ops->set_settings)
return -EOPNOTSUPP;
if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
return -EFAULT;
return dev->ethtool_ops->set_settings(dev, &cmd);
}
static int ethtool_get_drvinfo(struct net_device *dev, void *useraddr)
{
struct ethtool_drvinfo info;
struct ethtool_ops *ops = dev->ethtool_ops;
if (!ops->get_drvinfo)
return -EOPNOTSUPP;
memset(&info, 0, sizeof(info));
info.cmd = ETHTOOL_GDRVINFO;
ops->get_drvinfo(dev, &info);
if (ops->self_test_count)
info.testinfo_len = ops->self_test_count(dev);
if (ops->get_stats_count)
info.n_stats = ops->get_stats_count(dev);
if (ops->get_regs_len)
info.regdump_len = ops->get_regs_len(dev);
/* XXX: eeprom? */
if (copy_to_user(useraddr, &info, sizeof(info)))
return -EFAULT;
return 0;
}
static int ethtool_get_regs(struct net_device *dev, char *useraddr)
{
struct ethtool_regs regs;
struct ethtool_ops *ops = dev->ethtool_ops;
void *regbuf;
int reglen, ret;
if (!ops->get_regs || !ops->get_regs_len)
return -EOPNOTSUPP;
if (copy_from_user(&regs, useraddr, sizeof(regs)))
return -EFAULT;
reglen = ops->get_regs_len(dev);
if (regs.len > reglen)
regs.len = reglen;
regbuf = kmalloc(reglen, GFP_USER);
if (!regbuf)
return -ENOMEM;
ops->get_regs(dev, &regs, regbuf);
ret = -EFAULT;
if (copy_to_user(useraddr, &regs, sizeof(regs)))
goto out;
useraddr += offsetof(struct ethtool_regs, data);
if (copy_to_user(useraddr, regbuf, reglen))
goto out;
ret = 0;
out:
kfree(regbuf);
return ret;
}
static int ethtool_get_wol(struct net_device *dev, char *useraddr)
{
struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
if (!dev->ethtool_ops->get_wol)
return -EOPNOTSUPP;
dev->ethtool_ops->get_wol(dev, &wol);
if (copy_to_user(useraddr, &wol, sizeof(wol)))
return -EFAULT;
return 0;
}
static int ethtool_set_wol(struct net_device *dev, char *useraddr)
{
struct ethtool_wolinfo wol;
if (!dev->ethtool_ops->set_wol)
return -EOPNOTSUPP;
if (copy_from_user(&wol, useraddr, sizeof(wol)))
return -EFAULT;
return dev->ethtool_ops->set_wol(dev, &wol);
}
static int ethtool_get_msglevel(struct net_device *dev, char *useraddr)
{
struct ethtool_value edata = { ETHTOOL_GMSGLVL };
if (!dev->ethtool_ops->get_msglevel)
return -EOPNOTSUPP;
edata.data = dev->ethtool_ops->get_msglevel(dev);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
static int ethtool_set_msglevel(struct net_device *dev, char *useraddr)
{
struct ethtool_value edata;
if (!dev->ethtool_ops->set_msglevel)
return -EOPNOTSUPP;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
dev->ethtool_ops->set_msglevel(dev, edata.data);
return 0;
}
static int ethtool_nway_reset(struct net_device *dev)
{
if (!dev->ethtool_ops->nway_reset)
return -EOPNOTSUPP;
return dev->ethtool_ops->nway_reset(dev);
}
static int ethtool_get_link(struct net_device *dev, void *useraddr)
{
struct ethtool_value edata = { ETHTOOL_GLINK };
if (!dev->ethtool_ops->get_link)
return -EOPNOTSUPP;
edata.data = dev->ethtool_ops->get_link(dev);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
static int ethtool_get_eeprom(struct net_device *dev, void *useraddr)
{
struct ethtool_eeprom eeprom;
u8 *data;
int len, ret;
if (!dev->ethtool_ops->get_eeprom)
return -EOPNOTSUPP;
if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
return -EFAULT;
len = eeprom.len;
/* Check for wrap and zero */
if (eeprom.offset + len <= eeprom.offset)
return -EINVAL;
data = kmalloc(len, GFP_USER);
if (!data)
return -ENOMEM;
if (copy_from_user(data, useraddr + sizeof(eeprom), len))
return -EFAULT;
ret = dev->ethtool_ops->get_eeprom(dev, &eeprom, data);
if (!ret)
goto out;
ret = -EFAULT;
if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
goto out;
if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
goto out;
ret = 0;
out:
kfree(data);
return ret;
}
static int ethtool_set_eeprom(struct net_device *dev, void *useraddr)
{
struct ethtool_eeprom eeprom;
u8 *data;
int len, ret;
if (!dev->ethtool_ops->set_eeprom)
return -EOPNOTSUPP;
if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
return -EFAULT;
len = eeprom.len;
/* Check for wrap and zero */
if (eeprom.offset + len <= eeprom.offset)
return -EINVAL;
data = kmalloc(len, GFP_USER);
if (!data)
return -ENOMEM;
if (copy_from_user(data, useraddr + sizeof(eeprom), len))
return -EFAULT;
ret = dev->ethtool_ops->set_eeprom(dev, &eeprom, data);
if (ret)
goto out;
if (copy_to_user(useraddr + sizeof(eeprom), data, len))
ret = -EFAULT;
out:
kfree(data);
return ret;
}
static int ethtool_get_coalesce(struct net_device *dev, void *useraddr)
{
struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE };
if (!dev->ethtool_ops->get_coalesce)
return -EOPNOTSUPP;
dev->ethtool_ops->get_coalesce(dev, &coalesce);
if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
return -EFAULT;
return 0;
}
static int ethtool_set_coalesce(struct net_device *dev, void *useraddr)
{
struct ethtool_coalesce coalesce;
if (!dev->ethtool_ops->get_coalesce)
return -EOPNOTSUPP;
if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
return -EFAULT;
return dev->ethtool_ops->set_coalesce(dev, &coalesce);
}
static int ethtool_get_ringparam(struct net_device *dev, void *useraddr)
{
struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM };
if (!dev->ethtool_ops->get_ringparam)
return -EOPNOTSUPP;
dev->ethtool_ops->get_ringparam(dev, &ringparam);
if (copy_to_user(useraddr, &ringparam, sizeof(ringparam)))
return -EFAULT;
return 0;
}
static int ethtool_set_ringparam(struct net_device *dev, void *useraddr)
{
struct ethtool_ringparam ringparam;
if (!dev->ethtool_ops->get_ringparam)
return -EOPNOTSUPP;
if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
return -EFAULT;
return dev->ethtool_ops->set_ringparam(dev, &ringparam);
}
static int ethtool_get_pauseparam(struct net_device *dev, void *useraddr)
{
struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };
if (!dev->ethtool_ops->get_pauseparam)
return -EOPNOTSUPP;
dev->ethtool_ops->get_pauseparam(dev, &pauseparam);
if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam)))
return -EFAULT;
return 0;
}
static int ethtool_set_pauseparam(struct net_device *dev, void *useraddr)
{
struct ethtool_pauseparam pauseparam;
if (!dev->ethtool_ops->get_pauseparam)
return -EOPNOTSUPP;
if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
return -EFAULT;
return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
}
static int ethtool_get_rx_csum(struct net_device *dev, char *useraddr)
{
struct ethtool_value edata = { ETHTOOL_GRXCSUM };
if (!dev->ethtool_ops->get_rx_csum)
return -EOPNOTSUPP;
edata.data = dev->ethtool_ops->get_rx_csum(dev);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
static int ethtool_set_rx_csum(struct net_device *dev, char *useraddr)
{
struct ethtool_value edata;
if (!dev->ethtool_ops->set_rx_csum)
return -EOPNOTSUPP;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
dev->ethtool_ops->set_rx_csum(dev, edata.data);
return 0;
}
static int ethtool_get_tx_csum(struct net_device *dev, char *useraddr)
{
struct ethtool_value edata = { ETHTOOL_GTXCSUM };
if (!dev->ethtool_ops->get_tx_csum)
return -EOPNOTSUPP;
edata.data = dev->ethtool_ops->get_tx_csum(dev);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
static int ethtool_set_tx_csum(struct net_device *dev, char *useraddr)
{
struct ethtool_value edata;
if (!dev->ethtool_ops->set_tx_csum)
return -EOPNOTSUPP;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
return dev->ethtool_ops->set_tx_csum(dev, edata.data);
}
static int ethtool_get_sg(struct net_device *dev, char *useraddr)
{
struct ethtool_value edata = { ETHTOOL_GSG };
if (!dev->ethtool_ops->get_sg)
return -EOPNOTSUPP;
edata.data = dev->ethtool_ops->get_sg(dev);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
static int ethtool_set_sg(struct net_device *dev, char *useraddr)
{
struct ethtool_value edata;
if (!dev->ethtool_ops->set_sg)
return -EOPNOTSUPP;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
return dev->ethtool_ops->set_sg(dev, edata.data);
}
static int ethtool_self_test(struct net_device *dev, char *useraddr)
{
struct ethtool_test test;
struct ethtool_ops *ops = dev->ethtool_ops;
u64 *data;
int ret;
if (!ops->self_test || !ops->self_test_count)
return -EOPNOTSUPP;
if (copy_from_user(&test, useraddr, sizeof(test)))
return -EFAULT;
test.len = ops->self_test_count(dev);
data = kmalloc(test.len * sizeof(u64), GFP_USER);
if (!data)
return -ENOMEM;
ops->self_test(dev, &test, data);
ret = -EFAULT;
if (copy_to_user(useraddr, &test, sizeof(test)))
goto out;
useraddr += sizeof(test);
if (copy_to_user(useraddr, data, test.len * sizeof(u64)))
goto out;
ret = 0;
out:
kfree(data);
return ret;
}
static int ethtool_get_strings(struct net_device *dev, void *useraddr)
{
struct ethtool_gstrings gstrings;
struct ethtool_ops *ops = dev->ethtool_ops;
u8 *data;
int ret;
if (!ops->get_strings)
return -EOPNOTSUPP;
if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
return -EFAULT;
switch (gstrings.string_set) {
case ETH_SS_TEST:
if (ops->self_test_count)
gstrings.len = ops->self_test_count(dev);
else
return -EOPNOTSUPP;
case ETH_SS_STATS:
if (ops->get_stats_count)
gstrings.len = ops->get_stats_count(dev);
else
return -EOPNOTSUPP;
default:
return -EINVAL;
}
data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
if (!data)
return -ENOMEM;
ops->get_strings(dev, gstrings.string_set, data);
ret = -EFAULT;
if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
goto out;
useraddr += sizeof(gstrings);
if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
goto out;
ret = 0;
out:
kfree(data);
return ret;
}
static int ethtool_phys_id(struct net_device *dev, void *useraddr)
{
struct ethtool_value id;
if (!dev->ethtool_ops->phys_id)
return -EOPNOTSUPP;
if (copy_from_user(&id, useraddr, sizeof(id)))
return -EFAULT;
return dev->ethtool_ops->phys_id(dev, id.data);
}
static int ethtool_get_stats(struct net_device *dev, void *useraddr)
{
struct ethtool_stats stats;
struct ethtool_ops *ops = dev->ethtool_ops;
u64 *data;
int ret;
if (!ops->get_ethtool_stats || !ops->get_stats_count)
return -EOPNOTSUPP;
if (copy_from_user(&stats, useraddr, sizeof(stats)))
return -EFAULT;
stats.n_stats = ops->get_stats_count(dev);
data = kmalloc(stats.n_stats * sizeof(u64), GFP_USER);
if (!data)
return -ENOMEM;
ops->get_ethtool_stats(dev, &stats, data);
ret = -EFAULT;
if (copy_to_user(useraddr, &stats, sizeof(stats)))
goto out;
useraddr += sizeof(stats);
if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64)))
goto out;
ret = 0;
out:
kfree(data);
return ret;
}
/* The main entry point in this file. Called from net/core/dev.c */
int dev_ethtool(struct ifreq *ifr)
{
struct net_device *dev = __dev_get_by_name(ifr->ifr_name);
void *useraddr = (void *) ifr->ifr_data;
u32 ethcmd;
/*
* XXX: This can be pushed down into the ethtool_* handlers that
* need it. Keep existing behaviour for the moment.
*/
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (!dev || !netif_device_present(dev))
return -ENODEV;
if (!dev->ethtool_ops)
goto ioctl;
if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
return -EFAULT;
switch (ethcmd) {
case ETHTOOL_GSET:
return ethtool_get_settings(dev, useraddr);
case ETHTOOL_SSET:
return ethtool_set_settings(dev, useraddr);
case ETHTOOL_GDRVINFO:
return ethtool_get_drvinfo(dev, useraddr);
case ETHTOOL_GREGS:
return ethtool_get_regs(dev, useraddr);
case ETHTOOL_GWOL:
return ethtool_get_wol(dev, useraddr);
case ETHTOOL_SWOL:
return ethtool_set_wol(dev, useraddr);
case ETHTOOL_GMSGLVL:
return ethtool_get_msglevel(dev, useraddr);
case ETHTOOL_SMSGLVL:
return ethtool_set_msglevel(dev, useraddr);
case ETHTOOL_NWAY_RST:
return ethtool_nway_reset(dev);
case ETHTOOL_GLINK:
return ethtool_get_link(dev, useraddr);
case ETHTOOL_GEEPROM:
return ethtool_get_eeprom(dev, useraddr);
case ETHTOOL_SEEPROM:
return ethtool_set_eeprom(dev, useraddr);
case ETHTOOL_GCOALESCE:
return ethtool_get_coalesce(dev, useraddr);
case ETHTOOL_SCOALESCE:
return ethtool_set_coalesce(dev, useraddr);
case ETHTOOL_GRINGPARAM:
return ethtool_get_ringparam(dev, useraddr);
case ETHTOOL_SRINGPARAM:
return ethtool_set_ringparam(dev, useraddr);
case ETHTOOL_GPAUSEPARAM:
return ethtool_get_pauseparam(dev, useraddr);
case ETHTOOL_SPAUSEPARAM:
return ethtool_set_pauseparam(dev, useraddr);
case ETHTOOL_GRXCSUM:
return ethtool_get_rx_csum(dev, useraddr);
case ETHTOOL_SRXCSUM:
return ethtool_set_rx_csum(dev, useraddr);
case ETHTOOL_GTXCSUM:
return ethtool_get_tx_csum(dev, useraddr);
case ETHTOOL_STXCSUM:
return ethtool_set_tx_csum(dev, useraddr);
case ETHTOOL_GSG:
return ethtool_get_sg(dev, useraddr);
case ETHTOOL_SSG:
return ethtool_set_sg(dev, useraddr);
case ETHTOOL_TEST:
return ethtool_self_test(dev, useraddr);
case ETHTOOL_GSTRINGS:
return ethtool_get_strings(dev, useraddr);
case ETHTOOL_PHYS_ID:
return ethtool_phys_id(dev, useraddr);
case ETHTOOL_GSTATS:
return ethtool_get_stats(dev, useraddr);
default:
return -EOPNOTSUPP;
}
ioctl:
if (dev->do_ioctl)
return dev->do_ioctl(dev, ifr, SIOCETHTOOL);
return -EOPNOTSUPP;
}
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