summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pretzel.yyz.us>2005-06-28 06:05:03 +0400
committerJeff Garzik <jgarzik@pobox.com>2005-06-28 06:05:03 +0400
commit1bad3f4050b2a641bbfeaddb2717b28247311e9c (patch)
treebdc2efda40f48e0fbb64e6b9aca793e95ac72fc4 /drivers/net
parent747802ab478399f13ff57751c2ebd22577be4eeb (diff)
parentc7b645f934e52a54af58142d91fb51f881f8ce26 (diff)
downloadlinux-1bad3f4050b2a641bbfeaddb2717b28247311e9c.tar.xz
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/3c523.c1
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/b44.c3
-rw-r--r--drivers/net/cs89x0.c40
-rw-r--r--drivers/net/cs89x0.h2
-rw-r--r--drivers/net/e100.c25
-rw-r--r--drivers/net/e1000/e1000.h4
-rw-r--r--drivers/net/e1000/e1000_ethtool.c131
-rw-r--r--drivers/net/e1000/e1000_hw.c23
-rw-r--r--drivers/net/e1000/e1000_hw.h1
-rw-r--r--drivers/net/e1000/e1000_main.c111
-rw-r--r--drivers/net/forcedeth.c53
-rw-r--r--drivers/net/gianfar.c652
-rw-r--r--drivers/net/gianfar.h363
-rw-r--r--drivers/net/gianfar_ethtool.c277
-rw-r--r--drivers/net/pcnet32.c2
-rw-r--r--drivers/net/sb1000.c14
-rw-r--r--drivers/net/skfp/Makefile4
-rw-r--r--drivers/net/skfp/drvfbi.c222
-rw-r--r--drivers/net/skfp/ess.c4
-rw-r--r--drivers/net/skfp/fplustm.c70
-rw-r--r--drivers/net/skfp/h/cmtdef.h7
-rw-r--r--drivers/net/skfp/h/hwmtm.h25
-rw-r--r--drivers/net/skfp/hwmtm.c34
-rw-r--r--drivers/net/skfp/pcmplc.c7
-rw-r--r--drivers/net/skfp/pmf.c11
-rw-r--r--drivers/net/skfp/skfddi.c1
-rw-r--r--drivers/net/skfp/smt.c46
-rw-r--r--drivers/net/skfp/smtdef.c5
-rw-r--r--drivers/net/skfp/smtparse.c467
-rw-r--r--drivers/net/smc91x.c43
-rw-r--r--drivers/net/tokenring/lanstreamer.c6
-rw-r--r--drivers/net/tulip/tulip_core.c44
-rw-r--r--drivers/net/via-rhine.c6
-rw-r--r--drivers/net/wan/farsync.c1
-rw-r--r--drivers/net/wireless/airo.c2
-rw-r--r--drivers/net/wireless/orinoco.c2465
-rw-r--r--drivers/net/wireless/orinoco.h30
-rw-r--r--drivers/net/wireless/prism54/isl_38xx.c6
39 files changed, 2753 insertions, 2457 deletions
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 1247a25f1093..9e1fe2e0478c 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -1274,6 +1274,7 @@ module_param_array(irq, int, NULL, 0);
module_param_array(io, int, NULL, 0);
MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");
MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");
+MODULE_LICENSE("GPL");
int init_module(void)
{
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 47e158fa5aac..2b55687f6ee9 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1320,7 +1320,7 @@ config FORCEDETH
config CS89x0
tristate "CS89x0 support"
- depends on NET_PCI && (ISA || ARCH_IXDP2X01)
+ depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105
---help---
Support for CS89x0 chipset based Ethernet cards. If you have a
network (Ethernet) card of this type, say Y and read the
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 3fe8ba992c38..f1bd45e3da31 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1285,6 +1285,9 @@ static int b44_open(struct net_device *dev)
b44_init_hw(bp);
bp->flags |= B44_FLAG_INIT_COMPLETE;
+ netif_carrier_off(dev);
+ b44_check_phy(bp);
+
spin_unlock_irq(&bp->lock);
init_timer(&bp->timer);
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 25e4495de79e..b96d6fb1929e 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -174,6 +174,13 @@ static unsigned int cs8900_irq_map[] = {1,0,0,0};
#include <asm/irq.h>
static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
+#elif defined(CONFIG_ARCH_PNX0105)
+#include <asm/irq.h>
+#include <asm/arch/gpio.h>
+#define CIRRUS_DEFAULT_BASE IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000) /* = Physical address 0x48200000 */
+#define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */
+static unsigned int netcard_portlist[] __initdata = {CIRRUS_DEFAULT_BASE, 0};
+static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
#else
static unsigned int netcard_portlist[] __initdata =
{ 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
@@ -431,6 +438,30 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
#endif
}
+#ifdef CONFIG_ARCH_PNX0105
+ initialize_ebi();
+
+ /* Map GPIO registers for the pins connected to the CS8900a. */
+ if (map_cirrus_gpio() < 0)
+ return -ENODEV;
+
+ reset_cirrus();
+
+ /* Map event-router registers. */
+ if (map_event_router() < 0)
+ return -ENODEV;
+
+ enable_cirrus_irq();
+
+ unmap_cirrus_gpio();
+ unmap_event_router();
+
+ dev->base_addr = ioaddr;
+
+ for (i = 0 ; i < 3 ; i++)
+ readreg(dev, 0);
+#endif
+
/* Grab the region so we can find another board if autoIRQ fails. */
/* WTF is going on here? */
if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
@@ -672,7 +703,7 @@ printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT));
} else {
i = lp->isa_config & INT_NO_MASK;
if (lp->chip_type == CS8900) {
-#ifdef CONFIG_ARCH_IXDP2X01
+#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
i = cs8900_irq_map[0];
#else
/* Translate the IRQ using the IRQ mapping table. */
@@ -1145,7 +1176,7 @@ net_open(struct net_device *dev)
int i;
int ret;
-#ifndef CONFIG_SH_HICOSH4 /* uses irq#1, so this won't work */
+#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX0105) /* uses irq#1, so this won't work */
if (dev->irq < 2) {
/* Allow interrupts to be generated by the chip */
/* Cirrus' release had this: */
@@ -1176,7 +1207,7 @@ net_open(struct net_device *dev)
else
#endif
{
-#ifndef CONFIG_ARCH_IXDP2X01
+#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105)
if (((1 << dev->irq) & lp->irq_map) == 0) {
printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
dev->name, dev->irq, lp->irq_map);
@@ -1261,6 +1292,9 @@ net_open(struct net_device *dev)
case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;
default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
}
+#ifdef CONFIG_ARCH_PNX0105
+ result = A_CNF_10B_T;
+#endif
if (!result) {
printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);
release_irq:
diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h
index b0ef7ad2baad..bd3ad8e6cce9 100644
--- a/drivers/net/cs89x0.h
+++ b/drivers/net/cs89x0.h
@@ -16,7 +16,7 @@
#include <linux/config.h>
-#ifdef CONFIG_ARCH_IXDP2X01
+#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
/* IXDP2401/IXDP2801 uses dword-aligned register addressing */
#define CS89x0_PORT(reg) ((reg) * 2)
#else
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index cfaa6b2bf345..1e56c8eea35f 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1093,11 +1093,16 @@ static int e100_phy_init(struct nic *nic)
}
if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
- (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) &&
- (nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled)))
- /* enable/disable MDI/MDI-X auto-switching */
- mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
- nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
+ (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000))) {
+ /* enable/disable MDI/MDI-X auto-switching.
+ MDI/MDI-X auto-switching is disabled for 82551ER/QM chips */
+ if((nic->mac == mac_82551_E) || (nic->mac == mac_82551_F) ||
+ (nic->mac == mac_82551_10) || (nic->mii.force_media) ||
+ !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))
+ mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, 0);
+ else
+ mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, NCONFIG_AUTO_SWITCH);
+ }
return 0;
}
@@ -1666,8 +1671,10 @@ static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
if(stat_ack & stat_ack_rnr)
nic->ru_running = RU_SUSPENDED;
- e100_disable_irq(nic);
- netif_rx_schedule(netdev);
+ if(likely(netif_rx_schedule_prep(netdev))) {
+ e100_disable_irq(nic);
+ __netif_rx_schedule(netdev);
+ }
return IRQ_HANDLED;
}
@@ -2335,11 +2342,11 @@ static int __devinit e100_probe(struct pci_dev *pdev,
goto err_out_iounmap;
}
- e100_phy_init(nic);
-
if((err = e100_eeprom_load(nic)))
goto err_out_free;
+ e100_phy_init(nic);
+
memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
if(!is_valid_ether_addr(netdev->dev_addr)) {
DPRINTK(PROBE, ERR, "Invalid MAC address from "
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index af1e82c5b808..092757bc721f 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -140,7 +140,7 @@ struct e1000_adapter;
#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define AUTO_ALL_MODES 0
-#define E1000_EEPROM_82544_APM 0x0400
+#define E1000_EEPROM_82544_APM 0x0004
#define E1000_EEPROM_APME 0x0400
#ifndef E1000_MASTER_SLAVE
@@ -159,7 +159,7 @@ struct e1000_adapter;
* so a DMA handle can be stored along with the buffer */
struct e1000_buffer {
struct sk_buff *skb;
- uint64_t dma;
+ dma_addr_t dma;
unsigned long time_stamp;
uint16_t length;
uint16_t next_to_watch;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 237247f74df4..f133ff0b0b94 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -105,7 +105,7 @@ static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
static int
e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
if(hw->media_type == e1000_media_type_copper) {
@@ -141,9 +141,9 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
SUPPORTED_FIBRE |
SUPPORTED_Autoneg);
- ecmd->advertising = (SUPPORTED_1000baseT_Full |
- SUPPORTED_FIBRE |
- SUPPORTED_Autoneg);
+ ecmd->advertising = (ADVERTISED_1000baseT_Full |
+ ADVERTISED_FIBRE |
+ ADVERTISED_Autoneg);
ecmd->port = PORT_FIBRE;
@@ -179,13 +179,24 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
static int
e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
if(ecmd->autoneg == AUTONEG_ENABLE) {
hw->autoneg = 1;
- hw->autoneg_advertised = 0x002F;
- ecmd->advertising = 0x002F;
+ if(hw->media_type == e1000_media_type_fiber)
+ hw->autoneg_advertised = ADVERTISED_1000baseT_Full |
+ ADVERTISED_FIBRE |
+ ADVERTISED_Autoneg;
+ else
+ hw->autoneg_advertised = ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Full|
+ ADVERTISED_Autoneg |
+ ADVERTISED_TP;
+ ecmd->advertising = hw->autoneg_advertised;
} else
if(e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex))
return -EINVAL;
@@ -206,7 +217,7 @@ static void
e1000_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
pause->autoneg =
@@ -226,7 +237,7 @@ static int
e1000_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
adapter->fc_autoneg = pause->autoneg;
@@ -259,14 +270,14 @@ e1000_set_pauseparam(struct net_device *netdev,
static uint32_t
e1000_get_rx_csum(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
return adapter->rx_csum;
}
static int
e1000_set_rx_csum(struct net_device *netdev, uint32_t data)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
adapter->rx_csum = data;
if(netif_running(netdev)) {
@@ -286,7 +297,7 @@ e1000_get_tx_csum(struct net_device *netdev)
static int
e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
if(adapter->hw.mac_type < e1000_82543) {
if (!data)
@@ -306,8 +317,8 @@ e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
static int
e1000_set_tso(struct net_device *netdev, uint32_t data)
{
- struct e1000_adapter *adapter = netdev->priv;
- if ((adapter->hw.mac_type < e1000_82544) ||
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ if((adapter->hw.mac_type < e1000_82544) ||
(adapter->hw.mac_type == e1000_82547))
return data ? -EINVAL : 0;
@@ -322,14 +333,14 @@ e1000_set_tso(struct net_device *netdev, uint32_t data)
static uint32_t
e1000_get_msglevel(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
return adapter->msg_enable;
}
static void
e1000_set_msglevel(struct net_device *netdev, uint32_t data)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
adapter->msg_enable = data;
}
@@ -344,7 +355,7 @@ static void
e1000_get_regs(struct net_device *netdev,
struct ethtool_regs *regs, void *p)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
uint32_t *regs_buff = p;
uint16_t phy_data;
@@ -432,7 +443,7 @@ e1000_get_regs(struct net_device *netdev,
static int
e1000_get_eeprom_len(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
return adapter->hw.eeprom.word_size * 2;
}
@@ -440,7 +451,7 @@ static int
e1000_get_eeprom(struct net_device *netdev,
struct ethtool_eeprom *eeprom, uint8_t *bytes)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
uint16_t *eeprom_buff;
int first_word, last_word;
@@ -486,7 +497,7 @@ static int
e1000_set_eeprom(struct net_device *netdev,
struct ethtool_eeprom *eeprom, uint8_t *bytes)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
uint16_t *eeprom_buff;
void *ptr;
@@ -547,7 +558,7 @@ static void
e1000_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
strncpy(drvinfo->driver, e1000_driver_name, 32);
strncpy(drvinfo->version, e1000_driver_version, 32);
@@ -563,7 +574,7 @@ static void
e1000_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
e1000_mac_type mac_type = adapter->hw.mac_type;
struct e1000_desc_ring *txdr = &adapter->tx_ring;
struct e1000_desc_ring *rxdr = &adapter->rx_ring;
@@ -584,7 +595,7 @@ static int
e1000_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
e1000_mac_type mac_type = adapter->hw.mac_type;
struct e1000_desc_ring *txdr = &adapter->tx_ring;
struct e1000_desc_ring *rxdr = &adapter->rx_ring;
@@ -651,6 +662,9 @@ err_setup_rx:
E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \
value = E1000_READ_REG(&adapter->hw, R); \
if(value != (test[pat] & W & M)) { \
+ DPRINTK(DRV, ERR, "pattern test reg %04X failed: got " \
+ "0x%08X expected 0x%08X\n", \
+ E1000_##R, value, (test[pat] & W & M)); \
*data = (adapter->hw.mac_type < e1000_82543) ? \
E1000_82542_##R : E1000_##R; \
return 1; \
@@ -663,7 +677,9 @@ err_setup_rx:
uint32_t value; \
E1000_WRITE_REG(&adapter->hw, R, W & M); \
value = E1000_READ_REG(&adapter->hw, R); \
- if ((W & M) != (value & M)) { \
+ if((W & M) != (value & M)) { \
+ DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\
+ "expected 0x%08X\n", E1000_##R, (value & M), (W & M)); \
*data = (adapter->hw.mac_type < e1000_82543) ? \
E1000_82542_##R : E1000_##R; \
return 1; \
@@ -673,18 +689,33 @@ err_setup_rx:
static int
e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
{
- uint32_t value;
- uint32_t i;
+ uint32_t value, before, after;
+ uint32_t i, toggle;
/* The status register is Read Only, so a write should fail.
* Some bits that get toggled are ignored.
*/
- value = (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833));
- E1000_WRITE_REG(&adapter->hw, STATUS, (0xFFFFFFFF));
- if(value != (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833))) {
+ switch (adapter->hw.mac_type) {
+ case e1000_82573:
+ toggle = 0x7FFFF033;
+ break;
+ default:
+ toggle = 0xFFFFF833;
+ break;
+ }
+
+ before = E1000_READ_REG(&adapter->hw, STATUS);
+ value = (E1000_READ_REG(&adapter->hw, STATUS) & toggle);
+ E1000_WRITE_REG(&adapter->hw, STATUS, toggle);
+ after = E1000_READ_REG(&adapter->hw, STATUS) & toggle;
+ if(value != after) {
+ DPRINTK(DRV, ERR, "failed STATUS register test got: "
+ "0x%08X expected: 0x%08X\n", after, value);
*data = 1;
return 1;
}
+ /* restore previous status */
+ E1000_WRITE_REG(&adapter->hw, STATUS, before);
REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
@@ -766,7 +797,7 @@ e1000_test_intr(int irq,
struct pt_regs *regs)
{
struct net_device *netdev = (struct net_device *) data;
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
adapter->test_icr |= E1000_READ_REG(&adapter->hw, ICR);
@@ -1214,6 +1245,7 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter)
case e1000_82541_rev_2:
case e1000_82547:
case e1000_82547_rev_2:
+ case e1000_82573:
return e1000_integrated_phy_loopback(adapter);
break;
@@ -1422,7 +1454,7 @@ static void
e1000_diag_test(struct net_device *netdev,
struct ethtool_test *eth_test, uint64_t *data)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
boolean_t if_running = netif_running(netdev);
if(eth_test->flags == ETH_TEST_FL_OFFLINE) {
@@ -1482,7 +1514,7 @@ e1000_diag_test(struct net_device *netdev,
static void
e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
switch(adapter->hw.device_id) {
@@ -1527,7 +1559,7 @@ e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
static int
e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
switch(adapter->hw.device_id) {
@@ -1588,22 +1620,31 @@ e1000_led_blink_callback(unsigned long data)
static int
e1000_phys_id(struct net_device *netdev, uint32_t data)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ))
data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ);
- if(!adapter->blink_timer.function) {
- init_timer(&adapter->blink_timer);
- adapter->blink_timer.function = e1000_led_blink_callback;
- adapter->blink_timer.data = (unsigned long) adapter;
+ if(adapter->hw.mac_type < e1000_82573) {
+ if(!adapter->blink_timer.function) {
+ init_timer(&adapter->blink_timer);
+ adapter->blink_timer.function = e1000_led_blink_callback;
+ adapter->blink_timer.data = (unsigned long) adapter;
+ }
+ e1000_setup_led(&adapter->hw);
+ mod_timer(&adapter->blink_timer, jiffies);
+ msleep_interruptible(data * 1000);
+ del_timer_sync(&adapter->blink_timer);
+ }
+ else {
+ E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE |
+ E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK |
+ (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
+ (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED1_MODE_SHIFT) |
+ (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT)));
+ msleep_interruptible(data * 1000);
}
- e1000_setup_led(&adapter->hw);
- mod_timer(&adapter->blink_timer, jiffies);
-
- msleep_interruptible(data * 1000);
- del_timer_sync(&adapter->blink_timer);
e1000_led_off(&adapter->hw);
clear_bit(E1000_LED_ON, &adapter->led_status);
e1000_cleanup_led(&adapter->hw);
@@ -1614,7 +1655,7 @@ e1000_phys_id(struct net_device *netdev, uint32_t data)
static int
e1000_nway_reset(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
if(netif_running(netdev)) {
e1000_down(adapter);
e1000_up(adapter);
@@ -1632,7 +1673,7 @@ static void
e1000_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, uint64_t *data)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
int i;
e1000_update_stats(adapter);
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 723589b28be5..045f5426ab9a 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -354,18 +354,27 @@ e1000_set_media_type(struct e1000_hw *hw)
hw->media_type = e1000_media_type_internal_serdes;
break;
default:
- if(hw->mac_type >= e1000_82543) {
+ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ hw->media_type = e1000_media_type_fiber;
+ break;
+ case e1000_82573:
+ /* The STATUS_TBIMODE bit is reserved or reused for the this
+ * device.
+ */
+ hw->media_type = e1000_media_type_copper;
+ break;
+ default:
status = E1000_READ_REG(hw, STATUS);
- if(status & E1000_STATUS_TBIMODE) {
+ if (status & E1000_STATUS_TBIMODE) {
hw->media_type = e1000_media_type_fiber;
/* tbi_compatibility not valid on fiber */
hw->tbi_compatibility_en = FALSE;
} else {
hw->media_type = e1000_media_type_copper;
}
- } else {
- /* This is an 82542 (fiber only) */
- hw->media_type = e1000_media_type_fiber;
+ break;
}
}
}
@@ -1189,9 +1198,9 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw)
ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
if(ret_val)
return ret_val;
- }
+ }
- return E1000_SUCCESS;
+ return E1000_SUCCESS;
}
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index a0263ee96c6b..93e9f8788751 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -66,6 +66,7 @@ typedef enum {
e1000_eeprom_spi,
e1000_eeprom_microwire,
e1000_eeprom_flash,
+ e1000_eeprom_none, /* No NVM support */
e1000_num_eeprom_types
} e1000_eeprom_type;
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 137226d98d47..cb7f051a60ad 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -29,6 +29,8 @@
#include "e1000.h"
/* Change Log
+ * 6.0.58 4/20/05
+ * o Accepted ethtool cleanup patch from Stephen Hemminger
* 6.0.44+ 2/15/05
* o applied Anton's patch to resolve tx hang in hardware
* o Applied Andrew Mortons patch - e1000 stops working after resume
@@ -41,9 +43,9 @@ char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "6.0.54-k2"DRIVERNAPI
+#define DRV_VERSION "6.0.60-k2"DRIVERNAPI
char e1000_driver_version[] = DRV_VERSION;
-char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
+char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
*
@@ -517,7 +519,7 @@ e1000_probe(struct pci_dev *pdev,
SET_NETDEV_DEV(netdev, &pdev->dev);
pci_set_drvdata(pdev, netdev);
- adapter = netdev->priv;
+ adapter = netdev_priv(netdev);
adapter->netdev = netdev;
adapter->pdev = pdev;
adapter->hw.back = adapter;
@@ -738,7 +740,7 @@ static void __devexit
e1000_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t manc, swsm;
flush_scheduled_work();
@@ -871,7 +873,7 @@ e1000_sw_init(struct e1000_adapter *adapter)
static int
e1000_open(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
int err;
/* allocate transmit descriptors */
@@ -919,7 +921,7 @@ err_setup_tx:
static int
e1000_close(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
e1000_down(adapter);
@@ -1599,7 +1601,7 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter)
static int
e1000_set_mac(struct net_device *netdev, void *p)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct sockaddr *addr = p;
if(!is_valid_ether_addr(addr->sa_data))
@@ -1634,7 +1636,7 @@ e1000_set_mac(struct net_device *netdev, void *p)
static void
e1000_set_multi(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
struct dev_mc_list *mc_ptr;
unsigned long flags;
@@ -2213,7 +2215,7 @@ e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb)
static int
e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD;
unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
unsigned int tx_flags = 0;
@@ -2344,7 +2346,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
static void
e1000_tx_timeout(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
/* Do the reset outside of interrupt context */
schedule_work(&adapter->tx_timeout_task);
@@ -2353,7 +2355,7 @@ e1000_tx_timeout(struct net_device *netdev)
static void
e1000_tx_timeout_task(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
e1000_down(adapter);
e1000_up(adapter);
@@ -2370,7 +2372,7 @@ e1000_tx_timeout_task(struct net_device *netdev)
static struct net_device_stats *
e1000_get_stats(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
e1000_update_stats(adapter);
return &adapter->net_stats;
@@ -2387,7 +2389,7 @@ e1000_get_stats(struct net_device *netdev)
static int
e1000_change_mtu(struct net_device *netdev, int new_mtu)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
@@ -2598,7 +2600,7 @@ static irqreturn_t
e1000_intr(int irq, void *data, struct pt_regs *regs)
{
struct net_device *netdev = data;
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
uint32_t icr = E1000_READ_REG(hw, ICR);
#ifndef CONFIG_E1000_NAPI
@@ -2661,7 +2663,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
static int
e1000_clean(struct net_device *netdev, int *budget)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
int work_to_do = min(*budget, netdev->quota);
int tx_cleaned;
int work_done = 0;
@@ -2672,8 +2674,8 @@ e1000_clean(struct net_device *netdev, int *budget)
*budget -= work_done;
netdev->quota -= work_done;
- /* If no Tx and no Rx work done, exit the polling mode */
if ((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
+ /* If no Tx and not enough Rx work done, exit the polling mode */
netif_rx_complete(netdev);
e1000_irq_enable(adapter);
return 0;
@@ -2769,13 +2771,13 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
i = tx_ring->next_to_clean;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
- DPRINTK(TX_ERR, ERR, "Detected Tx Unit Hang\n"
+ DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
" TDH <%x>\n"
" TDT <%x>\n"
" next_to_use <%x>\n"
" next_to_clean <%x>\n"
"buffer_info[next_to_clean]\n"
- " dma <%llx>\n"
+ " dma <%zx>\n"
" time_stamp <%lx>\n"
" next_to_watch <%x>\n"
" jiffies <%lx>\n"
@@ -2994,7 +2996,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
- staterr = rx_desc->wb.middle.status_error;
+ staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
while(staterr & E1000_RXD_STAT_DD) {
buffer_info = &rx_ring->buffer_info[i];
@@ -3065,16 +3067,16 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
#ifdef CONFIG_E1000_NAPI
if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
- le16_to_cpu(rx_desc->wb.middle.vlan &
- E1000_RXD_SPC_VLAN_MASK));
+ le16_to_cpu(rx_desc->wb.middle.vlan) &
+ E1000_RXD_SPC_VLAN_MASK);
} else {
netif_receive_skb(skb);
}
#else /* CONFIG_E1000_NAPI */
if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
vlan_hwaccel_rx(skb, adapter->vlgrp,
- le16_to_cpu(rx_desc->wb.middle.vlan &
- E1000_RXD_SPC_VLAN_MASK));
+ le16_to_cpu(rx_desc->wb.middle.vlan) &
+ E1000_RXD_SPC_VLAN_MASK);
} else {
netif_rx(skb);
}
@@ -3087,7 +3089,7 @@ next_desc:
if(unlikely(++i == rx_ring->count)) i = 0;
rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
- staterr = rx_desc->wb.middle.status_error;
+ staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
}
rx_ring->next_to_clean = i;
adapter->alloc_rx_buf(adapter);
@@ -3371,11 +3373,12 @@ e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
static int
e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct mii_ioctl_data *data = if_mii(ifr);
int retval;
uint16_t mii_reg;
uint16_t spddplx;
+ unsigned long flags;
if(adapter->hw.media_type != e1000_media_type_copper)
return -EOPNOTSUPP;
@@ -3385,22 +3388,29 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
data->phy_id = adapter->hw.phy_addr;
break;
case SIOCGMIIREG:
- if (!capable(CAP_NET_ADMIN))
+ if(!capable(CAP_NET_ADMIN))
return -EPERM;
- if (e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
- &data->val_out))
+ spin_lock_irqsave(&adapter->stats_lock, flags);
+ if(e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
+ &data->val_out)) {
+ spin_unlock_irqrestore(&adapter->stats_lock, flags);
return -EIO;
+ }
+ spin_unlock_irqrestore(&adapter->stats_lock, flags);
break;
case SIOCSMIIREG:
- if (!capable(CAP_NET_ADMIN))
+ if(!capable(CAP_NET_ADMIN))
return -EPERM;
- if (data->reg_num & ~(0x1F))
+ if(data->reg_num & ~(0x1F))
return -EFAULT;
mii_reg = data->val_in;
- if (e1000_write_phy_reg(&adapter->hw, data->reg_num,
- mii_reg))
+ spin_lock_irqsave(&adapter->stats_lock, flags);
+ if(e1000_write_phy_reg(&adapter->hw, data->reg_num,
+ mii_reg)) {
+ spin_unlock_irqrestore(&adapter->stats_lock, flags);
return -EIO;
- if (adapter->hw.phy_type == e1000_phy_m88) {
+ }
+ if(adapter->hw.phy_type == e1000_phy_m88) {
switch (data->reg_num) {
case PHY_CTRL:
if(mii_reg & MII_CR_POWER_DOWN)
@@ -3420,8 +3430,12 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
HALF_DUPLEX;
retval = e1000_set_spd_dplx(adapter,
spddplx);
- if(retval)
+ if(retval) {
+ spin_unlock_irqrestore(
+ &adapter->stats_lock,
+ flags);
return retval;
+ }
}
if(netif_running(adapter->netdev)) {
e1000_down(adapter);
@@ -3431,8 +3445,11 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
break;
case M88E1000_PHY_SPEC_CTRL:
case M88E1000_EXT_PHY_SPEC_CTRL:
- if (e1000_phy_reset(&adapter->hw))
+ if(e1000_phy_reset(&adapter->hw)) {
+ spin_unlock_irqrestore(
+ &adapter->stats_lock, flags);
return -EIO;
+ }
break;
}
} else {
@@ -3448,6 +3465,7 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
break;
}
}
+ spin_unlock_irqrestore(&adapter->stats_lock, flags);
break;
default:
return -EOPNOTSUPP;
@@ -3504,7 +3522,7 @@ e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value)
static void
e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t ctrl, rctl;
e1000_irq_disable(adapter);
@@ -3544,7 +3562,7 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
static void
e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t vfta, index;
if((adapter->hw.mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
@@ -3560,7 +3578,7 @@ e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
static void
e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t vfta, index;
e1000_irq_disable(adapter);
@@ -3601,6 +3619,13 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx)
{
adapter->hw.autoneg = 0;
+ /* Fiber NICs only allow 1000 gbps Full duplex */
+ if((adapter->hw.media_type == e1000_media_type_fiber) &&
+ spddplx != (SPEED_1000 + DUPLEX_FULL)) {
+ DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n");
+ return -EINVAL;
+ }
+
switch(spddplx) {
case SPEED_10 + DUPLEX_HALF:
adapter->hw.forced_speed_duplex = e1000_10_half;
@@ -3647,7 +3672,7 @@ static int
e1000_suspend(struct pci_dev *pdev, uint32_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t ctrl, ctrl_ext, rctl, manc, status, swsm;
uint32_t wufc = adapter->wol;
@@ -3740,12 +3765,12 @@ static int
e1000_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct e1000_adapter *adapter = netdev->priv;
- uint32_t manc, ret, swsm;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ uint32_t manc, ret_val, swsm;
pci_set_power_state(pdev, 0);
pci_restore_state(pdev);
- ret = pci_enable_device(pdev);
+ ret_val = pci_enable_device(pdev);
pci_set_master(pdev);
pci_enable_wake(pdev, 3, 0);
@@ -3788,7 +3813,7 @@ e1000_resume(struct pci_dev *pdev)
static void
e1000_netpoll(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
disable_irq(adapter->pdev->irq);
e1000_intr(adapter->pdev->irq, netdev, NULL);
enable_irq(adapter->pdev->irq);
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 4ebcd052e150..64f0f697c958 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -82,6 +82,9 @@
* 0.31: 14 Nov 2004: ethtool support for getting/setting link
* capabilities.
* 0.32: 16 Apr 2005: RX_ERROR4 handling added.
+ * 0.33: 16 May 2005: Support for MCP51 added.
+ * 0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics.
+ * 0.35: 26 Jun 2005: Support for MCP55 added.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -93,7 +96,7 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
-#define FORCEDETH_VERSION "0.32"
+#define FORCEDETH_VERSION "0.35"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -2005,7 +2008,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
/* handle different descriptor versions */
if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 ||
pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 ||
- pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3)
+ pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3 ||
+ pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
+ pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_13)
np->desc_ver = DESC_VER_1;
else
np->desc_ver = DESC_VER_2;
@@ -2215,56 +2220,84 @@ static struct pci_device_id pci_tbl[] = {
.device = PCI_DEVICE_ID_NVIDIA_NVENET_4,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
},
{ /* nForce3 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_5,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
},
{ /* nForce3 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_6,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
},
{ /* nForce3 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_7,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
},
{ /* CK804 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_8,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
},
{ /* CK804 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_9,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
},
{ /* MCP04 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_10,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
},
{ /* MCP04 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_11,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+ },
+ { /* MCP51 Ethernet Controller */
+ .vendor = PCI_VENDOR_ID_NVIDIA,
+ .device = PCI_DEVICE_ID_NVIDIA_NVENET_12,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+ },
+ { /* MCP51 Ethernet Controller */
+ .vendor = PCI_VENDOR_ID_NVIDIA,
+ .device = PCI_DEVICE_ID_NVIDIA_NVENET_13,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+ },
+ { /* MCP55 Ethernet Controller */
+ .vendor = PCI_VENDOR_ID_NVIDIA,
+ .device = PCI_DEVICE_ID_NVIDIA_NVENET_14,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+ },
+ { /* MCP55 Ethernet Controller */
+ .vendor = PCI_VENDOR_ID_NVIDIA,
+ .device = PCI_DEVICE_ID_NVIDIA_NVENET_15,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
},
{0,},
};
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index b43b2b11aacd..6518334b9280 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -1,4 +1,4 @@
-/*
+/*
* drivers/net/gianfar.c
*
* Gianfar Ethernet Driver
@@ -22,10 +22,9 @@
* B-V +1.62
*
* Theory of operation
- * This driver is designed for the Triple-speed Ethernet
- * controllers on the Freescale 8540/8560 integrated processors,
- * as well as the Fast Ethernet Controller on the 8540.
- *
+ * This driver is designed for the non-CPM ethernet controllers
+ * on the 85xx and 83xx family of integrated processors
+ *
* The driver is initialized through platform_device. Structures which
* define the configuration needed by the board are defined in a
* board structure in arch/ppc/platforms (though I do not
@@ -39,12 +38,12 @@
*
* The Gianfar Ethernet Controller uses a ring of buffer
* descriptors. The beginning is indicated by a register
- * pointing to the physical address of the start of the ring.
- * The end is determined by a "wrap" bit being set in the
+ * pointing to the physical address of the start of the ring.
+ * The end is determined by a "wrap" bit being set in the
* last descriptor of the ring.
*
* When a packet is received, the RXF bit in the
- * IEVENT register is set, triggering an interrupt when the
+ * IEVENT register is set, triggering an interrupt when the
* corresponding bit in the IMASK register is also set (if
* interrupt coalescing is active, then the interrupt may not
* happen immediately, but will wait until either a set number
@@ -52,7 +51,7 @@
* interrupt handler will signal there is work to be done, and
* exit. Without NAPI, the packet(s) will be handled
* immediately. Both methods will start at the last known empty
- * descriptor, and process every subsequent descriptor until there
+ * descriptor, and process every subsequent descriptor until there
* are none left with data (NAPI will stop after a set number of
* packets to give time to other tasks, but will eventually
* process all the packets). The data arrives inside a
@@ -83,9 +82,13 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/if_vlan.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/device.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -123,7 +126,7 @@ static int gfar_set_mac_address(struct net_device *dev);
static int gfar_change_mtu(struct net_device *dev, int new_mtu);
static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);
-irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void gfar_phy_change(void *data);
@@ -139,9 +142,12 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
#ifdef CONFIG_GFAR_NAPI
static int gfar_poll(struct net_device *dev, int *budget);
#endif
-static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
+int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
static void gfar_phy_startup_timer(unsigned long data);
+static void gfar_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp);
+static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
extern struct ethtool_ops gfar_ethtool_ops;
@@ -149,6 +155,13 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc");
MODULE_DESCRIPTION("Gianfar Ethernet Driver");
MODULE_LICENSE("GPL");
+int gfar_uses_fcb(struct gfar_private *priv)
+{
+ if (priv->vlan_enable || priv->rx_csum_enable)
+ return 1;
+ else
+ return 0;
+}
static int gfar_probe(struct device *device)
{
u32 tempval;
@@ -159,7 +172,6 @@ static int gfar_probe(struct device *device)
struct resource *r;
int idx;
int err = 0;
- int dev_ethtool_ops = 0;
einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
@@ -265,15 +277,69 @@ static int gfar_probe(struct device *device)
dev->mtu = 1500;
dev->set_multicast_list = gfar_set_multi;
- /* Index into the array of possible ethtool
- * ops to catch all 4 possibilities */
- if((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) == 0)
- dev_ethtool_ops += 1;
+ dev->ethtool_ops = &gfar_ethtool_ops;
+
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
+ priv->rx_csum_enable = 1;
+ dev->features |= NETIF_F_IP_CSUM;
+ } else
+ priv->rx_csum_enable = 0;
+
+ priv->vlgrp = NULL;
- if((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE) == 0)
- dev_ethtool_ops += 2;
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
+ dev->vlan_rx_register = gfar_vlan_rx_register;
+ dev->vlan_rx_kill_vid = gfar_vlan_rx_kill_vid;
- dev->ethtool_ops = gfar_op_array[dev_ethtool_ops];
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+
+ priv->vlan_enable = 1;
+ }
+
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
+ priv->extended_hash = 1;
+ priv->hash_width = 9;
+
+ priv->hash_regs[0] = &priv->regs->igaddr0;
+ priv->hash_regs[1] = &priv->regs->igaddr1;
+ priv->hash_regs[2] = &priv->regs->igaddr2;
+ priv->hash_regs[3] = &priv->regs->igaddr3;
+ priv->hash_regs[4] = &priv->regs->igaddr4;
+ priv->hash_regs[5] = &priv->regs->igaddr5;
+ priv->hash_regs[6] = &priv->regs->igaddr6;
+ priv->hash_regs[7] = &priv->regs->igaddr7;
+ priv->hash_regs[8] = &priv->regs->gaddr0;
+ priv->hash_regs[9] = &priv->regs->gaddr1;
+ priv->hash_regs[10] = &priv->regs->gaddr2;
+ priv->hash_regs[11] = &priv->regs->gaddr3;
+ priv->hash_regs[12] = &priv->regs->gaddr4;
+ priv->hash_regs[13] = &priv->regs->gaddr5;
+ priv->hash_regs[14] = &priv->regs->gaddr6;
+ priv->hash_regs[15] = &priv->regs->gaddr7;
+
+ } else {
+ priv->extended_hash = 0;
+ priv->hash_width = 8;
+
+ priv->hash_regs[0] = &priv->regs->gaddr0;
+ priv->hash_regs[1] = &priv->regs->gaddr1;
+ priv->hash_regs[2] = &priv->regs->gaddr2;
+ priv->hash_regs[3] = &priv->regs->gaddr3;
+ priv->hash_regs[4] = &priv->regs->gaddr4;
+ priv->hash_regs[5] = &priv->regs->gaddr5;
+ priv->hash_regs[6] = &priv->regs->gaddr6;
+ priv->hash_regs[7] = &priv->regs->gaddr7;
+ }
+
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_PADDING)
+ priv->padding = DEFAULT_PADDING;
+ else
+ priv->padding = 0;
+
+ dev->hard_header_len += priv->padding;
+
+ if (dev->features & NETIF_F_IP_CSUM)
+ dev->hard_header_len += GMAC_FCB_LEN;
priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
#ifdef CONFIG_GFAR_BUFSTASH
@@ -289,6 +355,9 @@ static int gfar_probe(struct device *device)
priv->rxcount = DEFAULT_RXCOUNT;
priv->rxtime = DEFAULT_RXTIME;
+ /* Enable most messages by default */
+ priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+
err = register_netdev(dev);
if (err) {
@@ -360,8 +429,9 @@ static int init_phy(struct net_device *dev)
GFP_KERNEL);
if(NULL == mii_info) {
- printk(KERN_ERR "%s: Could not allocate mii_info\n",
- dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: Could not allocate mii_info\n",
+ dev->name);
return -ENOMEM;
}
@@ -410,7 +480,8 @@ static int init_phy(struct net_device *dev)
curphy = get_phy_info(priv->mii_info);
if (curphy == NULL) {
- printk(KERN_ERR "%s: No PHY found\n", dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: No PHY found\n", dev->name);
err = -1;
goto no_phy;
}
@@ -421,7 +492,7 @@ static int init_phy(struct net_device *dev)
if(curphy->init) {
err = curphy->init(priv->mii_info);
- if (err)
+ if (err)
goto phy_init_fail;
}
@@ -446,14 +517,14 @@ static void init_registers(struct net_device *dev)
gfar_write(&priv->regs->imask, IMASK_INIT_CLEAR);
/* Init hash registers to zero */
- gfar_write(&priv->regs->iaddr0, 0);
- gfar_write(&priv->regs->iaddr1, 0);
- gfar_write(&priv->regs->iaddr2, 0);
- gfar_write(&priv->regs->iaddr3, 0);
- gfar_write(&priv->regs->iaddr4, 0);
- gfar_write(&priv->regs->iaddr5, 0);
- gfar_write(&priv->regs->iaddr6, 0);
- gfar_write(&priv->regs->iaddr7, 0);
+ gfar_write(&priv->regs->igaddr0, 0);
+ gfar_write(&priv->regs->igaddr1, 0);
+ gfar_write(&priv->regs->igaddr2, 0);
+ gfar_write(&priv->regs->igaddr3, 0);
+ gfar_write(&priv->regs->igaddr4, 0);
+ gfar_write(&priv->regs->igaddr5, 0);
+ gfar_write(&priv->regs->igaddr6, 0);
+ gfar_write(&priv->regs->igaddr7, 0);
gfar_write(&priv->regs->gaddr0, 0);
gfar_write(&priv->regs->gaddr1, 0);
@@ -464,9 +535,6 @@ static void init_registers(struct net_device *dev)
gfar_write(&priv->regs->gaddr6, 0);
gfar_write(&priv->regs->gaddr7, 0);
- /* Zero out rctrl */
- gfar_write(&priv->regs->rctrl, 0x00000000);
-
/* Zero out the rmon mib registers if it has them */
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
memset((void *) &(priv->regs->rmon), 0,
@@ -497,20 +565,14 @@ static void init_registers(struct net_device *dev)
gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
}
-void stop_gfar(struct net_device *dev)
+
+/* Halt the receive and transmit queues */
+void gfar_halt(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar *regs = priv->regs;
- unsigned long flags;
u32 tempval;
- /* Lock it down */
- spin_lock_irqsave(&priv->lock, flags);
-
- /* Tell the kernel the link is down */
- priv->mii_info->link = 0;
- adjust_link(dev);
-
/* Mask all interrupts */
gfar_write(&regs->imask, IMASK_INIT_CLEAR);
@@ -533,13 +595,29 @@ void stop_gfar(struct net_device *dev)
tempval = gfar_read(&regs->maccfg1);
tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
gfar_write(&regs->maccfg1, tempval);
+}
+
+void stop_gfar(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ struct gfar *regs = priv->regs;
+ unsigned long flags;
+
+ /* Lock it down */
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Tell the kernel the link is down */
+ priv->mii_info->link = 0;
+ adjust_link(dev);
+
+ gfar_halt(dev);
if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
/* Clear any pending interrupts */
mii_clear_phy_interrupt(priv->mii_info);
/* Disable PHY Interrupts */
- mii_configure_phy_interrupt(priv->mii_info,
+ mii_configure_phy_interrupt(priv->mii_info,
MII_INTERRUPT_DISABLED);
}
@@ -566,7 +644,7 @@ void stop_gfar(struct net_device *dev)
sizeof(struct txbd8)*priv->tx_ring_size
+ sizeof(struct rxbd8)*priv->rx_ring_size,
priv->tx_bd_base,
- gfar_read(&regs->tbase));
+ gfar_read(&regs->tbase0));
}
/* If there are any tx skbs or rx skbs still around, free them.
@@ -620,6 +698,34 @@ void free_skb_resources(struct gfar_private *priv)
}
}
+void gfar_start(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ struct gfar *regs = priv->regs;
+ u32 tempval;
+
+ /* Enable Rx and Tx in MACCFG1 */
+ tempval = gfar_read(&regs->maccfg1);
+ tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
+ gfar_write(&regs->maccfg1, tempval);
+
+ /* Initialize DMACTRL to have WWR and WOP */
+ tempval = gfar_read(&priv->regs->dmactrl);
+ tempval |= DMACTRL_INIT_SETTINGS;
+ gfar_write(&priv->regs->dmactrl, tempval);
+
+ /* Clear THLT, so that the DMA starts polling now */
+ gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+
+ /* Make sure we aren't stopped */
+ tempval = gfar_read(&priv->regs->dmactrl);
+ tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
+ gfar_write(&priv->regs->dmactrl, tempval);
+
+ /* Unmask the interrupts we look for */
+ gfar_write(&regs->imask, IMASK_DEFAULT);
+}
+
/* Bring the controller up and running */
int startup_gfar(struct net_device *dev)
{
@@ -630,33 +736,34 @@ int startup_gfar(struct net_device *dev)
int i;
struct gfar_private *priv = netdev_priv(dev);
struct gfar *regs = priv->regs;
- u32 tempval;
int err = 0;
+ u32 rctrl = 0;
gfar_write(&regs->imask, IMASK_INIT_CLEAR);
/* Allocate memory for the buffer descriptors */
- vaddr = (unsigned long) dma_alloc_coherent(NULL,
+ vaddr = (unsigned long) dma_alloc_coherent(NULL,
sizeof (struct txbd8) * priv->tx_ring_size +
sizeof (struct rxbd8) * priv->rx_ring_size,
&addr, GFP_KERNEL);
if (vaddr == 0) {
- printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
- dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
+ dev->name);
return -ENOMEM;
}
priv->tx_bd_base = (struct txbd8 *) vaddr;
/* enet DMA only understands physical addresses */
- gfar_write(&regs->tbase, addr);
+ gfar_write(&regs->tbase0, addr);
/* Start the rx descriptor ring where the tx ring leaves off */
addr = addr + sizeof (struct txbd8) * priv->tx_ring_size;
vaddr = vaddr + sizeof (struct txbd8) * priv->tx_ring_size;
priv->rx_bd_base = (struct rxbd8 *) vaddr;
- gfar_write(&regs->rbase, addr);
+ gfar_write(&regs->rbase0, addr);
/* Setup the skbuff rings */
priv->tx_skbuff =
@@ -664,8 +771,9 @@ int startup_gfar(struct net_device *dev)
priv->tx_ring_size, GFP_KERNEL);
if (priv->tx_skbuff == NULL) {
- printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
- dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
+ dev->name);
err = -ENOMEM;
goto tx_skb_fail;
}
@@ -678,8 +786,9 @@ int startup_gfar(struct net_device *dev)
priv->rx_ring_size, GFP_KERNEL);
if (priv->rx_skbuff == NULL) {
- printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
- dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
+ dev->name);
err = -ENOMEM;
goto rx_skb_fail;
}
@@ -726,12 +835,13 @@ int startup_gfar(struct net_device *dev)
/* If the device has multiple interrupts, register for
* them. Otherwise, only register for the one */
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
- /* Install our interrupt handlers for Error,
+ /* Install our interrupt handlers for Error,
* Transmit, and Receive */
if (request_irq(priv->interruptError, gfar_error,
0, "enet_error", dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptError);
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d\n",
+ dev->name, priv->interruptError);
err = -1;
goto err_irq_fail;
@@ -739,8 +849,9 @@ int startup_gfar(struct net_device *dev)
if (request_irq(priv->interruptTransmit, gfar_transmit,
0, "enet_tx", dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptTransmit);
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d\n",
+ dev->name, priv->interruptTransmit);
err = -1;
@@ -749,8 +860,9 @@ int startup_gfar(struct net_device *dev)
if (request_irq(priv->interruptReceive, gfar_receive,
0, "enet_rx", dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
- dev->name, priv->interruptReceive);
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
+ dev->name, priv->interruptReceive);
err = -1;
goto rx_irq_fail;
@@ -758,8 +870,9 @@ int startup_gfar(struct net_device *dev)
} else {
if (request_irq(priv->interruptTransmit, gfar_interrupt,
0, "gfar_interrupt", dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptError);
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d\n",
+ dev->name, priv->interruptError);
err = -1;
goto err_irq_fail;
@@ -787,28 +900,22 @@ int startup_gfar(struct net_device *dev)
else
gfar_write(&regs->rxic, 0);
- init_waitqueue_head(&priv->rxcleanupq);
+ if (priv->rx_csum_enable)
+ rctrl |= RCTRL_CHECKSUMMING;
- /* Enable Rx and Tx in MACCFG1 */
- tempval = gfar_read(&regs->maccfg1);
- tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
- gfar_write(&regs->maccfg1, tempval);
+ if (priv->extended_hash)
+ rctrl |= RCTRL_EXTHASH;
- /* Initialize DMACTRL to have WWR and WOP */
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval |= DMACTRL_INIT_SETTINGS;
- gfar_write(&priv->regs->dmactrl, tempval);
+ if (priv->vlan_enable)
+ rctrl |= RCTRL_VLAN;
- /* Clear THLT, so that the DMA starts polling now */
- gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+ /* Init rctrl based on our settings */
+ gfar_write(&priv->regs->rctrl, rctrl);
- /* Make sure we aren't stopped */
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
- gfar_write(&priv->regs->dmactrl, tempval);
+ if (dev->features & NETIF_F_IP_CSUM)
+ gfar_write(&priv->regs->tctrl, TCTRL_INIT_CSUM);
- /* Unmask the interrupts we look for */
- gfar_write(&regs->imask, IMASK_DEFAULT);
+ gfar_start(dev);
return 0;
@@ -824,7 +931,7 @@ tx_skb_fail:
sizeof(struct txbd8)*priv->tx_ring_size
+ sizeof(struct rxbd8)*priv->rx_ring_size,
priv->tx_bd_base,
- gfar_read(&regs->tbase));
+ gfar_read(&regs->tbase0));
if (priv->mii_info->phyinfo->close)
priv->mii_info->phyinfo->close(priv->mii_info);
@@ -857,11 +964,62 @@ static int gfar_enet_open(struct net_device *dev)
return err;
}
+static struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp)
+{
+ struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN);
+
+ memset(fcb, 0, GMAC_FCB_LEN);
+
+ /* Flag the bd so the controller looks for the FCB */
+ bdp->status |= TXBD_TOE;
+
+ return fcb;
+}
+
+static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
+{
+ int len;
+
+ /* If we're here, it's a IP packet with a TCP or UDP
+ * payload. We set it to checksum, using a pseudo-header
+ * we provide
+ */
+ fcb->ip = 1;
+ fcb->tup = 1;
+ fcb->ctu = 1;
+ fcb->nph = 1;
+
+ /* Notify the controller what the protocol is */
+ if (skb->nh.iph->protocol == IPPROTO_UDP)
+ fcb->udp = 1;
+
+ /* l3os is the distance between the start of the
+ * frame (skb->data) and the start of the IP hdr.
+ * l4os is the distance between the start of the
+ * l3 hdr and the l4 hdr */
+ fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN);
+ fcb->l4os = (u16)(skb->h.raw - skb->nh.raw);
+
+ len = skb->nh.iph->tot_len - fcb->l4os;
+
+ /* Provide the pseudoheader csum */
+ fcb->phcs = ~csum_tcpudp_magic(skb->nh.iph->saddr,
+ skb->nh.iph->daddr, len,
+ skb->nh.iph->protocol, 0);
+}
+
+void gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
+{
+ fcb->vln = 1;
+ fcb->vlctl = vlan_tx_tag_get(skb);
+}
+
/* This is called by the kernel when a frame is ready for transmission. */
/* It is pointed to by the dev->hard_start_xmit function pointer */
static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
+ struct txfcb *fcb = NULL;
struct txbd8 *txbdp;
/* Update transmit stats */
@@ -876,9 +1034,24 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Clear all but the WRAP status flags */
txbdp->status &= TXBD_WRAP;
+ /* Set up checksumming */
+ if ((dev->features & NETIF_F_IP_CSUM)
+ && (CHECKSUM_HW == skb->ip_summed)) {
+ fcb = gfar_add_fcb(skb, txbdp);
+ gfar_tx_checksum(skb, fcb);
+ }
+
+ if (priv->vlan_enable &&
+ unlikely(priv->vlgrp && vlan_tx_tag_present(skb))) {
+ if (NULL == fcb)
+ fcb = gfar_add_fcb(skb, txbdp);
+
+ gfar_tx_vlan(skb, fcb);
+ }
+
/* Set buffer length and pointer */
txbdp->length = skb->len;
- txbdp->bufPtr = dma_map_single(NULL, skb->data,
+ txbdp->bufPtr = dma_map_single(NULL, skb->data,
skb->len, DMA_TO_DEVICE);
/* Save the skb pointer so we can free it later */
@@ -972,15 +1145,78 @@ int gfar_set_mac_address(struct net_device *dev)
}
+/* Enables and disables VLAN insertion/extraction */
+static void gfar_vlan_rx_register(struct net_device *dev,
+ struct vlan_group *grp)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ unsigned long flags;
+ u32 tempval;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->vlgrp = grp;
+
+ if (grp) {
+ /* Enable VLAN tag insertion */
+ tempval = gfar_read(&priv->regs->tctrl);
+ tempval |= TCTRL_VLINS;
+
+ gfar_write(&priv->regs->tctrl, tempval);
+
+ /* Enable VLAN tag extraction */
+ tempval = gfar_read(&priv->regs->rctrl);
+ tempval |= RCTRL_VLEX;
+ gfar_write(&priv->regs->rctrl, tempval);
+ } else {
+ /* Disable VLAN tag insertion */
+ tempval = gfar_read(&priv->regs->tctrl);
+ tempval &= ~TCTRL_VLINS;
+ gfar_write(&priv->regs->tctrl, tempval);
+
+ /* Disable VLAN tag extraction */
+ tempval = gfar_read(&priv->regs->rctrl);
+ tempval &= ~RCTRL_VLEX;
+ gfar_write(&priv->regs->rctrl, tempval);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->vlgrp)
+ priv->vlgrp->vlan_devices[vid] = NULL;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
static int gfar_change_mtu(struct net_device *dev, int new_mtu)
{
int tempsize, tempval;
struct gfar_private *priv = netdev_priv(dev);
int oldsize = priv->rx_buffer_size;
- int frame_size = new_mtu + 18;
+ int frame_size = new_mtu + ETH_HLEN;
+
+ if (priv->vlan_enable)
+ frame_size += VLAN_ETH_HLEN;
+
+ if (gfar_uses_fcb(priv))
+ frame_size += GMAC_FCB_LEN;
+
+ frame_size += priv->padding;
if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
- printk(KERN_ERR "%s: Invalid MTU setting\n", dev->name);
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: Invalid MTU setting\n",
+ dev->name);
return -EINVAL;
}
@@ -1120,7 +1356,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
skb->dev = dev;
bdp->bufPtr = dma_map_single(NULL, skb->data,
- priv->rx_buffer_size + RXBUF_ALIGNMENT,
+ priv->rx_buffer_size + RXBUF_ALIGNMENT,
DMA_FROM_DEVICE);
bdp->length = 0;
@@ -1190,11 +1426,10 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
__netif_rx_schedule(dev);
} else {
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
- dev->name, gfar_read(&priv->regs->ievent),
- gfar_read(&priv->regs->imask));
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
+ dev->name, gfar_read(&priv->regs->ievent),
+ gfar_read(&priv->regs->imask));
}
#else
@@ -1209,15 +1444,43 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
else
gfar_write(&priv->regs->rxic, 0);
- /* Just in case we need to wake the ring param changer */
- priv->rxclean = 1;
-
spin_unlock(&priv->lock);
#endif
return IRQ_HANDLED;
}
+static inline int gfar_rx_vlan(struct sk_buff *skb,
+ struct vlan_group *vlgrp, unsigned short vlctl)
+{
+#ifdef CONFIG_GFAR_NAPI
+ return vlan_hwaccel_receive_skb(skb, vlgrp, vlctl);
+#else
+ return vlan_hwaccel_rx(skb, vlgrp, vlctl);
+#endif
+}
+
+static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
+{
+ /* If valid headers were found, and valid sums
+ * were verified, then we tell the kernel that no
+ * checksumming is necessary. Otherwise, it is */
+ if (fcb->cip && !fcb->eip && fcb->ctu && !fcb->etu)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+}
+
+
+static inline struct rxfcb *gfar_get_fcb(struct sk_buff *skb)
+{
+ struct rxfcb *fcb = (struct rxfcb *)skb->data;
+
+ /* Remove the FCB from the skb */
+ skb_pull(skb, GMAC_FCB_LEN);
+
+ return fcb;
+}
/* gfar_process_frame() -- handle one incoming packet if skb
* isn't NULL. */
@@ -1225,35 +1488,51 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
int length)
{
struct gfar_private *priv = netdev_priv(dev);
+ struct rxfcb *fcb = NULL;
if (skb == NULL) {
-#ifdef BRIEF_GFAR_ERRORS
- printk(KERN_WARNING "%s: Missing skb!!.\n",
- dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
priv->stats.rx_dropped++;
priv->extra_stats.rx_skbmissing++;
} else {
+ int ret;
+
/* Prep the skb for the packet */
skb_put(skb, length);
+ /* Grab the FCB if there is one */
+ if (gfar_uses_fcb(priv))
+ fcb = gfar_get_fcb(skb);
+
+ /* Remove the padded bytes, if there are any */
+ if (priv->padding)
+ skb_pull(skb, priv->padding);
+
+ if (priv->rx_csum_enable)
+ gfar_rx_checksum(skb, fcb);
+
/* Tell the skb what kind of packet this is */
skb->protocol = eth_type_trans(skb, dev);
/* Send the packet up the stack */
- if (RECEIVE(skb) == NET_RX_DROP) {
+ if (unlikely(priv->vlgrp && fcb->vln))
+ ret = gfar_rx_vlan(skb, priv->vlgrp, fcb->vlctl);
+ else
+ ret = RECEIVE(skb);
+
+ if (NET_RX_DROP == ret)
priv->extra_stats.kernel_dropped++;
- }
}
return 0;
}
/* gfar_clean_rx_ring() -- Processes each frame in the rx ring
- * until the budget/quota has been reached. Returns the number
+ * until the budget/quota has been reached. Returns the number
* of frames handled
*/
-static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
+int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
{
struct rxbd8 *bdp;
struct sk_buff *skb;
@@ -1355,9 +1634,6 @@ static int gfar_poll(struct net_device *dev, int *budget)
mk_ic_value(priv->rxcount, priv->rxtime));
else
gfar_write(&priv->regs->rxic, 0);
-
- /* Signal to the ring size changer that it's safe to go */
- priv->rxclean = 1;
}
return (rx_work_limit < 0) ? 1 : 0;
@@ -1393,10 +1669,8 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (events & IEVENT_CRL)
priv->stats.tx_aborted_errors++;
if (events & IEVENT_XFUN) {
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_WARNING "%s: tx underrun. dropped packet\n",
- dev->name);
-#endif
+ if (netif_msg_tx_err(priv))
+ printk(KERN_WARNING "%s: tx underrun. dropped packet\n", dev->name);
priv->stats.tx_dropped++;
priv->extra_stats.tx_underrun++;
@@ -1415,36 +1689,30 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
#endif
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name,
- gfar_read(&priv->regs->rstat));
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
+ dev->name,
+ gfar_read(&priv->regs->rstat));
}
if (events & IEVENT_BABR) {
priv->stats.rx_errors++;
priv->extra_stats.rx_babr++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: babbling error\n", dev->name);
}
if (events & IEVENT_EBERR) {
priv->extra_stats.eberr++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-#endif
- }
- if (events & IEVENT_RXC) {
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: control frame\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: EBERR\n", dev->name);
}
+ if ((events & IEVENT_RXC) && (netif_msg_rx_err(priv)))
+ printk(KERN_DEBUG "%s: control frame\n", dev->name);
if (events & IEVENT_BABT) {
priv->extra_stats.tx_babt++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: babt error\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: babt error\n", dev->name);
}
return IRQ_HANDLED;
@@ -1510,7 +1778,7 @@ static void gfar_phy_timer(unsigned long data)
* If, after GFAR_AN_TIMEOUT seconds, it has not
* finished, we switch to forced.
* Either way, once the process has completed, we either
- * request the interrupt, or switch the timer over to
+ * request the interrupt, or switch the timer over to
* using gfar_phy_timer to check status */
static void gfar_phy_startup_timer(unsigned long data)
{
@@ -1535,8 +1803,9 @@ static void gfar_phy_startup_timer(unsigned long data)
/* Forcing failed! Give up */
if(result) {
- printk(KERN_ERR "%s: Forcing failed!\n",
- mii_info->dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_ERR "%s: Forcing failed!\n",
+ mii_info->dev->name);
return;
}
}
@@ -1546,16 +1815,17 @@ static void gfar_phy_startup_timer(unsigned long data)
/* Grab the PHY interrupt, if necessary/possible */
if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
- if (request_irq(priv->einfo->interruptPHY,
+ if (request_irq(priv->einfo->interruptPHY,
phy_interrupt,
- SA_SHIRQ,
- "phy_interrupt",
+ SA_SHIRQ,
+ "phy_interrupt",
mii_info->dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
- mii_info->dev->name,
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
+ mii_info->dev->name,
priv->einfo->interruptPHY);
} else {
- mii_configure_phy_interrupt(priv->mii_info,
+ mii_configure_phy_interrupt(priv->mii_info,
MII_INTERRUPT_ENABLED);
return;
}
@@ -1592,15 +1862,17 @@ static void adjust_link(struct net_device *dev)
tempval &= ~(MACCFG2_FULL_DUPLEX);
gfar_write(&regs->maccfg2, tempval);
- printk(KERN_INFO "%s: Half Duplex\n",
- dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Half Duplex\n",
+ dev->name);
} else {
tempval = gfar_read(&regs->maccfg2);
tempval |= MACCFG2_FULL_DUPLEX;
gfar_write(&regs->maccfg2, tempval);
- printk(KERN_INFO "%s: Full Duplex\n",
- dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Full Duplex\n",
+ dev->name);
}
priv->oldduplex = mii_info->duplex;
@@ -1622,27 +1894,32 @@ static void adjust_link(struct net_device *dev)
gfar_write(&regs->maccfg2, tempval);
break;
default:
- printk(KERN_WARNING
- "%s: Ack! Speed (%d) is not 10/100/1000!\n",
- dev->name, mii_info->speed);
+ if (netif_msg_link(priv))
+ printk(KERN_WARNING
+ "%s: Ack! Speed (%d) is not 10/100/1000!\n",
+ dev->name, mii_info->speed);
break;
}
- printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
- mii_info->speed);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
+ mii_info->speed);
priv->oldspeed = mii_info->speed;
}
if (!priv->oldlink) {
- printk(KERN_INFO "%s: Link is up\n", dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Link is up\n", dev->name);
priv->oldlink = 1;
netif_carrier_on(dev);
netif_schedule(dev);
}
} else {
if (priv->oldlink) {
- printk(KERN_INFO "%s: Link is down\n", dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Link is down\n",
+ dev->name);
priv->oldlink = 0;
priv->oldspeed = 0;
priv->oldduplex = -1;
@@ -1664,8 +1941,9 @@ static void gfar_set_multi(struct net_device *dev)
u32 tempval;
if(dev->flags & IFF_PROMISC) {
- printk(KERN_INFO "%s: Entering promiscuous mode.\n",
- dev->name);
+ if (netif_msg_drv(priv))
+ printk(KERN_INFO "%s: Entering promiscuous mode.\n",
+ dev->name);
/* Set RCTRL to PROM */
tempval = gfar_read(&regs->rctrl);
tempval |= RCTRL_PROM;
@@ -1679,6 +1957,14 @@ static void gfar_set_multi(struct net_device *dev)
if(dev->flags & IFF_ALLMULTI) {
/* Set the hash to rx all multicast frames */
+ gfar_write(&regs->igaddr0, 0xffffffff);
+ gfar_write(&regs->igaddr1, 0xffffffff);
+ gfar_write(&regs->igaddr2, 0xffffffff);
+ gfar_write(&regs->igaddr3, 0xffffffff);
+ gfar_write(&regs->igaddr4, 0xffffffff);
+ gfar_write(&regs->igaddr5, 0xffffffff);
+ gfar_write(&regs->igaddr6, 0xffffffff);
+ gfar_write(&regs->igaddr7, 0xffffffff);
gfar_write(&regs->gaddr0, 0xffffffff);
gfar_write(&regs->gaddr1, 0xffffffff);
gfar_write(&regs->gaddr2, 0xffffffff);
@@ -1689,6 +1975,14 @@ static void gfar_set_multi(struct net_device *dev)
gfar_write(&regs->gaddr7, 0xffffffff);
} else {
/* zero out the hash */
+ gfar_write(&regs->igaddr0, 0x0);
+ gfar_write(&regs->igaddr1, 0x0);
+ gfar_write(&regs->igaddr2, 0x0);
+ gfar_write(&regs->igaddr3, 0x0);
+ gfar_write(&regs->igaddr4, 0x0);
+ gfar_write(&regs->igaddr5, 0x0);
+ gfar_write(&regs->igaddr6, 0x0);
+ gfar_write(&regs->igaddr7, 0x0);
gfar_write(&regs->gaddr0, 0x0);
gfar_write(&regs->gaddr1, 0x0);
gfar_write(&regs->gaddr2, 0x0);
@@ -1727,16 +2021,15 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
{
u32 tempval;
struct gfar_private *priv = netdev_priv(dev);
- struct gfar *regs = priv->regs;
- u32 *hash = &regs->gaddr0;
u32 result = ether_crc(MAC_ADDR_LEN, addr);
- u8 whichreg = ((result >> 29) & 0x7);
- u8 whichbit = ((result >> 24) & 0x1f);
+ int width = priv->hash_width;
+ u8 whichbit = (result >> (32 - width)) & 0x1f;
+ u8 whichreg = result >> (32 - width + 5);
u32 value = (1 << (31-whichbit));
- tempval = gfar_read(&hash[whichreg]);
+ tempval = gfar_read(priv->hash_regs[whichreg]);
tempval |= value;
- gfar_write(&hash[whichreg], tempval);
+ gfar_write(priv->hash_regs[whichreg], tempval);
return;
}
@@ -1754,10 +2047,9 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK);
/* Hmm... */
-#if defined (BRIEF_GFAR_ERRORS) || defined (VERBOSE_GFAR_ERRORS)
- printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
- dev->name, events, gfar_read(&priv->regs->imask));
-#endif
+ if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
+ printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
+ dev->name, events, gfar_read(&priv->regs->imask));
/* Update the error counters */
if (events & IEVENT_TXE) {
@@ -1768,19 +2060,17 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
if (events & IEVENT_CRL)
priv->stats.tx_aborted_errors++;
if (events & IEVENT_XFUN) {
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: underrun. packet dropped.\n",
- dev->name);
-#endif
+ if (netif_msg_tx_err(priv))
+ printk(KERN_DEBUG "%s: underrun. packet dropped.\n",
+ dev->name);
priv->stats.tx_dropped++;
priv->extra_stats.tx_underrun++;
/* Reactivate the Tx Queues */
gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
}
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
-#endif
+ if (netif_msg_tx_err(priv))
+ printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
}
if (events & IEVENT_BSY) {
priv->stats.rx_errors++;
@@ -1793,35 +2083,31 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
#endif
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name,
- gfar_read(&priv->regs->rstat));
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
+ dev->name,
+ gfar_read(&priv->regs->rstat));
}
if (events & IEVENT_BABR) {
priv->stats.rx_errors++;
priv->extra_stats.rx_babr++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: babbling error\n", dev->name);
}
if (events & IEVENT_EBERR) {
priv->extra_stats.eberr++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: EBERR\n", dev->name);
}
- if (events & IEVENT_RXC)
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: control frame\n", dev->name);
-#endif
+ if ((events & IEVENT_RXC) && netif_msg_rx_status(priv))
+ if (netif_msg_rx_status(priv))
+ printk(KERN_DEBUG "%s: control frame\n", dev->name);
if (events & IEVENT_BABT) {
priv->extra_stats.tx_babt++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: babt error\n", dev->name);
-#endif
+ if (netif_msg_tx_err(priv))
+ printk(KERN_DEBUG "%s: babt error\n", dev->name);
}
return IRQ_HANDLED;
}
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index c2f783a6a9fa..28af087d9fbb 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -1,4 +1,4 @@
-/*
+/*
* drivers/net/gianfar.h
*
* Gianfar Ethernet Driver
@@ -53,6 +53,12 @@
/* The maximum number of packets to be handled in one call of gfar_poll */
#define GFAR_DEV_WEIGHT 64
+/* Length for FCB */
+#define GMAC_FCB_LEN 8
+
+/* Default padding amount */
+#define DEFAULT_PADDING 2
+
/* Number of bytes to align the rx bufs to */
#define RXBUF_ALIGNMENT 64
@@ -91,7 +97,7 @@ extern const char gfar_driver_version[];
#define JUMBO_FRAME_SIZE 9600
/* Latency of interface clock in nanoseconds */
-/* Interface clock latency , in this case, means the
+/* Interface clock latency , in this case, means the
* time described by a value of 1 in the interrupt
* coalescing registers' time fields. Since those fields
* refer to the time it takes for 64 clocks to pass, the
@@ -166,9 +172,28 @@ extern const char gfar_driver_version[];
mk_ic_icft(count) | \
mk_ic_ictt(time))
+#define RCTRL_PAL_MASK 0x001f0000
+#define RCTRL_VLEX 0x00002000
+#define RCTRL_FILREN 0x00001000
+#define RCTRL_GHTX 0x00000400
+#define RCTRL_IPCSEN 0x00000200
+#define RCTRL_TUCSEN 0x00000100
+#define RCTRL_PRSDEP_MASK 0x000000c0
+#define RCTRL_PRSDEP_INIT 0x000000c0
#define RCTRL_PROM 0x00000008
+#define RCTRL_CHECKSUMMING (RCTRL_IPCSEN \
+ | RCTRL_TUCSEN | RCTRL_PRSDEP_INIT)
+#define RCTRL_EXTHASH (RCTRL_GHTX)
+#define RCTRL_VLAN (RCTRL_PRSDEP_INIT)
+
+
#define RSTAT_CLEAR_RHALT 0x00800000
+#define TCTRL_IPCSEN 0x00004000
+#define TCTRL_TUCSEN 0x00002000
+#define TCTRL_VLINS 0x00001000
+#define TCTRL_INIT_CSUM (TCTRL_TUCSEN | TCTRL_IPCSEN)
+
#define IEVENT_INIT_CLEAR 0xffffffff
#define IEVENT_BABR 0x80000000
#define IEVENT_RXC 0x40000000
@@ -187,12 +212,16 @@ extern const char gfar_driver_version[];
#define IEVENT_RXB0 0x00008000
#define IEVENT_GRSC 0x00000100
#define IEVENT_RXF0 0x00000080
+#define IEVENT_FIR 0x00000008
+#define IEVENT_FIQ 0x00000004
+#define IEVENT_DPE 0x00000002
+#define IEVENT_PERR 0x00000001
#define IEVENT_RX_MASK (IEVENT_RXB0 | IEVENT_RXF0)
#define IEVENT_TX_MASK (IEVENT_TXB | IEVENT_TXF)
#define IEVENT_ERR_MASK \
(IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \
IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \
- | IEVENT_CRL | IEVENT_XFUN)
+ | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR)
#define IMASK_INIT_CLEAR 0x00000000
#define IMASK_BABR 0x80000000
@@ -212,10 +241,15 @@ extern const char gfar_driver_version[];
#define IMASK_RXB0 0x00008000
#define IMASK_GTSC 0x00000100
#define IMASK_RXFEN0 0x00000080
+#define IMASK_FIR 0x00000008
+#define IMASK_FIQ 0x00000004
+#define IMASK_DPE 0x00000002
+#define IMASK_PERR 0x00000001
#define IMASK_RX_DISABLED ~(IMASK_RXFEN0 | IMASK_BSY)
#define IMASK_DEFAULT (IMASK_TXEEN | IMASK_TXFEN | IMASK_TXBEN | \
IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \
- IMASK_XFUN | IMASK_RXC | IMASK_BABT)
+ IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
+ | IMASK_PERR)
/* Attribute fields */
@@ -254,6 +288,18 @@ extern const char gfar_driver_version[];
#define TXBD_RETRYLIMIT 0x0040
#define TXBD_RETRYCOUNTMASK 0x003c
#define TXBD_UNDERRUN 0x0002
+#define TXBD_TOE 0x0002
+
+/* Tx FCB param bits */
+#define TXFCB_VLN 0x80
+#define TXFCB_IP 0x40
+#define TXFCB_IP6 0x20
+#define TXFCB_TUP 0x10
+#define TXFCB_UDP 0x08
+#define TXFCB_CIP 0x04
+#define TXFCB_CTU 0x02
+#define TXFCB_NPH 0x01
+#define TXFCB_DEFAULT (TXFCB_IP|TXFCB_TUP|TXFCB_CTU|TXFCB_NPH)
/* RxBD status field bits */
#define RXBD_EMPTY 0x8000
@@ -273,6 +319,18 @@ extern const char gfar_driver_version[];
#define RXBD_TRUNCATED 0x0001
#define RXBD_STATS 0x01ff
+/* Rx FCB status field bits */
+#define RXFCB_VLN 0x8000
+#define RXFCB_IP 0x4000
+#define RXFCB_IP6 0x2000
+#define RXFCB_TUP 0x1000
+#define RXFCB_CIP 0x0800
+#define RXFCB_CTU 0x0400
+#define RXFCB_EIP 0x0200
+#define RXFCB_ETU 0x0100
+#define RXFCB_PERR_MASK 0x000c
+#define RXFCB_PERR_BADL3 0x0008
+
struct txbd8
{
u16 status; /* Status Fields */
@@ -280,6 +338,22 @@ struct txbd8
u32 bufPtr; /* Buffer Pointer */
};
+struct txfcb {
+ u8 vln:1,
+ ip:1,
+ ip6:1,
+ tup:1,
+ udp:1,
+ cip:1,
+ ctu:1,
+ nph:1;
+ u8 reserved;
+ u8 l4os; /* Level 4 Header Offset */
+ u8 l3os; /* Level 3 Header Offset */
+ u16 phcs; /* Pseudo-header Checksum */
+ u16 vlctl; /* VLAN control word */
+};
+
struct rxbd8
{
u16 status; /* Status Fields */
@@ -287,6 +361,21 @@ struct rxbd8
u32 bufPtr; /* Buffer Pointer */
};
+struct rxfcb {
+ u16 vln:1,
+ ip:1,
+ ip6:1,
+ tup:1,
+ cip:1,
+ ctu:1,
+ eip:1,
+ etu:1;
+ u8 rq; /* Receive Queue index */
+ u8 pro; /* Layer 4 Protocol */
+ u16 reserved;
+ u16 vlctl; /* VLAN control word */
+};
+
struct rmon_mib
{
u32 tr64; /* 0x.680 - Transmit and Receive 64-byte Frame Counter */
@@ -371,90 +460,191 @@ struct gfar_stats {
struct gfar {
- u8 res1[16];
- u32 ievent; /* 0x.010 - Interrupt Event Register */
- u32 imask; /* 0x.014 - Interrupt Mask Register */
- u32 edis; /* 0x.018 - Error Disabled Register */
+ u32 tsec_id; /* 0x.000 - Controller ID register */
+ u8 res1[12];
+ u32 ievent; /* 0x.010 - Interrupt Event Register */
+ u32 imask; /* 0x.014 - Interrupt Mask Register */
+ u32 edis; /* 0x.018 - Error Disabled Register */
u8 res2[4];
- u32 ecntrl; /* 0x.020 - Ethernet Control Register */
- u32 minflr; /* 0x.024 - Minimum Frame Length Register */
- u32 ptv; /* 0x.028 - Pause Time Value Register */
- u32 dmactrl; /* 0x.02c - DMA Control Register */
- u32 tbipa; /* 0x.030 - TBI PHY Address Register */
+ u32 ecntrl; /* 0x.020 - Ethernet Control Register */
+ u32 minflr; /* 0x.024 - Minimum Frame Length Register */
+ u32 ptv; /* 0x.028 - Pause Time Value Register */
+ u32 dmactrl; /* 0x.02c - DMA Control Register */
+ u32 tbipa; /* 0x.030 - TBI PHY Address Register */
u8 res3[88];
- u32 fifo_tx_thr; /* 0x.08c - FIFO transmit threshold register */
+ u32 fifo_tx_thr; /* 0x.08c - FIFO transmit threshold register */
u8 res4[8];
- u32 fifo_tx_starve; /* 0x.098 - FIFO transmit starve register */
+ u32 fifo_tx_starve; /* 0x.098 - FIFO transmit starve register */
u32 fifo_tx_starve_shutoff; /* 0x.09c - FIFO transmit starve shutoff register */
- u8 res5[96];
- u32 tctrl; /* 0x.100 - Transmit Control Register */
- u32 tstat; /* 0x.104 - Transmit Status Register */
- u8 res6[4];
- u32 tbdlen; /* 0x.10c - Transmit Buffer Descriptor Data Length Register */
- u32 txic; /* 0x.110 - Transmit Interrupt Coalescing Configuration Register */
- u8 res7[16];
- u32 ctbptr; /* 0x.124 - Current Transmit Buffer Descriptor Pointer Register */
- u8 res8[92];
- u32 tbptr; /* 0x.184 - Transmit Buffer Descriptor Pointer Low Register */
- u8 res9[124];
- u32 tbase; /* 0x.204 - Transmit Descriptor Base Address Register */
- u8 res10[168];
- u32 ostbd; /* 0x.2b0 - Out-of-Sequence Transmit Buffer Descriptor Register */
- u32 ostbdp; /* 0x.2b4 - Out-of-Sequence Transmit Data Buffer Pointer Register */
- u8 res11[72];
- u32 rctrl; /* 0x.300 - Receive Control Register */
- u32 rstat; /* 0x.304 - Receive Status Register */
- u8 res12[4];
- u32 rbdlen; /* 0x.30c - RxBD Data Length Register */
- u32 rxic; /* 0x.310 - Receive Interrupt Coalescing Configuration Register */
- u8 res13[16];
- u32 crbptr; /* 0x.324 - Current Receive Buffer Descriptor Pointer */
- u8 res14[24];
- u32 mrblr; /* 0x.340 - Maximum Receive Buffer Length Register */
- u8 res15[64];
- u32 rbptr; /* 0x.384 - Receive Buffer Descriptor Pointer */
- u8 res16[124];
- u32 rbase; /* 0x.404 - Receive Descriptor Base Address */
- u8 res17[248];
- u32 maccfg1; /* 0x.500 - MAC Configuration 1 Register */
- u32 maccfg2; /* 0x.504 - MAC Configuration 2 Register */
- u32 ipgifg; /* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */
- u32 hafdup; /* 0x.50c - Half Duplex Register */
- u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */
+ u8 res5[4];
+ u32 fifo_rx_pause; /* 0x.0a4 - FIFO receive pause threshold register */
+ u32 fifo_rx_alarm; /* 0x.0a8 - FIFO receive alarm threshold register */
+ u8 res6[84];
+ u32 tctrl; /* 0x.100 - Transmit Control Register */
+ u32 tstat; /* 0x.104 - Transmit Status Register */
+ u32 dfvlan; /* 0x.108 - Default VLAN Control word */
+ u32 tbdlen; /* 0x.10c - Transmit Buffer Descriptor Data Length Register */
+ u32 txic; /* 0x.110 - Transmit Interrupt Coalescing Configuration Register */
+ u32 tqueue; /* 0x.114 - Transmit queue control register */
+ u8 res7[40];
+ u32 tr03wt; /* 0x.140 - TxBD Rings 0-3 round-robin weightings */
+ u32 tr47wt; /* 0x.144 - TxBD Rings 4-7 round-robin weightings */
+ u8 res8[52];
+ u32 tbdbph; /* 0x.17c - Tx data buffer pointer high */
+ u8 res9a[4];
+ u32 tbptr0; /* 0x.184 - TxBD Pointer for ring 0 */
+ u8 res9b[4];
+ u32 tbptr1; /* 0x.18c - TxBD Pointer for ring 1 */
+ u8 res9c[4];
+ u32 tbptr2; /* 0x.194 - TxBD Pointer for ring 2 */
+ u8 res9d[4];
+ u32 tbptr3; /* 0x.19c - TxBD Pointer for ring 3 */
+ u8 res9e[4];
+ u32 tbptr4; /* 0x.1a4 - TxBD Pointer for ring 4 */
+ u8 res9f[4];
+ u32 tbptr5; /* 0x.1ac - TxBD Pointer for ring 5 */
+ u8 res9g[4];
+ u32 tbptr6; /* 0x.1b4 - TxBD Pointer for ring 6 */
+ u8 res9h[4];
+ u32 tbptr7; /* 0x.1bc - TxBD Pointer for ring 7 */
+ u8 res9[64];
+ u32 tbaseh; /* 0x.200 - TxBD base address high */
+ u32 tbase0; /* 0x.204 - TxBD Base Address of ring 0 */
+ u8 res10a[4];
+ u32 tbase1; /* 0x.20c - TxBD Base Address of ring 1 */
+ u8 res10b[4];
+ u32 tbase2; /* 0x.214 - TxBD Base Address of ring 2 */
+ u8 res10c[4];
+ u32 tbase3; /* 0x.21c - TxBD Base Address of ring 3 */
+ u8 res10d[4];
+ u32 tbase4; /* 0x.224 - TxBD Base Address of ring 4 */
+ u8 res10e[4];
+ u32 tbase5; /* 0x.22c - TxBD Base Address of ring 5 */
+ u8 res10f[4];
+ u32 tbase6; /* 0x.234 - TxBD Base Address of ring 6 */
+ u8 res10g[4];
+ u32 tbase7; /* 0x.23c - TxBD Base Address of ring 7 */
+ u8 res10[192];
+ u32 rctrl; /* 0x.300 - Receive Control Register */
+ u32 rstat; /* 0x.304 - Receive Status Register */
+ u8 res12[8];
+ u32 rxic; /* 0x.310 - Receive Interrupt Coalescing Configuration Register */
+ u32 rqueue; /* 0x.314 - Receive queue control register */
+ u8 res13[24];
+ u32 rbifx; /* 0x.330 - Receive bit field extract control register */
+ u32 rqfar; /* 0x.334 - Receive queue filing table address register */
+ u32 rqfcr; /* 0x.338 - Receive queue filing table control register */
+ u32 rqfpr; /* 0x.33c - Receive queue filing table property register */
+ u32 mrblr; /* 0x.340 - Maximum Receive Buffer Length Register */
+ u8 res14[56];
+ u32 rbdbph; /* 0x.37c - Rx data buffer pointer high */
+ u8 res15a[4];
+ u32 rbptr0; /* 0x.384 - RxBD pointer for ring 0 */
+ u8 res15b[4];
+ u32 rbptr1; /* 0x.38c - RxBD pointer for ring 1 */
+ u8 res15c[4];
+ u32 rbptr2; /* 0x.394 - RxBD pointer for ring 2 */
+ u8 res15d[4];
+ u32 rbptr3; /* 0x.39c - RxBD pointer for ring 3 */
+ u8 res15e[4];
+ u32 rbptr4; /* 0x.3a4 - RxBD pointer for ring 4 */
+ u8 res15f[4];
+ u32 rbptr5; /* 0x.3ac - RxBD pointer for ring 5 */
+ u8 res15g[4];
+ u32 rbptr6; /* 0x.3b4 - RxBD pointer for ring 6 */
+ u8 res15h[4];
+ u32 rbptr7; /* 0x.3bc - RxBD pointer for ring 7 */
+ u8 res16[64];
+ u32 rbaseh; /* 0x.400 - RxBD base address high */
+ u32 rbase0; /* 0x.404 - RxBD base address of ring 0 */
+ u8 res17a[4];
+ u32 rbase1; /* 0x.40c - RxBD base address of ring 1 */
+ u8 res17b[4];
+ u32 rbase2; /* 0x.414 - RxBD base address of ring 2 */
+ u8 res17c[4];
+ u32 rbase3; /* 0x.41c - RxBD base address of ring 3 */
+ u8 res17d[4];
+ u32 rbase4; /* 0x.424 - RxBD base address of ring 4 */
+ u8 res17e[4];
+ u32 rbase5; /* 0x.42c - RxBD base address of ring 5 */
+ u8 res17f[4];
+ u32 rbase6; /* 0x.434 - RxBD base address of ring 6 */
+ u8 res17g[4];
+ u32 rbase7; /* 0x.43c - RxBD base address of ring 7 */
+ u8 res17[192];
+ u32 maccfg1; /* 0x.500 - MAC Configuration 1 Register */
+ u32 maccfg2; /* 0x.504 - MAC Configuration 2 Register */
+ u32 ipgifg; /* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */
+ u32 hafdup; /* 0x.50c - Half Duplex Register */
+ u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */
u8 res18[12];
- u32 miimcfg; /* 0x.520 - MII Management Configuration Register */
- u32 miimcom; /* 0x.524 - MII Management Command Register */
- u32 miimadd; /* 0x.528 - MII Management Address Register */
- u32 miimcon; /* 0x.52c - MII Management Control Register */
- u32 miimstat; /* 0x.530 - MII Management Status Register */
- u32 miimind; /* 0x.534 - MII Management Indicator Register */
+ u32 miimcfg; /* 0x.520 - MII Management Configuration Register */
+ u32 miimcom; /* 0x.524 - MII Management Command Register */
+ u32 miimadd; /* 0x.528 - MII Management Address Register */
+ u32 miimcon; /* 0x.52c - MII Management Control Register */
+ u32 miimstat; /* 0x.530 - MII Management Status Register */
+ u32 miimind; /* 0x.534 - MII Management Indicator Register */
u8 res19[4];
- u32 ifstat; /* 0x.53c - Interface Status Register */
- u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */
- u32 macstnaddr2; /* 0x.544 - Station Address Part 2 Register */
- u8 res20[312];
- struct rmon_mib rmon;
- u8 res21[192];
- u32 iaddr0; /* 0x.800 - Indivdual address register 0 */
- u32 iaddr1; /* 0x.804 - Indivdual address register 1 */
- u32 iaddr2; /* 0x.808 - Indivdual address register 2 */
- u32 iaddr3; /* 0x.80c - Indivdual address register 3 */
- u32 iaddr4; /* 0x.810 - Indivdual address register 4 */
- u32 iaddr5; /* 0x.814 - Indivdual address register 5 */
- u32 iaddr6; /* 0x.818 - Indivdual address register 6 */
- u32 iaddr7; /* 0x.81c - Indivdual address register 7 */
+ u32 ifstat; /* 0x.53c - Interface Status Register */
+ u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */
+ u32 macstnaddr2; /* 0x.544 - Station Address Part 2 Register */
+ u32 mac01addr1; /* 0x.548 - MAC exact match address 1, part 1 */
+ u32 mac01addr2; /* 0x.54c - MAC exact match address 1, part 2 */
+ u32 mac02addr1; /* 0x.550 - MAC exact match address 2, part 1 */
+ u32 mac02addr2; /* 0x.554 - MAC exact match address 2, part 2 */
+ u32 mac03addr1; /* 0x.558 - MAC exact match address 3, part 1 */
+ u32 mac03addr2; /* 0x.55c - MAC exact match address 3, part 2 */
+ u32 mac04addr1; /* 0x.560 - MAC exact match address 4, part 1 */
+ u32 mac04addr2; /* 0x.564 - MAC exact match address 4, part 2 */
+ u32 mac05addr1; /* 0x.568 - MAC exact match address 5, part 1 */
+ u32 mac05addr2; /* 0x.56c - MAC exact match address 5, part 2 */
+ u32 mac06addr1; /* 0x.570 - MAC exact match address 6, part 1 */
+ u32 mac06addr2; /* 0x.574 - MAC exact match address 6, part 2 */
+ u32 mac07addr1; /* 0x.578 - MAC exact match address 7, part 1 */
+ u32 mac07addr2; /* 0x.57c - MAC exact match address 7, part 2 */
+ u32 mac08addr1; /* 0x.580 - MAC exact match address 8, part 1 */
+ u32 mac08addr2; /* 0x.584 - MAC exact match address 8, part 2 */
+ u32 mac09addr1; /* 0x.588 - MAC exact match address 9, part 1 */
+ u32 mac09addr2; /* 0x.58c - MAC exact match address 9, part 2 */
+ u32 mac10addr1; /* 0x.590 - MAC exact match address 10, part 1*/
+ u32 mac10addr2; /* 0x.594 - MAC exact match address 10, part 2*/
+ u32 mac11addr1; /* 0x.598 - MAC exact match address 11, part 1*/
+ u32 mac11addr2; /* 0x.59c - MAC exact match address 11, part 2*/
+ u32 mac12addr1; /* 0x.5a0 - MAC exact match address 12, part 1*/
+ u32 mac12addr2; /* 0x.5a4 - MAC exact match address 12, part 2*/
+ u32 mac13addr1; /* 0x.5a8 - MAC exact match address 13, part 1*/
+ u32 mac13addr2; /* 0x.5ac - MAC exact match address 13, part 2*/
+ u32 mac14addr1; /* 0x.5b0 - MAC exact match address 14, part 1*/
+ u32 mac14addr2; /* 0x.5b4 - MAC exact match address 14, part 2*/
+ u32 mac15addr1; /* 0x.5b8 - MAC exact match address 15, part 1*/
+ u32 mac15addr2; /* 0x.5bc - MAC exact match address 15, part 2*/
+ u8 res20[192];
+ struct rmon_mib rmon; /* 0x.680-0x.73c */
+ u32 rrej; /* 0x.740 - Receive filer rejected packet counter */
+ u8 res21[188];
+ u32 igaddr0; /* 0x.800 - Indivdual/Group address register 0*/
+ u32 igaddr1; /* 0x.804 - Indivdual/Group address register 1*/
+ u32 igaddr2; /* 0x.808 - Indivdual/Group address register 2*/
+ u32 igaddr3; /* 0x.80c - Indivdual/Group address register 3*/
+ u32 igaddr4; /* 0x.810 - Indivdual/Group address register 4*/
+ u32 igaddr5; /* 0x.814 - Indivdual/Group address register 5*/
+ u32 igaddr6; /* 0x.818 - Indivdual/Group address register 6*/
+ u32 igaddr7; /* 0x.81c - Indivdual/Group address register 7*/
u8 res22[96];
- u32 gaddr0; /* 0x.880 - Global address register 0 */
- u32 gaddr1; /* 0x.884 - Global address register 1 */
- u32 gaddr2; /* 0x.888 - Global address register 2 */
- u32 gaddr3; /* 0x.88c - Global address register 3 */
- u32 gaddr4; /* 0x.890 - Global address register 4 */
- u32 gaddr5; /* 0x.894 - Global address register 5 */
- u32 gaddr6; /* 0x.898 - Global address register 6 */
- u32 gaddr7; /* 0x.89c - Global address register 7 */
- u8 res23[856];
- u32 attr; /* 0x.bf8 - Attributes Register */
- u32 attreli; /* 0x.bfc - Attributes Extract Length and Extract Index Register */
+ u32 gaddr0; /* 0x.880 - Group address register 0 */
+ u32 gaddr1; /* 0x.884 - Group address register 1 */
+ u32 gaddr2; /* 0x.888 - Group address register 2 */
+ u32 gaddr3; /* 0x.88c - Group address register 3 */
+ u32 gaddr4; /* 0x.890 - Group address register 4 */
+ u32 gaddr5; /* 0x.894 - Group address register 5 */
+ u32 gaddr6; /* 0x.898 - Group address register 6 */
+ u32 gaddr7; /* 0x.89c - Group address register 7 */
+ u8 res23a[352];
+ u32 fifocfg; /* 0x.a00 - FIFO interface config register */
+ u8 res23b[252];
+ u8 res23c[248];
+ u32 attr; /* 0x.bf8 - Attributes Register */
+ u32 attreli; /* 0x.bfc - Attributes Extract Length and Extract Index Register */
u8 res24[1024];
};
@@ -496,6 +686,8 @@ struct gfar_private {
struct txbd8 *cur_tx; /* Next free ring entry */
struct txbd8 *dirty_tx; /* The Ring entry to be freed. */
struct gfar *regs; /* Pointer to the GFAR memory mapped Registers */
+ u32 *hash_regs[16];
+ int hash_width;
struct gfar *phyregs;
struct work_struct tq;
struct timer_list phy_info_timer;
@@ -506,9 +698,12 @@ struct gfar_private {
unsigned int rx_stash_size;
unsigned int tx_ring_size;
unsigned int rx_ring_size;
- wait_queue_head_t rxcleanupq;
- unsigned int rxclean;
+ unsigned char vlan_enable:1,
+ rx_csum_enable:1,
+ extended_hash:1;
+ unsigned short padding;
+ struct vlan_group *vlgrp;
/* Info structure initialized by board setup code */
unsigned int interruptTransmit;
unsigned int interruptReceive;
@@ -519,6 +714,8 @@ struct gfar_private {
int oldspeed;
int oldduplex;
int oldlink;
+
+ uint32_t msg_enable;
};
extern inline u32 gfar_read(volatile unsigned *addr)
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 28046e9e88ba..a451de629197 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -46,16 +46,18 @@
extern int startup_gfar(struct net_device *dev);
extern void stop_gfar(struct net_device *dev);
-extern void gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+extern void gfar_halt(struct net_device *dev);
+extern void gfar_start(struct net_device *dev);
+extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
u64 * buf);
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
static char stat_gstrings[][ETH_GSTRING_LEN] = {
"rx-dropped-by-kernel",
@@ -118,57 +120,56 @@ static char stat_gstrings[][ETH_GSTRING_LEN] = {
"tx-fragmented-frames",
};
+/* Fill in a buffer with the strings which correspond to the
+ * stats */
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+ memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
+ else
+ memcpy(buf, stat_gstrings,
+ GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+}
+
/* Fill in an array of 64-bit statistics from various sources.
* This array will be appended to the end of the ethtool_stats
* structure, and returned to user space
*/
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
{
int i;
struct gfar_private *priv = netdev_priv(dev);
- u32 *rmon = (u32 *) & priv->regs->rmon;
u64 *extra = (u64 *) & priv->extra_stats;
- struct gfar_stats *stats = (struct gfar_stats *) buf;
- for (i = 0; i < GFAR_RMON_LEN; i++) {
- stats->rmon[i] = (u64) (rmon[i]);
- }
-
- for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
- stats->extra[i] = extra[i];
- }
-}
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+ u32 *rmon = (u32 *) & priv->regs->rmon;
+ struct gfar_stats *stats = (struct gfar_stats *) buf;
-/* Returns the number of stats (and their corresponding strings) */
-int gfar_stats_count(struct net_device *dev)
-{
- return GFAR_STATS_LEN;
-}
+ for (i = 0; i < GFAR_RMON_LEN; i++)
+ stats->rmon[i] = (u64) (rmon[i]);
-void gfar_gstrings_normon(struct net_device *dev, u32 stringset, u8 * buf)
-{
- memcpy(buf, stat_gstrings, GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+ for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+ stats->extra[i] = extra[i];
+ } else
+ for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+ buf[i] = extra[i];
}
-void gfar_fill_stats_normon(struct net_device *dev,
- struct ethtool_stats *dummy, u64 * buf)
+/* Returns the number of stats (and their corresponding strings) */
+static int gfar_stats_count(struct net_device *dev)
{
- int i;
struct gfar_private *priv = netdev_priv(dev);
- u64 *extra = (u64 *) & priv->extra_stats;
- for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
- buf[i] = extra[i];
- }
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+ return GFAR_STATS_LEN;
+ else
+ return GFAR_EXTRA_STATS_LEN;
}
-
-int gfar_stats_count_normon(struct net_device *dev)
-{
- return GFAR_EXTRA_STATS_LEN;
-}
/* Fills in the drvinfo structure with some basic info */
-void gfar_gdrvinfo(struct net_device *dev, struct
+static void gfar_gdrvinfo(struct net_device *dev, struct
ethtool_drvinfo *drvinfo)
{
strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
@@ -182,7 +183,7 @@ void gfar_gdrvinfo(struct net_device *dev, struct
}
/* Return the current settings in the ethtool_cmd structure */
-int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct gfar_private *priv = netdev_priv(dev);
uint gigabit_support =
@@ -216,13 +217,13 @@ int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
}
/* Return the length of the register structure */
-int gfar_reglen(struct net_device *dev)
+static int gfar_reglen(struct net_device *dev)
{
return sizeof (struct gfar);
}
/* Return a dump of the GFAR register space */
-void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
+static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
{
int i;
struct gfar_private *priv = netdev_priv(dev);
@@ -233,13 +234,6 @@ void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regb
buf[i] = theregs[i];
}
-/* Fill in a buffer with the strings which correspond to the
- * stats */
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
-{
- memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
-}
-
/* Convert microseconds to ethernet clock ticks, which changes
* depending on what speed the controller is running at */
static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int usecs)
@@ -291,9 +285,12 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
/* Get the coalescing parameters, and put them in the cvals
* structure. */
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
{
struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+ return -EOPNOTSUPP;
cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime);
cvals->rx_max_coalesced_frames = priv->rxcount;
@@ -337,10 +334,13 @@ int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
* Both cvals->*_usecs and cvals->*_frames have to be > 0
* in order for coalescing to be active
*/
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
{
struct gfar_private *priv = netdev_priv(dev);
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+ return -EOPNOTSUPP;
+
/* Set up rx coalescing */
if ((cvals->rx_coalesce_usecs == 0) ||
(cvals->rx_max_coalesced_frames == 0))
@@ -379,7 +379,7 @@ int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
/* Fills in rvals with the current ring parameters. Currently,
* rx, rx_mini, and rx_jumbo rings are the same size, as mini and
* jumbo are ignored by the driver */
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
{
struct gfar_private *priv = netdev_priv(dev);
@@ -401,9 +401,8 @@ void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
* necessary so that we don't mess things up while we're in
* motion. We wait for the ring to be clean before reallocating
* the rings. */
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
{
- u32 tempval;
struct gfar_private *priv = netdev_priv(dev);
int err = 0;
@@ -425,37 +424,54 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
return -EINVAL;
}
- /* Stop the controller so we don't rx any more frames */
- /* But first, make sure we clear the bits */
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
- gfar_write(&priv->regs->dmactrl, tempval);
+ if (dev->flags & IFF_UP) {
+ unsigned long flags;
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval |= (DMACTRL_GRS | DMACTRL_GTS);
- gfar_write(&priv->regs->dmactrl, tempval);
+ /* Halt TX and RX, and process the frames which
+ * have already been received */
+ spin_lock_irqsave(&priv->lock, flags);
+ gfar_halt(dev);
+ gfar_clean_rx_ring(dev, priv->rx_ring_size);
+ spin_unlock_irqrestore(&priv->lock, flags);
- while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC)))
- cpu_relax();
+ /* Now we take down the rings to rebuild them */
+ stop_gfar(dev);
+ }
- /* Note that rx is not clean right now */
- priv->rxclean = 0;
+ /* Change the size */
+ priv->rx_ring_size = rvals->rx_pending;
+ priv->tx_ring_size = rvals->tx_pending;
- if (dev->flags & IFF_UP) {
- /* Tell the driver to process the rest of the frames */
- gfar_receive(0, (void *) dev, NULL);
+ /* Rebuild the rings with the new size */
+ if (dev->flags & IFF_UP)
+ err = startup_gfar(dev);
- /* Now wait for it to be done */
- wait_event_interruptible(priv->rxcleanupq, priv->rxclean);
+ return err;
+}
- /* Ok, all packets have been handled. Now we bring it down,
- * change the ring size, and bring it up */
+static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ int err = 0;
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+ return -EOPNOTSUPP;
+
+ if (dev->flags & IFF_UP) {
+ unsigned long flags;
+
+ /* Halt TX and RX, and process the frames which
+ * have already been received */
+ spin_lock_irqsave(&priv->lock, flags);
+ gfar_halt(dev);
+ gfar_clean_rx_ring(dev, priv->rx_ring_size);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Now we take down the rings to rebuild them */
stop_gfar(dev);
}
- priv->rx_ring_size = rvals->rx_pending;
- priv->tx_ring_size = rvals->tx_pending;
+ priv->rx_csum_enable = data;
if (dev->flags & IFF_UP)
err = startup_gfar(dev);
@@ -463,6 +479,61 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
return err;
}
+static uint32_t gfar_get_rx_csum(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+ return 0;
+
+ return priv->rx_csum_enable;
+}
+
+static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+ unsigned long flags;
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+ return -EOPNOTSUPP;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ gfar_halt(dev);
+
+ if (data)
+ dev->features |= NETIF_F_IP_CSUM;
+ else
+ dev->features &= ~NETIF_F_IP_CSUM;
+
+ gfar_start(dev);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static uint32_t gfar_get_tx_csum(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+ return 0;
+
+ return (dev->features & NETIF_F_IP_CSUM) != 0;
+}
+
+static uint32_t gfar_get_msglevel(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ return priv->msg_enable;
+}
+
+static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ priv->msg_enable = data;
+}
+
+
struct ethtool_ops gfar_ethtool_ops = {
.get_settings = gfar_gsettings,
.get_drvinfo = gfar_gdrvinfo,
@@ -476,52 +547,10 @@ struct ethtool_ops gfar_ethtool_ops = {
.get_strings = gfar_gstrings,
.get_stats_count = gfar_stats_count,
.get_ethtool_stats = gfar_fill_stats,
-};
-
-struct ethtool_ops gfar_normon_nocoalesce_ethtool_ops = {
- .get_settings = gfar_gsettings,
- .get_drvinfo = gfar_gdrvinfo,
- .get_regs_len = gfar_reglen,
- .get_regs = gfar_get_regs,
- .get_link = ethtool_op_get_link,
- .get_ringparam = gfar_gringparam,
- .set_ringparam = gfar_sringparam,
- .get_strings = gfar_gstrings_normon,
- .get_stats_count = gfar_stats_count_normon,
- .get_ethtool_stats = gfar_fill_stats_normon,
-};
-
-struct ethtool_ops gfar_nocoalesce_ethtool_ops = {
- .get_settings = gfar_gsettings,
- .get_drvinfo = gfar_gdrvinfo,
- .get_regs_len = gfar_reglen,
- .get_regs = gfar_get_regs,
- .get_link = ethtool_op_get_link,
- .get_ringparam = gfar_gringparam,
- .set_ringparam = gfar_sringparam,
- .get_strings = gfar_gstrings,
- .get_stats_count = gfar_stats_count,
- .get_ethtool_stats = gfar_fill_stats,
-};
-
-struct ethtool_ops gfar_normon_ethtool_ops = {
- .get_settings = gfar_gsettings,
- .get_drvinfo = gfar_gdrvinfo,
- .get_regs_len = gfar_reglen,
- .get_regs = gfar_get_regs,
- .get_link = ethtool_op_get_link,
- .get_coalesce = gfar_gcoalesce,
- .set_coalesce = gfar_scoalesce,
- .get_ringparam = gfar_gringparam,
- .set_ringparam = gfar_sringparam,
- .get_strings = gfar_gstrings_normon,
- .get_stats_count = gfar_stats_count_normon,
- .get_ethtool_stats = gfar_fill_stats_normon,
-};
-
-struct ethtool_ops *gfar_op_array[] = {
- &gfar_ethtool_ops,
- &gfar_normon_ethtool_ops,
- &gfar_nocoalesce_ethtool_ops,
- &gfar_normon_nocoalesce_ethtool_ops
+ .get_rx_csum = gfar_get_rx_csum,
+ .get_tx_csum = gfar_get_tx_csum,
+ .set_rx_csum = gfar_set_rx_csum,
+ .set_tx_csum = gfar_set_tx_csum,
+ .get_msglevel = gfar_get_msglevel,
+ .set_msglevel = gfar_set_msglevel,
};
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 13f114876965..3213f3e50487 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -850,7 +850,7 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
if ((!data) || (data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)))
data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
- schedule_timeout(data * HZ);
+ msleep_interruptible(data * 1000);
del_timer_sync(&lp->blink_timer);
/* Restore the original value of the bcrs */
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index e15369c8d165..d6388e1533f0 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -90,7 +90,6 @@ static int sb1000_close(struct net_device *dev);
/* SB1000 hardware routines to be used during open/configuration phases */
-static inline void nicedelay(unsigned long usecs);
static inline int card_wait_for_busy_clear(const int ioaddr[],
const char* name);
static inline int card_wait_for_ready(const int ioaddr[], const char* name,
@@ -254,13 +253,6 @@ static struct pnp_driver sb1000_driver = {
static const int TimeOutJiffies = (875 * HZ) / 100;
-static inline void nicedelay(unsigned long usecs)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ);
- return;
-}
-
/* Card Wait For Busy Clear (cannot be used during an interrupt) */
static inline int
card_wait_for_busy_clear(const int ioaddr[], const char* name)
@@ -475,7 +467,7 @@ sb1000_reset(const int ioaddr[], const char* name)
udelay(1000);
outb(0x0, port);
inb(port);
- nicedelay(60000);
+ ssleep(1);
outb(0x4, port);
inb(port);
udelay(1000);
@@ -537,7 +529,7 @@ sb1000_activate(const int ioaddr[], const char* name)
const unsigned char Command0[6] = {0x80, 0x11, 0x00, 0x00, 0x00, 0x00};
const unsigned char Command1[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00};
- nicedelay(50000);
+ ssleep(1);
if ((status = card_send_command(ioaddr, name, Command0, st)))
return status;
if ((status = card_send_command(ioaddr, name, Command1, st)))
@@ -944,7 +936,7 @@ sb1000_open(struct net_device *dev)
/* initialize sb1000 */
if ((status = sb1000_reset(ioaddr, name)))
return status;
- nicedelay(200000);
+ ssleep(1);
if ((status = sb1000_check_CRC(ioaddr, name)))
return status;
diff --git a/drivers/net/skfp/Makefile b/drivers/net/skfp/Makefile
index 5f4bb1a67400..cb23580fcffa 100644
--- a/drivers/net/skfp/Makefile
+++ b/drivers/net/skfp/Makefile
@@ -6,8 +6,8 @@ obj-$(CONFIG_SKFP) += skfp.o
skfp-objs := skfddi.o hwmtm.o fplustm.o smt.o cfm.o \
ecm.o pcmplc.o pmf.o queue.o rmt.o \
- smtdef.o smtinit.o smttimer.o srf.o smtparse.o\
- hwt.o drvfbi.o ess.o
+ smtdef.o smtinit.o smttimer.o srf.o hwt.o \
+ drvfbi.o ess.o
# NOTE:
# Compiling this driver produces some warnings (and some more are
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
index 052e841ba187..5b475833f645 100644
--- a/drivers/net/skfp/drvfbi.c
+++ b/drivers/net/skfp/drvfbi.c
@@ -105,8 +105,8 @@ extern int AIX_vpdReadByte() ;
#endif
-/* Prototypes of local functions. */
-void smt_stop_watchdog(struct s_smc *smc);
+/* Prototype of a local function. */
+static void smt_stop_watchdog(struct s_smc *smc);
#ifdef MCA
static int read_card_id() ;
@@ -631,7 +631,7 @@ void plc_clear_irq(struct s_smc *smc, int p)
* LED_Y_OFF just switch yellow LED off
* LED_Y_ON just switch yello LED on
*/
-void led_indication(struct s_smc *smc, int led_event)
+static void led_indication(struct s_smc *smc, int led_event)
{
/* use smc->hw.mac_ring_is_up == TRUE
* as indication for Ring Operational
@@ -764,122 +764,6 @@ void llc_recover_tx(struct s_smc *smc)
#endif
}
-/*--------------------------- DMA init ----------------------------*/
-#ifdef ISA
-
-/*
- * init DMA
- */
-void init_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
-
- /*
- * set cascade mode,
- * clear mask bit (enable DMA cannal)
- */
- if (dma > 3) {
- outp(0xd6,(dma & 0x03) | 0xc0) ;
- outp(0xd4, dma & 0x03) ;
- }
- else {
- outp(0x0b,(dma & 0x03) | 0xc0) ;
- outp(0x0a,dma & 0x03) ;
- }
-}
-
-/*
- * disable DMA
- */
-void dis_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
-
- /*
- * set mask bit (disable DMA cannal)
- */
- if (dma > 3) {
- outp(0xd4,(dma & 0x03) | 0x04) ;
- }
- else {
- outp(0x0a,(dma & 0x03) | 0x04) ;
- }
-}
-
-#endif /* ISA */
-
-#ifdef EISA
-
-/*arrays with io addresses of dma controller length and address registers*/
-static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ;
-static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ;
-static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ;
-
-void init_dma(struct s_smc *smc, int dma)
-{
- /*
- * extended mode register
- * 32 bit IO
- * type c
- * TC output
- * disable stop
- */
-
- /* mode read (write) demand */
- smc->hw.dma_rmode = (dma & 3) | 0x08 | 0x0 ;
- smc->hw.dma_wmode = (dma & 3) | 0x04 | 0x0 ;
-
- /* 32 bit IO's, burst DMA mode (type "C") */
- smc->hw.dma_emode = (dma & 3) | 0x08 | 0x30 ;
-
- outp((dma < 4) ? 0x40b : 0x4d6,smc->hw.dma_emode) ;
-
- /* disable chaining */
- outp((dma < 4) ? 0x40a : 0x4d4,(dma&3)) ;
-
- /*load dma controller addresses for fast access during set dma*/
- smc->hw.dma_base_word_count = cntr[smc->hw.dma];
- smc->hw.dma_base_address = base[smc->hw.dma];
- smc->hw.dma_base_address_page = page[smc->hw.dma];
-
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
-
- outp((dma < 4) ? 0x0a : 0xd4,(dma&3)|4) ;/* mask bit */
-}
-#endif /* EISA */
-
-#ifdef MCA
-void init_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
- SK_UNUSED(dma) ;
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
- SK_UNUSED(dma) ;
-}
-#endif
-
-#ifdef PCI
-void init_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
- SK_UNUSED(dma) ;
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
- SK_UNUSED(dma) ;
-}
-#endif
-
#ifdef MULT_OEM
static int is_equal_num(char comp1[], char comp2[], int num)
{
@@ -1407,7 +1291,7 @@ void smt_start_watchdog(struct s_smc *smc)
#endif /* DEBUG */
}
-void smt_stop_watchdog(struct s_smc *smc)
+static void smt_stop_watchdog(struct s_smc *smc)
{
SK_UNUSED(smc) ; /* Make LINT happy. */
#ifndef DEBUG
@@ -1422,104 +1306,6 @@ void smt_stop_watchdog(struct s_smc *smc)
}
#ifdef PCI
-static char get_rom_byte(struct s_smc *smc, u_short addr)
-{
- GET_PAGE(addr) ;
- return (READ_PROM(ADDR(B2_FDP))) ;
-}
-
-/*
- * ROM image defines
- */
-#define ROM_SIG_1 0
-#define ROM_SIG_2 1
-#define PCI_DATA_1 0x18
-#define PCI_DATA_2 0x19
-
-/*
- * PCI data structure defines
- */
-#define VPD_DATA_1 0x08
-#define VPD_DATA_2 0x09
-#define IMAGE_LEN_1 0x10
-#define IMAGE_LEN_2 0x11
-#define CODE_TYPE 0x14
-#define INDICATOR 0x15
-
-/*
- * BEGIN_MANUAL_ENTRY(mac_drv_vpd_read)
- * mac_drv_vpd_read(smc,buf,size,image)
- *
- * function DOWNCALL (FDDIWARE)
- * reads the VPD data of the FPROM and writes it into the
- * buffer
- *
- * para buf points to the buffer for the VPD data
- * size size of the VPD data buffer
- * image boot image; code type of the boot image
- * image = 0 Intel x86, PC-AT compatible
- * 1 OPENBOOT standard for PCI
- * 2-FF reserved
- *
- * returns len number of VPD data bytes read form the FPROM
- * <0 number of read bytes
- * >0 error: data invalid
- *
- * END_MANUAL_ENTRY
- */
-int mac_drv_vpd_read(struct s_smc *smc, char *buf, int size, char image)
-{
- u_short ibase ;
- u_short pci_base ;
- u_short vpd ;
- int len ;
-
- len = 0 ;
- ibase = 0 ;
- /*
- * as long images defined
- */
- while (get_rom_byte(smc,ibase+ROM_SIG_1) == 0x55 &&
- (u_char) get_rom_byte(smc,ibase+ROM_SIG_2) == 0xaa) {
- /*
- * get the pointer to the PCI data structure
- */
- pci_base = ibase + get_rom_byte(smc,ibase+PCI_DATA_1) +
- (get_rom_byte(smc,ibase+PCI_DATA_2) << 8) ;
-
- if (image == get_rom_byte(smc,pci_base+CODE_TYPE)) {
- /*
- * we have the right image, read the VPD data
- */
- vpd = ibase + get_rom_byte(smc,pci_base+VPD_DATA_1) +
- (get_rom_byte(smc,pci_base+VPD_DATA_2) << 8) ;
- if (vpd == ibase) {
- break ; /* no VPD data */
- }
- for (len = 0; len < size; len++,buf++,vpd++) {
- *buf = get_rom_byte(smc,vpd) ;
- }
- break ;
- }
- else {
- /*
- * try the next image
- */
- if (get_rom_byte(smc,pci_base+INDICATOR) & 0x80) {
- break ; /* this was the last image */
- }
- ibase = ibase + get_rom_byte(smc,ibase+IMAGE_LEN_1) +
- (get_rom_byte(smc,ibase+IMAGE_LEN_2) << 8) ;
- }
- }
-
- return(len) ;
-}
-
-void mac_drv_pci_fix(struct s_smc *smc, u_long fix_value)
-{
- smc->hw.pci_fix_value = fix_value ;
-}
void mac_do_pci_fix(struct s_smc *smc)
{
diff --git a/drivers/net/skfp/ess.c b/drivers/net/skfp/ess.c
index fd39b4b2ef7d..62b01328c496 100644
--- a/drivers/net/skfp/ess.c
+++ b/drivers/net/skfp/ess.c
@@ -102,7 +102,7 @@ void ess_timer_poll(struct s_smc *smc);
void ess_para_change(struct s_smc *smc);
int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
int fs);
-int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead);
+static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead);
/*
@@ -375,7 +375,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
* determines the synchronous bandwidth, set the TSYNC register and the
* mib variables SBAPayload, SBAOverhead and fddiMACT-NEG.
*/
-int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead)
+static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead)
{
/*
* determine the synchronous bandwidth (sync_bw) in bytes per T-NEG,
diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c
index 76e78442fc24..a2ed47f1cc70 100644
--- a/drivers/net/skfp/fplustm.c
+++ b/drivers/net/skfp/fplustm.c
@@ -1117,30 +1117,6 @@ void mac_clear_multicast(struct s_smc *smc)
/*
BEGIN_MANUAL_ENTRY(if,func;others;2)
- int mac_set_func_addr(smc,f_addr)
- struct s_smc *smc ;
- u_long f_addr ;
-
-Function DOWNCALL (SMT, fplustm.c)
- Set a Token-Ring functional address, the address will
- be activated after calling mac_update_multicast()
-
-Para f_addr functional bits in non-canonical format
-
-Returns 0: always success
-
- END_MANUAL_ENTRY()
- */
-int mac_set_func_addr(struct s_smc *smc, u_long f_addr)
-{
- smc->hw.fp.func_addr = f_addr ;
- return(0) ;
-}
-
-
-/*
- BEGIN_MANUAL_ENTRY(if,func;others;2)
-
int mac_add_multicast(smc,addr,can)
struct s_smc *smc ;
struct fddi_addr *addr ;
@@ -1203,52 +1179,6 @@ int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can)
}
/*
- BEGIN_MANUAL_ENTRY(if,func;others;2)
-
- void mac_del_multicast(smc,addr,can)
- struct s_smc *smc ;
- struct fddi_addr *addr ;
- int can ;
-
-Function DOWNCALL (SMT, fplustm.c)
- Delete an entry from the multicast table
-
-Para addr pointer to a multicast address
- can = 0: the multicast address has the physical format
- = 1: the multicast address has the canonical format
- | 0x80 permanent
-
- END_MANUAL_ENTRY()
- */
-void mac_del_multicast(struct s_smc *smc, struct fddi_addr *addr, int can)
-{
- SK_LOC_DECL(struct fddi_addr,own) ;
- struct s_fpmc *tb ;
-
- if (!(tb = mac_get_mc_table(smc,addr,&own,1,can & ~0x80)))
- return ;
- /*
- * permanent addresses must be deleted with perm bit
- * and vice versa
- */
- if (( tb->perm && (can & 0x80)) ||
- (!tb->perm && !(can & 0x80))) {
- /*
- * delete it
- */
- if (tb->n) {
- tb->n-- ;
- if (tb->perm) {
- smc->hw.fp.smt_slots_used-- ;
- }
- else {
- smc->hw.fp.os_slots_used-- ;
- }
- }
- }
-}
-
-/*
* mode
*/
diff --git a/drivers/net/skfp/h/cmtdef.h b/drivers/net/skfp/h/cmtdef.h
index 603982debc71..f2f771d8be76 100644
--- a/drivers/net/skfp/h/cmtdef.h
+++ b/drivers/net/skfp/h/cmtdef.h
@@ -507,7 +507,6 @@ void pcm_status_state(struct s_smc *smc, int np, int *type, int *state,
int *remote, int *mac);
void plc_config_mux(struct s_smc *smc, int mux);
void sm_lem_evaluate(struct s_smc *smc);
-void smt_clear_una_dna(struct s_smc *smc);
void mac_update_counter(struct s_smc *smc);
void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off);
void sm_ma_control(struct s_smc *smc, int mode);
@@ -541,11 +540,9 @@ void smt_timer_poll(struct s_smc *smc);
u_long smt_get_time(void);
u_long smt_get_tid(struct s_smc *smc);
void smt_timer_done(struct s_smc *smc);
-void smt_set_defaults(struct s_smc *smc);
void smt_fixup_mib(struct s_smc *smc);
void smt_reset_defaults(struct s_smc *smc, int level);
void smt_agent_task(struct s_smc *smc);
-void smt_please_reconnect(struct s_smc *smc, int reconn_time);
int smt_check_para(struct s_smc *smc, struct smt_header *sm,
const u_short list[]);
void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr);
@@ -568,7 +565,6 @@ int pcm_get_s_port(struct s_smc *smc);
int pcm_rooted_station(struct s_smc *smc);
int cfm_get_mac_input(struct s_smc *smc);
int cfm_get_mac_output(struct s_smc *smc);
-int port_to_mib(struct s_smc *smc, int p);
int cem_build_path(struct s_smc *smc, char *to, int path_index);
int sm_mac_get_tx_state(struct s_smc *smc);
char *get_pcmstate(struct s_smc *smc, int np);
@@ -580,8 +576,6 @@ void smt_send_frame(struct s_smc *smc, SMbuf *mb, int fc, int local);
void smt_set_timestamp(struct s_smc *smc, u_char *p);
void mac_set_rx_mode(struct s_smc *smc, int mode);
int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can);
-int mac_set_func_addr(struct s_smc *smc, u_long f_addr);
-void mac_del_multicast(struct s_smc *smc, struct fddi_addr *addr, int can);
void mac_update_multicast(struct s_smc *smc);
void mac_clear_multicast(struct s_smc *smc);
void set_formac_tsync(struct s_smc *smc, long sync_bw);
@@ -599,7 +593,6 @@ void plc_irq(struct s_smc *smc, int np, unsigned int cmd);
int smt_set_mac_opvalues(struct s_smc *smc);
#ifdef TAG_MODE
-void mac_drv_pci_fix(struct s_smc *smc, u_long fix_value);
void mac_do_pci_fix(struct s_smc *smc);
void mac_drv_clear_tx_queue(struct s_smc *smc);
void mac_drv_repair_descr(struct s_smc *smc);
diff --git a/drivers/net/skfp/h/hwmtm.h b/drivers/net/skfp/h/hwmtm.h
index 4e360af07d77..1a606d4bfe5e 100644
--- a/drivers/net/skfp/h/hwmtm.h
+++ b/drivers/net/skfp/h/hwmtm.h
@@ -262,31 +262,6 @@ struct os_debug {
(smc)->hw.fp.tx_q[queue].tx_curr_put
/*
- * BEGIN_MANUAL_ENTRY(HWM_TX_CHECK)
- * void HWM_TX_CHECK(smc,frame_status,low_water)
- *
- * function MACRO (hardware module, hwmtm.h)
- * This macro is invoked by the OS-specific before it left it's
- * driver_send function. This macro calls mac_drv_clear_txd
- * if the free TxDs of the current transmit queue is equal or
- * lower than the given low water mark.
- *
- * para frame_status status of the frame, see design description
- * low_water low water mark of free TxD's
- *
- * END_MANUAL_ENTRY
- */
-#ifndef HWM_NO_FLOW_CTL
-#define HWM_TX_CHECK(smc,frame_status,low_water) {\
- if ((low_water)>=(smc)->hw.fp.tx_q[(frame_status)&QUEUE_A0].tx_free) {\
- mac_drv_clear_txd(smc) ;\
- }\
-}
-#else
-#define HWM_TX_CHECK(smc,frame_status,low_water) mac_drv_clear_txd(smc)
-#endif
-
-/*
* BEGIN_MANUAL_ENTRY(HWM_GET_RX_FRAG_LEN)
* int HWM_GET_RX_FRAG_LEN(rxd)
*
diff --git a/drivers/net/skfp/hwmtm.c b/drivers/net/skfp/hwmtm.c
index 18d429021edb..438f424e6361 100644
--- a/drivers/net/skfp/hwmtm.c
+++ b/drivers/net/skfp/hwmtm.c
@@ -86,6 +86,7 @@ static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue);
static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue);
static SMbuf* get_llc_rx(struct s_smc *smc);
static SMbuf* get_txd_mb(struct s_smc *smc);
+static void mac_drv_clear_txd(struct s_smc *smc);
/*
-------------------------------------------------------------
@@ -146,7 +147,6 @@ extern int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead,
*/
void process_receive(struct s_smc *smc);
void fddi_isr(struct s_smc *smc);
-void mac_drv_clear_txd(struct s_smc *smc);
void smt_free_mbuf(struct s_smc *smc, SMbuf *mb);
void init_driver_fplus(struct s_smc *smc);
void mac_drv_rx_mode(struct s_smc *smc, int mode);
@@ -158,7 +158,6 @@ void hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
int frame_status);
-int mac_drv_rx_frag(struct s_smc *smc, void far *virt, int len);
int mac_drv_init(struct s_smc *smc);
int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len,
int frame_status);
@@ -1448,35 +1447,6 @@ void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
NDD_TRACE("RHfE",r,AIX_REVERSE(r->rxd_rbadr),0) ;
}
-#ifndef NDIS_OS2
-/*
- * BEGIN_MANUAL_ENTRY(mac_drv_rx_frag)
- * int mac_drv_rx_frag(smc,virt,len)
- *
- * function DOWNCALL (hwmtm.c)
- * mac_drv_rx_frag fills the fragment with a part of the frame.
- *
- * para virt the virtual address of the fragment
- * len the length in bytes of the fragment
- *
- * return 0: success code, no errors possible
- *
- * END_MANUAL_ENTRY
- */
-int mac_drv_rx_frag(struct s_smc *smc, void far *virt, int len)
-{
- NDD_TRACE("RHSB",virt,len,smc->os.hwm.r.mb_pos) ;
-
- DB_RX("receive from queue: len/virt: = %d/%x",len,virt,4) ;
- memcpy((char far *)virt,smc->os.hwm.r.mb_pos,len) ;
- smc->os.hwm.r.mb_pos += len ;
-
- NDD_TRACE("RHSE",smc->os.hwm.r.mb_pos,0,0) ;
- return(0) ;
-}
-#endif
-
-
/*
* BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue)
*
@@ -1978,7 +1948,7 @@ void smt_send_mbuf(struct s_smc *smc, SMbuf *mb, int fc)
*
* END_MANUAL_ENTRY
*/
-void mac_drv_clear_txd(struct s_smc *smc)
+static void mac_drv_clear_txd(struct s_smc *smc)
{
struct s_smt_tx_queue *queue ;
struct s_smt_fp_txd volatile *t1 ;
diff --git a/drivers/net/skfp/pcmplc.c b/drivers/net/skfp/pcmplc.c
index 571f055c096b..cd0aa4c151b0 100644
--- a/drivers/net/skfp/pcmplc.c
+++ b/drivers/net/skfp/pcmplc.c
@@ -1861,13 +1861,6 @@ void plc_irq(struct s_smc *smc, int np, unsigned int cmd)
#endif
}
-void pcm_set_lct_short(struct s_smc *smc, int n)
-{
- if (n <= 0 || n > 1000)
- return ;
- smc->s.lct_short = n ;
-}
-
#ifdef DEBUG
/*
* fill state struct
diff --git a/drivers/net/skfp/pmf.c b/drivers/net/skfp/pmf.c
index f2b446d8b0bf..efc639c013fd 100644
--- a/drivers/net/skfp/pmf.c
+++ b/drivers/net/skfp/pmf.c
@@ -36,12 +36,13 @@ static int smt_authorize(struct s_smc *smc, struct smt_header *sm);
static int smt_check_set_count(struct s_smc *smc, struct smt_header *sm);
static const struct s_p_tab* smt_get_ptab(u_short para);
static int smt_mib_phys(struct s_smc *smc);
-int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, int local,
- int set);
+static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
+ int local, int set);
void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para,
int index, int local);
static SMbuf *smt_build_pmf_response(struct s_smc *smc, struct smt_header *req,
int set, int local);
+static int port_to_mib(struct s_smc *smc, int p);
#define MOFFSS(e) ((int)&(((struct fddi_mib *)0)->e))
#define MOFFSA(e) ((int) (((struct fddi_mib *)0)->e))
@@ -1078,8 +1079,8 @@ wrong_error:
/*
* set parameter
*/
-int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, int local,
- int set)
+static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
+ int local, int set)
{
#define IFSET(x) if (set) (x)
@@ -1549,7 +1550,7 @@ static int smt_mib_phys(struct s_smc *smc)
#endif
}
-int port_to_mib(struct s_smc *smc, int p)
+static int port_to_mib(struct s_smc *smc, int p)
{
#ifdef CONCENTRATOR
SK_UNUSED(smc) ;
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index c88aad6edd74..4b5ed2c63177 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -149,7 +149,6 @@ extern void hwm_rx_frag(struct s_smc *smc, char far * virt, u_long phys,
extern void mac_drv_rx_mode(struct s_smc *smc, int mode);
extern void mac_drv_clear_rx_queue(struct s_smc *smc);
extern void enable_tx_irq(struct s_smc *smc, u_short queue);
-extern void mac_drv_clear_txd(struct s_smc *smc);
static struct pci_device_id skfddi_pci_tbl[] = {
{ PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, },
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index c3a0d2f10b2b..f17c05cbe44b 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -110,7 +110,7 @@ static void smt_fill_setcount(struct s_smc *smc, struct smt_p_setcount *setcount
static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed,
int len);
-void smt_clear_una_dna(struct s_smc *smc);
+static void smt_clear_una_dna(struct s_smc *smc);
static void smt_clear_old_una_dna(struct s_smc *smc);
#ifdef CONCENTRATOR
static int entity_to_index(void);
@@ -118,7 +118,7 @@ static int entity_to_index(void);
static void update_dac(struct s_smc *smc, int report);
static int div_ratio(u_long upper, u_long lower);
#ifdef USE_CAN_ADDR
-void hwm_conv_can(struct s_smc *smc, char *data, int len);
+static void hwm_conv_can(struct s_smc *smc, char *data, int len);
#else
#define hwm_conv_can(smc,data,len)
#endif
@@ -216,24 +216,6 @@ void smt_agent_task(struct s_smc *smc)
DB_SMT("SMT agent task\n",0,0) ;
}
-void smt_please_reconnect(struct s_smc *smc, int reconn_time)
-/* struct s_smc *smc; Pointer to SMT context */
-/* int reconn_time; Wait for reconnect time in seconds */
-{
- /*
- * The please reconnect variable is used as a timer.
- * It is decremented each time smt_event is called.
- * This happens every second or when smt_force_irq is called.
- * Note: smt_force_irq () is called on some packet receives and
- * when a multicast address is changed. Since nothing
- * is received during the disconnect and the multicast
- * address changes can be viewed as not very often and
- * the timer runs out close to its given value
- * (reconn_time).
- */
- smc->sm.please_reconnect = reconn_time ;
-}
-
#ifndef SMT_REAL_TOKEN_CT
void smt_emulate_token_ct(struct s_smc *smc, int mac_index)
{
@@ -1574,7 +1556,7 @@ static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long see
* clear DNA and UNA
* called from CFM if configuration changes
*/
-void smt_clear_una_dna(struct s_smc *smc)
+static void smt_clear_una_dna(struct s_smc *smc)
{
smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
@@ -2058,30 +2040,10 @@ int smt_action(struct s_smc *smc, int class, int code, int index)
}
/*
- * change tneg
- * set T_Req in MIB (Path Attribute)
- * calculate new values for MAC
- * if change required
- * disconnect
- * set reconnect
- * end
- */
-void smt_change_t_neg(struct s_smc *smc, u_long tneg)
-{
- smc->mib.a[PATH0].fddiPATHMaxT_Req = tneg ;
-
- if (smt_set_mac_opvalues(smc)) {
- RS_SET(smc,RS_EVENT) ;
- smc->sm.please_reconnect = 1 ;
- queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
- }
-}
-
-/*
* canonical conversion of <len> bytes beginning form *data
*/
#ifdef USE_CAN_ADDR
-void hwm_conv_can(struct s_smc *smc, char *data, int len)
+static void hwm_conv_can(struct s_smc *smc, char *data, int len)
{
int i ;
diff --git a/drivers/net/skfp/smtdef.c b/drivers/net/skfp/smtdef.c
index 5a0c8db816d8..4e07ff7073f1 100644
--- a/drivers/net/skfp/smtdef.c
+++ b/drivers/net/skfp/smtdef.c
@@ -76,11 +76,6 @@ void smt_reset_defaults(struct s_smc *smc, int level);
static void smt_init_mib(struct s_smc *smc, int level);
static int set_min_max(int maxflag, u_long mib, u_long limit, u_long *oper);
-void smt_set_defaults(struct s_smc *smc)
-{
- smt_reset_defaults(smc,0) ;
-}
-
#define MS2BCLK(x) ((x)*12500L)
#define US2BCLK(x) ((x)*1250L)
diff --git a/drivers/net/skfp/smtparse.c b/drivers/net/skfp/smtparse.c
deleted file mode 100644
index d5779e414dbe..000000000000
--- a/drivers/net/skfp/smtparse.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/******************************************************************************
- *
- * (C)Copyright 1998,1999 SysKonnect,
- * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- * See the file "skfddi.c" for further information.
- *
- * 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.
- *
- * The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-
-/*
- parser for SMT parameters
-*/
-
-#include "h/types.h"
-#include "h/fddi.h"
-#include "h/smc.h"
-#include "h/smt_p.h"
-
-#define KERNEL
-#include "h/smtstate.h"
-
-#ifndef lint
-static const char ID_sccs[] = "@(#)smtparse.c 1.12 98/10/06 (C) SK " ;
-#endif
-
-#ifdef sun
-#define _far
-#endif
-
-/*
- * convert to BCLK units
- */
-#define MS2BCLK(x) ((x)*12500L)
-#define US2BCLK(x) ((x/10)*125L)
-
-/*
- * parameter table
- */
-static struct s_ptab {
- char *pt_name ;
- u_short pt_num ;
- u_short pt_type ;
- u_long pt_min ;
- u_long pt_max ;
-} ptab[] = {
- { "PMFPASSWD",0, 0 } ,
- { "USERDATA",1, 0 } ,
- { "LERCUTOFFA",2, 1, 4, 15 } ,
- { "LERCUTOFFB",3, 1, 4, 15 } ,
- { "LERALARMA",4, 1, 4, 15 } ,
- { "LERALARMB",5, 1, 4, 15 } ,
- { "TMAX",6, 1, 5, 165 } ,
- { "TMIN",7, 1, 5, 165 } ,
- { "TREQ",8, 1, 5, 165 } ,
- { "TVX",9, 1, 2500, 10000 } ,
-#ifdef ESS
- { "SBAPAYLOAD",10, 1, 0, 1562 } ,
- { "SBAOVERHEAD",11, 1, 50, 5000 } ,
- { "MAXTNEG",12, 1, 5, 165 } ,
- { "MINSEGMENTSIZE",13, 1, 0, 4478 } ,
- { "SBACATEGORY",14, 1, 0, 0xffff } ,
- { "SYNCHTXMODE",15, 0 } ,
-#endif
-#ifdef SBA
- { "SBACOMMAND",16, 0 } ,
- { "SBAAVAILABLE",17, 1, 0, 100 } ,
-#endif
- { NULL }
-} ;
-
-/* Define maximum string size for values and keybuffer */
-#define MAX_VAL 40
-
-/*
- * local function declarations
- */
-static u_long parse_num(int type, char _far *value, char *v, u_long mn,
- u_long mx, int scale);
-static int parse_word(char *buf, char _far *text);
-
-#ifdef SIM
-#define DB_MAIN(a,b,c) printf(a,b,c)
-#else
-#define DB_MAIN(a,b,c)
-#endif
-
-/*
- * BEGIN_MANUAL_ENTRY()
- *
- * int smt_parse_arg(struct s_smc *,char _far *keyword,int type,
- char _far *value)
- *
- * parse SMT parameter
- * *keyword
- * pointer to keyword, must be \0, \n or \r terminated
- * *value pointer to value, either char * or u_long *
- * if char *
- * pointer to value, must be \0, \n or \r terminated
- * if u_long *
- * contains binary value
- *
- * type 0: integer
- * 1: string
- * return
- * 0 parameter parsed ok
- * != 0 error
- * NOTE:
- * function can be called with DS != SS
- *
- *
- * END_MANUAL_ENTRY()
- */
-int smt_parse_arg(struct s_smc *smc, char _far *keyword, int type,
- char _far *value)
-{
- char keybuf[MAX_VAL+1];
- char valbuf[MAX_VAL+1];
- char c ;
- char *p ;
- char *v ;
- char *d ;
- u_long val = 0 ;
- struct s_ptab *pt ;
- int st ;
- int i ;
-
- /*
- * parse keyword
- */
- if ((st = parse_word(keybuf,keyword)))
- return(st) ;
- /*
- * parse value if given as string
- */
- if (type == 1) {
- if ((st = parse_word(valbuf,value)))
- return(st) ;
- }
- /*
- * search in table
- */
- st = 0 ;
- for (pt = ptab ; (v = pt->pt_name) ; pt++) {
- for (p = keybuf ; (c = *p) ; p++,v++) {
- if (c != *v)
- break ;
- }
- if (!c && !*v)
- break ;
- }
- if (!v)
- return(-1) ;
-#if 0
- printf("=>%s<==>%s<=\n",pt->pt_name,valbuf) ;
-#endif
- /*
- * set value in MIB
- */
- if (pt->pt_type)
- val = parse_num(type,value,valbuf,pt->pt_min,pt->pt_max,1) ;
- switch (pt->pt_num) {
- case 0 :
- v = valbuf ;
- d = (char *) smc->mib.fddiPRPMFPasswd ;
- for (i = 0 ; i < (signed)sizeof(smc->mib.fddiPRPMFPasswd) ; i++)
- *d++ = *v++ ;
- DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiPRPMFPasswd) ;
- break ;
- case 1 :
- v = valbuf ;
- d = (char *) smc->mib.fddiSMTUserData ;
- for (i = 0 ; i < (signed)sizeof(smc->mib.fddiSMTUserData) ; i++)
- *d++ = *v++ ;
- DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiSMTUserData) ;
- break ;
- case 2 :
- smc->mib.p[PA].fddiPORTLer_Cutoff = (u_char) val ;
- DB_MAIN("SET %s = %d\n",
- pt->pt_name,smc->mib.p[PA].fddiPORTLer_Cutoff) ;
- break ;
- case 3 :
- smc->mib.p[PB].fddiPORTLer_Cutoff = (u_char) val ;
- DB_MAIN("SET %s = %d\n",
- pt->pt_name,smc->mib.p[PB].fddiPORTLer_Cutoff) ;
- break ;
- case 4 :
- smc->mib.p[PA].fddiPORTLer_Alarm = (u_char) val ;
- DB_MAIN("SET %s = %d\n",
- pt->pt_name,smc->mib.p[PA].fddiPORTLer_Alarm) ;
- break ;
- case 5 :
- smc->mib.p[PB].fddiPORTLer_Alarm = (u_char) val ;
- DB_MAIN("SET %s = %d\n",
- pt->pt_name,smc->mib.p[PB].fddiPORTLer_Alarm) ;
- break ;
- case 6 : /* TMAX */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.a[PATH0].fddiPATHT_MaxLowerBound =
- (u_long) -MS2BCLK((long)val) ;
- break ;
- case 7 : /* TMIN */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.m[MAC0].fddiMACT_Min =
- (u_long) -MS2BCLK((long)val) ;
- break ;
- case 8 : /* TREQ */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.a[PATH0].fddiPATHMaxT_Req =
- (u_long) -MS2BCLK((long)val) ;
- break ;
- case 9 : /* TVX */
- DB_MAIN("SET %s = %d \n",pt->pt_name,val) ;
- smc->mib.a[PATH0].fddiPATHTVXLowerBound =
- (u_long) -US2BCLK((long)val) ;
- break ;
-#ifdef ESS
- case 10 : /* SBAPAYLOAD */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- if (smc->mib.fddiESSPayload != val) {
- smc->ess.raf_act_timer_poll = TRUE ;
- smc->mib.fddiESSPayload = val ;
- }
- break ;
- case 11 : /* SBAOVERHEAD */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.fddiESSOverhead = val ;
- break ;
- case 12 : /* MAXTNEG */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.fddiESSMaxTNeg = (u_long) -MS2BCLK((long)val) ;
- break ;
- case 13 : /* MINSEGMENTSIZE */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.fddiESSMinSegmentSize = val ;
- break ;
- case 14 : /* SBACATEGORY */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.fddiESSCategory =
- (smc->mib.fddiESSCategory & 0xffff) |
- ((u_long)(val << 16)) ;
- break ;
- case 15 : /* SYNCHTXMODE */
- /* do not use memcmp(valbuf,"ALL",3) because DS != SS */
- if (valbuf[0] == 'A' && valbuf[1] == 'L' && valbuf[2] == 'L') {
- smc->mib.fddiESSSynchTxMode = TRUE ;
- DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
- }
- /* if (!memcmp(valbuf,"SPLIT",5)) { */
- if (valbuf[0] == 'S' && valbuf[1] == 'P' && valbuf[2] == 'L' &&
- valbuf[3] == 'I' && valbuf[4] == 'T') {
- DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
- smc->mib.fddiESSSynchTxMode = FALSE ;
- }
- break ;
-#endif
-#ifdef SBA
- case 16 : /* SBACOMMAND */
- /* if (!memcmp(valbuf,"START",5)) { */
- if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'A' &&
- valbuf[3] == 'R' && valbuf[4] == 'T') {
- DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
- smc->mib.fddiSBACommand = SB_START ;
- }
- /* if (!memcmp(valbuf,"STOP",4)) { */
- if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'O' &&
- valbuf[3] == 'P') {
- DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
- smc->mib.fddiSBACommand = SB_STOP ;
- }
- break ;
- case 17 : /* SBAAVAILABLE */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.fddiSBAAvailable = (u_char) val ;
- break ;
-#endif
- }
- return(0) ;
-}
-
-static int parse_word(char *buf, char _far *text)
-{
- char c ;
- char *p ;
- int p_len ;
- int quote ;
- int i ;
- int ok ;
-
- /*
- * skip leading white space
- */
- p = buf ;
- for (i = 0 ; i < MAX_VAL ; i++)
- *p++ = 0 ;
- p = buf ;
- p_len = 0 ;
- ok = 0 ;
- while ( (c = *text++) && (c != '\n') && (c != '\r')) {
- if ((c != ' ') && (c != '\t')) {
- ok = 1 ;
- break ;
- }
- }
- if (!ok)
- return(-1) ;
- if (c == '"') {
- quote = 1 ;
- }
- else {
- quote = 0 ;
- text-- ;
- }
- /*
- * parse valbuf
- */
- ok = 0 ;
- while (!ok && p_len < MAX_VAL-1 && (c = *text++) && (c != '\n')
- && (c != '\r')) {
- switch (quote) {
- case 0 :
- if ((c == ' ') || (c == '\t') || (c == '=')) {
- ok = 1 ;
- break ;
- }
- *p++ = c ;
- p_len++ ;
- break ;
- case 2 :
- *p++ = c ;
- p_len++ ;
- quote = 1 ;
- break ;
- case 1 :
- switch (c) {
- case '"' :
- ok = 1 ;
- break ;
- case '\\' :
- quote = 2 ;
- break ;
- default :
- *p++ = c ;
- p_len++ ;
- }
- }
- }
- *p++ = 0 ;
- for (p = buf ; (c = *p) ; p++) {
- if (c >= 'a' && c <= 'z')
- *p = c + 'A' - 'a' ;
- }
- return(0) ;
-}
-
-static u_long parse_num(int type, char _far *value, char *v, u_long mn,
- u_long mx, int scale)
-{
- u_long x = 0 ;
- char c ;
-
- if (type == 0) { /* integer */
- u_long _far *l ;
- u_long u1 ;
-
- l = (u_long _far *) value ;
- u1 = *l ;
- /*
- * if the value is negative take the lower limit
- */
- if ((long)u1 < 0) {
- if (- ((long)u1) > (long) mx) {
- u1 = 0 ;
- }
- else {
- u1 = (u_long) - ((long)u1) ;
- }
- }
- x = u1 ;
- }
- else { /* string */
- int sign = 0 ;
-
- if (*v == '-') {
- sign = 1 ;
- }
- while ((c = *v++) && (c >= '0') && (c <= '9')) {
- x = x * 10 + c - '0' ;
- }
- if (scale == 10) {
- x *= 10 ;
- if (c == '.') {
- if ((c = *v++) && (c >= '0') && (c <= '9')) {
- x += c - '0' ;
- }
- }
- }
- if (sign)
- x = (u_long) - ((long)x) ;
- }
- /*
- * if the value is negative
- * and the absolute value is outside the limits
- * take the lower limit
- * else
- * take the absoute value
- */
- if ((long)x < 0) {
- if (- ((long)x) > (long) mx) {
- x = 0 ;
- }
- else {
- x = (u_long) - ((long)x) ;
- }
- }
- if (x < mn)
- return(mn) ;
- else if (x > mx)
- return(mx) ;
- return(x) ;
-}
-
-#if 0
-struct s_smc SMC ;
-main()
-{
- char *p ;
- char *v ;
- char buf[100] ;
- int toggle = 0 ;
-
- while (gets(buf)) {
- p = buf ;
- while (*p && ((*p == ' ') || (*p == '\t')))
- p++ ;
-
- while (*p && ((*p != ' ') && (*p != '\t')))
- p++ ;
-
- v = p ;
- while (*v && ((*v == ' ') || (*v == '\t')))
- v++ ;
- if ((*v >= '0') && (*v <= '9')) {
- toggle = !toggle ;
- if (toggle) {
- u_long l ;
- l = atol(v) ;
- smt_parse_arg(&SMC,buf,0,(char _far *)&l) ;
- }
- else
- smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
- }
- else {
- smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
- }
- }
- exit(0) ;
-}
-#endif
-
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index fd80048f7f7a..cfb9d3cdb04a 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -315,15 +315,25 @@ static void smc_reset(struct net_device *dev)
struct smc_local *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->base;
unsigned int ctl, cfg;
+ struct sk_buff *pending_skb;
DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
- /* Disable all interrupts */
+ /* Disable all interrupts, block TX tasklet */
spin_lock(&lp->lock);
SMC_SELECT_BANK(2);
SMC_SET_INT_MASK(0);
+ pending_skb = lp->pending_tx_skb;
+ lp->pending_tx_skb = NULL;
spin_unlock(&lp->lock);
+ /* free any pending tx skb */
+ if (pending_skb) {
+ dev_kfree_skb(pending_skb);
+ lp->stats.tx_errors++;
+ lp->stats.tx_aborted_errors++;
+ }
+
/*
* This resets the registers mostly to defaults, but doesn't
* affect EEPROM. That seems unnecessary
@@ -389,14 +399,6 @@ static void smc_reset(struct net_device *dev)
SMC_SELECT_BANK(2);
SMC_SET_MMU_CMD(MC_RESET);
SMC_WAIT_MMU_BUSY();
-
- /* clear anything saved */
- if (lp->pending_tx_skb != NULL) {
- dev_kfree_skb (lp->pending_tx_skb);
- lp->pending_tx_skb = NULL;
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
- }
}
/*
@@ -440,6 +442,7 @@ static void smc_shutdown(struct net_device *dev)
{
struct smc_local *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->base;
+ struct sk_buff *pending_skb;
DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
@@ -447,7 +450,11 @@ static void smc_shutdown(struct net_device *dev)
spin_lock(&lp->lock);
SMC_SELECT_BANK(2);
SMC_SET_INT_MASK(0);
+ pending_skb = lp->pending_tx_skb;
+ lp->pending_tx_skb = NULL;
spin_unlock(&lp->lock);
+ if (pending_skb)
+ dev_kfree_skb(pending_skb);
/* and tell the card to stay away from that nasty outside world */
SMC_SELECT_BANK(0);
@@ -627,7 +634,12 @@ static void smc_hardware_send_pkt(unsigned long data)
}
skb = lp->pending_tx_skb;
+ if (unlikely(!skb)) {
+ smc_special_unlock(&lp->lock);
+ return;
+ }
lp->pending_tx_skb = NULL;
+
packet_no = SMC_GET_AR();
if (unlikely(packet_no & AR_FAILED)) {
printk("%s: Memory allocation failed.\n", dev->name);
@@ -702,7 +714,6 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
BUG_ON(lp->pending_tx_skb != NULL);
- lp->pending_tx_skb = skb;
/*
* The MMU wants the number of pages to be the number of 256 bytes
@@ -718,7 +729,6 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
if (unlikely(numPages > 7)) {
printk("%s: Far too big packet error.\n", dev->name);
- lp->pending_tx_skb = NULL;
lp->stats.tx_errors++;
lp->stats.tx_dropped++;
dev_kfree_skb(skb);
@@ -745,6 +755,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
smc_special_unlock(&lp->lock);
+ lp->pending_tx_skb = skb;
if (!poll_count) {
/* oh well, wait until the chip finds memory later */
netif_stop_queue(dev);
@@ -1062,7 +1073,7 @@ static void smc_phy_powerdown(struct net_device *dev)
above). linkwatch_event() also wants the netlink semaphore.
*/
while(lp->work_pending)
- schedule();
+ yield();
bmcr = smc_phy_read(dev, phy, MII_BMCR);
smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN);
@@ -1606,14 +1617,8 @@ static int smc_close(struct net_device *dev)
/* clear everything */
smc_shutdown(dev);
-
+ tasklet_kill(&lp->tx_task);
smc_phy_powerdown(dev);
-
- if (lp->pending_tx_skb) {
- dev_kfree_skb(lp->pending_tx_skb);
- lp->pending_tx_skb = NULL;
- }
-
return 0;
}
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 6e5ade99a38f..97712c3c4e07 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -455,8 +455,7 @@ static int streamer_reset(struct net_device *dev)
writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL);
t = jiffies;
/* Hold soft reset bit for a while */
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout(HZ);
+ ssleep(1);
writew(readw(streamer_mmio + BCTL) & ~BCTL_SOFTRESET,
streamer_mmio + BCTL);
@@ -512,8 +511,7 @@ static int streamer_reset(struct net_device *dev)
writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
while (!((readw(streamer_mmio + SISR)) & SISR_SRB_REPLY)) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ/10);
+ msleep_interruptible(100);
if (jiffies - t > 40 * HZ) {
printk(KERN_ERR
"IBM PCI tokenring card not responding\n");
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index cfc346e72d62..08e0f80f89d5 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -242,6 +242,7 @@ static struct pci_device_id tulip_pci_tbl[] = {
{ 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X }, /* ALi 1563 integrated ethernet */
{ 0x10b9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X }, /* ALi 1563 integrated ethernet */
{ 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */
+ { 0x14ea, 0xab08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* Planex FNW-3602-TX */
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
@@ -1756,11 +1757,19 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pdev);
- if (dev && netif_running (dev) && netif_device_present (dev)) {
- netif_device_detach (dev);
- tulip_down (dev);
- /* pci_power_off(pdev, -1); */
- }
+ if (!dev)
+ return -EINVAL;
+
+ if (netif_running(dev))
+ tulip_down(dev);
+
+ netif_device_detach(dev);
+ free_irq(dev->irq, dev);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
return 0;
}
@@ -1768,15 +1777,26 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
static int tulip_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ int retval;
- if (dev && netif_running (dev) && !netif_device_present (dev)) {
-#if 1
- pci_enable_device (pdev);
-#endif
- /* pci_power_on(pdev); */
- tulip_up (dev);
- netif_device_attach (dev);
+ if (!dev)
+ return -EINVAL;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ pci_enable_device(pdev);
+
+ if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))) {
+ printk (KERN_ERR "tulip: request_irq failed in resume\n");
+ return retval;
}
+
+ netif_device_attach(dev);
+
+ if (netif_running(dev))
+ tulip_up(dev);
+
return 0;
}
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 6200cfc4244e..be1c1047b9ba 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1398,7 +1398,7 @@ static void rhine_tx(struct net_device *dev)
while (rp->dirty_tx != rp->cur_tx) {
txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
if (debug > 6)
- printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n",
+ printk(KERN_DEBUG "Tx scavenge %d status %8.8x.\n",
entry, txstatus);
if (txstatus & DescOwn)
break;
@@ -1469,7 +1469,7 @@ static void rhine_rx(struct net_device *dev)
int data_size = desc_status >> 16;
if (debug > 4)
- printk(KERN_DEBUG " rhine_rx() status is %8.8x.\n",
+ printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n",
desc_status);
if (--boguscnt < 0)
break;
@@ -1487,7 +1487,7 @@ static void rhine_rx(struct net_device *dev)
} else if (desc_status & RxErr) {
/* There was a error. */
if (debug > 2)
- printk(KERN_DEBUG " rhine_rx() Rx "
+ printk(KERN_DEBUG "rhine_rx() Rx "
"error was %8.8x.\n",
desc_status);
rp->stats.rx_errors++;
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 7575b799ce53..7217d44e8854 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -981,6 +981,7 @@ fst_issue_cmd(struct fst_port_info *port, unsigned short cmd)
/* Wait for any previous command to complete */
while (mbval > NAK) {
spin_unlock_irqrestore(&card->card_lock, flags);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
spin_lock_irqsave(&card->card_lock, flags);
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 180968899cad..c12648d8192b 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -900,7 +900,7 @@ typedef struct aironet_ioctl {
unsigned char __user *data; // d-data
} aironet_ioctl;
-static char *swversion = "2.1";
+static char swversion[] = "2.1";
#endif /* CISCO_EXT */
#define NUM_MODULES 2
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index b1078baa1d5e..aabcdc2be05e 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -46,382 +46,9 @@
* under either the MPL or the GPL. */
/*
- * v0.01 -> v0.02 - 21/3/2001 - Jean II
- * o Allow to use regular ethX device name instead of dldwdX
- * o Warning on IBSS with ESSID=any for firmware 6.06
- * o Put proper range.throughput values (optimistic)
- * o IWSPY support (IOCTL and stat gather in Rx path)
- * o Allow setting frequency in Ad-Hoc mode
- * o Disable WEP setting if !has_wep to work on old firmware
- * o Fix txpower range
- * o Start adding support for Samsung/Compaq firmware
- *
- * v0.02 -> v0.03 - 23/3/2001 - Jean II
- * o Start adding Symbol support - need to check all that
- * o Fix Prism2/Symbol WEP to accept 128 bits keys
- * o Add Symbol WEP (add authentication type)
- * o Add Prism2/Symbol rate
- * o Add PM timeout (holdover duration)
- * o Enable "iwconfig eth0 key off" and friends (toggle flags)
- * o Enable "iwconfig eth0 power unicast/all" (toggle flags)
- * o Try with an Intel card. It report firmware 1.01, behave like
- * an antiquated firmware, however on windows it says 2.00. Yuck !
- * o Workaround firmware bug in allocate buffer (Intel 1.01)
- * o Finish external renaming to orinoco...
- * o Testing with various Wavelan firmwares
- *
- * v0.03 -> v0.04 - 30/3/2001 - Jean II
- * o Update to Wireless 11 -> add retry limit/lifetime support
- * o Tested with a D-Link DWL 650 card, fill in firmware support
- * o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot)
- * o Fixed the Prism2 WEP bugs that I introduced in v0.03 :-(
- * It works on D-Link *only* after a tcpdump. Weird...
- * And still doesn't work on Intel card. Grrrr...
- * o Update the mode after a setport3
- * o Add preamble setting for Symbol cards (not yet enabled)
- * o Don't complain as much about Symbol cards...
- *
- * v0.04 -> v0.04b - 22/4/2001 - David Gibson
- * o Removed the 'eth' parameter - always use ethXX as the
- * interface name instead of dldwdXX. The other was racy
- * anyway.
- * o Clean up RID definitions in hermes.h, other cleanups
- *
- * v0.04b -> v0.04c - 24/4/2001 - Jean II
- * o Tim Hurley <timster AT seiki.bliztech.com> reported a D-Link card
- * with vendor 02 and firmware 0.08. Added in the capabilities...
- * o Tested Lucent firmware 7.28, everything works...
- *
- * v0.04c -> v0.05 - 3/5/2001 - Benjamin Herrenschmidt
- * o Spin-off Pcmcia code. This file is renamed orinoco.c,
- * and orinoco_cs.c now contains only the Pcmcia specific stuff
- * o Add Airport driver support on top of orinoco.c (see airport.c)
- *
- * v0.05 -> v0.05a - 4/5/2001 - Jean II
- * o Revert to old Pcmcia code to fix breakage of Ben's changes...
- *
- * v0.05a -> v0.05b - 4/5/2001 - Jean II
- * o add module parameter 'ignore_cis_vcc' for D-Link @ 5V
- * o D-Link firmware doesn't support multicast. We just print a few
- * error messages, but otherwise everything works...
- * o For David : set/getport3 works fine, just upgrade iwpriv...
- *
- * v0.05b -> v0.05c - 5/5/2001 - Benjamin Herrenschmidt
- * o Adapt airport.c to latest changes in orinoco.c
- * o Remove deferred power enabling code
- *
- * v0.05c -> v0.05d - 5/5/2001 - Jean II
- * o Workaround to SNAP decapsulate frame from Linksys AP
- * original patch from : Dong Liu <dliu AT research.bell-labs.com>
- * (note : the memcmp bug was mine - fixed)
- * o Remove set_retry stuff, no firmware support it (bloat--).
- *
- * v0.05d -> v0.06 - 25/5/2001 - Jean II
- * Original patch from "Hong Lin" <alin AT redhat.com>,
- * "Ian Kinner" <ikinner AT redhat.com>
- * and "David Smith" <dsmith AT redhat.com>
- * o Init of priv->tx_rate_ctrl in firmware specific section.
- * o Prism2/Symbol rate, upto should be 0xF and not 0x15. Doh !
- * o Spectrum card always need cor_reset (for every reset)
- * o Fix cor_reset to not lose bit 7 in the register
- * o flush_stale_links to remove zombie Pcmcia instances
- * o Ack previous hermes event before reset
- * Me (with my little hands)
- * o Allow orinoco.c to call cor_reset via priv->card_reset_handler
- * o Add priv->need_card_reset to toggle this feature
- * o Fix various buglets when setting WEP in Symbol firmware
- * Now, encryption is fully functional on Symbol cards. Youpi !
- *
- * v0.06 -> v0.06b - 25/5/2001 - Jean II
- * o IBSS on Symbol use port_mode = 4. Please don't ask...
- *
- * v0.06b -> v0.06c - 29/5/2001 - Jean II
- * o Show first spy address in /proc/net/wireless for IBSS mode as well
- *
- * v0.06c -> v0.06d - 6/7/2001 - David Gibson
- * o Change a bunch of KERN_INFO messages to KERN_DEBUG, as per Linus'
- * wishes to reduce the number of unnecessary messages.
- * o Removed bogus message on CRC error.
- * o Merged fixes for v0.08 Prism 2 firmware from William Waghorn
- * <willwaghorn AT yahoo.co.uk>
- * o Slight cleanup/re-arrangement of firmware detection code.
- *
- * v0.06d -> v0.06e - 1/8/2001 - David Gibson
- * o Removed some redundant global initializers (orinoco_cs.c).
- * o Added some module metadata
- *
- * v0.06e -> v0.06f - 14/8/2001 - David Gibson
- * o Wording fix to license
- * o Added a 'use_alternate_encaps' module parameter for APs which need an
- * oui of 00:00:00. We really need a better way of handling this, but
- * the module flag is better than nothing for now.
- *
- * v0.06f -> v0.07 - 20/8/2001 - David Gibson
- * o Removed BAP error retries from hermes_bap_seek(). For Tx we now
- * let the upper layers handle the retry, we retry explicitly in the
- * Rx path, but don't make as much noise about it.
- * o Firmware detection cleanups.
- *
- * v0.07 -> v0.07a - 1/10/3001 - Jean II
- * o Add code to read Symbol firmware revision, inspired by latest code
- * in Spectrum24 by Lee John Keyser-Allen - Thanks Lee !
- * o Thanks to Jared Valentine <hidden AT xmission.com> for "providing" me
- * a 3Com card with a recent firmware, fill out Symbol firmware
- * capabilities of latest rev (2.20), as well as older Symbol cards.
- * o Disable Power Management in newer Symbol firmware, the API
- * has changed (documentation needed).
- *
- * v0.07a -> v0.08 - 3/10/2001 - David Gibson
- * o Fixed a possible buffer overrun found by the Stanford checker (in
- * dldwd_ioctl_setiwencode()). Can only be called by root anyway, so not
- * a big problem.
- * o Turned has_big_wep on for Intersil cards. That's not true for all of
- * them but we should at least let the capable ones try.
- * o Wait for BUSY to clear at the beginning of hermes_bap_seek(). I
- * realized that my assumption that the driver's serialization
- * would prevent the BAP being busy on entry was possibly false, because
- * things other than seeks may make the BAP busy.
- * o Use "alternate" (oui 00:00:00) encapsulation by default.
- * Setting use_old_encaps will mimic the old behaviour, but I think we
- * will be able to eliminate this.
- * o Don't try to make __initdata const (the version string). This can't
- * work because of the way the __initdata sectioning works.
- * o Added MODULE_LICENSE tags.
- * o Support for PLX (transparent PCMCIA->PCI bridge) cards.
- * o Changed to using the new type-fascist min/max.
- *
- * v0.08 -> v0.08a - 9/10/2001 - David Gibson
- * o Inserted some missing acknowledgements/info into the Changelog.
- * o Fixed some bugs in the normalization of signal level reporting.
- * o Fixed bad bug in WEP key handling on Intersil and Symbol firmware,
- * which led to an instant crash on big-endian machines.
- *
- * v0.08a -> v0.08b - 20/11/2001 - David Gibson
- * o Lots of cleanup and bugfixes in orinoco_plx.c
- * o Cleanup to handling of Tx rate setting.
- * o Removed support for old encapsulation method.
- * o Removed old "dldwd" names.
- * o Split RID constants into a new file hermes_rid.h
- * o Renamed RID constants to match linux-wlan-ng and prism2.o
- * o Bugfixes in hermes.c
- * o Poke the PLX's INTCSR register, so it actually starts
- * generating interrupts. These cards might actually work now.
- * o Update to wireless extensions v12 (Jean II)
- * o Support for tallies and inquire command (Jean II)
- * o Airport updates for newer PPC kernels (BenH)
- *
- * v0.08b -> v0.09 - 21/12/2001 - David Gibson
- * o Some new PCI IDs for PLX cards.
- * o Removed broken attempt to do ALLMULTI reception. Just use
- * promiscuous mode instead
- * o Preliminary work for list-AP (Jean II)
- * o Airport updates from (BenH)
- * o Eliminated racy hw_ready stuff
- * o Fixed generation of fake events in irq handler. This should
- * finally kill the EIO problems (Jean II & dgibson)
- * o Fixed breakage of bitrate set/get on Agere firmware (Jean II)
- *
- * v0.09 -> v0.09a - 2/1/2002 - David Gibson
- * o Fixed stupid mistake in multicast list handling, triggering
- * a BUG()
- *
- * v0.09a -> v0.09b - 16/1/2002 - David Gibson
- * o Fixed even stupider mistake in new interrupt handling, which
- * seriously broke things on big-endian machines.
- * o Removed a bunch of redundant includes and exports.
- * o Removed a redundant MOD_{INC,DEC}_USE_COUNT pair in airport.c
- * o Don't attempt to do hardware level multicast reception on
- * Intersil firmware, just go promisc instead.
- * o Typo fixed in hermes_issue_cmd()
- * o Eliminated WIRELESS_SPY #ifdefs
- * o Status code reported on Tx exceptions
- * o Moved netif_wake_queue() from ALLOC interrupts to TX and TXEXC
- * interrupts, which should fix the timeouts we're seeing.
- *
- * v0.09b -> v0.10 - 25 Feb 2002 - David Gibson
- * o Removed nested structures used for header parsing, so the
- * driver should now work without hackery on ARM
- * o Fix for WEP handling on Intersil (Hawk Newton)
- * o Eliminated the /proc/hermes/ethXX/regs debugging file. It
- * was never very useful.
- * o Make Rx errors less noisy.
- *
- * v0.10 -> v0.11 - 5 Apr 2002 - David Gibson
- * o Laid the groundwork in hermes.[ch] for devices which map
- * into PCI memory space rather than IO space.
- * o Fixed bug in multicast handling (cleared multicast list when
- * leaving promiscuous mode).
- * o Relegated Tx error messages to debug.
- * o Cleaned up / corrected handling of allocation lengths.
- * o Set OWNSSID in IBSS mode for WinXP interoperability (jimc).
- * o Change to using alloc_etherdev() for structure allocations.
- * o Check for and drop undersized packets.
- * o Fixed a race in stopping/waking the queue. This should fix
- * the timeout problems (Pavel Roskin)
- * o Reverted to netif_wake_queue() on the ALLOC event.
- * o Fixes for recent Symbol firmwares which lack AP density
- * (Pavel Roskin).
- *
- * v0.11 -> v0.11a - 29 Apr 2002 - David Gibson
- * o Handle different register spacing, necessary for Prism 2.5
- * PCI adaptors (Steve Hill).
- * o Cleaned up initialization of card structures in orinoco_cs
- * and airport. Removed card->priv field.
- * o Make response structure optional for hermes_docmd_wait()
- * Pavel Roskin)
- * o Added PCI id for Nortel emobility to orinoco_plx.c.
- * o Cleanup to handling of Symbol's allocation bug. (Pavel Roskin)
- * o Cleanups to firmware capability detection.
- * o Arrange for orinoco_pci.c to override firmware detection.
- * We should be able to support the PCI Intersil cards now.
- * o Cleanup handling of reset_cor and hard_reset (Pavel Roskin).
- * o Remove erroneous use of USER_BAP in the TxExc handler (Jouni
- * Malinen).
- * o Makefile changes for better integration into David Hinds
- * pcmcia-cs package.
- *
- * v0.11a -> v0.11b - 1 May 2002 - David Gibson
- * o Better error reporting in orinoco_plx_init_one()
- * o Fixed multiple bad kfree() bugs introduced by the
- * alloc_orinocodev() changes.
- *
- * v0.11b -> v0.12 - 19 Jun 2002 - David Gibson
- * o Support changing the MAC address.
- * o Correct display of Intersil firmware revision numbers.
- * o Entirely revised locking scheme. Should be both simpler and
- * better.
- * o Merged some common code in orinoco_plx, orinoco_pci and
- * airport by creating orinoco_default_{open,stop,reset}()
- * which are used as the dev->open, dev->stop, priv->reset
- * callbacks if none are specified when alloc_orinocodev() is
- * called.
- * o Removed orinoco_plx_interrupt() and orinoco_pci_interrupt().
- * They didn't do anything.
- *
- * v0.12 -> v0.12a - 4 Jul 2002 - David Gibson
- * o Some rearrangement of code.
- * o Numerous fixups to locking and rest handling, particularly
- * for PCMCIA.
- * o This allows open and stop net_device methods to be in
- * orinoco.c now, rather than in the init modules.
- * o In orinoco_cs.c link->priv now points to the struct
- * net_device not to the struct orinoco_private.
- * o Added a check for undersized SNAP frames, which could cause
- * crashes.
- *
- * v0.12a -> v0.12b - 11 Jul 2002 - David Gibson
- * o Fix hw->num_init testing code, so num_init is actually
- * incremented.
- * o Fix very stupid bug in orinoco_cs which broke compile with
- * CONFIG_SMP.
- * o Squashed a warning.
- *
- * v0.12b -> v0.12c - 26 Jul 2002 - David Gibson
- * o Change to C9X style designated initializers.
- * o Add support for 3Com AirConnect PCI.
- * o No longer ignore the hard_reset argument to
- * alloc_orinocodev(). Oops.
- *
- * v0.12c -> v0.13beta1 - 13 Sep 2002 - David Gibson
- * o Revert the broken 0.12* locking scheme and go to a new yet
- * simpler scheme.
- * o Do firmware resets only in orinoco_init() and when waking
- * the card from hard sleep.
- *
- * v0.13beta1 -> v0.13 - 27 Sep 2002 - David Gibson
- * o Re-introduced full resets (via schedule_task()) on Tx
- * timeout.
- *
- * v0.13 -> v0.13a - 30 Sep 2002 - David Gibson
- * o Minor cleanups to info frame handling. Add basic support
- * for linkstatus info frames.
- * o Include required kernel headers in orinoco.h, to avoid
- * compile problems.
- *
- * v0.13a -> v0.13b - 10 Feb 2003 - David Gibson
- * o Implemented hard reset for Airport cards
- * o Experimental suspend/resume implementation for orinoco_pci
- * o Abolished /proc debugging support, replaced with a debugging
- * iwpriv. Now it's ugly and simple instead of ugly and complex.
- * o Bugfix in hermes.c if the firmware returned a record length
- * of 0, we could go clobbering memory.
- * o Bugfix in orinoco_stop() - it used to fail if hw_unavailable
- * was set, which was usually true on PCMCIA hot removes.
- * o Track LINKSTATUS messages, silently drop Tx packets before
- * we are connected (avoids confusing the firmware), and only
- * give LINKSTATUS printk()s if the status has changed.
- *
- * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson
- * o Cleanup: use dev instead of priv in various places.
- * o Bug fix: Don't ReleaseConfiguration on RESET_PHYSICAL event
- * if we're in the middle of a (driver initiated) hard reset.
- * o Bug fix: ETH_ZLEN is supposed to include the header
- * (Dionysus Blazakis & Manish Karir)
- * o Convert to using workqueues instead of taskqueues (and
- * backwards compatibility macros for pre 2.5.41 kernels).
- * o Drop redundant (I think...) MOD_{INC,DEC}_USE_COUNT in
- * airport.c
- * o New orinoco_tmd.c init module from Joerg Dorchain for
- * TMD7160 based PCI to PCMCIA bridges (similar to
- * orinoco_plx.c).
- *
- * v0.13c -> v0.13d - 22 Apr 2003 - David Gibson
- * o Make hw_unavailable a counter, rather than just a flag, this
- * is necessary to avoid some races (such as a card being
- * removed in the middle of orinoco_reset().
- * o Restore Release/RequestConfiguration in the PCMCIA event handler
- * when dealing with a driver initiated hard reset. This is
- * necessary to prevent hangs due to a spurious interrupt while
- * the reset is in progress.
- * o Clear the 802.11 header when transmitting, even though we
- * don't use it. This fixes a long standing bug on some
- * firmwares, which seem to get confused if that isn't done.
- * o Be less eager to de-encapsulate SNAP frames, only do so if
- * the OUI is 00:00:00 or 00:00:f8, leave others alone. The old
- * behaviour broke CDP (Cisco Discovery Protocol).
- * o Use dev instead of priv for free_irq() as well as
- * request_irq() (oops).
- * o Attempt to reset rather than giving up if we get too many
- * IRQs.
- * o Changed semantics of __orinoco_down() so it can be called
- * safely with hw_unavailable set. It also now clears the
- * linkstatus (since we're going to have to reassociate).
- *
- * v0.13d -> v0.13e - 12 May 2003 - David Gibson
- * o Support for post-2.5.68 return values from irq handler.
- * o Fixed bug where underlength packets would be double counted
- * in the rx_dropped statistics.
- * o Provided a module parameter to suppress linkstatus messages.
- *
- * v0.13e -> v0.14alpha1 - 30 Sep 2003 - David Gibson
- * o Replaced priv->connected logic with netif_carrier_on/off()
- * calls.
- * o Remove has_ibss_any and never set the CREATEIBSS RID when
- * the ESSID is empty. Too many firmwares break if we do.
- * o 2.6 merges: Replace pdev->slot_name with pci_name(), remove
- * __devinitdata from PCI ID tables, use free_netdev().
- * o Enabled shared-key authentication for Agere firmware (from
- * Robert J. Moore <Robert.J.Moore AT allanbank.com>
- * o Move netif_wake_queue() (back) to the Tx completion from the
- * ALLOC event. This seems to prevent/mitigate the rolling
- * error -110 problems at least on some Intersil firmwares.
- * Theoretically reduces performance, but I can't measure it.
- * Patch from Andrew Tridgell <tridge AT samba.org>
- *
- * v0.14alpha1 -> v0.14alpha2 - 20 Oct 2003 - David Gibson
- * o Correctly turn off shared-key authentication when requested
- * (bugfix from Robert J. Moore).
- * o Correct airport sleep interfaces for current 2.6 kernels.
- * o Add code for key change without disabling/enabling the MAC
- * port. This is supposed to allow 802.1x to work sanely, but
- * doesn't seem to yet.
- *
* TODO
- * o New wireless extensions API (patch from Moustafa
- * Youssef, updated by Jim Carter and Pavel Roskin).
* o Handle de-encapsulation within network layer, provide 802.11
* headers (patch from Thomas 'Dent' Mirlacher)
- * o RF monitor mode support
* o Fix possible races in SPY handling.
* o Disconnect wireless extensions from fundamental configuration.
* o (maybe) Software WEP support (patch from Stano Meduna).
@@ -462,7 +89,10 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -496,6 +126,10 @@ static int ignore_disconnect; /* = 0 */
module_param(ignore_disconnect, int, 0644);
MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer");
+static int force_monitor; /* = 0 */
+module_param(force_monitor, int, 0644);
+MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
+
/********************************************************************/
/* Compile time configuration and compatibility stuff */
/********************************************************************/
@@ -511,6 +145,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
/* Internal constants */
/********************************************************************/
+/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
+static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
+
#define ORINOCO_MIN_MTU 256
#define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
@@ -537,6 +175,11 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
| HERMES_EV_WTERR | HERMES_EV_INFO \
| HERMES_EV_INFDROP )
+#define MAX_RID_LEN 1024
+
+static const struct iw_handler_def orinoco_handler_def;
+static struct ethtool_ops orinoco_ethtool_ops;
+
/********************************************************************/
/* Data tables */
/********************************************************************/
@@ -571,26 +214,45 @@ static struct {
/* Data types */
/********************************************************************/
-struct header_struct {
- /* 802.3 */
- u8 dest[ETH_ALEN];
- u8 src[ETH_ALEN];
- u16 len;
- /* 802.2 */
+/* Used in Event handling.
+ * We avoid nested structres as they break on ARM -- Moustafa */
+struct hermes_tx_descriptor_802_11 {
+ /* hermes_tx_descriptor */
+ u16 status;
+ u16 reserved1;
+ u16 reserved2;
+ u32 sw_support;
+ u8 retry_count;
+ u8 tx_rate;
+ u16 tx_control;
+
+ /* ieee802_11_hdr */
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+ u8 addr4[ETH_ALEN];
+ u16 data_len;
+
+ /* ethhdr */
+ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
+ unsigned char h_source[ETH_ALEN]; /* source ether addr */
+ unsigned short h_proto; /* packet type ID field */
+
+ /* p8022_hdr */
u8 dsap;
u8 ssap;
u8 ctrl;
- /* SNAP */
u8 oui[3];
+
u16 ethertype;
} __attribute__ ((packed));
-/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
-u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-
-#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
-
+/* Rx frame header except compatibility 802.3 header */
struct hermes_rx_descriptor {
+ /* Control */
u16 status;
u32 time;
u8 silence;
@@ -598,13 +260,24 @@ struct hermes_rx_descriptor {
u8 rate;
u8 rxflow;
u32 reserved;
+
+ /* 802.11 header */
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+ u8 addr4[ETH_ALEN];
+
+ /* Data length */
+ u16 data_len;
} __attribute__ ((packed));
/********************************************************************/
/* Function prototypes */
/********************************************************************/
-static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int __orinoco_program_rids(struct net_device *dev);
static void __orinoco_set_multicast_list(struct net_device *dev);
@@ -628,6 +301,10 @@ static inline void set_port_type(struct orinoco_private *priv)
priv->createibss = 1;
}
break;
+ case IW_MODE_MONITOR:
+ priv->port_type = 3;
+ priv->createibss = 0;
+ break;
default:
printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
priv->ndev->name);
@@ -814,7 +491,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
return 1;
}
- if (! netif_carrier_ok(dev)) {
+ if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
/* Oops, the firmware hasn't established a connection,
silently drop the packet (this seems to be the
safest approach). */
@@ -951,26 +628,55 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
struct orinoco_private *priv = netdev_priv(dev);
struct net_device_stats *stats = &priv->stats;
u16 fid = hermes_read_regn(hw, TXCOMPLFID);
- struct hermes_tx_descriptor desc;
+ struct hermes_tx_descriptor_802_11 hdr;
int err = 0;
if (fid == DUMMY_FID)
return; /* Nothing's really happened */
- err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0);
+ /* Read the frame header */
+ err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
+ sizeof(struct hermes_tx_descriptor) +
+ sizeof(struct ieee80211_hdr),
+ fid, 0);
+
+ hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+ stats->tx_errors++;
+
if (err) {
printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
"(FID=%04X error %d)\n",
dev->name, fid, err);
- } else {
- DEBUG(1, "%s: Tx error, status %d\n",
- dev->name, le16_to_cpu(desc.status));
+ return;
}
- stats->tx_errors++;
+ DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
+ err, fid);
+
+ /* We produce a TXDROP event only for retry or lifetime
+ * exceeded, because that's the only status that really mean
+ * that this particular node went away.
+ * Other errors means that *we* screwed up. - Jean II */
+ hdr.status = le16_to_cpu(hdr.status);
+ if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
+ union iwreq_data wrqu;
+
+ /* Copy 802.11 dest address.
+ * We use the 802.11 header because the frame may
+ * not be 802.3 or may be mangled...
+ * In Ad-Hoc mode, it will be the node address.
+ * In managed mode, it will be most likely the AP addr
+ * User space will figure out how to convert it to
+ * whatever it needs (IP address or else).
+ * - Jean II */
+ memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+
+ /* Send event to user space */
+ wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
+ }
netif_wake_queue(dev);
- hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
}
static void orinoco_tx_timeout(struct net_device *dev)
@@ -1047,18 +753,127 @@ static void orinoco_stat_gather(struct net_device *dev,
}
}
+/*
+ * orinoco_rx_monitor - handle received monitor frames.
+ *
+ * Arguments:
+ * dev network device
+ * rxfid received FID
+ * desc rx descriptor of the frame
+ *
+ * Call context: interrupt
+ */
+static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
+ struct hermes_rx_descriptor *desc)
+{
+ u32 hdrlen = 30; /* return full header by default */
+ u32 datalen = 0;
+ u16 fc;
+ int err;
+ int len;
+ struct sk_buff *skb;
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &priv->stats;
+ hermes_t *hw = &priv->hw;
+
+ len = le16_to_cpu(desc->data_len);
+
+ /* Determine the size of the header and the data */
+ fc = le16_to_cpu(desc->frame_ctl);
+ switch (fc & IEEE80211_FCTL_FTYPE) {
+ case IEEE80211_FTYPE_DATA:
+ if ((fc & IEEE80211_FCTL_TODS)
+ && (fc & IEEE80211_FCTL_FROMDS))
+ hdrlen = 30;
+ else
+ hdrlen = 24;
+ datalen = len;
+ break;
+ case IEEE80211_FTYPE_MGMT:
+ hdrlen = 24;
+ datalen = len;
+ break;
+ case IEEE80211_FTYPE_CTL:
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PSPOLL:
+ case IEEE80211_STYPE_RTS:
+ case IEEE80211_STYPE_CFEND:
+ case IEEE80211_STYPE_CFENDACK:
+ hdrlen = 16;
+ break;
+ case IEEE80211_STYPE_CTS:
+ case IEEE80211_STYPE_ACK:
+ hdrlen = 10;
+ break;
+ }
+ break;
+ default:
+ /* Unknown frame type */
+ break;
+ }
+
+ /* sanity check the length */
+ if (datalen > IEEE80211_DATA_LEN + 12) {
+ printk(KERN_DEBUG "%s: oversized monitor frame, "
+ "data length = %d\n", dev->name, datalen);
+ err = -EIO;
+ stats->rx_length_errors++;
+ goto update_stats;
+ }
+
+ skb = dev_alloc_skb(hdrlen + datalen);
+ if (!skb) {
+ printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
+ dev->name);
+ err = -ENOMEM;
+ goto drop;
+ }
+
+ /* Copy the 802.11 header to the skb */
+ memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
+ skb->mac.raw = skb->data;
+
+ /* If any, copy the data from the card to the skb */
+ if (datalen > 0) {
+ err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+ ALIGN(datalen, 2), rxfid,
+ HERMES_802_2_OFFSET);
+ if (err) {
+ printk(KERN_ERR "%s: error %d reading monitor frame\n",
+ dev->name, err);
+ goto drop;
+ }
+ }
+
+ skb->dev = dev;
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = __constant_htons(ETH_P_802_2);
+
+ dev->last_rx = jiffies;
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+
+ netif_rx(skb);
+ return;
+
+ drop:
+ dev_kfree_skb_irq(skb);
+ update_stats:
+ stats->rx_errors++;
+ stats->rx_dropped++;
+}
+
static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
{
struct orinoco_private *priv = netdev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct iw_statistics *wstats = &priv->wstats;
struct sk_buff *skb = NULL;
- u16 rxfid, status;
- int length, data_len, data_off;
- char *p;
+ u16 rxfid, status, fc;
+ int length;
struct hermes_rx_descriptor desc;
- struct header_struct hdr;
- struct ethhdr *eh;
+ struct ethhdr *hdr;
int err;
rxfid = hermes_read_regn(hw, RXFID);
@@ -1068,53 +883,46 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
if (err) {
printk(KERN_ERR "%s: error %d reading Rx descriptor. "
"Frame dropped.\n", dev->name, err);
- stats->rx_errors++;
- goto drop;
+ goto update_stats;
}
status = le16_to_cpu(desc.status);
- if (status & HERMES_RXSTAT_ERR) {
- if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
- wstats->discard.code++;
- DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
- dev->name);
- } else {
- stats->rx_crc_errors++;
- DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name);
- }
- stats->rx_errors++;
- goto drop;
+ if (status & HERMES_RXSTAT_BADCRC) {
+ DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
+ dev->name);
+ stats->rx_crc_errors++;
+ goto update_stats;
}
- /* For now we ignore the 802.11 header completely, assuming
- that the card's firmware has handled anything vital */
+ /* Handle frames in monitor mode */
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ orinoco_rx_monitor(dev, rxfid, &desc);
+ return;
+ }
- err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr),
- rxfid, HERMES_802_3_OFFSET);
- if (err) {
- printk(KERN_ERR "%s: error %d reading frame header. "
- "Frame dropped.\n", dev->name, err);
- stats->rx_errors++;
- goto drop;
+ if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
+ DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
+ dev->name);
+ wstats->discard.code++;
+ goto update_stats;
}
- length = ntohs(hdr.len);
-
+ length = le16_to_cpu(desc.data_len);
+ fc = le16_to_cpu(desc.frame_ctl);
+
/* Sanity checks */
if (length < 3) { /* No for even an 802.2 LLC header */
/* At least on Symbol firmware with PCF we get quite a
lot of these legitimately - Poll frames with no
data. */
- stats->rx_dropped++;
- goto drop;
+ return;
}
if (length > IEEE802_11_DATA_LEN) {
printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
dev->name, length);
stats->rx_length_errors++;
- stats->rx_errors++;
- goto drop;
+ goto update_stats;
}
/* We need space for the packet data itself, plus an ethernet
@@ -1126,60 +934,53 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
if (!skb) {
printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
dev->name);
- goto drop;
+ goto update_stats;
}
- skb_reserve(skb, 2); /* This way the IP header is aligned */
+ /* We'll prepend the header, so reserve space for it. The worst
+ case is no decapsulation, when 802.3 header is prepended and
+ nothing is removed. 2 is for aligning the IP header. */
+ skb_reserve(skb, ETH_HLEN + 2);
+
+ err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
+ ALIGN(length, 2), rxfid,
+ HERMES_802_2_OFFSET);
+ if (err) {
+ printk(KERN_ERR "%s: error %d reading frame. "
+ "Frame dropped.\n", dev->name, err);
+ goto drop;
+ }
/* Handle decapsulation
* In most cases, the firmware tell us about SNAP frames.
* For some reason, the SNAP frames sent by LinkSys APs
* are not properly recognised by most firmwares.
* So, check ourselves */
- if (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
- ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
- is_ethersnap(&hdr)) {
+ if (length >= ENCAPS_OVERHEAD &&
+ (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
+ ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
+ is_ethersnap(skb->data))) {
/* These indicate a SNAP within 802.2 LLC within
802.11 frame which we'll need to de-encapsulate to
the original EthernetII frame. */
-
- if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
- stats->rx_length_errors++;
- goto drop;
- }
-
- /* Remove SNAP header, reconstruct EthernetII frame */
- data_len = length - ENCAPS_OVERHEAD;
- data_off = HERMES_802_3_OFFSET + sizeof(hdr);
-
- eh = (struct ethhdr *)skb_put(skb, ETH_HLEN);
-
- memcpy(eh, &hdr, 2 * ETH_ALEN);
- eh->h_proto = hdr.ethertype;
+ hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
} else {
- /* All other cases indicate a genuine 802.3 frame. No
- decapsulation needed. We just throw the whole
- thing in, and hope the protocol layer can deal with
- it as 802.3 */
- data_len = length;
- data_off = HERMES_802_3_OFFSET;
- /* FIXME: we re-read from the card data we already read here */
- }
-
- p = skb_put(skb, data_len);
- err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2),
- rxfid, data_off);
- if (err) {
- printk(KERN_ERR "%s: error %d reading frame. "
- "Frame dropped.\n", dev->name, err);
- stats->rx_errors++;
- goto drop;
+ /* 802.3 frame - prepend 802.3 header as is */
+ hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+ hdr->h_proto = htons(length);
}
+ memcpy(hdr->h_dest, desc.addr1, ETH_ALEN);
+ if (fc & IEEE80211_FCTL_FROMDS)
+ memcpy(hdr->h_source, desc.addr3, ETH_ALEN);
+ else
+ memcpy(hdr->h_source, desc.addr2, ETH_ALEN);
dev->last_rx = jiffies;
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_NONE;
+ if (fc & IEEE80211_FCTL_TODS)
+ skb->pkt_type = PACKET_OTHERHOST;
/* Process the wireless stats if needed */
orinoco_stat_gather(dev, skb, &desc);
@@ -1192,11 +993,10 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
return;
drop:
+ dev_kfree_skb_irq(skb);
+ update_stats:
+ stats->rx_errors++;
stats->rx_dropped++;
-
- if (skb)
- dev_kfree_skb_irq(skb);
- return;
}
/********************************************************************/
@@ -1240,6 +1040,99 @@ static void print_linkstatus(struct net_device *dev, u16 status)
dev->name, s, status);
}
+/* Search scan results for requested BSSID, join it if found */
+static void orinoco_join_ap(struct net_device *dev)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct hermes *hw = &priv->hw;
+ int err;
+ unsigned long flags;
+ struct join_req {
+ u8 bssid[ETH_ALEN];
+ u16 channel;
+ } __attribute__ ((packed)) req;
+ const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
+ struct prism2_scan_apinfo *atom;
+ int offset = 4;
+ u8 *buf;
+ u16 len;
+
+ /* Allocate buffer for scan results */
+ buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
+ if (! buf)
+ return;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ goto out;
+
+ /* Sanity checks in case user changed something in the meantime */
+ if (! priv->bssid_fixed)
+ goto out;
+
+ if (strlen(priv->desired_essid) == 0)
+ goto out;
+
+ /* Read scan results from the firmware */
+ err = hermes_read_ltv(hw, USER_BAP,
+ HERMES_RID_SCANRESULTSTABLE,
+ MAX_SCAN_LEN, &len, buf);
+ if (err) {
+ printk(KERN_ERR "%s: Cannot read scan results\n",
+ dev->name);
+ goto out;
+ }
+
+ len = HERMES_RECLEN_TO_BYTES(len);
+
+ /* Go through the scan results looking for the channel of the AP
+ * we were requested to join */
+ for (; offset + atom_len <= len; offset += atom_len) {
+ atom = (struct prism2_scan_apinfo *) (buf + offset);
+ if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0)
+ goto found;
+ }
+
+ DEBUG(1, "%s: Requested AP not found in scan results\n",
+ dev->name);
+ goto out;
+
+ found:
+ memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
+ req.channel = atom->channel; /* both are little-endian */
+ err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
+ &req);
+ if (err)
+ printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
+
+ out:
+ kfree(buf);
+ orinoco_unlock(priv, &flags);
+}
+
+/* Send new BSSID to userspace */
+static void orinoco_send_wevents(struct net_device *dev)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct hermes *hw = &priv->hw;
+ union iwreq_data wrqu;
+ int err;
+ unsigned long flags;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return;
+
+ err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
+ ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
+ if (err != 0)
+ return;
+
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+ /* Send event to user space */
+ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+ orinoco_unlock(priv, &flags);
+}
+
static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
{
struct orinoco_private *priv = netdev_priv(dev);
@@ -1307,6 +1200,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
u16 newstatus;
int connected;
+ if (priv->iw_mode == IW_MODE_MONITOR)
+ break;
+
if (len != sizeof(linkstatus)) {
printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
dev->name, len);
@@ -1319,6 +1215,15 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
break;
newstatus = le16_to_cpu(linkstatus.linkstatus);
+ /* Symbol firmware uses "out of range" to signal that
+ * the hostscan frame can be requested. */
+ if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
+ priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
+ priv->has_hostscan && priv->scan_inprogress) {
+ hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
+ break;
+ }
+
connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
|| (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
|| (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
@@ -1328,12 +1233,89 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
else if (!ignore_disconnect)
netif_carrier_off(dev);
- if (newstatus != priv->last_linkstatus)
+ if (newstatus != priv->last_linkstatus) {
+ priv->last_linkstatus = newstatus;
print_linkstatus(dev, newstatus);
+ /* The info frame contains only one word which is the
+ * status (see hermes.h). The status is pretty boring
+ * in itself, that's why we export the new BSSID...
+ * Jean II */
+ schedule_work(&priv->wevent_work);
+ }
+ }
+ break;
+ case HERMES_INQ_SCAN:
+ if (!priv->scan_inprogress && priv->bssid_fixed &&
+ priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
+ schedule_work(&priv->join_work);
+ break;
+ }
+ /* fall through */
+ case HERMES_INQ_HOSTSCAN:
+ case HERMES_INQ_HOSTSCAN_SYMBOL: {
+ /* Result of a scanning. Contains information about
+ * cells in the vicinity - Jean II */
+ union iwreq_data wrqu;
+ unsigned char *buf;
+
+ /* Sanity check */
+ if (len > 4096) {
+ printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
+ dev->name, len);
+ break;
+ }
- priv->last_linkstatus = newstatus;
+ /* We are a strict producer. If the previous scan results
+ * have not been consumed, we just have to drop this
+ * frame. We can't remove the previous results ourselves,
+ * that would be *very* racy... Jean II */
+ if (priv->scan_result != NULL) {
+ printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name);
+ break;
+ }
+
+ /* Allocate buffer for results */
+ buf = kmalloc(len, GFP_ATOMIC);
+ if (buf == NULL)
+ /* No memory, so can't printk()... */
+ break;
+
+ /* Read scan data */
+ err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
+ infofid, sizeof(info));
+ if (err)
+ break;
+
+#ifdef ORINOCO_DEBUG
+ {
+ int i;
+ printk(KERN_DEBUG "Scan result [%02X", buf[0]);
+ for(i = 1; i < (len * 2); i++)
+ printk(":%02X", buf[i]);
+ printk("]\n");
+ }
+#endif /* ORINOCO_DEBUG */
+
+ /* Allow the clients to access the results */
+ priv->scan_len = len;
+ priv->scan_result = buf;
+
+ /* Send an empty event to user space.
+ * We don't send the received data on the event because
+ * it would require us to do complex transcoding, and
+ * we want to minimise the work done in the irq handler
+ * Use a request to extract the data - Jean II */
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
}
break;
+ case HERMES_INQ_SEC_STAT_AGERE:
+ /* Security status (Agere specific) */
+ /* Ignore this frame for now */
+ if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+ break;
+ /* fall through */
default:
printk(KERN_DEBUG "%s: Unknown information frame received: "
"type 0x%04x, length %d\n", dev->name, type, len);
@@ -1470,6 +1452,36 @@ static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
return err;
}
+/* Set fixed AP address */
+static int __orinoco_hw_set_wap(struct orinoco_private *priv)
+{
+ int roaming_flag;
+ int err = 0;
+ hermes_t *hw = &priv->hw;
+
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_AGERE:
+ /* not supported */
+ break;
+ case FIRMWARE_TYPE_INTERSIL:
+ if (priv->bssid_fixed)
+ roaming_flag = 2;
+ else
+ roaming_flag = 1;
+
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFROAMINGMODE,
+ roaming_flag);
+ break;
+ case FIRMWARE_TYPE_SYMBOL:
+ err = HERMES_WRITE_RECORD(hw, USER_BAP,
+ HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
+ &priv->desired_bssid);
+ break;
+ }
+ return err;
+}
+
/* Change the WEP keys and/or the current keys. Can be called
* either from __orinoco_hw_setup_wep() or directly from
* orinoco_ioctl_setiwencode(). In the later case the association
@@ -1655,6 +1667,13 @@ static int __orinoco_program_rids(struct net_device *dev)
}
}
+ /* Set the desired BSSID */
+ err = __orinoco_hw_set_wap(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting AP address\n",
+ dev->name, err);
+ return err;
+ }
/* Set the desired ESSID */
idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
@@ -1793,6 +1812,20 @@ static int __orinoco_program_rids(struct net_device *dev)
}
}
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ /* Enable monitor mode */
+ dev->type = ARPHRD_IEEE80211;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_MONITOR, 0, NULL);
+ } else {
+ /* Disable monitor mode */
+ dev->type = ARPHRD_ETHER;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_STOP, 0, NULL);
+ }
+ if (err)
+ return err;
+
/* Set promiscuity / multicast*/
priv->promiscuous = 0;
priv->mc_count = 0;
@@ -1869,55 +1902,6 @@ __orinoco_set_multicast_list(struct net_device *dev)
dev->flags &= ~IFF_PROMISC;
}
-static int orinoco_reconfigure(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- struct hermes *hw = &priv->hw;
- unsigned long flags;
- int err = 0;
-
- if (priv->broken_disableport) {
- schedule_work(&priv->reset_work);
- return 0;
- }
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = hermes_disable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n",
- dev->name);
- priv->broken_disableport = 1;
- goto out;
- }
-
- err = __orinoco_program_rids(dev);
- if (err) {
- printk(KERN_WARNING "%s: Unable to reconfigure card\n",
- dev->name);
- goto out;
- }
-
- err = hermes_enable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
- dev->name);
- goto out;
- }
-
- out:
- if (err) {
- printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
- schedule_work(&priv->reset_work);
- err = 0;
- }
-
- orinoco_unlock(priv, &flags);
- return err;
-
-}
-
/* This must be called from user context, without locks held - use
* schedule_work() */
static void orinoco_reset(struct net_device *dev)
@@ -1946,6 +1930,11 @@ static void orinoco_reset(struct net_device *dev)
orinoco_unlock(priv, &flags);
+ /* Scanning support: Cleanup of driver struct */
+ kfree(priv->scan_result);
+ priv->scan_result = NULL;
+ priv->scan_inprogress = 0;
+
if (priv->hard_reset) {
err = (*priv->hard_reset)(priv);
if (err) {
@@ -2184,6 +2173,8 @@ static int determine_firmware(struct net_device *dev)
priv->has_mwo = (firmver >= 0x60000);
priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
priv->ibss_port = 1;
+ priv->has_hostscan = (firmver >= 0x8000a);
+ priv->broken_monitor = (firmver >= 0x80000);
/* Tested with Agere firmware :
* 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
@@ -2229,6 +2220,8 @@ static int determine_firmware(struct net_device *dev)
priv->ibss_port = 4;
priv->broken_disableport = (firmver == 0x25013) ||
(firmver >= 0x30000 && firmver <= 0x31000);
+ priv->has_hostscan = (firmver >= 0x31001) ||
+ (firmver >= 0x29057 && firmver < 0x30000);
/* Tested with Intel firmware : 0x20015 => Jean II */
/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
break;
@@ -2248,6 +2241,7 @@ static int determine_firmware(struct net_device *dev)
priv->has_ibss = (firmver >= 0x000700); /* FIXME */
priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
priv->has_pm = (firmver >= 0x000700);
+ priv->has_hostscan = (firmver >= 0x010301);
if (firmver >= 0x000800)
priv->ibss_port = 0;
@@ -2456,8 +2450,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
dev->tx_timeout = orinoco_tx_timeout;
dev->watchdog_timeo = HZ; /* 1 second timeout */
dev->get_stats = orinoco_get_stats;
+ dev->ethtool_ops = &orinoco_ethtool_ops;
dev->get_wireless_stats = orinoco_get_wireless_stats;
- dev->do_ioctl = orinoco_ioctl;
+ dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def;
dev->change_mtu = orinoco_change_mtu;
dev->set_multicast_list = orinoco_set_multicast_list;
/* we use the default eth_mac_addr for setting the MAC addr */
@@ -2473,6 +2468,8 @@ struct net_device *alloc_orinocodev(int sizeof_card,
* before anything else touches the
* hardware */
INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
+ INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev);
+ INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev);
netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
@@ -2483,6 +2480,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
void free_orinocodev(struct net_device *dev)
{
+ struct orinoco_private *priv = netdev_priv(dev);
+
+ kfree(priv->scan_result);
free_netdev(dev);
}
@@ -2490,24 +2490,6 @@ void free_orinocodev(struct net_device *dev)
/* Wireless extensions */
/********************************************************************/
-static int orinoco_hw_get_bssid(struct orinoco_private *priv,
- char buf[ETH_ALEN])
-{
- hermes_t *hw = &priv->hw;
- int err = 0;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
- ETH_ALEN, NULL, buf);
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
char buf[IW_ESSID_MAX_SIZE+1])
{
@@ -2633,140 +2615,271 @@ static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
return 0;
}
-static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
+static int orinoco_ioctl_getname(struct net_device *dev,
+ struct iw_request_info *info,
+ char *name,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
- int mode;
- struct iw_range range;
int numrates;
- int i, k;
+ int err;
+
+ err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
+
+ if (!err && (numrates > 2))
+ strcpy(name, "IEEE 802.11b");
+ else
+ strcpy(name, "IEEE 802.11-DS");
+
+ return 0;
+}
+
+static int orinoco_ioctl_setwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
+ static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- TRACE_ENTER(dev->name);
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ /* Enable automatic roaming - no sanity checks are needed */
+ if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
+ memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
+ priv->bssid_fixed = 0;
+ memset(priv->desired_bssid, 0, ETH_ALEN);
+
+ /* "off" means keep existing connection */
+ if (ap_addr->sa_data[0] == 0) {
+ __orinoco_hw_set_wap(priv);
+ err = 0;
+ }
+ goto out;
+ }
+
+ if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
+ printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
+ "support manual roaming\n",
+ dev->name);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (priv->iw_mode != IW_MODE_INFRA) {
+ printk(KERN_WARNING "%s: Manual roaming supported only in "
+ "managed mode\n", dev->name);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ /* Intersil firmware hangs without Desired ESSID */
+ if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
+ strlen(priv->desired_essid) == 0) {
+ printk(KERN_WARNING "%s: Desired ESSID must be set for "
+ "manual roaming\n", dev->name);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ /* Finally, enable manual roaming */
+ priv->bssid_fixed = 1;
+ memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
+
+ out:
+ orinoco_unlock(priv, &flags);
+ return err;
+}
+
+static int orinoco_ioctl_getwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+
+ hermes_t *hw = &priv->hw;
+ int err = 0;
+ unsigned long flags;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ ap_addr->sa_family = ARPHRD_ETHER;
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+ ETH_ALEN, NULL, ap_addr->sa_data);
+
+ orinoco_unlock(priv, &flags);
+
+ return err;
+}
- if (!access_ok(VERIFY_WRITE, rrq->pointer, sizeof(range)))
- return -EFAULT;
+static int orinoco_ioctl_setmode(struct net_device *dev,
+ struct iw_request_info *info,
+ u32 *mode,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int err = -EINPROGRESS; /* Call commit handler */
+ unsigned long flags;
- rrq->length = sizeof(range);
+ if (priv->iw_mode == *mode)
+ return 0;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- mode = priv->iw_mode;
+ switch (*mode) {
+ case IW_MODE_ADHOC:
+ if (!priv->has_ibss && !priv->has_port3)
+ err = -EOPNOTSUPP;
+ break;
+
+ case IW_MODE_INFRA:
+ break;
+
+ case IW_MODE_MONITOR:
+ if (priv->broken_monitor && !force_monitor) {
+ printk(KERN_WARNING "%s: Monitor mode support is "
+ "buggy in this firmware, not enabling\n",
+ dev->name);
+ err = -EOPNOTSUPP;
+ }
+ break;
+
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ if (err == -EINPROGRESS) {
+ priv->iw_mode = *mode;
+ set_port_type(priv);
+ }
+
orinoco_unlock(priv, &flags);
- memset(&range, 0, sizeof(range));
+ return err;
+}
+
+static int orinoco_ioctl_getmode(struct net_device *dev,
+ struct iw_request_info *info,
+ u32 *mode,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+
+ *mode = priv->iw_mode;
+ return 0;
+}
+
+static int orinoco_ioctl_getiwrange(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *rrq,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int err = 0;
+ struct iw_range *range = (struct iw_range *) extra;
+ int numrates;
+ int i, k;
+
+ TRACE_ENTER(dev->name);
- /* Much of this shamelessly taken from wvlan_cs.c. No idea
- * what it all means -dgibson */
- range.we_version_compiled = WIRELESS_EXT;
- range.we_version_source = 11;
+ rrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
- range.min_nwid = range.max_nwid = 0; /* We don't use nwids */
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 14;
/* Set available channels/frequencies */
- range.num_channels = NUM_CHANNELS;
+ range->num_channels = NUM_CHANNELS;
k = 0;
for (i = 0; i < NUM_CHANNELS; i++) {
if (priv->channel_mask & (1 << i)) {
- range.freq[k].i = i + 1;
- range.freq[k].m = channel_frequency[i] * 100000;
- range.freq[k].e = 1;
+ range->freq[k].i = i + 1;
+ range->freq[k].m = channel_frequency[i] * 100000;
+ range->freq[k].e = 1;
k++;
}
if (k >= IW_MAX_FREQUENCIES)
break;
}
- range.num_frequency = k;
+ range->num_frequency = k;
+ range->sensitivity = 3;
- range.sensitivity = 3;
+ if (priv->has_wep) {
+ range->max_encoding_tokens = ORINOCO_MAX_KEYS;
+ range->encoding_size[0] = SMALL_KEY_SIZE;
+ range->num_encoding_sizes = 1;
- if ((mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
+ if (priv->has_big_wep) {
+ range->encoding_size[1] = LARGE_KEY_SIZE;
+ range->num_encoding_sizes = 2;
+ }
+ }
+
+ if ((priv->iw_mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
/* Quality stats meaningless in ad-hoc mode */
- range.max_qual.qual = 0;
- range.max_qual.level = 0;
- range.max_qual.noise = 0;
- range.avg_qual.qual = 0;
- range.avg_qual.level = 0;
- range.avg_qual.noise = 0;
} else {
- range.max_qual.qual = 0x8b - 0x2f;
- range.max_qual.level = 0x2f - 0x95 - 1;
- range.max_qual.noise = 0x2f - 0x95 - 1;
+ range->max_qual.qual = 0x8b - 0x2f;
+ range->max_qual.level = 0x2f - 0x95 - 1;
+ range->max_qual.noise = 0x2f - 0x95 - 1;
/* Need to get better values */
- range.avg_qual.qual = 0x24;
- range.avg_qual.level = 0xC2;
- range.avg_qual.noise = 0x9E;
+ range->avg_qual.qual = 0x24;
+ range->avg_qual.level = 0xC2;
+ range->avg_qual.noise = 0x9E;
}
err = orinoco_hw_get_bitratelist(priv, &numrates,
- range.bitrate, IW_MAX_BITRATES);
+ range->bitrate, IW_MAX_BITRATES);
if (err)
return err;
- range.num_bitrates = numrates;
-
+ range->num_bitrates = numrates;
+
/* Set an indication of the max TCP throughput in bit/s that we can
* expect using this interface. May be use for QoS stuff...
* Jean II */
- if(numrates > 2)
- range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */
+ if (numrates > 2)
+ range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */
else
- range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */
-
- range.min_rts = 0;
- range.max_rts = 2347;
- range.min_frag = 256;
- range.max_frag = 2346;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- if (priv->has_wep) {
- range.max_encoding_tokens = ORINOCO_MAX_KEYS;
-
- range.encoding_size[0] = SMALL_KEY_SIZE;
- range.num_encoding_sizes = 1;
-
- if (priv->has_big_wep) {
- range.encoding_size[1] = LARGE_KEY_SIZE;
- range.num_encoding_sizes = 2;
- }
- } else {
- range.num_encoding_sizes = 0;
- range.max_encoding_tokens = 0;
- }
- orinoco_unlock(priv, &flags);
-
- range.min_pmp = 0;
- range.max_pmp = 65535000;
- range.min_pmt = 0;
- range.max_pmt = 65535 * 1000; /* ??? */
- range.pmp_flags = IW_POWER_PERIOD;
- range.pmt_flags = IW_POWER_TIMEOUT;
- range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
-
- range.num_txpower = 1;
- range.txpower[0] = 15; /* 15dBm */
- range.txpower_capa = IW_TXPOW_DBM;
-
- range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
- range.retry_flags = IW_RETRY_LIMIT;
- range.r_time_flags = IW_RETRY_LIFETIME;
- range.min_retry = 0;
- range.max_retry = 65535; /* ??? */
- range.min_r_time = 0;
- range.max_r_time = 65535 * 1000; /* ??? */
-
- if (copy_to_user(rrq->pointer, &range, sizeof(range)))
- return -EFAULT;
+ range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */
+
+ range->min_rts = 0;
+ range->max_rts = 2347;
+ range->min_frag = 256;
+ range->max_frag = 2346;
+
+ range->min_pmp = 0;
+ range->max_pmp = 65535000;
+ range->min_pmt = 0;
+ range->max_pmt = 65535 * 1000; /* ??? */
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
+
+ range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+ range->retry_flags = IW_RETRY_LIMIT;
+ range->r_time_flags = IW_RETRY_LIFETIME;
+ range->min_retry = 0;
+ range->max_retry = 65535; /* ??? */
+ range->min_r_time = 0;
+ range->max_r_time = 65535 * 1000; /* ??? */
TRACE_EXIT(dev->name);
return 0;
}
-static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setiwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq,
+ char *keybuf)
{
struct orinoco_private *priv = netdev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
@@ -2774,8 +2887,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
int enable = priv->wep_on;
int restricted = priv->wep_restrict;
u16 xlen = 0;
- int err = 0;
- char keybuf[ORINOCO_MAX_KEY_SIZE];
+ int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
if (! priv->has_wep)
@@ -2788,9 +2900,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep )
return -E2BIG;
-
- if (copy_from_user(keybuf, erq->pointer, erq->length))
- return -EFAULT;
}
if (orinoco_lock(priv, &flags) != 0)
@@ -2864,12 +2973,14 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
return err;
}
-static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getiwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq,
+ char *keybuf)
{
struct orinoco_private *priv = netdev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
u16 xlen = 0;
- char keybuf[ORINOCO_MAX_KEY_SIZE];
unsigned long flags;
if (! priv->has_wep)
@@ -2898,51 +3009,47 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *er
memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
orinoco_unlock(priv, &flags);
-
- if (erq->pointer) {
- if (copy_to_user(erq->pointer, keybuf, xlen))
- return -EFAULT;
- }
-
return 0;
}
-static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq,
+ char *essidbuf)
{
struct orinoco_private *priv = netdev_priv(dev);
- char essidbuf[IW_ESSID_MAX_SIZE+1];
unsigned long flags;
/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
* anyway... - Jean II */
- memset(&essidbuf, 0, sizeof(essidbuf));
-
- if (erq->flags) {
- /* iwconfig includes the NUL in the specified length */
- if (erq->length > IW_ESSID_MAX_SIZE+1)
- return -E2BIG;
-
- if (copy_from_user(&essidbuf, erq->pointer, erq->length))
- return -EFAULT;
-
- essidbuf[IW_ESSID_MAX_SIZE] = '\0';
- }
+ /* Hum... Should not use Wireless Extension constant (may change),
+ * should use our own... - Jean II */
+ if (erq->length > IW_ESSID_MAX_SIZE)
+ return -E2BIG;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid));
+ /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
+ memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+
+ /* If not ANY, get the new ESSID */
+ if (erq->flags) {
+ memcpy(priv->desired_essid, essidbuf, erq->length);
+ }
orinoco_unlock(priv, &flags);
- return 0;
+ return -EINPROGRESS; /* Call commit handler */
}
-static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq,
+ char *essidbuf)
{
struct orinoco_private *priv = netdev_priv(dev);
- char essidbuf[IW_ESSID_MAX_SIZE+1];
int active;
int err = 0;
unsigned long flags;
@@ -2956,51 +3063,46 @@ static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
} else {
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- memcpy(essidbuf, priv->desired_essid, sizeof(essidbuf));
+ memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE + 1);
orinoco_unlock(priv, &flags);
}
erq->flags = 1;
erq->length = strlen(essidbuf) + 1;
- if (erq->pointer)
- if (copy_to_user(erq->pointer, essidbuf, erq->length))
- return -EFAULT;
TRACE_EXIT(dev->name);
return 0;
}
-static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_setnick(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *nrq,
+ char *nickbuf)
{
struct orinoco_private *priv = netdev_priv(dev);
- char nickbuf[IW_ESSID_MAX_SIZE+1];
unsigned long flags;
if (nrq->length > IW_ESSID_MAX_SIZE)
return -E2BIG;
- memset(nickbuf, 0, sizeof(nickbuf));
-
- if (copy_from_user(nickbuf, nrq->pointer, nrq->length))
- return -EFAULT;
-
- nickbuf[nrq->length] = '\0';
-
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- memcpy(priv->nick, nickbuf, sizeof(priv->nick));
+ memset(priv->nick, 0, sizeof(priv->nick));
+ memcpy(priv->nick, nickbuf, nrq->length);
orinoco_unlock(priv, &flags);
- return 0;
+ return -EINPROGRESS; /* Call commit handler */
}
-static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_getnick(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *nrq,
+ char *nickbuf)
{
struct orinoco_private *priv = netdev_priv(dev);
- char nickbuf[IW_ESSID_MAX_SIZE+1];
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0)
@@ -3011,23 +3113,22 @@ static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
nrq->length = strlen(nickbuf)+1;
- if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf)))
- return -EFAULT;
-
return 0;
}
-static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
+static int orinoco_ioctl_setfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *frq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
int chan = -1;
unsigned long flags;
+ int err = -EINPROGRESS; /* Call commit handler */
- /* We can only use this in Ad-Hoc demo mode to set the operating
- * frequency, or in IBSS mode to set the frequency where the IBSS
- * will be created - Jean II */
- if (priv->iw_mode != IW_MODE_ADHOC)
- return -EOPNOTSUPP;
+ /* In infrastructure mode the AP sets the channel */
+ if (priv->iw_mode == IW_MODE_INFRA)
+ return -EBUSY;
if ( (frq->e == 0) && (frq->m <= 1000) ) {
/* Setting by channel number */
@@ -3051,13 +3152,44 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
+
priv->channel = chan;
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ /* Fast channel change - no commit if successful */
+ hermes_t *hw = &priv->hw;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_SET_CHANNEL,
+ chan, NULL);
+ }
orinoco_unlock(priv, &flags);
+ return err;
+}
+
+static int orinoco_ioctl_getfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *frq,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int tmp;
+
+ /* Locking done in there */
+ tmp = orinoco_hw_get_freq(priv);
+ if (tmp < 0) {
+ return tmp;
+ }
+
+ frq->m = tmp;
+ frq->e = 1;
+
return 0;
}
-static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_getsens(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *srq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
@@ -3083,7 +3215,10 @@ static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
return 0;
}
-static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_setsens(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *srq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
int val = srq->value;
@@ -3100,10 +3235,13 @@ static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
priv->ap_density = val;
orinoco_unlock(priv, &flags);
- return 0;
+ return -EINPROGRESS; /* Call commit handler */
}
-static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
int val = rrq->value;
@@ -3121,13 +3259,30 @@ static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
priv->rts_thresh = val;
orinoco_unlock(priv, &flags);
+ return -EINPROGRESS; /* Call commit handler */
+}
+
+static int orinoco_ioctl_getrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+
+ rrq->value = priv->rts_thresh;
+ rrq->disabled = (rrq->value == 2347);
+ rrq->fixed = 1;
+
return 0;
}
-static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_setfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *frq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
+ int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0)
@@ -3159,11 +3314,14 @@ static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
return err;
}
-static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_getfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *frq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
- int err = 0;
+ int err;
u16 val;
unsigned long flags;
@@ -3196,10 +3354,12 @@ static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
return err;
}
-static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
int ratemode = -1;
int bitrate; /* 100s of kilobits */
int i;
@@ -3235,10 +3395,13 @@ static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
priv->bitratemode = ratemode;
orinoco_unlock(priv, &flags);
- return err;
+ return -EINPROGRESS;
}
-static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
@@ -3303,10 +3466,13 @@ static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
return err;
}
-static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_setpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *prq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
+ int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0)
@@ -3355,7 +3521,10 @@ static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
return err;
}
-static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_getpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *prq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
@@ -3403,7 +3572,10 @@ static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
return err;
}
-static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getretry(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
@@ -3454,10 +3626,38 @@ static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
return err;
}
-static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_reset(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int val = *( (int *) wrq->u.name );
+
+ if (! capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
+ printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
+
+ /* Firmware reset */
+ orinoco_reset(dev);
+ } else {
+ printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
+
+ schedule_work(&priv->reset_work);
+ }
+
+ return 0;
+}
+
+static int orinoco_ioctl_setibssport(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
+
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int val = *( (int *) extra );
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0)
@@ -3469,28 +3669,28 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
set_port_type(priv);
orinoco_unlock(priv, &flags);
- return 0;
+ return -EINPROGRESS; /* Call commit handler */
}
-static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getibssport(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int *val = (int *)wrq->u.name;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
+ int *val = (int *) extra;
*val = priv->ibss_port;
- orinoco_unlock(priv, &flags);
-
return 0;
}
-static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_setport3(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int val = *( (int *) wrq->u.name );
+ int val = *( (int *) extra );
int err = 0;
unsigned long flags;
@@ -3519,51 +3719,131 @@ static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
err = -EINVAL;
}
- if (! err)
+ if (! err) {
/* Actually update the mode we are using */
set_port_type(priv);
+ err = -EINPROGRESS;
+ }
orinoco_unlock(priv, &flags);
return err;
}
-static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getport3(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int *val = (int *) extra;
+
+ *val = priv->prefer_port3;
+ return 0;
+}
+
+static int orinoco_ioctl_setpreamble(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int *val = (int *)wrq->u.name;
unsigned long flags;
+ int val;
+
+ if (! priv->has_preamble)
+ return -EOPNOTSUPP;
+
+ /* 802.11b has recently defined some short preamble.
+ * Basically, the Phy header has been reduced in size.
+ * This increase performance, especially at high rates
+ * (the preamble is transmitted at 1Mb/s), unfortunately
+ * this give compatibility troubles... - Jean II */
+ val = *( (int *) extra );
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- *val = priv->prefer_port3;
+ if (val)
+ priv->preamble = 1;
+ else
+ priv->preamble = 0;
+
orinoco_unlock(priv, &flags);
+
+ return -EINPROGRESS; /* Call commit handler */
+}
+
+static int orinoco_ioctl_getpreamble(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int *val = (int *) extra;
+
+ if (! priv->has_preamble)
+ return -EOPNOTSUPP;
+
+ *val = priv->preamble;
return 0;
}
+/* ioctl interface to hermes_read_ltv()
+ * To use with iwpriv, pass the RID as the token argument, e.g.
+ * iwpriv get_rid [0xfc00]
+ * At least Wireless Tools 25 is required to use iwpriv.
+ * For Wireless Tools 25 and 26 append "dummy" are the end. */
+static int orinoco_ioctl_getrid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ hermes_t *hw = &priv->hw;
+ int rid = data->flags;
+ u16 length;
+ int err;
+ unsigned long flags;
+
+ /* It's a "get" function, but we don't want users to access the
+ * WEP key and other raw firmware data */
+ if (! capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (rid < 0xfc00 || rid > 0xffff)
+ return -EINVAL;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
+ extra);
+ if (err)
+ goto out;
+
+ data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
+ MAX_RID_LEN);
+
+ out:
+ orinoco_unlock(priv, &flags);
+ return err;
+}
+
/* Spy is used for link quality/strength measurements in Ad-Hoc mode
* Jean II */
-static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_setspy(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *srq,
+ char *extra)
+
{
struct orinoco_private *priv = netdev_priv(dev);
- struct sockaddr address[IW_MAX_SPY];
+ struct sockaddr *address = (struct sockaddr *) extra;
int number = srq->length;
int i;
- int err = 0;
unsigned long flags;
- /* Check the number of addresses */
- if (number > IW_MAX_SPY)
- return -E2BIG;
-
- /* Get the data in the driver */
- if (srq->pointer) {
- if (copy_from_user(address, srq->pointer,
- sizeof(struct sockaddr) * number))
- return -EFAULT;
- }
-
/* Make sure nobody mess with the structure while we do */
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
@@ -3587,14 +3867,17 @@ static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
/* Now, let the others play */
orinoco_unlock(priv, &flags);
- return err;
+ /* Do NOT call commit handler */
+ return 0;
}
-static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_getspy(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *srq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- struct sockaddr address[IW_MAX_SPY];
- struct iw_quality spy_stat[IW_MAX_SPY];
+ struct sockaddr *address = (struct sockaddr *) extra;
int number;
int i;
unsigned long flags;
@@ -3603,7 +3886,12 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
return -EBUSY;
number = priv->spy_number;
- if ((number > 0) && (srq->pointer)) {
+ /* Create address struct */
+ for (i = 0; i < number; i++) {
+ memcpy(address[i].sa_data, priv->spy_address[i], ETH_ALEN);
+ address[i].sa_family = AF_UNIX;
+ }
+ if (number > 0) {
/* Create address struct */
for (i = 0; i < number; i++) {
memcpy(address[i].sa_data, priv->spy_address[i],
@@ -3614,344 +3902,503 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
/* In theory, we should disable irqs while copying the stats
* because the rx path might update it in the middle...
* Bah, who care ? - Jean II */
- memcpy(&spy_stat, priv->spy_stat,
- sizeof(struct iw_quality) * IW_MAX_SPY);
- for (i=0; i < number; i++)
- priv->spy_stat[i].updated = 0;
+ memcpy(extra + (sizeof(struct sockaddr) * number),
+ priv->spy_stat, sizeof(struct iw_quality) * number);
}
+ /* Reset updated flags. */
+ for (i = 0; i < number; i++)
+ priv->spy_stat[i].updated = 0;
orinoco_unlock(priv, &flags);
- /* Push stuff to user space */
srq->length = number;
- if(copy_to_user(srq->pointer, address,
- sizeof(struct sockaddr) * number))
- return -EFAULT;
- if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number),
- &spy_stat, sizeof(struct iw_quality) * number))
- return -EFAULT;
return 0;
}
-static int
-orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+/* Trigger a scan (look for other cells in the vicinity */
+static int orinoco_ioctl_setscan(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *srq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- struct iwreq *wrq = (struct iwreq *)rq;
+ hermes_t *hw = &priv->hw;
int err = 0;
- int tmp;
- int changed = 0;
unsigned long flags;
- TRACE_ENTER(dev->name);
+ /* Note : you may have realised that, as this is a SET operation,
+ * this is priviledged and therefore a normal user can't
+ * perform scanning.
+ * This is not an error, while the device perform scanning,
+ * traffic doesn't flow, so it's a perfect DoS...
+ * Jean II */
- /* In theory, we could allow most of the the SET stuff to be
- * done. In practice, the lapse of time at startup when the
- * card is not ready is very short, so why bother... Note
- * that netif_device_present is different from up/down
- * (ifconfig), when the device is not yet up, it is usually
- * already ready... Jean II */
- if (! netif_device_present(dev))
- return -ENODEV;
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
- switch (cmd) {
- case SIOCGIWNAME:
- strcpy(wrq->u.name, "IEEE 802.11-DS");
- break;
-
- case SIOCGIWAP:
- wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
- err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
- break;
+ /* Scanning with port 0 disabled would fail */
+ if (!netif_running(dev)) {
+ err = -ENETDOWN;
+ goto out;
+ }
- case SIOCGIWRANGE:
- err = orinoco_ioctl_getiwrange(dev, &wrq->u.data);
- break;
+ /* In monitor mode, the scan results are always empty.
+ * Probe responses are passed to the driver as received
+ * frames and could be processed in software. */
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
- case SIOCSIWMODE:
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- switch (wrq->u.mode) {
- case IW_MODE_ADHOC:
- if (! (priv->has_ibss || priv->has_port3) )
- err = -EINVAL;
- else {
- priv->iw_mode = IW_MODE_ADHOC;
- changed = 1;
- }
- break;
+ /* Note : because we don't lock out the irq handler, the way
+ * we access scan variables in priv is critical.
+ * o scan_inprogress : not touched by irq handler
+ * o scan_mode : not touched by irq handler
+ * o scan_result : irq is strict producer, non-irq is strict
+ * consumer.
+ * o scan_len : synchronised with scan_result
+ * Before modifying anything on those variables, please think hard !
+ * Jean II */
- case IW_MODE_INFRA:
- priv->iw_mode = IW_MODE_INFRA;
- changed = 1;
- break;
+ /* If there is still some left-over scan results, get rid of it */
+ if (priv->scan_result != NULL) {
+ /* What's likely is that a client did crash or was killed
+ * between triggering the scan request and reading the
+ * results, so we need to reset everything.
+ * Some clients that are too slow may suffer from that...
+ * Jean II */
+ kfree(priv->scan_result);
+ priv->scan_result = NULL;
+ }
- default:
- err = -EINVAL;
- break;
- }
- set_port_type(priv);
- orinoco_unlock(priv, &flags);
- break;
+ /* Save flags */
+ priv->scan_mode = srq->flags;
- case SIOCGIWMODE:
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- wrq->u.mode = priv->iw_mode;
- orinoco_unlock(priv, &flags);
- break;
+ /* Always trigger scanning, even if it's in progress.
+ * This way, if the info frame get lost, we will recover somewhat
+ * gracefully - Jean II */
- case SIOCSIWENCODE:
- err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding);
- if (! err)
- changed = 1;
+ if (priv->has_hostscan) {
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_SYMBOL:
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFHOSTSCAN_SYMBOL,
+ HERMES_HOSTSCAN_SYMBOL_ONCE |
+ HERMES_HOSTSCAN_SYMBOL_BCAST);
+ break;
+ case FIRMWARE_TYPE_INTERSIL: {
+ u16 req[3];
+
+ req[0] = cpu_to_le16(0x3fff); /* All channels */
+ req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
+ req[2] = 0; /* Any ESSID */
+ err = HERMES_WRITE_RECORD(hw, USER_BAP,
+ HERMES_RID_CNFHOSTSCAN, &req);
+ }
break;
+ case FIRMWARE_TYPE_AGERE:
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSCANSSID_AGERE,
+ 0); /* Any ESSID */
+ if (err)
+ break;
- case SIOCGIWENCODE:
- if (! capable(CAP_NET_ADMIN)) {
- err = -EPERM;
+ err = hermes_inquire(hw, HERMES_INQ_SCAN);
break;
}
+ } else
+ err = hermes_inquire(hw, HERMES_INQ_SCAN);
- err = orinoco_ioctl_getiwencode(dev, &wrq->u.encoding);
- break;
-
- case SIOCSIWESSID:
- err = orinoco_ioctl_setessid(dev, &wrq->u.essid);
- if (! err)
- changed = 1;
- break;
+ /* One more client */
+ if (! err)
+ priv->scan_inprogress = 1;
- case SIOCGIWESSID:
- err = orinoco_ioctl_getessid(dev, &wrq->u.essid);
- break;
+ out:
+ orinoco_unlock(priv, &flags);
+ return err;
+}
- case SIOCSIWNICKN:
- err = orinoco_ioctl_setnick(dev, &wrq->u.data);
- if (! err)
- changed = 1;
- break;
+/* Translate scan data returned from the card to a card independant
+ * format that the Wireless Tools will understand - Jean II */
+static inline int orinoco_translate_scan(struct net_device *dev,
+ char *buffer,
+ char *scan,
+ int scan_len)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int offset; /* In the scan data */
+ union hermes_scan_info *atom;
+ int atom_len;
+ u16 capabilities;
+ u16 channel;
+ struct iw_event iwe; /* Temporary buffer */
+ char * current_ev = buffer;
+ char * end_buf = buffer + IW_SCAN_MAX_DATA;
- case SIOCGIWNICKN:
- err = orinoco_ioctl_getnick(dev, &wrq->u.data);
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_AGERE:
+ atom_len = sizeof(struct agere_scan_apinfo);
+ offset = 0;
break;
-
- case SIOCGIWFREQ:
- tmp = orinoco_hw_get_freq(priv);
- if (tmp < 0) {
- err = tmp;
- } else {
- wrq->u.freq.m = tmp;
- wrq->u.freq.e = 1;
- }
+ case FIRMWARE_TYPE_SYMBOL:
+ /* Lack of documentation necessitates this hack.
+ * Different firmwares have 68 or 76 byte long atoms.
+ * We try modulo first. If the length divides by both,
+ * we check what would be the channel in the second
+ * frame for a 68-byte atom. 76-byte atoms have 0 there.
+ * Valid channel cannot be 0. */
+ if (scan_len % 76)
+ atom_len = 68;
+ else if (scan_len % 68)
+ atom_len = 76;
+ else if (scan_len >= 1292 && scan[68] == 0)
+ atom_len = 76;
+ else
+ atom_len = 68;
+ offset = 0;
break;
-
- case SIOCSIWFREQ:
- err = orinoco_ioctl_setfreq(dev, &wrq->u.freq);
- if (! err)
- changed = 1;
+ case FIRMWARE_TYPE_INTERSIL:
+ offset = 4;
+ if (priv->has_hostscan)
+ atom_len = scan[0] + (scan[1] << 8);
+ else
+ atom_len = offsetof(struct prism2_scan_apinfo, atim);
break;
+ default:
+ return 0;
+ }
- case SIOCGIWSENS:
- err = orinoco_ioctl_getsens(dev, &wrq->u.sens);
- break;
+ /* Check that we got an whole number of atoms */
+ if ((scan_len - offset) % atom_len) {
+ printk(KERN_ERR "%s: Unexpected scan data length %d, "
+ "atom_len %d, offset %d\n", dev->name, scan_len,
+ atom_len, offset);
+ return 0;
+ }
- case SIOCSIWSENS:
- err = orinoco_ioctl_setsens(dev, &wrq->u.sens);
- if (! err)
- changed = 1;
- break;
+ /* Read the entries one by one */
+ for (; offset + atom_len <= scan_len; offset += atom_len) {
+ /* Get next atom */
+ atom = (union hermes_scan_info *) (scan + offset);
+
+ /* First entry *MUST* be the AP MAC address */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN);
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+ /* Other entries will be displayed in the order we give them */
+
+ /* Add the ESSID */
+ iwe.u.data.length = le16_to_cpu(atom->a.essid_len);
+ if (iwe.u.data.length > 32)
+ iwe.u.data.length = 32;
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.flags = 1;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
+
+ /* Add mode */
+ iwe.cmd = SIOCGIWMODE;
+ capabilities = le16_to_cpu(atom->a.capabilities);
+ if (capabilities & 0x3) {
+ if (capabilities & 0x1)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_ADHOC;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
+ }
- case SIOCGIWRTS:
- wrq->u.rts.value = priv->rts_thresh;
- wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
- wrq->u.rts.fixed = 1;
- break;
+ channel = atom->s.channel;
+ if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) {
+ /* Add frequency */
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = channel_frequency[channel-1] * 100000;
+ iwe.u.freq.e = 1;
+ current_ev = iwe_stream_add_event(current_ev, end_buf,
+ &iwe, IW_EV_FREQ_LEN);
+ }
- case SIOCSIWRTS:
- err = orinoco_ioctl_setrts(dev, &wrq->u.rts);
- if (! err)
- changed = 1;
- break;
+ /* Add quality statistics */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.updated = 0x10; /* no link quality */
+ iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95;
+ iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95;
+ /* Wireless tools prior to 27.pre22 will show link quality
+ * anyway, so we provide a reasonable value. */
+ if (iwe.u.qual.level > iwe.u.qual.noise)
+ iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+ else
+ iwe.u.qual.qual = 0;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
- case SIOCSIWFRAG:
- err = orinoco_ioctl_setfrag(dev, &wrq->u.frag);
- if (! err)
- changed = 1;
- break;
+ /* Add encryption capability */
+ iwe.cmd = SIOCGIWENCODE;
+ if (capabilities & 0x10)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ iwe.u.data.length = 0;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
+
+ /* Bit rate is not available in Lucent/Agere firmwares */
+ if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
+ char * current_val = current_ev + IW_EV_LCP_LEN;
+ int i;
+ int step;
+
+ if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
+ step = 2;
+ else
+ step = 1;
+
+ iwe.cmd = SIOCGIWRATE;
+ /* Those two flags are ignored... */
+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+ /* Max 10 values */
+ for (i = 0; i < 10; i += step) {
+ /* NULL terminated */
+ if (atom->p.rates[i] == 0x0)
+ break;
+ /* Bit rate given in 500 kb/s units (+ 0x80) */
+ iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000);
+ current_val = iwe_stream_add_value(current_ev, current_val,
+ end_buf, &iwe,
+ IW_EV_PARAM_LEN);
+ }
+ /* Check if we added any event */
+ if ((current_val - current_ev) > IW_EV_LCP_LEN)
+ current_ev = current_val;
+ }
- case SIOCGIWFRAG:
- err = orinoco_ioctl_getfrag(dev, &wrq->u.frag);
- break;
+ /* The other data in the scan result are not really
+ * interesting, so for now drop it - Jean II */
+ }
+ return current_ev - buffer;
+}
- case SIOCSIWRATE:
- err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate);
- if (! err)
- changed = 1;
- break;
+/* Return results of a scan */
+static int orinoco_ioctl_getscan(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *srq,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int err = 0;
+ unsigned long flags;
- case SIOCGIWRATE:
- err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate);
- break;
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
- case SIOCSIWPOWER:
- err = orinoco_ioctl_setpower(dev, &wrq->u.power);
- if (! err)
- changed = 1;
- break;
+ /* If no results yet, ask to try again later */
+ if (priv->scan_result == NULL) {
+ if (priv->scan_inprogress)
+ /* Important note : we don't want to block the caller
+ * until results are ready for various reasons.
+ * First, managing wait queues is complex and racy.
+ * Second, we grab some rtnetlink lock before comming
+ * here (in dev_ioctl()).
+ * Third, we generate an Wireless Event, so the
+ * caller can wait itself on that - Jean II */
+ err = -EAGAIN;
+ else
+ /* Client error, no scan results...
+ * The caller need to restart the scan. */
+ err = -ENODATA;
+ } else {
+ /* We have some results to push back to user space */
+
+ /* Translate to WE format */
+ srq->length = orinoco_translate_scan(dev, extra,
+ priv->scan_result,
+ priv->scan_len);
+
+ /* Return flags */
+ srq->flags = (__u16) priv->scan_mode;
+
+ /* Results are here, so scan no longer in progress */
+ priv->scan_inprogress = 0;
+
+ /* In any case, Scan results will be cleaned up in the
+ * reset function and when exiting the driver.
+ * The person triggering the scanning may never come to
+ * pick the results, so we need to do it in those places.
+ * Jean II */
+
+#ifdef SCAN_SINGLE_READ
+ /* If you enable this option, only one client (the first
+ * one) will be able to read the result (and only one
+ * time). If there is multiple concurent clients that
+ * want to read scan results, this behavior is not
+ * advisable - Jean II */
+ kfree(priv->scan_result);
+ priv->scan_result = NULL;
+#endif /* SCAN_SINGLE_READ */
+ /* Here, if too much time has elapsed since last scan,
+ * we may want to clean up scan results... - Jean II */
+ }
+
+ orinoco_unlock(priv, &flags);
+ return err;
+}
- case SIOCGIWPOWER:
- err = orinoco_ioctl_getpower(dev, &wrq->u.power);
- break;
+/* Commit handler, called after set operations */
+static int orinoco_ioctl_commit(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct hermes *hw = &priv->hw;
+ unsigned long flags;
+ int err = 0;
- case SIOCGIWTXPOW:
- /* The card only supports one tx power, so this is easy */
- wrq->u.txpower.value = 15; /* dBm */
- wrq->u.txpower.fixed = 1;
- wrq->u.txpower.disabled = 0;
- wrq->u.txpower.flags = IW_TXPOW_DBM;
- break;
+ if (!priv->open)
+ return 0;
- case SIOCSIWRETRY:
- err = -EOPNOTSUPP;
- break;
+ if (priv->broken_disableport) {
+ orinoco_reset(dev);
+ return 0;
+ }
- case SIOCGIWRETRY:
- err = orinoco_ioctl_getretry(dev, &wrq->u.retry);
- break;
+ if (orinoco_lock(priv, &flags) != 0)
+ return err;
- case SIOCSIWSPY:
- err = orinoco_ioctl_setspy(dev, &wrq->u.data);
- break;
+ err = hermes_disable_port(hw, 0);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to disable port "
+ "while reconfiguring card\n", dev->name);
+ priv->broken_disableport = 1;
+ goto out;
+ }
- case SIOCGIWSPY:
- err = orinoco_ioctl_getspy(dev, &wrq->u.data);
- break;
+ err = __orinoco_program_rids(dev);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+ dev->name);
+ goto out;
+ }
- case SIOCGIWPRIV:
- if (wrq->u.data.pointer) {
- struct iw_priv_args privtab[] = {
- { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
- { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
- { SIOCIWFIRSTPRIV + 0x2,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- 0, "set_port3" },
- { SIOCIWFIRSTPRIV + 0x3, 0,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_port3" },
- { SIOCIWFIRSTPRIV + 0x4,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- 0, "set_preamble" },
- { SIOCIWFIRSTPRIV + 0x5, 0,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_preamble" },
- { SIOCIWFIRSTPRIV + 0x6,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- 0, "set_ibssport" },
- { SIOCIWFIRSTPRIV + 0x7, 0,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_ibssport" },
- };
-
- wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]);
- if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab)))
- err = -EFAULT;
- }
- break;
-
- case SIOCIWFIRSTPRIV + 0x0: /* force_reset */
- case SIOCIWFIRSTPRIV + 0x1: /* card_reset */
- if (! capable(CAP_NET_ADMIN)) {
- err = -EPERM;
- break;
- }
-
- printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
+ err = hermes_enable_port(hw, 0);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+ dev->name);
+ goto out;
+ }
+ out:
+ if (err) {
+ printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
schedule_work(&priv->reset_work);
- break;
-
- case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
- if (! capable(CAP_NET_ADMIN)) {
- err = -EPERM;
- break;
- }
-
- err = orinoco_ioctl_setport3(dev, wrq);
- if (! err)
- changed = 1;
- break;
+ err = 0;
+ }
- case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */
- err = orinoco_ioctl_getport3(dev, wrq);
- break;
+ orinoco_unlock(priv, &flags);
+ return err;
+}
- case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */
- if (! capable(CAP_NET_ADMIN)) {
- err = -EPERM;
- break;
- }
+static const struct iw_priv_args orinoco_privtab[] = {
+ { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
+ { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
+ { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ 0, "set_port3" },
+ { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "get_port3" },
+ { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ 0, "set_preamble" },
+ { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "get_preamble" },
+ { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ 0, "set_ibssport" },
+ { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "get_ibssport" },
+ { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
+ "get_rid" },
+};
- /* 802.11b has recently defined some short preamble.
- * Basically, the Phy header has been reduced in size.
- * This increase performance, especially at high rates
- * (the preamble is transmitted at 1Mb/s), unfortunately
- * this give compatibility troubles... - Jean II */
- if(priv->has_preamble) {
- int val = *( (int *) wrq->u.name );
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- if (val)
- priv->preamble = 1;
- else
- priv->preamble = 0;
- orinoco_unlock(priv, &flags);
- changed = 1;
- } else
- err = -EOPNOTSUPP;
- break;
- case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */
- if(priv->has_preamble) {
- int *val = (int *)wrq->u.name;
+/*
+ * Structures to export the Wireless Handlers
+ */
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- *val = priv->preamble;
- orinoco_unlock(priv, &flags);
- } else
- err = -EOPNOTSUPP;
- break;
- case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */
- if (! capable(CAP_NET_ADMIN)) {
- err = -EPERM;
- break;
- }
+static const iw_handler orinoco_handler[] = {
+ [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) orinoco_ioctl_commit,
+ [SIOCGIWNAME -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getname,
+ [SIOCSIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfreq,
+ [SIOCGIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfreq,
+ [SIOCSIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setmode,
+ [SIOCGIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getmode,
+ [SIOCSIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setsens,
+ [SIOCGIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getsens,
+ [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwrange,
+ [SIOCSIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setspy,
+ [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy,
+ [SIOCSIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap,
+ [SIOCGIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap,
+ [SIOCSIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan,
+ [SIOCGIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan,
+ [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid,
+ [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid,
+ [SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick,
+ [SIOCGIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getnick,
+ [SIOCSIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrate,
+ [SIOCGIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrate,
+ [SIOCSIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrts,
+ [SIOCGIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrts,
+ [SIOCSIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfrag,
+ [SIOCGIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfrag,
+ [SIOCGIWRETRY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getretry,
+ [SIOCSIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_setiwencode,
+ [SIOCGIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwencode,
+ [SIOCSIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setpower,
+ [SIOCGIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getpower,
+};
- err = orinoco_ioctl_setibssport(dev, wrq);
- if (! err)
- changed = 1;
- break;
- case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */
- err = orinoco_ioctl_getibssport(dev, wrq);
- break;
+/*
+ Added typecasting since we no longer use iwreq_data -- Moustafa
+ */
+static const iw_handler orinoco_private_handler[] = {
+ [0] (iw_handler) orinoco_ioctl_reset,
+ [1] (iw_handler) orinoco_ioctl_reset,
+ [2] (iw_handler) orinoco_ioctl_setport3,
+ [3] (iw_handler) orinoco_ioctl_getport3,
+ [4] (iw_handler) orinoco_ioctl_setpreamble,
+ [5] (iw_handler) orinoco_ioctl_getpreamble,
+ [6] (iw_handler) orinoco_ioctl_setibssport,
+ [7] (iw_handler) orinoco_ioctl_getibssport,
+ [9] (iw_handler) orinoco_ioctl_getrid,
+};
- default:
- err = -EOPNOTSUPP;
- }
-
- if (! err && changed && netif_running(dev)) {
- err = orinoco_reconfigure(dev);
- }
+static const struct iw_handler_def orinoco_handler_def = {
+ .num_standard = ARRAY_SIZE(orinoco_handler),
+ .num_private = ARRAY_SIZE(orinoco_private_handler),
+ .num_private_args = ARRAY_SIZE(orinoco_privtab),
+ .standard = orinoco_handler,
+ .private = orinoco_private_handler,
+ .private_args = orinoco_privtab,
+};
- TRACE_EXIT(dev->name);
+static void orinoco_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
- return err;
+ strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
+ strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
+ strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
+ if (dev->class_dev.dev)
+ strncpy(info->bus_info, dev->class_dev.dev->bus_id,
+ sizeof(info->bus_info) - 1);
+ else
+ snprintf(info->bus_info, sizeof(info->bus_info) - 1,
+ "PCMCIA %p", priv->hw.iobase);
}
+static struct ethtool_ops orinoco_ethtool_ops = {
+ .get_drvinfo = orinoco_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+};
/********************************************************************/
/* Debugging */
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index f749b50d1088..2f213a7103fe 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -7,7 +7,7 @@
#ifndef _ORINOCO_H
#define _ORINOCO_H
-#define DRIVER_VERSION "0.14alpha2"
+#define DRIVER_VERSION "0.15rc2"
#include <linux/types.h>
#include <linux/spinlock.h>
@@ -22,6 +22,8 @@
#define WIRELESS_SPY // enable iwspy support
+#define MAX_SCAN_LEN 4096
+
#define ORINOCO_MAX_KEY_SIZE 14
#define ORINOCO_MAX_KEYS 4
@@ -30,6 +32,20 @@ struct orinoco_key {
char data[ORINOCO_MAX_KEY_SIZE];
} __attribute__ ((packed));
+struct header_struct {
+ /* 802.3 */
+ u8 dest[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ u16 len;
+ /* 802.2 */
+ u8 dsap;
+ u8 ssap;
+ u8 ctrl;
+ /* SNAP */
+ u8 oui[3];
+ u16 ethertype;
+} __attribute__ ((packed));
+
typedef enum {
FIRMWARE_TYPE_AGERE,
FIRMWARE_TYPE_INTERSIL,
@@ -48,6 +64,8 @@ struct orinoco_private {
/* driver state */
int open;
u16 last_linkstatus;
+ struct work_struct join_work;
+ struct work_struct wevent_work;
/* Net device stuff */
struct net_device *ndev;
@@ -74,7 +92,9 @@ struct orinoco_private {
unsigned int has_pm:1;
unsigned int has_preamble:1;
unsigned int has_sensitivity:1;
+ unsigned int has_hostscan:1;
unsigned int broken_disableport:1;
+ unsigned int broken_monitor:1;
/* Configuration paramaters */
u32 iw_mode;
@@ -84,6 +104,8 @@ struct orinoco_private {
int bitratemode;
char nick[IW_ESSID_MAX_SIZE+1];
char desired_essid[IW_ESSID_MAX_SIZE+1];
+ char desired_bssid[ETH_ALEN];
+ int bssid_fixed;
u16 frag_thresh, mwo_robust;
u16 channel;
u16 ap_density, rts_thresh;
@@ -98,6 +120,12 @@ struct orinoco_private {
/* Configuration dependent variables */
int port_type, createibss;
int promiscuous, mc_count;
+
+ /* Scanning support */
+ int scan_inprogress; /* Scan pending... */
+ u32 scan_mode; /* Type of scan done */
+ char * scan_result; /* Result of previous scan */
+ int scan_len; /* Lenght of result */
};
#ifdef ORINOCO_DEBUG
diff --git a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c
index 4481ec18c5a0..adc7499136dc 100644
--- a/drivers/net/wireless/prism54/isl_38xx.c
+++ b/drivers/net/wireless/prism54/isl_38xx.c
@@ -112,10 +112,10 @@ isl38xx_handle_wakeup(isl38xx_control_block *control_block,
void
isl38xx_trigger_device(int asleep, void __iomem *device_base)
{
- struct timeval current_time;
u32 reg, counter = 0;
#if VERBOSE > SHOW_ERROR_MESSAGES
+ struct timeval current_time;
DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
#endif
@@ -126,11 +126,11 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
do_gettimeofday(&current_time);
DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n",
current_time.tv_sec, (long)current_time.tv_usec);
-#endif
DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
current_time.tv_sec, (long)current_time.tv_usec,
readl(device_base + ISL38XX_CTRL_STAT_REG));
+#endif
udelay(ISL38XX_WRITEIO_DELAY);
reg = readl(device_base + ISL38XX_INT_IDENT_REG);
@@ -148,10 +148,12 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
counter++;
}
+#if VERBOSE > SHOW_ERROR_MESSAGES
DEBUG(SHOW_TRACING,
"%08li.%08li Device register read %08x\n",
current_time.tv_sec, (long)current_time.tv_usec,
readl(device_base + ISL38XX_CTRL_STAT_REG));
+#endif
udelay(ISL38XX_WRITEIO_DELAY);
#if VERBOSE > SHOW_ERROR_MESSAGES