aboutsummaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
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/skge.c1710
-rw-r--r--drivers/net/skge.h586
-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
41 files changed, 3686 insertions, 3820 deletions
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 1247a25f109..9e1fe2e0478 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 47e158fa5aa..2b55687f6ee 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 3fe8ba992c3..f1bd45e3da3 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 25e4495de79..b96d6fb1929 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 b0ef7ad2baa..bd3ad8e6cce 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 cfaa6b2bf34..1e56c8eea35 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 af1e82c5b80..092757bc721 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 237247f74df..f133ff0b0b9 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 723589b28be..045f5426ab9 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 a0263ee96c6..93e9f878875 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 137226d98d4..cb7f051a60a 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 4ebcd052e15..64f0f697c95 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 b43b2b11aac..6518334b928 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 c2f783a6a9f..28af087d9fb 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 28046e9e88b..a451de62919 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 13f11487696..3213f3e5048 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 e15369c8d16..d6388e1533f 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 5f4bb1a6740..cb23580fcff 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 052e841ba18..5b475833f64 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 fd39b4b2ef7..62b01328c49 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 76e78442fc2..a2ed47f1cc7 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 603982debc7..f2f771d8be7 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 4e360af07d7..1a606d4bfe5 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 18d429021ed..438f424e636 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 571f055c096..cd0aa4c151b 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 f2b446d8b0b..efc639c013f 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 c88aad6edd7..4b5ed2c6317 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 c3a0d2f10b2..f17c05cbe44 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 5a0c8db816d..4e07ff7073f 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 d5779e414db..00000000000
--- 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/skge.c b/drivers/net/skge.c
index 30e8d589d16..3dbb1cb09ed 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -7,7 +7,7 @@
* of the original driver such as link fail-over and link management because
* those should be done at higher levels.
*
- * Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
+ * Copyright (C) 2004, 2005 Stephen Hemminger <shemminger@osdl.org>
*
* 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
@@ -42,19 +42,20 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "0.6"
+#define DRV_VERSION "0.7"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
#define DEFAULT_RX_RING_SIZE 512
#define MAX_TX_RING_SIZE 1024
#define MAX_RX_RING_SIZE 4096
+#define RX_COPY_THRESHOLD 128
+#define RX_BUF_SIZE 1536
#define PHY_RETRIES 1000
#define ETH_JUMBO_MTU 9000
#define TX_WATCHDOG (5 * HZ)
#define NAPI_WEIGHT 64
#define BLINK_HZ (HZ/4)
-#define LINK_POLL_HZ (HZ/10)
MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
@@ -70,28 +71,17 @@ module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
static const struct pci_device_id skge_id_table[] = {
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_SYSKONNECT, 0x9E00, /* SK-9Exx */
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_MARVELL, 0x4320, /* Gigabit Ethernet Controller */
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_MARVELL, 0x5005, /* Marvell (11ab), Belkin */
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064,
- PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940) },
+ { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx */
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */
+ { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) },
+ { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032) },
+ { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, skge_id_table);
@@ -99,19 +89,22 @@ MODULE_DEVICE_TABLE(pci, skge_id_table);
static int skge_up(struct net_device *dev);
static int skge_down(struct net_device *dev);
static void skge_tx_clean(struct skge_port *skge);
-static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
-static void skge_gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
static void genesis_get_stats(struct skge_port *skge, u64 *data);
static void yukon_get_stats(struct skge_port *skge, u64 *data);
static void yukon_init(struct skge_hw *hw, int port);
static void yukon_reset(struct skge_hw *hw, int port);
static void genesis_mac_init(struct skge_hw *hw, int port);
static void genesis_reset(struct skge_hw *hw, int port);
+static void genesis_link_up(struct skge_port *skge);
+/* Avoid conditionals by using array */
static const int txqaddr[] = { Q_XA1, Q_XA2 };
static const int rxqaddr[] = { Q_R1, Q_R2 };
static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F };
static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F };
+static const u32 portirqmask[] = { IS_PORT_1, IS_PORT_2 };
/* Don't need to look at whole 16K.
* last interesting register is descriptor poll timer.
@@ -154,7 +147,7 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs,
static int wol_supported(const struct skge_hw *hw)
{
return !((hw->chip_id == CHIP_ID_GENESIS ||
- (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0)));
+ (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)));
}
static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -170,7 +163,7 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
- if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
+ if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
return -EOPNOTSUPP;
if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw))
@@ -190,6 +183,36 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return 0;
}
+/* Determine supported/adverised modes based on hardware.
+ * Note: ethtoool ADVERTISED_xxx == SUPPORTED_xxx
+ */
+static u32 skge_supported_modes(const struct skge_hw *hw)
+{
+ u32 supported;
+
+ if (iscopper(hw)) {
+ supported = SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_1000baseT_Half
+ | SUPPORTED_1000baseT_Full
+ | SUPPORTED_Autoneg| SUPPORTED_TP;
+
+ if (hw->chip_id == CHIP_ID_GENESIS)
+ supported &= ~(SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full);
+
+ else if (hw->chip_id == CHIP_ID_YUKON)
+ supported &= ~SUPPORTED_1000baseT_Half;
+ } else
+ supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
+ | SUPPORTED_Autoneg;
+
+ return supported;
+}
static int skge_get_settings(struct net_device *dev,
struct ethtool_cmd *ecmd)
@@ -198,38 +221,13 @@ static int skge_get_settings(struct net_device *dev,
struct skge_hw *hw = skge->hw;
ecmd->transceiver = XCVR_INTERNAL;
+ ecmd->supported = skge_supported_modes(hw);
if (iscopper(hw)) {
- if (hw->chip_id == CHIP_ID_GENESIS)
- ecmd->supported = SUPPORTED_1000baseT_Full
- | SUPPORTED_1000baseT_Half
- | SUPPORTED_Autoneg | SUPPORTED_TP;
- else {
- ecmd->supported = SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full
- | SUPPORTED_Autoneg| SUPPORTED_TP;
-
- if (hw->chip_id == CHIP_ID_YUKON)
- ecmd->supported &= ~SUPPORTED_1000baseT_Half;
-
- else if (hw->chip_id == CHIP_ID_YUKON_FE)
- ecmd->supported &= ~(SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full);
- }
-
ecmd->port = PORT_TP;
ecmd->phy_address = hw->phy_addr;
- } else {
- ecmd->supported = SUPPORTED_1000baseT_Full
- | SUPPORTED_FIBRE
- | SUPPORTED_Autoneg;
-
+ } else
ecmd->port = PORT_FIBRE;
- }
ecmd->advertising = skge->advertising;
ecmd->autoneg = skge->autoneg;
@@ -238,65 +236,57 @@ static int skge_get_settings(struct net_device *dev,
return 0;
}
-static u32 skge_modes(const struct skge_hw *hw)
-{
- u32 modes = ADVERTISED_Autoneg
- | ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half
- | ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half
- | ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half;
-
- if (iscopper(hw)) {
- modes |= ADVERTISED_TP;
- switch(hw->chip_id) {
- case CHIP_ID_GENESIS:
- modes &= ~(ADVERTISED_100baseT_Full
- | ADVERTISED_100baseT_Half
- | ADVERTISED_10baseT_Full
- | ADVERTISED_10baseT_Half);
- break;
-
- case CHIP_ID_YUKON:
- modes &= ~ADVERTISED_1000baseT_Half;
- break;
-
- case CHIP_ID_YUKON_FE:
- modes &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
- break;
- }
- } else {
- modes |= ADVERTISED_FIBRE;
- modes &= ~ADVERTISED_1000baseT_Half;
- }
- return modes;
-}
-
static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct skge_port *skge = netdev_priv(dev);
const struct skge_hw *hw = skge->hw;
+ u32 supported = skge_supported_modes(hw);
if (ecmd->autoneg == AUTONEG_ENABLE) {
- if (ecmd->advertising & skge_modes(hw))
- return -EINVAL;
+ ecmd->advertising = supported;
+ skge->duplex = -1;
+ skge->speed = -1;
} else {
+ u32 setting;
+
switch(ecmd->speed) {
case SPEED_1000:
- if (hw->chip_id == CHIP_ID_YUKON_FE)
+ if (ecmd->duplex == DUPLEX_FULL)
+ setting = SUPPORTED_1000baseT_Full;
+ else if (ecmd->duplex == DUPLEX_HALF)
+ setting = SUPPORTED_1000baseT_Half;
+ else
return -EINVAL;
break;
case SPEED_100:
+ if (ecmd->duplex == DUPLEX_FULL)
+ setting = SUPPORTED_100baseT_Full;
+ else if (ecmd->duplex == DUPLEX_HALF)
+ setting = SUPPORTED_100baseT_Half;
+ else
+ return -EINVAL;
+ break;
+
case SPEED_10:
- if (iscopper(hw) || hw->chip_id == CHIP_ID_GENESIS)
+ if (ecmd->duplex == DUPLEX_FULL)
+ setting = SUPPORTED_10baseT_Full;
+ else if (ecmd->duplex == DUPLEX_HALF)
+ setting = SUPPORTED_10baseT_Half;
+ else
return -EINVAL;
break;
default:
return -EINVAL;
}
+
+ if ((setting & supported) == 0)
+ return -EINVAL;
+
+ skge->speed = ecmd->speed;
+ skge->duplex = ecmd->duplex;
}
skge->autoneg = ecmd->autoneg;
- skge->speed = ecmd->speed;
- skge->duplex = ecmd->duplex;
skge->advertising = ecmd->advertising;
if (netif_running(dev)) {
@@ -393,7 +383,7 @@ static void skge_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
int i;
- switch(stringset) {
+ switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < ARRAY_SIZE(skge_stats); i++)
memcpy(data + i * ETH_GSTRING_LEN,
@@ -511,14 +501,6 @@ static int skge_set_rx_csum(struct net_device *dev, u32 data)
return 0;
}
-/* Only Yukon II supports TSO (not implemented yet) */
-static int skge_set_tso(struct net_device *dev, u32 data)
-{
- if (data)
- return -EOPNOTSUPP;
- return 0;
-}
-
static void skge_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *ecmd)
{
@@ -540,9 +522,9 @@ static int skge_set_pauseparam(struct net_device *dev,
skge->autoneg = ecmd->autoneg;
if (ecmd->rx_pause && ecmd->tx_pause)
skge->flow_control = FLOW_MODE_SYMMETRIC;
- else if(ecmd->rx_pause && !ecmd->tx_pause)
+ else if (ecmd->rx_pause && !ecmd->tx_pause)
skge->flow_control = FLOW_MODE_REM_SEND;
- else if(!ecmd->rx_pause && ecmd->tx_pause)
+ else if (!ecmd->rx_pause && ecmd->tx_pause)
skge->flow_control = FLOW_MODE_LOC_SEND;
else
skge->flow_control = FLOW_MODE_NONE;
@@ -559,8 +541,6 @@ static inline u32 hwkhz(const struct skge_hw *hw)
{
if (hw->chip_id == CHIP_ID_GENESIS)
return 53215; /* or: 53.125 MHz */
- else if (hw->chip_id == CHIP_ID_YUKON_EC)
- return 125000; /* or: 125.000 MHz */
else
return 78215; /* or: 78.125 MHz */
}
@@ -643,30 +623,18 @@ static int skge_set_coalesce(struct net_device *dev,
static void skge_led_on(struct skge_hw *hw, int port)
{
if (hw->chip_id == CHIP_ID_GENESIS) {
- skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON);
+ skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON);
skge_write8(hw, B0_LED, LED_STAT_ON);
- skge_write8(hw, SKGEMAC_REG(port, RX_LED_TST), LED_T_ON);
- skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 100);
- skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START);
+ skge_write8(hw, SK_REG(port, RX_LED_TST), LED_T_ON);
+ skge_write32(hw, SK_REG(port, RX_LED_VAL), 100);
+ skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
- switch (hw->phy_type) {
- case SK_PHY_BCOM:
- skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL,
- PHY_B_PEC_LED_ON);
- break;
- case SK_PHY_LONE:
- skge_xm_phy_write(hw, port, PHY_LONE_LED_CFG,
- 0x0800);
- break;
- default:
- skge_write8(hw, SKGEMAC_REG(port, TX_LED_TST), LED_T_ON);
- skge_write32(hw, SKGEMAC_REG(port, TX_LED_VAL), 100);
- skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START);
- }
+ /* For Broadcom Phy only */
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
} else {
- skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
- skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+ gm_phy_write(hw, port, PHY_MARV_LED_OVER,
PHY_M_LED_MO_DUP(MO_LED_ON) |
PHY_M_LED_MO_10(MO_LED_ON) |
PHY_M_LED_MO_100(MO_LED_ON) |
@@ -678,28 +646,17 @@ static void skge_led_on(struct skge_hw *hw, int port)
static void skge_led_off(struct skge_hw *hw, int port)
{
if (hw->chip_id == CHIP_ID_GENESIS) {
- skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_OFF);
+ skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
skge_write8(hw, B0_LED, LED_STAT_OFF);
- skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 0);
- skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_T_OFF);
+ skge_write32(hw, SK_REG(port, RX_LED_VAL), 0);
+ skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF);
- switch (hw->phy_type) {
- case SK_PHY_BCOM:
- skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL,
- PHY_B_PEC_LED_OFF);
- break;
- case SK_PHY_LONE:
- skge_xm_phy_write(hw, port, PHY_LONE_LED_CFG,
- PHY_L_LC_LEDT);
- break;
- default:
- skge_write32(hw, SKGEMAC_REG(port, TX_LED_VAL), 0);
- skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_T_OFF);
- }
+ /* Broadcom only */
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
} else {
- skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
- skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+ gm_phy_write(hw, port, PHY_MARV_LED_OVER,
PHY_M_LED_MO_DUP(MO_LED_OFF) |
PHY_M_LED_MO_10(MO_LED_OFF) |
PHY_M_LED_MO_100(MO_LED_OFF) |
@@ -730,7 +687,7 @@ static int skge_phys_id(struct net_device *dev, u32 data)
{
struct skge_port *skge = netdev_priv(dev);
- if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+ if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
/* start blinking */
@@ -763,8 +720,6 @@ static struct ethtool_ops skge_ethtool_ops = {
.set_pauseparam = skge_set_pauseparam,
.get_coalesce = skge_get_coalesce,
.set_coalesce = skge_set_coalesce,
- .get_tso = ethtool_op_get_tso,
- .set_tso = skge_set_tso,
.get_sg = ethtool_op_get_sg,
.set_sg = skge_set_sg,
.get_tx_csum = ethtool_op_get_tx_csum,
@@ -793,6 +748,7 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base)
for (i = 0, e = ring->start, d = vaddr; i < ring->count; i++, e++, d++) {
e->desc = d;
+ e->skb = NULL;
if (i == ring->count - 1) {
e->next = ring->start;
d->next_offset = base;
@@ -806,24 +762,23 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base)
return 0;
}
-/* Setup buffer for receiving */
-static inline int skge_rx_alloc(struct skge_port *skge,
- struct skge_element *e)
+static struct sk_buff *skge_rx_alloc(struct net_device *dev, unsigned int size)
{
- unsigned long bufsize = skge->netdev->mtu + ETH_HLEN; /* VLAN? */
- struct skge_rx_desc *rd = e->desc;
- struct sk_buff *skb;
- u64 map;
+ struct sk_buff *skb = dev_alloc_skb(size);
- skb = dev_alloc_skb(bufsize + NET_IP_ALIGN);
- if (unlikely(!skb)) {
- printk(KERN_DEBUG PFX "%s: out of memory for receive\n",
- skge->netdev->name);
- return -ENOMEM;
+ if (likely(skb)) {
+ skb->dev = dev;
+ skb_reserve(skb, NET_IP_ALIGN);
}
+ return skb;
+}
- skb->dev = skge->netdev;
- skb_reserve(skb, NET_IP_ALIGN);
+/* Allocate and setup a new buffer for receiving */
+static void skge_rx_setup(struct skge_port *skge, struct skge_element *e,
+ struct sk_buff *skb, unsigned int bufsize)
+{
+ struct skge_rx_desc *rd = e->desc;
+ u64 map;
map = pci_map_single(skge->hw->pdev, skb->data, bufsize,
PCI_DMA_FROMDEVICE);
@@ -841,55 +796,69 @@ static inline int skge_rx_alloc(struct skge_port *skge,
rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize;
pci_unmap_addr_set(e, mapaddr, map);
pci_unmap_len_set(e, maplen, bufsize);
- return 0;
}
-/* Free all unused buffers in receive ring, assumes receiver stopped */
+/* Resume receiving using existing skb,
+ * Note: DMA address is not changed by chip.
+ * MTU not changed while receiver active.
+ */
+static void skge_rx_reuse(struct skge_element *e, unsigned int size)
+{
+ struct skge_rx_desc *rd = e->desc;
+
+ rd->csum2 = 0;
+ rd->csum2_start = ETH_HLEN;
+
+ wmb();
+
+ rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | size;
+}
+
+
+/* Free all buffers in receive ring, assumes receiver stopped */
static void skge_rx_clean(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
struct skge_ring *ring = &skge->rx_ring;
struct skge_element *e;
- for (e = ring->to_clean; e != ring->to_use; e = e->next) {
+ e = ring->start;
+ do {
struct skge_rx_desc *rd = e->desc;
rd->control = 0;
-
- pci_unmap_single(hw->pdev,
- pci_unmap_addr(e, mapaddr),
- pci_unmap_len(e, maplen),
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb(e->skb);
- e->skb = NULL;
- }
- ring->to_clean = e;
+ if (e->skb) {
+ pci_unmap_single(hw->pdev,
+ pci_unmap_addr(e, mapaddr),
+ pci_unmap_len(e, maplen),
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(e->skb);
+ e->skb = NULL;
+ }
+ } while ((e = e->next) != ring->start);
}
+
/* Allocate buffers for receive ring
- * For receive: to_use is refill location
- * to_clean is next received frame.
- *
- * if (to_use == to_clean)
- * then ring all frames in ring need buffers
- * if (to_use->next == to_clean)
- * then ring all frames in ring have buffers
+ * For receive: to_clean is next received frame.
*/
static int skge_rx_fill(struct skge_port *skge)
{
struct skge_ring *ring = &skge->rx_ring;
struct skge_element *e;
- int ret = 0;
+ unsigned int bufsize = skge->rx_buf_size;
- for (e = ring->to_use; e->next != ring->to_clean; e = e->next) {
- if (skge_rx_alloc(skge, e)) {
- ret = 1;
- break;
- }
+ e = ring->start;
+ do {
+ struct sk_buff *skb = skge_rx_alloc(skge->netdev, bufsize);
- }
- ring->to_use = e;
+ if (!skb)
+ return -ENOMEM;
+
+ skge_rx_setup(skge, e, skb, bufsize);
+ } while ( (e = e->next) != ring->start);
- return ret;
+ ring->to_clean = ring->start;
+ return 0;
}
static void skge_link_up(struct skge_port *skge)
@@ -919,50 +888,50 @@ static void skge_link_down(struct skge_port *skge)
printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name);
}
-static u16 skge_xm_phy_read(struct skge_hw *hw, int port, u16 reg)
+static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg)
{
int i;
u16 v;
- skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
- v = skge_xm_read16(hw, port, XM_PHY_DATA);
- if (hw->phy_type != SK_PHY_XMAC) {
- for (i = 0; i < PHY_RETRIES; i++) {
- udelay(1);
- if (skge_xm_read16(hw, port, XM_MMU_CMD)
- & XM_MMU_PHY_RDY)
- goto ready;
- }
+ xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+ v = xm_read16(hw, port, XM_PHY_DATA);
- printk(KERN_WARNING PFX "%s: phy read timed out\n",
- hw->dev[port]->name);
- return 0;
- ready:
- v = skge_xm_read16(hw, port, XM_PHY_DATA);
+ /* Need to wait for external PHY */
+ for (i = 0; i < PHY_RETRIES; i++) {
+ udelay(1);
+ if (xm_read16(hw, port, XM_MMU_CMD)
+ & XM_MMU_PHY_RDY)
+ goto ready;
}
+ printk(KERN_WARNING PFX "%s: phy read timed out\n",
+ hw->dev[port]->name);
+ return 0;
+ ready:
+ v = xm_read16(hw, port, XM_PHY_DATA);
+
return v;
}
-static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
{
int i;
- skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+ xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
for (i = 0; i < PHY_RETRIES; i++) {
- if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
+ if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
goto ready;
- cpu_relax();
+ udelay(1);
}
printk(KERN_WARNING PFX "%s: phy write failed to come ready\n",
hw->dev[port]->name);
ready:
- skge_xm_write16(hw, port, XM_PHY_DATA, val);
+ xm_write16(hw, port, XM_PHY_DATA, val);
for (i = 0; i < PHY_RETRIES; i++) {
udelay(1);
- if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
+ if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
return;
}
printk(KERN_WARNING PFX "%s: phy write timed out\n",
@@ -999,34 +968,112 @@ static void genesis_init(struct skge_hw *hw)
static void genesis_reset(struct skge_hw *hw, int port)
{
- int i;
- u64 zero = 0;
+ const u8 zero[8] = { 0 };
/* reset the statistics module */
- skge_xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT);
- skge_xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */
- skge_xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */
- skge_xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */
- skge_xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */
+ xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT);
+ xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */
+ xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */
+ xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */
+ xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */
- /* disable all PHY IRQs */
- if (hw->phy_type == SK_PHY_BCOM)
- skge_xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
+ /* disable Broadcom PHY IRQ */
+ xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
- skge_xm_outhash(hw, port, XM_HSM, (u8 *) &zero);
- for (i = 0; i < 15; i++)
- skge_xm_outaddr(hw, port, XM_EXM(i), (u8 *) &zero);
- skge_xm_outhash(hw, port, XM_SRC_CHK, (u8 *) &zero);
+ xm_outhash(hw, port, XM_HSM, zero);
}
-static void genesis_mac_init(struct skge_hw *hw, int port)
+/* Convert mode to MII values */
+static const u16 phy_pause_map[] = {
+ [FLOW_MODE_NONE] = 0,
+ [FLOW_MODE_LOC_SEND] = PHY_AN_PAUSE_ASYM,
+ [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP,
+ [FLOW_MODE_REM_SEND] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM,
+};
+
+
+/* Check status of Broadcom phy link */
+static void bcom_check_link(struct skge_hw *hw, int port)
{
- struct skge_port *skge = netdev_priv(hw->dev[port]);
+ struct net_device *dev = hw->dev[port];
+ struct skge_port *skge = netdev_priv(dev);
+ u16 status;
+
+ /* read twice because of latch */
+ (void) xm_phy_read(hw, port, PHY_BCOM_STAT);
+ status = xm_phy_read(hw, port, PHY_BCOM_STAT);
+
+ pr_debug("bcom_check_link status=0x%x\n", status);
+
+ if ((status & PHY_ST_LSYNC) == 0) {
+ u16 cmd = xm_read16(hw, port, XM_MMU_CMD);
+ cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+ xm_write16(hw, port, XM_MMU_CMD, cmd);
+ /* dummy read to ensure writing */
+ (void) xm_read16(hw, port, XM_MMU_CMD);
+
+ if (netif_carrier_ok(dev))
+ skge_link_down(skge);
+ } else {
+ if (skge->autoneg == AUTONEG_ENABLE &&
+ (status & PHY_ST_AN_OVER)) {
+ u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP);
+ u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
+
+ if (lpa & PHY_B_AN_RF) {
+ printk(KERN_NOTICE PFX "%s: remote fault\n",
+ dev->name);
+ return;
+ }
+
+ /* Check Duplex mismatch */
+ switch(aux & PHY_B_AS_AN_RES_MSK) {
+ case PHY_B_RES_1000FD:
+ skge->duplex = DUPLEX_FULL;
+ break;
+ case PHY_B_RES_1000HD:
+ skge->duplex = DUPLEX_HALF;
+ break;
+ default:
+ printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
+ dev->name);
+ return;
+ }
+
+
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+ switch (aux & PHY_B_AS_PAUSE_MSK) {
+ case PHY_B_AS_PAUSE_MSK:
+ skge->flow_control = FLOW_MODE_SYMMETRIC;
+ break;
+ case PHY_B_AS_PRR:
+ skge->flow_control = FLOW_MODE_REM_SEND;
+ break;
+ case PHY_B_AS_PRT:
+ skge->flow_control = FLOW_MODE_LOC_SEND;
+ break;
+ default:
+ skge->flow_control = FLOW_MODE_NONE;
+ }
+
+ skge->speed = SPEED_1000;
+ }
+
+ if (!netif_carrier_ok(dev))
+ genesis_link_up(skge);
+ }
+}
+
+/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional
+ * Phy on for 100 or 10Mbit operation
+ */
+static void bcom_phy_init(struct skge_port *skge, int jumbo)
+{
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
int i;
- u32 r;
- u16 id1;
- u16 ctrl1, ctrl2, ctrl3, ctrl4, ctrl5;
+ u16 id1, r, ext, ctl;
/* magic workaround patterns for Broadcom */
static const struct {
@@ -1042,16 +1089,120 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
{ 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 },
};
+ pr_debug("bcom_phy_init\n");
+
+ /* read Id from external PHY (all have the same address) */
+ id1 = xm_phy_read(hw, port, PHY_XMAC_ID1);
+
+ /* Optimize MDIO transfer by suppressing preamble. */
+ r = xm_read16(hw, port, XM_MMU_CMD);
+ r |= XM_MMU_NO_PRE;
+ xm_write16(hw, port, XM_MMU_CMD,r);
+
+ switch(id1) {
+ case PHY_BCOM_ID1_C0:
+ /*
+ * Workaround BCOM Errata for the C0 type.
+ * Write magic patterns to reserved registers.
+ */
+ for (i = 0; i < ARRAY_SIZE(C0hack); i++)
+ xm_phy_write(hw, port,
+ C0hack[i].reg, C0hack[i].val);
+
+ break;
+ case PHY_BCOM_ID1_A1:
+ /*
+ * Workaround BCOM Errata for the A1 type.
+ * Write magic patterns to reserved registers.
+ */
+ for (i = 0; i < ARRAY_SIZE(A1hack); i++)
+ xm_phy_write(hw, port,
+ A1hack[i].reg, A1hack[i].val);
+ break;
+ }
+
+ /*
+ * Workaround BCOM Errata (#10523) for all BCom PHYs.
+ * Disable Power Management after reset.
+ */
+ r = xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL);
+ r |= PHY_B_AC_DIS_PM;
+ xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r);
+
+ /* Dummy read */
+ xm_read16(hw, port, XM_ISRC);
+
+ ext = PHY_B_PEC_EN_LTR; /* enable tx led */
+ ctl = PHY_CT_SP1000; /* always 1000mbit */
+
+ if (skge->autoneg == AUTONEG_ENABLE) {
+ /*
+ * Workaround BCOM Errata #1 for the C5 type.
+ * 1000Base-T Link Acquisition Failure in Slave Mode
+ * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
+ */
+ u16 adv = PHY_B_1000C_RD;
+ if (skge->advertising & ADVERTISED_1000baseT_Half)
+ adv |= PHY_B_1000C_AHD;
+ if (skge->advertising & ADVERTISED_1000baseT_Full)
+ adv |= PHY_B_1000C_AFD;
+ xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, adv);
+
+ ctl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+ } else {
+ if (skge->duplex == DUPLEX_FULL)
+ ctl |= PHY_CT_DUP_MD;
+ /* Force to slave */
+ xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, PHY_B_1000C_MSE);
+ }
+
+ /* Set autonegotiation pause parameters */
+ xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV,
+ phy_pause_map[skge->flow_control] | PHY_AN_CSMA);
+
+ /* Handle Jumbo frames */
+ if (jumbo) {
+ xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+ PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK);
+
+ ext |= PHY_B_PEC_HIGH_LA;
+
+ }
+
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ext);
+ xm_phy_write(hw, port, PHY_BCOM_CTRL, ctl);
+
+ /* Use link status change interrrupt */
+ xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+
+ bcom_check_link(hw, port);
+}
+
+static void genesis_mac_init(struct skge_hw *hw, int port)
+{
+ struct net_device *dev = hw->dev[port];
+ struct skge_port *skge = netdev_priv(dev);
+ int jumbo = hw->dev[port]->mtu > ETH_DATA_LEN;
+ int i;
+ u32 r;
+ const u8 zero[6] = { 0 };
+
+ /* Clear MIB counters */
+ xm_write16(hw, port, XM_STAT_CMD,
+ XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+ /* Clear two times according to Errata #3 */
+ xm_write16(hw, port, XM_STAT_CMD,
+ XM_SC_CLR_RXC | XM_SC_CLR_TXC);
/* initialize Rx, Tx and Link LED */
- skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON);
- skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON);
+ skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON);
+ skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON);
- skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START);
- skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START);
+ skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
+ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START);
/* Unreset the XMAC. */
- skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
/*
* Perform additional initialization for external PHYs,
@@ -1059,67 +1210,56 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
* GMII mode.
*/
spin_lock_bh(&hw->phy_lock);
- if (hw->phy_type != SK_PHY_XMAC) {
- /* Take PHY out of reset. */
- r = skge_read32(hw, B2_GP_IO);
- if (port == 0)
- r |= GP_DIR_0|GP_IO_0;
- else
- r |= GP_DIR_2|GP_IO_2;
-
- skge_write32(hw, B2_GP_IO, r);
- skge_read32(hw, B2_GP_IO);
-
- /* Enable GMII mode on the XMAC. */
- skge_xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
-
- id1 = skge_xm_phy_read(hw, port, PHY_XMAC_ID1);
-
- /* Optimize MDIO transfer by suppressing preamble. */
- skge_xm_write16(hw, port, XM_MMU_CMD,
- skge_xm_read16(hw, port, XM_MMU_CMD)
- | XM_MMU_NO_PRE);
-
- if (id1 == PHY_BCOM_ID1_C0) {
- /*
- * Workaround BCOM Errata for the C0 type.
- * Write magic patterns to reserved registers.
- */
- for (i = 0; i < ARRAY_SIZE(C0hack); i++)
- skge_xm_phy_write(hw, port,
- C0hack[i].reg, C0hack[i].val);
-
- } else if (id1 == PHY_BCOM_ID1_A1) {
- /*
- * Workaround BCOM Errata for the A1 type.
- * Write magic patterns to reserved registers.
- */
- for (i = 0; i < ARRAY_SIZE(A1hack); i++)
- skge_xm_phy_write(hw, port,
- A1hack[i].reg, A1hack[i].val);
- }
+ /* Take external Phy out of reset */
+ r = skge_read32(hw, B2_GP_IO);
+ if (port == 0)
+ r |= GP_DIR_0|GP_IO_0;
+ else
+ r |= GP_DIR_2|GP_IO_2;
- /*
- * Workaround BCOM Errata (#10523) for all BCom PHYs.
- * Disable Power Management after reset.
- */
- r = skge_xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL);
- skge_xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r | PHY_B_AC_DIS_PM);
- }
+ skge_write32(hw, B2_GP_IO, r);
+ skge_read32(hw, B2_GP_IO);
+ spin_unlock_bh(&hw->phy_lock);
- /* Dummy read */
- skge_xm_read16(hw, port, XM_ISRC);
+ /* Enable GMII interfac */
+ xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
+
+ bcom_phy_init(skge, jumbo);
+
+ /* Set Station Address */
+ xm_outaddr(hw, port, XM_SA, dev->dev_addr);
+
+ /* We don't use match addresses so clear */
+ for (i = 1; i < 16; i++)
+ xm_outaddr(hw, port, XM_EXM(i), zero);
- r = skge_xm_read32(hw, port, XM_MODE);
- skge_xm_write32(hw, port, XM_MODE, r|XM_MD_CSA);
+ /* configure Rx High Water Mark (XM_RX_HI_WM) */
+ xm_write16(hw, port, XM_RX_HI_WM, 1450);
/* We don't need the FCS appended to the packet. */
- r = skge_xm_read16(hw, port, XM_RX_CMD);
- skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_STRIP_FCS);
+ r = XM_RX_LENERR_OK | XM_RX_STRIP_FCS;
+ if (jumbo)
+ r |= XM_RX_BIG_PK_OK;
+
+ if (skge->duplex == DUPLEX_HALF) {
+ /*
+ * If in manual half duplex mode the other side might be in
+ * full duplex mode, so ignore if a carrier extension is not seen
+ * on frames received
+ */
+ r |= XM_RX_DIS_CEXT;
+ }
+ xm_write16(hw, port, XM_RX_CMD, r);
+
/* We want short frames padded to 60 bytes. */
- r = skge_xm_read16(hw, port, XM_TX_CMD);
- skge_xm_write16(hw, port, XM_TX_CMD, r | XM_TX_AUTO_PAD);
+ xm_write16(hw, port, XM_TX_CMD, XM_TX_AUTO_PAD);
+
+ /*
+ * Bump up the transmit threshold. This helps hold off transmit
+ * underruns when we're blasting traffic from both ports at once.
+ */
+ xm_write16(hw, port, XM_TX_THR, 512);
/*
* Enable the reception of all error frames. This is is
@@ -1135,19 +1275,22 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
* case the XMAC will start transfering frames out of the
* RX FIFO as soon as the FIFO threshold is reached.
*/
- r = skge_xm_read32(hw, port, XM_MODE);
- skge_xm_write32(hw, port, XM_MODE,
- XM_MD_RX_CRCE|XM_MD_RX_LONG|XM_MD_RX_RUNT|
- XM_MD_RX_ERR|XM_MD_RX_IRLE);
+ xm_write32(hw, port, XM_MODE, XM_DEF_MODE);
- skge_xm_outaddr(hw, port, XM_SA, hw->dev[port]->dev_addr);
- skge_xm_outaddr(hw, port, XM_EXM(0), hw->dev[port]->dev_addr);
/*
- * Bump up the transmit threshold. This helps hold off transmit
- * underruns when we're blasting traffic from both ports at once.
+ * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK)
+ * - Enable all bits excepting 'Octets Rx OK Low CntOv'
+ * and 'Octets Rx OK Hi Cnt Ov'.
*/
- skge_xm_write16(hw, port, XM_TX_THR, 512);
+ xm_write32(hw, port, XM_RX_EV_MSK, XMR_DEF_MSK);
+
+ /*
+ * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK)
+ * - Enable all bits excepting 'Octets Tx OK Low CntOv'
+ * and 'Octets Tx OK Hi Cnt Ov'.
+ */
+ xm_write32(hw, port, XM_TX_EV_MSK, XMT_DEF_MSK);
/* Configure MAC arbiter */
skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR);
@@ -1164,137 +1307,30 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
skge_write8(hw, B3_MA_RCINI_TX2, 0);
/* Configure Rx MAC FIFO */
- skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_RST_CLR);
- skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT);
- skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
+ skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_CLR);
+ skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT);
+ skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
/* Configure Tx MAC FIFO */
- skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_RST_CLR);
- skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
- skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
+ skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_CLR);
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
+ skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
- if (hw->dev[port]->mtu > ETH_DATA_LEN) {
+ if (jumbo) {
/* Enable frame flushing if jumbo frames used */
- skge_write16(hw, SKGEMAC_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH);
+ skge_write16(hw, SK_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH);
} else {
/* enable timeout timers if normal frames */
skge_write16(hw, B3_PA_CTRL,
- port == 0 ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2);
+ (port == 0) ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2);
}
-
-
- r = skge_xm_read16(hw, port, XM_RX_CMD);
- if (hw->dev[port]->mtu > ETH_DATA_LEN)
- skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_BIG_PK_OK);
- else
- skge_xm_write16(hw, port, XM_RX_CMD, r & ~(XM_RX_BIG_PK_OK));
-
- switch (hw->phy_type) {
- case SK_PHY_XMAC:
- if (skge->autoneg == AUTONEG_ENABLE) {
- ctrl1 = PHY_X_AN_FD | PHY_X_AN_HD;
-
- switch (skge->flow_control) {
- case FLOW_MODE_NONE:
- ctrl1 |= PHY_X_P_NO_PAUSE;
- break;
- case FLOW_MODE_LOC_SEND:
- ctrl1 |= PHY_X_P_ASYM_MD;
- break;
- case FLOW_MODE_SYMMETRIC:
- ctrl1 |= PHY_X_P_SYM_MD;
- break;
- case FLOW_MODE_REM_SEND:
- ctrl1 |= PHY_X_P_BOTH_MD;
- break;
- }
-
- skge_xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl1);
- ctrl2 = PHY_CT_ANE | PHY_CT_RE_CFG;
- } else {
- ctrl2 = 0;
- if (skge->duplex == DUPLEX_FULL)
- ctrl2 |= PHY_CT_DUP_MD;
- }
-
- skge_xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl2);
- break;
-
- case SK_PHY_BCOM:
- ctrl1 = PHY_CT_SP1000;
- ctrl2 = 0;
- ctrl3 = PHY_SEL_TYPE;
- ctrl4 = PHY_B_PEC_EN_LTR;
- ctrl5 = PHY_B_AC_TX_TST;
-
- if (skge->autoneg == AUTONEG_ENABLE) {
- /*
- * Workaround BCOM Errata #1 for the C5 type.
- * 1000Base-T Link Acquisition Failure in Slave Mode
- * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
- */
- ctrl2 |= PHY_B_1000C_RD;
- if (skge->advertising & ADVERTISED_1000baseT_Half)
- ctrl2 |= PHY_B_1000C_AHD;
- if (skge->advertising & ADVERTISED_1000baseT_Full)
- ctrl2 |= PHY_B_1000C_AFD;
-
- /* Set Flow-control capabilities */
- switch (skge->flow_control) {
- case FLOW_MODE_NONE:
- ctrl3 |= PHY_B_P_NO_PAUSE;
- break;
- case FLOW_MODE_LOC_SEND:
- ctrl3 |= PHY_B_P_ASYM_MD;
- break;
- case FLOW_MODE_SYMMETRIC:
- ctrl3 |= PHY_B_P_SYM_MD;
- break;
- case FLOW_MODE_REM_SEND:
- ctrl3 |= PHY_B_P_BOTH_MD;
- break;
- }
-
- /* Restart Auto-negotiation */
- ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
- } else {
- if (skge->duplex == DUPLEX_FULL)
- ctrl1 |= PHY_CT_DUP_MD;
-
- ctrl2 |= PHY_B_1000C_MSE; /* set it to Slave */
- }
-
- skge_xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, ctrl2);
- skge_xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV, ctrl3);
-
- if (skge->netdev->mtu > ETH_DATA_LEN) {
- ctrl4 |= PHY_B_PEC_HIGH_LA;
- ctrl5 |= PHY_B_AC_LONG_PACK;
-
- skge_xm_phy_write(hw, port,PHY_BCOM_AUX_CTRL, ctrl5);
- }
-
- skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ctrl4);
- skge_xm_phy_write(hw, port, PHY_BCOM_CTRL, ctrl1);
- break;
- }
- spin_unlock_bh(&hw->phy_lock);
-
- /* Clear MIB counters */
- skge_xm_write16(hw, port, XM_STAT_CMD,
- XM_SC_CLR_RXC | XM_SC_CLR_TXC);
- /* Clear two times according to Errata #3 */
- skge_xm_write16(hw, port, XM_STAT_CMD,
- XM_SC_CLR_RXC | XM_SC_CLR_TXC);
-
- /* Start polling for link status */
- mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
}
static void genesis_stop(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
int port = skge->port;
+ u32 reg;
/* Clear Tx packet arbiter timeout IRQ */
skge_write16(hw, B3_PA_CTRL,
@@ -1304,33 +1340,30 @@ static void genesis_stop(struct skge_port *skge)
* If the transfer stucks at the MAC the STOP command will not
* terminate if we don't flush the XMAC's transmit FIFO !
*/
- skge_xm_write32(hw, port, XM_MODE,
- skge_xm_read32(hw, port, XM_MODE)|XM_MD_FTF);
+ xm_write32(hw, port, XM_MODE,
+ xm_read32(hw, port, XM_MODE)|XM_MD_FTF);
/* Reset the MAC */
- skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
/* For external PHYs there must be special handling */
- if (hw->phy_type != SK_PHY_XMAC) {
- u32 reg = skge_read32(hw, B2_GP_IO);
-
- if (port == 0) {
- reg |= GP_DIR_0;
- reg &= ~GP_IO_0;
- } else {
- reg |= GP_DIR_2;
- reg &= ~GP_IO_2;
- }
- skge_write32(hw, B2_GP_IO, reg);
- skge_read32(hw, B2_GP_IO);
+ reg = skge_read32(hw, B2_GP_IO);
+ if (port == 0) {
+ reg |= GP_DIR_0;
+ reg &= ~GP_IO_0;
+ } else {
+ reg |= GP_DIR_2;
+ reg &= ~GP_IO_2;
}
+ skge_write32(hw, B2_GP_IO, reg);
+ skge_read32(hw, B2_GP_IO);
- skge_xm_write16(hw, port, XM_MMU_CMD,
- skge_xm_read16(hw, port, XM_MMU_CMD)
+ xm_write16(hw, port, XM_MMU_CMD,
+ xm_read16(hw, port, XM_MMU_CMD)
& ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
- skge_xm_read16(hw, port, XM_MMU_CMD);
+ xm_read16(hw, port, XM_MMU_CMD);
}
@@ -1341,11 +1374,11 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data)
int i;
unsigned long timeout = jiffies + HZ;
- skge_xm_write16(hw, port,
+ xm_write16(hw, port,
XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC);
/* wait for update to complete */
- while (skge_xm_read16(hw, port, XM_STAT_CMD)
+ while (xm_read16(hw, port, XM_STAT_CMD)
& (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) {
if (time_after(jiffies, timeout))
break;
@@ -1353,68 +1386,60 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data)
}
/* special case for 64 bit octet counter */
- data[0] = (u64) skge_xm_read32(hw, port, XM_TXO_OK_HI) << 32
- | skge_xm_read32(hw, port, XM_TXO_OK_LO);
- data[1] = (u64) skge_xm_read32(hw, port, XM_RXO_OK_HI) << 32
- | skge_xm_read32(hw, port, XM_RXO_OK_LO);
+ data[0] = (u64) xm_read32(hw, port, XM_TXO_OK_HI) << 32
+ | xm_read32(hw, port, XM_TXO_OK_LO);
+ data[1] = (u64) xm_read32(hw, port, XM_RXO_OK_HI) << 32
+ | xm_read32(hw, port, XM_RXO_OK_LO);
for (i = 2; i < ARRAY_SIZE(skge_stats); i++)
- data[i] = skge_xm_read32(hw, port, skge_stats[i].xmac_offset);
+ data[i] = xm_read32(hw, port, skge_stats[i].xmac_offset);
}
static void genesis_mac_intr(struct skge_hw *hw, int port)
{
struct skge_port *skge = netdev_priv(hw->dev[port]);
- u16 status = skge_xm_read16(hw, port, XM_ISRC);
-
- pr_debug("genesis_intr status %x\n", status);
- if (hw->phy_type == SK_PHY_XMAC) {
- /* LInk down, start polling for state change */
- if (status & XM_IS_INP_ASS) {
- skge_xm_write16(hw, port, XM_IMSK,
- skge_xm_read16(hw, port, XM_IMSK) | XM_IS_INP_ASS);
- mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
- }
- else if (status & XM_IS_AND)
- mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
- }
+ u16 status = xm_read16(hw, port, XM_ISRC);
+
+ if (netif_msg_intr(skge))
+ printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
+ skge->netdev->name, status);
if (status & XM_IS_TXF_UR) {
- skge_xm_write32(hw, port, XM_MODE, XM_MD_FTF);
+ xm_write32(hw, port, XM_MODE, XM_MD_FTF);
++skge->net_stats.tx_fifo_errors;
}
if (status & XM_IS_RXF_OV) {
- skge_xm_write32(hw, port, XM_MODE, XM_MD_FRF);
+ xm_write32(hw, port, XM_MODE, XM_MD_FRF);
++skge->net_stats.rx_fifo_errors;
}
}
-static void skge_gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
{
int i;
- skge_gma_write16(hw, port, GM_SMI_DATA, val);
- skge_gma_write16(hw, port, GM_SMI_CTRL,
+ gma_write16(hw, port, GM_SMI_DATA, val);
+ gma_write16(hw, port, GM_SMI_CTRL,
GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg));
for (i = 0; i < PHY_RETRIES; i++) {
udelay(1);
- if (!(skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
+ if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
break;
}
}
-static u16 skge_gm_phy_read(struct skge_hw *hw, int port, u16 reg)
+static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg)
{
int i;
- skge_gma_write16(hw, port, GM_SMI_CTRL,
+ gma_write16(hw, port, GM_SMI_CTRL,
GM_SMI_CT_PHY_AD(hw->phy_addr)
| GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
for (i = 0; i < PHY_RETRIES; i++) {
udelay(1);
- if (skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
+ if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
goto ready;
}
@@ -1422,24 +1447,7 @@ static u16 skge_gm_phy_read(struct skge_hw *hw, int port, u16 reg)
hw->dev[port]->name);
return 0;
ready:
- return skge_gma_read16(hw, port, GM_SMI_DATA);
-}
-
-static void genesis_link_down(struct skge_port *skge)
-{
- struct skge_hw *hw = skge->hw;
- int port = skge->port;
-
- pr_debug("genesis_link_down\n");
-
- skge_xm_write16(hw, port, XM_MMU_CMD,
- skge_xm_read16(hw, port, XM_MMU_CMD)
- & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
-
- /* dummy read to ensure writing */
- (void) skge_xm_read16(hw, port, XM_MMU_CMD);
-
- skge_link_down(skge);
+ return gma_read16(hw, port, GM_SMI_DATA);
}
static void genesis_link_up(struct skge_port *skge)
@@ -1450,7 +1458,7 @@ static void genesis_link_up(struct skge_port *skge)
u32 mode, msk;
pr_debug("genesis_link_up\n");
- cmd = skge_xm_read16(hw, port, XM_MMU_CMD);
+ cmd = xm_read16(hw, port, XM_MMU_CMD);
/*
* enabling pause frame reception is required for 1000BT
@@ -1458,14 +1466,15 @@ static void genesis_link_up(struct skge_port *skge)
*/
if (skge->flow_control == FLOW_MODE_NONE ||
skge->flow_control == FLOW_MODE_LOC_SEND)
+ /* Disable Pause Frame Reception */
cmd |= XM_MMU_IGN_PF;
else
/* Enable Pause Frame Reception */
cmd &= ~XM_MMU_IGN_PF;
- skge_xm_write16(hw, port, XM_MMU_CMD, cmd);
+ xm_write16(hw, port, XM_MMU_CMD, cmd);
- mode = skge_xm_read32(hw, port, XM_MODE);
+ mode = xm_read32(hw, port, XM_MODE);
if (skge->flow_control == FLOW_MODE_SYMMETRIC ||
skge->flow_control == FLOW_MODE_LOC_SEND) {
/*
@@ -1479,10 +1488,10 @@ static void genesis_link_up(struct skge_port *skge)
/* XM_PAUSE_DA = '010000C28001' (default) */
/* XM_MAC_PTIME = 0xffff (maximum) */
/* remember this value is defined in big endian (!) */
- skge_xm_write16(hw, port, XM_MAC_PTIME, 0xffff);
+ xm_write16(hw, port, XM_MAC_PTIME, 0xffff);
mode |= XM_PAUSE_MODE;
- skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
+ skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
} else {
/*
* disable pause frame generation is required for 1000BT
@@ -1491,125 +1500,68 @@ static void genesis_link_up(struct skge_port *skge)
/* Disable Pause Mode in Mode Register */
mode &= ~XM_PAUSE_MODE;
- skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
+ skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
}
- skge_xm_write32(hw, port, XM_MODE, mode);
+ xm_write32(hw, port, XM_MODE, mode);
msk = XM_DEF_MSK;
- if (hw->phy_type != SK_PHY_XMAC)
- msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */
+ /* disable GP0 interrupt bit for external Phy */
+ msk |= XM_IS_INP_ASS;
- skge_xm_write16(hw, port, XM_IMSK, msk);
- skge_xm_read16(hw, port, XM_ISRC);
+ xm_write16(hw, port, XM_IMSK, msk);
+ xm_read16(hw, port, XM_ISRC);
/* get MMU Command Reg. */
- cmd = skge_xm_read16(hw, port, XM_MMU_CMD);
- if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL)
+ cmd = xm_read16(hw, port, XM_MMU_CMD);
+ if (skge->duplex == DUPLEX_FULL)
cmd |= XM_MMU_GMII_FD;
- if (hw->phy_type == SK_PHY_BCOM) {
- /*
- * Workaround BCOM Errata (#10523) for all BCom Phys
- * Enable Power Management after link up
- */
- skge_xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
- skge_xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
- & ~PHY_B_AC_DIS_PM);
- skge_xm_phy_write(hw, port, PHY_BCOM_INT_MASK,
- PHY_B_DEF_MSK);
- }
+ /*
+ * Workaround BCOM Errata (#10523) for all BCom Phys
+ * Enable Power Management after link up
+ */
+ xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+ xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
+ & ~PHY_B_AC_DIS_PM);
+ xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
/* enable Rx/Tx */
- skge_xm_write16(hw, port, XM_MMU_CMD,
+ xm_write16(hw, port, XM_MMU_CMD,
cmd | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
skge_link_up(skge);
}
-static void genesis_bcom_intr(struct skge_port *skge)
+static inline void bcom_phy_intr(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
int port = skge->port;
- u16 stat = skge_xm_phy_read(hw, port, PHY_BCOM_INT_STAT);
+ u16 isrc;
+
+ isrc = xm_phy_read(hw, port, PHY_BCOM_INT_STAT);
+ if (netif_msg_intr(skge))
+ printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x\n",
+ skge->netdev->name, isrc);
- pr_debug("genesis_bcom intr stat=%x\n", stat);
+ if (isrc & PHY_B_IS_PSE)
+ printk(KERN_ERR PFX "%s: uncorrectable pair swap error\n",
+ hw->dev[port]->name);
/* Workaround BCom Errata:
* enable and disable loopback mode if "NO HCD" occurs.
*/
- if (stat & PHY_B_IS_NO_HDCL) {
- u16 ctrl = skge_xm_phy_read(hw, port, PHY_BCOM_CTRL);
- skge_xm_phy_write(hw, port, PHY_BCOM_CTRL,
+ if (isrc & PHY_B_IS_NO_HDCL) {
+ u16 ctrl = xm_phy_read(hw, port, PHY_BCOM_CTRL);
+ xm_phy_write(hw, port, PHY_BCOM_CTRL,
ctrl | PHY_CT_LOOP);
- skge_xm_phy_write(hw, port, PHY_BCOM_CTRL,
+ xm_phy_write(hw, port, PHY_BCOM_CTRL,
ctrl & ~PHY_CT_LOOP);
}
- stat = skge_xm_phy_read(hw, port, PHY_BCOM_STAT);
- if (stat & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) {
- u16 aux = skge_xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
- if ( !(aux & PHY_B_AS_LS) && netif_carrier_ok(skge->netdev))
- genesis_link_down(skge);
-
- else if (stat & PHY_B_IS_LST_CHANGE) {
- if (aux & PHY_B_AS_AN_C) {
- switch (aux & PHY_B_AS_AN_RES_MSK) {
- case PHY_B_RES_1000FD:
- skge->duplex = DUPLEX_FULL;
- break;
- case PHY_B_RES_1000HD:
- skge->duplex = DUPLEX_HALF;
- break;
- }
-
- switch (aux & PHY_B_AS_PAUSE_MSK) {
- case PHY_B_AS_PAUSE_MSK:
- skge->flow_control = FLOW_MODE_SYMMETRIC;
- break;
- case PHY_B_AS_PRR:
- skge->flow_control = FLOW_MODE_REM_SEND;
- break;
- case PHY_B_AS_PRT:
- skge->flow_control = FLOW_MODE_LOC_SEND;
- break;
- default:
- skge->flow_control = FLOW_MODE_NONE;
- }
- skge->speed = SPEED_1000;
- }
- genesis_link_up(skge);
- }
- else
- mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
- }
-}
+ if (isrc & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+ bcom_check_link(hw, port);
-/* Perodic poll of phy status to check for link transistion */
-static void skge_link_timer(unsigned long __arg)
-{
- struct skge_port *skge = (struct skge_port *) __arg;
- struct skge_hw *hw = skge->hw;
- int port = skge->port;
-
- if (hw->chip_id != CHIP_ID_GENESIS || !netif_running(skge->netdev))
- return;
-
- spin_lock_bh(&hw->phy_lock);
- if (hw->phy_type == SK_PHY_BCOM)
- genesis_bcom_intr(skge);
- else {
- int i;
- for (i = 0; i < 3; i++)
- if (skge_xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)
- break;
-
- if (i == 3)
- mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
- else
- genesis_link_up(skge);
- }
- spin_unlock_bh(&hw->phy_lock);
}
/* Marvell Phy Initailization */
@@ -1621,31 +1573,27 @@ static void yukon_init(struct skge_hw *hw, int port)
pr_debug("yukon_init\n");
if (skge->autoneg == AUTONEG_ENABLE) {
- u16 ectrl = skge_gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
+ u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
PHY_M_EC_MAC_S_MSK);
ectrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ);
- /* on PHY 88E1111 there is a change for downshift control */
- if (hw->chip_id == CHIP_ID_YUKON_EC)
- ectrl |= PHY_M_EC_M_DSC_2(0) | PHY_M_EC_DOWN_S_ENA;
- else
- ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
+ ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
- skge_gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
+ gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
}
- ctrl = skge_gm_phy_read(hw, port, PHY_MARV_CTRL);
+ ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
if (skge->autoneg == AUTONEG_DISABLE)
ctrl &= ~PHY_CT_ANE;
ctrl |= PHY_CT_RESET;
- skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+ gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
ctrl = 0;
ct1000 = 0;
- adv = PHY_SEL_TYPE;
+ adv = PHY_AN_CSMA;
if (skge->autoneg == AUTONEG_ENABLE) {
if (iscopper(hw)) {
@@ -1661,41 +1609,12 @@ static void yukon_init(struct skge_hw *hw, int port)
adv |= PHY_M_AN_10_FD;
if (skge->advertising & ADVERTISED_10baseT_Half)
adv |= PHY_M_AN_10_HD;
-
- /* Set Flow-control capabilities */
- switch (skge->flow_control) {
- case FLOW_MODE_NONE:
- adv |= PHY_B_P_NO_PAUSE;
- break;
- case FLOW_MODE_LOC_SEND:
- adv |= PHY_B_P_ASYM_MD;
- break;
- case FLOW_MODE_SYMMETRIC:
- adv |= PHY_B_P_SYM_MD;
- break;
- case FLOW_MODE_REM_SEND:
- adv |= PHY_B_P_BOTH_MD;
- break;
- }
- } else { /* special defines for FIBER (88E1011S only) */
+ } else /* special defines for FIBER (88E1011S only) */
adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
- /* Set Flow-control capabilities */
- switch (skge->flow_control) {
- case FLOW_MODE_NONE:
- adv |= PHY_M_P_NO_PAUSE_X;
- break;
- case FLOW_MODE_LOC_SEND:
- adv |= PHY_M_P_ASYM_MD_X;
- break;
- case FLOW_MODE_SYMMETRIC:
- adv |= PHY_M_P_SYM_MD_X;
- break;
- case FLOW_MODE_REM_SEND:
- adv |= PHY_M_P_BOTH_MD_X;
- break;
- }
- }
+ /* Set Flow-control capabilities */
+ adv |= phy_pause_map[skge->flow_control];
+
/* Restart Auto-negotiation */
ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
} else {
@@ -1717,36 +1636,23 @@ static void yukon_init(struct skge_hw *hw, int port)
ctrl |= PHY_CT_RESET;
}
- if (hw->chip_id != CHIP_ID_YUKON_FE)
- skge_gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
+ gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
- skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
- skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+ gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
+ gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
/* Setup Phy LED's */
ledctrl = PHY_M_LED_PULS_DUR(PULS_170MS);
ledover = 0;
- if (hw->chip_id == CHIP_ID_YUKON_FE) {
- /* on 88E3082 these bits are at 11..9 (shifted left) */
- ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) << 1;
-
- skge_gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR,
- ((skge_gm_phy_read(hw, port, PHY_MARV_FE_LED_PAR)
-
- & ~PHY_M_FELP_LED1_MSK)
- | PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_ACT_BL)));
- } else {
- /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */
- ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL;
+ ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL;
- /* turn off the Rx LED (LED_RX) */
- ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
- }
+ /* turn off the Rx LED (LED_RX) */
+ ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
/* disable blink mode (LED_DUPLEX) on collisions */
ctrl |= PHY_M_LEDC_DP_CTRL;
- skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
+ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
if (skge->autoneg == AUTONEG_DISABLE || skge->speed == SPEED_100) {
/* turn on 100 Mbps LED (LED_LINK100) */
@@ -1754,25 +1660,25 @@ static void yukon_init(struct skge_hw *hw, int port)
}
if (ledover)
- skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
+ gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
/* Enable phy interrupt on autonegotiation complete (or link up) */
if (skge->autoneg == AUTONEG_ENABLE)
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
else
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
}
static void yukon_reset(struct skge_hw *hw, int port)
{
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */
- skge_gma_write16(hw, port, GM_MC_ADDR_H1, 0); /* clear MC hash */
- skge_gma_write16(hw, port, GM_MC_ADDR_H2, 0);
- skge_gma_write16(hw, port, GM_MC_ADDR_H3, 0);
- skge_gma_write16(hw, port, GM_MC_ADDR_H4, 0);
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */
+ gma_write16(hw, port, GM_MC_ADDR_H1, 0); /* clear MC hash */
+ gma_write16(hw, port, GM_MC_ADDR_H2, 0);
+ gma_write16(hw, port, GM_MC_ADDR_H3, 0);
+ gma_write16(hw, port, GM_MC_ADDR_H4, 0);
- skge_gma_write16(hw, port, GM_RX_CTRL,
- skge_gma_read16(hw, port, GM_RX_CTRL)
+ gma_write16(hw, port, GM_RX_CTRL,
+ gma_read16(hw, port, GM_RX_CTRL)
| GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
}
@@ -1785,17 +1691,17 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
/* WA code for COMA mode -- set PHY reset */
if (hw->chip_id == CHIP_ID_YUKON_LITE &&
- chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+ hw->chip_rev == CHIP_REV_YU_LITE_A3)
skge_write32(hw, B2_GP_IO,
(skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9));
/* hard reset */
- skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), GPC_RST_SET);
- skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_RST_SET);
+ skge_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
+ skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET);
/* WA code for COMA mode -- clear PHY reset */
if (hw->chip_id == CHIP_ID_YUKON_LITE &&
- chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+ hw->chip_rev == CHIP_REV_YU_LITE_A3)
skge_write32(hw, B2_GP_IO,
(skge_read32(hw, B2_GP_IO) | GP_DIR_9)
& ~GP_IO_9);
@@ -1806,13 +1712,13 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
reg |= iscopper(hw) ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB;
/* Clear GMC reset */
- skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), reg | GPC_RST_SET);
- skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), reg | GPC_RST_CLR);
- skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
+ skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_SET);
+ skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_CLR);
+ skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
if (skge->autoneg == AUTONEG_DISABLE) {
reg = GM_GPCR_AU_ALL_DIS;
- skge_gma_write16(hw, port, GM_GP_CTRL,
- skge_gma_read16(hw, port, GM_GP_CTRL) | reg);
+ gma_write16(hw, port, GM_GP_CTRL,
+ gma_read16(hw, port, GM_GP_CTRL) | reg);
switch (skge->speed) {
case SPEED_1000:
@@ -1828,7 +1734,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL;
switch (skge->flow_control) {
case FLOW_MODE_NONE:
- skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+ skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
reg |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
break;
case FLOW_MODE_LOC_SEND:
@@ -1836,7 +1742,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
}
- skge_gma_write16(hw, port, GM_GP_CTRL, reg);
+ gma_write16(hw, port, GM_GP_CTRL, reg);
skge_read16(hw, GMAC_IRQ_SRC);
spin_lock_bh(&hw->phy_lock);
@@ -1844,25 +1750,25 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
spin_unlock_bh(&hw->phy_lock);
/* MIB clear */
- reg = skge_gma_read16(hw, port, GM_PHY_ADDR);
- skge_gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
+ reg = gma_read16(hw, port, GM_PHY_ADDR);
+ gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
for (i = 0; i < GM_MIB_CNT_SIZE; i++)
- skge_gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i);
- skge_gma_write16(hw, port, GM_PHY_ADDR, reg);
+ gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i);
+ gma_write16(hw, port, GM_PHY_ADDR, reg);
/* transmit control */
- skge_gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF));
+ gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF));
/* receive control reg: unicast + multicast + no FCS */
- skge_gma_write16(hw, port, GM_RX_CTRL,
+ gma_write16(hw, port, GM_RX_CTRL,
GM_RXCR_UCF_ENA | GM_RXCR_CRC_DIS | GM_RXCR_MCF_ENA);
/* transmit flow control */
- skge_gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff);
+ gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff);
/* transmit parameter */
- skge_gma_write16(hw, port, GM_TX_PARAM,
+ gma_write16(hw, port, GM_TX_PARAM,
TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) |
TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) |
TX_IPG_JAM_DATA(TX_IPG_JAM_DEF));
@@ -1872,33 +1778,33 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
if (hw->dev[port]->mtu > 1500)
reg |= GM_SMOD_JUMBO_ENA;
- skge_gma_write16(hw, port, GM_SERIAL_MODE, reg);
+ gma_write16(hw, port, GM_SERIAL_MODE, reg);
/* physical address: used for pause frames */
- skge_gm_set_addr(hw, port, GM_SRC_ADDR_1L, addr);
+ gma_set_addr(hw, port, GM_SRC_ADDR_1L, addr);
/* virtual address for data */
- skge_gm_set_addr(hw, port, GM_SRC_ADDR_2L, addr);
+ gma_set_addr(hw, port, GM_SRC_ADDR_2L, addr);
/* enable interrupt mask for counter overflows */
- skge_gma_write16(hw, port, GM_TX_IRQ_MSK, 0);
- skge_gma_write16(hw, port, GM_RX_IRQ_MSK, 0);
- skge_gma_write16(hw, port, GM_TR_IRQ_MSK, 0);
+ gma_write16(hw, port, GM_TX_IRQ_MSK, 0);
+ gma_write16(hw, port, GM_RX_IRQ_MSK, 0);
+ gma_write16(hw, port, GM_TR_IRQ_MSK, 0);
/* Initialize Mac Fifo */
/* Configure Rx MAC FIFO */
- skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK);
+ skge_write16(hw, SK_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK);
reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
if (hw->chip_id == CHIP_ID_YUKON_LITE &&
- chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+ hw->chip_rev == CHIP_REV_YU_LITE_A3)
reg &= ~GMF_RX_F_FL_ON;
- skge_write8(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
- skge_write16(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), reg);
- skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
+ skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
+ skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
+ skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
/* Configure Tx MAC FIFO */
- skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
- skge_write16(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
+ skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
+ skge_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
}
static void yukon_stop(struct skge_port *skge)
@@ -1907,19 +1813,19 @@ static void yukon_stop(struct skge_port *skge)
int port = skge->port;
if (hw->chip_id == CHIP_ID_YUKON_LITE &&
- chip_rev(hw) == CHIP_REV_YU_LITE_A3) {
+ hw->chip_rev == CHIP_REV_YU_LITE_A3) {
skge_write32(hw, B2_GP_IO,
skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9);
}
- skge_gma_write16(hw, port, GM_GP_CTRL,
- skge_gma_read16(hw, port, GM_GP_CTRL)
+ gma_write16(hw, port, GM_GP_CTRL,
+ gma_read16(hw, port, GM_GP_CTRL)
& ~(GM_GPCR_RX_ENA|GM_GPCR_RX_ENA));
- skge_gma_read16(hw, port, GM_GP_CTRL);
+ gma_read16(hw, port, GM_GP_CTRL);
/* set GPHY Control reset */
- skge_gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET);
- skge_gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET);
+ gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET);
+ gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET);
}
static void yukon_get_stats(struct skge_port *skge, u64 *data)
@@ -1928,39 +1834,40 @@ static void yukon_get_stats(struct skge_port *skge, u64 *data)
int port = skge->port;
int i;
- data[0] = (u64) skge_gma_read32(hw, port, GM_TXO_OK_HI) << 32
- | skge_gma_read32(hw, port, GM_TXO_OK_LO);
- data[1] = (u64) skge_gma_read32(hw, port, GM_RXO_OK_HI) << 32
- | skge_gma_read32(hw, port, GM_RXO_OK_LO);
+ data[0] = (u64) gma_read32(hw, port, GM_TXO_OK_HI) << 32
+ | gma_read32(hw, port, GM_TXO_OK_LO);
+ data[1] = (u64) gma_read32(hw, port, GM_RXO_OK_HI) << 32
+ | gma_read32(hw, port, GM_RXO_OK_LO);
for (i = 2; i < ARRAY_SIZE(skge_stats); i++)
- data[i] = skge_gma_read32(hw, port,
+ data[i] = gma_read32(hw, port,
skge_stats[i].gma_offset);
}
static void yukon_mac_intr(struct skge_hw *hw, int port)
{
- struct skge_port *skge = netdev_priv(hw->dev[port]);
- u8 status = skge_read8(hw, SKGEMAC_REG(port, GMAC_IRQ_SRC));
+ struct net_device *dev = hw->dev[port];
+ struct skge_port *skge = netdev_priv(dev);
+ u8 status = skge_read8(hw, SK_REG(port, GMAC_IRQ_SRC));
+
+ if (netif_msg_intr(skge))
+ printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
+ dev->name, status);
- pr_debug("yukon_intr status %x\n", status);
if (status & GM_IS_RX_FF_OR) {
++skge->net_stats.rx_fifo_errors;
- skge_gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO);
+ gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO);
}
if (status & GM_IS_TX_FF_UR) {
++skge->net_stats.tx_fifo_errors;
- skge_gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU);
+ gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU);
}
}
static u16 yukon_speed(const struct skge_hw *hw, u16 aux)
{
- if (hw->chip_id == CHIP_ID_YUKON_FE)
- return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10;
-
- switch(aux & PHY_M_PS_SPEED_MSK) {
+ switch (aux & PHY_M_PS_SPEED_MSK) {
case PHY_M_PS_SPEED_1000:
return SPEED_1000;
case PHY_M_PS_SPEED_100:
@@ -1981,15 +1888,15 @@ static void yukon_link_up(struct skge_port *skge)
/* Enable Transmit FIFO Underrun */
skge_write8(hw, GMAC_IRQ_MSK, GMAC_DEF_MSK);
- reg = skge_gma_read16(hw, port, GM_GP_CTRL);
+ reg = gma_read16(hw, port, GM_GP_CTRL);
if (skge->duplex == DUPLEX_FULL || skge->autoneg == AUTONEG_ENABLE)
reg |= GM_GPCR_DUP_FULL;
/* enable Rx/Tx */
reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
- skge_gma_write16(hw, port, GM_GP_CTRL, reg);
+ gma_write16(hw, port, GM_GP_CTRL, reg);
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
skge_link_up(skge);
}
@@ -1999,16 +1906,15 @@ static void yukon_link_down(struct skge_port *skge)
int port = skge->port;
pr_debug("yukon_link_down\n");
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);
- skge_gm_phy_write(hw, port, GM_GP_CTRL,
- skge_gm_phy_read(hw, port, GM_GP_CTRL)
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);
+ gm_phy_write(hw, port, GM_GP_CTRL,
+ gm_phy_read(hw, port, GM_GP_CTRL)
& ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA));
- if (hw->chip_id != CHIP_ID_YUKON_FE &&
- skge->flow_control == FLOW_MODE_REM_SEND) {
+ if (skge->flow_control == FLOW_MODE_REM_SEND) {
/* restore Asymmetric Pause bit */
- skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
- skge_gm_phy_read(hw, port,
+ gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
+ gm_phy_read(hw, port,
PHY_MARV_AUNE_ADV)
| PHY_M_AN_ASP);
@@ -2027,20 +1933,21 @@ static void yukon_phy_intr(struct skge_port *skge)
const char *reason = NULL;
u16 istatus, phystat;
- istatus = skge_gm_phy_read(hw, port, PHY_MARV_INT_STAT);
- phystat = skge_gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
- pr_debug("yukon phy intr istat=%x phy_stat=%x\n", istatus, phystat);
+ istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT);
+ phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
+
+ if (netif_msg_intr(skge))
+ printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x 0x%x\n",
+ skge->netdev->name, istatus, phystat);
if (istatus & PHY_M_IS_AN_COMPL) {
- if (skge_gm_phy_read(hw, port, PHY_MARV_AUNE_LP)
+ if (gm_phy_read(hw, port, PHY_MARV_AUNE_LP)
& PHY_M_AN_RF) {
reason = "remote fault";
goto failed;
}
- if (!(hw->chip_id == CHIP_ID_YUKON_FE || hw->chip_id == CHIP_ID_YUKON_EC)
- && (skge_gm_phy_read(hw, port, PHY_MARV_1000T_STAT)
- & PHY_B_1000S_MSF)) {
+ if (gm_phy_read(hw, port, PHY_MARV_1000T_STAT) & PHY_B_1000S_MSF) {
reason = "master/slave fault";
goto failed;
}
@@ -2054,10 +1961,6 @@ static void yukon_phy_intr(struct skge_port *skge)
? DUPLEX_FULL : DUPLEX_HALF;
skge->speed = yukon_speed(hw, phystat);
- /* Tx & Rx Pause Enabled bits are at 9..8 */
- if (hw->chip_id == CHIP_ID_YUKON_XL)
- phystat >>= 6;
-
/* We are using IEEE 802.3z/D5.0 Table 37-4 */
switch (phystat & PHY_M_PS_PAUSE_MSK) {
case PHY_M_PS_PAUSE_MSK:
@@ -2075,9 +1978,9 @@ static void yukon_phy_intr(struct skge_port *skge)
if (skge->flow_control == FLOW_MODE_NONE ||
(skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF))
- skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+ skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
else
- skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
+ skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
yukon_link_up(skge);
return;
}
@@ -2161,6 +2064,12 @@ static int skge_up(struct net_device *dev)
if (netif_msg_ifup(skge))
printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
+ if (dev->mtu > RX_BUF_SIZE)
+ skge->rx_buf_size = dev->mtu + ETH_HLEN + NET_IP_ALIGN;
+ else
+ skge->rx_buf_size = RX_BUF_SIZE;
+
+
rx_size = skge->rx_ring.count * sizeof(struct skge_rx_desc);
tx_size = skge->tx_ring.count * sizeof(struct skge_tx_desc);
skge->mem_size = tx_size + rx_size;
@@ -2173,7 +2082,8 @@ static int skge_up(struct net_device *dev)
if ((err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma)))
goto free_pci_mem;
- if (skge_rx_fill(skge))
+ err = skge_rx_fill(skge);
+ if (err)
goto free_rx_ring;
if ((err = skge_ring_alloc(&skge->tx_ring, skge->mem + rx_size,
@@ -2182,6 +2092,10 @@ static int skge_up(struct net_device *dev)
skge->tx_avail = skge->tx_ring.count - 1;
+ /* Enable IRQ from port */
+ hw->intr_mask |= portirqmask[port];
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
+
/* Initialze MAC */
if (hw->chip_id == CHIP_ID_GENESIS)
genesis_mac_init(hw, port);
@@ -2189,7 +2103,7 @@ static int skge_up(struct net_device *dev)
yukon_mac_init(hw, port);
/* Configure RAMbuffers */
- chunk = hw->ram_size / (isdualport(hw) ? 4 : 2);
+ chunk = hw->ram_size / ((hw->ports + 1)*2);
ram_addr = hw->ram_offset + 2 * chunk * port;
skge_ramset(hw, rxqaddr[port], ram_addr, chunk);
@@ -2227,7 +2141,6 @@ static int skge_down(struct net_device *dev)
netif_stop_queue(dev);
del_timer_sync(&skge->led_blink);
- del_timer_sync(&skge->link_check);
/* Stop transmitter */
skge_write8(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_STOP);
@@ -2240,12 +2153,12 @@ static int skge_down(struct net_device *dev)
yukon_stop(skge);
/* Disable Force Sync bit and Enable Alloc bit */
- skge_write8(hw, SKGEMAC_REG(port, TXA_CTRL),
+ skge_write8(hw, SK_REG(port, TXA_CTRL),
TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
/* Stop Interval Timer and Limit Counter of Tx Arbiter */
- skge_write32(hw, SKGEMAC_REG(port, TXA_ITI_INI), 0L);
- skge_write32(hw, SKGEMAC_REG(port, TXA_LIM_INI), 0L);
+ skge_write32(hw, SK_REG(port, TXA_ITI_INI), 0L);
+ skge_write32(hw, SK_REG(port, TXA_LIM_INI), 0L);
/* Reset PCI FIFO */
skge_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_SET_RESET);
@@ -2260,13 +2173,13 @@ static int skge_down(struct net_device *dev)
skge_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_SET_RESET);
if (hw->chip_id == CHIP_ID_GENESIS) {
- skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_RST_SET);
- skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_RST_SET);
- skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_STOP);
- skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_STOP);
+ skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_SET);
+ skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_SET);
+ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_STOP);
+ skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_STOP);
} else {
- skge_write8(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
- skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
+ skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+ skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
}
/* turn off led's */
@@ -2299,10 +2212,10 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
local_irq_save(flags);
if (!spin_trylock(&skge->tx_lock)) {
- /* Collision - tell upper layer to requeue */
- local_irq_restore(flags);
- return NETDEV_TX_LOCKED;
- }
+ /* Collision - tell upper layer to requeue */
+ local_irq_restore(flags);
+ return NETDEV_TX_LOCKED;
+ }
if (unlikely(skge->tx_avail < skb_shinfo(skb)->nr_frags +1)) {
netif_stop_queue(dev);
@@ -2333,7 +2246,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
* does. Looks like hardware is wrong?
*/
if (ip->protocol == IPPROTO_UDP
- && chip_rev(hw) == 0 && hw->chip_id == CHIP_ID_YUKON)
+ && hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON)
control = BMU_TCP_CHECK;
else
control = BMU_UDP_CHECK;
@@ -2394,6 +2307,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
static inline void skge_tx_free(struct skge_hw *hw, struct skge_element *e)
{
+ /* This ring element can be skb or fragment */
if (e->skb) {
pci_unmap_single(hw->pdev,
pci_unmap_addr(e, mapaddr),
@@ -2438,16 +2352,17 @@ static void skge_tx_timeout(struct net_device *dev)
static int skge_change_mtu(struct net_device *dev, int new_mtu)
{
int err = 0;
+ int running = netif_running(dev);
- if(new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
+ if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL;
- dev->mtu = new_mtu;
- if (netif_running(dev)) {
+ if (running)
skge_down(dev);
+ dev->mtu = new_mtu;
+ if (running)
skge_up(dev);
- }
return err;
}
@@ -2462,7 +2377,9 @@ static void genesis_set_multicast(struct net_device *dev)
u32 mode;
u8 filter[8];
- mode = skge_xm_read32(hw, port, XM_MODE);
+ pr_debug("genesis_set_multicast flags=%x count=%d\n", dev->flags, dev->mc_count);
+
+ mode = xm_read32(hw, port, XM_MODE);
mode |= XM_MD_ENA_HASH;
if (dev->flags & IFF_PROMISC)
mode |= XM_MD_ENA_PROM;
@@ -2473,17 +2390,16 @@ static void genesis_set_multicast(struct net_device *dev)
memset(filter, 0xff, sizeof(filter));
else {
memset(filter, 0, sizeof(filter));
- for(i = 0; list && i < count; i++, list = list->next) {
- u32 crc = crc32_le(~0, list->dmi_addr, ETH_ALEN);
- u8 bit = 63 - (crc & 63);
-
+ for (i = 0; list && i < count; i++, list = list->next) {
+ u32 crc, bit;
+ crc = ether_crc_le(ETH_ALEN, list->dmi_addr);
+ bit = ~crc & 0x3f;
filter[bit/8] |= 1 << (bit%8);
}
}
- skge_xm_outhash(hw, port, XM_HSM, filter);
-
- skge_xm_write32(hw, port, XM_MODE, mode);
+ xm_write32(hw, port, XM_MODE, mode);
+ xm_outhash(hw, port, XM_HSM, filter);
}
static void yukon_set_multicast(struct net_device *dev)
@@ -2497,7 +2413,7 @@ static void yukon_set_multicast(struct net_device *dev)
memset(filter, 0, sizeof(filter));
- reg = skge_gma_read16(hw, port, GM_RX_CTRL);
+ reg = gma_read16(hw, port, GM_RX_CTRL);
reg |= GM_RXCR_UCF_ENA;
if (dev->flags & IFF_PROMISC) /* promiscious */
@@ -2510,23 +2426,23 @@ static void yukon_set_multicast(struct net_device *dev)
int i;
reg |= GM_RXCR_MCF_ENA;
- for(i = 0; list && i < dev->mc_count; i++, list = list->next) {
+ for (i = 0; list && i < dev->mc_count; i++, list = list->next) {
u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f;
filter[bit/8] |= 1 << (bit%8);
}
}
- skge_gma_write16(hw, port, GM_MC_ADDR_H1,
+ gma_write16(hw, port, GM_MC_ADDR_H1,
(u16)filter[0] | ((u16)filter[1] << 8));
- skge_gma_write16(hw, port, GM_MC_ADDR_H2,
+ gma_write16(hw, port, GM_MC_ADDR_H2,
(u16)filter[2] | ((u16)filter[3] << 8));
- skge_gma_write16(hw, port, GM_MC_ADDR_H3,
+ gma_write16(hw, port, GM_MC_ADDR_H3,
(u16)filter[4] | ((u16)filter[5] << 8));
- skge_gma_write16(hw, port, GM_MC_ADDR_H4,
+ gma_write16(hw, port, GM_MC_ADDR_H4,
(u16)filter[6] | ((u16)filter[7] << 8));
- skge_gma_write16(hw, port, GM_RX_CTRL, reg);
+ gma_write16(hw, port, GM_RX_CTRL, reg);
}
static inline int bad_phy_status(const struct skge_hw *hw, u32 status)
@@ -2545,28 +2461,76 @@ static void skge_rx_error(struct skge_port *skge, int slot,
printk(KERN_DEBUG PFX "%s: rx err, slot %d control 0x%x status 0x%x\n",
skge->netdev->name, slot, control, status);
- if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
- || (control & BMU_BBC) > skge->netdev->mtu + VLAN_ETH_HLEN)
+ if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF))
skge->net_stats.rx_length_errors++;
- else {
- if (skge->hw->chip_id == CHIP_ID_GENESIS) {
- if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
- skge->net_stats.rx_length_errors++;
- if (status & XMR_FS_FRA_ERR)
- skge->net_stats.rx_frame_errors++;
- if (status & XMR_FS_FCS_ERR)
- skge->net_stats.rx_crc_errors++;
- } else {
- if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE))
- skge->net_stats.rx_length_errors++;
- if (status & GMR_FS_FRAGMENT)
- skge->net_stats.rx_frame_errors++;
- if (status & GMR_FS_CRC_ERR)
- skge->net_stats.rx_crc_errors++;
+ else if (skge->hw->chip_id == CHIP_ID_GENESIS) {
+ if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
+ skge->net_stats.rx_length_errors++;
+ if (status & XMR_FS_FRA_ERR)
+ skge->net_stats.rx_frame_errors++;
+ if (status & XMR_FS_FCS_ERR)
+ skge->net_stats.rx_crc_errors++;
+ } else {
+ if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE))
+ skge->net_stats.rx_length_errors++;
+ if (status & GMR_FS_FRAGMENT)
+ skge->net_stats.rx_frame_errors++;
+ if (status & GMR_FS_CRC_ERR)
+ skge->net_stats.rx_crc_errors++;
+ }
+}
+
+/* Get receive buffer from descriptor.
+ * Handles copy of small buffers and reallocation failures
+ */
+static inline struct sk_buff *skge_rx_get(struct skge_port *skge,
+ struct skge_element *e,
+ unsigned int len)
+{
+ struct sk_buff *nskb, *skb;
+
+ if (len < RX_COPY_THRESHOLD) {
+ nskb = skge_rx_alloc(skge->netdev, len + NET_IP_ALIGN);
+ if (unlikely(!nskb))
+ return NULL;
+
+ pci_dma_sync_single_for_cpu(skge->hw->pdev,
+ pci_unmap_addr(e, mapaddr),
+ len, PCI_DMA_FROMDEVICE);
+ memcpy(nskb->data, e->skb->data, len);
+ pci_dma_sync_single_for_device(skge->hw->pdev,
+ pci_unmap_addr(e, mapaddr),
+ len, PCI_DMA_FROMDEVICE);
+
+ if (skge->rx_csum) {
+ struct skge_rx_desc *rd = e->desc;
+ nskb->csum = le16_to_cpu(rd->csum2);
+ nskb->ip_summed = CHECKSUM_HW;
}
+ skge_rx_reuse(e, skge->rx_buf_size);
+ return nskb;
+ } else {
+ nskb = skge_rx_alloc(skge->netdev, skge->rx_buf_size);
+ if (unlikely(!nskb))
+ return NULL;
+
+ pci_unmap_single(skge->hw->pdev,
+ pci_unmap_addr(e, mapaddr),
+ pci_unmap_len(e, maplen),
+ PCI_DMA_FROMDEVICE);
+ skb = e->skb;
+ if (skge->rx_csum) {
+ struct skge_rx_desc *rd = e->desc;
+ skb->csum = le16_to_cpu(rd->csum2);
+ skb->ip_summed = CHECKSUM_HW;
+ }
+
+ skge_rx_setup(skge, e, nskb, skge->rx_buf_size);
+ return skb;
}
}
+
static int skge_poll(struct net_device *dev, int *budget)
{
struct skge_port *skge = netdev_priv(dev);
@@ -2575,13 +2539,12 @@ static int skge_poll(struct net_device *dev, int *budget)
struct skge_element *e;
unsigned int to_do = min(dev->quota, *budget);
unsigned int work_done = 0;
- int done;
- static const u32 irqmask[] = { IS_PORT_1, IS_PORT_2 };
- for (e = ring->to_clean; e != ring->to_use && work_done < to_do;
- e = e->next) {
+ pr_debug("skge_poll\n");
+
+ for (e = ring->to_clean; work_done < to_do; e = e->next) {
struct skge_rx_desc *rd = e->desc;
- struct sk_buff *skb = e->skb;
+ struct sk_buff *skb;
u32 control, len, status;
rmb();
@@ -2590,19 +2553,12 @@ static int skge_poll(struct net_device *dev, int *budget)
break;
len = control & BMU_BBC;
- e->skb = NULL;
-
- pci_unmap_single(hw->pdev,
- pci_unmap_addr(e, mapaddr),
- pci_unmap_len(e, maplen),
- PCI_DMA_FROMDEVICE);
-
status = rd->status;
- if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
- || len > dev->mtu + VLAN_ETH_HLEN
- || bad_phy_status(hw, status)) {
+
+ if (unlikely((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
+ || bad_phy_status(hw, status))) {
skge_rx_error(skge, e - ring->start, control, status);
- dev_kfree_skb(skb);
+ skge_rx_reuse(e, skge->rx_buf_size);
continue;
}
@@ -2610,43 +2566,37 @@ static int skge_poll(struct net_device *dev, int *budget)
printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n",
dev->name, e - ring->start, rd->status, len);
- skb_put(skb, len);
- skb->protocol = eth_type_trans(skb, dev);
-
- if (skge->rx_csum) {
- skb->csum = le16_to_cpu(rd->csum2);
- skb->ip_summed = CHECKSUM_HW;
- }
+ skb = skge_rx_get(skge, e, len);
+ if (likely(skb)) {
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, dev);
- dev->last_rx = jiffies;
- netif_receive_skb(skb);
+ dev->last_rx = jiffies;
+ netif_receive_skb(skb);
- ++work_done;
+ ++work_done;
+ } else
+ skge_rx_reuse(e, skge->rx_buf_size);
}
ring->to_clean = e;
- *budget -= work_done;
- dev->quota -= work_done;
- done = work_done < to_do;
-
- if (skge_rx_fill(skge))
- done = 0;
-
/* restart receiver */
wmb();
skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR),
CSR_START | CSR_IRQ_CL_F);
- if (done) {
- local_irq_disable();
- hw->intr_mask |= irqmask[skge->port];
- /* Order is important since data can get interrupted */
- skge_write32(hw, B0_IMSK, hw->intr_mask);
- __netif_rx_complete(dev);
- local_irq_enable();
- }
+ *budget -= work_done;
+ dev->quota -= work_done;
- return !done;
+ if (work_done >= to_do)
+ return 1; /* not done */
+
+ local_irq_disable();
+ __netif_rx_complete(dev);
+ hw->intr_mask |= portirqmask[skge->port];
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
+ local_irq_enable();
+ return 0;
}
static inline void skge_tx_intr(struct net_device *dev)
@@ -2657,7 +2607,7 @@ static inline void skge_tx_intr(struct net_device *dev)
struct skge_element *e;
spin_lock(&skge->tx_lock);
- for(e = ring->to_clean; e != ring->to_use; e = e->next) {
+ for (e = ring->to_clean; e != ring->to_use; e = e->next) {
struct skge_tx_desc *td = e->desc;
u32 control;
@@ -2690,12 +2640,12 @@ static void skge_mac_parity(struct skge_hw *hw, int port)
: (port == 0 ? "(port A)": "(port B"));
if (hw->chip_id == CHIP_ID_GENESIS)
- skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1),
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1),
MFF_CLR_PERR);
else
/* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */
- skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T),
- (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0)
+ skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T),
+ (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)
? GMF_CLI_TX_FC : GMF_CLI_TX_PE);
}
@@ -2703,16 +2653,16 @@ static void skge_pci_clear(struct skge_hw *hw)
{
u16 status;
- status = skge_read16(hw, SKGEPCI_REG(PCI_STATUS));
+ pci_read_config_word(hw->pdev, PCI_STATUS, &status);
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- skge_write16(hw, SKGEPCI_REG(PCI_STATUS),
- status | PCI_STATUS_ERROR_BITS);
+ pci_write_config_word(hw->pdev, PCI_STATUS,
+ status | PCI_STATUS_ERROR_BITS);
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
}
static void skge_mac_intr(struct skge_hw *hw, int port)
{
- if (hw->chip_id == CHIP_ID_GENESIS)
+ if (hw->chip_id == CHIP_ID_GENESIS)
genesis_mac_intr(hw, port);
else
yukon_mac_intr(hw, port);
@@ -2726,9 +2676,9 @@ static void skge_error_irq(struct skge_hw *hw)
if (hw->chip_id == CHIP_ID_GENESIS) {
/* clear xmac errors */
if (hwstatus & (IS_NO_STAT_M1|IS_NO_TIST_M1))
- skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+ skge_write16(hw, SK_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT);
if (hwstatus & (IS_NO_STAT_M2|IS_NO_TIST_M2))
- skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT);
+ skge_write16(hw, SK_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT);
} else {
/* Timestamp (unused) overflow */
if (hwstatus & IS_IRQ_TIST_OV)
@@ -2803,8 +2753,8 @@ static void skge_extirq(unsigned long data)
if (hw->chip_id != CHIP_ID_GENESIS)
yukon_phy_intr(skge);
- else if (hw->phy_type == SK_PHY_BCOM)
- genesis_bcom_intr(skge);
+ else
+ bcom_phy_intr(skge);
}
}
spin_unlock(&hw->phy_lock);
@@ -2824,19 +2774,14 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_NONE;
status &= hw->intr_mask;
-
- if ((status & IS_R1_F) && netif_rx_schedule_prep(hw->dev[0])) {
- status &= ~IS_R1_F;
+ if (status & IS_R1_F) {
hw->intr_mask &= ~IS_R1_F;
- skge_write32(hw, B0_IMSK, hw->intr_mask);
- __netif_rx_schedule(hw->dev[0]);
+ netif_rx_schedule(hw->dev[0]);
}
- if ((status & IS_R2_F) && netif_rx_schedule_prep(hw->dev[1])) {
- status &= ~IS_R2_F;
+ if (status & IS_R2_F) {
hw->intr_mask &= ~IS_R2_F;
- skge_write32(hw, B0_IMSK, hw->intr_mask);
- __netif_rx_schedule(hw->dev[1]);
+ netif_rx_schedule(hw->dev[1]);
}
if (status & IS_XA1_F)
@@ -2845,9 +2790,27 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
if (status & IS_XA2_F)
skge_tx_intr(hw->dev[1]);
+ if (status & IS_PA_TO_RX1) {
+ struct skge_port *skge = netdev_priv(hw->dev[0]);
+ ++skge->net_stats.rx_over_errors;
+ skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX1);
+ }
+
+ if (status & IS_PA_TO_RX2) {
+ struct skge_port *skge = netdev_priv(hw->dev[1]);
+ ++skge->net_stats.rx_over_errors;
+ skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2);
+ }
+
+ if (status & IS_PA_TO_TX1)
+ skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX1);
+
+ if (status & IS_PA_TO_TX2)
+ skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX2);
+
if (status & IS_MAC1)
skge_mac_intr(hw, 0);
-
+
if (status & IS_MAC2)
skge_mac_intr(hw, 1);
@@ -2859,8 +2822,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
tasklet_schedule(&hw->ext_tasklet);
}
- if (status)
- skge_write32(hw, B0_IMSK, hw->intr_mask);
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
return IRQ_HANDLED;
}
@@ -2904,9 +2866,6 @@ static const struct {
{ CHIP_ID_YUKON, "Yukon" },
{ CHIP_ID_YUKON_LITE, "Yukon-Lite"},
{ CHIP_ID_YUKON_LP, "Yukon-LP"},
- { CHIP_ID_YUKON_XL, "Yukon-2 XL"},
- { CHIP_ID_YUKON_EC, "YUKON-2 EC"},
- { CHIP_ID_YUKON_FE, "YUKON-2 FE"},
};
static const char *skge_board_name(const struct skge_hw *hw)
@@ -2930,8 +2889,8 @@ static const char *skge_board_name(const struct skge_hw *hw)
static int skge_reset(struct skge_hw *hw)
{
u16 ctst;
- u8 t8;
- int i, ports;
+ u8 t8, mac_cfg;
+ int i;
ctst = skge_read16(hw, B0_CTST);
@@ -2952,12 +2911,9 @@ static int skge_reset(struct skge_hw *hw)
hw->phy_type = skge_read8(hw, B2_E_1) & 0xf;
hw->pmd_type = skge_read8(hw, B2_PMD_TYP);
- switch(hw->chip_id) {
+ switch (hw->chip_id) {
case CHIP_ID_GENESIS:
switch (hw->phy_type) {
- case SK_PHY_XMAC:
- hw->phy_addr = PHY_ADDR_XMAC;
- break;
case SK_PHY_BCOM:
hw->phy_addr = PHY_ADDR_BCOM;
break;
@@ -2986,8 +2942,9 @@ static int skge_reset(struct skge_hw *hw)
return -EOPNOTSUPP;
}
- hw->mac_cfg = skge_read8(hw, B2_MAC_CFG);
- ports = isdualport(hw) ? 2 : 1;
+ mac_cfg = skge_read8(hw, B2_MAC_CFG);
+ hw->ports = (mac_cfg & CFG_SNG_MAC) ? 1 : 2;
+ hw->chip_rev = (mac_cfg & CFG_CHIP_R_MSK) >> 4;
/* read the adapters RAM size */
t8 = skge_read8(hw, B2_E_0);
@@ -3010,9 +2967,9 @@ static int skge_reset(struct skge_hw *hw)
/* switch power to VCC (WA for VAUX problem) */
skge_write8(hw, B0_POWER_CTRL,
PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
- for (i = 0; i < ports; i++) {
- skge_write16(hw, SKGEMAC_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
- skge_write16(hw, SKGEMAC_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+ for (i = 0; i < hw->ports; i++) {
+ skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
+ skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
}
}
@@ -3022,8 +2979,8 @@ static int skge_reset(struct skge_hw *hw)
skge_write8(hw, B0_LED, LED_STAT_ON);
/* enable the Tx Arbiters */
- for (i = 0; i < ports; i++)
- skge_write8(hw, SKGEMAC_REG(i, TXA_CTRL), TXA_ENA_ARB);
+ for (i = 0; i < hw->ports; i++)
+ skge_write8(hw, SK_REG(i, TXA_CTRL), TXA_ENA_ARB);
/* Initialize ram interface */
skge_write16(hw, B3_RI_CTRL, RI_RST_CLR);
@@ -3050,16 +3007,14 @@ static int skge_reset(struct skge_hw *hw)
skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100));
skge_write32(hw, B2_IRQM_CTRL, TIM_START);
- hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1;
- if (isdualport(hw))
- hw->intr_mask |= IS_PORT_2;
+ hw->intr_mask = IS_HW_ERR | IS_EXT_REG;
skge_write32(hw, B0_IMSK, hw->intr_mask);
if (hw->chip_id != CHIP_ID_GENESIS)
skge_write8(hw, GMAC_IRQ_MSK, 0);
spin_lock_bh(&hw->phy_lock);
- for (i = 0; i < ports; i++) {
+ for (i = 0; i < hw->ports; i++) {
if (hw->chip_id == CHIP_ID_GENESIS)
genesis_reset(hw, i);
else
@@ -3071,7 +3026,8 @@ static int skge_reset(struct skge_hw *hw)
}
/* Initialize network device */
-static struct net_device *skge_devinit(struct skge_hw *hw, int port)
+static struct net_device *skge_devinit(struct skge_hw *hw, int port,
+ int highmem)
{
struct skge_port *skge;
struct net_device *dev = alloc_etherdev(sizeof(*skge));
@@ -3104,6 +3060,8 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port)
#endif
dev->irq = hw->pdev->irq;
dev->features = NETIF_F_LLTX;
+ if (highmem)
+ dev->features |= NETIF_F_HIGHDMA;
skge = netdev_priv(dev);
skge->netdev = dev;
@@ -3117,7 +3075,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port)
skge->flow_control = FLOW_MODE_SYMMETRIC;
skge->duplex = -1;
skge->speed = -1;
- skge->advertising = skge_modes(hw);
+ skge->advertising = skge_supported_modes(hw);
hw->dev[port] = dev;
@@ -3125,10 +3083,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port)
spin_lock_init(&skge->tx_lock);
- init_timer(&skge->link_check);
- skge->link_check.function = skge_link_timer;
- skge->link_check.data = (unsigned long) skge;
-
init_timer(&skge->led_blink);
skge->led_blink.function = skge_blink_timer;
skge->led_blink.data = (unsigned long) skge;
@@ -3232,14 +3186,11 @@ static int __devinit skge_probe(struct pci_dev *pdev,
printk(KERN_INFO PFX "addr 0x%lx irq %d chip %s rev %d\n",
pci_resource_start(pdev, 0), pdev->irq,
- skge_board_name(hw), chip_rev(hw));
+ skge_board_name(hw), hw->chip_rev);
- if ((dev = skge_devinit(hw, 0)) == NULL)
+ if ((dev = skge_devinit(hw, 0, using_dac)) == NULL)
goto err_out_led_off;
- if (using_dac)
- dev->features |= NETIF_F_HIGHDMA;
-
if ((err = register_netdev(dev))) {
printk(KERN_ERR PFX "%s: cannot register net device\n",
pci_name(pdev));
@@ -3248,10 +3199,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
skge_show_addr(dev);
- if (isdualport(hw) && (dev1 = skge_devinit(hw, 1))) {
- if (using_dac)
- dev1->features |= NETIF_F_HIGHDMA;
-
+ if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) {
if (register_netdev(dev1) == 0)
skge_show_addr(dev1);
else {
@@ -3288,7 +3236,7 @@ static void __devexit skge_remove(struct pci_dev *pdev)
struct skge_hw *hw = pci_get_drvdata(pdev);
struct net_device *dev0, *dev1;
- if(!hw)
+ if (!hw)
return;
if ((dev1 = hw->dev[1]))
@@ -3316,7 +3264,7 @@ static int skge_suspend(struct pci_dev *pdev, u32 state)
struct skge_hw *hw = pci_get_drvdata(pdev);
int i, wol = 0;
- for(i = 0; i < 2; i++) {
+ for (i = 0; i < 2; i++) {
struct net_device *dev = hw->dev[i];
if (dev) {
@@ -3349,11 +3297,11 @@ static int skge_resume(struct pci_dev *pdev)
skge_reset(hw);
- for(i = 0; i < 2; i++) {
+ for (i = 0; i < 2; i++) {
struct net_device *dev = hw->dev[i];
if (dev) {
netif_device_attach(dev);
- if(netif_running(dev))
+ if (netif_running(dev))
skge_up(dev);
}
}
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 36c62b68fab..14d0cc01fb9 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -7,31 +7,6 @@
/* PCI config registers */
#define PCI_DEV_REG1 0x40
#define PCI_DEV_REG2 0x44
-#ifndef PCI_VPD
-#define PCI_VPD 0x50
-#endif
-
-/* PCI_OUR_REG_2 32 bit Our Register 2 */
-enum {
- PCI_VPD_WR_THR = 0xff<<24, /* Bit 31..24: VPD Write Threshold */
- PCI_DEV_SEL = 0x7f<<17, /* Bit 23..17: EEPROM Device Select */
- PCI_VPD_ROM_SZ = 7 <<14, /* Bit 16..14: VPD ROM Size */
- /* Bit 13..12: reserved */
- PCI_EN_DUMMY_RD = 1<<3, /* Enable Dummy Read */
- PCI_REV_DESC = 1<<2, /* Reverse Desc. Bytes */
- PCI_USEDATA64 = 1<<0, /* Use 64Bit Data bus ext */
-};
-
-/* PCI_VPD_ADR_REG 16 bit VPD Address Register */
-enum {
- PCI_VPD_FLAG = 1<<15, /* starts VPD rd/wr cycle */
- PCI_VPD_ADR_MSK =0x7fffL, /* Bit 14.. 0: VPD Address Mask */
- VPD_RES_ID = 0x82,
- VPD_RES_READ = 0x90,
- VPD_RES_WRITE = 0x81,
- VPD_RES_END = 0x78,
-};
-
#define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
PCI_STATUS_SIG_SYSTEM_ERROR | \
@@ -39,7 +14,6 @@ enum {
PCI_STATUS_REC_TARGET_ABORT | \
PCI_STATUS_PARITY)
-
enum csr_regs {
B0_RAP = 0x0000,
B0_CTST = 0x0004,
@@ -229,8 +203,11 @@ enum {
IS_XA2_F = 1<<1, /* Q_XA2 End of Frame */
IS_XA2_C = 1<<0, /* Q_XA2 Encoding Error */
- IS_PORT_1 = IS_XA1_F| IS_R1_F| IS_MAC1,
- IS_PORT_2 = IS_XA2_F| IS_R2_F| IS_MAC2,
+ IS_TO_PORT1 = IS_PA_TO_RX1 | IS_PA_TO_TX1,
+ IS_TO_PORT2 = IS_PA_TO_RX2 | IS_PA_TO_TX2,
+
+ IS_PORT_1 = IS_XA1_F| IS_R1_F | IS_TO_PORT1 | IS_MAC1,
+ IS_PORT_2 = IS_XA2_F| IS_R2_F | IS_TO_PORT2 | IS_MAC2,
};
@@ -288,14 +265,6 @@ enum {
CHIP_REV_YU_LITE_A3 = 7, /* Chip Rev. for YUKON-Lite A3 */
};
-/* B2_LD_TEST 8 bit EPROM loader test register */
-enum {
- LD_T_ON = 1<<3, /* Loader Test mode on */
- LD_T_OFF = 1<<2, /* Loader Test mode off */
- LD_T_STEP = 1<<1, /* Decrement FPROM addr. Counter */
- LD_START = 1<<0, /* Start loading FPROM */
-};
-
/* B2_TI_CTRL 8 bit Timer control */
/* B2_IRQM_CTRL 8 bit IRQ Moderation Timer Control */
enum {
@@ -313,16 +282,6 @@ enum {
TIM_T_STEP = 1<<0, /* Test step */
};
-/* B28_DPT_INI 32 bit Descriptor Poll Timer Init Val */
-/* B28_DPT_VAL 32 bit Descriptor Poll Timer Curr Val */
-/* B28_DPT_CTRL 8 bit Descriptor Poll Timer Ctrl Reg */
-enum {
- DPT_MSK = 0x00ffffffL, /* Bit 23.. 0: Desc Poll Timer Bits */
-
- DPT_START = 1<<1, /* Start Descriptor Poll Timer */
- DPT_STOP = 1<<0, /* Stop Descriptor Poll Timer */
-};
-
/* B2_GP_IO 32 bit General Purpose I/O Register */
enum {
GP_DIR_9 = 1<<25, /* IO_9 direct, 0=In/1=Out */
@@ -348,30 +307,6 @@ enum {
GP_IO_0 = 1<<0, /* IO_0 pin */
};
-/* Rx/Tx Path related Arbiter Test Registers */
-/* B3_MA_TO_TEST 16 bit MAC Arbiter Timeout Test Reg */
-/* B3_MA_RC_TEST 16 bit MAC Arbiter Recovery Test Reg */
-/* B3_PA_TEST 16 bit Packet Arbiter Test Register */
-/* Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */
-enum {
- TX2_T_EV = 1<<15,/* TX2 Timeout/Recv Event occured */
- TX2_T_ON = 1<<14,/* TX2 Timeout/Recv Timer Test On */
- TX2_T_OFF = 1<<13,/* TX2 Timeout/Recv Timer Tst Off */
- TX2_T_STEP = 1<<12,/* TX2 Timeout/Recv Timer Step */
- TX1_T_EV = 1<<11,/* TX1 Timeout/Recv Event occured */
- TX1_T_ON = 1<<10,/* TX1 Timeout/Recv Timer Test On */
- TX1_T_OFF = 1<<9, /* TX1 Timeout/Recv Timer Tst Off */
- TX1_T_STEP = 1<<8, /* TX1 Timeout/Recv Timer Step */
- RX2_T_EV = 1<<7, /* RX2 Timeout/Recv Event occured */
- RX2_T_ON = 1<<6, /* RX2 Timeout/Recv Timer Test On */
- RX2_T_OFF = 1<<5, /* RX2 Timeout/Recv Timer Tst Off */
- RX2_T_STEP = 1<<4, /* RX2 Timeout/Recv Timer Step */
- RX1_T_EV = 1<<3, /* RX1 Timeout/Recv Event occured */
- RX1_T_ON = 1<<2, /* RX1 Timeout/Recv Timer Test On */
- RX1_T_OFF = 1<<1, /* RX1 Timeout/Recv Timer Tst Off */
- RX1_T_STEP = 1<<0, /* RX1 Timeout/Recv Timer Step */
-};
-
/* Descriptor Bit Definition */
/* TxCtrl Transmit Buffer Control Field */
/* RxCtrl Receive Buffer Control Field */
@@ -428,14 +363,6 @@ enum {
RI_RST_SET = 1<<0, /* Set RAM Interface Reset */
};
-/* B3_RI_TEST 8 bit RAM Iface Test Register */
-enum {
- RI_T_EV = 1<<3, /* Timeout Event occured */
- RI_T_ON = 1<<2, /* Timeout Timer Test On */
- RI_T_OFF = 1<<1, /* Timeout Timer Test Off */
- RI_T_STEP = 1<<0, /* Timeout Timer Step */
-};
-
/* MAC Arbiter Registers */
/* B3_MA_TO_CTRL 16 bit MAC Arbiter Timeout Ctrl Reg */
enum {
@@ -452,19 +379,6 @@ enum {
#define SK_PKT_TO_MAX 0xffff /* Maximum value */
#define SK_RI_TO_53 36 /* RAM interface timeout */
-
-/* B3_MA_RC_CTRL 16 bit MAC Arbiter Recovery Ctrl Reg */
-enum {
- MA_ENA_REC_TX2 = 1<<7, /* Enable Recovery Timer TX2 */
- MA_DIS_REC_TX2 = 1<<6, /* Disable Recovery Timer TX2 */
- MA_ENA_REC_TX1 = 1<<5, /* Enable Recovery Timer TX1 */
- MA_DIS_REC_TX1 = 1<<4, /* Disable Recovery Timer TX1 */
- MA_ENA_REC_RX2 = 1<<3, /* Enable Recovery Timer RX2 */
- MA_DIS_REC_RX2 = 1<<2, /* Disable Recovery Timer RX2 */
- MA_ENA_REC_RX1 = 1<<1, /* Enable Recovery Timer RX1 */
- MA_DIS_REC_RX1 = 1<<0, /* Disable Recovery Timer RX1 */
-};
-
/* Packet Arbiter Registers */
/* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */
enum {
@@ -488,7 +402,7 @@ enum {
PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
-/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */
/* TXA_ITI_INI 32 bit Tx Arb Interval Timer Init Val */
/* TXA_ITI_VAL 32 bit Tx Arb Interval Timer Value */
/* TXA_LIM_INI 32 bit Tx Arb Limit Counter Init Val */
@@ -511,7 +425,7 @@ enum {
/*
* Bank 4 - 5
*/
-/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */
enum {
TXA_ITI_INI = 0x0200,/* 32 bit Tx Arb Interval Timer Init Val*/
TXA_ITI_VAL = 0x0204,/* 32 bit Tx Arb Interval Timer Value */
@@ -537,7 +451,7 @@ enum {
/* Queue Register Offsets, use Q_ADDR() to access */
enum {
- B8_Q_REGS = 0x0400, /* base of Queue registers */
+ B8_Q_REGS = 0x0400, /* base of Queue registers */
Q_D = 0x00, /* 8*32 bit Current Descriptor */
Q_DA_L = 0x20, /* 32 bit Current Descriptor Address Low dWord */
Q_DA_H = 0x24, /* 32 bit Current Descriptor Address High dWord */
@@ -618,8 +532,7 @@ enum {
enum {
PHY_ADDR_XMAC = 0<<8,
PHY_ADDR_BCOM = 1<<8,
- PHY_ADDR_LONE = 3<<8,
- PHY_ADDR_NAT = 0<<8,
+
/* GPHY address (bits 15..11 of SMI control reg) */
PHY_ADDR_MARV = 0,
};
@@ -986,7 +899,7 @@ enum {
LINKLED_BLINK_OFF = 0x10,
LINKLED_BLINK_ON = 0x20,
};
-
+
/* GMAC and GPHY Control Registers (YUKON only) */
enum {
GMAC_CTRL = 0x0f00,/* 32 bit GMAC Control Reg */
@@ -1151,54 +1064,6 @@ enum {
PHY_MARV_FE_SPEC_2 = 0x1c,/* 16 bit r/w Specific Control Reg. 2 */
};
-/* Level One-PHY Registers, indirect addressed over XMAC */
-enum {
- PHY_LONE_CTRL = 0x00,/* 16 bit r/w PHY Control Register */
- PHY_LONE_STAT = 0x01,/* 16 bit r/o PHY Status Register */
- PHY_LONE_ID0 = 0x02,/* 16 bit r/o PHY ID0 Register */
- PHY_LONE_ID1 = 0x03,/* 16 bit r/o PHY ID1 Register */
- PHY_LONE_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */
- PHY_LONE_AUNE_LP = 0x05,/* 16 bit r/o Link Part Ability Reg */
- PHY_LONE_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */
- PHY_LONE_NEPG = 0x07,/* 16 bit r/w Next Page Register */
- PHY_LONE_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */
- /* Level One-specific registers */
- PHY_LONE_1000T_CTRL = 0x09,/* 16 bit r/w 1000Base-T Control Reg */
- PHY_LONE_1000T_STAT = 0x0a,/* 16 bit r/o 1000Base-T Status Reg */
- PHY_LONE_EXT_STAT = 0x0f,/* 16 bit r/o Extended Status Reg */
- PHY_LONE_PORT_CFG = 0x10,/* 16 bit r/w Port Configuration Reg*/
- PHY_LONE_Q_STAT = 0x11,/* 16 bit r/o Quick Status Reg */
- PHY_LONE_INT_ENAB = 0x12,/* 16 bit r/w Interrupt Enable Reg */
- PHY_LONE_INT_STAT = 0x13,/* 16 bit r/o Interrupt Status Reg */
- PHY_LONE_LED_CFG = 0x14,/* 16 bit r/w LED Configuration Reg */
- PHY_LONE_PORT_CTRL = 0x15,/* 16 bit r/w Port Control Reg */
- PHY_LONE_CIM = 0x16,/* 16 bit r/o CIM Reg */
-};
-
-/* National-PHY Registers, indirect addressed over XMAC */
-enum {
- PHY_NAT_CTRL = 0x00,/* 16 bit r/w PHY Control Register */
- PHY_NAT_STAT = 0x01,/* 16 bit r/w PHY Status Register */
- PHY_NAT_ID0 = 0x02,/* 16 bit r/o PHY ID0 Register */
- PHY_NAT_ID1 = 0x03,/* 16 bit r/o PHY ID1 Register */
- PHY_NAT_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */
- PHY_NAT_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Ability Reg */
- PHY_NAT_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */
- PHY_NAT_NEPG = 0x07,/* 16 bit r/w Next Page Register */
- PHY_NAT_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner Reg */
- /* National-specific registers */
- PHY_NAT_1000T_CTRL = 0x09,/* 16 bit r/w 1000Base-T Control Reg */
- PHY_NAT_1000T_STAT = 0x0a,/* 16 bit r/o 1000Base-T Status Reg */
- PHY_NAT_EXT_STAT = 0x0f,/* 16 bit r/o Extended Status Register */
- PHY_NAT_EXT_CTRL1 = 0x10,/* 16 bit r/o Extended Control Reg1 */
- PHY_NAT_Q_STAT1 = 0x11,/* 16 bit r/o Quick Status Reg1 */
- PHY_NAT_10B_OP = 0x12,/* 16 bit r/o 10Base-T Operations Reg */
- PHY_NAT_EXT_CTRL2 = 0x13,/* 16 bit r/o Extended Control Reg1 */
- PHY_NAT_Q_STAT2 = 0x14,/* 16 bit r/o Quick Status Reg2 */
-
- PHY_NAT_PHY_ADDR = 0x19,/* 16 bit r/o PHY Address Register */
-};
-
enum {
PHY_CT_RESET = 1<<15, /* Bit 15: (sc) clear all PHY related regs */
PHY_CT_LOOP = 1<<14, /* Bit 14: enable Loopback over PHY */
@@ -1253,8 +1118,29 @@ enum {
PHY_MARV_ID1_Y2 = 0x0C91, /* Yukon-2 (PHY 88E1112) */
};
+/* Advertisement register bits */
enum {
PHY_AN_NXT_PG = 1<<15, /* Bit 15: Request Next Page */
+ PHY_AN_ACK = 1<<14, /* Bit 14: (ro) Acknowledge Received */
+ PHY_AN_RF = 1<<13, /* Bit 13: Remote Fault Bits */
+
+ PHY_AN_PAUSE_ASYM = 1<<11,/* Bit 11: Try for asymmetric */
+ PHY_AN_PAUSE_CAP = 1<<10, /* Bit 10: Try for pause */
+ PHY_AN_100BASE4 = 1<<9, /* Bit 9: Try for 100mbps 4k packets */
+ PHY_AN_100FULL = 1<<8, /* Bit 8: Try for 100mbps full-duplex */
+ PHY_AN_100HALF = 1<<7, /* Bit 7: Try for 100mbps half-duplex */
+ PHY_AN_10FULL = 1<<6, /* Bit 6: Try for 10mbps full-duplex */
+ PHY_AN_10HALF = 1<<5, /* Bit 5: Try for 10mbps half-duplex */
+ PHY_AN_CSMA = 1<<0, /* Bit 0: Only selector supported */
+ PHY_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/
+ PHY_AN_FULL = PHY_AN_100FULL | PHY_AN_10FULL | PHY_AN_CSMA,
+ PHY_AN_ALL = PHY_AN_10HALF | PHY_AN_10FULL |
+ PHY_AN_100HALF | PHY_AN_100FULL,
+};
+
+/* Xmac Specific */
+enum {
+ PHY_X_AN_NXT_PG = 1<<15, /* Bit 15: Request Next Page */
PHY_X_AN_ACK = 1<<14, /* Bit 14: (ro) Acknowledge Received */
PHY_X_AN_RFB = 3<<12,/* Bit 13..12: Remote Fault Bits */
@@ -1263,82 +1149,6 @@ enum {
PHY_X_AN_FD = 1<<5, /* Bit 5: Full Duplex */
};
-enum {
- PHY_B_AN_RF = 1<<13, /* Bit 13: Remote Fault */
-
- PHY_B_AN_ASP = 1<<11, /* Bit 11: Asymmetric Pause */
- PHY_B_AN_PC = 1<<10, /* Bit 10: Pause Capable */
- PHY_B_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/
-};
-
-enum {
- PHY_L_AN_RF = 1<<13, /* Bit 13: Remote Fault */
- /* Bit 12: reserved */
- PHY_L_AN_ASP = 1<<11, /* Bit 11: Asymmetric Pause */
- PHY_L_AN_PC = 1<<10, /* Bit 10: Pause Capable */
-
- PHY_L_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/
-};
-
-/* PHY_NAT_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement */
-/* PHY_NAT_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/
-/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */
-enum {
- PHY_N_AN_RF = 1<<13, /* Bit 13: Remote Fault */
-
- PHY_N_AN_100F = 1<<11, /* Bit 11: 100Base-T2 FD Support */
- PHY_N_AN_100H = 1<<10, /* Bit 10: 100Base-T2 HD Support */
-
- PHY_N_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/
-};
-
-/* field type definition for PHY_x_AN_SEL */
-enum {
- PHY_SEL_TYPE = 1, /* 00001 = Ethernet */
-};
-
-enum {
- PHY_ANE_LP_NP = 1<<3, /* Bit 3: Link Partner can Next Page */
- PHY_ANE_LOC_NP = 1<<2, /* Bit 2: Local PHY can Next Page */
- PHY_ANE_RX_PG = 1<<1, /* Bit 1: Page Received */
-};
-
-enum {
- PHY_ANE_PAR_DF = 1<<4, /* Bit 4: Parallel Detection Fault */
-
- PHY_ANE_LP_CAP = 1<<0, /* Bit 0: Link Partner Auto-Neg. Cap. */
-};
-
-enum {
- PHY_NP_MORE = 1<<15, /* Bit 15: More, Next Pages to follow */
- PHY_NP_ACK1 = 1<<14, /* Bit 14: (ro) Ack1, for receiving a message */
- PHY_NP_MSG_VAL = 1<<13, /* Bit 13: Message Page valid */
- PHY_NP_ACK2 = 1<<12, /* Bit 12: Ack2, comply with msg content */
- PHY_NP_TOG = 1<<11, /* Bit 11: Toggle Bit, ensure sync */
- PHY_NP_MSG = 0x07ff, /* Bit 10..0: Message from/to Link Partner */
-};
-
-enum {
- PHY_X_EX_FD = 1<<15, /* Bit 15: Device Supports Full Duplex */
- PHY_X_EX_HD = 1<<14, /* Bit 14: Device Supports Half Duplex */
-};
-
-enum {
- PHY_X_RS_PAUSE = 3<<7,/* Bit 8..7: selected Pause Mode */
- PHY_X_RS_HD = 1<<6, /* Bit 6: Half Duplex Mode selected */
- PHY_X_RS_FD = 1<<5, /* Bit 5: Full Duplex Mode selected */
- PHY_X_RS_ABLMIS = 1<<4, /* Bit 4: duplex or pause cap mismatch */
- PHY_X_RS_PAUMIS = 1<<3, /* Bit 3: pause capability mismatch */
-};
-
-/** Remote Fault Bits (PHY_X_AN_RFB) encoding */
-enum {
- X_RFB_OK = 0<<12,/* Bit 13..12 No errors, Link OK */
- X_RFB_LF = 1<<12, /* Bit 13..12 Link Failure */
- X_RFB_OFF = 2<<12,/* Bit 13..12 Offline */
- X_RFB_AN_ERR = 3<<12,/* Bit 13..12 Auto-Negotiation Error */
-};
-
/* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */
enum {
PHY_X_P_NO_PAUSE = 0<<7,/* Bit 8..7: no Pause Mode */
@@ -1418,6 +1228,16 @@ enum {
PHY_B_PES_MLT3_ER = 1<<0, /* Bit 0: MLT3 code Error */
};
+/* PHY_BCOM_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/
+/* PHY_BCOM_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/
+enum {
+ PHY_B_AN_RF = 1<<13, /* Bit 13: Remote Fault */
+
+ PHY_B_AN_ASP = 1<<11, /* Bit 11: Asymmetric Pause */
+ PHY_B_AN_PC = 1<<10, /* Bit 10: Pause Capable */
+};
+
+
/***** PHY_BCOM_FC_CTR 16 bit r/w False Carrier Counter *****/
enum {
PHY_B_FC_CTR = 0xff, /* Bit 7..0: False Carrier Counter */
@@ -1478,7 +1298,9 @@ enum {
PHY_B_IS_LST_CHANGE = 1<<1, /* Bit 1: Link Status Changed */
PHY_B_IS_CRC_ER = 1<<0, /* Bit 0: CRC Error */
};
-#define PHY_B_DEF_MSK (~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+#define PHY_B_DEF_MSK \
+ (~(PHY_B_IS_PSE | PHY_B_IS_AN_PR | PHY_B_IS_DUP_CHANGE | \
+ PHY_B_IS_LSP_CHANGE | PHY_B_IS_LST_CHANGE))
/* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */
enum {
@@ -1495,166 +1317,6 @@ enum {
PHY_B_RES_1000HD = 6<<8,/* Bit 10..8: 1000Base-T Half Dup. */
};
-/*
- * Level One-Specific
- */
-/***** PHY_LONE_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
-enum {
- PHY_L_1000C_TEST = 7<<13,/* Bit 15..13: Test Modes */
- PHY_L_1000C_MSE = 1<<12, /* Bit 12: Master/Slave Enable */
- PHY_L_1000C_MSC = 1<<11, /* Bit 11: M/S Configuration */
- PHY_L_1000C_RD = 1<<10, /* Bit 10: Repeater/DTE */
- PHY_L_1000C_AFD = 1<<9, /* Bit 9: Advertise Full Duplex */
- PHY_L_1000C_AHD = 1<<8, /* Bit 8: Advertise Half Duplex */
-};
-
-/***** PHY_LONE_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/
-enum {
- PHY_L_1000S_MSF = 1<<15, /* Bit 15: Master/Slave Fault */
- PHY_L_1000S_MSR = 1<<14, /* Bit 14: Master/Slave Result */
- PHY_L_1000S_LRS = 1<<13, /* Bit 13: Local Receiver Status */
- PHY_L_1000S_RRS = 1<<12, /* Bit 12: Remote Receiver Status */
- PHY_L_1000S_LP_FD = 1<<11, /* Bit 11: Link Partner can FD */
- PHY_L_1000S_LP_HD = 1<<10, /* Bit 10: Link Partner can HD */
-
- PHY_L_1000S_IEC = 0xff, /* Bit 7..0: Idle Error Count */
-
-/***** PHY_LONE_EXT_STAT 16 bit r/o Extended Status Register *****/
- PHY_L_ES_X_FD_CAP = 1<<15, /* Bit 15: 1000Base-X FD capable */
- PHY_L_ES_X_HD_CAP = 1<<14, /* Bit 14: 1000Base-X HD capable */
- PHY_L_ES_T_FD_CAP = 1<<13, /* Bit 13: 1000Base-T FD capable */
- PHY_L_ES_T_HD_CAP = 1<<12, /* Bit 12: 1000Base-T HD capable */
-};
-
-/***** PHY_LONE_PORT_CFG 16 bit r/w Port Configuration Reg *****/
-enum {
- PHY_L_PC_REP_MODE = 1<<15, /* Bit 15: Repeater Mode */
-
- PHY_L_PC_TX_DIS = 1<<13, /* Bit 13: Tx output Disabled */
- PHY_L_PC_BY_SCR = 1<<12, /* Bit 12: Bypass Scrambler */
- PHY_L_PC_BY_45 = 1<<11, /* Bit 11: Bypass 4B5B-Decoder */
- PHY_L_PC_JAB_DIS = 1<<10, /* Bit 10: Jabber Disabled */
- PHY_L_PC_SQE = 1<<9, /* Bit 9: Enable Heartbeat */
- PHY_L_PC_TP_LOOP = 1<<8, /* Bit 8: TP Loopback */
- PHY_L_PC_SSS = 1<<7, /* Bit 7: Smart Speed Selection */
- PHY_L_PC_FIFO_SIZE = 1<<6, /* Bit 6: FIFO Size */
- PHY_L_PC_PRE_EN = 1<<5, /* Bit 5: Preamble Enable */
- PHY_L_PC_CIM = 1<<4, /* Bit 4: Carrier Integrity Mon */
- PHY_L_PC_10_SER = 1<<3, /* Bit 3: Use Serial Output */
- PHY_L_PC_ANISOL = 1<<2, /* Bit 2: Unisolate Port */
- PHY_L_PC_TEN_BIT = 1<<1, /* Bit 1: 10bit iface mode on */
- PHY_L_PC_ALTCLOCK = 1<<0, /* Bit 0: (ro) ALTCLOCK Mode on */
-};
-
-/***** PHY_LONE_Q_STAT 16 bit r/o Quick Status Reg *****/
-enum {
- PHY_L_QS_D_RATE = 3<<14,/* Bit 15..14: Data Rate */
- PHY_L_QS_TX_STAT = 1<<13, /* Bit 13: Transmitting */
- PHY_L_QS_RX_STAT = 1<<12, /* Bit 12: Receiving */
- PHY_L_QS_COL_STAT = 1<<11, /* Bit 11: Collision */
- PHY_L_QS_L_STAT = 1<<10, /* Bit 10: Link is up */
- PHY_L_QS_DUP_MOD = 1<<9, /* Bit 9: Full/Half Duplex */
- PHY_L_QS_AN = 1<<8, /* Bit 8: AutoNeg is On */
- PHY_L_QS_AN_C = 1<<7, /* Bit 7: AN is Complete */
- PHY_L_QS_LLE = 7<<4,/* Bit 6..4: Line Length Estim. */
- PHY_L_QS_PAUSE = 1<<3, /* Bit 3: LP advertised Pause */
- PHY_L_QS_AS_PAUSE = 1<<2, /* Bit 2: LP adv. asym. Pause */
- PHY_L_QS_ISOLATE = 1<<1, /* Bit 1: CIM Isolated */
- PHY_L_QS_EVENT = 1<<0, /* Bit 0: Event has occurred */
-};
-
-/***** PHY_LONE_INT_ENAB 16 bit r/w Interrupt Enable Reg *****/
-/***** PHY_LONE_INT_STAT 16 bit r/o Interrupt Status Reg *****/
-enum {
- PHY_L_IS_AN_F = 1<<13, /* Bit 13: Auto-Negotiation fault */
- PHY_L_IS_CROSS = 1<<11, /* Bit 11: Crossover used */
- PHY_L_IS_POL = 1<<10, /* Bit 10: Polarity correct. used */
- PHY_L_IS_SS = 1<<9, /* Bit 9: Smart Speed Downgrade */
- PHY_L_IS_CFULL = 1<<8, /* Bit 8: Counter Full */
- PHY_L_IS_AN_C = 1<<7, /* Bit 7: AutoNeg Complete */
- PHY_L_IS_SPEED = 1<<6, /* Bit 6: Speed Changed */
- PHY_L_IS_DUP = 1<<5, /* Bit 5: Duplex Changed */
- PHY_L_IS_LS = 1<<4, /* Bit 4: Link Status Changed */
- PHY_L_IS_ISOL = 1<<3, /* Bit 3: Isolate Occured */
- PHY_L_IS_MDINT = 1<<2, /* Bit 2: (ro) STAT: MII Int Pending */
- PHY_L_IS_INTEN = 1<<1, /* Bit 1: ENAB: Enable IRQs */
- PHY_L_IS_FORCE = 1<<0, /* Bit 0: ENAB: Force Interrupt */
-};
-
-/* int. mask */
-#define PHY_L_DEF_MSK (PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN)
-
-/***** PHY_LONE_LED_CFG 16 bit r/w LED Configuration Reg *****/
-enum {
- PHY_L_LC_LEDC = 3<<14,/* Bit 15..14: Col/Blink/On/Off */
- PHY_L_LC_LEDR = 3<<12,/* Bit 13..12: Rx/Blink/On/Off */
- PHY_L_LC_LEDT = 3<<10,/* Bit 11..10: Tx/Blink/On/Off */
- PHY_L_LC_LEDG = 3<<8,/* Bit 9..8: Giga/Blink/On/Off */
- PHY_L_LC_LEDS = 3<<6,/* Bit 7..6: 10-100/Blink/On/Off */
- PHY_L_LC_LEDL = 3<<4,/* Bit 5..4: Link/Blink/On/Off */
- PHY_L_LC_LEDF = 3<<2,/* Bit 3..2: Duplex/Blink/On/Off */
- PHY_L_LC_PSTRECH= 1<<1, /* Bit 1: Strech LED Pulses */
- PHY_L_LC_FREQ = 1<<0, /* Bit 0: 30/100 ms */
-};
-
-/***** PHY_LONE_PORT_CTRL 16 bit r/w Port Control Reg *****/
-enum {
- PHY_L_PC_TX_TCLK = 1<<15, /* Bit 15: Enable TX_TCLK */
- PHY_L_PC_ALT_NP = 1<<13, /* Bit 14: Alternate Next Page */
- PHY_L_PC_GMII_ALT= 1<<12, /* Bit 13: Alternate GMII driver */
- PHY_L_PC_TEN_CRS = 1<<10, /* Bit 10: Extend CRS*/
-};
-
-/***** PHY_LONE_CIM 16 bit r/o CIM Reg *****/
-enum {
- PHY_L_CIM_ISOL = 0xff<<8,/* Bit 15..8: Isolate Count */
- PHY_L_CIM_FALSE_CAR = 0xff, /* Bit 7..0: False Carrier Count */
-};
-
-/*
- * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding
- */
-enum {
- PHY_L_P_NO_PAUSE= 0<<10,/* Bit 11..10: no Pause Mode */
- PHY_L_P_SYM_MD = 1<<10, /* Bit 11..10: symmetric Pause Mode */
- PHY_L_P_ASYM_MD = 2<<10,/* Bit 11..10: asymmetric Pause Mode */
- PHY_L_P_BOTH_MD = 3<<10,/* Bit 11..10: both Pause Mode */
-};
-
-/*
- * National-Specific
- */
-/***** PHY_NAT_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
-enum {
- PHY_N_1000C_TEST= 7<<13,/* Bit 15..13: Test Modes */
- PHY_N_1000C_MSE = 1<<12, /* Bit 12: Master/Slave Enable */
- PHY_N_1000C_MSC = 1<<11, /* Bit 11: M/S Configuration */
- PHY_N_1000C_RD = 1<<10, /* Bit 10: Repeater/DTE */
- PHY_N_1000C_AFD = 1<<9, /* Bit 9: Advertise Full Duplex */
- PHY_N_1000C_AHD = 1<<8, /* Bit 8: Advertise Half Duplex */
- PHY_N_1000C_APC = 1<<7, /* Bit 7: Asymmetric Pause Cap. */};
-
-
-/***** PHY_NAT_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/
-enum {
- PHY_N_1000S_MSF = 1<<15, /* Bit 15: Master/Slave Fault */
- PHY_N_1000S_MSR = 1<<14, /* Bit 14: Master/Slave Result */
- PHY_N_1000S_LRS = 1<<13, /* Bit 13: Local Receiver Status */
- PHY_N_1000S_RRS = 1<<12, /* Bit 12: Remote Receiver Status*/
- PHY_N_1000S_LP_FD= 1<<11, /* Bit 11: Link Partner can FD */
- PHY_N_1000S_LP_HD= 1<<10, /* Bit 10: Link Partner can HD */
- PHY_N_1000C_LP_APC= 1<<9, /* Bit 9: LP Asym. Pause Cap. */
- PHY_N_1000S_IEC = 0xff, /* Bit 7..0: Idle Error Count */
-};
-
-/***** PHY_NAT_EXT_STAT 16 bit r/o Extended Status Register *****/
-enum {
- PHY_N_ES_X_FD_CAP= 1<<15, /* Bit 15: 1000Base-X FD capable */
- PHY_N_ES_X_HD_CAP= 1<<14, /* Bit 14: 1000Base-X HD capable */
- PHY_N_ES_T_FD_CAP= 1<<13, /* Bit 13: 1000Base-T FD capable */
- PHY_N_ES_T_HD_CAP= 1<<12, /* Bit 12: 1000Base-T HD capable */
-};
-
/** Marvell-Specific */
enum {
PHY_M_AN_NXT_PG = 1<<15, /* Request Next Page */
@@ -1718,7 +1380,7 @@ enum {
PHY_M_PC_EN_DET_PLUS = 3<<8, /* Energy Detect Plus (Mode 2) */
};
-#define PHY_M_PC_MDI_XMODE(x) (((x)<<5) & PHY_M_PC_MDIX_MSK)
+#define PHY_M_PC_MDI_XMODE(x) (((x)<<5) & PHY_M_PC_MDIX_MSK)
enum {
PHY_M_PC_MAN_MDI = 0, /* 00 = Manual MDI configuration */
@@ -2105,7 +1767,7 @@ enum {
GM_GPSR_FC_RX_DIS = 1<<2, /* Bit 2: Rx Flow-Control Mode Disabled */
GM_GPSR_PROM_EN = 1<<1, /* Bit 1: Promiscuous Mode Enabled */
};
-
+
/* GM_GP_CTRL 16 bit r/w General Purpose Control Register */
enum {
GM_GPCR_PROM_ENA = 1<<14, /* Bit 14: Enable Promiscuous Mode */
@@ -2127,7 +1789,7 @@ enum {
#define GM_GPCR_SPEED_1000 (GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100)
#define GM_GPCR_AU_ALL_DIS (GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS|GM_GPCR_AU_SPD_DIS)
-
+
/* GM_TX_CTRL 16 bit r/w Transmit Control Register */
enum {
GM_TXCR_FORCE_JAM = 1<<15, /* Bit 15: Force Jam / Flow-Control */
@@ -2138,7 +1800,7 @@ enum {
#define TX_COL_THR(x) (((x)<<10) & GM_TXCR_COL_THR_MSK)
#define TX_COL_DEF 0x04
-
+
/* GM_RX_CTRL 16 bit r/w Receive Control Register */
enum {
GM_RXCR_UCF_ENA = 1<<15, /* Bit 15: Enable Unicast filtering */
@@ -2146,7 +1808,7 @@ enum {
GM_RXCR_CRC_DIS = 1<<13, /* Bit 13: Remove 4-byte CRC */
GM_RXCR_PASS_FC = 1<<12, /* Bit 12: Pass FC packets to FIFO */
};
-
+
/* GM_TX_PARAM 16 bit r/w Transmit Parameter Register */
enum {
GM_TXPA_JAMLEN_MSK = 0x03<<14, /* Bit 15..14: Jam Length */
@@ -2171,7 +1833,7 @@ enum {
GM_SMOD_JUMBO_ENA = 1<<8, /* Bit 8: Enable Jumbo (Max. Frame Len) */
GM_SMOD_IPG_MSK = 0x1f /* Bit 4..0: Inter-Packet Gap (IPG) */
};
-
+
#define DATA_BLIND_VAL(x) (((x)<<11) & GM_SMOD_DATABL_MSK)
#define DATA_BLIND_DEF 0x04
@@ -2186,7 +1848,7 @@ enum {
GM_SMI_CT_RD_VAL = 1<<4, /* Bit 4: Read Valid (Read completed) */
GM_SMI_CT_BUSY = 1<<3, /* Bit 3: Busy (Operation in progress) */
};
-
+
#define GM_SMI_CT_PHY_AD(x) (((x)<<11) & GM_SMI_CT_PHY_A_MSK)
#define GM_SMI_CT_REG_AD(x) (((x)<<6) & GM_SMI_CT_REG_A_MSK)
@@ -2195,7 +1857,7 @@ enum {
GM_PAR_MIB_CLR = 1<<5, /* Bit 5: Set MIB Clear Counter Mode */
GM_PAR_MIB_TST = 1<<4, /* Bit 4: MIB Load Counter (Test Mode) */
};
-
+
/* Receive Frame Status Encoding */
enum {
GMR_FS_LEN = 0xffff<<16, /* Bit 31..16: Rx Frame Length */
@@ -2217,12 +1879,12 @@ enum {
/*
* GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR)
*/
- GMR_FS_ANY_ERR = GMR_FS_CRC_ERR | GMR_FS_LONG_ERR |
- GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC |
+ GMR_FS_ANY_ERR = GMR_FS_CRC_ERR | GMR_FS_LONG_ERR |
+ GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC |
GMR_FS_JABBER,
/* Rx GMAC FIFO Flush Mask (default) */
RX_FF_FL_DEF_MSK = GMR_FS_CRC_ERR | GMR_FS_RX_FF_OV |GMR_FS_MII_ERR |
- GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE |
+ GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE |
GMR_FS_JABBER,
};
@@ -2540,10 +2202,6 @@ enum {
};
-/* XM_PHY_ADDR 16 bit r/w PHY Address Register */
-#define XM_PHY_ADDR_SZ 0x1f /* Bit 4..0: PHY Address bits */
-
-
/* XM_GP_PORT 32 bit r/w General Purpose Port Register */
enum {
XM_GP_ANIP = 1<<6, /* Bit 6: (ro) Auto-Neg. in progress */
@@ -2662,8 +2320,8 @@ enum {
};
#define XM_PAUSE_MODE (XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I)
-#define XM_DEF_MODE (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
- XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA)
+#define XM_DEF_MODE (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
+ XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA)
/* XM_STAT_CMD 16 bit r/w Statistics Command Register */
enum {
@@ -2793,28 +2451,20 @@ struct skge_hw {
u32 intr_mask;
struct net_device *dev[2];
- u8 mac_cfg;
u8 chip_id;
+ u8 chip_rev;
u8 phy_type;
u8 pmd_type;
u16 phy_addr;
+ u8 ports;
u32 ram_size;
u32 ram_offset;
-
+
struct tasklet_struct ext_tasklet;
spinlock_t phy_lock;
};
-static inline int isdualport(const struct skge_hw *hw)
-{
- return !(hw->mac_cfg & CFG_SNG_MAC);
-}
-
-static inline u8 chip_rev(const struct skge_hw *hw)
-{
- return (hw->mac_cfg & CFG_CHIP_R_MSK) >> 4;
-}
static inline int iscopper(const struct skge_hw *hw)
{
@@ -2827,7 +2477,7 @@ enum {
FLOW_MODE_REM_SEND = 2, /* Symmetric or just remote */
FLOW_MODE_SYMMETRIC = 3, /* Both stations may send PAUSE */
};
-
+
struct skge_port {
u32 msg_enable;
struct skge_hw *hw;
@@ -2853,8 +2503,8 @@ struct skge_port {
void *mem; /* PCI memory for rings */
dma_addr_t dma;
unsigned long mem_size;
+ unsigned int rx_buf_size;
- struct timer_list link_check;
struct timer_list led_blink;
};
@@ -2863,7 +2513,6 @@ struct skge_port {
static inline u32 skge_read32(const struct skge_hw *hw, int reg)
{
return readl(hw->regs + reg);
-
}
static inline u16 skge_read16(const struct skge_hw *hw, int reg)
@@ -2892,114 +2541,87 @@ static inline void skge_write8(const struct skge_hw *hw, int reg, u8 val)
}
/* MAC Related Registers inside the device. */
-#define SKGEMAC_REG(port,reg) (((port)<<7)+(reg))
-
-/* PCI config space can be accessed via memory mapped space */
-#define SKGEPCI_REG(reg) ((reg)+ 0x380)
-
-#define SKGEXM_REG(port, reg) \
+#define SK_REG(port,reg) (((port)<<7)+(reg))
+#define SK_XMAC_REG(port, reg) \
((BASE_XMAC_1 + (port) * (BASE_XMAC_2 - BASE_XMAC_1)) | (reg) << 1)
-static inline u32 skge_xm_read32(const struct skge_hw *hw, int port, int reg)
-{
- return skge_read32(hw, SKGEXM_REG(port,reg));
-}
-
-static inline u16 skge_xm_read16(const struct skge_hw *hw, int port, int reg)
+static inline u32 xm_read32(const struct skge_hw *hw, int port, int reg)
{
- return skge_read16(hw, SKGEXM_REG(port,reg));
+ u32 v;
+ v = skge_read16(hw, SK_XMAC_REG(port, reg));
+ v |= (u32)skge_read16(hw, SK_XMAC_REG(port, reg+2)) << 16;
+ return v;
}
-static inline u8 skge_xm_read8(const struct skge_hw *hw, int port, int reg)
+static inline u16 xm_read16(const struct skge_hw *hw, int port, int reg)
{
- return skge_read8(hw, SKGEXM_REG(port,reg));
+ return skge_read16(hw, SK_XMAC_REG(port,reg));
}
-static inline void skge_xm_write32(const struct skge_hw *hw, int port, int r, u32 v)
+static inline void xm_write32(const struct skge_hw *hw, int port, int r, u32 v)
{
- skge_write32(hw, SKGEXM_REG(port,r), v);
+ skge_write16(hw, SK_XMAC_REG(port,r), v & 0xffff);
+ skge_write16(hw, SK_XMAC_REG(port,r+2), v >> 16);
}
-static inline void skge_xm_write16(const struct skge_hw *hw, int port, int r, u16 v)
+static inline void xm_write16(const struct skge_hw *hw, int port, int r, u16 v)
{
- skge_write16(hw, SKGEXM_REG(port,r), v);
+ skge_write16(hw, SK_XMAC_REG(port,r), v);
}
-static inline void skge_xm_write8(const struct skge_hw *hw, int port, int r, u8 v)
-{
- skge_write8(hw, SKGEXM_REG(port,r), v);
-}
-
-static inline void skge_xm_outhash(const struct skge_hw *hw, int port, int reg,
+static inline void xm_outhash(const struct skge_hw *hw, int port, int reg,
const u8 *hash)
{
- skge_xm_write16(hw, port, reg,
- (u16)hash[0] | ((u16)hash[1] << 8));
- skge_xm_write16(hw, port, reg+2,
- (u16)hash[2] | ((u16)hash[3] << 8));
- skge_xm_write16(hw, port, reg+4,
- (u16)hash[4] | ((u16)hash[5] << 8));
- skge_xm_write16(hw, port, reg+6,
- (u16)hash[6] | ((u16)hash[7] << 8));
+ xm_write16(hw, port, reg, (u16)hash[0] | ((u16)hash[1] << 8));
+ xm_write16(hw, port, reg+2, (u16)hash[2] | ((u16)hash[3] << 8));
+ xm_write16(hw, port, reg+4, (u16)hash[4] | ((u16)hash[5] << 8));
+ xm_write16(hw, port, reg+6, (u16)hash[6] | ((u16)hash[7] << 8));
}
-static inline void skge_xm_outaddr(const struct skge_hw *hw, int port, int reg,
+static inline void xm_outaddr(const struct skge_hw *hw, int port, int reg,
const u8 *addr)
{
- skge_xm_write16(hw, port, reg,
- (u16)addr[0] | ((u16)addr[1] << 8));
- skge_xm_write16(hw, port, reg,
- (u16)addr[2] | ((u16)addr[3] << 8));
- skge_xm_write16(hw, port, reg,
- (u16)addr[4] | ((u16)addr[5] << 8));
+ xm_write16(hw, port, reg, (u16)addr[0] | ((u16)addr[1] << 8));
+ xm_write16(hw, port, reg+2, (u16)addr[2] | ((u16)addr[3] << 8));
+ xm_write16(hw, port, reg+4, (u16)addr[4] | ((u16)addr[5] << 8));
}
+#define SK_GMAC_REG(port,reg) \
+ (BASE_GMAC_1 + (port) * (BASE_GMAC_2-BASE_GMAC_1) + (reg))
-#define SKGEGMA_REG(port,reg) \
- ((reg) + BASE_GMAC_1 + \
- (port) * (BASE_GMAC_2-BASE_GMAC_1))
-
-static inline u16 skge_gma_read16(const struct skge_hw *hw, int port, int reg)
+static inline u16 gma_read16(const struct skge_hw *hw, int port, int reg)
{
- return skge_read16(hw, SKGEGMA_REG(port,reg));
+ return skge_read16(hw, SK_GMAC_REG(port,reg));
}
-static inline u32 skge_gma_read32(const struct skge_hw *hw, int port, int reg)
+static inline u32 gma_read32(const struct skge_hw *hw, int port, int reg)
{
- return (u32) skge_read16(hw, SKGEGMA_REG(port,reg))
- | ((u32)skge_read16(hw, SKGEGMA_REG(port,reg+4)) << 16);
+ return (u32) skge_read16(hw, SK_GMAC_REG(port,reg))
+ | ((u32)skge_read16(hw, SK_GMAC_REG(port,reg+4)) << 16);
}
-static inline u8 skge_gma_read8(const struct skge_hw *hw, int port, int reg)
+static inline void gma_write16(const struct skge_hw *hw, int port, int r, u16 v)
{
- return skge_read8(hw, SKGEGMA_REG(port,reg));
+ skge_write16(hw, SK_GMAC_REG(port,r), v);
}
-static inline void skge_gma_write16(const struct skge_hw *hw, int port, int r, u16 v)
+static inline void gma_write32(const struct skge_hw *hw, int port, int r, u32 v)
{
- skge_write16(hw, SKGEGMA_REG(port,r), v);
+ skge_write16(hw, SK_GMAC_REG(port, r), (u16) v);
+ skge_write32(hw, SK_GMAC_REG(port, r+4), (u16)(v >> 16));
}
-static inline void skge_gma_write32(const struct skge_hw *hw, int port, int r, u32 v)
+static inline void gma_write8(const struct skge_hw *hw, int port, int r, u8 v)
{
- skge_write16(hw, SKGEGMA_REG(port, r), (u16) v);
- skge_write32(hw, SKGEGMA_REG(port, r+4), (u16)(v >> 16));
+ skge_write8(hw, SK_GMAC_REG(port,r), v);
}
-static inline void skge_gma_write8(const struct skge_hw *hw, int port, int r, u8 v)
-{
- skge_write8(hw, SKGEGMA_REG(port,r), v);
-}
-
-static inline void skge_gm_set_addr(struct skge_hw *hw, int port, int reg,
+static inline void gma_set_addr(struct skge_hw *hw, int port, int reg,
const u8 *addr)
{
- skge_gma_write16(hw, port, reg,
- (u16) addr[0] | ((u16) addr[1] << 8));
- skge_gma_write16(hw, port, reg+4,
- (u16) addr[2] | ((u16) addr[3] << 8));
- skge_gma_write16(hw, port, reg+8,
- (u16) addr[4] | ((u16) addr[5] << 8));
+ gma_write16(hw, port, reg, (u16) addr[0] | ((u16) addr[1] << 8));
+ gma_write16(hw, port, reg+4,(u16) addr[2] | ((u16) addr[3] << 8));
+ gma_write16(hw, port, reg+8,(u16) addr[4] | ((u16) addr[5] << 8));
}
-
+
#endif
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index fd80048f7f7..cfb9d3cdb04 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 6e5ade99a38..97712c3c4e0 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 cfc346e72d6..08e0f80f89d 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 6200cfc4244..be1c1047b9b 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 7575b799ce5..7217d44e885 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 943be6baaad..758b48ba65c 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 a57187391f8..4d0b5a336bd 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 <net/ieee80211.h>
@@ -497,6 +127,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 */
/********************************************************************/
@@ -512,6 +146,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 (IEEE80211_DATA_LEN - ENCAPS_OVERHEAD)
@@ -538,6 +176,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 */
/********************************************************************/
@@ -572,26 +215,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;
@@ -599,13 +261,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);
@@ -629,6 +302,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);
@@ -815,7 +492,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). */
@@ -952,26 +629,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)
@@ -1048,18 +754,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);
@@ -1069,53 +884,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 > IEEE80211_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
@@ -1127,60 +935,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);
@@ -1193,11 +994,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;
}
/********************************************************************/
@@ -1241,6 +1041,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);
@@ -1308,6 +1201,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);
@@ -1320,6 +1216,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);
@@ -1329,12 +1234,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;
+ }
+
+ /* 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;
- priv->last_linkstatus = newstatus;
+ /* 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);
@@ -1471,6 +1453,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
@@ -1656,6 +1668,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));
@@ -1794,6 +1813,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;
@@ -1870,55 +1903,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)
@@ -1947,6 +1931,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) {
@@ -2185,6 +2174,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
@@ -2230,6 +2221,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;
@@ -2249,6 +2242,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;
@@ -2457,8 +2451,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 */
@@ -2474,6 +2469,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;
@@ -2484,6 +2481,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);
}
@@ -2491,24 +2491,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])
{
@@ -2634,140 +2616,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 (!access_ok(VERIFY_WRITE, rrq->pointer, sizeof(range)))
- return -EFAULT;
+ 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;
+ }
- rrq->length = sizeof(range);
+ 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;
- mode = priv->iw_mode;
+ 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);
- memset(&range, 0, sizeof(range));
+ return err;
+}
- /* 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;
+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;
- range.min_nwid = range.max_nwid = 0; /* We don't use nwids */
+ if (priv->iw_mode == *mode)
+ return 0;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ 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);
+
+ 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);
+
+ rrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ 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;
@@ -2775,8 +2888,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)
@@ -2789,9 +2901,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)
@@ -2865,12 +2974,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)
@@ -2899,51 +3010,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;
@@ -2957,51 +3064,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)
@@ -3012,23 +3114,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 */
@@ -3052,13 +3153,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;
@@ -3084,7 +3216,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;
@@ -3101,10 +3236,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;
@@ -3122,13 +3260,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)
@@ -3160,11 +3315,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;
@@ -3197,10 +3355,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;
@@ -3236,10 +3396,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;
@@ -3304,10 +3467,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)
@@ -3356,7 +3522,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;
@@ -3404,7 +3573,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;
@@ -3455,10 +3627,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)
@@ -3470,28 +3670,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;
@@ -3520,51 +3720,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;
@@ -3588,14 +3868,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;
@@ -3604,7 +3887,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],
@@ -3615,344 +3903,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 f749b50d108..2f213a7103f 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 4481ec18c5a..adc7499136d 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