Commit 7f4174f1 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-scsi.bkbits.net/scsi-for-linus-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 3b76b263 edf68308
......@@ -103,6 +103,10 @@ static int el3_debug = EL3_DEBUG;
static int el3_debug = 2;
#endif
/* Used to do a global count of all the cards in the system. Must be
* a global variable so that the mca/eisa probe routines can increment
* it */
static int el3_cards = 0;
/* To minimize the size of the driver source I only define operating
constants if they are used several times. You'll need the manual
......@@ -167,16 +171,15 @@ struct el3_private {
/* skb send-queue */
int head, size;
struct sk_buff *queue[SKB_QUEUE_SIZE];
char mca_slot;
#ifdef CONFIG_PM
struct pm_dev *pmdev;
#endif
#ifdef __ISAPNP__
struct pnp_dev *pnpdev;
#endif
#ifdef CONFIG_EISA
struct eisa_device *edev;
#endif
enum {
EL3_MCA,
EL3_PNP,
EL3_EISA,
} type; /* type of device */
struct device *dev;
};
static int id_port __initdata = 0x110; /* Start with 0x110 to avoid new sound cards.*/
static struct net_device *el3_root_dev;
......@@ -200,6 +203,8 @@ static int el3_suspend(struct pm_dev *pdev);
static int el3_resume(struct pm_dev *pdev);
static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data);
#endif
/* generic device remove for all device types */
static int el3_device_remove (struct device *device);
#ifdef CONFIG_EISA
struct eisa_device_id el3_eisa_ids[] = {
......@@ -209,31 +214,46 @@ struct eisa_device_id el3_eisa_ids[] = {
};
static int el3_eisa_probe (struct device *device);
static int el3_eisa_remove (struct device *device);
struct eisa_driver el3_eisa_driver = {
.id_table = el3_eisa_ids,
.driver = {
.name = "3c509",
.probe = el3_eisa_probe,
.remove = __devexit_p (el3_eisa_remove)
.remove = __devexit_p (el3_device_remove)
}
};
#endif
#ifdef CONFIG_MCA
struct el3_mca_adapters_struct {
char* name;
int id;
static int el3_mca_probe(struct device *dev);
static short el3_mca_adapter_ids[] __initdata = {
0x627c,
0x627d,
0x62db,
0x62f6,
0x62f7,
0x0000
};
static char *el3_mca_adapter_names[] __initdata = {
"3Com 3c529 EtherLink III (10base2)",
"3Com 3c529 EtherLink III (10baseT)",
"3Com 3c529 EtherLink III (test mode)",
"3Com 3c529 EtherLink III (TP or coax)",
"3Com 3c529 EtherLink III (TP)",
NULL
};
static struct el3_mca_adapters_struct el3_mca_adapters[] __initdata = {
{ "3Com 3c529 EtherLink III (10base2)", 0x627c },
{ "3Com 3c529 EtherLink III (10baseT)", 0x627d },
{ "3Com 3c529 EtherLink III (test mode)", 0x62db },
{ "3Com 3c529 EtherLink III (TP or coax)", 0x62f6 },
{ "3Com 3c529 EtherLink III (TP)", 0x62f7 },
{ NULL, 0 },
static struct mca_driver el3_mca_driver = {
.id_table = el3_mca_adapter_ids,
.driver = {
.name = "3c529",
.bus = &mca_bus_type,
.probe = el3_mca_probe,
.remove = __devexit_p(el3_device_remove),
},
};
#endif /* CONFIG_MCA */
......@@ -264,12 +284,12 @@ static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
};
static u16 el3_isapnp_phys_addr[8][3];
#endif /* __ISAPNP__ */
static int nopnp;
#endif /* __ISAPNP__ */
/* With the driver model introduction for EISA devices, both init
* and cleanup have been split :
* - EISA devices probe/remove starts in el3_eisa_probe/el3_eisa_remove
* - EISA devices probe/remove starts in el3_eisa_probe/el3_device_remove
* - MCA/ISA still use el3_probe
*
* Both call el3_common_init/el3_common_remove. */
......@@ -279,9 +299,8 @@ static int __init el3_common_init (struct net_device *dev)
struct el3_private *lp = dev->priv;
short i;
#ifdef CONFIG_EISA
if (!lp->edev) /* EISA devices are not chained */
#endif
el3_cards++;
if (!lp->dev) /* probed devices are not chained */
{
lp->next_dev = el3_root_dev;
el3_root_dev = dev;
......@@ -337,17 +356,13 @@ static void el3_common_remove (struct net_device *dev)
struct el3_private *lp = dev->priv;
(void) lp; /* Keep gcc quiet... */
#ifdef CONFIG_MCA
if(lp->mca_slot!=-1)
mca_mark_as_unused(lp->mca_slot);
#endif
#ifdef CONFIG_PM
if (lp->pmdev)
pm_unregister(lp->pmdev);
#endif
#ifdef __ISAPNP__
if (lp->pnpdev)
pnp_device_detach(lp->pnpdev);
if (lp->type == EL3_PNP)
pnp_device_detach(to_pnp_dev(lp->dev));
#endif
unregister_netdev (dev);
......@@ -363,76 +378,11 @@ static int __init el3_probe(int card_idx)
int ioaddr, irq, if_port;
u16 phys_addr[3];
static int current_tag;
int mca_slot = -1;
#ifdef __ISAPNP__
static int pnp_cards;
struct pnp_dev *idev = NULL;
#endif /* __ISAPNP__ */
#ifdef CONFIG_MCA
/* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch, heavily
* modified by Chris Beauregard (cpbeaure@csclub.uwaterloo.ca)
* to support standard MCA probing.
*
* redone for multi-card detection by ZP Gu (zpg@castle.net)
* now works as a module
*/
if( MCA_bus ) {
int slot, j;
u_char pos4, pos5;
for( j = 0; el3_mca_adapters[j].name != NULL; j ++ ) {
slot = 0;
while( slot != MCA_NOTFOUND ) {
slot = mca_find_unused_adapter(
el3_mca_adapters[j].id, slot );
if( slot == MCA_NOTFOUND ) break;
/* if we get this far, an adapter has been
* detected and is enabled
*/
pos4 = mca_read_stored_pos( slot, 4 );
pos5 = mca_read_stored_pos( slot, 5 );
ioaddr = ((short)((pos4&0xfc)|0x02)) << 8;
irq = pos5 & 0x0f;
/* probing for a card at a particular IO/IRQ */
if(dev && ((dev->irq >= 1 && dev->irq != irq) ||
(dev->base_addr >= 1 && dev->base_addr != ioaddr))) {
slot++; /* probing next slot */
continue;
}
printk("3c509: found %s at slot %d\n",
el3_mca_adapters[j].name, slot + 1 );
/* claim the slot */
mca_set_adapter_name(slot, el3_mca_adapters[j].name);
mca_set_adapter_procfn(slot, NULL, NULL);
mca_mark_as_used(slot);
if_port = pos4 & 0x03;
if (el3_debug > 2) {
printk("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port);
}
EL3WINDOW(0);
for (i = 0; i < 3; i++) {
phys_addr[i] = htons(read_eeprom(ioaddr, i));
}
mca_slot = slot;
goto found;
}
}
/* if we get here, we didn't find an MCA adapter */
return -ENODEV;
}
#endif /* CONFIG_MCA */
#ifdef __ISAPNP__
if (nopnp == 1)
goto no_pnp;
......@@ -580,7 +530,7 @@ static int __init el3_probe(int card_idx)
/* Free the interrupt so that some other card can use it. */
outw(0x0f00, ioaddr + WN0_IRQ);
found:
dev = init_etherdev(NULL, sizeof(struct el3_private));
if (dev == NULL) {
release_region(ioaddr, EL3_IO_EXTENT);
......@@ -594,13 +544,80 @@ static int __init el3_probe(int card_idx)
dev->if_port = if_port;
lp = dev->priv;
#ifdef __ISAPNP__
lp->pnpdev = idev;
lp->dev = &idev->dev;
#endif
lp->mca_slot = mca_slot;
return el3_common_init (dev);
}
#ifdef CONFIG_MCA
static int __init el3_mca_probe(struct device *device) {
/* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch,
* heavily modified by Chris Beauregard
* (cpbeaure@csclub.uwaterloo.ca) to support standard MCA
* probing.
*
* redone for multi-card detection by ZP Gu (zpg@castle.net)
* now works as a module */
struct el3_private *lp;
short i;
int ioaddr, irq, if_port;
u16 phys_addr[3];
struct net_device *dev = NULL;
u_char pos4, pos5;
struct mca_device *mdev = to_mca_device(device);
int slot = mdev->slot;
pos4 = mca_device_read_stored_pos(mdev, 4);
pos5 = mca_device_read_stored_pos(mdev, 5);
ioaddr = ((short)((pos4&0xfc)|0x02)) << 8;
irq = pos5 & 0x0f;
printk("3c529: found %s at slot %d\n",
el3_mca_adapter_names[mdev->index], slot + 1);
/* claim the slot */
strncpy(device->name, el3_mca_adapter_names[mdev->index],
sizeof(device->name));
mca_device_set_claim(mdev, 1);
if_port = pos4 & 0x03;
irq = mca_device_transform_irq(mdev, irq);
ioaddr = mca_device_transform_ioport(mdev, ioaddr);
if (el3_debug > 2) {
printk("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port);
}
EL3WINDOW(0);
for (i = 0; i < 3; i++) {
phys_addr[i] = htons(read_eeprom(ioaddr, i));
}
dev = init_etherdev(NULL, sizeof(struct el3_private));
if (dev == NULL) {
release_region(ioaddr, EL3_IO_EXTENT);
return -ENOMEM;
}
SET_MODULE_OWNER(dev);
memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
dev->base_addr = ioaddr;
dev->irq = irq;
dev->if_port = if_port;
lp = dev->priv;
lp->dev = device;
lp->type = EL3_MCA;
device->driver_data = dev;
return el3_common_init (dev);
}
#endif /* CONFIG_MCA */
#ifdef CONFIG_EISA
static int __init el3_eisa_probe (struct device *device)
{
......@@ -642,25 +659,26 @@ static int __init el3_eisa_probe (struct device *device)
dev->irq = irq;
dev->if_port = if_port;
lp = dev->priv;
lp->mca_slot = -1;
lp->edev = edev;
lp->dev = device;
lp->type = EL3_EISA;
eisa_set_drvdata (edev, dev);
return el3_common_init (dev);
}
#endif
static int __devexit el3_eisa_remove (struct device *device)
/* This remove works for all device types.
*
* The net dev must be stored in the driver_data field */
static int __devexit el3_device_remove (struct device *device)
{
struct eisa_device *edev;
struct net_device *dev;
edev = to_eisa_device (device);
dev = eisa_get_drvdata (edev);
dev = device->driver_data;
el3_common_remove (dev);
return 0;
}
#endif
/* Read a word from the EEPROM using the regular EEPROM access register.
Assume that we are in register window zero.
......@@ -1080,7 +1098,7 @@ el3_close(struct net_device *dev)
free_irq(dev->irq, dev);
/* Switching back to window 0 disables the IRQ. */
EL3WINDOW(0);
if (!lp->edev) {
if (lp->type != EL3_EISA) {
/* But we explicitly zero the IRQ line select anyway. Don't do
* it on EISA cards, it prevents the module from getting an
* IRQ after unload+reload... */
......@@ -1530,7 +1548,7 @@ MODULE_LICENSE("GPL");
static int __init el3_init_module(void)
{
int el3_cards = 0;
el3_cards = 0;
if (debug >= 0)
el3_debug = debug;
......@@ -1548,8 +1566,9 @@ static int __init el3_init_module(void)
if (eisa_driver_register (&el3_eisa_driver) < 0) {
eisa_driver_unregister (&el3_eisa_driver);
}
else
el3_cards++; /* Found an eisa card */
#endif
#ifdef CONFIG_MCA
mca_register_driver(&el3_mca_driver);
#endif
return el3_cards ? 0 : -ENODEV;
}
......@@ -1569,6 +1588,9 @@ static void __exit el3_cleanup_module(void)
#ifdef CONFIG_EISA
eisa_driver_unregister (&el3_eisa_driver);
#endif
#ifdef CONFIG_MCA
mca_unregister_driver(&el3_mca_driver);
#endif
}
module_init (el3_init_module);
......
......@@ -224,6 +224,9 @@ static struct devprobe isa_probes[] __initdata = {
#ifdef CONFIG_EL2 /* 3c503 */
{el2_probe, 0},
#endif
#ifdef CONFIG_EL3
{el3_probe, 0},
#endif
#ifdef CONFIG_HPLAN
{hp_probe, 0},
#endif
......
......@@ -4,5 +4,5 @@
obj-$(CONFIG_E100) += e100.o
e100-objs := e100_main.o e100_config.o e100_proc.o e100_phy.o \
e100-objs := e100_main.o e100_config.o e100_phy.o \
e100_eeprom.o e100_test.o
......@@ -56,7 +56,6 @@
#include <linux/if.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/ip.h>
#define E100_REGS_LEN 1
......@@ -926,20 +925,7 @@ struct e100_private {
struct cfg_params params; /* adapter's command line parameters */
struct proc_dir_entry *proc_parent;
char *id_string;
char *cable_status;
char *mdix_status;
/* Variables for HWI */
int saved_open_circut;
int saved_short_circut;
int saved_distance;
int saved_i;
int saved_same;
unsigned char hwi_started;
struct timer_list hwi_timer; /* hwi timer id */
u32 speed_duplex_caps; /* adapter's speed/duplex capabilities */
......
......@@ -83,13 +83,15 @@
#include "e100_phy.h"
#include "e100_vendor.h"
#ifdef CONFIG_PROC_FS
extern int e100_create_proc_subdir(struct e100_private *, char *);
extern void e100_remove_proc_subdir(struct e100_private *, char *);
#else
#define e100_create_proc_subdir(X, Y) 0
#define e100_remove_proc_subdir(X, Y) do {} while(0)
#endif
static char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
"rx_length_errors", "rx_over_errors", "rx_crc_errors",
"rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
"tx_heartbeat_errors", "tx_window_errors",
};
#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN
static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *);
static void e100_get_speed_duplex_caps(struct e100_private *);
......@@ -135,7 +137,7 @@ static void e100_non_tx_background(unsigned long);
/* Global Data structures and variables */
char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
char e100_driver_version[]="2.1.29-k1";
char e100_driver_version[]="2.1.29-k4";
const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
char e100_short_driver_name[] = "e100";
static int e100nics = 0;
......@@ -150,15 +152,6 @@ struct notifier_block e100_notifier_reboot = {
.priority = 0
};
#endif
static int e100_notify_netdev(struct notifier_block *, unsigned long event, void *ptr);
struct notifier_block e100_notifier_netdev = {
.notifier_call = e100_notify_netdev,
.next = NULL,
.priority = 0
};
static void e100_get_mdix_status(struct e100_private *bdp);
/*********************************************************************/
/*! This is a GCC extension to ANSI C.
......@@ -196,6 +189,7 @@ void e100_set_speed_duplex(struct e100_private *);
char *e100_get_brand_msg(struct e100_private *);
static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
static u8 e100_sw_init(struct e100_private *);
static void e100_tco_workaround(struct e100_private *);
static unsigned char e100_alloc_space(struct e100_private *);
static void e100_dealloc_space(struct e100_private *);
static int e100_alloc_tcb_pool(struct e100_private *);
......@@ -213,7 +207,7 @@ u16 e100_eeprom_calculate_chksum(struct e100_private *adapter);
static unsigned char e100_clr_cntrs(struct e100_private *);
static unsigned char e100_load_microcode(struct e100_private *);
static unsigned char e100_hw_init(struct e100_private *, u32);
static unsigned char e100_hw_init(struct e100_private *);
static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *);
static unsigned char e100_update_stats(struct e100_private *bdp);
......@@ -349,8 +343,6 @@ void e100_tx_srv(struct e100_private *);
u32 e100_rx_srv(struct e100_private *);
void e100_watchdog(struct net_device *);
static void e100_do_hwi(struct net_device *);
static void e100_hwi_restore(struct e100_private *);
void e100_refresh_txthld(struct e100_private *);
void e100_manage_adaptive_ifs(struct e100_private *);
void e100_clear_pools(struct e100_private *);
......@@ -610,10 +602,6 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
bdp->watchdog_timer.data = (unsigned long) dev;
bdp->watchdog_timer.function = (void *) &e100_watchdog;
init_timer(&bdp->hwi_timer);
bdp->hwi_timer.data = (unsigned long) dev;
bdp->hwi_timer.function = (void *) &e100_do_hwi;
if ((rc = e100_pci_setup(pcid, bdp)) != 0) {
goto err_dealloc;
}
......@@ -686,21 +674,6 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
bdp->device->name, e100_get_brand_msg(bdp));
e100_print_brd_conf(bdp);
bdp->id_string = e100_get_brand_msg(bdp);
e100_get_mdix_status(bdp);
if (netif_carrier_ok(bdp->device))
bdp->cable_status = "Cable OK";
else {
if (bdp->rev_id < D102_REV_ID)
bdp->cable_status = "Not supported";
else
bdp->cable_status = "Not available";
}
if (e100_create_proc_subdir(bdp, bdp->ifname) < 0) {
printk(KERN_ERR "e100: Failed to create proc dir for %s\n",
bdp->device->name);
}
bdp->wolsupported = 0;
bdp->wolopts = 0;
......@@ -766,8 +739,6 @@ e100_remove1(struct pci_dev *pcid)
unregister_netdev(dev);
e100_remove_proc_subdir(bdp, bdp->ifname);
e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
......@@ -804,7 +775,6 @@ e100_init_module(void)
#ifdef CONFIG_PM
register_reboot_notifier(&e100_notifier_reboot);
#endif
register_netdevice_notifier(&e100_notifier_netdev);
}
return ret;
......@@ -816,7 +786,6 @@ e100_cleanup_module(void)
#ifdef CONFIG_PM
unregister_reboot_notifier(&e100_notifier_reboot);
#endif
unregister_netdevice_notifier(&e100_notifier_netdev);
pci_unregister_driver(&e100_driver);
}
......@@ -1265,7 +1234,7 @@ e100_init(struct e100_private *bdp)
/* read NIC's part number */
e100_rd_pwa_no(bdp);
if (!e100_hw_init(bdp, PORT_SOFTWARE_RESET)) {
if (!e100_hw_init(bdp)) {
printk(KERN_ERR "e100: hw init failed\n");
return false;
}
......@@ -1314,10 +1283,46 @@ e100_sw_init(struct e100_private *bdp)
return 1;
}
static void __devinit
e100_tco_workaround(struct e100_private *bdp)
{
int i;
/* Do software reset */
e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
/* Do a dummy LOAD CU BASE command. */
/* This gets us out of pre-driver to post-driver. */
e100_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE);
/* Wait 20 msec for reset to take effect */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ / 50 + 1);
/* disable interrupts since they are enabled */
/* after device reset */
e100_disable_clear_intr(bdp);
/* Wait for command to be cleared up to 1 sec */
for (i=0; i<100; i++) {
if (!readb(&bdp->scb->scb_cmd_low))
break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ / 100 + 1);
}
/* Wait for TCO request bit in PMDR register to be clear */
for (i=0; i<50; i++) {
if (!(readb(&bdp->scb->scb_ext.d101m_scb.scb_pmdr) & BIT_1))
break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ / 100 + 1);
}
}
/**
* e100_hw_init - initialized tthe hardware
* @bdp: atapter's private data struct
* @reset_cmd: s/w reset or selective reset
*
* This routine performs a reset on the adapter, and configures the adapter.
* This includes configuring the 82557 LAN controller, validating and setting
......@@ -1329,13 +1334,16 @@ e100_sw_init(struct e100_private *bdp)
* false - If the adapter failed initialization
*/
unsigned char __devinit
e100_hw_init(struct e100_private *bdp, u32 reset_cmd)
e100_hw_init(struct e100_private *bdp)
{
if (!e100_phy_init(bdp))
return false;
/* Issue a software reset to the e100 */
e100_sw_reset(bdp, reset_cmd);
e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
/* Only 82559 or above needs TCO workaround */
if (bdp->rev_id >= D101MA_REV_ID)
e100_tco_workaround(bdp);
/* Load the CU BASE (set to 0, because we use linear mode) */
if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
......@@ -1391,6 +1399,7 @@ e100_setup_tcb_pool(tcb_t *head, unsigned int qlen, struct e100_private *bdp)
u32 next_phys; /* the next phys addr */
u16 txcommand = CB_S_BIT | CB_TX_SF_BIT;
bdp->tx_count = 0;
if (bdp->flags & USE_IPCB) {
txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT;
} else if (bdp->flags & IS_BACHELOR) {
......@@ -1634,7 +1643,6 @@ e100_watchdog(struct net_device *dev)
if (!netif_running(dev)) {
return;
}
e100_get_mdix_status(bdp);
/* check if link state has changed */
if (e100_phy_check(bdp)) {
......@@ -1647,37 +1655,10 @@ e100_watchdog(struct net_device *dev)
e100_config_fc(bdp);
e100_config(bdp);
bdp->cable_status = "Cable OK";
} else {
printk(KERN_ERR "e100: %s NIC Link is Down\n",
bdp->device->name);
if (bdp->rev_id < D102_REV_ID)
bdp->cable_status = "Not supported";
else {
/* Initiate hwi, ie, cable diagnostic */
bdp->saved_open_circut = 0xffff;
bdp->saved_short_circut = 0xffff;
bdp->saved_distance = 0xffff;
bdp->saved_i = 0;
bdp->saved_same = 0;
bdp->hwi_started = 1;
/* Disable MDI/MDI-X auto switching */
e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
MDI_MDIX_RESET_ALL_MASK);
/* Set to 100 Full as required by hwi test */
e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
BMCR_SPEED100 | BMCR_FULLDPLX);
/* Enable and execute HWI test */
e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
(HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
/* Launch hwi timer in 1 msec */
mod_timer(&(bdp->hwi_timer), jiffies + (HZ / 1000) );
}
}
}
......@@ -1836,10 +1817,8 @@ e100intr(int irq, void *dev_inst, struct pt_regs *regs)
bdp->drv_stats.rx_intr_pkts += e100_rx_srv(bdp);
/* clean up after tx'ed packets */
if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) {
bdp->tx_count = 0; /* restart tx interrupt batch count */
if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX))
e100_tx_srv(bdp);
}
e100_set_intr_mask(bdp);
}
......@@ -2147,11 +2126,12 @@ e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb)
tcb->tcb_thrshld = bdp->tx_thld;
tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT);
/* set the I bit on the modulo tcbs, so we will get an interrupt * to
* clean things up */
if (!(++bdp->tx_count % TX_FRAME_CNT)) {
/* Set I (Interrupt) bit on every (TX_FRAME_CNT)th packet */
if (!(++bdp->tx_count % TX_FRAME_CNT))
tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT);
}
else
/* Clear I bit on other packets */
tcb->tcb_hdr.cb_cmd &= ~__constant_cpu_to_le16(CB_I_BIT);
tcb->tcb_skb = skb;
......@@ -3054,12 +3034,6 @@ e100_isolate_driver(struct e100_private *bdp)
if (bdp->device->flags & IFF_UP) {
e100_disable_clear_intr(bdp);
del_timer_sync(&bdp->watchdog_timer);
del_timer_sync(&bdp->hwi_timer);
/* If in middle of cable diag, */
if (bdp->hwi_started) {
bdp->hwi_started = 0;
e100_hwi_restore(bdp);
}
netif_carrier_off(bdp->device);
netif_stop_queue(bdp->device);
bdp->last_tcb = NULL;
......@@ -3205,6 +3179,22 @@ e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
case ETHTOOL_SEEPROM:
rc = e100_ethtool_eeprom(dev, ifr);
break;
case ETHTOOL_GSTATS: {
struct {
struct ethtool_stats cmd;
uint64_t data[E100_STATS_LEN];
} stats = { {ETHTOOL_GSTATS, E100_STATS_LEN} };
struct e100_private *bdp = dev->priv;
void *addr = ifr->ifr_data;
int i;
for(i = 0; i < E100_STATS_LEN; i++)
stats.data[i] =
((unsigned long *)&bdp->drv_stats.net_stats)[i];
if(copy_to_user(addr, &stats, sizeof(stats)))
return -EFAULT;
return 0;
}
case ETHTOOL_GWOL:
case ETHTOOL_SWOL:
rc = e100_ethtool_wol(dev, ifr);
......@@ -3456,6 +3446,7 @@ e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
sizeof (info.fw_version) - 1);
strncpy(info.bus_info, bdp->pdev->slot_name,
sizeof (info.bus_info) - 1);
info.n_stats = E100_STATS_LEN;
info.regdump_len = E100_REGS_LEN * sizeof(u32);
info.eedump_len = (bdp->eeprom_size << 1);
info.testinfo_len = E100_MAX_TEST_RES;
......@@ -3816,6 +3807,19 @@ static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
test_strings[i]);
}
break;
case ETH_SS_STATS: {
char *strings = NULL;
void *addr = ifr->ifr_data;
info.len = E100_STATS_LEN;
strings = *e100_gstrings_stats;
if(copy_to_user(ifr->ifr_data, &info, sizeof(info)))
return -EFAULT;
addr += offsetof(struct ethtool_gstrings, data);
if(copy_to_user(addr, strings,
info.len * ETH_GSTRING_LEN))
return -EFAULT;
return 0;
}
default:
return -EOPNOTSUPP;
}
......@@ -4054,29 +4058,6 @@ e100_non_tx_background(unsigned long ptr)
spin_unlock_bh(&(bdp->bd_non_tx_lock));
}
int e100_notify_netdev(struct notifier_block *nb, unsigned long event, void *p)
{
struct e100_private *bdp;
struct net_device *netdev = p;
if(netdev == NULL)
return NOTIFY_DONE;
switch(event) {
case NETDEV_CHANGENAME:
if(netdev->open == e100_open) {
bdp = netdev->priv;
/* rename the proc nodes the easy way */
e100_remove_proc_subdir(bdp, bdp->ifname);
memcpy(bdp->ifname, netdev->name, IFNAMSIZ);
bdp->ifname[IFNAMSIZ-1] = 0;
e100_create_proc_subdir(bdp, bdp->ifname);
}
break;
}
return NOTIFY_DONE;
}
#ifdef CONFIG_PM
static int
e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
......@@ -4140,128 +4121,6 @@ e100_resume(struct pci_dev *pcid)
}
#endif /* CONFIG_PM */
static void
e100_get_mdix_status(struct e100_private *bdp)
{
if (bdp->rev_id < D102_REV_ID) {
if (netif_carrier_ok(bdp->device))
bdp->mdix_status = "MDI";
else
bdp->mdix_status = "None";
} else {
u16 ctrl_reg;
/* Read the MDIX control register */
e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &ctrl_reg);
if (ctrl_reg & MDI_MDIX_CONFIG_IS_OK) {
if (ctrl_reg & MDI_MDIX_STATUS)
bdp->mdix_status = "MDI-X";
else
bdp->mdix_status = "MDI";
} else
bdp->mdix_status = "None";
}
}
static void
e100_do_hwi(struct net_device *dev)
{
struct e100_private *bdp = dev->priv;
u16 ctrl_reg;
int distance, open_circut, short_circut;
e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg);
distance = ctrl_reg & HWI_TEST_DISTANCE;
open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM;
short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM;
if ((distance == bdp->saved_distance) &&
(open_circut == bdp->saved_open_circut) &&
(short_circut == bdp->saved_short_circut))
bdp->saved_same++;
else {
bdp->saved_same = 0;
bdp->saved_distance = distance;
bdp->saved_open_circut = open_circut;
bdp->saved_short_circut = short_circut;
}
if (bdp->saved_same == MAX_SAME_RESULTS) {
if ((open_circut && !(short_circut)) ||
(!(open_circut) && short_circut)) {
u8 near_end = ((distance * HWI_REGISTER_GRANULARITY) <
HWI_NEAR_END_BOUNDARY);
if (open_circut) {
if (near_end)
bdp->cable_status = "Open Circut Near End";
else
bdp->cable_status = "Open Circut Far End";
} else {
if (near_end)
bdp->cable_status = "Short Circut Near End";
else
bdp->cable_status = "Short Circut Far End";
}
goto done;
}
}
else if (bdp->saved_i == HWI_MAX_LOOP) {
bdp->cable_status = "Test failed";
goto done;
}
/* Do another hwi test */
e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
(HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
bdp->saved_i++;
/* relaunch hwi timer in 1 msec */
mod_timer(&(bdp->hwi_timer), jiffies + (HZ / 1000) );
return;
done:
e100_hwi_restore(bdp);
bdp->hwi_started = 0;
return;
}
static void e100_hwi_restore(struct e100_private *bdp)
{
u16 control = 0;
/* Restore speed, duplex and autoneg before */
/* hwi test, i.e., cable diagnostic */
/* Reset hwi test */
e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK);
if ((bdp->params.e100_speed_duplex == E100_AUTONEG) &&
(bdp->rev_id >= D102_REV_ID))
/* Enable MDI/MDI-X auto switching */
e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
MDI_MDIX_AUTO_SWITCH_ENABLE);
switch (bdp->params.e100_speed_duplex) {
case E100_SPEED_10_HALF:
break;
case E100_SPEED_10_FULL:
control = BMCR_FULLDPLX;
break;
case E100_SPEED_100_HALF:
control = BMCR_SPEED100;
break;
case E100_SPEED_100_FULL:
control = BMCR_SPEED100 | BMCR_FULLDPLX;
break;
case E100_AUTONEG:
control = BMCR_ANENABLE | BMCR_ANRESTART;
break;
}
/* Restore original speed/duplex */
e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
return;
}
#ifdef E100_CU_DEBUG
unsigned char
e100_cu_unknown_state(struct e100_private *bdp)
......
/*******************************************************************************
Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
The full GNU General Public License is included in this distribution in the
file called LICENSE.
Contact Information:
Linux NICS <linux.nics@intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
/**********************************************************************
* *
* INTEL CORPORATION *
* *
* This software is supplied under the terms of the license included *
* above. All use of this driver must be in accordance with the terms *
* of that license. *
* *
* Module Name: e100_proc.c *
* *
* Abstract: Functions to handle the proc file system. *
* Create the proc directories and files and run read and *
* write requests from the user *
* *
* Environment: This file is intended to be specific to the Linux *
* operating system. *
* *
**********************************************************************/
#include <linux/config.h>
#ifdef CONFIG_PROC_FS
#include "e100.h"
/* MDI sleep time is at least 50 ms, in jiffies */
#define MDI_SLEEP_TIME ((HZ / 20) + 1)
/***************************************************************************/
/* /proc File System Interaface Support Functions */
/***************************************************************************/
static struct proc_dir_entry *adapters_proc_dir = 0;
/* externs from e100_main.c */
extern char e100_short_driver_name[];
extern char e100_driver_version[];
extern struct net_device_stats *e100_get_stats(struct net_device *dev);
extern char *e100_get_brand_msg(struct e100_private *bdp);
extern int e100_mdi_write(struct e100_private *, u32, u32, u16);
static void e100_proc_cleanup(void);
static unsigned char e100_init_proc_dir(void);
#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters"
#define WRITE_BUF_MAX_LEN 20
#define READ_BUF_MAX_LEN 256
#define E100_PE_LEN 25
#define bdp_drv_off(off) (unsigned long)(offsetof(struct e100_private, drv_stats.off))
#define bdp_prm_off(off) (unsigned long)(offsetof(struct e100_private, params.off))
typedef struct _e100_proc_entry {
char *name;
read_proc_t *read_proc;
write_proc_t *write_proc;
unsigned long offset; /* offset into bdp. ~0 means no value, pass NULL. */
} e100_proc_entry;
static int
generic_read(char *page, char **start, off_t off, int count, int *eof, int len)
{
if (len <= off + count)
*eof = 1;
*start = page + off;
len -= off;
if (len > count)
len = count;
if (len < 0)
len = 0;
return len;
}
static int
read_ulong(char *page, char **start, off_t off,
int count, int *eof, unsigned long l)
{
int len;
len = sprintf(page, "%lu\n", l);
return generic_read(page, start, off, count, eof, len);
}
static int
read_gen_ulong(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
unsigned long val = 0;
if (data)
val = *((unsigned long *) data);
return read_ulong(page, start, off, count, eof, val);
}
static int
read_hwaddr(char *page, char **start, off_t off,
int count, int *eof, unsigned char *hwaddr)
{
int len;
len = sprintf(page, "%02X:%02X:%02X:%02X:%02X:%02X\n",
hwaddr[0], hwaddr[1], hwaddr[2],
hwaddr[3], hwaddr[4], hwaddr[5]);
return generic_read(page, start, off, count, eof, len);
}
static int
read_descr(char *page, char **start, off_t off, int count, int *eof, void *data)
{
struct e100_private *bdp = data;
int len;
len = sprintf(page, "%s\n", bdp->id_string);
return generic_read(page, start, off, count, eof, len);
}
static int
read_permanent_hwaddr(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
struct e100_private *bdp = data;
unsigned char *hwaddr = bdp->perm_node_address;
return read_hwaddr(page, start, off, count, eof, hwaddr);
}
static int
read_part_number(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
struct e100_private *bdp = data;
int len;
len = sprintf(page, "%06lx-%03x\n",
(unsigned long) (bdp->pwa_no >> 8),
(unsigned int) (bdp->pwa_no & 0xFF));
return generic_read(page, start, off, count, eof, len);
}
static void
set_led(struct e100_private *bdp, u16 led_mdi_op)
{
e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
bdp->phy_addr, led_mdi_op);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(MDI_SLEEP_TIME);
/* turn led ownership to the chip */
e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
bdp->phy_addr, PHY_82555_LED_NORMAL_CONTROL);
}
static int
write_blink_led_timer(struct file *file, const char *buffer,
unsigned long count, void *data)
{
struct e100_private *bdp = data;
char s_blink_op[WRITE_BUF_MAX_LEN + 1];
char *res;
unsigned long i_blink_op;
if (!buffer)
return -EINVAL;
if (count > WRITE_BUF_MAX_LEN) {
count = WRITE_BUF_MAX_LEN;
}
if (copy_from_user(s_blink_op, buffer, count))
return -EFAULT;
s_blink_op[count] = '\0';
i_blink_op = simple_strtoul(s_blink_op, &res, 0);
if (res == s_blink_op) {
return -EINVAL;
}
switch (i_blink_op) {
case LED_OFF:
set_led(bdp, PHY_82555_LED_OFF);
break;
case LED_ON:
if (bdp->rev_id >= D101MA_REV_ID)
set_led(bdp, PHY_82555_LED_ON_559);
else
set_led(bdp, PHY_82555_LED_ON_PRE_559);
break;
default:
return -EINVAL;
}
return count;
}
static e100_proc_entry e100_proc_list[] = {
{"Description", read_descr, 0, 0},
{"Permanent_HWaddr", read_permanent_hwaddr, 0, 0},
{"Part_Number", read_part_number, 0, 0},
{"\n",},
{"Rx_TCP_Checksum_Good", read_gen_ulong, 0, ~0},
{"Rx_TCP_Checksum_Bad", read_gen_ulong, 0, ~0},
{"Tx_TCP_Checksum_Good", read_gen_ulong, 0, ~0},
{"Tx_TCP_Checksum_Bad", read_gen_ulong, 0, ~0},
{"\n",},
{"Tx_Abort_Late_Coll", read_gen_ulong, 0, bdp_drv_off(tx_late_col)},
{"Tx_Deferred_Ok", read_gen_ulong, 0, bdp_drv_off(tx_ok_defrd)},
{"Tx_Single_Coll_Ok", read_gen_ulong, 0, bdp_drv_off(tx_one_retry)},
{"Tx_Multi_Coll_Ok", read_gen_ulong, 0, bdp_drv_off(tx_mt_one_retry)},
{"Rx_Long_Length_Errors", read_gen_ulong, 0, ~0},
{"\n",},
{"Tx_Flow_Control_Pause", read_gen_ulong, 0, bdp_drv_off(xmt_fc_pkts)},
{"Rx_Flow_Control_Pause", read_gen_ulong, 0, bdp_drv_off(rcv_fc_pkts)},
{"Rx_Flow_Control_Unsup", read_gen_ulong, 0, bdp_drv_off(rcv_fc_unsupported)},
{"\n",},
{"Tx_TCO_Packets", read_gen_ulong, 0, bdp_drv_off(xmt_tco_pkts)},
{"Rx_TCO_Packets", read_gen_ulong, 0, bdp_drv_off(rcv_tco_pkts)},
{"\n",},
{"Rx_Interrupt_Packets", read_gen_ulong, 0, bdp_drv_off(rx_intr_pkts)},
{"Identify_Adapter", 0, write_blink_led_timer, 0},
{"", 0, 0, 0}
};
static int
read_info(char *page, char **start, off_t off, int count, int *eof, void *data)
{
struct e100_private *bdp = data;
e100_proc_entry *pe;
int tmp;
void *val;
int len = 0;
for (pe = e100_proc_list; pe->name[0]; pe++) {
if (pe->name[0] == '\n') {
len += sprintf(page + len, "\n");
continue;
}
if (pe->read_proc) {
if ((len + READ_BUF_MAX_LEN + E100_PE_LEN + 1) >=
PAGE_SIZE)
break;
if (pe->offset != ~0)
val = ((char *) bdp) + pe->offset;
else
val = NULL;
len += sprintf(page + len, "%-"
__MODULE_STRING(E100_PE_LEN)
"s ", pe->name);
len += pe->read_proc(page + len, start, 0,
READ_BUF_MAX_LEN + 1, &tmp, val);
}
}
return generic_read(page, start, off, count, eof, len);
}
static struct proc_dir_entry *
create_proc_rw(char *name, void *data, struct proc_dir_entry *parent,
read_proc_t * read_proc, write_proc_t * write_proc)
{
struct proc_dir_entry *pdep;
mode_t mode = S_IFREG;
if (write_proc) {
mode |= S_IWUSR;
if (read_proc) {
mode |= S_IRUSR;
}
} else if (read_proc) {
mode |= S_IRUGO;
}
if (!(pdep = create_proc_entry(name, mode, parent)))
return NULL;
pdep->read_proc = read_proc;
pdep->write_proc = write_proc;
pdep->data = data;
return pdep;
}
void
e100_remove_proc_subdir(struct e100_private *bdp, char *name)
{
e100_proc_entry *pe;
char info[256];
int len;
/* If our root /proc dir was not created, there is nothing to remove */
if (adapters_proc_dir == NULL) {
return;
}
len = strlen(bdp->ifname);
strncpy(info, bdp->ifname, sizeof (info));
strncat(info + len, ".info", sizeof (info) - len);
if (bdp->proc_parent) {
for (pe = e100_proc_list; pe->name[0]; pe++) {
if (pe->name[0] == '\n')
continue;
remove_proc_entry(pe->name, bdp->proc_parent);
}
remove_proc_entry(bdp->ifname, adapters_proc_dir);
bdp->proc_parent = NULL;
}
remove_proc_entry(info, adapters_proc_dir);
/* try to remove the main /proc dir, if it's empty */
e100_proc_cleanup();
}
int
e100_create_proc_subdir(struct e100_private *bdp)
{
struct proc_dir_entry *dev_dir;
e100_proc_entry *pe;
char info[256];
int len;
void *data;
/* create the main /proc dir if needed */
if (!adapters_proc_dir) {
if (!e100_init_proc_dir())
return -ENOMEM;
}
strncpy(info, bdp->ifname, sizeof (info));
len = strlen(info);
strncat(info + len, ".info", sizeof (info) - len);
/* info */
if (!(create_proc_rw(info, bdp, adapters_proc_dir, read_info, 0))) {
e100_proc_cleanup();
return -ENOMEM;
}
dev_dir = create_proc_entry(bdp->ifname, S_IFDIR,
adapters_proc_dir);
bdp->proc_parent = dev_dir;
if (!dev_dir) {
e100_remove_proc_subdir(bdp, bdp->ifname);
return -ENOMEM;
}
for (pe = e100_proc_list; pe->name[0]; pe++) {
if (pe->name[0] == '\n')
continue;
if (pe->offset != ~0)
data = ((char *) bdp) + pe->offset;
else
data = NULL;
if (!(create_proc_rw(pe->name, data, dev_dir,
pe->read_proc, pe->write_proc))) {
e100_remove_proc_subdir(bdp, bdp->ifname);
return -ENOMEM;
}
}
return 0;
}
/****************************************************************************
* Name: e100_init_proc_dir
*
* Description: This routine creates the top-level /proc directory for the
* driver in /proc/net
*
* Arguments: none
*
* Returns: true on success, false on fail
*
***************************************************************************/
static unsigned char
e100_init_proc_dir(void)
{
int len;
/* first check if adapters_proc_dir already exists */
len = strlen(ADAPTERS_PROC_DIR);
for (adapters_proc_dir = proc_net->subdir;
adapters_proc_dir; adapters_proc_dir = adapters_proc_dir->next) {
if ((adapters_proc_dir->namelen == len) &&
(!memcmp(adapters_proc_dir->name, ADAPTERS_PROC_DIR, len)))
break;
}
if (!adapters_proc_dir)
adapters_proc_dir =
create_proc_entry(ADAPTERS_PROC_DIR, S_IFDIR, proc_net);
if (!adapters_proc_dir)
return false;
return true;
}
/****************************************************************************
* Name: e100_proc_cleanup
*
* Description: This routine clears the top-level /proc directory, if empty.
*
* Arguments: none
*
* Returns: none
*
***************************************************************************/
static void
e100_proc_cleanup(void)
{
struct proc_dir_entry *de;
if (adapters_proc_dir == NULL) {
return;
}
/* check if subdir list is empty before removing adapters_proc_dir */
for (de = adapters_proc_dir->subdir; de; de = de->next) {
/* ignore . and .. */
if (*(de->name) != '.')
break;
}
if (de)
return;
remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
adapters_proc_dir = NULL;
}
#endif /* CONFIG_PROC_FS */
......@@ -32,5 +32,4 @@
obj-$(CONFIG_E1000) += e1000.o
e1000-objs := e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o \
e1000_proc.o
e1000-objs := e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o
......@@ -157,9 +157,6 @@ struct e1000_desc_ring {
struct e1000_adapter {
struct timer_list watchdog_timer;
struct timer_list phy_info_timer;
#ifdef CONFIG_PROC_FS
struct list_head proc_list_head;
#endif
struct vlan_group *vlgrp;
char *id_string;
uint32_t bd_number;
......
......@@ -39,6 +39,16 @@ extern int e1000_up(struct e1000_adapter *adapter);
extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reset(struct e1000_adapter *adapter);
static char e1000_gstrings_stats[][ETH_GSTRING_LEN] = {
"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
"rx_length_errors", "rx_over_errors", "rx_crc_errors",
"rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
"tx_heartbeat_errors", "tx_window_errors",
};
#define E1000_STATS_LEN sizeof(e1000_gstrings_stats) / ETH_GSTRING_LEN
static void
e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
{
......@@ -173,6 +183,7 @@ e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
strncpy(drvinfo->version, e1000_driver_version, 32);
strncpy(drvinfo->fw_version, "N/A", 32);
strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
drvinfo->n_stats = E1000_STATS_LEN;
#define E1000_REGS_LEN 32
drvinfo->regdump_len = E1000_REGS_LEN * sizeof(uint32_t);
drvinfo->eedump_len = e1000_eeprom_size(&adapter->hw);
......@@ -209,17 +220,23 @@ e1000_ethtool_geeprom(struct e1000_adapter *adapter,
struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
{
struct e1000_hw *hw = &adapter->hw;
int i, max_len, first_word, last_word;
int max_len, first_word, last_word;
int ret_val = 0;
int i;
if(eeprom->len == 0)
return -EINVAL;
if(eeprom->len == 0) {
ret_val = -EINVAL;
goto geeprom_error;
}
eeprom->magic = hw->vendor_id | (hw->device_id << 16);
max_len = e1000_eeprom_size(hw);
if(eeprom->offset > eeprom->offset + eeprom->len)
return -EINVAL;
if(eeprom->offset > eeprom->offset + eeprom->len) {
ret_val = -EINVAL;
goto geeprom_error;
}
if((eeprom->offset + eeprom->len) > max_len)
eeprom->len = (max_len - eeprom->offset);
......@@ -230,7 +247,8 @@ e1000_ethtool_geeprom(struct e1000_adapter *adapter,
for(i = 0; i <= (last_word - first_word); i++)
e1000_read_eeprom(hw, first_word + i, &eeprom_buff[i]);
return 0;
geeprom_error:
return ret_val;
}
static int
......@@ -238,9 +256,10 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter,
struct ethtool_eeprom *eeprom, void *user_data)
{
struct e1000_hw *hw = &adapter->hw;
uint16_t eeprom_buff[256];
int i, max_len, first_word, last_word;
uint16_t *eeprom_buff;
int max_len, first_word, last_word;
void *ptr;
int i;
if(eeprom->len == 0)
return -EOPNOTSUPP;
......@@ -255,6 +274,10 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter,
first_word = eeprom->offset >> 1;
last_word = (eeprom->offset + eeprom->len - 1) >> 1;
eeprom_buff = kmalloc(max_len, GFP_KERNEL);
if(eeprom_buff == NULL)
return -ENOMEM;
ptr = (void *)eeprom_buff;
if(eeprom->offset & 1) {
......@@ -269,8 +292,10 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter,
e1000_read_eeprom(hw, last_word,
&eeprom_buff[last_word - first_word]);
}
if(copy_from_user(ptr, user_data, eeprom->len))
if(copy_from_user(ptr, user_data, eeprom->len)) {
kfree(eeprom_buff);
return -EFAULT;
}
for(i = 0; i <= (last_word - first_word); i++)
e1000_write_eeprom(hw, first_word + i, eeprom_buff[i]);
......@@ -279,6 +304,8 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter,
if(first_word <= EEPROM_CHECKSUM_REG)
e1000_update_eeprom_checksum(hw);
kfree(eeprom_buff);
return 0;
}
......@@ -438,6 +465,28 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
return -EFAULT;
return 0;
}
case ETHTOOL_GSTRINGS: {
struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS };
char *strings = NULL;
if(copy_from_user(&gstrings, addr, sizeof(gstrings)))
return -EFAULT;
switch(gstrings.string_set) {
case ETH_SS_STATS:
gstrings.len = E1000_STATS_LEN;
strings = *e1000_gstrings_stats;
break;
default:
return -EOPNOTSUPP;
}
if(copy_to_user(addr, &gstrings, sizeof(gstrings)))
return -EFAULT;
addr += offsetof(struct ethtool_gstrings, data);
if(copy_to_user(addr, strings,
gstrings.len * ETH_GSTRING_LEN))
return -EFAULT;
return 0;
}
case ETHTOOL_GREGS: {
struct ethtool_regs regs = {ETHTOOL_GREGS};
uint32_t regs_buff[E1000_REGS_LEN];
......@@ -493,26 +542,40 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
}
case ETHTOOL_GEEPROM: {
struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM};
uint16_t eeprom_buff[256];
uint16_t *eeprom_buff;
void *ptr;
int err;
int max_len, err = 0;
if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
return -EFAULT;
max_len = e1000_eeprom_size(&adapter->hw);
if((err = e1000_ethtool_geeprom(adapter,
&eeprom, eeprom_buff)))
return err;
eeprom_buff = kmalloc(max_len, GFP_KERNEL);
if(copy_to_user(addr, &eeprom, sizeof(eeprom)))
return -EFAULT;
if(eeprom_buff == NULL)
return -ENOMEM;
if(copy_from_user(&eeprom, addr, sizeof(eeprom))) {
err = -EFAULT;
goto err_geeprom_ioctl;
}
if((err = e1000_ethtool_geeprom(adapter, &eeprom,
eeprom_buff)))
goto err_geeprom_ioctl;
if(copy_to_user(addr, &eeprom, sizeof(eeprom))) {
err = -EFAULT;
goto err_geeprom_ioctl;
}
addr += offsetof(struct ethtool_eeprom, data);
ptr = ((void *)eeprom_buff) + (eeprom.offset & 1);
if(copy_to_user(addr, ptr, eeprom.len))
return -EFAULT;
return 0;
err = -EFAULT;
err_geeprom_ioctl:
kfree(eeprom_buff);
return err;
}
case ETHTOOL_SEEPROM: {
struct ethtool_eeprom eeprom;
......@@ -526,6 +589,20 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
addr += offsetof(struct ethtool_eeprom, data);
return e1000_ethtool_seeprom(adapter, &eeprom, addr);
}
case ETHTOOL_GSTATS: {
struct {
struct ethtool_stats cmd;
uint64_t data[E1000_STATS_LEN];
} stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} };
int i;
for(i = 0; i < E1000_STATS_LEN; i++)
stats.data[i] =
((unsigned long *)&adapter->net_stats)[i];
if(copy_to_user(addr, &stats, sizeof(stats)))
return -EFAULT;
return 0;
}
default:
return -EOPNOTSUPP;
}
......
......@@ -59,7 +59,7 @@
char e1000_driver_name[] = "e1000";
char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
char e1000_driver_version[] = "4.4.19-k1";
char e1000_driver_version[] = "4.4.19-k3";
char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
......@@ -171,7 +171,6 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
static void e1000_restore_vlan(struct e1000_adapter *adapter);
static int e1000_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
static int e1000_notify_netdev(struct notifier_block *, unsigned long event, void *ptr);
static int e1000_suspend(struct pci_dev *pdev, uint32_t state);
#ifdef CONFIG_PM
static int e1000_resume(struct pci_dev *pdev);
......@@ -183,17 +182,9 @@ struct notifier_block e1000_notifier_reboot = {
.priority = 0
};
struct notifier_block e1000_notifier_netdev = {
.notifier_call = e1000_notify_netdev,
.next = NULL,
.priority = 0
};
/* Exported from other modules */
extern void e1000_check_options(struct e1000_adapter *adapter);
extern void e1000_proc_dev_setup(struct e1000_adapter *adapter);
extern void e1000_proc_dev_free(struct e1000_adapter *adapter);
extern int e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr);
static struct pci_driver e1000_driver = {
......@@ -229,10 +220,8 @@ e1000_init_module(void)
printk(KERN_INFO "%s\n", e1000_copyright);
ret = pci_module_init(&e1000_driver);
if(ret >= 0) {
if(ret >= 0)
register_reboot_notifier(&e1000_notifier_reboot);
register_netdevice_notifier(&e1000_notifier_netdev);
}
return ret;
}
......@@ -249,7 +238,6 @@ static void __exit
e1000_exit_module(void)
{
unregister_reboot_notifier(&e1000_notifier_reboot);
unregister_netdevice_notifier(&e1000_notifier_netdev);
pci_unregister_driver(&e1000_driver);
}
......@@ -433,10 +421,8 @@ e1000_probe(struct pci_dev *pdev,
netdev->features = NETIF_F_SG;
}
#ifdef NETIF_F_TSO
if(adapter->hw.mac_type >= e1000_82544)
netdev->features |= NETIF_F_TSO;
#endif
if(pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
......@@ -490,7 +476,6 @@ e1000_probe(struct pci_dev *pdev,
printk(KERN_INFO "%s: %s\n", netdev->name, adapter->id_string);
e1000_check_options(adapter);
e1000_proc_dev_setup(adapter);
/* Initial Wake on LAN setting
* If APM wake is enabled in the EEPROM,
......@@ -548,8 +533,6 @@ e1000_remove(struct pci_dev *pdev)
e1000_phy_hw_reset(&adapter->hw);
e1000_proc_dev_free(adapter);
iounmap(adapter->hw.hw_addr);
pci_release_regions(pdev);
......@@ -1314,7 +1297,6 @@ e1000_watchdog(unsigned long data)
static inline boolean_t
e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags)
{
#ifdef NETIF_F_TSO
struct e1000_context_desc *context_desc;
int i;
uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
......@@ -1358,7 +1340,6 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags)
return TRUE;
}
#endif
return FALSE;
}
......@@ -1398,6 +1379,8 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
{
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
int len, offset, size, count, i;
int tso = skb_shinfo(skb)->tso_size;
int nr_frags = skb_shinfo(skb)->nr_frags;
int f;
len = skb->len - skb->data_len;
......@@ -1409,6 +1392,10 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
while(len) {
i = (i + 1) % tx_ring->count;
size = min(len, adapter->max_data_per_txd);
/* Workaround for premature desc write-backs
* in TSO mode. Append 4-byte sentinel desc */
if(tso && !nr_frags && size == len && size > 4)
size -= 4;
tx_ring->buffer_info[i].length = size;
tx_ring->buffer_info[i].dma =
pci_map_single(adapter->pdev,
......@@ -1422,7 +1409,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
count++;
}
for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
for(f = 0; f < nr_frags; f++) {
struct skb_frag_struct *frag;
frag = &skb_shinfo(skb)->frags[f];
......@@ -1432,6 +1419,10 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
while(len) {
i = (i + 1) % tx_ring->count;
size = min(len, adapter->max_data_per_txd);
/* Workaround for premature desc write-backs
* in TSO mode. Append 4-byte sentinel desc */
if(tso && f == (nr_frags-1) && size == len && size > 4)
size -= 4;
tx_ring->buffer_info[i].length = size;
tx_ring->buffer_info[i].dma =
pci_map_page(adapter->pdev,
......@@ -1439,6 +1430,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
frag->page_offset + offset,
size,
PCI_DMA_TODEVICE);
tx_ring->buffer_info[i].time_stamp = jiffies;
len -= size;
offset += size;
......@@ -1520,13 +1512,8 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
for(f = 0; f < skb_shinfo(skb)->nr_frags; f++)
count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
adapter->max_data_per_txd);
#ifdef NETIF_F_TSO
if((skb_shinfo(skb)->tso_size) || (skb->ip_summed == CHECKSUM_HW))
count++;
#else
if(skb->ip_summed == CHECKSUM_HW)
count++;
#endif
if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) {
netif_stop_queue(netdev);
......@@ -1823,7 +1810,10 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
#ifdef CONFIG_E1000_NAPI
if (netif_rx_schedule_prep(netdev)) {
e1000_irq_disable(adapter);
/* Disable interrupts and enable polling */
atomic_inc(&adapter->irq_sem);
E1000_WRITE_REG(&adapter->hw, IMC, ~0);
E1000_WRITE_FLUSH(&adapter->hw);
__netif_rx_schedule(netdev);
}
#else
......@@ -2429,29 +2419,6 @@ e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
return NOTIFY_DONE;
}
static int
e1000_notify_netdev(struct notifier_block *nb, unsigned long event, void *p)
{
struct e1000_adapter *adapter;
struct net_device *netdev = p;
if(netdev == NULL)
return NOTIFY_DONE;
switch(event) {
case NETDEV_CHANGENAME:
if(netdev->open == e1000_open) {
adapter = netdev->priv;
/* rename the proc nodes the easy way */
e1000_proc_dev_free(adapter);
memcpy(adapter->ifname, netdev->name, IFNAMSIZ);
adapter->ifname[IFNAMSIZ-1] = 0;
e1000_proc_dev_setup(adapter);
}
break;
}
return NOTIFY_DONE;
}
static int
e1000_suspend(struct pci_dev *pdev, uint32_t state)
{
......
/*******************************************************************************
Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
The full GNU General Public License is included in this distribution in the
file called LICENSE.
Contact Information:
Linux NICS <linux.nics@intel.com>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
/*
* Proc fs support.
*
* Read-only files created by driver (if CONFIG_PROC_FS):
*
* /proc/net/PRO_LAN_Adapters/<ethx>.info
* /proc/net/PRO_LAN_Adapters/<ethx>/<attribute>
*
* where <ethx> is the system device name, i.e eth0.
* <attribute> is the driver attribute name.
*
* There is one file for each driver attribute, where the contents
* of the file is the attribute value. The ethx.info file contains
* a list of all driver attributes in one file.
*
*/
#include "e1000.h"
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters"
#define TAG_MAX_LENGTH 32
#define LINE_MAX_LENGTH 80
#define FIELD_MAX_LENGTH LINE_MAX_LENGTH - TAG_MAX_LENGTH - 3
extern char e1000_driver_name[];
extern char e1000_driver_version[];
/*
* The list of driver proc attributes is stored in a proc_list link
* list. The list is build with proc_list_setup and is used to
* build the proc fs nodes. The private data for each node is the
* corresponding link in the link list.
*/
struct proc_list {
struct list_head list; /* link list */
char tag[TAG_MAX_LENGTH + 1]; /* attribute name */
void *data; /* attribute data */
size_t len; /* sizeof data */
char *(*func)(void *, size_t, char *); /* format data func */
};
static int
e1000_proc_read(char *page, char **start, off_t off, int count, int *eof)
{
int len = strlen(page);
page[len++] = '\n';
if(len <= off + count)
*eof = 1;
*start = page + off;
len -= off;
if(len > count)
len = count;
if(len < 0)
len = 0;
return len;
}
static int
e1000_proc_info_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
struct list_head *proc_list_head = data, *curr;
struct proc_list *elem;
char *p = page;
char buf[FIELD_MAX_LENGTH + 1];
list_for_each(curr, proc_list_head) {
elem = list_entry(curr, struct proc_list, list);
if (p - page + LINE_MAX_LENGTH >= PAGE_SIZE)
break;
if(!strlen(elem->tag))
p += sprintf(p, "\n");
else
p += sprintf(p, "%-*.*s %.*s\n",
TAG_MAX_LENGTH, TAG_MAX_LENGTH,
elem->tag, FIELD_MAX_LENGTH,
elem->func(elem->data, elem->len, buf));
}
*p = '\0';
return e1000_proc_read(page, start, off, count, eof);
}
static int
e1000_proc_single_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
struct proc_list *elem = data;
sprintf(page, "%.*s", FIELD_MAX_LENGTH, elem->func(elem->data,
elem->len, page));
return e1000_proc_read(page, start, off, count, eof);
}
static void
e1000_proc_dirs_free(char *name, struct list_head *proc_list_head)
{
struct proc_dir_entry *intel_proc_dir, *proc_dir;
char info_name[strlen(name) + strlen(".info")];
for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
intel_proc_dir = intel_proc_dir->next) {
if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
!memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
break;
}
if(!intel_proc_dir)
return;
for(proc_dir = intel_proc_dir->subdir; proc_dir;
proc_dir = proc_dir->next) {
if ((proc_dir->namelen == strlen(name)) &&
!memcmp(proc_dir->name, name, strlen(name)))
break;
}
if(proc_dir) {
struct list_head *curr;
struct proc_list *elem;
list_for_each(curr, proc_list_head) {
elem = list_entry(curr, struct proc_list, list);
remove_proc_entry(elem->tag, proc_dir);
}
strcpy(info_name, name);
strcat(info_name, ".info");
remove_proc_entry(info_name, intel_proc_dir);
remove_proc_entry(name, intel_proc_dir);
}
/* If the intel dir is empty, remove it */
for(proc_dir = intel_proc_dir->subdir; proc_dir;
proc_dir = proc_dir->next) {
/* ignore . and .. */
if(*(proc_dir->name) == '.')
continue;
break;
}
if(!proc_dir)
remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
}
static int
e1000_proc_singles_create(struct proc_dir_entry *parent,
struct list_head *proc_list_head)
{
struct list_head *curr;
struct proc_list *elem;
list_for_each(curr, proc_list_head) {
struct proc_dir_entry *proc_entry;
elem = list_entry(curr, struct proc_list, list);
if(!strlen(elem->tag))
continue;
if(!(proc_entry =
create_proc_entry(elem->tag, S_IFREG, parent)))
return 0;
proc_entry->read_proc = e1000_proc_single_read;
proc_entry->data = elem;
SET_MODULE_OWNER(proc_entry);
}
return 1;
}
static void
e1000_proc_dirs_create(void *data, char *name,
struct list_head *proc_list_head)
{
struct proc_dir_entry *intel_proc_dir, *proc_dir, *info_entry;
char info_name[strlen(name) + strlen(".info")];
for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
intel_proc_dir = intel_proc_dir->next) {
if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
!memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
break;
}
if(!intel_proc_dir)
if(!(intel_proc_dir =
create_proc_entry(ADAPTERS_PROC_DIR,
S_IFDIR, proc_net)))
return;
if(!(proc_dir =
create_proc_entry(name, S_IFDIR, intel_proc_dir)))
return;
SET_MODULE_OWNER(proc_dir);
if(!e1000_proc_singles_create(proc_dir, proc_list_head))
return;
strcpy(info_name, name);
strcat(info_name, ".info");
if(!(info_entry =
create_proc_entry(info_name, S_IFREG, intel_proc_dir)))
return;
SET_MODULE_OWNER(info_entry);
info_entry->read_proc = e1000_proc_info_read;
info_entry->data = proc_list_head;
}
static void
e1000_proc_list_add(struct list_head *proc_list_head, char *tag,
void *data, size_t len,
char *(*func)(void *, size_t, char *))
{
struct proc_list *new = (struct proc_list *)
kmalloc(sizeof(struct proc_list), GFP_KERNEL);
if(!new)
return;
strncpy(new->tag, tag, TAG_MAX_LENGTH);
new->data = data;
new->len = len;
new->func = func;
list_add_tail(&new->list, proc_list_head);
}
static void
e1000_proc_list_free(struct list_head *proc_list_head)
{
struct proc_list *elem;
while(!list_empty(proc_list_head)) {
elem = list_entry(proc_list_head->next, struct proc_list, list);
list_del(&elem->list);
kfree(elem);
}
}
/*
* General purpose formating functions
*/
static char *
e1000_proc_str(void *data, size_t len, char *buf)
{
sprintf(buf, "%s", (char *)data);
return buf;
}
static char *
e1000_proc_hex(void *data, size_t len, char *buf)
{
switch(len) {
case sizeof(uint8_t):
sprintf(buf, "0x%02x", *(uint8_t *)data);
break;
case sizeof(uint16_t):
sprintf(buf, "0x%04x", *(uint16_t *)data);
break;
case sizeof(uint32_t):
sprintf(buf, "0x%08x", *(uint32_t *)data);
break;
case sizeof(uint64_t):
sprintf(buf, "0x%08Lx", (unsigned long long)*(uint64_t *)data);
break;
}
return buf;
}
static char *
e1000_proc_unsigned(void *data, size_t len, char *buf)
{
switch(len) {
case sizeof(uint8_t):
sprintf(buf, "%u", *(uint8_t *)data);
break;
case sizeof(uint16_t):
sprintf(buf, "%u", *(uint16_t *)data);
break;
case sizeof(uint32_t):
sprintf(buf, "%u", *(uint32_t *)data);
break;
case sizeof(uint64_t):
sprintf(buf, "%Lu", (unsigned long long)*(uint64_t *)data);
break;
}
return buf;
}
/*
* Specific formating functions
*/
static char *
e1000_proc_part_number(void *data, size_t len, char *buf)
{
sprintf(buf, "%06x-%03x", *(uint32_t *)data >> 8,
*(uint32_t *)data & 0x000000FF);
return buf;
}
static char *
e1000_proc_slot(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
sprintf(buf, "%u", PCI_SLOT(adapter->pdev->devfn));
return buf;
}
static char *
e1000_proc_bus_type(void *data, size_t len, char *buf)
{
e1000_bus_type bus_type = *(e1000_bus_type *)data;
sprintf(buf,
bus_type == e1000_bus_type_pci ? "PCI" :
bus_type == e1000_bus_type_pcix ? "PCI-X" :
"UNKNOWN");
return buf;
}
static char *
e1000_proc_bus_speed(void *data, size_t len, char *buf)
{
e1000_bus_speed bus_speed = *(e1000_bus_speed *)data;
sprintf(buf,
bus_speed == e1000_bus_speed_33 ? "33MHz" :
bus_speed == e1000_bus_speed_66 ? "66MHz" :
bus_speed == e1000_bus_speed_100 ? "100MHz" :
bus_speed == e1000_bus_speed_133 ? "133MHz" :
"UNKNOWN");
return buf;
}
static char *
e1000_proc_bus_width(void *data, size_t len, char *buf)
{
e1000_bus_width bus_width = *(e1000_bus_width *)data;
sprintf(buf,
bus_width == e1000_bus_width_32 ? "32-bit" :
bus_width == e1000_bus_width_64 ? "64-bit" :
"UNKNOWN");
return buf;
}
static char *
e1000_proc_hwaddr(void *data, size_t len, char *buf)
{
unsigned char *hwaddr = data;
sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
hwaddr[0], hwaddr[1], hwaddr[2],
hwaddr[3], hwaddr[4], hwaddr[5]);
return buf;
}
static char *
e1000_proc_link(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
sprintf(buf, netif_running(adapter->netdev) ?
netif_carrier_ok(adapter->netdev) ?
"up" : "down" : "N/A");
return buf;
}
static char *
e1000_proc_link_speed(void *data, size_t len, char *buf)
{
uint16_t link_speed = *(uint16_t *)data;
sprintf(buf, link_speed ? "%u" : "N/A", link_speed);
return buf;
}
static char *
e1000_proc_link_duplex(void *data, size_t len, char *buf)
{
uint16_t link_duplex = *(uint16_t *)data;
sprintf(buf,
link_duplex == FULL_DUPLEX ? "Full" :
link_duplex == HALF_DUPLEX ? "Half" :
"N/A");
return buf;
}
static char *
e1000_proc_state(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
sprintf(buf, adapter->netdev->flags & IFF_UP ? "up" : "down");
return buf;
}
static char *
e1000_proc_media_type(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
sprintf(buf,
adapter->hw.media_type == e1000_media_type_copper ?
"Copper" : "Fiber");
return buf;
}
static char *
e1000_proc_cable_length(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
e1000_cable_length cable_length = adapter->phy_info.cable_length;
sprintf(buf, "%s%s",
cable_length == e1000_cable_length_50 ? "0-50" :
cable_length == e1000_cable_length_50_80 ? "50-80" :
cable_length == e1000_cable_length_80_110 ? "80-110" :
cable_length == e1000_cable_length_110_140 ? "110-140" :
cable_length == e1000_cable_length_140 ? "> 140" :
"Unknown",
cable_length != e1000_cable_length_undefined ?
" Meters (+/- 20 Meters)" : "");
return buf;
}
static char *
e1000_proc_extended(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
e1000_10bt_ext_dist_enable dist_enable =
adapter->phy_info.extended_10bt_distance;
sprintf(buf,
dist_enable == e1000_10bt_ext_dist_enable_normal ? "Disabled" :
dist_enable == e1000_10bt_ext_dist_enable_lower ? "Enabled" :
"Unknown");
return buf;
}
static char *
e1000_proc_cable_polarity(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
e1000_rev_polarity polarity = adapter->phy_info.cable_polarity;
sprintf(buf,
polarity == e1000_rev_polarity_normal ? "Normal" :
polarity == e1000_rev_polarity_reversed ? "Reversed" :
"Unknown");
return buf;
}
static char *
e1000_proc_polarity_correction(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
e1000_polarity_reversal correction =
adapter->phy_info.polarity_correction;
sprintf(buf,
correction == e1000_polarity_reversal_enabled ? "Disabled" :
correction == e1000_polarity_reversal_disabled ? "Enabled" :
"Unknown");
return buf;
}
static char *
e1000_proc_mdi_x_enabled(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
e1000_auto_x_mode mdix_mode = adapter->phy_info.mdix_mode;
sprintf(buf,
mdix_mode == e1000_auto_x_mode_manual_mdi ? "MDI" :
mdix_mode == e1000_auto_x_mode_manual_mdix ? "MDI-X" :
"Unknown");
return buf;
}
static char *
e1000_proc_rx_status(void *data, size_t len, char *buf)
{
e1000_1000t_rx_status rx_status = *(e1000_1000t_rx_status *)data;
sprintf(buf,
rx_status == e1000_1000t_rx_status_not_ok ? "NOT_OK" :
rx_status == e1000_1000t_rx_status_ok ? "OK" :
"Unknown");
return buf;
}
/*
* e1000_proc_list_setup - build link list of proc praramters
* @adapter: board private structure
*
* Order matters - ethx.info entries are ordered in the order links
* are added to list.
*/
#define LIST_ADD_F(T,D,F) \
e1000_proc_list_add(proc_list_head, (T), (D), sizeof(*(D)), (F))
#define LIST_ADD_BLANK() LIST_ADD_F("", NULL, NULL)
#define LIST_ADD_S(T,D) LIST_ADD_F((T), (D), e1000_proc_str)
#define LIST_ADD_H(T,D) LIST_ADD_F((T), (D), e1000_proc_hex)
#define LIST_ADD_U(T,D) LIST_ADD_F((T), (D), e1000_proc_unsigned)
static void
e1000_proc_list_setup(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
struct list_head *proc_list_head = &adapter->proc_list_head;
INIT_LIST_HEAD(proc_list_head);
LIST_ADD_S("Description", adapter->id_string);
LIST_ADD_F("Part_Number", &adapter->part_num, e1000_proc_part_number);
LIST_ADD_S("Driver_Name", e1000_driver_name);
LIST_ADD_S("Driver_Version", e1000_driver_version);
LIST_ADD_H("PCI_Vendor", &hw->vendor_id);
LIST_ADD_H("PCI_Device_ID", &hw->device_id);
LIST_ADD_H("PCI_Subsystem_Vendor", &hw->subsystem_vendor_id);
LIST_ADD_H("PCI_Subsystem_ID", &hw->subsystem_id);
LIST_ADD_H("PCI_Revision_ID", &hw->revision_id);
LIST_ADD_U("PCI_Bus", &adapter->pdev->bus->number);
LIST_ADD_F("PCI_Slot", adapter, e1000_proc_slot);
if(adapter->hw.mac_type >= e1000_82543) {
LIST_ADD_F("PCI_Bus_Type",
&hw->bus_type, e1000_proc_bus_type);
LIST_ADD_F("PCI_Bus_Speed",
&hw->bus_speed, e1000_proc_bus_speed);
LIST_ADD_F("PCI_Bus_Width",
&hw->bus_width, e1000_proc_bus_width);
}
LIST_ADD_U("IRQ", &adapter->pdev->irq);
LIST_ADD_S("System_Device_Name", adapter->ifname);
LIST_ADD_F("Current_HWaddr",
adapter->netdev->dev_addr, e1000_proc_hwaddr);
LIST_ADD_F("Permanent_HWaddr",
adapter->hw.perm_mac_addr, e1000_proc_hwaddr);
LIST_ADD_BLANK();
LIST_ADD_F("Link", adapter, e1000_proc_link);
LIST_ADD_F("Speed", &adapter->link_speed, e1000_proc_link_speed);
LIST_ADD_F("Duplex", &adapter->link_duplex, e1000_proc_link_duplex);
LIST_ADD_F("State", adapter, e1000_proc_state);
LIST_ADD_BLANK();
/* Standard net device stats */
LIST_ADD_U("Rx_Packets", &adapter->net_stats.rx_packets);
LIST_ADD_U("Tx_Packets", &adapter->net_stats.tx_packets);
LIST_ADD_U("Rx_Bytes", &adapter->net_stats.rx_bytes);
LIST_ADD_U("Tx_Bytes", &adapter->net_stats.tx_bytes);
LIST_ADD_U("Rx_Errors", &adapter->net_stats.rx_errors);
LIST_ADD_U("Tx_Errors", &adapter->net_stats.tx_errors);
LIST_ADD_U("Rx_Dropped", &adapter->net_stats.rx_dropped);
LIST_ADD_U("Tx_Dropped", &adapter->net_stats.tx_dropped);
LIST_ADD_U("Multicast", &adapter->net_stats.multicast);
LIST_ADD_U("Collisions", &adapter->net_stats.collisions);
LIST_ADD_U("Rx_Length_Errors", &adapter->net_stats.rx_length_errors);
LIST_ADD_U("Rx_Over_Errors", &adapter->net_stats.rx_over_errors);
LIST_ADD_U("Rx_CRC_Errors", &adapter->net_stats.rx_crc_errors);
LIST_ADD_U("Rx_Frame_Errors", &adapter->net_stats.rx_frame_errors);
LIST_ADD_U("Rx_FIFO_Errors", &adapter->net_stats.rx_fifo_errors);
LIST_ADD_U("Rx_Missed_Errors", &adapter->net_stats.rx_missed_errors);
LIST_ADD_U("Tx_Aborted_Errors", &adapter->net_stats.tx_aborted_errors);
LIST_ADD_U("Tx_Carrier_Errors", &adapter->net_stats.tx_carrier_errors);
LIST_ADD_U("Tx_FIFO_Errors", &adapter->net_stats.tx_fifo_errors);
LIST_ADD_U("Tx_Heartbeat_Errors",
&adapter->net_stats.tx_heartbeat_errors);
LIST_ADD_U("Tx_Window_Errors", &adapter->net_stats.tx_window_errors);
/* 8254x-specific stats */
LIST_ADD_U("Tx_Abort_Late_Coll", &adapter->stats.latecol);
LIST_ADD_U("Tx_Deferred_Ok", &adapter->stats.dc);
LIST_ADD_U("Tx_Single_Coll_Ok", &adapter->stats.scc);
LIST_ADD_U("Tx_Multi_Coll_Ok", &adapter->stats.mcc);
LIST_ADD_U("Rx_Long_Length_Errors", &adapter->stats.roc);
LIST_ADD_U("Rx_Short_Length_Errors", &adapter->stats.ruc);
/* The 82542 does not have some of these stats */
if(adapter->hw.mac_type >= e1000_82543) {
LIST_ADD_U("Rx_Align_Errors", &adapter->stats.algnerrc);
LIST_ADD_U("Tx_TCP_Seg_Good", &adapter->stats.tsctc);
LIST_ADD_U("Tx_TCP_Seg_Failed", &adapter->stats.tsctfc);
}
LIST_ADD_U("Rx_Flow_Control_XON", &adapter->stats.xonrxc);
LIST_ADD_U("Rx_Flow_Control_XOFF", &adapter->stats.xoffrxc);
LIST_ADD_U("Tx_Flow_Control_XON", &adapter->stats.xontxc);
LIST_ADD_U("Tx_Flow_Control_XOFF", &adapter->stats.xofftxc);
LIST_ADD_U("Rx_CSum_Offload_Good", &adapter->hw_csum_good);
LIST_ADD_U("Rx_CSum_Offload_Errors", &adapter->hw_csum_err);
LIST_ADD_BLANK();
/* Cable diags */
LIST_ADD_F("PHY_Media_Type", adapter, e1000_proc_media_type);
if(adapter->hw.media_type == e1000_media_type_copper) {
LIST_ADD_F("PHY_Cable_Length",
adapter, e1000_proc_cable_length);
LIST_ADD_F("PHY_Extended_10Base_T_Distance",
adapter, e1000_proc_extended);
LIST_ADD_F("PHY_Cable_Polarity",
adapter, e1000_proc_cable_polarity);
LIST_ADD_F("PHY_Disable_Polarity_Correction",
adapter, e1000_proc_polarity_correction);
LIST_ADD_U("PHY_Idle_Errors",
&adapter->phy_stats.idle_errors);
LIST_ADD_U("PHY_Receive_Errors",
&adapter->phy_stats.receive_errors);
LIST_ADD_F("PHY_MDI_X_Enabled",
adapter, e1000_proc_mdi_x_enabled);
LIST_ADD_F("PHY_Local_Receiver_Status",
&adapter->phy_info.local_rx,
e1000_proc_rx_status);
LIST_ADD_F("PHY_Remote_Receiver_Status",
&adapter->phy_info.remote_rx,
e1000_proc_rx_status);
}
}
/*
* e1000_proc_dev_setup - create proc fs nodes and link list
* @adapter: board private structure
*/
void
e1000_proc_dev_setup(struct e1000_adapter *adapter)
{
e1000_proc_list_setup(adapter);
e1000_proc_dirs_create(adapter,
adapter->ifname,
&adapter->proc_list_head);
}
/*
* e1000_proc_dev_free - free proc fs nodes and link list
* @adapter: board private structure
*/
void
e1000_proc_dev_free(struct e1000_adapter *adapter)
{
e1000_proc_dirs_free(adapter->ifname, &adapter->proc_list_head);
e1000_proc_list_free(&adapter->proc_list_head);
}
#else /* CONFIG_PROC_FS */
void e1000_proc_dev_setup(struct e1000_adapter *adapter) {}
void e1000_proc_dev_free(struct e1000_adapter *adapter) {}
#endif /* CONFIG_PROC_FS */
/* $Id: tg3.c,v 1.43.2.80 2002/03/14 00:10:04 davem Exp $
/*
* tg3.c: Broadcom Tigon3 ethernet driver.
*
* Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
......@@ -54,8 +54,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "1.2a"
#define DRV_MODULE_RELDATE "Dec 9, 2002"
#define DRV_MODULE_VERSION "1.4"
#define DRV_MODULE_RELDATE "Feb 1, 2003"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
......@@ -141,6 +141,12 @@ static struct pci_device_id tg3_pci_tbl[] __devinitdata = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702A3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_SYSKONNECT, 0x4400,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000,
......@@ -163,6 +169,8 @@ static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
spin_unlock_irqrestore(&tp->indirect_lock, flags);
} else {
writel(val, tp->regs + off);
if ((tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG) != 0)
readl(tp->regs + off);
}
}
......@@ -213,28 +221,11 @@ static void tg3_enable_ints(struct tg3 *tp)
tw32(TG3PCI_MISC_HOST_CTRL,
(tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000);
if (tp->hw_status->status & SD_STATUS_UPDATED) {
tw32(GRC_LOCAL_CTRL,
tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
}
tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
}
static inline void tg3_mask_ints(struct tg3 *tp)
{
tw32(TG3PCI_MISC_HOST_CTRL,
(tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
}
static inline void tg3_unmask_ints(struct tg3 *tp)
{
tw32(TG3PCI_MISC_HOST_CTRL,
(tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
if (tp->hw_status->status & SD_STATUS_UPDATED) {
if (tp->hw_status->status & SD_STATUS_UPDATED)
tw32(GRC_LOCAL_CTRL,
tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
}
}
static void tg3_switch_clocks(struct tg3 *tp)
......@@ -900,6 +891,20 @@ static int tg3_setup_copper_phy(struct tg3 *tp)
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
/* Some third-party PHYs need to be reset on link going
* down.
*
* XXX 5705 note: This workaround also applies to 5705_a0
*/
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
netif_carrier_ok(tp->dev)) {
tg3_readphy(tp, MII_BMSR, &bmsr);
tg3_readphy(tp, MII_BMSR, &bmsr);
if (!(bmsr & BMSR_LSTATUS))
tg3_phy_reset(tp, 1);
}
if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
tg3_readphy(tp, MII_BMSR, &bmsr);
tg3_readphy(tp, MII_BMSR, &bmsr);
......@@ -1958,13 +1963,12 @@ static int tg3_rx(struct tg3 *tp, int budget)
}
if ((tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) &&
(desc->type_flags & RXD_FLAG_TCPUDP_CSUM)) {
skb->csum = htons((desc->ip_tcp_csum & RXD_TCPCSUM_MASK)
>> RXD_TCPCSUM_SHIFT);
skb->ip_summed = CHECKSUM_HW;
} else {
(desc->type_flags & RXD_FLAG_TCPUDP_CSUM) &&
(((desc->ip_tcp_csum & RXD_TCPCSUM_MASK)
>> RXD_TCPCSUM_SHIFT) == 0xffff))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb->ip_summed = CHECKSUM_NONE;
}
skb->protocol = eth_type_trans(skb, tp->dev);
#if TG3_VLAN_TAG_USED
......@@ -2017,10 +2021,12 @@ static int tg3_poll(struct net_device *netdev, int *budget)
{
struct tg3 *tp = netdev->priv;
struct tg3_hw_status *sblk = tp->hw_status;
unsigned long flags;
int done;
spin_lock_irq(&tp->lock);
spin_lock_irqsave(&tp->lock, flags);
/* handle link change and other phy events */
if (!(tp->tg3_flags &
(TG3_FLAG_USE_LINKCHG_REG |
TG3_FLAG_POLL_SERDES))) {
......@@ -2031,12 +2037,14 @@ static int tg3_poll(struct net_device *netdev, int *budget)
}
}
/* run TX completion thread */
if (sblk->idx[0].tx_consumer != tp->tx_cons) {
spin_lock(&tp->tx_lock);
tg3_tx(tp);
spin_unlock(&tp->tx_lock);
}
/* run RX thread, within the bounds set by NAPI */
done = 1;
if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) {
int orig_budget = *budget;
......@@ -2054,44 +2062,35 @@ static int tg3_poll(struct net_device *netdev, int *budget)
done = 0;
}
/* if no more work, tell net stack and NIC we're done */
if (done) {
netif_rx_complete(netdev);
tg3_unmask_ints(tp);
tg3_enable_ints(tp);
}
spin_unlock_irq(&tp->lock);
spin_unlock_irqrestore(&tp->lock, flags);
return (done ? 0 : 1);
}
static __inline__ void tg3_interrupt_main_work(struct net_device *dev, struct tg3 *tp)
static inline unsigned int tg3_has_work(struct net_device *dev, struct tg3 *tp)
{
struct tg3_hw_status *sblk = tp->hw_status;
int work_exists = 0;
unsigned int work_exists = 0;
/* check for phy events */
if (!(tp->tg3_flags &
(TG3_FLAG_USE_LINKCHG_REG |
TG3_FLAG_POLL_SERDES))) {
if (sblk->status & SD_STATUS_LINK_CHG)
work_exists = 1;
}
/* check for RX/TX work to do */
if (sblk->idx[0].tx_consumer != tp->tx_cons ||
sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
work_exists = 1;
if (!work_exists)
return;
if (netif_rx_schedule_prep(dev)) {
/* NOTE: These writes are posted by the readback of
* the mailbox register done by our caller.
*/
tg3_mask_ints(tp);
__netif_rx_schedule(dev);
} else {
printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
dev->name);
}
return work_exists;
}
static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
......@@ -2104,16 +2103,33 @@ static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_lock_irqsave(&tp->lock, flags);
if (sblk->status & SD_STATUS_UPDATED) {
/*
* writing any value to intr-mbox-0 clears PCI INTA# and
* chip-internal interrupt pending events.
* writing non-zero to intr-mbox-0 additional tells the
* NIC to stop sending us irqs, engaging "in-intr-handler"
* event coalescing.
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000001);
/*
* Flush PCI write. This also guarantees that our
* status block has been flushed to host memory.
*/
tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
sblk->status &= ~SD_STATUS_UPDATED;
tg3_interrupt_main_work(dev, tp);
if (likely(tg3_has_work(dev, tp)))
netif_rx_schedule(dev); /* schedule NAPI poll */
else {
/* no work, shared interrupt perhaps? re-enable
* interrupts, and flush that PCI write
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000000);
tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
}
}
spin_unlock_irqrestore(&tp->lock, flags);
}
......@@ -2213,11 +2229,6 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
return -1;
}
/* NOTE: Broadcom's driver botches this case up really bad.
* This is especially true if any of the frag pages
* are in highmem. It will instantly oops in that case.
*/
/* New SKB is guarenteed to be linear. */
entry = *start;
new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len,
......@@ -2649,6 +2660,17 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
int new_mtu)
{
dev->mtu = new_mtu;
if (new_mtu > ETH_DATA_LEN)
tp->tg3_flags |= TG3_FLAG_JUMBO_ENABLE;
else
tp->tg3_flags &= ~TG3_FLAG_JUMBO_ENABLE;
}
static int tg3_change_mtu(struct net_device *dev, int new_mtu)
{
struct tg3 *tp = dev->priv;
......@@ -2660,7 +2682,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
/* We'll just catch it later when the
* device is up'd.
*/
dev->mtu = new_mtu;
tg3_set_mtu(dev, tp, new_mtu);
return 0;
}
......@@ -2669,12 +2691,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
tg3_halt(tp);
dev->mtu = new_mtu;
if (new_mtu > ETH_DATA_LEN)
tp->tg3_flags |= TG3_FLAG_JUMBO_ENABLE;
else
tp->tg3_flags &= ~TG3_FLAG_JUMBO_ENABLE;
tg3_set_mtu(dev, tp, new_mtu);
tg3_init_rings(tp);
tg3_init_hw(tp);
......@@ -4285,6 +4302,12 @@ static int tg3_reset_hw(struct tg3 *tp)
if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
tw32(MAC_SERDES_CFG, 0x616000);
/* Prevent chip from dropping frames when flow control
* is enabled.
*/
tw32(MAC_LOW_WMARK_MAX_RX_FRAME, 2);
tr32(MAC_LOW_WMARK_MAX_RX_FRAME);
err = tg3_setup_phy(tp);
if (err)
return err;
......@@ -4353,8 +4376,9 @@ static int tg3_init_hw(struct tg3 *tp)
static void tg3_timer(unsigned long __opaque)
{
struct tg3 *tp = (struct tg3 *) __opaque;
unsigned long flags;
spin_lock_irq(&tp->lock);
spin_lock_irqsave(&tp->lock, flags);
spin_lock(&tp->tx_lock);
/* All of this garbage is because when using non-tagged
......@@ -4436,7 +4460,7 @@ static void tg3_timer(unsigned long __opaque)
}
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);
spin_unlock_irqrestore(&tp->lock, flags);
tp->timer.expires = jiffies + tp->timer_offset;
add_timer(&tp->timer);
......@@ -5793,7 +5817,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
(tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)) {
tg3_writephy(tp, 0x1c, 0x8d68);
tg3_writephy(tp, 0x1c, 0x8d68);
}
......@@ -5999,6 +6024,14 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
}
}
/* Back to back register writes can cause problems on this chip,
* the workaround is to read back all reg writes except those to
* mailbox regs. See tg3_write_indirect_reg32().
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
tp->tg3_flags |= TG3_FLAG_5701_REG_WRITE_BUG;
if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0)
tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED;
if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
......@@ -6013,8 +6046,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
/* Force the chip into D0. */
err = tg3_set_power_state(tp, 0);
if (err)
if (err) {
printk(KERN_ERR PFX "(%s) transition to D0 failed\n",
tp->pdev->slot_name);
return err;
}
/* 5700 B0 chips do not support checksumming correctly due
* to hardware bugs.
......@@ -6022,18 +6058,14 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0)
tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS;
/* Regardless of whether checksums work or not, we configure
* the StrongARM chips to not compute the pseudo header checksums
* in either direction. Because of the way Linux checksum support
* works we do not need the chips to do this, and taking the load
* off of the TX/RX onboard StrongARM cpus means that they will not be
* the bottleneck. Whoever wrote Broadcom's driver did not
* understand the situation at all. He could have bothered
* to read Jes's Acenic driver because the logic (and this part of
* the Tigon2 hardware/firmware) is pretty much identical.
/* Pseudo-header checksum is done by hardware logic and not
* the offload processers, so make the chip do the pseudo-
* header checksums on receive. For transmit it is more
* convenient to do the pseudo-header checksum in software
* as Linux does that on transmit for us in all cases.
*/
tp->tg3_flags |= TG3_FLAG_NO_TX_PSEUDO_CSUM;
tp->tg3_flags |= TG3_FLAG_NO_RX_PSEUDO_CSUM;
tp->tg3_flags &= ~TG3_FLAG_NO_RX_PSEUDO_CSUM;
/* Derive initial jumbo mode from MTU assigned in
* ether_setup() via the alloc_etherdev() call
......@@ -6111,19 +6143,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG)
tp->tg3_flags |= TG3_FLAG_HOST_TXDS;
/* Quick sanity check. Make sure we see an expected
* value here.
*/
grc_misc_cfg = tr32(GRC_MISC_CFG);
grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
if (grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5700 &&
grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5701 &&
grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5702FE &&
grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703 &&
grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703S &&
grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5704 &&
grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_AC91002A1)
return -ENODEV;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) {
......@@ -6131,14 +6152,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ;
}
/* ROFL, you should see Broadcom's driver code implementing
* this, stuff like "if (a || b)" where a and b are always
* mutually exclusive. DaveM finds like 6 bugs today, hello!
*/
/* this one is limited to 10/100 only */
if (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5702FE)
tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
err = tg3_phy_probe(tp);
if (err) {
printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n",
tp->pdev->slot_name, err);
/* ... but do not return immediately ... */
}
tg3_read_partno(tp);
......@@ -6192,17 +6215,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
/* 5700 chips can get confused if TX buffers straddle the
* 4GB address boundary in some cases.
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
/* ROFL! Latest Broadcom driver disables NETIF_F_HIGHDMA
* in this case instead of fixing their workaround code.
*
* Like, hey, there is this skb_copy() thing guys,
* use it. Oh I can't stop laughing...
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
tp->dev->hard_start_xmit = tg3_start_xmit_4gbug;
} else {
else
tp->dev->hard_start_xmit = tg3_start_xmit;
}
tp->rx_offset = 2;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
......@@ -6368,6 +6384,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
(0x7 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
(0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
/* XXX 5705 note: set MIN_DMA to zero here */
} else {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
tp->dma_rwctrl =
......@@ -6385,12 +6402,19 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
/* Wheee, some more chip bugs... */
if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1 ||
tp->pci_chip_rev_id == CHIPREV_ID_5703_A2 ||
tp->pci_chip_rev_id == CHIPREV_ID_5703_A3 ||
tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
u32 ccval = (tr32(TG3PCI_CLOCK_CTRL) & 0x1f);
if (ccval == 0x6 || ccval == 0x7)
tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
}
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
tp->dma_rwctrl &= ~(DMA_RWCTRL_MIN_DMA
<< DMA_RWCTRL_MIN_DMA_SHIFT);
/* We don't do this on x86 because it seems to hurt performace.
* It does help things on other platforms though.
......
......@@ -113,6 +113,8 @@
#define CHIPREV_ID_5703_A2 0x1002
#define CHIPREV_ID_5703_A3 0x1003
#define CHIPREV_ID_5704_A0 0x2000
#define CHIPREV_ID_5704_A1 0x2001
#define CHIPREV_ID_5704_A2 0x2002
#define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12)
#define ASIC_REV_5700 0x07
#define ASIC_REV_5701 0x00
......@@ -454,6 +456,7 @@
#define RCV_RULE_DISABLE_MASK 0x7fffffff
#define MAC_RCV_RULE_CFG 0x00000500
#define RCV_RULE_CFG_DEFAULT_CLASS 0x00000008
#define MAC_LOW_WMARK_MAX_RX_FRAME 0x00000504
/* 0x504 --> 0x590 unused */
#define MAC_SERDES_CFG 0x00000590
#define MAC_SERDES_STAT 0x00000594
......@@ -1136,6 +1139,7 @@
#define GRC_MISC_CFG_BOARD_ID_5703S 0x00002000
#define GRC_MISC_CFG_BOARD_ID_5704 0x00000000
#define GRC_MISC_CFG_BOARD_ID_5704CIOBE 0x00004000
#define GRC_MISC_CFG_BOARD_ID_5704_A2 0x00008000
#define GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000
#define GRC_LOCAL_CTRL 0x00006808
#define GRC_LCLCTRL_INT_ACTIVE 0x00000001
......@@ -1791,6 +1795,7 @@ struct tg3 {
#define TG3_FLAG_USE_LINKCHG_REG 0x00000008
#define TG3_FLAG_USE_MI_INTERRUPT 0x00000010
#define TG3_FLAG_ENABLE_ASF 0x00000020
#define TG3_FLAG_5701_REG_WRITE_BUG 0x00000040
#define TG3_FLAG_POLL_SERDES 0x00000080
#define TG3_FLAG_MBOX_WRITE_REORDER 0x00000100
#define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200
......
......@@ -1661,6 +1661,9 @@
#define PCI_DEVICE_ID_TIGON3_5702FE 0x164d
#define PCI_DEVICE_ID_TIGON3_5702X 0x16a6
#define PCI_DEVICE_ID_TIGON3_5703X 0x16a7
#define PCI_DEVICE_ID_TIGON3_5704S 0x16a8
#define PCI_DEVICE_ID_TIGON3_5702A3 0x16c6
#define PCI_DEVICE_ID_TIGON3_5703A3 0x16c7
#define PCI_DEVICE_ID_BCM4401 0x4401
#define PCI_VENDOR_ID_SYBA 0x1592
......
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